@soulcraft/sdk 1.7.0 → 2.0.1
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/dist/client/create-client-sdk.d.ts +16 -2
- package/dist/client/create-client-sdk.d.ts.map +1 -1
- package/dist/client/create-client-sdk.js +2 -7
- package/dist/client/create-client-sdk.js.map +1 -1
- package/dist/client/index.d.ts +44 -37
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +59 -44
- package/dist/client/index.js.map +1 -1
- package/dist/client/namespace-proxy.d.ts +108 -0
- package/dist/client/namespace-proxy.d.ts.map +1 -0
- package/dist/client/namespace-proxy.js +151 -0
- package/dist/client/namespace-proxy.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/modules/app-context/index.d.ts +15 -15
- package/dist/modules/app-context/index.d.ts.map +1 -1
- package/dist/modules/app-context/index.js +17 -17
- package/dist/modules/app-context/index.js.map +1 -1
- package/dist/namespaces.d.ts +2942 -0
- package/dist/namespaces.d.ts.map +1 -0
- package/dist/namespaces.js +37 -0
- package/dist/namespaces.js.map +1 -0
- package/dist/rpc.d.ts +156 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +26 -0
- package/dist/rpc.js.map +1 -0
- package/dist/server/create-sdk.d.ts.map +1 -1
- package/dist/server/create-sdk.js +3 -13
- package/dist/server/create-sdk.js.map +1 -1
- package/dist/server/handlers/annotations.d.ts +52 -0
- package/dist/server/handlers/annotations.d.ts.map +1 -0
- package/dist/server/handlers/annotations.js +204 -0
- package/dist/server/handlers/annotations.js.map +1 -0
- package/dist/server/handlers/auth.d.ts +53 -0
- package/dist/server/handlers/auth.d.ts.map +1 -0
- package/dist/server/handlers/auth.js +66 -0
- package/dist/server/handlers/auth.js.map +1 -0
- package/dist/server/handlers/certification.d.ts +32 -0
- package/dist/server/handlers/certification.d.ts.map +1 -0
- package/dist/server/handlers/certification.js +253 -0
- package/dist/server/handlers/certification.js.map +1 -0
- package/dist/server/handlers/chat/conversations.d.ts +91 -0
- package/dist/server/handlers/chat/conversations.d.ts.map +1 -0
- package/dist/server/handlers/chat/conversations.js +314 -0
- package/dist/server/handlers/chat/conversations.js.map +1 -0
- package/dist/server/handlers/chat/delegator.d.ts +144 -0
- package/dist/server/handlers/chat/delegator.d.ts.map +1 -0
- package/dist/server/handlers/chat/delegator.js +431 -0
- package/dist/server/handlers/chat/delegator.js.map +1 -0
- package/dist/server/handlers/chat/engine.d.ts +81 -0
- package/dist/server/handlers/chat/engine.d.ts.map +1 -0
- package/dist/server/handlers/chat/engine.js +446 -0
- package/dist/server/handlers/chat/engine.js.map +1 -0
- package/dist/server/handlers/chat/executor.d.ts +65 -0
- package/dist/server/handlers/chat/executor.d.ts.map +1 -0
- package/dist/server/handlers/chat/executor.js +375 -0
- package/dist/server/handlers/chat/executor.js.map +1 -0
- package/dist/server/handlers/chat/index.d.ts +62 -0
- package/dist/server/handlers/chat/index.d.ts.map +1 -0
- package/dist/server/handlers/chat/index.js +182 -0
- package/dist/server/handlers/chat/index.js.map +1 -0
- package/dist/server/handlers/chat/memory.d.ts +91 -0
- package/dist/server/handlers/chat/memory.d.ts.map +1 -0
- package/dist/server/handlers/chat/memory.js +293 -0
- package/dist/server/handlers/chat/memory.js.map +1 -0
- package/dist/server/handlers/chat/models.d.ts +180 -0
- package/dist/server/handlers/chat/models.d.ts.map +1 -0
- package/dist/server/handlers/chat/models.js +304 -0
- package/dist/server/handlers/chat/models.js.map +1 -0
- package/dist/server/handlers/chat/planner.d.ts +116 -0
- package/dist/server/handlers/chat/planner.d.ts.map +1 -0
- package/dist/server/handlers/chat/planner.js +344 -0
- package/dist/server/handlers/chat/planner.js.map +1 -0
- package/dist/server/handlers/chat/types.d.ts +515 -0
- package/dist/server/handlers/chat/types.d.ts.map +1 -0
- package/dist/server/handlers/chat/types.js +11 -0
- package/dist/server/handlers/chat/types.js.map +1 -0
- package/dist/server/handlers/collections.d.ts +67 -0
- package/dist/server/handlers/collections.d.ts.map +1 -0
- package/dist/server/handlers/collections.js +484 -0
- package/dist/server/handlers/collections.js.map +1 -0
- package/dist/server/handlers/commerce.d.ts +106 -0
- package/dist/server/handlers/commerce.d.ts.map +1 -0
- package/dist/server/handlers/commerce.js +62 -0
- package/dist/server/handlers/commerce.js.map +1 -0
- package/dist/server/handlers/config.d.ts +112 -0
- package/dist/server/handlers/config.d.ts.map +1 -0
- package/dist/server/handlers/config.js +122 -0
- package/dist/server/handlers/config.js.map +1 -0
- package/dist/server/handlers/export.d.ts +72 -0
- package/dist/server/handlers/export.d.ts.map +1 -0
- package/dist/server/handlers/export.js +175 -0
- package/dist/server/handlers/export.js.map +1 -0
- package/dist/server/handlers/formats.d.ts +77 -0
- package/dist/server/handlers/formats.d.ts.map +1 -0
- package/dist/server/handlers/formats.js +65 -0
- package/dist/server/handlers/formats.js.map +1 -0
- package/dist/server/handlers/graph.d.ts +31 -0
- package/dist/server/handlers/graph.d.ts.map +1 -0
- package/dist/server/handlers/graph.js +490 -0
- package/dist/server/handlers/graph.js.map +1 -0
- package/dist/server/handlers/import.d.ts +96 -0
- package/dist/server/handlers/import.d.ts.map +1 -0
- package/dist/server/handlers/import.js +108 -0
- package/dist/server/handlers/import.js.map +1 -0
- package/dist/server/handlers/index.d.ts +68 -0
- package/dist/server/handlers/index.d.ts.map +1 -0
- package/dist/server/handlers/index.js +71 -0
- package/dist/server/handlers/index.js.map +1 -0
- package/dist/server/handlers/media.d.ts +76 -0
- package/dist/server/handlers/media.d.ts.map +1 -0
- package/dist/server/handlers/media.js +53 -0
- package/dist/server/handlers/media.js.map +1 -0
- package/dist/server/handlers/project.d.ts +45 -0
- package/dist/server/handlers/project.d.ts.map +1 -0
- package/dist/server/handlers/project.js +181 -0
- package/dist/server/handlers/project.js.map +1 -0
- package/dist/server/handlers/publish.d.ts +102 -0
- package/dist/server/handlers/publish.d.ts.map +1 -0
- package/dist/server/handlers/publish.js +130 -0
- package/dist/server/handlers/publish.js.map +1 -0
- package/dist/server/handlers/pulse.d.ts +39 -0
- package/dist/server/handlers/pulse.d.ts.map +1 -0
- package/dist/server/handlers/pulse.js +78 -0
- package/dist/server/handlers/pulse.js.map +1 -0
- package/dist/server/handlers/realtime.d.ts +55 -0
- package/dist/server/handlers/realtime.d.ts.map +1 -0
- package/dist/server/handlers/realtime.js +49 -0
- package/dist/server/handlers/realtime.js.map +1 -0
- package/dist/server/handlers/search.d.ts +21 -0
- package/dist/server/handlers/search.d.ts.map +1 -0
- package/dist/server/handlers/search.js +237 -0
- package/dist/server/handlers/search.js.map +1 -0
- package/dist/server/handlers/session.d.ts +47 -0
- package/dist/server/handlers/session.d.ts.map +1 -0
- package/dist/server/handlers/session.js +286 -0
- package/dist/server/handlers/session.js.map +1 -0
- package/dist/server/handlers/settings.d.ts +97 -0
- package/dist/server/handlers/settings.d.ts.map +1 -0
- package/dist/server/handlers/settings.js +131 -0
- package/dist/server/handlers/settings.js.map +1 -0
- package/dist/server/handlers/workspace.d.ts +78 -0
- package/dist/server/handlers/workspace.d.ts.map +1 -0
- package/dist/server/handlers/workspace.js +270 -0
- package/dist/server/handlers/workspace.js.map +1 -0
- package/dist/server/hono-router.d.ts +66 -0
- package/dist/server/hono-router.d.ts.map +1 -0
- package/dist/server/hono-router.js +203 -0
- package/dist/server/hono-router.js.map +1 -0
- package/dist/server/index.d.ts +27 -19
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +30 -18
- package/dist/server/index.js.map +1 -1
- package/dist/server/namespace-router.d.ts +204 -0
- package/dist/server/namespace-router.d.ts.map +1 -0
- package/dist/server/namespace-router.js +262 -0
- package/dist/server/namespace-router.js.map +1 -0
- package/dist/transports/http-namespace.d.ts +210 -0
- package/dist/transports/http-namespace.d.ts.map +1 -0
- package/dist/transports/http-namespace.js +514 -0
- package/dist/transports/http-namespace.js.map +1 -0
- package/dist/types.d.ts +59 -65
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -3
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/chat/delegator
|
|
3
|
+
* @description Tiered model delegation: Sonnet triage → Haiku execute → Sonnet synthesize.
|
|
4
|
+
*
|
|
5
|
+
* The delegator handles normal (non-plan-mode) chat by:
|
|
6
|
+
* 1. **Triage** — Sonnet analyzes the user message and decides: answer directly,
|
|
7
|
+
* delegate specific tasks to Haiku, or recommend Plan Mode for complex work.
|
|
8
|
+
* 2. **Execute** — Haiku runs each delegated task (tool calls). If a task fails,
|
|
9
|
+
* auto-escalates to Sonnet (the fallback model).
|
|
10
|
+
* 3. **Synthesize** — Sonnet combines task results into a coherent response.
|
|
11
|
+
*
|
|
12
|
+
* The delegator uses the injected {@link ChatAIClient} and {@link ToolExecutor},
|
|
13
|
+
* so it works with any product's tool set (Workshop, Venue, Academy).
|
|
14
|
+
*/
|
|
15
|
+
import { DEFAULT_MODEL_TIERS } from './models.js';
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
// System Prompts
|
|
18
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Build the triage system prompt dynamically from available tool definitions.
|
|
21
|
+
*
|
|
22
|
+
* @param tools - Available tool definitions.
|
|
23
|
+
* @returns Complete triage system prompt.
|
|
24
|
+
*/
|
|
25
|
+
function buildTriagePrompt(tools) {
|
|
26
|
+
const toolList = tools.map(t => `- ${t.name}: ${t.description}`).join('\n');
|
|
27
|
+
return `You are an AI assistant that routes and triages user requests.
|
|
28
|
+
Your job is to analyze the user's message and decide how to handle it most efficiently.
|
|
29
|
+
|
|
30
|
+
You MUST respond with a JSON object in one of these three formats:
|
|
31
|
+
|
|
32
|
+
## 1. DIRECT - Answer directly (for questions, explanations, simple reasoning)
|
|
33
|
+
Use this when you can answer completely without any tool calls.
|
|
34
|
+
{
|
|
35
|
+
"decision": "direct",
|
|
36
|
+
"reasoning": "Why this can be answered directly",
|
|
37
|
+
"directResponse": "Your complete response to the user"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
## 2. DELEGATE_TASKS - Delegate specific tasks to be executed
|
|
41
|
+
Use this when the request requires tool operations with clear inputs/outputs.
|
|
42
|
+
{
|
|
43
|
+
"decision": "delegate_tasks",
|
|
44
|
+
"reasoning": "Why this needs task delegation",
|
|
45
|
+
"tasks": [
|
|
46
|
+
{
|
|
47
|
+
"id": "task_1",
|
|
48
|
+
"description": "What this task does",
|
|
49
|
+
"tool": "tool_name",
|
|
50
|
+
"input": { "param": "value" },
|
|
51
|
+
"purpose": "Why this task is needed"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
## 3. RECOMMEND_PLAN - Recommend enabling Plan Mode
|
|
57
|
+
Use this for complex, multi-step tasks with dependencies.
|
|
58
|
+
{
|
|
59
|
+
"decision": "recommend_plan",
|
|
60
|
+
"reasoning": "Why this task is complex",
|
|
61
|
+
"recommendPlanReason": "User-friendly explanation of why Plan Mode would help"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
## Available Tools
|
|
65
|
+
${toolList}
|
|
66
|
+
|
|
67
|
+
## Guidelines
|
|
68
|
+
- Use DIRECT for: questions, explanations, analysis, reasoning
|
|
69
|
+
- Use DELEGATE_TASKS for: search operations, file reads, entity lookups, simple CRUD
|
|
70
|
+
- Use RECOMMEND_PLAN for: multi-file changes, architectural changes, complex workflows
|
|
71
|
+
|
|
72
|
+
Always respond with valid JSON only.`;
|
|
73
|
+
}
|
|
74
|
+
/** System prompt template for task execution. */
|
|
75
|
+
const TASK_EXECUTION_PROMPT = `You are an AI assistant executing a specific task.
|
|
76
|
+
|
|
77
|
+
Your task: {task_description}
|
|
78
|
+
Purpose: {task_purpose}
|
|
79
|
+
|
|
80
|
+
Execute this task using the available tools. Be efficient and focused.
|
|
81
|
+
Only do what this specific task requires.`;
|
|
82
|
+
/** System prompt template for result synthesis. */
|
|
83
|
+
const SYNTHESIS_PROMPT = `You are an AI assistant synthesizing results from multiple tasks.
|
|
84
|
+
|
|
85
|
+
The user asked: {user_message}
|
|
86
|
+
|
|
87
|
+
Tasks were executed to answer this request. Here are the results:
|
|
88
|
+
{task_results}
|
|
89
|
+
|
|
90
|
+
Synthesize these results into a clear, helpful response for the user.
|
|
91
|
+
Be concise and directly address what the user asked.`;
|
|
92
|
+
/**
|
|
93
|
+
* Triage a user message — Sonnet decides how to handle it.
|
|
94
|
+
*
|
|
95
|
+
* Parses Claude's JSON response into a {@link RoutingDecision}. If parsing
|
|
96
|
+
* fails, falls back to treating the response as a direct answer.
|
|
97
|
+
*
|
|
98
|
+
* @param options - Triage configuration.
|
|
99
|
+
* @returns The routing decision and token usage.
|
|
100
|
+
*/
|
|
101
|
+
export async function triageMessage(options) {
|
|
102
|
+
const { message, conversationHistory, aiClient, tools, triageModel = DEFAULT_MODEL_TIERS.triage, } = options;
|
|
103
|
+
try {
|
|
104
|
+
const response = await aiClient.create({
|
|
105
|
+
model: triageModel,
|
|
106
|
+
maxTokens: 4096,
|
|
107
|
+
system: buildTriagePrompt(tools),
|
|
108
|
+
messages: [
|
|
109
|
+
...conversationHistory.map(msg => ({
|
|
110
|
+
role: msg.role,
|
|
111
|
+
content: msg.content,
|
|
112
|
+
})),
|
|
113
|
+
{ role: 'user', content: message },
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
const inputTokens = response.usage?.input_tokens || 0;
|
|
117
|
+
const outputTokens = response.usage?.output_tokens || 0;
|
|
118
|
+
// Extract text content
|
|
119
|
+
let responseText = '';
|
|
120
|
+
for (const block of response.content) {
|
|
121
|
+
if (block.type === 'text' && block.text) {
|
|
122
|
+
responseText += block.text;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Parse JSON response (handle markdown code blocks)
|
|
126
|
+
let decision;
|
|
127
|
+
try {
|
|
128
|
+
const jsonMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/) || [null, responseText];
|
|
129
|
+
const cleanJson = (jsonMatch[1] || responseText).trim();
|
|
130
|
+
decision = JSON.parse(cleanJson);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
decision = {
|
|
134
|
+
decision: 'direct',
|
|
135
|
+
reasoning: 'Failed to parse structured decision',
|
|
136
|
+
directResponse: responseText,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Normalize task statuses
|
|
140
|
+
if (decision.decision === 'delegate_tasks' && decision.tasks) {
|
|
141
|
+
decision.tasks = decision.tasks.map((task, idx) => ({
|
|
142
|
+
...task,
|
|
143
|
+
id: task.id || `task_${idx + 1}`,
|
|
144
|
+
status: 'pending',
|
|
145
|
+
purpose: task.purpose || task.description,
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
return { decision, inputTokens, outputTokens };
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
const message_ = error instanceof Error ? error.message : String(error);
|
|
152
|
+
return {
|
|
153
|
+
decision: {
|
|
154
|
+
decision: 'direct',
|
|
155
|
+
reasoning: 'Error during triage',
|
|
156
|
+
directResponse: `I encountered an error processing your request: ${message_}`,
|
|
157
|
+
},
|
|
158
|
+
inputTokens: 0,
|
|
159
|
+
outputTokens: 0,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Execute a single delegated task using the executor model.
|
|
165
|
+
*
|
|
166
|
+
* If the task has explicit `tool` and `input` fields (from triage), executes
|
|
167
|
+
* the tool directly without an AI call. Otherwise, sends the task description
|
|
168
|
+
* to the executor model and lets it choose tools.
|
|
169
|
+
*
|
|
170
|
+
* Auto-escalates to the fallback model on failure.
|
|
171
|
+
*
|
|
172
|
+
* @param options - Task execution configuration.
|
|
173
|
+
* @returns Execution result with token usage.
|
|
174
|
+
*/
|
|
175
|
+
export async function executeTask(options) {
|
|
176
|
+
const { task, aiClient, toolExecutor, tools, toolContext, executeModel = DEFAULT_MODEL_TIERS.executor, fallbackModel = DEFAULT_MODEL_TIERS.fallback, } = options;
|
|
177
|
+
// Direct tool execution (triage provided explicit tool + input)
|
|
178
|
+
if (task.tool && task.input) {
|
|
179
|
+
try {
|
|
180
|
+
const result = await toolExecutor.execute(task.tool, task.input, toolContext);
|
|
181
|
+
return {
|
|
182
|
+
taskId: task.id,
|
|
183
|
+
success: true,
|
|
184
|
+
result,
|
|
185
|
+
model: executeModel,
|
|
186
|
+
escalated: false,
|
|
187
|
+
inputTokens: 0,
|
|
188
|
+
outputTokens: 0,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
193
|
+
return {
|
|
194
|
+
taskId: task.id,
|
|
195
|
+
success: false,
|
|
196
|
+
error: message,
|
|
197
|
+
model: executeModel,
|
|
198
|
+
escalated: false,
|
|
199
|
+
inputTokens: 0,
|
|
200
|
+
outputTokens: 0,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// AI-driven execution with the executor model
|
|
205
|
+
const prompt = TASK_EXECUTION_PROMPT
|
|
206
|
+
.replace('{task_description}', task.description)
|
|
207
|
+
.replace('{task_purpose}', task.purpose);
|
|
208
|
+
let result = await executeTaskWithModel(task, executeModel, prompt, aiClient, toolExecutor, tools, toolContext);
|
|
209
|
+
// Auto-escalate on failure
|
|
210
|
+
if (!result.success && fallbackModel !== executeModel) {
|
|
211
|
+
result = await executeTaskWithModel(task, fallbackModel, prompt, aiClient, toolExecutor, tools, toolContext);
|
|
212
|
+
result.escalated = true;
|
|
213
|
+
}
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Execute a task using a specific model — internal helper.
|
|
218
|
+
*
|
|
219
|
+
* @param task - The delegated task.
|
|
220
|
+
* @param model - Model to use.
|
|
221
|
+
* @param systemPrompt - Task-specific system prompt.
|
|
222
|
+
* @param aiClient - AI client.
|
|
223
|
+
* @param toolExecutor - Tool executor.
|
|
224
|
+
* @param tools - Available tool definitions.
|
|
225
|
+
* @param toolContext - Execution context.
|
|
226
|
+
* @returns Task execution result.
|
|
227
|
+
*/
|
|
228
|
+
async function executeTaskWithModel(task, model, systemPrompt, aiClient, toolExecutor, tools, toolContext) {
|
|
229
|
+
try {
|
|
230
|
+
const response = await aiClient.create({
|
|
231
|
+
model,
|
|
232
|
+
maxTokens: 8192,
|
|
233
|
+
system: systemPrompt,
|
|
234
|
+
messages: [{ role: 'user', content: `Execute task: ${task.description}` }],
|
|
235
|
+
tools,
|
|
236
|
+
});
|
|
237
|
+
const inputTokens = response.usage?.input_tokens || 0;
|
|
238
|
+
const outputTokens = response.usage?.output_tokens || 0;
|
|
239
|
+
let result = null;
|
|
240
|
+
let textResponse = '';
|
|
241
|
+
for (const block of response.content) {
|
|
242
|
+
if (block.type === 'text' && block.text) {
|
|
243
|
+
textResponse += block.text;
|
|
244
|
+
}
|
|
245
|
+
else if (block.type === 'tool_use' && block.name) {
|
|
246
|
+
try {
|
|
247
|
+
result = await toolExecutor.execute(block.name, (block.input || {}), toolContext);
|
|
248
|
+
}
|
|
249
|
+
catch (toolError) {
|
|
250
|
+
const message = toolError instanceof Error ? toolError.message : String(toolError);
|
|
251
|
+
return {
|
|
252
|
+
taskId: task.id,
|
|
253
|
+
success: false,
|
|
254
|
+
error: `Tool error: ${message}`,
|
|
255
|
+
model,
|
|
256
|
+
escalated: false,
|
|
257
|
+
inputTokens,
|
|
258
|
+
outputTokens,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
taskId: task.id,
|
|
265
|
+
success: true,
|
|
266
|
+
result: result ?? textResponse,
|
|
267
|
+
model,
|
|
268
|
+
escalated: false,
|
|
269
|
+
inputTokens,
|
|
270
|
+
outputTokens,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
275
|
+
return {
|
|
276
|
+
taskId: task.id,
|
|
277
|
+
success: false,
|
|
278
|
+
error: message,
|
|
279
|
+
model,
|
|
280
|
+
escalated: false,
|
|
281
|
+
inputTokens: 0,
|
|
282
|
+
outputTokens: 0,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Synthesize task results into a coherent response using Sonnet.
|
|
288
|
+
*
|
|
289
|
+
* Takes the raw task outputs and composes a user-facing answer that
|
|
290
|
+
* addresses the original request.
|
|
291
|
+
*
|
|
292
|
+
* @param options - Synthesis configuration.
|
|
293
|
+
* @returns The synthesized response text and token usage.
|
|
294
|
+
*/
|
|
295
|
+
export async function synthesizeResults(options) {
|
|
296
|
+
const { userMessage, taskResults, aiClient, synthesizeModel = DEFAULT_MODEL_TIERS.triage, } = options;
|
|
297
|
+
const taskResultsStr = taskResults.map(tr => {
|
|
298
|
+
if (tr.success) {
|
|
299
|
+
return `Task ${tr.taskId}: SUCCESS\nResult: ${JSON.stringify(tr.result, null, 2)}`;
|
|
300
|
+
}
|
|
301
|
+
return `Task ${tr.taskId}: FAILED\nError: ${tr.error}`;
|
|
302
|
+
}).join('\n\n');
|
|
303
|
+
const prompt = SYNTHESIS_PROMPT
|
|
304
|
+
.replace('{user_message}', userMessage)
|
|
305
|
+
.replace('{task_results}', taskResultsStr);
|
|
306
|
+
try {
|
|
307
|
+
const response = await aiClient.create({
|
|
308
|
+
model: synthesizeModel,
|
|
309
|
+
maxTokens: 4096,
|
|
310
|
+
system: prompt,
|
|
311
|
+
messages: [{ role: 'user', content: 'Synthesize the task results into a response.' }],
|
|
312
|
+
});
|
|
313
|
+
let responseText = '';
|
|
314
|
+
for (const block of response.content) {
|
|
315
|
+
if (block.type === 'text' && block.text) {
|
|
316
|
+
responseText += block.text;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
response: responseText,
|
|
321
|
+
inputTokens: response.usage?.input_tokens || 0,
|
|
322
|
+
outputTokens: response.usage?.output_tokens || 0,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
327
|
+
return {
|
|
328
|
+
response: `I completed some tasks but had trouble summarizing the results: ${message}`,
|
|
329
|
+
inputTokens: 0,
|
|
330
|
+
outputTokens: 0,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Execute the full Sonnet → Haiku → Sonnet delegation flow.
|
|
336
|
+
*
|
|
337
|
+
* 1. Triage with Sonnet → routing decision
|
|
338
|
+
* 2. Execute tasks with Haiku (auto-escalate on failure)
|
|
339
|
+
* 3. Synthesize with Sonnet
|
|
340
|
+
*
|
|
341
|
+
* @param options - Delegation configuration.
|
|
342
|
+
* @returns The delegation result with synthesized response.
|
|
343
|
+
*/
|
|
344
|
+
export async function delegateAndExecute(options) {
|
|
345
|
+
const { message, conversationHistory, aiClient, tools, toolExecutor, toolContext, triageModel, executeModel, fallbackModel, onTaskStart, onTaskComplete, } = options;
|
|
346
|
+
let totalInputTokens = 0;
|
|
347
|
+
let totalOutputTokens = 0;
|
|
348
|
+
let escalationCount = 0;
|
|
349
|
+
// Step 1: Triage
|
|
350
|
+
const triageResult = await triageMessage({
|
|
351
|
+
message,
|
|
352
|
+
conversationHistory,
|
|
353
|
+
aiClient,
|
|
354
|
+
tools,
|
|
355
|
+
...(triageModel != null ? { triageModel } : {}),
|
|
356
|
+
});
|
|
357
|
+
totalInputTokens += triageResult.inputTokens;
|
|
358
|
+
totalOutputTokens += triageResult.outputTokens;
|
|
359
|
+
const { decision } = triageResult;
|
|
360
|
+
// Direct response — no delegation needed
|
|
361
|
+
if (decision.decision === 'direct') {
|
|
362
|
+
return {
|
|
363
|
+
success: true,
|
|
364
|
+
taskResults: [],
|
|
365
|
+
...(decision.directResponse != null ? { synthesizedResponse: decision.directResponse } : {}),
|
|
366
|
+
totalTokens: { input: totalInputTokens, output: totalOutputTokens },
|
|
367
|
+
escalationCount: 0,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
// Recommend plan mode
|
|
371
|
+
if (decision.decision === 'recommend_plan') {
|
|
372
|
+
return {
|
|
373
|
+
success: true,
|
|
374
|
+
taskResults: [],
|
|
375
|
+
synthesizedResponse: decision.recommendPlanReason ||
|
|
376
|
+
'This is a complex task. I recommend enabling Plan Mode for better results.',
|
|
377
|
+
totalTokens: { input: totalInputTokens, output: totalOutputTokens },
|
|
378
|
+
escalationCount: 0,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
// Delegate tasks
|
|
382
|
+
if (decision.decision === 'delegate_tasks' && decision.tasks) {
|
|
383
|
+
const taskResults = [];
|
|
384
|
+
// Step 2: Execute tasks sequentially
|
|
385
|
+
for (const task of decision.tasks) {
|
|
386
|
+
if (onTaskStart)
|
|
387
|
+
await onTaskStart(task);
|
|
388
|
+
const result = await executeTask({
|
|
389
|
+
task,
|
|
390
|
+
aiClient,
|
|
391
|
+
toolExecutor,
|
|
392
|
+
tools,
|
|
393
|
+
toolContext,
|
|
394
|
+
...(executeModel != null ? { executeModel } : {}),
|
|
395
|
+
...(fallbackModel != null ? { fallbackModel } : {}),
|
|
396
|
+
});
|
|
397
|
+
taskResults.push(result);
|
|
398
|
+
totalInputTokens += result.inputTokens;
|
|
399
|
+
totalOutputTokens += result.outputTokens;
|
|
400
|
+
if (result.escalated)
|
|
401
|
+
escalationCount++;
|
|
402
|
+
if (onTaskComplete)
|
|
403
|
+
await onTaskComplete(result);
|
|
404
|
+
}
|
|
405
|
+
// Step 3: Synthesize
|
|
406
|
+
const synthesisResult = await synthesizeResults({
|
|
407
|
+
userMessage: message,
|
|
408
|
+
taskResults,
|
|
409
|
+
aiClient,
|
|
410
|
+
...(triageModel != null ? { synthesizeModel: triageModel } : {}),
|
|
411
|
+
});
|
|
412
|
+
totalInputTokens += synthesisResult.inputTokens;
|
|
413
|
+
totalOutputTokens += synthesisResult.outputTokens;
|
|
414
|
+
return {
|
|
415
|
+
success: taskResults.every(r => r.success),
|
|
416
|
+
taskResults,
|
|
417
|
+
synthesizedResponse: synthesisResult.response,
|
|
418
|
+
totalTokens: { input: totalInputTokens, output: totalOutputTokens },
|
|
419
|
+
escalationCount,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
// Fallback — should not reach here
|
|
423
|
+
return {
|
|
424
|
+
success: false,
|
|
425
|
+
taskResults: [],
|
|
426
|
+
synthesizedResponse: 'Unable to process your request.',
|
|
427
|
+
totalTokens: { input: totalInputTokens, output: totalOutputTokens },
|
|
428
|
+
escalationCount: 0,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=delegator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegator.js","sourceRoot":"","sources":["../../../../src/server/handlers/chat/delegator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/handlers/chat/engine
|
|
3
|
+
* @description The core streaming chat engine — agentic tool-use loop with
|
|
4
|
+
* stuck detection, timeout protection, and fire-and-forget persistence.
|
|
5
|
+
*
|
|
6
|
+
* The engine is transport-agnostic: it yields `ChatStreamChunk` frames via
|
|
7
|
+
* an `AsyncGenerator`. The transport layer (SSE, WebSocket, PostMessage)
|
|
8
|
+
* delivers those chunks to the client.
|
|
9
|
+
*
|
|
10
|
+
* ## Agentic Loop
|
|
11
|
+
*
|
|
12
|
+
* When Claude calls a tool, the engine:
|
|
13
|
+
* 1. Executes the tool via the injected {@link ToolExecutor}
|
|
14
|
+
* 2. Feeds the result back to Claude as a `tool_result` message
|
|
15
|
+
* 3. Claude continues (more text, more tool calls, or `message_stop`)
|
|
16
|
+
* 4. Repeat until no more tool calls, max iterations, or timeout
|
|
17
|
+
*
|
|
18
|
+
* ## Stuck Detection
|
|
19
|
+
*
|
|
20
|
+
* If the same tool with the same input is called 3 times consecutively,
|
|
21
|
+
* the engine breaks the loop to prevent infinite spinning.
|
|
22
|
+
*
|
|
23
|
+
* ## Fire-and-Forget
|
|
24
|
+
*
|
|
25
|
+
* Message storage, auto-titling, and background learning happen async
|
|
26
|
+
* without blocking the stream.
|
|
27
|
+
*/
|
|
28
|
+
import type { ChatHandlerOptions } from './types.js';
|
|
29
|
+
import type { ChatStreamChunk } from '../../../namespaces.js';
|
|
30
|
+
import type { HandlerContext } from '../../namespace-router.js';
|
|
31
|
+
/**
|
|
32
|
+
* Options for a single streaming chat message.
|
|
33
|
+
*/
|
|
34
|
+
export interface StreamMessageOptions {
|
|
35
|
+
/** The user's message text. */
|
|
36
|
+
message: string;
|
|
37
|
+
/** Existing conversation ID, or undefined to create a new one. */
|
|
38
|
+
conversationId?: string;
|
|
39
|
+
/** Forced model override. */
|
|
40
|
+
model?: string;
|
|
41
|
+
/** Whether Plan Mode is enabled. */
|
|
42
|
+
planModeEnabled?: boolean;
|
|
43
|
+
/** Product-specific context (e.g. ChatContext, KitAIContext). */
|
|
44
|
+
productContext?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run the streaming chat engine for a single message.
|
|
48
|
+
*
|
|
49
|
+
* Yields {@link ChatStreamChunk} frames: `text`, `tool_use`, `tool_result`,
|
|
50
|
+
* `status`, `thinking_start`, `thinking_delta`, `thinking_end`, and
|
|
51
|
+
* terminal `done` or `error`.
|
|
52
|
+
*
|
|
53
|
+
* This is the core of the chat system — the full agentic loop with
|
|
54
|
+
* tool use, stuck detection, timeout, and fire-and-forget persistence.
|
|
55
|
+
*
|
|
56
|
+
* @param opts - Message options.
|
|
57
|
+
* @param handlerCtx - Handler context with brain, user, workspace.
|
|
58
|
+
* @param config - Chat handler configuration (injected dependencies).
|
|
59
|
+
* @yields ChatStreamChunk frames.
|
|
60
|
+
*/
|
|
61
|
+
export declare function streamMessage(opts: StreamMessageOptions, handlerCtx: HandlerContext, config: ChatHandlerOptions): AsyncGenerator<ChatStreamChunk>;
|
|
62
|
+
/**
|
|
63
|
+
* Send a message and collect the full response (non-streaming).
|
|
64
|
+
*
|
|
65
|
+
* Internally uses the streaming engine and collects all text chunks.
|
|
66
|
+
*
|
|
67
|
+
* @param opts - Message options.
|
|
68
|
+
* @param handlerCtx - Handler context.
|
|
69
|
+
* @param config - Chat handler configuration.
|
|
70
|
+
* @returns Complete response with conversation ID and usage.
|
|
71
|
+
*/
|
|
72
|
+
export declare function sendMessage(opts: StreamMessageOptions, handlerCtx: HandlerContext, config: ChatHandlerOptions): Promise<{
|
|
73
|
+
response: string;
|
|
74
|
+
conversationId: string;
|
|
75
|
+
usage: {
|
|
76
|
+
inputTokens: number;
|
|
77
|
+
outputTokens: number;
|
|
78
|
+
model: string;
|
|
79
|
+
};
|
|
80
|
+
}>;
|
|
81
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../src/server/handlers/chat/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAUV,kBAAkB,EAGnB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAE7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AA6B/D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oCAAoC;IACpC,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAuB,aAAa,CAClC,IAAI,EAAE,oBAAoB,EAC1B,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,kBAAkB,GACzB,cAAc,CAAC,eAAe,CAAC,CAgVjC;AAMD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,oBAAoB,EAC1B,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC;IACT,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CACpE,CAAC,CAeD"}
|