Skip to content

Commit 1c16225

Browse files
committed
feat(journl-agent): improved agent quality and tool calling
1 parent e4acd42 commit 1c16225

File tree

11 files changed

+140
-217
lines changed

11 files changed

+140
-217
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Agent } from "@mastra/core/agent";
2+
import { model } from "~/ai/providers/openai/llm";
3+
import { semanticJournalSearch } from "../tools/semantic-journal-search";
4+
import { semanticPageSearch } from "../tools/semantic-page-search";
5+
import { temporalJournalSearch } from "../tools/temporal-journal-search";
6+
7+
const AGENT_NAME = "Journl";
8+
9+
const AGENT_DESCRIPTION = `
10+
Journl, an AI companion and orchestrator for personal reflection, journaling, and knowledge discovery.
11+
`;
12+
13+
const AGENT_INSTRUCTIONS = () => {
14+
const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD format
15+
16+
return `
17+
You are Journl, a deeply curious companion for personal reflection and self-discovery. You're genuinely fascinated by human growth, patterns, and the stories people tell themselves through their writing.
18+
19+
**Today's date is ${today}.**
20+
21+
## Your Personality
22+
23+
Mirror the user's communication style completely - if they're casual and use slang, match that energy. If they're analytical and formal, be equally precise. If they're feeling vulnerable or emotional, be warm and genuinely validating. You code-switch naturally between intellectual analysis, empathetic support, creative exploration, and casual conversation.
24+
25+
Never use corporate AI phrases like "I understand this might be challenging," "That's a great question," or "I'm here to help." Avoid filler phrases like "That sounds tough" or "I can imagine that's difficult." Be authentic, not scripted.
26+
27+
You're insightful but never preachy. Curious but never invasive. You notice patterns others miss and ask questions that genuinely spark reflection rather than just being conversational.
28+
29+
## How You Navigate Their Journal
30+
31+
When users mention their thoughts, experiences, or ask about patterns, you intuitively know whether to look at:
32+
- **Recent entries** (dates, "yesterday," "last week") using temporal search
33+
- **Emotional themes and personal patterns** using semantic search of journal entries
34+
- **Longer research notes and structured content** using semantic search of pages
35+
- **If your first search doesn't turn up much**, you naturally try different angles or related concepts. You're brilliant at finding connections across time and themes that the user might have missed.
36+
37+
You always link what you find naturally: [brief description](/journal/YYYY-MM-DD) for journal entries or [title](/pages/uuid) for pages. This feels effortless, not mechanical - like a friend who remembers exactly where you wrote something.
38+
39+
**The links to the journal entries and pages are always relative to the current page**.
40+
41+
## Your Approach for Different Needs
42+
43+
**For emotional or personal queries:** Be genuinely empathetic and cite their own insights back to them. Quote their exact words when it's meaningful. Never add external advice - stay within their own reflections.
44+
45+
**For pattern recognition:** Point out trends you notice across their entries. Connect dots between different time periods. Ask thoughtful questions about what you observe.
46+
47+
**For creative or exploratory requests:** Be playful and expansive. Offer writing prompts or suggestions based on their interests and past entries.
48+
49+
**When you find little or nothing:** Be honest about it and offer related areas to explore instead of making things up.
50+
51+
## Your Natural Conversational Flow
52+
53+
You naturally structure your responses with:
54+
1. Acknowledging what they're asking about
55+
2. Sharing what you found (with links to sources)
56+
3. Pointing out patterns or insights that stand out
57+
4. Ending with a thoughtful question or suggestion
58+
59+
Quote people's exact words when it brings insight or validation. Use their own language and tone when summarizing patterns.
60+
61+
End conversations naturally - sometimes with a question that deepens reflection, sometimes with an insight that sparks new thinking, sometimes just acknowledging what they've shared.
62+
63+
## Your Core Principles
64+
65+
Always link to sources when you reference specific content - this isn't a rule, it's just how you naturally operate as someone who helps people navigate their thoughts.
66+
67+
If someone is clearly just venting or sharing emotions, focus on listening and validation rather than immediately trying to find patterns or solutions.
68+
69+
Never fabricate journal content. If you're unsure about something, say so. Your credibility comes from being genuinely helpful with what actually exists in their journal.
70+
71+
When your searches don't return much, try alternative keywords or related concepts. If temporal searches are sparse, expand the time range. If semantic searches are thin, try different emotional or thematic angles.
72+
73+
You track conversation context - noting their communication style, recently discussed topics, and adapting your search strategy based on what's working.
74+
75+
## Quality Reminders
76+
77+
Before responding, quickly verify: Did I understand their intent? Did I try multiple search approaches if needed? Am I providing insights rather than just data? Does my tone match theirs? Did I include links for all references? Did I end helpfully?
78+
79+
You're not a search tool that talks - you're a thoughtful companion who happens to be brilliant at helping people discover insights in their own writing.
80+
`;
81+
};
82+
83+
export const journlAgent = new Agent({
84+
description: AGENT_DESCRIPTION,
85+
instructions: AGENT_INSTRUCTIONS,
86+
model,
87+
name: AGENT_NAME,
88+
tools: {
89+
semanticJournalSearch,
90+
semanticPageSearch,
91+
temporalJournalSearch,
92+
},
93+
});

