musubi-sdd 5.1.0 → 5.6.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/README.ja.md +106 -48
- package/README.md +110 -32
- package/bin/musubi-analyze.js +74 -67
- package/bin/musubi-browser.js +27 -26
- package/bin/musubi-change.js +48 -47
- package/bin/musubi-checkpoint.js +10 -7
- package/bin/musubi-convert.js +25 -25
- package/bin/musubi-costs.js +27 -10
- package/bin/musubi-gui.js +52 -46
- package/bin/musubi-init.js +1952 -10
- package/bin/musubi-orchestrate.js +327 -239
- package/bin/musubi-remember.js +69 -56
- package/bin/musubi-resolve.js +53 -45
- package/bin/musubi-trace.js +51 -22
- package/bin/musubi-validate.js +39 -30
- package/bin/musubi-workflow.js +33 -34
- package/bin/musubi.js +39 -2
- package/package.json +1 -1
- package/src/agents/agent-loop.js +94 -95
- package/src/agents/agentic/code-generator.js +119 -109
- package/src/agents/agentic/code-reviewer.js +105 -108
- package/src/agents/agentic/index.js +4 -4
- package/src/agents/browser/action-executor.js +13 -13
- package/src/agents/browser/ai-comparator.js +11 -10
- package/src/agents/browser/context-manager.js +6 -6
- package/src/agents/browser/index.js +5 -5
- package/src/agents/browser/nl-parser.js +31 -46
- package/src/agents/browser/screenshot.js +2 -2
- package/src/agents/browser/test-generator.js +6 -4
- package/src/agents/function-tool.js +71 -65
- package/src/agents/index.js +7 -7
- package/src/agents/schema-generator.js +98 -94
- package/src/analyzers/ast-extractor.js +158 -146
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +241 -126
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +77 -81
- package/src/analyzers/security-analyzer.js +19 -11
- package/src/analyzers/stuck-detector.js +19 -17
- package/src/converters/index.js +78 -57
- package/src/converters/ir/types.js +12 -12
- package/src/converters/parsers/musubi-parser.js +134 -126
- package/src/converters/parsers/openapi-parser.js +70 -53
- package/src/converters/parsers/speckit-parser.js +239 -175
- package/src/converters/writers/musubi-writer.js +123 -118
- package/src/converters/writers/speckit-writer.js +124 -113
- package/src/generators/rust-migration-generator.js +512 -0
- package/src/gui/public/index.html +1365 -1211
- package/src/gui/server.js +41 -40
- package/src/gui/services/file-watcher.js +23 -8
- package/src/gui/services/project-scanner.js +26 -20
- package/src/gui/services/replanning-service.js +27 -23
- package/src/gui/services/traceability-service.js +8 -8
- package/src/gui/services/workflow-service.js +14 -7
- package/src/index.js +151 -0
- package/src/integrations/cicd.js +90 -104
- package/src/integrations/codegraph-mcp.js +643 -0
- package/src/integrations/documentation.js +142 -103
- package/src/integrations/examples.js +95 -80
- package/src/integrations/github-client.js +17 -17
- package/src/integrations/index.js +5 -5
- package/src/integrations/mcp/index.js +21 -21
- package/src/integrations/mcp/mcp-context-provider.js +76 -78
- package/src/integrations/mcp/mcp-discovery.js +74 -72
- package/src/integrations/mcp/mcp-tool-registry.js +99 -94
- package/src/integrations/mcp-connector.js +70 -66
- package/src/integrations/platforms.js +50 -49
- package/src/integrations/tool-discovery.js +37 -31
- package/src/llm-providers/anthropic-provider.js +11 -11
- package/src/llm-providers/base-provider.js +16 -18
- package/src/llm-providers/copilot-provider.js +22 -19
- package/src/llm-providers/index.js +26 -25
- package/src/llm-providers/ollama-provider.js +11 -11
- package/src/llm-providers/openai-provider.js +12 -12
- package/src/managers/agent-memory.js +36 -24
- package/src/managers/checkpoint-manager.js +4 -8
- package/src/managers/delta-spec.js +19 -19
- package/src/managers/index.js +13 -4
- package/src/managers/memory-condenser.js +35 -45
- package/src/managers/repo-skill-manager.js +57 -31
- package/src/managers/skill-loader.js +25 -22
- package/src/managers/skill-tools.js +36 -72
- package/src/managers/workflow.js +30 -22
- package/src/monitoring/cost-tracker.js +48 -46
- package/src/monitoring/incident-manager.js +116 -106
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +75 -62
- package/src/monitoring/quality-dashboard.js +45 -41
- package/src/monitoring/release-manager.js +63 -53
- package/src/orchestration/agent-skill-binding.js +39 -47
- package/src/orchestration/error-handler.js +65 -107
- package/src/orchestration/guardrails/base-guardrail.js +26 -24
- package/src/orchestration/guardrails/guardrail-rules.js +50 -64
- package/src/orchestration/guardrails/index.js +5 -5
- package/src/orchestration/guardrails/input-guardrail.js +58 -45
- package/src/orchestration/guardrails/output-guardrail.js +104 -81
- package/src/orchestration/guardrails/safety-check.js +79 -79
- package/src/orchestration/index.js +38 -55
- package/src/orchestration/mcp-tool-adapters.js +96 -99
- package/src/orchestration/orchestration-engine.js +21 -21
- package/src/orchestration/pattern-registry.js +60 -45
- package/src/orchestration/patterns/auto.js +34 -47
- package/src/orchestration/patterns/group-chat.js +59 -65
- package/src/orchestration/patterns/handoff.js +67 -65
- package/src/orchestration/patterns/human-in-loop.js +51 -72
- package/src/orchestration/patterns/nested.js +25 -40
- package/src/orchestration/patterns/sequential.js +35 -34
- package/src/orchestration/patterns/swarm.js +63 -56
- package/src/orchestration/patterns/triage.js +150 -109
- package/src/orchestration/reasoning/index.js +9 -9
- package/src/orchestration/reasoning/planning-engine.js +143 -140
- package/src/orchestration/reasoning/reasoning-engine.js +206 -144
- package/src/orchestration/reasoning/self-correction.js +121 -128
- package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
- package/src/orchestration/replanning/alternative-generator.js +37 -42
- package/src/orchestration/replanning/config.js +63 -59
- package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
- package/src/orchestration/replanning/index.js +24 -20
- package/src/orchestration/replanning/plan-evaluator.js +49 -50
- package/src/orchestration/replanning/plan-monitor.js +32 -28
- package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
- package/src/orchestration/replanning/replan-history.js +33 -26
- package/src/orchestration/replanning/replanning-engine.js +106 -108
- package/src/orchestration/skill-executor.js +107 -109
- package/src/orchestration/skill-registry.js +85 -89
- package/src/orchestration/workflow-examples.js +228 -231
- package/src/orchestration/workflow-executor.js +65 -68
- package/src/orchestration/workflow-orchestrator.js +72 -73
- package/src/phase4-integration.js +47 -40
- package/src/phase5-integration.js +89 -30
- package/src/reporters/coverage-report.js +82 -30
- package/src/reporters/hierarchical-reporter.js +498 -0
- package/src/reporters/traceability-matrix-report.js +29 -20
- package/src/resolvers/issue-resolver.js +43 -31
- package/src/steering/advanced-validation.js +133 -124
- package/src/steering/auto-updater.js +60 -73
- package/src/steering/index.js +6 -6
- package/src/steering/quality-metrics.js +41 -35
- package/src/steering/steering-auto-update.js +83 -86
- package/src/steering/steering-validator.js +98 -106
- package/src/steering/template-constraints.js +53 -54
- package/src/templates/agents/claude-code/CLAUDE.md +32 -32
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
- package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
- package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
- package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
- package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
- package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
- package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
- package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
- package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
- package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
- package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
- package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
- package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
- package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
- package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
- package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
- package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
- package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
- package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
- package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
- package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
- package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
- package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
- package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
- package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
- package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
- package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
- package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
- package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
- package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
- package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
- package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
- package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
- package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
- package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
- package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
- package/src/templates/agents/codex/AGENTS.md +74 -42
- package/src/templates/agents/cursor/AGENTS.md +74 -42
- package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
- package/src/templates/agents/github-copilot/AGENTS.md +83 -51
- package/src/templates/agents/qwen-code/QWEN.md +74 -42
- package/src/templates/agents/windsurf/AGENTS.md +74 -42
- package/src/templates/architectures/README.md +41 -0
- package/src/templates/architectures/clean-architecture/README.md +113 -0
- package/src/templates/architectures/event-driven/README.md +162 -0
- package/src/templates/architectures/hexagonal/README.md +130 -0
- package/src/templates/index.js +6 -1
- package/src/templates/locale-manager.js +16 -16
- package/src/templates/shared/delta-spec-template.md +20 -13
- package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
- package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
- package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
- package/src/templates/shared/steering/structure.md +95 -0
- package/src/templates/skills/browser-agent.md +21 -16
- package/src/templates/skills/web-gui.md +8 -0
- package/src/templates/template-constraints.js +50 -53
- package/src/validators/advanced-validation.js +30 -36
- package/src/validators/constitutional-validator.js +77 -73
- package/src/validators/critic-system.js +49 -59
- package/src/validators/delta-format.js +59 -55
- package/src/validators/traceability-validator.js +7 -11
package/src/agents/agent-loop.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MUSUBI Agent Loop
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Implements agentic tool-calling loop inspired by OpenAI Agents SDK
|
|
5
5
|
* and AutoGen patterns. Executes tool calls, processes results, and
|
|
6
6
|
* continues until completion or limit is reached.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @module agents/agent-loop
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -53,30 +53,30 @@ class AgentLoop extends EventEmitter {
|
|
|
53
53
|
*/
|
|
54
54
|
constructor(config = {}) {
|
|
55
55
|
super();
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
this.maxIterations = config.maxIterations ?? 10;
|
|
58
58
|
this.timeout = config.timeout ?? 60000;
|
|
59
59
|
this.iterationTimeout = config.iterationTimeout ?? 30000;
|
|
60
60
|
this.continueOnError = config.continueOnError ?? false;
|
|
61
61
|
this.completionCheck = config.completionCheck ?? this.defaultCompletionCheck.bind(this);
|
|
62
62
|
this.guardrails = config.guardrails ?? null;
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
/** @type {Map<string, ToolDefinition>} */
|
|
65
65
|
this.tools = new Map();
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
/** @type {Array} */
|
|
68
68
|
this.messages = [];
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
/** @type {Array<ToolCall>} */
|
|
71
71
|
this.toolCallHistory = [];
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
/** @type {boolean} */
|
|
74
74
|
this.isRunning = false;
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
/** @type {AbortController|null} */
|
|
77
77
|
this.abortController = null;
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
/**
|
|
81
81
|
* Register a tool for the agent to use
|
|
82
82
|
* @param {ToolDefinition} tool
|
|
@@ -85,18 +85,18 @@ class AgentLoop extends EventEmitter {
|
|
|
85
85
|
if (!tool.name || typeof tool.handler !== 'function') {
|
|
86
86
|
throw new Error('Tool must have name and handler function');
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
this.tools.set(tool.name, {
|
|
90
90
|
name: tool.name,
|
|
91
91
|
description: tool.description || '',
|
|
92
92
|
parameters: tool.parameters || { type: 'object', properties: {} },
|
|
93
|
-
handler: tool.handler
|
|
93
|
+
handler: tool.handler,
|
|
94
94
|
});
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
this.emit('tool:registered', { name: tool.name });
|
|
97
97
|
return this;
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
/**
|
|
101
101
|
* Register multiple tools at once
|
|
102
102
|
* @param {ToolDefinition[]} tools
|
|
@@ -107,7 +107,7 @@ class AgentLoop extends EventEmitter {
|
|
|
107
107
|
}
|
|
108
108
|
return this;
|
|
109
109
|
}
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
/**
|
|
112
112
|
* Unregister a tool
|
|
113
113
|
* @param {string} name
|
|
@@ -119,7 +119,7 @@ class AgentLoop extends EventEmitter {
|
|
|
119
119
|
}
|
|
120
120
|
return deleted;
|
|
121
121
|
}
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
/**
|
|
124
124
|
* Get all registered tools in OpenAI function format
|
|
125
125
|
* @returns {Array}
|
|
@@ -130,11 +130,11 @@ class AgentLoop extends EventEmitter {
|
|
|
130
130
|
function: {
|
|
131
131
|
name: tool.name,
|
|
132
132
|
description: tool.description,
|
|
133
|
-
parameters: tool.parameters
|
|
134
|
-
}
|
|
133
|
+
parameters: tool.parameters,
|
|
134
|
+
},
|
|
135
135
|
}));
|
|
136
136
|
}
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
/**
|
|
139
139
|
* Run the agent loop with an LLM provider
|
|
140
140
|
* @param {Object} options
|
|
@@ -148,62 +148,62 @@ class AgentLoop extends EventEmitter {
|
|
|
148
148
|
if (this.isRunning) {
|
|
149
149
|
throw new Error('Agent loop is already running');
|
|
150
150
|
}
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
this.isRunning = true;
|
|
153
153
|
this.abortController = new AbortController();
|
|
154
154
|
this.messages = [];
|
|
155
155
|
this.toolCallHistory = [];
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
const startTime = Date.now();
|
|
158
158
|
const timeoutId = setTimeout(() => this.abort('timeout'), this.timeout);
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
const metrics = {
|
|
161
161
|
iterations: 0,
|
|
162
162
|
toolCalls: 0,
|
|
163
163
|
startTime,
|
|
164
164
|
endTime: null,
|
|
165
165
|
duration: null,
|
|
166
|
-
tokensUsed: 0
|
|
166
|
+
tokensUsed: 0,
|
|
167
167
|
};
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
try {
|
|
170
170
|
// Initialize messages
|
|
171
171
|
this.messages.push({ role: 'system', content: systemPrompt });
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
// Apply input guardrails if configured
|
|
174
174
|
const processedInput = await this.applyInputGuardrails(userMessage, context);
|
|
175
175
|
this.messages.push({ role: 'user', content: processedInput });
|
|
176
|
-
|
|
176
|
+
|
|
177
177
|
let iteration = 0;
|
|
178
178
|
let completed = false;
|
|
179
179
|
let finalOutput = null;
|
|
180
|
-
|
|
180
|
+
|
|
181
181
|
while (iteration < this.maxIterations && !completed) {
|
|
182
182
|
if (this.abortController.signal.aborted) {
|
|
183
183
|
return this.createResult('aborted', finalOutput, metrics);
|
|
184
184
|
}
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
iteration++;
|
|
187
187
|
metrics.iterations = iteration;
|
|
188
188
|
this.emit('iteration:start', { iteration, maxIterations: this.maxIterations });
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
// Call LLM
|
|
191
191
|
const response = await this.callLLMWithTimeout(llmProvider, {
|
|
192
192
|
messages: this.messages,
|
|
193
193
|
tools: this.getToolSchemas(),
|
|
194
|
-
context
|
|
194
|
+
context,
|
|
195
195
|
});
|
|
196
|
-
|
|
196
|
+
|
|
197
197
|
if (response.usage) {
|
|
198
198
|
metrics.tokensUsed += response.usage.total_tokens || 0;
|
|
199
199
|
}
|
|
200
|
-
|
|
200
|
+
|
|
201
201
|
// Check for tool calls
|
|
202
202
|
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
203
203
|
// Execute tool calls
|
|
204
204
|
const toolResults = await this.executeToolCalls(response.toolCalls);
|
|
205
205
|
metrics.toolCalls += response.toolCalls.length;
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
// Add assistant message with tool calls
|
|
208
208
|
this.messages.push({
|
|
209
209
|
role: 'assistant',
|
|
@@ -213,68 +213,67 @@ class AgentLoop extends EventEmitter {
|
|
|
213
213
|
type: 'function',
|
|
214
214
|
function: {
|
|
215
215
|
name: tc.tool || tc.name,
|
|
216
|
-
arguments: JSON.stringify(tc.arguments)
|
|
217
|
-
}
|
|
218
|
-
}))
|
|
216
|
+
arguments: JSON.stringify(tc.arguments),
|
|
217
|
+
},
|
|
218
|
+
})),
|
|
219
219
|
});
|
|
220
|
-
|
|
220
|
+
|
|
221
221
|
// Add tool results
|
|
222
222
|
for (const result of toolResults) {
|
|
223
223
|
this.messages.push({
|
|
224
224
|
role: 'tool',
|
|
225
225
|
tool_call_id: result.callId,
|
|
226
|
-
content: JSON.stringify(result.output)
|
|
226
|
+
content: JSON.stringify(result.output),
|
|
227
227
|
});
|
|
228
228
|
}
|
|
229
|
-
|
|
229
|
+
|
|
230
230
|
this.emit('iteration:complete', {
|
|
231
231
|
iteration,
|
|
232
232
|
toolCalls: response.toolCalls.length,
|
|
233
|
-
hasMore: true
|
|
233
|
+
hasMore: true,
|
|
234
234
|
});
|
|
235
235
|
} else {
|
|
236
236
|
// No tool calls - LLM response is final
|
|
237
237
|
finalOutput = response.content;
|
|
238
|
-
|
|
238
|
+
|
|
239
239
|
// Apply output guardrails
|
|
240
240
|
finalOutput = await this.applyOutputGuardrails(finalOutput, context);
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
// Add final assistant message
|
|
243
243
|
this.messages.push({
|
|
244
244
|
role: 'assistant',
|
|
245
|
-
content: finalOutput
|
|
245
|
+
content: finalOutput,
|
|
246
246
|
});
|
|
247
|
-
|
|
247
|
+
|
|
248
248
|
// Check completion
|
|
249
249
|
completed = await this.completionCheck(finalOutput, this.messages, context);
|
|
250
|
-
|
|
250
|
+
|
|
251
251
|
this.emit('iteration:complete', {
|
|
252
252
|
iteration,
|
|
253
253
|
toolCalls: 0,
|
|
254
|
-
hasMore: !completed
|
|
254
|
+
hasMore: !completed,
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
-
|
|
258
|
+
|
|
259
259
|
metrics.endTime = Date.now();
|
|
260
260
|
metrics.duration = metrics.endTime - startTime;
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
if (iteration >= this.maxIterations && !completed) {
|
|
263
263
|
return this.createResult('max_iterations', finalOutput, metrics);
|
|
264
264
|
}
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
return this.createResult('completed', finalOutput, metrics);
|
|
267
|
-
|
|
268
267
|
} catch (error) {
|
|
269
268
|
metrics.endTime = Date.now();
|
|
270
269
|
metrics.duration = metrics.endTime - startTime;
|
|
271
|
-
|
|
270
|
+
|
|
272
271
|
this.emit('error', error);
|
|
273
|
-
|
|
272
|
+
|
|
274
273
|
if (error.message === 'timeout') {
|
|
275
274
|
return this.createResult('timeout', null, metrics);
|
|
276
275
|
}
|
|
277
|
-
|
|
276
|
+
|
|
278
277
|
return this.createResult('error', null, metrics, error);
|
|
279
278
|
} finally {
|
|
280
279
|
clearTimeout(timeoutId);
|
|
@@ -282,7 +281,7 @@ class AgentLoop extends EventEmitter {
|
|
|
282
281
|
this.abortController = null;
|
|
283
282
|
}
|
|
284
283
|
}
|
|
285
|
-
|
|
284
|
+
|
|
286
285
|
/**
|
|
287
286
|
* Call LLM with per-iteration timeout
|
|
288
287
|
* @param {Object} llmProvider
|
|
@@ -294,8 +293,9 @@ class AgentLoop extends EventEmitter {
|
|
|
294
293
|
const timeoutId = setTimeout(() => {
|
|
295
294
|
reject(new Error('Iteration timeout'));
|
|
296
295
|
}, this.iterationTimeout);
|
|
297
|
-
|
|
298
|
-
llmProvider
|
|
296
|
+
|
|
297
|
+
llmProvider
|
|
298
|
+
.chat(options)
|
|
299
299
|
.then(response => {
|
|
300
300
|
clearTimeout(timeoutId);
|
|
301
301
|
resolve(response);
|
|
@@ -306,7 +306,7 @@ class AgentLoop extends EventEmitter {
|
|
|
306
306
|
});
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
|
-
|
|
309
|
+
|
|
310
310
|
/**
|
|
311
311
|
* Execute tool calls and collect results
|
|
312
312
|
* @param {ToolCall[]} toolCalls
|
|
@@ -314,73 +314,72 @@ class AgentLoop extends EventEmitter {
|
|
|
314
314
|
*/
|
|
315
315
|
async executeToolCalls(toolCalls) {
|
|
316
316
|
const results = [];
|
|
317
|
-
|
|
317
|
+
|
|
318
318
|
for (const call of toolCalls) {
|
|
319
319
|
const toolName = call.tool || call.name;
|
|
320
320
|
const callId = call.id || `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
321
|
-
|
|
321
|
+
|
|
322
322
|
this.emit('tool:call', { name: toolName, arguments: call.arguments, id: callId });
|
|
323
|
-
|
|
323
|
+
|
|
324
324
|
try {
|
|
325
325
|
const tool = this.tools.get(toolName);
|
|
326
|
-
|
|
326
|
+
|
|
327
327
|
if (!tool) {
|
|
328
328
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
329
329
|
}
|
|
330
|
-
|
|
330
|
+
|
|
331
331
|
const output = await tool.handler(call.arguments);
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
this.toolCallHistory.push({
|
|
334
334
|
id: callId,
|
|
335
335
|
tool: toolName,
|
|
336
336
|
arguments: call.arguments,
|
|
337
337
|
output,
|
|
338
|
-
status: 'success'
|
|
338
|
+
status: 'success',
|
|
339
339
|
});
|
|
340
|
-
|
|
340
|
+
|
|
341
341
|
results.push({
|
|
342
342
|
callId,
|
|
343
343
|
tool: toolName,
|
|
344
344
|
output,
|
|
345
|
-
status: 'success'
|
|
345
|
+
status: 'success',
|
|
346
346
|
});
|
|
347
|
-
|
|
347
|
+
|
|
348
348
|
this.emit('tool:result', { name: toolName, output, id: callId, status: 'success' });
|
|
349
|
-
|
|
350
349
|
} catch (error) {
|
|
351
|
-
const
|
|
350
|
+
const _errorResult = {
|
|
352
351
|
callId,
|
|
353
352
|
tool: toolName,
|
|
354
353
|
error: error.message,
|
|
355
|
-
status: 'error'
|
|
354
|
+
status: 'error',
|
|
356
355
|
};
|
|
357
|
-
|
|
356
|
+
|
|
358
357
|
this.toolCallHistory.push({
|
|
359
358
|
id: callId,
|
|
360
359
|
tool: toolName,
|
|
361
360
|
arguments: call.arguments,
|
|
362
361
|
error: error.message,
|
|
363
|
-
status: 'error'
|
|
362
|
+
status: 'error',
|
|
364
363
|
});
|
|
365
|
-
|
|
364
|
+
|
|
366
365
|
this.emit('tool:error', { name: toolName, error: error.message, id: callId });
|
|
367
|
-
|
|
366
|
+
|
|
368
367
|
if (this.continueOnError) {
|
|
369
368
|
results.push({
|
|
370
369
|
callId,
|
|
371
370
|
tool: toolName,
|
|
372
371
|
output: { error: error.message },
|
|
373
|
-
status: 'error'
|
|
372
|
+
status: 'error',
|
|
374
373
|
});
|
|
375
374
|
} else {
|
|
376
375
|
throw error;
|
|
377
376
|
}
|
|
378
377
|
}
|
|
379
378
|
}
|
|
380
|
-
|
|
379
|
+
|
|
381
380
|
return results;
|
|
382
381
|
}
|
|
383
|
-
|
|
382
|
+
|
|
384
383
|
/**
|
|
385
384
|
* Default completion check - returns true when LLM provides final response
|
|
386
385
|
* @param {*} output
|
|
@@ -388,11 +387,11 @@ class AgentLoop extends EventEmitter {
|
|
|
388
387
|
* @param {Object} context
|
|
389
388
|
* @returns {Promise<boolean>}
|
|
390
389
|
*/
|
|
391
|
-
async defaultCompletionCheck(
|
|
390
|
+
async defaultCompletionCheck(_output, _messages, _context) {
|
|
392
391
|
// By default, if we reach here (no tool calls), we're done
|
|
393
392
|
return true;
|
|
394
393
|
}
|
|
395
|
-
|
|
394
|
+
|
|
396
395
|
/**
|
|
397
396
|
* Apply input guardrails if configured
|
|
398
397
|
* @param {string} input
|
|
@@ -403,7 +402,7 @@ class AgentLoop extends EventEmitter {
|
|
|
403
402
|
if (!this.guardrails?.input) {
|
|
404
403
|
return input;
|
|
405
404
|
}
|
|
406
|
-
|
|
405
|
+
|
|
407
406
|
try {
|
|
408
407
|
const result = await this.guardrails.input.validate(input, context);
|
|
409
408
|
if (!result.valid) {
|
|
@@ -415,7 +414,7 @@ class AgentLoop extends EventEmitter {
|
|
|
415
414
|
throw error;
|
|
416
415
|
}
|
|
417
416
|
}
|
|
418
|
-
|
|
417
|
+
|
|
419
418
|
/**
|
|
420
419
|
* Apply output guardrails if configured
|
|
421
420
|
* @param {string} output
|
|
@@ -426,7 +425,7 @@ class AgentLoop extends EventEmitter {
|
|
|
426
425
|
if (!this.guardrails?.output) {
|
|
427
426
|
return output;
|
|
428
427
|
}
|
|
429
|
-
|
|
428
|
+
|
|
430
429
|
try {
|
|
431
430
|
const result = await this.guardrails.output.validate(output, context);
|
|
432
431
|
if (!result.valid) {
|
|
@@ -439,7 +438,7 @@ class AgentLoop extends EventEmitter {
|
|
|
439
438
|
return output;
|
|
440
439
|
}
|
|
441
440
|
}
|
|
442
|
-
|
|
441
|
+
|
|
443
442
|
/**
|
|
444
443
|
* Create standardized result object
|
|
445
444
|
* @param {string} status
|
|
@@ -458,12 +457,12 @@ class AgentLoop extends EventEmitter {
|
|
|
458
457
|
...metrics,
|
|
459
458
|
toolCallCount: this.toolCallHistory.length,
|
|
460
459
|
successfulCalls: this.toolCallHistory.filter(tc => tc.status === 'success').length,
|
|
461
|
-
failedCalls: this.toolCallHistory.filter(tc => tc.status === 'error').length
|
|
460
|
+
failedCalls: this.toolCallHistory.filter(tc => tc.status === 'error').length,
|
|
462
461
|
},
|
|
463
|
-
...(error && { error: error.message })
|
|
462
|
+
...(error && { error: error.message }),
|
|
464
463
|
};
|
|
465
464
|
}
|
|
466
|
-
|
|
465
|
+
|
|
467
466
|
/**
|
|
468
467
|
* Abort the running loop
|
|
469
468
|
* @param {string} [reason='aborted']
|
|
@@ -474,7 +473,7 @@ class AgentLoop extends EventEmitter {
|
|
|
474
473
|
this.emit('abort', { reason });
|
|
475
474
|
}
|
|
476
475
|
}
|
|
477
|
-
|
|
476
|
+
|
|
478
477
|
/**
|
|
479
478
|
* Get current loop state
|
|
480
479
|
* @returns {Object}
|
|
@@ -484,10 +483,10 @@ class AgentLoop extends EventEmitter {
|
|
|
484
483
|
isRunning: this.isRunning,
|
|
485
484
|
messageCount: this.messages.length,
|
|
486
485
|
toolCallCount: this.toolCallHistory.length,
|
|
487
|
-
registeredTools: Array.from(this.tools.keys())
|
|
486
|
+
registeredTools: Array.from(this.tools.keys()),
|
|
488
487
|
};
|
|
489
488
|
}
|
|
490
|
-
|
|
489
|
+
|
|
491
490
|
/**
|
|
492
491
|
* Reset the loop state
|
|
493
492
|
*/
|
|
@@ -495,7 +494,7 @@ class AgentLoop extends EventEmitter {
|
|
|
495
494
|
if (this.isRunning) {
|
|
496
495
|
throw new Error('Cannot reset while loop is running');
|
|
497
496
|
}
|
|
498
|
-
|
|
497
|
+
|
|
499
498
|
this.messages = [];
|
|
500
499
|
this.toolCallHistory = [];
|
|
501
500
|
this.emit('reset');
|
|
@@ -509,24 +508,24 @@ class AgentLoop extends EventEmitter {
|
|
|
509
508
|
*/
|
|
510
509
|
function createMockLLMProvider(responses) {
|
|
511
510
|
let callIndex = 0;
|
|
512
|
-
|
|
511
|
+
|
|
513
512
|
return {
|
|
514
|
-
async chat(
|
|
513
|
+
async chat(_options) {
|
|
515
514
|
if (callIndex >= responses.length) {
|
|
516
515
|
return { content: 'Done', toolCalls: [] };
|
|
517
516
|
}
|
|
518
|
-
|
|
517
|
+
|
|
519
518
|
const response = responses[callIndex++];
|
|
520
519
|
return {
|
|
521
520
|
content: response.content || null,
|
|
522
521
|
toolCalls: response.toolCalls || [],
|
|
523
|
-
usage: response.usage || { total_tokens: 100 }
|
|
522
|
+
usage: response.usage || { total_tokens: 100 },
|
|
524
523
|
};
|
|
525
|
-
}
|
|
524
|
+
},
|
|
526
525
|
};
|
|
527
526
|
}
|
|
528
527
|
|
|
529
528
|
module.exports = {
|
|
530
529
|
AgentLoop,
|
|
531
|
-
createMockLLMProvider
|
|
530
|
+
createMockLLMProvider,
|
|
532
531
|
};
|