@kirosnn/mosaic 0.71.0 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -5
- package/package.json +4 -2
- package/src/agent/Agent.ts +353 -131
- package/src/agent/context.ts +4 -4
- package/src/agent/prompts/systemPrompt.ts +15 -6
- package/src/agent/prompts/toolsPrompt.ts +75 -10
- package/src/agent/provider/anthropic.ts +100 -100
- package/src/agent/provider/google.ts +102 -102
- package/src/agent/provider/mistral.ts +95 -95
- package/src/agent/provider/ollama.ts +77 -60
- package/src/agent/provider/openai.ts +42 -38
- package/src/agent/provider/rateLimit.ts +178 -0
- package/src/agent/provider/xai.ts +99 -99
- package/src/agent/tools/definitions.ts +19 -9
- package/src/agent/tools/executor.ts +95 -85
- package/src/agent/tools/exploreExecutor.ts +8 -10
- package/src/agent/tools/grep.ts +30 -29
- package/src/agent/tools/question.ts +7 -1
- package/src/agent/types.ts +9 -8
- package/src/components/App.tsx +45 -45
- package/src/components/CustomInput.tsx +214 -36
- package/src/components/Main.tsx +1146 -954
- package/src/components/Setup.tsx +1 -1
- package/src/components/Welcome.tsx +1 -1
- package/src/components/main/ApprovalPanel.tsx +4 -3
- package/src/components/main/ChatPage.tsx +858 -675
- package/src/components/main/HomePage.tsx +53 -38
- package/src/components/main/QuestionPanel.tsx +52 -7
- package/src/components/main/ThinkingIndicator.tsx +2 -1
- package/src/index.tsx +50 -20
- package/src/mcp/approvalPolicy.ts +148 -0
- package/src/mcp/cli/add.ts +185 -0
- package/src/mcp/cli/doctor.ts +77 -0
- package/src/mcp/cli/index.ts +85 -0
- package/src/mcp/cli/list.ts +50 -0
- package/src/mcp/cli/logs.ts +24 -0
- package/src/mcp/cli/manage.ts +99 -0
- package/src/mcp/cli/show.ts +53 -0
- package/src/mcp/cli/tools.ts +77 -0
- package/src/mcp/config.ts +223 -0
- package/src/mcp/index.ts +80 -0
- package/src/mcp/processManager.ts +299 -0
- package/src/mcp/rateLimiter.ts +50 -0
- package/src/mcp/registry.ts +151 -0
- package/src/mcp/schemaConverter.ts +100 -0
- package/src/mcp/servers/navigation.ts +854 -0
- package/src/mcp/toolCatalog.ts +169 -0
- package/src/mcp/types.ts +95 -0
- package/src/utils/approvalBridge.ts +17 -5
- package/src/utils/commands/compact.ts +30 -0
- package/src/utils/commands/echo.ts +1 -1
- package/src/utils/commands/index.ts +4 -6
- package/src/utils/commands/new.ts +15 -0
- package/src/utils/commands/types.ts +3 -0
- package/src/utils/config.ts +3 -1
- package/src/utils/diffRendering.tsx +1 -3
- package/src/utils/exploreBridge.ts +10 -0
- package/src/utils/markdown.tsx +163 -99
- package/src/utils/models.ts +31 -9
- package/src/utils/questionBridge.ts +36 -1
- package/src/utils/tokenEstimator.ts +32 -0
- package/src/utils/toolFormatting.ts +268 -7
- package/src/web/app.tsx +72 -72
- package/src/web/components/HomePage.tsx +7 -7
- package/src/web/components/MessageItem.tsx +22 -22
- package/src/web/components/QuestionPanel.tsx +72 -12
- package/src/web/components/Sidebar.tsx +0 -2
- package/src/web/components/ThinkingIndicator.tsx +1 -0
- package/src/web/server.tsx +767 -683
- package/src/utils/commands/redo.ts +0 -74
- package/src/utils/commands/sessions.ts +0 -129
- package/src/utils/commands/undo.ts +0 -75
- package/src/utils/undoRedo.ts +0 -429
- package/src/utils/undoRedoBridge.ts +0 -45
- package/src/utils/undoRedoDb.ts +0 -338
|
@@ -60,7 +60,7 @@ IMPORTANT: Use "**/" prefix for recursive search:
|
|
|
60
60
|
### grep
|
|
61
61
|
Search for text within files.
|
|
62
62
|
- query (string, required): Text to search for
|
|
63
|
-
- file_type (string, optional): ts, tsx, js,
|
|
63
|
+
- file_type (string, optional): language or extension (ts, tsx, js, txt, .env)
|
|
64
64
|
- pattern (string, optional): Glob pattern for files
|
|
65
65
|
- regex (boolean, optional): Treat query as regex
|
|
66
66
|
- context (number, optional): Lines around matches
|
|
@@ -84,8 +84,16 @@ Track progress on multi-step tasks.
|
|
|
84
84
|
- step (string): Action description
|
|
85
85
|
- status: "pending" | "in_progress" | "completed"
|
|
86
86
|
|
|
87
|
-
Use plan for
|
|
88
|
-
|
|
87
|
+
Use plan for any task that is not a single obvious step. Default to planning when unsure.
|
|
88
|
+
Use plan when there are 2+ actions, file changes, or unclear success criteria.
|
|
89
|
+
Plan rules:
|
|
90
|
+
- Keep plans short (3-6 steps) and outcome-focused
|
|
91
|
+
- Exactly one step can be "in_progress" at a time
|
|
92
|
+
- Mark a step "completed" before starting the next
|
|
93
|
+
- Keep unstarted steps "pending"
|
|
94
|
+
Always update the plan after each step.
|
|
95
|
+
Never output a plan as plain text, JSON, or tags. Use the plan tool call only.
|
|
96
|
+
Never mark multiple future steps as completed in a single update. Show progress incrementally as each step is done.
|
|
89
97
|
|
|
90
98
|
## Web Access
|
|
91
99
|
|
|
@@ -117,6 +125,11 @@ Ask user with predefined options. ONLY way to ask questions.
|
|
|
117
125
|
- options (array, required): At least 2 options
|
|
118
126
|
- label (string): Display text
|
|
119
127
|
- value (string|null): Return value
|
|
128
|
+
- group (string, optional): Group header for consecutive options with the same group
|
|
129
|
+
- timeout (number, optional): Seconds before the question auto-rejects
|
|
130
|
+
- validation (object, optional): Regex validation for custom text input
|
|
131
|
+
- pattern (string): Regex pattern the custom text must match
|
|
132
|
+
- message (string, optional): Error message shown on validation failure
|
|
120
133
|
|
|
121
134
|
CRITICAL: Never ask questions in plain text. Always use this tool.
|
|
122
135
|
|
|
@@ -210,12 +223,64 @@ NEVER ask questions in plain text. The question tool is MANDATORY.
|
|
|
210
223
|
|
|
211
224
|
# Workflow Summary
|
|
212
225
|
|
|
213
|
-
1.
|
|
214
|
-
2.
|
|
215
|
-
3.
|
|
216
|
-
4.
|
|
217
|
-
5.
|
|
226
|
+
1. PLAN: Use plan unless the task is trivial (single obvious action)
|
|
227
|
+
2. COMMUNICATE: Say what you're about to do
|
|
228
|
+
3. READ: Always read files before modifying
|
|
229
|
+
4. ACT: Use the appropriate tool
|
|
230
|
+
5. VERIFY: Run tests/builds to confirm
|
|
231
|
+
6. REPORT: Summarize what was done`;
|
|
218
232
|
|
|
219
|
-
export function getToolsPrompt(): string {
|
|
220
|
-
|
|
233
|
+
export function getToolsPrompt(mcpToolInfos?: Array<{ serverId: string; name: string; description: string; inputSchema: Record<string, unknown>; canonicalId: string; safeId: string }>): string {
|
|
234
|
+
if (!mcpToolInfos || mcpToolInfos.length === 0) {
|
|
235
|
+
return TOOLS_PROMPT;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const mcpSection = buildMcpToolsSection(mcpToolInfos);
|
|
239
|
+
return TOOLS_PROMPT + '\n\n' + mcpSection;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function buildMcpToolsSection(tools: Array<{ serverId: string; name: string; description: string; inputSchema: Record<string, unknown>; canonicalId: string; safeId: string }>): string {
|
|
243
|
+
const lines: string[] = [];
|
|
244
|
+
lines.push('## External Tools (MCP)');
|
|
245
|
+
lines.push('');
|
|
246
|
+
lines.push('These tools are provided by external MCP servers. Call them by their tool name.');
|
|
247
|
+
lines.push('They may require approval before execution.');
|
|
248
|
+
lines.push('');
|
|
249
|
+
|
|
250
|
+
const byServer = new Map<string, typeof tools>();
|
|
251
|
+
for (const t of tools) {
|
|
252
|
+
const list = byServer.get(t.serverId) || [];
|
|
253
|
+
list.push(t);
|
|
254
|
+
byServer.set(t.serverId, list);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
for (const [serverId, serverTools] of byServer) {
|
|
258
|
+
lines.push(`### Server: ${serverId}`);
|
|
259
|
+
lines.push('');
|
|
260
|
+
for (const t of serverTools) {
|
|
261
|
+
lines.push(`#### ${t.safeId}`);
|
|
262
|
+
if (t.description) {
|
|
263
|
+
lines.push(t.description);
|
|
264
|
+
}
|
|
265
|
+
const schema = t.inputSchema;
|
|
266
|
+
if (schema && typeof schema === 'object' && schema.properties) {
|
|
267
|
+
const props = schema.properties as Record<string, Record<string, unknown>>;
|
|
268
|
+
const required = (schema.required || []) as string[];
|
|
269
|
+
const paramLines: string[] = [];
|
|
270
|
+
for (const [key, propSchema] of Object.entries(props)) {
|
|
271
|
+
const type = propSchema.type || 'unknown';
|
|
272
|
+
const desc = propSchema.description || '';
|
|
273
|
+
const req = required.includes(key) ? 'required' : 'optional';
|
|
274
|
+
paramLines.push(`- ${key} (${type}, ${req})${desc ? ': ' + desc : ''}`);
|
|
275
|
+
}
|
|
276
|
+
if (paramLines.length > 0) {
|
|
277
|
+
lines.push('Parameters:');
|
|
278
|
+
lines.push(...paramLines);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
lines.push('');
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return lines.join('\n');
|
|
221
286
|
}
|
|
@@ -2,6 +2,7 @@ import { streamText, CoreMessage } from 'ai';
|
|
|
2
2
|
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
3
3
|
import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
|
|
4
4
|
import { shouldEnableReasoning } from './reasoning';
|
|
5
|
+
import { getRetryDecision, normalizeError, runWithRetry } from './rateLimit';
|
|
5
6
|
|
|
6
7
|
export class AnthropicProvider implements Provider {
|
|
7
8
|
async *sendMessage(
|
|
@@ -17,107 +18,106 @@ export class AnthropicProvider implements Provider {
|
|
|
17
18
|
apiKey: cleanApiKey,
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
try {
|
|
22
|
+
let stepCounter = 0;
|
|
23
|
+
|
|
24
|
+
yield* runWithRetry(async function* () {
|
|
25
|
+
const result = streamText({
|
|
26
|
+
model: anthropic(cleanModel),
|
|
27
|
+
messages: messages,
|
|
28
|
+
system: config.systemPrompt,
|
|
29
|
+
tools: config.tools,
|
|
30
|
+
maxSteps: config.maxSteps || 100,
|
|
31
|
+
abortSignal: options?.abortSignal,
|
|
32
|
+
experimental_providerMetadata: reasoningEnabled
|
|
33
|
+
? {
|
|
34
|
+
anthropic: {
|
|
35
|
+
thinkingBudgetTokens: 10000,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
: undefined,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
for await (const chunk of result.fullStream as any) {
|
|
42
|
+
const c: any = chunk;
|
|
43
|
+
switch (c.type) {
|
|
44
|
+
case 'reasoning':
|
|
45
|
+
if (c.textDelta) {
|
|
46
|
+
yield {
|
|
47
|
+
type: 'reasoning-delta',
|
|
48
|
+
content: c.textDelta,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
case 'text-delta':
|
|
54
|
+
yield {
|
|
55
|
+
type: 'text-delta',
|
|
56
|
+
content: c.textDelta,
|
|
57
|
+
};
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
case 'step-start':
|
|
61
|
+
yield {
|
|
62
|
+
type: 'step-start',
|
|
63
|
+
stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
|
|
64
|
+
};
|
|
65
|
+
stepCounter++;
|
|
66
|
+
break;
|
|
67
|
+
|
|
68
|
+
case 'step-finish':
|
|
69
|
+
yield {
|
|
70
|
+
type: 'step-finish',
|
|
71
|
+
stepNumber:
|
|
72
|
+
typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
|
|
73
|
+
finishReason: String(c.finishReason ?? 'stop'),
|
|
74
|
+
};
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case 'tool-call':
|
|
78
|
+
yield {
|
|
79
|
+
type: 'tool-call-end',
|
|
80
|
+
toolCallId: String(c.toolCallId ?? ''),
|
|
81
|
+
toolName: String(c.toolName ?? ''),
|
|
82
|
+
args: (c.args ?? {}) as Record<string, unknown>,
|
|
83
|
+
};
|
|
84
|
+
break;
|
|
85
|
+
|
|
86
|
+
case 'tool-result':
|
|
87
|
+
yield {
|
|
88
|
+
type: 'tool-result',
|
|
89
|
+
toolCallId: String(c.toolCallId ?? ''),
|
|
90
|
+
toolName: String(c.toolName ?? ''),
|
|
91
|
+
result: c.result,
|
|
92
|
+
};
|
|
93
|
+
break;
|
|
94
|
+
|
|
95
|
+
case 'finish':
|
|
96
|
+
yield {
|
|
97
|
+
type: 'finish',
|
|
98
|
+
finishReason: String(c.finishReason ?? 'stop'),
|
|
99
|
+
usage: c.usage,
|
|
100
|
+
};
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
case 'error': {
|
|
104
|
+
const err = normalizeError(c.error);
|
|
105
|
+
const decision = getRetryDecision(err);
|
|
106
|
+
if (decision.shouldRetry) {
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
yield {
|
|
110
|
+
type: 'error',
|
|
111
|
+
error: err.message,
|
|
112
|
+
};
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
32
116
|
}
|
|
33
|
-
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let stepCounter = 0;
|
|
38
|
-
|
|
39
|
-
for await (const chunk of result.fullStream as any) {
|
|
40
|
-
const c: any = chunk;
|
|
41
|
-
switch (c.type) {
|
|
42
|
-
case 'reasoning':
|
|
43
|
-
if (c.textDelta) {
|
|
44
|
-
yield {
|
|
45
|
-
type: 'reasoning-delta',
|
|
46
|
-
content: c.textDelta,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
break;
|
|
50
|
-
|
|
51
|
-
case 'text-delta':
|
|
52
|
-
yield {
|
|
53
|
-
type: 'text-delta',
|
|
54
|
-
content: c.textDelta,
|
|
55
|
-
};
|
|
56
|
-
break;
|
|
57
|
-
|
|
58
|
-
case 'step-start':
|
|
59
|
-
yield {
|
|
60
|
-
type: 'step-start',
|
|
61
|
-
stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
|
|
62
|
-
};
|
|
63
|
-
stepCounter++;
|
|
64
|
-
break;
|
|
65
|
-
|
|
66
|
-
case 'step-finish':
|
|
67
|
-
yield {
|
|
68
|
-
type: 'step-finish',
|
|
69
|
-
stepNumber:
|
|
70
|
-
typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
|
|
71
|
-
finishReason: String(c.finishReason ?? 'stop'),
|
|
72
|
-
};
|
|
73
|
-
break;
|
|
74
|
-
|
|
75
|
-
case 'tool-call':
|
|
76
|
-
yield {
|
|
77
|
-
type: 'tool-call-end',
|
|
78
|
-
toolCallId: String(c.toolCallId ?? ''),
|
|
79
|
-
toolName: String(c.toolName ?? ''),
|
|
80
|
-
args: (c.args ?? {}) as Record<string, unknown>,
|
|
81
|
-
};
|
|
82
|
-
break;
|
|
83
|
-
|
|
84
|
-
case 'tool-result':
|
|
85
|
-
yield {
|
|
86
|
-
type: 'tool-result',
|
|
87
|
-
toolCallId: String(c.toolCallId ?? ''),
|
|
88
|
-
toolName: String(c.toolName ?? ''),
|
|
89
|
-
result: c.result,
|
|
90
|
-
};
|
|
91
|
-
break;
|
|
92
|
-
|
|
93
|
-
case 'finish':
|
|
94
|
-
yield {
|
|
95
|
-
type: 'finish',
|
|
96
|
-
finishReason: String(c.finishReason ?? 'stop'),
|
|
97
|
-
usage: c.usage,
|
|
98
|
-
};
|
|
99
|
-
break;
|
|
100
|
-
|
|
101
|
-
case 'error':
|
|
102
|
-
{
|
|
103
|
-
const err = c.error;
|
|
104
|
-
const msg =
|
|
105
|
-
err instanceof Error
|
|
106
|
-
? err.message
|
|
107
|
-
: typeof err === 'string'
|
|
108
|
-
? err
|
|
109
|
-
: 'Unknown error';
|
|
110
|
-
yield {
|
|
111
|
-
type: 'error',
|
|
112
|
-
error: msg,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
} catch (error) {
|
|
119
|
-
if (options?.abortSignal?.aborted) return;
|
|
120
|
-
yield {
|
|
117
|
+
}, { abortSignal: options?.abortSignal });
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (options?.abortSignal?.aborted) return;
|
|
120
|
+
yield {
|
|
121
121
|
type: 'error',
|
|
122
122
|
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
123
123
|
};
|
|
@@ -2,6 +2,7 @@ import { streamText, CoreMessage } from 'ai';
|
|
|
2
2
|
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
3
3
|
import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
|
|
4
4
|
import { shouldEnableReasoning } from './reasoning';
|
|
5
|
+
import { getRetryDecision, normalizeError, runWithRetry } from './rateLimit';
|
|
5
6
|
|
|
6
7
|
export class GoogleProvider implements Provider {
|
|
7
8
|
async *sendMessage(
|
|
@@ -17,109 +18,108 @@ export class GoogleProvider implements Provider {
|
|
|
17
18
|
apiKey: cleanApiKey,
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
try {
|
|
22
|
+
let stepCounter = 0;
|
|
23
|
+
|
|
24
|
+
yield* runWithRetry(async function* () {
|
|
25
|
+
const result = streamText({
|
|
26
|
+
model: google(cleanModel),
|
|
27
|
+
messages: messages,
|
|
28
|
+
system: config.systemPrompt,
|
|
29
|
+
tools: config.tools,
|
|
30
|
+
maxSteps: config.maxSteps || 100,
|
|
31
|
+
abortSignal: options?.abortSignal,
|
|
32
|
+
providerOptions: reasoningEnabled
|
|
33
|
+
? {
|
|
34
|
+
google: {
|
|
35
|
+
thinkingConfig: {
|
|
36
|
+
style: 'THINKING_STYLE_DETAILED',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
: undefined,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
for await (const chunk of result.fullStream as any) {
|
|
44
|
+
const c: any = chunk;
|
|
45
|
+
switch (c.type) {
|
|
46
|
+
case 'reasoning':
|
|
47
|
+
if (c.textDelta) {
|
|
48
|
+
yield {
|
|
49
|
+
type: 'reasoning-delta',
|
|
50
|
+
content: c.textDelta,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
|
|
55
|
+
case 'text-delta':
|
|
56
|
+
yield {
|
|
57
|
+
type: 'text-delta',
|
|
58
|
+
content: c.textDelta,
|
|
59
|
+
};
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
case 'step-start':
|
|
63
|
+
yield {
|
|
64
|
+
type: 'step-start',
|
|
65
|
+
stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
|
|
66
|
+
};
|
|
67
|
+
stepCounter++;
|
|
68
|
+
break;
|
|
69
|
+
|
|
70
|
+
case 'step-finish':
|
|
71
|
+
yield {
|
|
72
|
+
type: 'step-finish',
|
|
73
|
+
stepNumber:
|
|
74
|
+
typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
|
|
75
|
+
finishReason: String(c.finishReason ?? 'stop'),
|
|
76
|
+
};
|
|
77
|
+
break;
|
|
78
|
+
|
|
79
|
+
case 'tool-call':
|
|
80
|
+
yield {
|
|
81
|
+
type: 'tool-call-end',
|
|
82
|
+
toolCallId: String(c.toolCallId ?? ''),
|
|
83
|
+
toolName: String(c.toolName ?? ''),
|
|
84
|
+
args: (c.args ?? {}) as Record<string, unknown>,
|
|
85
|
+
};
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'tool-result':
|
|
89
|
+
yield {
|
|
90
|
+
type: 'tool-result',
|
|
91
|
+
toolCallId: String(c.toolCallId ?? ''),
|
|
92
|
+
toolName: String(c.toolName ?? ''),
|
|
93
|
+
result: c.result,
|
|
94
|
+
};
|
|
95
|
+
break;
|
|
96
|
+
|
|
97
|
+
case 'finish':
|
|
98
|
+
yield {
|
|
99
|
+
type: 'finish',
|
|
100
|
+
finishReason: String(c.finishReason ?? 'stop'),
|
|
101
|
+
usage: c.usage,
|
|
102
|
+
};
|
|
103
|
+
break;
|
|
104
|
+
|
|
105
|
+
case 'error': {
|
|
106
|
+
const err = normalizeError(c.error);
|
|
107
|
+
const decision = getRetryDecision(err);
|
|
108
|
+
if (decision.shouldRetry) {
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
yield {
|
|
112
|
+
type: 'error',
|
|
113
|
+
error: err.message,
|
|
114
|
+
};
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
34
118
|
}
|
|
35
|
-
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let stepCounter = 0;
|
|
40
|
-
|
|
41
|
-
for await (const chunk of result.fullStream as any) {
|
|
42
|
-
const c: any = chunk;
|
|
43
|
-
switch (c.type) {
|
|
44
|
-
case 'reasoning':
|
|
45
|
-
if (c.textDelta) {
|
|
46
|
-
yield {
|
|
47
|
-
type: 'reasoning-delta',
|
|
48
|
-
content: c.textDelta,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
break;
|
|
52
|
-
|
|
53
|
-
case 'text-delta':
|
|
54
|
-
yield {
|
|
55
|
-
type: 'text-delta',
|
|
56
|
-
content: c.textDelta,
|
|
57
|
-
};
|
|
58
|
-
break;
|
|
59
|
-
|
|
60
|
-
case 'step-start':
|
|
61
|
-
yield {
|
|
62
|
-
type: 'step-start',
|
|
63
|
-
stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
|
|
64
|
-
};
|
|
65
|
-
stepCounter++;
|
|
66
|
-
break;
|
|
67
|
-
|
|
68
|
-
case 'step-finish':
|
|
69
|
-
yield {
|
|
70
|
-
type: 'step-finish',
|
|
71
|
-
stepNumber:
|
|
72
|
-
typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
|
|
73
|
-
finishReason: String(c.finishReason ?? 'stop'),
|
|
74
|
-
};
|
|
75
|
-
break;
|
|
76
|
-
|
|
77
|
-
case 'tool-call':
|
|
78
|
-
yield {
|
|
79
|
-
type: 'tool-call-end',
|
|
80
|
-
toolCallId: String(c.toolCallId ?? ''),
|
|
81
|
-
toolName: String(c.toolName ?? ''),
|
|
82
|
-
args: (c.args ?? {}) as Record<string, unknown>,
|
|
83
|
-
};
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case 'tool-result':
|
|
87
|
-
yield {
|
|
88
|
-
type: 'tool-result',
|
|
89
|
-
toolCallId: String(c.toolCallId ?? ''),
|
|
90
|
-
toolName: String(c.toolName ?? ''),
|
|
91
|
-
result: c.result,
|
|
92
|
-
};
|
|
93
|
-
break;
|
|
94
|
-
|
|
95
|
-
case 'finish':
|
|
96
|
-
yield {
|
|
97
|
-
type: 'finish',
|
|
98
|
-
finishReason: String(c.finishReason ?? 'stop'),
|
|
99
|
-
usage: c.usage,
|
|
100
|
-
};
|
|
101
|
-
break;
|
|
102
|
-
|
|
103
|
-
case 'error':
|
|
104
|
-
{
|
|
105
|
-
const err = c.error;
|
|
106
|
-
const msg =
|
|
107
|
-
err instanceof Error
|
|
108
|
-
? err.message
|
|
109
|
-
: typeof err === 'string'
|
|
110
|
-
? err
|
|
111
|
-
: 'Unknown error';
|
|
112
|
-
yield {
|
|
113
|
-
type: 'error',
|
|
114
|
-
error: msg,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
} catch (error) {
|
|
121
|
-
if (options?.abortSignal?.aborted) return;
|
|
122
|
-
yield {
|
|
119
|
+
}, { abortSignal: options?.abortSignal });
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (options?.abortSignal?.aborted) return;
|
|
122
|
+
yield {
|
|
123
123
|
type: 'error',
|
|
124
124
|
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
125
125
|
};
|