funolio-agent 0.16.4 → 0.17.2
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/auth/token-refresh.d.ts +13 -5
- package/dist/auth/token-refresh.d.ts.map +1 -1
- package/dist/auth/token-refresh.js +123 -28
- package/dist/auth/token-refresh.js.map +1 -1
- package/dist/clerk-model.d.ts.map +1 -1
- package/dist/clerk-model.js +3 -0
- package/dist/clerk-model.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/local-server.d.ts.map +1 -1
- package/dist/local-server.js +49 -54
- package/dist/local-server.js.map +1 -1
- package/dist/message-loop.d.ts +1 -0
- package/dist/message-loop.d.ts.map +1 -1
- package/dist/message-loop.js +24 -1
- package/dist/message-loop.js.map +1 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +20 -0
- package/dist/oauth.js.map +1 -1
- package/dist/orchestration/front-door-policy.d.ts +8 -0
- package/dist/orchestration/front-door-policy.d.ts.map +1 -1
- package/dist/orchestration/front-door-policy.js +69 -203
- package/dist/orchestration/front-door-policy.js.map +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.js +5 -8
- package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
- package/dist/orchestration/safeguards.d.ts +1 -1
- package/dist/orchestration/safeguards.js +1 -1
- package/dist/orchestrator.d.ts +7 -2
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +100 -73
- package/dist/orchestrator.js.map +1 -1
- package/dist/providers/anthropic.d.ts +1 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +10 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/tools/run-command.d.ts.map +1 -1
- package/dist/tools/run-command.js +90 -11
- package/dist/tools/run-command.js.map +1 -1
- package/dist/tools/schedule-task.d.ts.map +1 -1
- package/dist/tools/schedule-task.js +3 -0
- package/dist/tools/schedule-task.js.map +1 -1
- package/dist/tools/search-memory.d.ts.map +1 -1
- package/dist/tools/search-memory.js +10 -6
- package/dist/tools/search-memory.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-engine.d.ts +6 -1
- package/dist/workflow-engine.d.ts.map +1 -1
- package/dist/workflow-engine.js +30 -1
- package/dist/workflow-engine.js.map +1 -1
- package/package.json +1 -1
package/dist/orchestrator.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 4. Verifies results against success criteria
|
|
10
10
|
* 5. Reports concise status back to the user
|
|
11
11
|
*
|
|
12
|
-
* The user sees ONLY their conversation with
|
|
12
|
+
* The user sees ONLY their conversation with the orchestrator.
|
|
13
13
|
* Worker LLM conversations happen behind the scenes.
|
|
14
14
|
*/
|
|
15
15
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
@@ -67,7 +67,7 @@ const ORCHESTRATION_NODE_RETRY_LIMITS = {
|
|
|
67
67
|
understand_request: 0,
|
|
68
68
|
risk_gate: 0,
|
|
69
69
|
choose_path: 0,
|
|
70
|
-
execute_direct:
|
|
70
|
+
execute_direct: 1,
|
|
71
71
|
delegate_specialist: 1,
|
|
72
72
|
run_workflow: 1,
|
|
73
73
|
verify_result: 2,
|
|
@@ -164,12 +164,37 @@ class OrchestratorAgent {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
// ─── Single-Call Orchestrator ─────────────────────────
|
|
168
|
+
// Ben always does the work first. If user named another bot, delegate AFTER.
|
|
169
|
+
if (selectedOrchestrator) {
|
|
170
|
+
orchestrationState.intent = 'execute_self';
|
|
171
|
+
(0, state_1.setOrchestrationPath)(orchestrationState, 'direct', 'direct');
|
|
172
|
+
this.recordOrchestrationAudit(orchestrationState, 'choose_path', 'path_selected', 'Orchestrator executes directly (single-call model).');
|
|
173
|
+
// Check for delegation targets before executing
|
|
174
|
+
const mentionedOtherBots = this.getMentionedAgents(prompt)
|
|
175
|
+
.filter((a) => a.id !== selectedOrchestrator.id);
|
|
176
|
+
// Step 1: Ben does the work — if delegating, tell Ben to skip the delegate's role
|
|
177
|
+
let executionPrompt = prompt;
|
|
178
|
+
if (mentionedOtherBots.length > 0) {
|
|
179
|
+
const botNames = mentionedOtherBots.map((b) => b.name).join(', ');
|
|
180
|
+
const role = this.inferDelegationRole(prompt);
|
|
181
|
+
executionPrompt = `${prompt}\n\n[System: ${botNames} will handle ${role} after you finish. Do YOUR work only — do not perform ${role} yourself. Complete your task and return your deliverable.]`;
|
|
182
|
+
}
|
|
183
|
+
const directResult = await this.executeOrchestratorOwnedWork(executionPrompt, conversationId, selectedOrchestrator, initialAssignments, initialProject, opts, orchestrationState);
|
|
184
|
+
if (mentionedOtherBots.length > 0 && directResult.ok) {
|
|
185
|
+
const delegateBot = mentionedOtherBots[0];
|
|
186
|
+
this.recordOrchestrationAudit(orchestrationState, 'delegate_specialist', 'delegated', `Delegating to ${delegateBot.name} after orchestrator completed work.`, { delegateBot: delegateBot.name });
|
|
187
|
+
try {
|
|
188
|
+
const delegateResponse = await this.executeDelegation(directResult.response, prompt, delegateBot, conversationId, initialProject, opts, orchestrationState);
|
|
189
|
+
return delegateResponse;
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
// If delegation fails, still return Ben's result
|
|
193
|
+
this.recordOrchestrationAudit(orchestrationState, 'delegate_specialist', 'blocked', `Delegation to ${delegateBot.name} failed: ${err?.message || err}. Returning orchestrator result.`);
|
|
194
|
+
return directResult.response;
|
|
195
|
+
}
|
|
171
196
|
}
|
|
172
|
-
|
|
197
|
+
return directResult.response;
|
|
173
198
|
}
|
|
174
199
|
this.reportHiddenRoleProgress(opts, 'intent_classifier', 'Classifying request');
|
|
175
200
|
(0, state_1.addHelperRoleUsage)(orchestrationState, 'intent_classifier');
|
|
@@ -943,15 +968,9 @@ class OrchestratorAgent {
|
|
|
943
968
|
return lines.join('\n\n');
|
|
944
969
|
}
|
|
945
970
|
getAgentReferenceTerms(agent) {
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
terms.push('gpt');
|
|
950
|
-
if (normalized === 'ben')
|
|
951
|
-
terms.push('claude');
|
|
952
|
-
if (normalized === 'john')
|
|
953
|
-
terms.push('codex');
|
|
954
|
-
return Array.from(new Set(terms.map((term) => term.trim()).filter(Boolean)));
|
|
971
|
+
// Only use exact bot names — no aliases.
|
|
972
|
+
// Aliases like "claude" → "Ben" cause false matches on every prompt.
|
|
973
|
+
return [agent.name.trim()].filter(Boolean);
|
|
955
974
|
}
|
|
956
975
|
/**
|
|
957
976
|
* Interpret user intent using the clerk.
|
|
@@ -1420,13 +1439,6 @@ class OrchestratorAgent {
|
|
|
1420
1439
|
.replace(/\n?STATUS:\s*(PASS|FAIL|COMPLETE|BLOCKED|UNKNOWN)\s*$/i, '')
|
|
1421
1440
|
.trim() || rawText.trim();
|
|
1422
1441
|
}
|
|
1423
|
-
isOrchestratorV2Enabled() {
|
|
1424
|
-
const envValue = String(process.env.ORCH_V2_ENABLED || '').trim().toLowerCase();
|
|
1425
|
-
if (envValue === '1' || envValue === 'true' || envValue === 'yes' || envValue === 'on') {
|
|
1426
|
-
return true;
|
|
1427
|
-
}
|
|
1428
|
-
return data.getSetting('orchestrator_v2_enabled') === 'true';
|
|
1429
|
-
}
|
|
1430
1442
|
resolveSelectedOrchestratorBot(conversation) {
|
|
1431
1443
|
const conversationBotId = conversation?.agent_id;
|
|
1432
1444
|
if (conversationBotId) {
|
|
@@ -1526,22 +1538,10 @@ class OrchestratorAgent {
|
|
|
1526
1538
|
explicitWorkflowRequested: normalizedDecision.explicitWorkflowRequested,
|
|
1527
1539
|
corrected: normalizedDecision.corrected,
|
|
1528
1540
|
});
|
|
1541
|
+
// Clarify should never reach here (parser + policy convert to execute_self),
|
|
1542
|
+
// but if it somehow does, treat it as execute_self — just do the work.
|
|
1529
1543
|
if (decision.mode === 'clarify') {
|
|
1530
|
-
|
|
1531
|
-
this.recordOrchestrationAudit(state, 'require_confirmation', 'clarification_requested', decision.reason || 'Orchestrator requested clarification.', { clarificationQuestions: decision.clarification_questions || [] });
|
|
1532
|
-
return this.formatClarificationResponse({
|
|
1533
|
-
primaryMode: 'DIRECT_CONVERSATION',
|
|
1534
|
-
secondaryModes: [],
|
|
1535
|
-
executionOrder: ['DIRECT_CONVERSATION'],
|
|
1536
|
-
userFacingMode: 'DIRECT_RESPONSE',
|
|
1537
|
-
targetScope: 'SELF',
|
|
1538
|
-
confidence: 'HIGH',
|
|
1539
|
-
intent: 'question',
|
|
1540
|
-
isMultiStep: false,
|
|
1541
|
-
reasoning: decision.reason,
|
|
1542
|
-
needsClarification: true,
|
|
1543
|
-
clarificationQuestions: decision.clarification_questions || ['Can you clarify what you want me to do?'],
|
|
1544
|
-
}, overview);
|
|
1544
|
+
decision.mode = 'execute_self';
|
|
1545
1545
|
}
|
|
1546
1546
|
if (decision.mode === 'respond') {
|
|
1547
1547
|
const response = decision.response?.trim() || this.handleDirectConversation(prompt, overview, roleAssignments, state);
|
|
@@ -1550,39 +1550,10 @@ class OrchestratorAgent {
|
|
|
1550
1550
|
return response;
|
|
1551
1551
|
}
|
|
1552
1552
|
if (decision.mode === 'execute_self') {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
executionOrder: ['DIRECT_CONVERSATION'],
|
|
1557
|
-
userFacingMode: 'DIRECT_RESPONSE',
|
|
1558
|
-
targetScope: 'SELF',
|
|
1559
|
-
confidence: 'HIGH',
|
|
1560
|
-
intent: this.inferFrontDoorIntent(normalizedDecision.taskType, decision),
|
|
1561
|
-
isMultiStep: false,
|
|
1562
|
-
reasoning: decision.reason,
|
|
1563
|
-
};
|
|
1564
|
-
const frontDoorEffectivePolicy = this.buildFrontDoorEffectivePolicy(policy, orchestratorBot, roleAssignments, normalizedDecision.taskType);
|
|
1565
|
-
const validation = this.validateIntentExecution(prompt, directIntent, frontDoorEffectivePolicy);
|
|
1566
|
-
if (!validation.ok) {
|
|
1567
|
-
return validation.clarificationQuestions?.length
|
|
1568
|
-
? this.formatClarificationResponse({ ...directIntent, clarificationQuestions: validation.clarificationQuestions }, overview)
|
|
1569
|
-
: null;
|
|
1570
|
-
}
|
|
1571
|
-
const guardrailQuestions = this.buildDeterministicGuardrailQuestions(validation.executionSpec, roleAssignments, directIntent);
|
|
1572
|
-
if (guardrailQuestions.length > 0) {
|
|
1573
|
-
return this.formatClarificationResponse({ ...directIntent, clarificationQuestions: guardrailQuestions }, overview);
|
|
1574
|
-
}
|
|
1575
|
-
this.applyExecutionSpecToState(state, validation.executionSpec);
|
|
1576
|
-
if (validation.executionSpec.requiresConfirmation) {
|
|
1577
|
-
return this.createConfirmationCheckpoint(prompt, conversationId, directIntent, validation.executionSpec, projectId, roleAssignments, state);
|
|
1578
|
-
}
|
|
1553
|
+
// No guardrails, no confirmation checkpoints, no validation blocking.
|
|
1554
|
+
// Ben just does the work — like Claude CLI.
|
|
1555
|
+
(0, state_1.setOrchestrationPath)(state, 'direct', 'direct');
|
|
1579
1556
|
const directResult = await this.executeOrchestratorOwnedWork(prompt, conversationId, orchestratorBot, roleAssignments, project, opts, state);
|
|
1580
|
-
if (directResult.ok && directIntent.intent === 'build' && state.requestedArtifactTargets.length > 0) {
|
|
1581
|
-
const artifactValidation = this.validateRequestedArtifactTargets(state, project);
|
|
1582
|
-
if (!artifactValidation.ok) {
|
|
1583
|
-
return `${orchestratorBot.name} encountered an issue: ${artifactValidation.message}`;
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
1557
|
return directResult.response;
|
|
1587
1558
|
}
|
|
1588
1559
|
if (decision.mode === 'delegate') {
|
|
@@ -1736,11 +1707,11 @@ class OrchestratorAgent {
|
|
|
1736
1707
|
this.reportHiddenRoleProgress(opts, 'orchestrator', `${orchestratorBot.name} is working on the request`);
|
|
1737
1708
|
const result = await this.runNodeWithRetry('execute_direct', state, async () => this.workflowEngine.execute(prompt, conversationId, orchestratorBot.id, {
|
|
1738
1709
|
disableDecomposition: true,
|
|
1739
|
-
isOrchestrated:
|
|
1710
|
+
isOrchestrated: false,
|
|
1740
1711
|
projectId: project?.id || state.projectId || null,
|
|
1741
1712
|
workspacePath: project?.folder?.trim() || undefined,
|
|
1742
|
-
persistConversationMessages:
|
|
1743
|
-
workerMode:
|
|
1713
|
+
persistConversationMessages: true,
|
|
1714
|
+
workerMode: false,
|
|
1744
1715
|
onWorkerChunk: opts.onWorkerChunk,
|
|
1745
1716
|
onProgress: (progress) => {
|
|
1746
1717
|
if (progress.event === 'step-started') {
|
|
@@ -1790,6 +1761,59 @@ class OrchestratorAgent {
|
|
|
1790
1761
|
this.recordOrchestrationAudit(state, 'finalize_response', 'completed', 'Completed orchestrator-owned execution.');
|
|
1791
1762
|
return { ok: true, response: reviewed, rawResult: result };
|
|
1792
1763
|
}
|
|
1764
|
+
/**
|
|
1765
|
+
* Delegate Ben's completed work to another bot (e.g., John for QA, Brain for research).
|
|
1766
|
+
* Called AFTER executeOrchestratorOwnedWork completes.
|
|
1767
|
+
*/
|
|
1768
|
+
async executeDelegation(benResult, originalPrompt, delegateBot, conversationId, project, opts, state) {
|
|
1769
|
+
const role = this.inferDelegationRole(originalPrompt);
|
|
1770
|
+
const roleLabel = role === 'qa' ? 'QA / review' : role === 'research' ? 'research / analysis' : 'review';
|
|
1771
|
+
const delegationPrompt = [
|
|
1772
|
+
`The user's original request:\n${originalPrompt}`,
|
|
1773
|
+
'',
|
|
1774
|
+
`The orchestrator (Ben) completed the following work:\n${benResult.length > 8000 ? benResult.slice(0, 8000) + '\n...(truncated)' : benResult}`,
|
|
1775
|
+
'',
|
|
1776
|
+
`Your task: Perform ${roleLabel} on the completed work above.`,
|
|
1777
|
+
role === 'qa'
|
|
1778
|
+
? 'Review the work against the original request. Report what passes and what fails. Be specific about any issues found.'
|
|
1779
|
+
: role === 'research'
|
|
1780
|
+
? 'Analyze the work and provide insights, suggestions, or additional research as requested.'
|
|
1781
|
+
: 'Review and provide your feedback on the completed work.',
|
|
1782
|
+
].join('\n');
|
|
1783
|
+
this.reportHiddenRoleProgress(opts, 'orchestrator', `Sending work to ${delegateBot.name} for ${roleLabel}`);
|
|
1784
|
+
(0, state_1.addHelperRoleUsage)(state, 'dispatch_controller');
|
|
1785
|
+
(0, state_1.addDelegateTarget)(state, delegateBot.name);
|
|
1786
|
+
const result = await this.runNodeWithRetry('delegate_specialist', state, async () => this.workflowEngine.execute(delegationPrompt, conversationId, delegateBot.id, {
|
|
1787
|
+
disableDecomposition: true,
|
|
1788
|
+
isOrchestrated: false,
|
|
1789
|
+
workerMode: false,
|
|
1790
|
+
projectId: project?.id || state.projectId || null,
|
|
1791
|
+
workspacePath: project?.folder?.trim() || undefined,
|
|
1792
|
+
persistConversationMessages: true,
|
|
1793
|
+
onWorkerChunk: opts.onWorkerChunk,
|
|
1794
|
+
onProgress: (progress) => {
|
|
1795
|
+
if (progress.event === 'step-started') {
|
|
1796
|
+
this.reportHiddenRoleProgress(opts, 'orchestrator', `${delegateBot.name} is reviewing the work`);
|
|
1797
|
+
}
|
|
1798
|
+
else if (progress.event === 'step-completed') {
|
|
1799
|
+
this.reportHiddenRoleProgress(opts, 'orchestrator', `${delegateBot.name} completed review`);
|
|
1800
|
+
}
|
|
1801
|
+
},
|
|
1802
|
+
}));
|
|
1803
|
+
const delegateResponse = this.stripWorkerProtocol(result.mergedResult);
|
|
1804
|
+
this.reportHiddenRoleProgress(opts, 'orchestrator', `${delegateBot.name} completed ${roleLabel}`);
|
|
1805
|
+
this.recordOrchestrationAudit(state, 'finalize_response', 'completed', `Delegation to ${delegateBot.name} completed.`);
|
|
1806
|
+
// Return combined response
|
|
1807
|
+
return `${benResult}\n\n---\n\n**${delegateBot.name} (${roleLabel}):**\n\n${delegateResponse}`;
|
|
1808
|
+
}
|
|
1809
|
+
inferDelegationRole(prompt) {
|
|
1810
|
+
const lower = prompt.toLowerCase();
|
|
1811
|
+
if (/\b(qa|test|review|check|verify|audit|pass\/fail)\b/.test(lower))
|
|
1812
|
+
return 'qa';
|
|
1813
|
+
if (/\b(research|brainstorm|analyze|investigate|evaluate)\b/.test(lower))
|
|
1814
|
+
return 'research';
|
|
1815
|
+
return 'discuss';
|
|
1816
|
+
}
|
|
1793
1817
|
inferRequestedWorkflowRoles(prompt, roleAssignments) {
|
|
1794
1818
|
const normalized = String(prompt || '').toLowerCase();
|
|
1795
1819
|
const explicitResearch = /\b(brain|gpt|research(?:es|ed|ing)?|investigat(?:e|es|ed|ing)|analy[sz](?:e|es|ed|ing)|analysis|sound idea|review the idea|pressure[- ]?test|brainstorm(?:ed|ing)?)\b/.test(normalized)
|
|
@@ -2421,6 +2445,9 @@ class OrchestratorAgent {
|
|
|
2421
2445
|
if (state && workflowTemplate) {
|
|
2422
2446
|
state.preferredWorkflowUsed = true;
|
|
2423
2447
|
}
|
|
2448
|
+
// TODO: planWorkflow uses the cheap clerk (GPT-4o-mini). Per architecture doc,
|
|
2449
|
+
// workflow planning should be done by the orchestrator LLM, not the clerk.
|
|
2450
|
+
// The clerk should only do summaries, extraction, and compression.
|
|
2424
2451
|
const plannedSteps = !workflowTemplate
|
|
2425
2452
|
? await this.clerk.planWorkflow({
|
|
2426
2453
|
prompt,
|