Skip to content

Commit d7d9632

Browse files
authored
Merge pull request #52 from ssdeanx/develop
Develop
2 parents 1f144f5 + 1579228 commit d7d9632

34 files changed

Lines changed: 653 additions & 4585 deletions

app/chat/providers/chat-context.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ export function ChatProvider({
321321
}, [messages])
322322

323323
const sendMessage = useCallback(
324-
(text: string, _files?: File[]) => {
324+
(text: string, files?: File[]) => {
325325
if (!text.trim() || isLoading) {return}
326326
setChatError(null)
327327
aiSendMessage({ text: text.trim() })

app/networks/providers/network-context.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,18 +295,28 @@ export function NetworkProvider({
295295
for (const message of messages) {
296296
if (message.role === "assistant" && message.parts !== null) {
297297
for (const [partIndex, part] of message.parts.entries()) {
298-
// Handle agent and workflow progress events
298+
// Handle legacy agent/workflow events by normalizing them into progress events
299299
if (part.type === "data-tool-agent" || part.type === "data-tool-workflow") {
300-
const agentPart = part as { data: AgentDataPart }
301-
const eventData = agentPart.data
300+
const agentPart = part as { data?: AgentDataPart }
301+
const eventData = agentPart.data as Record<string, unknown> | undefined
302+
const dataObj = eventData?.data as Record<string, unknown> | undefined
302303

303-
if (eventData?.data?.text?.trim()) {
304+
const msg = typeof dataObj?.text === 'string' ? dataObj.text
305+
: typeof dataObj?.message === 'string' ? dataObj.message
306+
: typeof eventData?.message === 'string' ? eventData.message
307+
: typeof eventData?.text === 'string' ? eventData.text
308+
: ''
309+
310+
const stage = typeof eventData?.stage === 'string' ? eventData.stage : (typeof dataObj?.stage === 'string' ? dataObj.stage : part.type.replace("data-tool-", ""))
311+
const agentId = typeof eventData?.id === 'string' ? eventData.id : undefined
312+
313+
if (msg && msg.trim().length > 0) {
304314
allProgressEvents.push({
305315
id: `${message.id}-${part.type}-${partIndex}`,
306-
stage: part.type.replace("data-tool-", ""),
316+
stage: String(stage),
307317
status: "in-progress",
308-
message: eventData.data.text,
309-
agentId: eventData.id,
318+
message: msg,
319+
agentId,
310320
timestamp: new Date(),
311321
data: eventData,
312322
})
@@ -318,7 +328,7 @@ export function NetworkProvider({
318328
const progressPart = part as { type: string; data?: { status?: string; message?: string; stage?: string; agentId?: string } }
319329
const eventData = progressPart.data
320330

321-
if (eventData?.status && (eventData.status === "in-progress" || eventData.status === "done" || eventData.status === "error")) {
331+
if (typeof eventData?.status === 'string' && (eventData.status === "in-progress" || eventData.status === "done")) {
322332
allProgressEvents.push({
323333
id: `${message.id}-${part.type}-${partIndex}`,
324334
stage: eventData.stage ?? "progress",

app/workflows/providers/workflow-context.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -319,17 +319,20 @@ export function WorkflowProvider({
319319
}
320320
}
321321

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

327-
if (eventData) {
330+
if (msg && msg.trim().length > 0) {
328331
allProgressEvents.push({
329332
id: `${message.id}-${part.type}-${partIndex}`,
330-
stage: "tool agent",
331-
status: "in-progress",
332-
message: `Agent executing tool`,
333+
stage: String(stage),
334+
status: 'in-progress',
335+
message: msg,
333336
timestamp: new Date(),
334337
data: eventData,
335338
})

eslint.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ export default [
6262
},
6363
},
6464
rules: {
65-
'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
66-
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
65+
'no-unused-vars': ['warn', { }],
66+
'@typescript-eslint/no-unused-vars': ['warn', {}],
6767
'no-console': 'warn',
6868
'no-var': 'warn',
6969
'object-shorthand': 'error',

memory-bank/copilot-rules.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,32 @@ If any fail, do NOT proceed. Fix issues first.
152152

153153
---
154154

155+
## Tool Streaming & Progress Events
156+
157+
All tools must follow the TASK001 streaming convention:
158+
159+
- Prefer the runtime agent instance via `context.mastra.getAgent('<agentId>')` when available, otherwise fall back to the local agent import.
160+
- If the agent exposes a stream API, call `agent.stream(prompt)` returning a `MastraModelOutput` and:
161+
- Pipe `textStream` / `fullStream` to `context.writer` so the UI receives nested chunks
162+
- Await `stream.text` for the final text
163+
- Use `stream.object` when present for structured responses and fall back to JSON parsing of `stream.text`
164+
- If no streaming API, call `agent.generate(prompt)` and parse `response.object` or JSON text as a fallback.
165+
- Emit progress events with the exact format below at start/in-progress/done:
166+
167+
```typescript
168+
await context?.writer?.custom({
169+
type: 'data-tool-progress',
170+
data: {
171+
status: 'in-progress',
172+
message: `📈 Fetching tool-id data for ${inputData.symbol}/${inputData.market}`,
173+
stage: 'tool-id'
174+
},
175+
id: 'tool-id'
176+
});
177+
```
178+
179+
- Update the TASK001 scratchpad (`/memory-bank/tasks/TASK001-tool-streaming.md`) when implementing or changing tool streaming behavior.
180+
155181
## 🎨 UI Component Rules
156182

157183
### Component Locations

memory-bank/memory-bank-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ This document instructs GitHub Copilot on how to:
3737
- Status check → + progress.md
3838
```
3939

40+
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.
4041
### On Context Reset (New Session)
4142

4243
```markdown
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +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
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
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# TASK001 - Update Log (2025-12-14)
2+
3+
Summary of changes performed to align tools with the streaming + progress convention:
4+
5+
- Replaced `data-tool-agent` messages with `data-tool-progress` (standard in-progress/done events) in:
6+
- `src/mastra/tools/evaluateResultTool.ts`
7+
- `src/mastra/tools/extractLearningsTool.ts`
8+
- `src/mastra/tools/editor-agent-tool.ts`
9+
- `src/mastra/tools/copywriter-agent-tool.ts`
10+
11+
- Normalized nested-agent streaming pattern in tools to:
12+
- Prefer `context.mastra.getAgent()` runtime instance if available, otherwise fall back to local agent import
13+
- Use `agent.stream(prompt)` returning `MastraModelOutput` when available
14+
- Pipe `textStream` / `fullStream` to `context.writer`
15+
- Parse `stream.object` or JSON text safely for structured output
16+
17+
- Updated `src/mastra/tools/financial-chart-tools.ts` to use the same streaming pattern and to validate agent capability (check for `generate` or `stream`).
18+
19+
- Updated client-side parsers to normalize legacy `data-tool-agent` parts into `data-tool-progress` events:
20+
- `app/networks/providers/network-context.tsx`
21+
- `app/workflows/providers/workflow-context.tsx`
22+
23+
- Updated `src/mastra/tools/AGENTS.md` with a note referencing this task and the progress convention.
24+
25+
Notes:
26+
- Tests will be added next to verify that progress events and streaming behavior are emitted consistently. (Pending)
27+
- If you'd like, I can add/restore unit tests and run the test suite now.

src/mastra/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ This folder contains the middleware and high-level components that define Mastra
4545

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

5050
---
5151
Last updated: 2025-11-26

src/mastra/agents/researchAgent.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export type UserTier = 'free' | 'pro' | 'enterprise'
3434
export interface ResearchRuntimeContext {
3535
'user-tier': UserTier
3636
language: 'en' | 'es' | 'ja' | 'fr'
37+
// Optional runtime fields the server middleware may populate
38+
userId?: string
39+
researchPhase?: 'initial' | 'followup' | 'validation' | string
3740
}
3841
log.info('Initializing Research Agent...')
3942

@@ -46,13 +49,18 @@ export const researchAgent = new Agent({
4649
// runtimeContext is read at invocation time
4750
const userTier = requestContext.get('user-tier') ?? 'free'
4851
const language = requestContext.get('language') ?? 'en'
52+
const userId = requestContext.get('userId') ?? 'anonymous'
53+
const researchPhase = requestContext.get('researchPhase') ?? 'initial'
54+
4955
return {
5056
role: 'system',
5157
content: `
5258
<role>
5359
5460
Tier: ${userTier}
5561
Language: ${language}
62+
UserId: ${userId}
63+
Research Phase: ${researchPhase}
5664
5765
You are a Senior Research Analyst. Your goal is to research topics thoroughly by following a precise, multi-phase process.
5866
</role>
@@ -160,8 +168,8 @@ export const researchAgent = new Agent({
160168
// higher quality (chat style) for enterprise
161169
return google.chat('gemini-3-pro-preview')
162170
} else if (userTier === 'pro') {
163-
// Chat bison for pro as well
164-
return googleAI
171+
// cheaper/faster model for pro tier
172+
return 'google/gemini-2.5-flash-preview-09-2025'
165173
}
166174
// cheaper/faster model for free tier
167175
return google.chat('gemini-2.5-flash-preview-09-2025')

0 commit comments

Comments
 (0)