Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/chat/providers/chat-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export function ChatProvider({
}, [messages])

const sendMessage = useCallback(
(text: string, _files?: File[]) => {
(text: string, files?: File[]) => {
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unused parameter files (renamed from _files) will now trigger ESLint warnings due to the ESLint configuration change that removed the underscore ignore pattern. If this parameter is intentionally unused but required by the function signature, it should be prefixed with underscore to document this intent.

Suggested change
(text: string, files?: File[]) => {
(text: string, _files?: File[]) => {

Copilot uses AI. Check for mistakes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent parameter naming: removed underscore from unused parameter.

The parameter name was changed from _files to files, but:

  1. The parameter is not used in the function body (lines 325-328)
  2. The interface definition at line 95 still uses _files with the underscore prefix
  3. Removing the underscore suggests the parameter should be used, but it isn't

The underscore prefix is a convention for intentionally unused parameters (especially important with no-unused-vars ESLint rules).

Either keep the underscore prefix for consistency:

-    (text: string, files?: File[]) => {
+    (text: string, _files?: File[]) => {

Or implement file handling if the parameter is meant to be used:

     (text: string, files?: File[]) => {
       if (!text.trim() || isLoading) {return}
       setChatError(null)
-      aiSendMessage({ text: text.trim() })
+      aiSendMessage({ 
+        text: text.trim(),
+        // Handle files if needed
+      })
     },

Note: The interface at line 95 should also be updated to match whichever approach you choose.

🤖 Prompt for AI Agents
In app/chat/providers/chat-context.tsx around line 324, the parameter name was
changed from `_files` to `files` but the parameter is unused (and the interface
at line 95 still uses `_files`), causing inconsistent naming and confusing
intent; restore the underscore to indicate an intentionally unused parameter by
renaming the parameter back to `_files` here and update the interface at line 95
to match, OR if file handling is intended, implement the file processing logic
inside the function and update the interface at line 95 to use `files` (ensuring
ESLint no-unused-vars compliance and consistent names across both declaration
and implementation).

if (!text.trim() || isLoading) {return}
setChatError(null)
aiSendMessage({ text: text.trim() })
Expand Down
26 changes: 18 additions & 8 deletions app/networks/providers/network-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,28 @@ export function NetworkProvider({
for (const message of messages) {
if (message.role === "assistant" && message.parts !== null) {
for (const [partIndex, part] of message.parts.entries()) {
// Handle agent and workflow progress events
// Handle legacy agent/workflow events by normalizing them into progress events
if (part.type === "data-tool-agent" || part.type === "data-tool-workflow") {
const agentPart = part as { data: AgentDataPart }
const eventData = agentPart.data
const agentPart = part as { data?: AgentDataPart }
const eventData = agentPart.data as Record<string, unknown> | undefined
const dataObj = eventData?.data as Record<string, unknown> | undefined

if (eventData?.data?.text?.trim()) {
const msg = typeof dataObj?.text === 'string' ? dataObj.text
: typeof dataObj?.message === 'string' ? dataObj.message
: typeof eventData?.message === 'string' ? eventData.message
: typeof eventData?.text === 'string' ? eventData.text
: ''
Comment on lines +304 to +308
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to extract the message msg is a bit complex and could be simplified. Using a helper function or a more streamlined approach might improve readability and maintainability, especially since similar logic is repeated in app/workflows/providers/workflow-context.tsx.


const stage = typeof eventData?.stage === 'string' ? eventData.stage : (typeof dataObj?.stage === 'string' ? dataObj.stage : part.type.replace("data-tool-", ""))
const agentId = typeof eventData?.id === 'string' ? eventData.id : undefined

if (msg && msg.trim().length > 0) {
allProgressEvents.push({
id: `${message.id}-${part.type}-${partIndex}`,
stage: part.type.replace("data-tool-", ""),
stage: String(stage),
status: "in-progress",
message: eventData.data.text,
agentId: eventData.id,
message: msg,
agentId,
timestamp: new Date(),
data: eventData,
})
Expand All @@ -318,7 +328,7 @@ export function NetworkProvider({
const progressPart = part as { type: string; data?: { status?: string; message?: string; stage?: string; agentId?: string } }
const eventData = progressPart.data

if (eventData?.status && (eventData.status === "in-progress" || eventData.status === "done" || eventData.status === "error")) {
if (typeof eventData?.status === 'string' && (eventData.status === "in-progress" || eventData.status === "done")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cd /repo && head -50 app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 117


🏁 Script executed:

cd /repo && sed -n '30,45p' app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 117


🏁 Script executed:

cd /repo && sed -n '325,340p' app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 117


🏁 Script executed:

cd /repo && rg -n 'data-tool-progress' --type=tsx -A 8

Repository: ssdeanx/AgentStack

Length of output: 117


🏁 Script executed:

cd /repo && rg -n 'ProgressEvent' --type=tsx -B 2 -A 5

Repository: ssdeanx/AgentStack

Length of output: 117


🏁 Script executed:

cd /repo && rg -n 'data-tool-error' --type=tsx -A 5

Repository: ssdeanx/AgentStack

Length of output: 117


🏁 Script executed:

wc -l app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 108


🏁 Script executed:

sed -n '30,45p' app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 324


🏁 Script executed:

sed -n '325,340p' app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 937


🏁 Script executed:

rg -n 'data-tool-progress' --type=tsx -A 8

Repository: ssdeanx/AgentStack

Length of output: 89


🏁 Script executed:

rg -n 'ProgressEvent' --type=tsx -B 2 -A 5

Repository: ssdeanx/AgentStack

Length of output: 89


🏁 Script executed:

rg -n 'status.*error' app/networks/providers/network-context.tsx -B 2 -A 2

Repository: ssdeanx/AgentStack

Length of output: 692


🏁 Script executed:

rg -n 'data-tool-error' app/networks/providers/network-context.tsx -B 2 -A 5

Repository: ssdeanx/AgentStack

Length of output: 44


🏁 Script executed:

rg -n 'status.*error\|error.*status' app/networks/providers/network-context.tsx -B 3 -A 3

Repository: ssdeanx/AgentStack

Length of output: 44


🏁 Script executed:

grep -n 'part\.type' app/networks/providers/network-context.tsx | head -20

Repository: ssdeanx/AgentStack

Length of output: 728


🏁 Script executed:

sed -n '275,360p' app/networks/providers/network-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 3772


🏁 Script executed:

find . -name "workflow-context.tsx" -o -name "workflow-context.ts"

Repository: ssdeanx/AgentStack

Length of output: 108


🏁 Script executed:

sed -n '380,430p' app/workflows/providers/workflow-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 2606


🏁 Script executed:

grep -n 'status.*error\|error.*status' app/workflows/providers/workflow-context.tsx -B 2 -A 2

Repository: ssdeanx/AgentStack

Length of output: 945


Include "error" status in the data-tool-progress condition to match the ProgressEvent interface and workflow-context.tsx pattern.

The status check at line 331 excludes "error", causing progress events with status: "error" to be silently dropped. The ProgressEvent interface (line 37) defines status as "in-progress" | "done" | "error", and workflow-context.tsx (line 399-400) explicitly includes all three statuses when handling similar data-workflow-progress events.

Change line 331 from:

if (typeof eventData?.status === 'string' && (eventData.status === "in-progress" || eventData.status === "done"))

To:

if (typeof eventData?.status === 'string' && (eventData.status === "in-progress" || eventData.status === "done" || eventData.status === "error"))
🤖 Prompt for AI Agents
In app/networks/providers/network-context.tsx around line 331, the conditional
that filters data-tool-progress events only allows "in-progress" and "done"
statuses and therefore drops "error" events; update the check to also accept
eventData.status === "error" so it matches the ProgressEvent interface and the
pattern used in workflow-context.tsx, ensuring error status events are processed
the same way as the other statuses.

allProgressEvents.push({
id: `${message.id}-${part.type}-${partIndex}`,
stage: eventData.stage ?? "progress",
Expand Down
15 changes: 9 additions & 6 deletions app/workflows/providers/workflow-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,17 +319,20 @@ export function WorkflowProvider({
}
}

// Handle tool agent events (data-tool-agent)
// Handle legacy tool agent events (data-tool-agent) by normalizing into progress events
if (part.type === "data-tool-agent") {
const agentPart = part as { data?: AgentDataPart }
const eventData = agentPart.data
const eventData = agentPart.data as Record<string, unknown> | undefined
const dataObj = eventData?.data as Record<string, unknown> | undefined
const msg = typeof dataObj?.text === 'string' ? dataObj.text : (typeof dataObj?.message === 'string' ? dataObj.message : (typeof eventData?.message === 'string' ? eventData.message : `Agent executing tool`))
const stage = typeof eventData?.stage === 'string' ? eventData.stage : 'tool agent'

if (eventData) {
if (msg && msg.trim().length > 0) {
allProgressEvents.push({
id: `${message.id}-${part.type}-${partIndex}`,
stage: "tool agent",
status: "in-progress",
message: `Agent executing tool`,
stage: String(stage),
status: 'in-progress',
message: msg,
timestamp: new Date(),
data: eventData,
})
Expand Down
4 changes: 2 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ export default [
},
},
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'no-unused-vars': ['warn', { }],
'@typescript-eslint/no-unused-vars': ['warn', {}],
Comment on lines +65 to +66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: removed ignore patterns for underscore-prefixed variables/args - this will cause warnings for intentionally unused parameters like _context or _req

Suggested change
'no-unused-vars': ['warn', { }],
'@typescript-eslint/no-unused-vars': ['warn', {}],
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
Prompt To Fix With AI
This is a comment left during a code review.
Path: eslint.config.js
Line: 65:66

Comment:
**logic:** removed ignore patterns for underscore-prefixed variables/args - this will cause warnings for intentionally unused parameters like `_context` or `_req`

```suggestion
            'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
            '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +65 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Removing the argsIgnorePattern and varsIgnorePattern options means we can no longer mark intentionally unused variables with an underscore to suppress warnings. This might lead to unnecessary warnings for variables that are required by an interface but not used in the implementation. Was this change intentional? If so, what is the new convention for handling such cases?

Suggested change
'no-unused-vars': ['warn', { }],
'@typescript-eslint/no-unused-vars': ['warn', {}],
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],

Comment on lines +65 to +66
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ESLint configuration change removes important ignore patterns for unused variables starting with underscore. The empty object {} means ALL unused variables will now trigger warnings, even those intentionally prefixed with _ to indicate they're unused but required (e.g., function signatures matching interfaces).

This will likely cause numerous false-positive warnings throughout the codebase where developers intentionally use _ prefix to indicate "I know this parameter is unused but it's required by the signature".

Suggested change
'no-unused-vars': ['warn', { }],
'@typescript-eslint/no-unused-vars': ['warn', {}],
'no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],

Copilot uses AI. Check for mistakes.
'no-console': 'warn',
'no-var': 'warn',
'object-shorthand': 'error',
Expand Down
26 changes: 26 additions & 0 deletions memory-bank/copilot-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,32 @@ If any fail, do NOT proceed. Fix issues first.

---

## Tool Streaming & Progress Events

All tools must follow the TASK001 streaming convention:

- Prefer the runtime agent instance via `context.mastra.getAgent('<agentId>')` when available, otherwise fall back to the local agent import.
- If the agent exposes a stream API, call `agent.stream(prompt)` returning a `MastraModelOutput` and:
- Pipe `textStream` / `fullStream` to `context.writer` so the UI receives nested chunks
- Await `stream.text` for the final text
- Use `stream.object` when present for structured responses and fall back to JSON parsing of `stream.text`
- If no streaming API, call `agent.generate(prompt)` and parse `response.object` or JSON text as a fallback.
- Emit progress events with the exact format below at start/in-progress/done:

```typescript
await context?.writer?.custom({
type: 'data-tool-progress',
data: {
status: 'in-progress',
message: `📈 Fetching tool-id data for ${inputData.symbol}/${inputData.market}`,
stage: 'tool-id'
},
id: 'tool-id'
});
```
Comment on lines +167 to +177
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Improve consistency of placeholder values in example.

The progress event example mixes generic placeholders ("tool-id") with specific financial API fields (inputData.symbol, inputData.market), creating confusion about what values should be used.

Either use fully generic placeholders:

 await context?.writer?.custom({
   type: 'data-tool-progress',
   data: {
     status: 'in-progress',
-    message: `📈 Fetching tool-id data for ${inputData.symbol}/${inputData.market}`,
+    message: `Processing ${toolName} with input: ${inputData.param}`,
     stage: 'tool-id'
   },
   id: 'tool-id'
 });

Or use a complete real-world example:

 await context?.writer?.custom({
   type: 'data-tool-progress',
   data: {
     status: 'in-progress',
     message: `📈 Fetching Alpha Vantage crypto data for ${inputData.symbol}/${inputData.market}`,
-    stage: 'tool-id'
+    stage: 'alpha-vantage-crypto'
   },
-  id: 'tool-id'
+  id: 'alpha-vantage-crypto'
 });

The second approach matches the real example shown in AGENTS.md (lines 124-132) and provides clearer guidance.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```typescript
await context?.writer?.custom({
type: 'data-tool-progress',
data: {
status: 'in-progress',
message: `📈 Fetching tool-id data for ${inputData.symbol}/${inputData.market}`,
stage: 'tool-id'
},
id: 'tool-id'
});
```
🤖 Prompt for AI Agents
In memory-bank/copilot-rules.md around lines 167 to 177, the progress event
example mixes generic placeholders ("tool-id") with concrete fields
(inputData.symbol/inputData.market); update the example for consistency by
choosing one style and applying it throughout—either replace the specific fields
with generic placeholders (e.g., ${symbol}/${market}) and keep id as 'tool-id',
or convert id to a realistic value and use a complete real-world example
matching AGENTS.md (lines 124-132); ensure the chosen approach is applied to all
keys (type, data.status, data.message, data.stage, id) and update the message
text accordingly so placeholders are consistent across the snippet.


- Update the TASK001 scratchpad (`/memory-bank/tasks/TASK001-tool-streaming.md`) when implementing or changing tool streaming behavior.

## 🎨 UI Component Rules

### Component Locations
Expand Down
1 change: 1 addition & 0 deletions memory-bank/memory-bank-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ This document instructs GitHub Copilot on how to:
- Status check → + progress.md
```

Note: For tool implementation tasks, consult `memory-bank/tasks/TASK001-tool-streaming.md` which documents the standard streaming and progress-event conventions (use `context.writer` with `data-tool-progress` start/in-progress/done events, and prefer `agent.stream()` with `MastraModelOutput` when available). Update the task scratchpad with any deviations or agent-specific details.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Excessive line length in markdown documentation.

Line 40 exceeds 300 characters, violating the project's markdown guideline to limit lines to 80 characters for readability.

Apply this diff to reformat the note with proper line breaks:

-Note: For tool implementation tasks, consult `memory-bank/tasks/TASK001-tool-streaming.md` which documents the standard streaming and progress-event conventions (use `context.writer` with `data-tool-progress` start/in-progress/done events, and prefer `agent.stream()` with `MastraModelOutput` when available). Update the task scratchpad with any deviations or agent-specific details.
+Note: For tool implementation tasks, consult
+`memory-bank/tasks/TASK001-tool-streaming.md` which documents the standard
+streaming and progress-event conventions (use `context.writer` with
+`data-tool-progress` start/in-progress/done events, and prefer
+`agent.stream()` with `MastraModelOutput` when available). Update the task
+scratchpad with any deviations or agent-specific details.

As per coding guidelines, limit line length to 80 characters in markdown for readability.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Note: For tool implementation tasks, consult `memory-bank/tasks/TASK001-tool-streaming.md` which documents the standard streaming and progress-event conventions (use `context.writer` with `data-tool-progress` start/in-progress/done events, and prefer `agent.stream()` with `MastraModelOutput` when available). Update the task scratchpad with any deviations or agent-specific details.
Note: For tool implementation tasks, consult
`memory-bank/tasks/TASK001-tool-streaming.md` which documents the standard
streaming and progress-event conventions (use `context.writer` with
`data-tool-progress` start/in-progress/done events, and prefer
`agent.stream()` with `MastraModelOutput` when available). Update the task
scratchpad with any deviations or agent-specific details.
🤖 Prompt for AI Agents
In memory-bank/memory-bank-instructions.md around line 40, the Note paragraph
exceeds the project's 80-character markdown line-length rule; reflow the
sentence into multiple lines no longer than 80 characters, preserving all
content and inline code/backticks (e.g.,
`memory-bank/tasks/TASK001-tool-streaming.md`, `context.writer`,
`data-tool-progress`, `agent.stream()`, `MastraModelOutput`), and ensure the
final wrapped paragraph reads naturally and keeps the instruction to update the
task scratchpad with any deviations.

### On Context Reset (New Session)

```markdown
Expand Down
2 changes: 1 addition & 1 deletion memory-bank/tasks/TASK001-tool-streaming.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# [Task 001] - Implement Tool Streaming with Writer in ALL Tools\n\n**Status:** In Progress \n**Added:** 2025-11-22 \n**Updated:** 2025-11-22\n\n## Original Request\n\nUser: Fetch Mastra tool streaming docs, implement in #file:tools. Clarified: ALL tools use writer directly, no utility.\n\n## Thought Process\n\nMastra docs: execute({context, writer?}): await writer?.write({type:'custom-event'| 'progress', ...}); return result. 12 tools need surgical updates: add writer param, emit start/progress/end.\n\n## Implementation Plan\n\n- Create tasks structure\n- Update all 12 .tool.ts executes\n- Add streaming tests\n- Update AGENTS.md\n\n## Progress Tracking\n\n**Overall Status:** In Progress - 10%\n\n### Subtasks\n\n| ID | Description | Status | Updated | Notes \n|-----|--------------------------------------|-------------|-------------|-------\n| 1.1 | Create tasks/ folder & files | Complete | 2025-11-22 | Done\n| 1.2 | Read all tool files | In Progress | 2025-11-22 | 3 read, 9 pending\n| 1.3 | Edit weather-tool.ts | Not Started | | \n| 1.4 | Edit serpapi-search.tool.ts | Not Started | | \n| ... | Edit remaining tools | Not Started | | \n| 1.x | Tests & AGENTS.md | Not Started | | \n\n## Progress Log\n\n### 2025-11-22\n- Created tasks structure\n- Read 3 sample tools\n- Planning batch edits\n
# [Task 001] - Implement Tool Streaming with Writer in ALL Tools\n\n**Status:** In Progress \n**Added:** 2025-11-22 \n**Updated:** 2025-11-22\n\n## Original Request\n\nUser: Fetch Mastra tool streaming docs, implement in #file:tools. Clarified: ALL tools use writer directly, no utility.\n\n## Thought Process\n\nMastra docs: execute({context, writer?}): await writer?.write({type:'custom-event'| 'progress', ...}); return result. 12 tools need surgical updates: add writer param, emit start/progress/end.\n\n## Implementation Plan\n\n- Create tasks structure\n- Update all 12 .tool.ts executes\n- Add streaming tests\n- Update AGENTS.md\n\n## Progress Tracking\n\n**Overall Status:** In Progress - 10%\n\n### Subtasks\n\n| ID | Description | Status | Updated | Notes \n|-----|--------------------------------------|-------------|-------------|-------\n| 1.1 | Create tasks/ folder & files | Complete | 2025-11-22 | Done\n| 1.2 | Read all tool files | In Progress | 2025-11-22 | 3 read, 9 pending\n| 1.3 | Edit weather-tool.ts | Not Started | | \n| 1.4 | Edit serpapi-search.tool.ts | Not Started | | \n| ... | Edit remaining tools | Not Started | | \n| 1.x | Tests & AGENTS.md | Not Started | | \n\n## Progress Log\n\n### 2025-11-22\n- Created tasks structure\n- Read 3 sample tools\n- Planning batch edits\n
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incorrect file format: markdown stored as escaped single-line string.

This markdown file is stored as a single line with \n escape sequences instead of actual line breaks. Markdown files should use proper multi-line formatting for readability and maintainability.

The content should be reformatted as a proper multi-line markdown file. For example, the beginning should be:

-# [Task 001] - Implement Tool Streaming with Writer in ALL Tools\n\n**Status:** In Progress  \n**Added:** 2025-11-22  \n**Updated:** 2025-11-22\n\n## Original Request\n\nUser: Fetch Mastra tool streaming docs, implement in #file:tools. Clarified: ALL tools use writer directly, no utility.\n\n## Thought Process\n\nMastra docs: execute({context, writer?}): await writer?.write({type:'custom-event'| 'progress', ...}); return result. 12 tools need surgical updates: add writer param, emit start/progress/end.\n\n## Implementation Plan\n\n- Create tasks structure\n- Update all 12 .tool.ts executes\n- Add streaming tests\n- Update AGENTS.md\n\n## Progress Tracking\n\n**Overall Status:** In Progress - 10%\n\n### Subtasks\n\n| ID  | Description                          | Status      | Updated     | Notes \n|-----|--------------------------------------|-------------|-------------|-------\n| 1.1 | Create tasks/ folder & files         | Complete    | 2025-11-22 | Done\n| 1.2 | Read all tool files                  | In Progress | 2025-11-22 | 3 read, 9 pending\n| 1.3 | Edit weather-tool.ts                 | Not Started |             | \n| 1.4 | Edit serpapi-search.tool.ts          | Not Started |             | \n| ... | Edit remaining tools                 | Not Started |             | \n| 1.x | Tests & AGENTS.md                    | Not Started |             | \n\n## Progress Log\n\n### 2025-11-22\n- Created tasks structure\n- Read 3 sample tools\n- Planning batch edits\n
+# [Task 001] - Implement Tool Streaming with Writer in ALL Tools
+
+**Status:** In Progress  
+**Added:** 2025-11-22  
+**Updated:** 2025-11-22
+
+## Original Request
+
+User: Fetch Mastra tool streaming docs, implement in #file:tools. Clarified: ALL tools use writer directly, no utility.
+
+## Thought Process
+
+Mastra docs: execute({context, writer?}): await writer?.write({type:'custom-event'| 'progress', ...}); return result. 12 tools need surgical updates: add writer param, emit start/progress/end.
+
+## Implementation Plan
+
+- Create tasks structure
+- Update all 12 .tool.ts executes
+- Add streaming tests
+- Update AGENTS.md
+
+## Progress Tracking
+
+**Overall Status:** In Progress - 10%
+
+### Subtasks
+
+| ID  | Description                          | Status      | Updated     | Notes |
+|-----|--------------------------------------|-------------|-------------|-------|
+| 1.1 | Create tasks/ folder & files         | Complete    | 2025-11-22 | Done  |
+| 1.2 | Read all tool files                  | In Progress | 2025-11-22 | 3 read, 9 pending |
+| 1.3 | Edit weather-tool.ts                 | Not Started |             |       |
+| 1.4 | Edit serpapi-search.tool.ts          | Not Started |             |       |
+| ... | Edit remaining tools                 | Not Started |             |       |
+| 1.x | Tests & AGENTS.md                    | Not Started |             |       |
+
+## Progress Log
+
+### 2025-11-22
+- Created tasks structure
+- Read 3 sample tools
+- Planning batch edits

As per coding guidelines, limit line length to 80 characters in markdown for readability and use proper whitespace between sections.

🤖 Prompt for AI Agents
In memory-bank/tasks/TASK001-tool-streaming.md around lines 1 to 1, the markdown
content is stored as a single-line string containing literal "\n" sequences
instead of real line breaks; convert it into a proper multi-line markdown file
by replacing the escaped "\n" with actual newlines, restoring the intended
headings/paragraphs and list formatting, break long lines to a maximum of ~80
characters for readability, and ensure proper blank lines between sections
(headings, lists, code blocks) per markdown conventions.

27 changes: 27 additions & 0 deletions memory-bank/tasks/TASK001-update-2025-12-14.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# TASK001 - Update Log (2025-12-14)

Summary of changes performed to align tools with the streaming + progress convention:

- Replaced `data-tool-agent` messages with `data-tool-progress` (standard in-progress/done events) in:
- `src/mastra/tools/evaluateResultTool.ts`
- `src/mastra/tools/extractLearningsTool.ts`
- `src/mastra/tools/editor-agent-tool.ts`
- `src/mastra/tools/copywriter-agent-tool.ts`

- Normalized nested-agent streaming pattern in tools to:
- Prefer `context.mastra.getAgent()` runtime instance if available, otherwise fall back to local agent import
- Use `agent.stream(prompt)` returning `MastraModelOutput` when available
- Pipe `textStream` / `fullStream` to `context.writer`
- Parse `stream.object` or JSON text safely for structured output

- Updated `src/mastra/tools/financial-chart-tools.ts` to use the same streaming pattern and to validate agent capability (check for `generate` or `stream`).

- Updated client-side parsers to normalize legacy `data-tool-agent` parts into `data-tool-progress` events:
- `app/networks/providers/network-context.tsx`
- `app/workflows/providers/workflow-context.tsx`

- Updated `src/mastra/tools/AGENTS.md` with a note referencing this task and the progress convention.

Notes:
- Tests will be added next to verify that progress events and streaming behavior are emitted consistently. (Pending)
- If you'd like, I can add/restore unit tests and run the test suite now.
Comment on lines +25 to +27
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Update log incomplete: missing mention of deleted test files.

The PR objectives state that five test files were deleted (serpapi-news-trends.tool.test.ts, serpapi-search.tool.test.ts, serpapi-shopping.tool.test.ts, weather-tool.test.ts, web-scraper-tool.test.ts), but this update log only mentions adding new tests. The deletion of existing test suites should be documented here with justification.

Add a section documenting the test file deletions:

 - Updated `src/mastra/tools/AGENTS.md` with a note referencing this task and the progress convention.
 
+- Removed outdated test files (migrating to streaming-based test approach):
+  - `src/mastra/tools/tests/serpapi-news-trends.tool.test.ts`
+  - `src/mastra/tools/tests/serpapi-search.tool.test.ts`
+  - `src/mastra/tools/tests/serpapi-shopping.tool.test.ts`
+  - `src/mastra/tools/tests/weather-tool.test.ts`
+  - `src/mastra/tools/tests/web-scraper-tool.test.ts`
+
 Notes:
 - Tests will be added next to verify that progress events and streaming behavior are emitted consistently. (Pending)

Based on learnings, ensure that removing tests is justified and that test coverage is maintained or restored to avoid regressions.

🤖 Prompt for AI Agents
In memory-bank/tasks/TASK001-update-2025-12-14.md around lines 25 to 27, the
update log omits mention and justification of five deleted test files; add a new
section that lists the removed tests (serpapi-news-trends.tool.test.ts,
serpapi-search.tool.test.ts, serpapi-shopping.tool.test.ts,
weather-tool.test.ts, web-scraper-tool.test.ts), brief rationale for each
deletion (why they were removed or replaced), and notes on how coverage is
preserved or will be restored (e.g., new tests added, test refactors, or
alternative validation strategies) so reviewers can verify test coverage is
maintained.

2 changes: 1 addition & 1 deletion src/mastra/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ This folder contains the middleware and high-level components that define Mastra

- Use explicit Zod schemas for every tool input/output.
- Keep tools small and side-effect-free when possible; agents orchestrate tools and handle context.
- Use `RuntimeContext` to enforce access control in tools and workflows.
- Use `RequestContext` (per-request) or agent-specific runtime context types (e.g. `EditorRuntimeContext`) to enforce access control in tools and workflows.

---
Last updated: 2025-11-26
12 changes: 10 additions & 2 deletions src/mastra/agents/researchAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export type UserTier = 'free' | 'pro' | 'enterprise'
export interface ResearchRuntimeContext {
'user-tier': UserTier
language: 'en' | 'es' | 'ja' | 'fr'
// Optional runtime fields the server middleware may populate
userId?: string
researchPhase?: 'initial' | 'followup' | 'validation' | string
}
log.info('Initializing Research Agent...')

Expand All @@ -46,13 +49,18 @@ export const researchAgent = new Agent({
// runtimeContext is read at invocation time
const userTier = requestContext.get('user-tier') ?? 'free'
const language = requestContext.get('language') ?? 'en'
const userId = requestContext.get('userId') ?? 'anonymous'
const researchPhase = requestContext.get('researchPhase') ?? 'initial'

return {
role: 'system',
content: `
<role>

Tier: ${userTier}
Language: ${language}
UserId: ${userId}
Research Phase: ${researchPhase}

You are a Senior Research Analyst. Your goal is to research topics thoroughly by following a precise, multi-phase process.
</role>
Expand Down Expand Up @@ -160,8 +168,8 @@ export const researchAgent = new Agent({
// higher quality (chat style) for enterprise
return google.chat('gemini-3-pro-preview')
} else if (userTier === 'pro') {
// Chat bison for pro as well
return googleAI
// cheaper/faster model for pro tier
return 'google/gemini-2.5-flash-preview-09-2025'
}
// cheaper/faster model for free tier
return google.chat('gemini-2.5-flash-preview-09-2025')
Expand Down
97 changes: 66 additions & 31 deletions src/mastra/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ import { researchPaperAgent } from './agents/researchPaperAgent';

// Utility Agents
import { daneNewContributor } from './workflows/new-contributor';
import { calendarAgent } from './agents/calendarAgent';
import { bgColorAgent } from './agents/bgColorAgent';
import { danePackagePublisher } from './agents/package-publisher';

// Financial Chart Agents
import {
Expand All @@ -72,6 +75,7 @@ import { codingA2ACoordinator } from './a2a/codingA2ACoordinator';

// Workflows
import { trace } from "@opentelemetry/api";
import type { RequestContext } from '@mastra/core/request-context';
import { acpAgent } from './agents/acpAgent';
import { businessStrategyAgent, complianceMonitoringAgent, contractAnalysisAgent, legalResearchAgent } from "./agents/businessLegalAgents";
import { dane, daneChangeLog, daneCommitMessage, daneIssueLabeler, daneLinkChecker } from './agents/dane';
Expand Down Expand Up @@ -140,6 +144,11 @@ export const mastra = new Mastra({
daneLinkChecker,
daneChangeLog,
dane,
// Calendar and misc
calendarAgent,
bgColorAgent,
// Package publisher
danePackagePublisher,
// Financial Chart Agents
chartTypeAdvisorAgent,
chartDataProcessorAgent,
Expand Down Expand Up @@ -453,37 +462,63 @@ export const mastra = new Mastra({
sendSources: true,
}),
],
// cors: {
// origin: ["*"], // Allow specific origins or '*' for all
// allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
// allowHeaders: ["Content-Type", "Authorization"],
// exposeHeaders: ["Content-Length", "X-Requested-With"],
// credentials: false,
// },
// middleware: [
// Middleware to extract data from the request body
// async (c, next) => {
// const runtimeContext = c.get("runtimeContext");
//
// if (c.req.method === "POST") {
// try {
// const clonedReq = c.req.raw.clone();
/// const body = await clonedReq.json();
//
// Ensure body and body.data are objects before using them
// if (body !== null && typeof body === 'object' && body.data !== null && typeof body.data === 'object') {
// const data = body.data as Record<string, unknown>;
// for (const [key, value] of Object.entries(data)) {
// runtimeContext.set(key, value);
// }
// }
// } catch {
// log.error("Failed to parse request body for middleware");
// }
// }
// await next();
// },
//0 ],
middleware: [
// Populate RequestContext with real runtime values derived from headers (used by agents/tools)
async (c, next) => {
const country = c.req.header('CF-IPCountry') ?? ''
const authHeader = c.req.header('Authorization') ?? ''
const headerUserId = c.req.header('x-user-id')
const headerUserTier = c.req.header('x-user-tier')
const acceptLanguage = c.req.header('accept-language') ?? ''
const researchPhaseHeader = c.req.header('x-research-phase')

const requestContext = c.get('requestContext') as RequestContext | undefined
if (requestContext?.set) {
// Temperature unit (from Cloudflare geo header)
const unit = country === 'US' ? 'fahrenheit' : 'celsius'
requestContext.set('temperature-unit', unit)

// userId: prefer explicit header, otherwise try to parse from a bearer token (format: "Bearer user:<id>")
let userId = headerUserId
if (!userId && authHeader !== null && authHeader !== '' && authHeader.startsWith('Bearer ')) {
const token = authHeader.slice('Bearer '.length)
const exec = /user:([^;\s]+)/.exec(token)
if (exec) { userId = exec[1] }
}
if (userId !== null && userId !== '') { requestContext.set('userId', userId) }

// user-tier: prefer explicit header, otherwise derive from token hints
let userTier = headerUserTier
if (!userTier && authHeader !== null && authHeader !== '' && authHeader.startsWith('Bearer ')) {
const token = authHeader.slice('Bearer '.length)
if (token.includes('enterprise')) { userTier = 'enterprise' }
else if (token.includes('pro')) { userTier = 'pro' }
else { userTier = 'free' }
}
if (userTier !== null && userTier !== '') { requestContext.set('user-tier', userTier) }

// language: prefer Accept-Language header (primary language subtag), fallback to 'en'
const language = acceptLanguage.split(',')[0]?.split('-')[0] ?? 'en'
const supported = ['en', 'es', 'ja', 'fr']
requestContext.set('language', supported.includes(language) ? language : 'en')

// research phase
requestContext.set('researchPhase', researchPhaseHeader ?? 'initial')

// runtime API key (for tools that may accept runtimeContext.apiKey)
// if (apiKeyHeader !== null && apiKeyHeader !== '') { requestContext.set('apiKey', apiKeyHeader) }
}

await next()
},
// Request timing logger
async (c, next) => {
const start = Date.now()
await next()
const duration = Date.now() - start
log.info(`${c.req.method} ${c.req.url} - ${duration}ms`)
},
]
}
});

Expand Down
7 changes: 5 additions & 2 deletions src/mastra/tools/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ await context?.writer?.custom({
type: "data-tool-progress",
data: {
status: "in-progress", // "in-progress" | "done"
message: "Descriptive progress message...",
message: "Descriptive progress message ${inputData.context}....`,",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: malformed template string in documentation example - has mismatched quotes and backticks

Suggested change
message: "Descriptive progress message ${inputData.context}....`,",
message: "Descriptive progress message...",
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/tools/AGENTS.md
Line: 105:105

Comment:
**syntax:** malformed template string in documentation example - has mismatched quotes and backticks

```suggestion
    message: "Descriptive progress message...",
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There appears to be a typo in the example message string. It contains an extra backtick and a comma at the end, which could be confusing for developers referencing this documentation.

Suggested change
message: "Descriptive progress message ${inputData.context}....`,",
message: `Descriptive progress message ${inputData.context}....`,

Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string literal template interpolation syntax has incorrect quoting. The backtick for template literal starts mid-string and ends with a mismatched quote character. This appears to be:

message: "Descriptive progress message ${inputData.context}....`,",

Should likely be either a full template literal or a regular string without interpolation.

Suggested change
message: "Descriptive progress message ${inputData.context}....`,",
message: `Descriptive progress message ${inputData.context}....`,

Copilot uses AI. Check for mistakes.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incorrect template literal syntax in example.

The progress message example mixes double quotes with template interpolation syntax, which is invalid JavaScript. Template literals must use backticks, not double quotes.

Apply this diff to correct the syntax:

-    message: "Descriptive progress message ${inputData.context}....`,",
+    message: `Descriptive progress message for ${inputData.symbol}...`,

Compare with the correct example on line 128:

message: `📈 Fetching Alpha Vantage crypto data for ${inputData.symbol}/${inputData.market}`,

Additionally, consider using a more specific field name (like symbol, market, etc.) instead of the generic inputData.context to better illustrate the pattern.

🤖 Prompt for AI Agents
In src/mastra/tools/AGENTS.md around line 105, the example uses double quotes
with ${...} interpolation which is invalid; change the string to a template
literal using backticks and replace the generic inputData.context with a more
specific field (e.g., inputData.symbol or inputData.market) to mirror the
correct example on line 128 so the message becomes a backtick-delimited template
literal that interpolates a concrete field.

stage: "tool-name" // Tool identifier (same as id)
},
id: "tool-name" // Tool identifier outside data object
Expand Down Expand Up @@ -132,6 +132,8 @@ await context?.writer?.custom({
});
```

> Note: These conventions are tracked in the memory bank task `TASK001-update-2025-12-14`. Recent commits synced tool implementations and memory-bank progress notes to follow this standard.

## Testing
97% coverage via Vitest. Run:

Expand All @@ -146,7 +148,7 @@ From `package.json`: `@mastra/core`, `zod`, `serpapi`, `playwright`, `cheerio`,

---

**Last updated:** 2025-11-27
**Last updated:** 2025-12-14

## Related

Expand All @@ -158,6 +160,7 @@ From `package.json`: `@mastra/core`, `zod`, `serpapi`, `playwright`, `cheerio`,

| Version | Date | Changes |
|---------|------|---------|
| 2.4.0 | 2025-12-14 | Custom Agent nest events|
| 2.3.0 | 2025-11-28 | Added Financial Chart Tools: chartSupervisorTool, chartGeneratorTool, chartDataProcessorTool, chartTypeAdvisorTool |
Comment on lines +163 to 164
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Vague changelog entry.

The changelog description "Custom Agent nest events" is unclear and doesn't adequately describe the changes documented in this PR. Based on the update notes in TASK001-update-2025-12-14.md, the changes involve standardizing progress events (data-tool-progress), normalizing legacy formats, and establishing streaming conventions.

Consider a more descriptive changelog entry:

-| 2.4.0 | 2025-12-14 | Custom Agent nest events|
+| 2.4.0 | 2025-12-14 | Standardized tool progress events (data-tool-progress) and streaming patterns; normalized legacy data-tool-agent events |

This provides clearer information about what changed and why users would care about this version.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| 2.4.0 | 2025-12-14 | Custom Agent nest events|
| 2.3.0 | 2025-11-28 | Added Financial Chart Tools: chartSupervisorTool, chartGeneratorTool, chartDataProcessorTool, chartTypeAdvisorTool |
| 2.4.0 | 2025-12-14 | Standardized tool progress events (data-tool-progress) and streaming patterns; normalized legacy data-tool-agent events |
| 2.3.0 | 2025-11-28 | Added Financial Chart Tools: chartSupervisorTool, chartGeneratorTool, chartDataProcessorTool, chartTypeAdvisorTool |
🤖 Prompt for AI Agents
In src/mastra/tools/AGENTS.md around lines 163-164, the changelog entry "Custom
Agent nest events" is too vague; replace it with a concise, descriptive entry
that summarizes the actual changes from TASK001-update-2025-12-14.md (e.g.,
"Standardized data-tool-progress events, normalized legacy event formats to the
new schema, and established streaming conventions for agent tool output"),
mention the impact on consumers (event names and format changes, backward
compatibility handling), and include a one-line note pointing readers to
TASK001-update-2025-12-14.md for full details.

| 2.2.0 | 2025-11-27 | Full 30+ tools catalogued w/ badges, categories (financial/RAG/web/document), tests status, relative links |
| 2.1.0 | 2025-11-26 | Meta update, 30+ claim |
Expand Down
Loading
Loading