funolio-agent 1.0.7 → 1.0.47
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/approval.d.ts +1 -0
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +12 -0
- package/dist/approval.js.map +1 -1
- package/dist/auth/auto-detect.d.ts +11 -3
- package/dist/auth/auto-detect.d.ts.map +1 -1
- package/dist/auth/auto-detect.js +136 -168
- package/dist/auth/auto-detect.js.map +1 -1
- package/dist/auth/subscription-runtime.js +1 -1
- package/dist/auth/subscription-runtime.js.map +1 -1
- package/dist/backfill.d.ts.map +1 -1
- package/dist/backfill.js +31 -28
- package/dist/backfill.js.map +1 -1
- package/dist/bot-manager.d.ts +16 -4
- package/dist/bot-manager.d.ts.map +1 -1
- package/dist/bot-manager.js +280 -73
- package/dist/bot-manager.js.map +1 -1
- package/dist/clerk-model.d.ts +10 -6
- package/dist/clerk-model.d.ts.map +1 -1
- package/dist/clerk-model.js +39 -16
- package/dist/clerk-model.js.map +1 -1
- package/dist/cli.js +7 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/import-history.js +5 -1
- package/dist/commands/import-history.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +57 -225
- package/dist/commands/start.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -2
- package/dist/config.js.map +1 -1
- package/dist/context-window.js +1 -1
- package/dist/context-window.js.map +1 -1
- package/dist/import-parser-core.d.ts.map +1 -1
- package/dist/import-parser-core.js +74 -8
- package/dist/import-parser-core.js.map +1 -1
- package/dist/local-data.d.ts +59 -6
- package/dist/local-data.d.ts.map +1 -1
- package/dist/local-data.js +544 -62
- package/dist/local-data.js.map +1 -1
- package/dist/local-db.d.ts.map +1 -1
- package/dist/local-db.js +21 -1
- package/dist/local-db.js.map +1 -1
- package/dist/local-funnel.d.ts +0 -7
- package/dist/local-funnel.d.ts.map +1 -1
- package/dist/local-funnel.js +19 -28
- package/dist/local-funnel.js.map +1 -1
- package/dist/local-import-worker.d.ts.map +1 -1
- package/dist/local-import-worker.js +49 -4
- package/dist/local-import-worker.js.map +1 -1
- package/dist/local-memory-search.d.ts.map +1 -1
- package/dist/local-memory-search.js +6 -3
- package/dist/local-memory-search.js.map +1 -1
- package/dist/local-server.d.ts +37 -0
- package/dist/local-server.d.ts.map +1 -1
- package/dist/local-server.js +731 -227
- package/dist/local-server.js.map +1 -1
- package/dist/mcp/local-memory-server.d.ts +1 -1
- package/dist/mcp/local-memory-server.d.ts.map +1 -1
- package/dist/mcp/local-memory-server.js +23 -11
- package/dist/mcp/local-memory-server.js.map +1 -1
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +86 -18
- package/dist/mcp/manager.js.map +1 -1
- package/dist/message-loop.d.ts +5 -10
- package/dist/message-loop.d.ts.map +1 -1
- package/dist/message-loop.js +393 -289
- package/dist/message-loop.js.map +1 -1
- package/dist/mqtt-client.d.ts +4 -1
- package/dist/mqtt-client.d.ts.map +1 -1
- package/dist/mqtt-client.js.map +1 -1
- package/dist/orchestration/orchestrator-blocked-prompt.d.ts +2 -1
- package/dist/orchestration/orchestrator-blocked-prompt.d.ts.map +1 -1
- package/dist/orchestration/orchestrator-blocked-prompt.js +11 -0
- package/dist/orchestration/orchestrator-blocked-prompt.js.map +1 -1
- package/dist/orchestration/orchestrator-final-response-prompt.d.ts +4 -1
- package/dist/orchestration/orchestrator-final-response-prompt.d.ts.map +1 -1
- package/dist/orchestration/orchestrator-final-response-prompt.js +8 -6
- package/dist/orchestration/orchestrator-final-response-prompt.js.map +1 -1
- package/dist/orchestration/worker-operating-prompt.d.ts +2 -0
- package/dist/orchestration/worker-operating-prompt.d.ts.map +1 -1
- package/dist/orchestration/worker-operating-prompt.js +39 -0
- package/dist/orchestration/worker-operating-prompt.js.map +1 -1
- package/dist/orchestrator.d.ts +13 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +235 -133
- package/dist/orchestrator.js.map +1 -1
- package/dist/providers/anthropic.d.ts +0 -5
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +29 -75
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/claude-cli.d.ts.map +1 -1
- package/dist/providers/claude-cli.js +16 -140
- package/dist/providers/claude-cli.js.map +1 -1
- package/dist/providers/codex-cli.d.ts.map +1 -1
- package/dist/providers/codex-cli.js +78 -59
- package/dist/providers/codex-cli.js.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +4 -2
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +27 -2
- package/dist/providers/openai.js.map +1 -1
- package/dist/storage-mode.d.ts +5 -0
- package/dist/storage-mode.d.ts.map +1 -0
- package/dist/storage-mode.js +21 -0
- package/dist/storage-mode.js.map +1 -0
- package/dist/summarization-pipeline.d.ts +9 -0
- package/dist/summarization-pipeline.d.ts.map +1 -1
- package/dist/summarization-pipeline.js +61 -17
- package/dist/summarization-pipeline.js.map +1 -1
- package/dist/tools/analyze-image.js +2 -2
- package/dist/tools/analyze-image.js.map +1 -1
- package/dist/tools/edit-file.js +3 -3
- package/dist/tools/edit-file.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +36 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-directory.js +7 -4
- package/dist/tools/list-directory.js.map +1 -1
- package/dist/tools/read-file.js +3 -3
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/run-command.js +3 -3
- package/dist/tools/run-command.js.map +1 -1
- package/dist/tools/sandbox.d.ts +10 -5
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +41 -13
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/search-codebase.js +2 -2
- package/dist/tools/search-codebase.js.map +1 -1
- package/dist/tools/search-local-memory.d.ts.map +1 -1
- package/dist/tools/search-local-memory.js +19 -8
- package/dist/tools/search-local-memory.js.map +1 -1
- package/dist/tools/spawn-subagent.js.map +1 -1
- package/dist/tools/write-file.js +3 -3
- package/dist/tools/write-file.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/verification/index.js +2 -2
- package/dist/verification/index.js.map +1 -1
- package/dist/wizard-state.d.ts.map +1 -1
- package/dist/wizard-state.js +16 -2
- package/dist/wizard-state.js.map +1 -1
- package/dist/wizard-support.d.ts +2 -2
- package/dist/wizard-support.d.ts.map +1 -1
- package/dist/wizard-support.js +80 -93
- package/dist/wizard-support.js.map +1 -1
- package/dist/workflow-engine.d.ts +3 -1
- package/dist/workflow-engine.d.ts.map +1 -1
- package/dist/workflow-engine.js +131 -12
- package/dist/workflow-engine.js.map +1 -1
- package/package.json +1 -1
package/dist/orchestrator.js
CHANGED
|
@@ -61,6 +61,7 @@ const state_1 = require("./orchestration/state");
|
|
|
61
61
|
const orchestrator_profile_1 = require("./orchestrator-profile");
|
|
62
62
|
const context_window_1 = require("./context-window");
|
|
63
63
|
const data = __importStar(require("./local-data"));
|
|
64
|
+
const storage_mode_1 = require("./storage-mode");
|
|
64
65
|
const fs = __importStar(require("fs"));
|
|
65
66
|
const os = __importStar(require("os"));
|
|
66
67
|
const path = __importStar(require("path"));
|
|
@@ -83,10 +84,17 @@ const ORCHESTRATION_NODE_RETRY_LIMITS = {
|
|
|
83
84
|
class OrchestratorAgent {
|
|
84
85
|
clerk;
|
|
85
86
|
workflowEngine;
|
|
87
|
+
lastResponseMeta = null;
|
|
86
88
|
constructor(clerk, workflowEngine) {
|
|
87
89
|
this.clerk = clerk;
|
|
88
90
|
this.workflowEngine = workflowEngine;
|
|
89
91
|
}
|
|
92
|
+
getLastResponseMeta() {
|
|
93
|
+
return this.lastResponseMeta;
|
|
94
|
+
}
|
|
95
|
+
setLastResponseMeta(meta) {
|
|
96
|
+
this.lastResponseMeta = meta;
|
|
97
|
+
}
|
|
90
98
|
async runNodeWithRetry(node, state, work) {
|
|
91
99
|
const maxRetries = ORCHESTRATION_NODE_RETRY_LIMITS[node] ?? 0;
|
|
92
100
|
let attempt = 0;
|
|
@@ -109,6 +117,7 @@ class OrchestratorAgent {
|
|
|
109
117
|
* Returns O's response to display to the user.
|
|
110
118
|
*/
|
|
111
119
|
async handleUserMessage(prompt, conversationId, opts) {
|
|
120
|
+
this.lastResponseMeta = null;
|
|
112
121
|
const conversation = conversationId ? data.getConversation(conversationId) : undefined;
|
|
113
122
|
const routingMode = conversation?.routing_mode;
|
|
114
123
|
const conversationProjectId = conversation?.project_id || opts.projectId;
|
|
@@ -137,6 +146,13 @@ class OrchestratorAgent {
|
|
|
137
146
|
}
|
|
138
147
|
const promptAssignments = this.parseRoleAssignments(prompt);
|
|
139
148
|
const selectedOrchestrator = this.resolveSelectedOrchestratorBot(conversation);
|
|
149
|
+
if (selectedOrchestrator) {
|
|
150
|
+
this.setLastResponseMeta({
|
|
151
|
+
agentName: 'Orchestrator',
|
|
152
|
+
botId: selectedOrchestrator.id,
|
|
153
|
+
modelLabel: null,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
140
156
|
if (selectedOrchestrator) {
|
|
141
157
|
orchestrationState.orchestratorBotId = selectedOrchestrator.id;
|
|
142
158
|
}
|
|
@@ -197,26 +213,40 @@ class OrchestratorAgent {
|
|
|
197
213
|
if (frontDoorResult !== null)
|
|
198
214
|
return frontDoorResult;
|
|
199
215
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (intent) {
|
|
216
|
+
let intent;
|
|
217
|
+
let routedPlan;
|
|
218
|
+
if (selectedOrchestrator) {
|
|
219
|
+
this.reportHiddenRoleProgress(opts, 'intent_classifier', 'Recovering routing from code fallback');
|
|
220
|
+
intent = this.fallbackClassifyUserMessage(prompt, routingMode);
|
|
221
|
+
orchestrationState.fallbackUsed = true;
|
|
207
222
|
if (this.applyClassificationGuards(prompt, intent, routingMode)) {
|
|
208
223
|
(0, state_1.markMisrouteCorrected)(orchestrationState);
|
|
209
224
|
}
|
|
210
|
-
this.reportHiddenRoleProgress(opts, 'intent_classifier', `
|
|
225
|
+
this.reportHiddenRoleProgress(opts, 'intent_classifier', `Classified request as ${this.describeIntentForActivity(intent)}`);
|
|
211
226
|
}
|
|
212
227
|
else {
|
|
213
228
|
this.reportHiddenRoleProgress(opts, 'intent_classifier', 'Classifying request');
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
229
|
+
(0, state_1.addHelperRoleUsage)(orchestrationState, 'intent_classifier');
|
|
230
|
+
routedPlan = await this.decomposeAndRouteUserMessage(prompt, conversationId, opts.projectId, routingMode);
|
|
231
|
+
const routedIntent = routedPlan?.intents.length === 1
|
|
232
|
+
? this.buildIntentAnalysisFromRoutedIntent(routedPlan.intents[0])
|
|
233
|
+
: undefined;
|
|
234
|
+
if (routedIntent) {
|
|
235
|
+
intent = routedIntent;
|
|
236
|
+
if (this.applyClassificationGuards(prompt, intent, routingMode)) {
|
|
237
|
+
(0, state_1.markMisrouteCorrected)(orchestrationState);
|
|
238
|
+
}
|
|
239
|
+
this.reportHiddenRoleProgress(opts, 'intent_classifier', `Routed single intent as ${this.describeIntentForActivity(intent)}`);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
this.reportHiddenRoleProgress(opts, 'intent_classifier', 'Classifying request');
|
|
243
|
+
intent = await this.classifyUserMessage(prompt, opts.projectId, routingMode);
|
|
244
|
+
orchestrationState.fallbackUsed = true;
|
|
245
|
+
if (this.applyClassificationGuards(prompt, intent, routingMode)) {
|
|
246
|
+
(0, state_1.markMisrouteCorrected)(orchestrationState);
|
|
247
|
+
}
|
|
248
|
+
this.reportHiddenRoleProgress(opts, 'intent_classifier', `Classified request as ${this.describeIntentForActivity(intent)}`);
|
|
218
249
|
}
|
|
219
|
-
this.reportHiddenRoleProgress(opts, 'intent_classifier', `Classified request as ${this.describeIntentForActivity(intent)}`);
|
|
220
250
|
}
|
|
221
251
|
orchestrationState.intent = intent.intent;
|
|
222
252
|
orchestrationState.taskType = intent.primaryMode;
|
|
@@ -400,6 +430,7 @@ class OrchestratorAgent {
|
|
|
400
430
|
const orchestratorOwnsCoding = orchestratorName.length > 0
|
|
401
431
|
&& (orchestratorName === codingOwner
|
|
402
432
|
|| roleClass === 'code'
|
|
433
|
+
|| roleClass === 'coding'
|
|
403
434
|
|| roleClass === 'coder'
|
|
404
435
|
|| roleClass === 'builder'
|
|
405
436
|
|| roleClass === 'developer');
|
|
@@ -1276,9 +1307,12 @@ class OrchestratorAgent {
|
|
|
1276
1307
|
return finalize(this.formatProjectKnowledgeResponse(overview, []), 'Handled project knowledge request directly.');
|
|
1277
1308
|
}
|
|
1278
1309
|
if (/\b(hello|hi|hey|are you there|good morning|good afternoon|good evening)\b/i.test(normalized)) {
|
|
1279
|
-
return '
|
|
1310
|
+
return "I'm here and ready. Tell me what you want me to coordinate.";
|
|
1280
1311
|
}
|
|
1281
|
-
|
|
1312
|
+
if (/\b(thanks|thank you|great work|good work|nice work|well done|awesome|perfect|just complementing you|just complimenting you|complimenting you|nothing else)\b/i.test(normalized)) {
|
|
1313
|
+
return "Thanks. I'm here when you need me.";
|
|
1314
|
+
}
|
|
1315
|
+
return "I'm here. Tell me what you want to do next.";
|
|
1282
1316
|
}
|
|
1283
1317
|
formatPolicyUpdateResponse(prompt, intent, assignments, overview) {
|
|
1284
1318
|
const lines = ['I’m reading that as an orchestration policy update, not as immediate work.'];
|
|
@@ -1487,6 +1521,16 @@ class OrchestratorAgent {
|
|
|
1487
1521
|
roleAssignments,
|
|
1488
1522
|
});
|
|
1489
1523
|
const normalizeName = (value) => String(value || '').trim().toLowerCase();
|
|
1524
|
+
const fastDecision = this.buildFastFrontDoorDecision(prompt, frontDoorSignals, promptAssignments, roleAssignments);
|
|
1525
|
+
if (fastDecision) {
|
|
1526
|
+
this.recordOrchestrationAudit(state, 'understand_request', 'path_selected', fastDecision.reason, {
|
|
1527
|
+
decisionMode: fastDecision.mode,
|
|
1528
|
+
delegateTarget: fastDecision.delegate_target || null,
|
|
1529
|
+
delegateRole: fastDecision.delegate_role || null,
|
|
1530
|
+
fastPath: true,
|
|
1531
|
+
});
|
|
1532
|
+
return this.handleFrontDoorDecision(fastDecision, prompt, conversationId, opts, orchestratorBot, projectId, project, policy, promptAssignments, roleAssignments, overview, state, signalSpecialists, workflowNames);
|
|
1533
|
+
}
|
|
1490
1534
|
const operatingPrompt = (0, orchestrator_operating_prompt_1.buildOrchestratorOperatingPrompt)({
|
|
1491
1535
|
orchestratorName: orchestratorBot.name,
|
|
1492
1536
|
primaryRole: orchestratorBot.role_label || orchestratorBot.role_class || null,
|
|
@@ -1528,6 +1572,7 @@ class OrchestratorAgent {
|
|
|
1528
1572
|
const result = await this.runNodeWithRetry('understand_request', state, async () => this.workflowEngine.execute(decisionPrompt, null, orchestratorBot.id, {
|
|
1529
1573
|
disableDecomposition: true,
|
|
1530
1574
|
disableTools: true,
|
|
1575
|
+
disallowCliRuntime: true,
|
|
1531
1576
|
projectId: projectId || null,
|
|
1532
1577
|
workspacePath: project?.folder?.trim() || undefined,
|
|
1533
1578
|
systemPromptOverride: operatingPrompt,
|
|
@@ -1600,6 +1645,71 @@ class OrchestratorAgent {
|
|
|
1600
1645
|
};
|
|
1601
1646
|
}
|
|
1602
1647
|
}
|
|
1648
|
+
return this.handleFrontDoorDecision(decision, prompt, conversationId, opts, orchestratorBot, projectId, project, policy, promptAssignments, roleAssignments, overview, state, signalSpecialists, workflowNames);
|
|
1649
|
+
}
|
|
1650
|
+
buildFastFrontDoorDecision(prompt, frontDoorSignals, promptAssignments, roleAssignments) {
|
|
1651
|
+
const normalizeName = (value) => String(value || '').trim().toLowerCase();
|
|
1652
|
+
const taskType = (0, front_door_policy_1.inferFrontDoorTaskType)(prompt);
|
|
1653
|
+
const normalizedPrompt = prompt.trim().toLowerCase();
|
|
1654
|
+
if (taskType === 'conversation') {
|
|
1655
|
+
if (/\b(hello|hi|hey|are you there|good morning|good afternoon|good evening)\b/i.test(normalizedPrompt)) {
|
|
1656
|
+
return {
|
|
1657
|
+
mode: 'respond',
|
|
1658
|
+
reason: 'Code-first front door handled a simple greeting conversationally.',
|
|
1659
|
+
response: "I'm here and ready. Tell me what you want me to coordinate.",
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
if (/\b(thanks|thank you|great work|good work|nice work|well done|awesome|perfect|just complementing you|just complimenting you|complimenting you|nothing else)\b/i.test(normalizedPrompt)) {
|
|
1663
|
+
return {
|
|
1664
|
+
mode: 'respond',
|
|
1665
|
+
reason: 'Code-first front door handled a simple conversational compliment without invoking workflow routing.',
|
|
1666
|
+
response: "Thanks. I'm here when you need me.",
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
const promptAssignedRoles = [promptAssignments.coding, promptAssignments.qa, promptAssignments.research].filter(Boolean).length;
|
|
1671
|
+
const multiWorkerRequested = taskType === 'mixed'
|
|
1672
|
+
|| promptAssignedRoles >= 2
|
|
1673
|
+
|| frontDoorSignals.matchedBots.length >= 2
|
|
1674
|
+
|| frontDoorSignals.matchedRoles.length >= 2
|
|
1675
|
+
|| frontDoorSignals.matchedWorkflowNames.length > 0
|
|
1676
|
+
|| frontDoorSignals.preferredMode === 'workflow';
|
|
1677
|
+
if (multiWorkerRequested) {
|
|
1678
|
+
return {
|
|
1679
|
+
mode: 'workflow',
|
|
1680
|
+
reason: frontDoorSignals.matchedWorkflowNames.length > 0
|
|
1681
|
+
? 'Code-first front door fast-pathed a named or selected workflow request without waiting on orchestrator routing.'
|
|
1682
|
+
: 'Code-first front door fast-pathed an obvious staged multi-worker request without waiting on orchestrator routing.',
|
|
1683
|
+
workflow_request: prompt,
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
if (taskType === 'policy' || taskType === 'status' || taskType === 'conversation')
|
|
1687
|
+
return null;
|
|
1688
|
+
if (/\bwhat do you think|can we|should we|do you agree|need to discuss|discuss more|is this a good idea|thoughts\??|recommend(?:ation)?\b/i.test(prompt)) {
|
|
1689
|
+
return null;
|
|
1690
|
+
}
|
|
1691
|
+
const preferredTarget = frontDoorSignals.preferredTarget
|
|
1692
|
+
|| (taskType === 'coding' ? roleAssignments.coding
|
|
1693
|
+
: taskType === 'qa' ? roleAssignments.qa
|
|
1694
|
+
: taskType === 'research' ? roleAssignments.research
|
|
1695
|
+
: null);
|
|
1696
|
+
if (!preferredTarget)
|
|
1697
|
+
return null;
|
|
1698
|
+
const delegateRole = frontDoorSignals.matchedRoles[0]
|
|
1699
|
+
|| (normalizeName(preferredTarget) === normalizeName(roleAssignments.qa) ? 'qa'
|
|
1700
|
+
: normalizeName(preferredTarget) === normalizeName(roleAssignments.research) ? 'research'
|
|
1701
|
+
: 'coding');
|
|
1702
|
+
return {
|
|
1703
|
+
mode: 'delegate',
|
|
1704
|
+
reason: frontDoorSignals.explicitOrchestrationRequested
|
|
1705
|
+
? 'Code-first front door fast-pathed an explicit single-worker request without waiting on orchestrator routing.'
|
|
1706
|
+
: 'Code-first front door fast-pathed a single-worker task to the assigned specialist.',
|
|
1707
|
+
delegate_target: preferredTarget,
|
|
1708
|
+
delegate_role: delegateRole,
|
|
1709
|
+
delegate_request: prompt,
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
async handleFrontDoorDecision(decision, prompt, conversationId, opts, orchestratorBot, projectId, project, policy, promptAssignments, roleAssignments, overview, state, signalSpecialists, workflowNames) {
|
|
1603
1713
|
if (!decision) {
|
|
1604
1714
|
this.recordOrchestrationAudit(state, 'understand_request', 'blocked', 'Orchestrator-first decision phase did not return valid JSON. Falling back to legacy clerk chain.', { featureFlag: 'orchestrator_v2_enabled' });
|
|
1605
1715
|
return null;
|
|
@@ -1949,6 +2059,7 @@ class OrchestratorAgent {
|
|
|
1949
2059
|
const result = await this.runNodeWithRetry('run_workflow', state, async () => this.workflowEngine.execute(taskPrompt, conversationId, owner.id, {
|
|
1950
2060
|
apiKey: this.resolveApiKey(owner.provider),
|
|
1951
2061
|
taskId: task.id,
|
|
2062
|
+
stepDescription: task.title,
|
|
1952
2063
|
disableDecomposition: true,
|
|
1953
2064
|
isOrchestrated: true,
|
|
1954
2065
|
projectId: project?.id || opts.projectId || state.projectId || null,
|
|
@@ -1989,6 +2100,7 @@ class OrchestratorAgent {
|
|
|
1989
2100
|
async handleBlockedTodoTask(task, opts, state, orchestratorBot, project) {
|
|
1990
2101
|
const policy = data.getEffectiveOrchestrationPolicy(project?.id || opts.projectId || state.projectId || undefined);
|
|
1991
2102
|
const artifacts = data.listTodoArtifactsForTask(task.id, 'active').map((item) => item.path_or_ref);
|
|
2103
|
+
const completedTasks = data.listCompletedTodoTasksForConversation(task.conversation_id || state.conversationId || '');
|
|
1992
2104
|
const workerRole = task.task_type || task.next_worker_role || 'general';
|
|
1993
2105
|
const blockedPrompt = (0, orchestrator_blocked_prompt_1.buildBlockedWorkerOrchestratorPrompt)({
|
|
1994
2106
|
orchestratorName: orchestratorBot.name,
|
|
@@ -2001,33 +2113,33 @@ class OrchestratorAgent {
|
|
|
2001
2113
|
workspacePath: project?.folder || null,
|
|
2002
2114
|
effectivePolicy: policy,
|
|
2003
2115
|
artifactRefs: artifacts,
|
|
2116
|
+
completedTasks,
|
|
2004
2117
|
blockerSummary: task.blocker_summary || 'Worker is blocked.',
|
|
2005
2118
|
checkedContext: task.blocker_checked || 'No checked context was recorded.',
|
|
2006
2119
|
userQuestion: task.blocker_question || 'What should happen next?',
|
|
2007
2120
|
});
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
});
|
|
2121
|
+
let rawResponse = '';
|
|
2122
|
+
try {
|
|
2123
|
+
rawResponse = await this.runNodeWithRetry('finalize_response', state, async () => this.respondAsClerk(blockedPrompt, 'You are Clerk. Write the user-facing blocker message after work has already started. Be concise, outcome-first, and do not restate the full original request.'));
|
|
2124
|
+
}
|
|
2125
|
+
catch (error) {
|
|
2126
|
+
this.recordOrchestrationAudit(state, 'finalize_response', 'blocked', `Blocked final response generation failed: ${error?.message || error}`);
|
|
2127
|
+
rawResponse = '';
|
|
2128
|
+
}
|
|
2129
|
+
const response = (!rawResponse.trim() || /no steps completed\.?/i.test(rawResponse))
|
|
2130
|
+
? ''
|
|
2131
|
+
: rawResponse;
|
|
2020
2132
|
state.finalResponseDraft = response;
|
|
2021
2133
|
return response;
|
|
2022
2134
|
}
|
|
2023
2135
|
async finalizeQueuedTodoChain(conversationId, opts, state, orchestratorBot, project, workflowName) {
|
|
2024
|
-
const completedTasks = data.listCompletedTodoTasksForConversation(conversationId)
|
|
2136
|
+
const completedTasks = data.listCompletedTodoTasksForConversation(conversationId).map((task) => ({
|
|
2137
|
+
...task,
|
|
2138
|
+
artifactRefs: data.listTodoArtifactsForTask(task.id, 'completed').map((item) => item.path_or_ref),
|
|
2139
|
+
}));
|
|
2025
2140
|
if (completedTasks.length === 0) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
: 'The queued workflow finished without any completed worker output.';
|
|
2029
|
-
state.finalResponseDraft = fallback;
|
|
2030
|
-
return fallback;
|
|
2141
|
+
state.finalResponseDraft = '';
|
|
2142
|
+
return '';
|
|
2031
2143
|
}
|
|
2032
2144
|
const policy = data.getEffectiveOrchestrationPolicy(project?.id || opts.projectId || state.projectId || undefined);
|
|
2033
2145
|
const finalPrompt = (0, orchestrator_final_response_prompt_1.buildOrchestratorFinalResponsePrompt)({
|
|
@@ -2037,18 +2149,17 @@ class OrchestratorAgent {
|
|
|
2037
2149
|
effectivePolicy: policy,
|
|
2038
2150
|
completedTasks,
|
|
2039
2151
|
});
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
});
|
|
2152
|
+
let response = '';
|
|
2153
|
+
try {
|
|
2154
|
+
response = await this.runNodeWithRetry('finalize_response', state, async () => this.respondAsClerk(finalPrompt, 'You are Clerk. Write the final user-facing answer after the workflow is complete. Do not restate the full request. Say what was created, where it is, the concise result, and only any important caveat. Do not claim everything was verified, defect-free, or ready for use unless a completed verification step explicitly established that.'));
|
|
2155
|
+
}
|
|
2156
|
+
catch (error) {
|
|
2157
|
+
this.recordOrchestrationAudit(state, 'finalize_response', 'blocked', `Final response generation failed: ${error?.message || error}`);
|
|
2158
|
+
response = '';
|
|
2159
|
+
}
|
|
2160
|
+
if (!response.trim() || /no steps completed\.?/i.test(response)) {
|
|
2161
|
+
response = '';
|
|
2162
|
+
}
|
|
2052
2163
|
state.finalResponseDraft = response;
|
|
2053
2164
|
this.recordOrchestrationAudit(state, 'finalize_response', 'completed', workflowName
|
|
2054
2165
|
? `Completed automatic TODO dispatch for workflow "${workflowName}".`
|
|
@@ -2066,6 +2177,7 @@ class OrchestratorAgent {
|
|
|
2066
2177
|
originalPrompt: prompt,
|
|
2067
2178
|
stepInstruction: 'Handle this delegated request directly.',
|
|
2068
2179
|
owner,
|
|
2180
|
+
previousWorker: null,
|
|
2069
2181
|
nextWorker: null,
|
|
2070
2182
|
projectName,
|
|
2071
2183
|
workspacePath,
|
|
@@ -2098,6 +2210,7 @@ class OrchestratorAgent {
|
|
|
2098
2210
|
originalPrompt: prompt,
|
|
2099
2211
|
stepInstruction: step.instruction,
|
|
2100
2212
|
owner: step.owner,
|
|
2213
|
+
previousWorker: steps[index - 1]?.owner || null,
|
|
2101
2214
|
nextWorker: steps[index + 1]?.owner || null,
|
|
2102
2215
|
projectName,
|
|
2103
2216
|
workspacePath,
|
|
@@ -2126,6 +2239,7 @@ class OrchestratorAgent {
|
|
|
2126
2239
|
originalPrompt: prompt,
|
|
2127
2240
|
stepInstruction: this.defaultStepInstructionForRole(item.role, prompt),
|
|
2128
2241
|
owner: item.agent,
|
|
2242
|
+
previousWorker: owners[index - 1]?.agent || null,
|
|
2129
2243
|
nextWorker: owners[index + 1]?.agent || null,
|
|
2130
2244
|
projectName: projectName || null,
|
|
2131
2245
|
workspacePath: workspacePath || null,
|
|
@@ -2178,16 +2292,34 @@ class OrchestratorAgent {
|
|
|
2178
2292
|
}
|
|
2179
2293
|
buildWorkerTaskPrompt(input) {
|
|
2180
2294
|
const workerRole = String(input.owner.role_label || input.owner.role_class || 'general').trim() || 'general';
|
|
2295
|
+
const taskType = this.normalizeTaskTypeForWorker(input.owner, null);
|
|
2181
2296
|
const composedTask = [
|
|
2182
2297
|
`Step instruction: ${input.stepInstruction}`,
|
|
2183
|
-
''
|
|
2184
|
-
|
|
2185
|
-
|
|
2298
|
+
taskType === 'qa'
|
|
2299
|
+
? 'QA scope: Use PREVIOUS WORKER HANDOFF, queued task details, and explicit success criteria as the source of truth for this QA pass. Only search for broader context if those inputs are incomplete.'
|
|
2300
|
+
: taskType === 'verify'
|
|
2301
|
+
? 'Verification scope: Compare the delivered work against the original user request and the explicit success criteria.'
|
|
2302
|
+
: '',
|
|
2303
|
+
String(input.nextWorker?.role_label || input.nextWorker?.role_class || '').trim().toLowerCase() === 'qa'
|
|
2304
|
+
? 'QA handoff rule: Scope the handoff to static artifact/code review, concrete implementation claims, and explicit pass/fail checks. Do not ask the next QA worker to open a browser, capture screenshots, test desktop/mobile breakpoints, check animations or hover effects, or re-compare against the full original request unless the user explicitly asked for runtime verification.'
|
|
2305
|
+
: '',
|
|
2306
|
+
String(input.nextWorker?.role_label || input.nextWorker?.role_class || '').trim().toLowerCase() === 'qa'
|
|
2307
|
+
? 'QA handoff rule: Do not ask the next QA worker to use memory search, image analysis, or broad codebase discovery unless a specific missing expectation cannot be checked from the artifact and nearby implementation.'
|
|
2308
|
+
: '',
|
|
2309
|
+
taskType === 'qa'
|
|
2310
|
+
? null
|
|
2311
|
+
: '',
|
|
2312
|
+
taskType === 'qa'
|
|
2313
|
+
? null
|
|
2314
|
+
: 'Original user request (reference only):',
|
|
2315
|
+
taskType === 'qa'
|
|
2316
|
+
? null
|
|
2317
|
+
: input.originalPrompt,
|
|
2186
2318
|
].join('\n');
|
|
2187
2319
|
return (0, worker_operating_prompt_1.buildWorkerOperatingPrompt)({
|
|
2188
2320
|
workerName: input.owner.name,
|
|
2189
2321
|
workerRole,
|
|
2190
|
-
taskType
|
|
2322
|
+
taskType,
|
|
2191
2323
|
taskTitle: input.stepInstruction,
|
|
2192
2324
|
taskPrompt: composedTask,
|
|
2193
2325
|
projectName: input.projectName,
|
|
@@ -2196,6 +2328,8 @@ class OrchestratorAgent {
|
|
|
2196
2328
|
heading: '',
|
|
2197
2329
|
defaultLine: 'No confirmed special policy is set.',
|
|
2198
2330
|
}),
|
|
2331
|
+
previousWorkerName: input.previousWorker?.name || null,
|
|
2332
|
+
previousWorkerRole: input.previousWorker ? String(input.previousWorker.role_label || input.previousWorker.role_class || 'general') : null,
|
|
2199
2333
|
nextWorkerName: input.nextWorker?.name || null,
|
|
2200
2334
|
nextWorkerRole: input.nextWorker ? String(input.nextWorker.role_label || input.nextWorker.role_class || 'general') : null,
|
|
2201
2335
|
});
|
|
@@ -2204,7 +2338,7 @@ class OrchestratorAgent {
|
|
|
2204
2338
|
if (role === 'research')
|
|
2205
2339
|
return `Research and plan: ${this.summarizeTodoTitle(prompt)}`;
|
|
2206
2340
|
if (role === 'qa')
|
|
2207
|
-
return `QA and
|
|
2341
|
+
return `QA and review: ${this.summarizeTodoTitle(prompt)}`;
|
|
2208
2342
|
return `Build and implement: ${this.summarizeTodoTitle(prompt)}`;
|
|
2209
2343
|
}
|
|
2210
2344
|
defaultStepInstructionForRole(role, prompt) {
|
|
@@ -2212,7 +2346,7 @@ class OrchestratorAgent {
|
|
|
2212
2346
|
return 'Research, brainstorm, or plan the work so the implementation handoff is specific and actionable.';
|
|
2213
2347
|
}
|
|
2214
2348
|
if (role === 'qa') {
|
|
2215
|
-
return '
|
|
2349
|
+
return 'QA the completed work against the previous worker handoff, delivered artifact, and explicit success criteria. Focus on artifact/code review only. Do not do browser checks, image analysis, memory search, or broad codebase discovery unless runtime verification was explicitly requested or the handoff is missing a specific fact you cannot otherwise inspect. If issues remain, prepare a precise fix handoff for the previous worker.';
|
|
2216
2350
|
}
|
|
2217
2351
|
return `Implement the requested work directly. Keep the original request in scope: ${prompt}`;
|
|
2218
2352
|
}
|
|
@@ -2220,7 +2354,7 @@ class OrchestratorAgent {
|
|
|
2220
2354
|
if (role === 'research')
|
|
2221
2355
|
return 'Produce a clear handoff that gives the next worker enough detail to execute without guessing.';
|
|
2222
2356
|
if (role === 'qa')
|
|
2223
|
-
return 'Verify the work against the
|
|
2357
|
+
return 'Verify the delivered work against the handoff and explicit success criteria, and prepare a fix handoff if issues remain.';
|
|
2224
2358
|
return 'Complete the requested implementation and prepare the next worker handoff.';
|
|
2225
2359
|
}
|
|
2226
2360
|
summarizeTodoTitle(text) {
|
|
@@ -2318,7 +2452,7 @@ class OrchestratorAgent {
|
|
|
2318
2452
|
'',
|
|
2319
2453
|
`Your task: Perform ${roleLabel} on the completed work above.`,
|
|
2320
2454
|
role === 'qa'
|
|
2321
|
-
? '
|
|
2455
|
+
? 'QA the completed work against the delivered artifact and the explicit requirements that are already present. Use the original request only to fill in missing expectations. Report what passes and what fails, and be specific about any issues found.'
|
|
2322
2456
|
: role === 'research'
|
|
2323
2457
|
? 'Analyze the work and provide insights, suggestions, or additional research as requested.'
|
|
2324
2458
|
: 'Review and provide your feedback on the completed work.',
|
|
@@ -2393,7 +2527,7 @@ class OrchestratorAgent {
|
|
|
2393
2527
|
return assignedName === orchestratorName;
|
|
2394
2528
|
const roleClass = String(orchestratorBot.role_class || '').trim().toLowerCase();
|
|
2395
2529
|
if (role === 'coding')
|
|
2396
|
-
return ['code', 'coder', 'builder', 'developer', 'engineer', 'orchestrator', 'manager'].includes(roleClass);
|
|
2530
|
+
return ['code', 'coding', 'coder', 'builder', 'developer', 'engineer', 'orchestrator', 'manager'].includes(roleClass);
|
|
2397
2531
|
if (role === 'qa')
|
|
2398
2532
|
return ['qa', 'review', 'reviewer'].includes(roleClass);
|
|
2399
2533
|
if (role === 'research')
|
|
@@ -2667,61 +2801,8 @@ class OrchestratorAgent {
|
|
|
2667
2801
|
return response;
|
|
2668
2802
|
}
|
|
2669
2803
|
async maybeRunFinalCriticPass(input) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
if (input.state?.riskLevel !== 'high')
|
|
2673
|
-
return input.candidateResponse;
|
|
2674
|
-
const qaName = input.roleAssignments.qa;
|
|
2675
|
-
if (!qaName)
|
|
2676
|
-
return input.candidateResponse;
|
|
2677
|
-
const agent = (0, orchestrator_profile_1.filterOutOrchestratorProfiles)(data.listAgentProfiles())
|
|
2678
|
-
.find((candidate) => candidate.name.toLowerCase() === qaName.toLowerCase());
|
|
2679
|
-
if (!agent)
|
|
2680
|
-
return input.candidateResponse;
|
|
2681
|
-
input.state && (0, state_1.addHelperRoleUsage)(input.state, 'verifier');
|
|
2682
|
-
input.state && (0, state_1.addDelegateTarget)(input.state, agent.name);
|
|
2683
|
-
input.state && this.recordOrchestrationAudit(input.state, 'verify_result', 'delegated', `Running final high-risk review with ${agent.name}.`, { qaAgent: agent.name });
|
|
2684
|
-
const reviewPrompt = [
|
|
2685
|
-
'You are performing a final high-risk review for an already-completed response.',
|
|
2686
|
-
'Check for safety, consistency with the user request, and whether the response appears complete enough to show as finished.',
|
|
2687
|
-
'',
|
|
2688
|
-
`Original user request:\n${input.prompt}`,
|
|
2689
|
-
'',
|
|
2690
|
-
`Candidate final response:\n${input.candidateResponse}`,
|
|
2691
|
-
'',
|
|
2692
|
-
'Return this exact footer structure:',
|
|
2693
|
-
'RESULT: PASS or FAIL, followed by one short sentence.',
|
|
2694
|
-
'SUMMARY: one short sentence.',
|
|
2695
|
-
'STATUS: PASS or FAIL',
|
|
2696
|
-
].join('\n');
|
|
2697
|
-
try {
|
|
2698
|
-
const result = await this.runNodeWithRetry('verify_result', input.state, async () => this.workflowEngine.execute(reviewPrompt, input.conversationId, agent.id, {
|
|
2699
|
-
disableDecomposition: true,
|
|
2700
|
-
disableTools: true,
|
|
2701
|
-
projectId: input.project?.id || input.state?.projectId || null,
|
|
2702
|
-
workspacePath: input.project?.folder?.trim() || undefined,
|
|
2703
|
-
}));
|
|
2704
|
-
const cleaned = this.stripWorkerProtocol(result.mergedResult);
|
|
2705
|
-
const footer = (0, status_parser_1.parseStructuredFooter)(result.mergedResult);
|
|
2706
|
-
if (input.state) {
|
|
2707
|
-
(0, state_1.appendArtifact)(input.state, 'qaFindings', cleaned || footer.summary || footer.result || 'High-risk review completed.');
|
|
2708
|
-
}
|
|
2709
|
-
const status = String(footer.status || '').trim().toUpperCase();
|
|
2710
|
-
if (status === 'FAIL' || status === 'BLOCKED') {
|
|
2711
|
-
input.state && this.recordOrchestrationAudit(input.state, 'verify_result', 'blocked', `${agent.name} flagged the final response for revision.`, { qaStatus: status, qaSummary: footer.summary || cleaned || null });
|
|
2712
|
-
return [
|
|
2713
|
-
'I paused after final review found issues that still need attention.',
|
|
2714
|
-
'',
|
|
2715
|
-
`QA review (${agent.name}): ${cleaned || footer.summary || 'The final response was not approved.'}`,
|
|
2716
|
-
].join('\n');
|
|
2717
|
-
}
|
|
2718
|
-
input.state && this.recordOrchestrationAudit(input.state, 'verify_result', 'verified', `${agent.name} approved the final high-risk response.`, { qaStatus: status || 'PASS' });
|
|
2719
|
-
return input.candidateResponse;
|
|
2720
|
-
}
|
|
2721
|
-
catch (error) {
|
|
2722
|
-
input.state && this.recordOrchestrationAudit(input.state, 'verify_result', 'blocked', `Final review failed to run cleanly: ${error?.message || error}`);
|
|
2723
|
-
return input.candidateResponse;
|
|
2724
|
-
}
|
|
2804
|
+
void input;
|
|
2805
|
+
return input.candidateResponse;
|
|
2725
2806
|
}
|
|
2726
2807
|
isHighRiskPrompt(prompt) {
|
|
2727
2808
|
return /\b(delete|remove|destroy|drop|wipe|erase|purge|archive|unarchive|deploy|ship|publish|release|migrate|migration|schema change|database change|permission|permissions|access|oauth|token|secret|credential|auth|security|api key|provider|settings?)\b/i.test(prompt);
|
|
@@ -3215,6 +3296,14 @@ class OrchestratorAgent {
|
|
|
3215
3296
|
reportHiddenRoleProgress(opts, roleName, detail) {
|
|
3216
3297
|
opts.onProgress(`${roleName}::${detail}`);
|
|
3217
3298
|
}
|
|
3299
|
+
formatConfirmationRequest(prompt) {
|
|
3300
|
+
const singleLine = String(prompt || '').replace(/\s+/g, ' ').trim();
|
|
3301
|
+
if (!singleLine)
|
|
3302
|
+
return 'Requested action';
|
|
3303
|
+
if (singleLine.length <= 180)
|
|
3304
|
+
return singleLine;
|
|
3305
|
+
return `${singleLine.slice(0, 177)}...`;
|
|
3306
|
+
}
|
|
3218
3307
|
describeIntentForActivity(intent) {
|
|
3219
3308
|
switch (intent.primaryMode) {
|
|
3220
3309
|
case 'PROXY_MODE':
|
|
@@ -3325,6 +3414,21 @@ class OrchestratorAgent {
|
|
|
3325
3414
|
}
|
|
3326
3415
|
return assignments;
|
|
3327
3416
|
}
|
|
3417
|
+
clerkModelLabel() {
|
|
3418
|
+
const runtime = this.clerk.getRuntimeInfo();
|
|
3419
|
+
if (!runtime.model)
|
|
3420
|
+
return 'Clerk';
|
|
3421
|
+
return `${runtime.model} | Clerk`;
|
|
3422
|
+
}
|
|
3423
|
+
async respondAsClerk(userPrompt, systemPrompt) {
|
|
3424
|
+
const response = await this.clerk.respond(userPrompt, systemPrompt);
|
|
3425
|
+
this.setLastResponseMeta({
|
|
3426
|
+
agentName: 'Clerk',
|
|
3427
|
+
botId: null,
|
|
3428
|
+
modelLabel: this.clerkModelLabel(),
|
|
3429
|
+
});
|
|
3430
|
+
return response;
|
|
3431
|
+
}
|
|
3328
3432
|
hasRoleAssignments(assignments) {
|
|
3329
3433
|
return Boolean(assignments.coding || assignments.qa || assignments.research);
|
|
3330
3434
|
}
|
|
@@ -3356,7 +3460,7 @@ class OrchestratorAgent {
|
|
|
3356
3460
|
const result = {};
|
|
3357
3461
|
const roleClass = String(orchestratorBot?.role_class || '').trim().toLowerCase();
|
|
3358
3462
|
if (orchestratorBot?.name) {
|
|
3359
|
-
if (['code', 'coder', 'builder', 'developer', 'engineer'].includes(roleClass)) {
|
|
3463
|
+
if (['code', 'coding', 'coder', 'builder', 'developer', 'engineer'].includes(roleClass)) {
|
|
3360
3464
|
result.coding = orchestratorBot.name;
|
|
3361
3465
|
}
|
|
3362
3466
|
else if (['qa', 'review', 'reviewer'].includes(roleClass)) {
|
|
@@ -3367,7 +3471,7 @@ class OrchestratorAgent {
|
|
|
3367
3471
|
}
|
|
3368
3472
|
}
|
|
3369
3473
|
const findByRole = (roles) => bots.find((bot) => roles.includes(String(bot.role_class || '').trim().toLowerCase()));
|
|
3370
|
-
result.coding = result.coding || findByRole(['code', 'coder', 'builder', 'developer', 'engineer'])?.name;
|
|
3474
|
+
result.coding = result.coding || findByRole(['code', 'coding', 'coder', 'builder', 'developer', 'engineer'])?.name;
|
|
3371
3475
|
result.qa = result.qa || findByRole(['qa', 'review', 'reviewer'])?.name;
|
|
3372
3476
|
result.research = result.research || findByRole(['research', 'researcher', 'analyst', 'advisor'])?.name;
|
|
3373
3477
|
return result;
|
|
@@ -3437,17 +3541,10 @@ class OrchestratorAgent {
|
|
|
3437
3541
|
},
|
|
3438
3542
|
});
|
|
3439
3543
|
return [
|
|
3440
|
-
'
|
|
3441
|
-
|
|
3442
|
-
`
|
|
3443
|
-
|
|
3444
|
-
? [
|
|
3445
|
-
'',
|
|
3446
|
-
'Deterministic guardrail path:',
|
|
3447
|
-
...deterministicPlan.steps.map((step, index) => `${index + 1}. ${step}`),
|
|
3448
|
-
]
|
|
3449
|
-
: []),
|
|
3450
|
-
'Reply with "yes, continue" to proceed or "no, cancel" to stop here.',
|
|
3544
|
+
'Are you sure you want to continue with this request?',
|
|
3545
|
+
`Request: ${this.formatConfirmationRequest(prompt)}`,
|
|
3546
|
+
`Reason: ${executionSpec.riskReasons.join(', ') || 'sensitive change'}.`,
|
|
3547
|
+
'Reply with "yes, continue" or "no, cancel".',
|
|
3451
3548
|
].join('\n');
|
|
3452
3549
|
}
|
|
3453
3550
|
async handlePendingCheckpoint(prompt, checkpoint, opts, fallbackState) {
|
|
@@ -3457,11 +3554,14 @@ class OrchestratorAgent {
|
|
|
3457
3554
|
return 'Understood. I cancelled that pending action.';
|
|
3458
3555
|
}
|
|
3459
3556
|
if (!this.isCheckpointConfirmation(prompt)) {
|
|
3557
|
+
const pausedPrompt = typeof checkpoint.payload?.prompt === 'string'
|
|
3558
|
+
? checkpoint.payload.prompt
|
|
3559
|
+
: fallbackState.userPromptRaw || '';
|
|
3460
3560
|
return [
|
|
3461
|
-
'I still have a paused
|
|
3462
|
-
|
|
3561
|
+
'I still have a paused action waiting for confirmation.',
|
|
3562
|
+
`Request: ${this.formatConfirmationRequest(pausedPrompt)}`,
|
|
3463
3563
|
`Reason: ${checkpoint.reason}.`,
|
|
3464
|
-
'Reply with "yes, continue"
|
|
3564
|
+
'Reply with "yes, continue" or "no, cancel".',
|
|
3465
3565
|
].join('\n');
|
|
3466
3566
|
}
|
|
3467
3567
|
const payload = checkpoint.payload || {};
|
|
@@ -3710,7 +3810,7 @@ class OrchestratorAgent {
|
|
|
3710
3810
|
merged.qa ? `${merged.qa} handles QA` : null,
|
|
3711
3811
|
merged.research ? `${merged.research} handles research` : null,
|
|
3712
3812
|
].filter(Boolean);
|
|
3713
|
-
if (parts.length > 0) {
|
|
3813
|
+
if (parts.length > 0 && (0, storage_mode_1.isServerStorageMode)()) {
|
|
3714
3814
|
data.upsertMemoryFact({
|
|
3715
3815
|
agentId,
|
|
3716
3816
|
conversationId,
|
|
@@ -3922,13 +4022,15 @@ class OrchestratorAgent {
|
|
|
3922
4022
|
if (!workflow)
|
|
3923
4023
|
return;
|
|
3924
4024
|
data.setProjectSetting(projectId, ORCHESTRATOR_WORKFLOW_SETTING_KEY, JSON.stringify(workflow));
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
4025
|
+
if ((0, storage_mode_1.isServerStorageMode)()) {
|
|
4026
|
+
data.upsertMemoryFact({
|
|
4027
|
+
agentId,
|
|
4028
|
+
conversationId,
|
|
4029
|
+
factType: 'operating_instruction',
|
|
4030
|
+
content: `Preferred workflow for this project: ${workflow.steps.join('; ')}.`,
|
|
4031
|
+
extractionMethod: 'orchestrator',
|
|
4032
|
+
});
|
|
4033
|
+
}
|
|
3932
4034
|
data.logAdminAudit({
|
|
3933
4035
|
actorType: 'orchestrator',
|
|
3934
4036
|
actorId: 'Project Manager',
|