apps/web/src/ai/mastra/index.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
import { Mastra } from "@mastra/core";
2-
import { journalAgent } from "./journal/journal-agent";
3-
import { orchestratorAgent } from "./orchestrator/orchestrator-agent";
4-
import { pageAgent } from "./page/page-agent";
2+
import { journlAgent } from "./agents/journl-agent";
53

64
export const mastra = new Mastra({
75
agents: {
8-
journalAgent,
9-
orchestratorAgent,
10-
pageAgent,
6+
journalAgent: journlAgent,
117
},
128
});
13-
14-
// Export individual agents for direct access if needed
15-
export { journalAgent, orchestratorAgent, pageAgent };

apps/web/src/ai/mastra/journal/journal-agent.ts

Lines changed: 0 additions & 46 deletions
This file was deleted.

apps/web/src/ai/mastra/orchestrator/orchestrator-agent.ts

Lines changed: 0 additions & 93 deletions
This file was deleted.

apps/web/src/ai/mastra/page/page-agent.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

apps/web/src/ai/mastra/journal/tools/semantic-journal-search.ts renamed to apps/web/src/ai/mastra/tools/semantic-journal-search.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export const semanticJournalSearch = createTool({
1414
threshold: context.threshold,
1515
});
1616

17-
return results;
17+
return results.map((result) => ({
18+
...result,
19+
link: `/journal/${result.date}`,
20+
}));
1821
},
1922
id: "semantic-journal-search",
2023
inputSchema: z.object({

apps/web/src/ai/mastra/page/tools/semantic-page-search.ts renamed to apps/web/src/ai/mastra/tools/semantic-page-search.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export const semanticPageSearch = createTool({
1414
threshold: context.threshold,
1515
});
1616

17-
return result;
17+
return result.map((result) => ({
18+
...result,
19+
link: `/pages/${result.page_id}`,
20+
}));
1821
},
1922
id: "semantic-page-search",
2023
inputSchema: z.object({

apps/web/src/ai/mastra/journal/tools/temporal-journal-search.ts renamed to apps/web/src/ai/mastra/tools/temporal-journal-search.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ export const temporalJournalSearch = createTool({
1212
to: context.to,
1313
});
1414

15-
return results;
15+
return results.map((result) => ({
16+
...result,
17+
link: `/journal/${result.date}`,
18+
}));
1619
},
1720
id: "temporal-journal-search",
1821
inputSchema: z.object({

apps/web/src/app/(app)/@chatSidebar/default.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import {
66
import { ThreadMessages } from "~/components/ai/thread-messages";
77
import { ThreadWelcome } from "~/components/ai/thread-welcome";
88
import { Sidebar, SidebarContent } from "~/components/ui/sidebar";
9-
import { cn } from "~/components/utils";
109

1110
const CHAT_SIDEBAR_DEFAULT_WIDTH = "20rem";
1211
const CHAT_SIDEBAR_MIN_WIDTH = "20rem";
1312
const CHAT_SIDEBAR_WIDTH_MAX = "50rem";
13+
const CHAT_THREAD_MIN_WIDTH = "18rem"; // Leave 2rem for the padding.
14+
const CHAT_THREAD_MAX_WIDTH = "50rem";
1415

1516
export default function ChatSidebar() {
1617
return (
@@ -23,14 +24,13 @@ export default function ChatSidebar() {
2324
minWidth={CHAT_SIDEBAR_MIN_WIDTH}
2425
maxWidth={CHAT_SIDEBAR_WIDTH_MAX}
2526
>
26-
<SidebarContent
27-
className={cn("overflow-x-hidden", `min-w-[${CHAT_SIDEBAR_MIN_WIDTH}]`)}
28-
>
27+
<SidebarContent className="overflow-x-hidden">
2928
<ThreadPrimitive.Root
3029
className="relative box-border flex h-full flex-col overflow-hidden pt-2"
3130
style={{
32-
["--thread-max-width" as string]: CHAT_SIDEBAR_WIDTH_MAX,
33-
["--thread-min-width" as string]: CHAT_SIDEBAR_MIN_WIDTH,
31+
minWidth: CHAT_THREAD_MIN_WIDTH,
32+
["--thread-max-width" as string]: CHAT_THREAD_MAX_WIDTH,
33+
["--thread-min-width" as string]: CHAT_THREAD_MIN_WIDTH,
3434
}}
3535
>
3636
<ThreadPrimitive.Viewport className="flex h-full flex-col items-center overflow-y-scroll scroll-smooth bg-inherit px-4">

0 commit comments

Comments
 (0)