@jackchen_me/open-multi-agent 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- package/.github/pull_request_template.md +14 -0
- package/.github/workflows/ci.yml +23 -0
- package/CLAUDE.md +80 -0
- package/CODE_OF_CONDUCT.md +48 -0
- package/CONTRIBUTING.md +72 -0
- package/DECISIONS.md +43 -0
- package/README.md +144 -144
- package/README_zh.md +277 -0
- package/SECURITY.md +17 -0
- package/dist/agent/agent.d.ts +20 -1
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +233 -12
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/loop-detector.d.ts +39 -0
- package/dist/agent/loop-detector.d.ts.map +1 -0
- package/dist/agent/loop-detector.js +122 -0
- package/dist/agent/loop-detector.js.map +1 -0
- package/dist/agent/pool.d.ts +2 -1
- package/dist/agent/pool.d.ts.map +1 -1
- package/dist/agent/pool.js +4 -2
- package/dist/agent/pool.js.map +1 -1
- package/dist/agent/runner.d.ts +23 -1
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +113 -12
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/structured-output.d.ts +33 -0
- package/dist/agent/structured-output.d.ts.map +1 -0
- package/dist/agent/structured-output.js +116 -0
- package/dist/agent/structured-output.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/llm/adapter.d.ts +12 -4
- package/dist/llm/adapter.d.ts.map +1 -1
- package/dist/llm/adapter.js +28 -5
- package/dist/llm/adapter.js.map +1 -1
- package/dist/llm/anthropic.d.ts +1 -1
- package/dist/llm/anthropic.d.ts.map +1 -1
- package/dist/llm/anthropic.js +2 -1
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/copilot.d.ts +92 -0
- package/dist/llm/copilot.d.ts.map +1 -0
- package/dist/llm/copilot.js +427 -0
- package/dist/llm/copilot.js.map +1 -0
- package/dist/llm/gemini.d.ts +65 -0
- package/dist/llm/gemini.d.ts.map +1 -0
- package/dist/llm/gemini.js +317 -0
- package/dist/llm/gemini.js.map +1 -0
- package/dist/llm/grok.d.ts +21 -0
- package/dist/llm/grok.d.ts.map +1 -0
- package/dist/llm/grok.js +24 -0
- package/dist/llm/grok.js.map +1 -0
- package/dist/llm/openai-common.d.ts +54 -0
- package/dist/llm/openai-common.d.ts.map +1 -0
- package/dist/llm/openai-common.js +242 -0
- package/dist/llm/openai-common.js.map +1 -0
- package/dist/llm/openai.d.ts +2 -2
- package/dist/llm/openai.d.ts.map +1 -1
- package/dist/llm/openai.js +23 -226
- package/dist/llm/openai.js.map +1 -1
- package/dist/orchestrator/orchestrator.d.ts +25 -1
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +214 -41
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/task/queue.d.ts +31 -2
- package/dist/task/queue.d.ts.map +1 -1
- package/dist/task/queue.js +70 -3
- package/dist/task/queue.js.map +1 -1
- package/dist/task/task.d.ts +3 -0
- package/dist/task/task.d.ts.map +1 -1
- package/dist/task/task.js +5 -1
- package/dist/task/task.js.map +1 -1
- package/dist/team/messaging.d.ts.map +1 -1
- package/dist/team/messaging.js +2 -1
- package/dist/team/messaging.js.map +1 -1
- package/dist/tool/text-tool-extractor.d.ts +32 -0
- package/dist/tool/text-tool-extractor.d.ts.map +1 -0
- package/dist/tool/text-tool-extractor.js +187 -0
- package/dist/tool/text-tool-extractor.js.map +1 -0
- package/dist/types.d.ts +167 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/trace.d.ts +12 -0
- package/dist/utils/trace.d.ts.map +1 -0
- package/dist/utils/trace.js +30 -0
- package/dist/utils/trace.js.map +1 -0
- package/examples/05-copilot-test.ts +49 -0
- package/examples/06-local-model.ts +200 -0
- package/examples/07-fan-out-aggregate.ts +209 -0
- package/examples/08-gemma4-local.ts +192 -0
- package/examples/09-structured-output.ts +73 -0
- package/examples/10-task-retry.ts +132 -0
- package/examples/11-trace-observability.ts +133 -0
- package/examples/12-grok.ts +154 -0
- package/examples/13-gemini.ts +48 -0
- package/package.json +14 -3
- package/src/agent/agent.ts +273 -15
- package/src/agent/loop-detector.ts +137 -0
- package/src/agent/pool.ts +9 -2
- package/src/agent/runner.ts +148 -19
- package/src/agent/structured-output.ts +126 -0
- package/src/index.ts +17 -1
- package/src/llm/adapter.ts +29 -5
- package/src/llm/anthropic.ts +2 -1
- package/src/llm/copilot.ts +552 -0
- package/src/llm/gemini.ts +378 -0
- package/src/llm/grok.ts +29 -0
- package/src/llm/openai-common.ts +294 -0
- package/src/llm/openai.ts +31 -261
- package/src/orchestrator/orchestrator.ts +260 -40
- package/src/task/queue.ts +74 -4
- package/src/task/task.ts +8 -1
- package/src/team/messaging.ts +3 -1
- package/src/tool/text-tool-extractor.ts +219 -0
- package/src/types.ts +186 -6
- package/src/utils/trace.ts +34 -0
- package/tests/agent-hooks.test.ts +473 -0
- package/tests/agent-pool.test.ts +212 -0
- package/tests/approval.test.ts +464 -0
- package/tests/built-in-tools.test.ts +393 -0
- package/tests/gemini-adapter.test.ts +97 -0
- package/tests/grok-adapter.test.ts +74 -0
- package/tests/llm-adapters.test.ts +357 -0
- package/tests/loop-detection.test.ts +456 -0
- package/tests/openai-fallback.test.ts +159 -0
- package/tests/orchestrator.test.ts +281 -0
- package/tests/scheduler.test.ts +221 -0
- package/tests/semaphore.test.ts +57 -0
- package/tests/shared-memory.test.ts +122 -0
- package/tests/structured-output.test.ts +331 -0
- package/tests/task-queue.test.ts +244 -0
- package/tests/task-retry.test.ts +368 -0
- package/tests/task-utils.test.ts +155 -0
- package/tests/team-messaging.test.ts +329 -0
- package/tests/text-tool-extractor.test.ts +170 -0
- package/tests/tool-executor.test.ts +193 -0
- package/tests/trace.test.ts +453 -0
- package/vitest.config.ts +9 -0
package/dist/agent/pool.js
CHANGED
|
@@ -92,11 +92,11 @@ export class AgentPool {
|
|
|
92
92
|
*
|
|
93
93
|
* @throws {Error} If the agent name is not found.
|
|
94
94
|
*/
|
|
95
|
-
async run(agentName, prompt) {
|
|
95
|
+
async run(agentName, prompt, runOptions) {
|
|
96
96
|
const agent = this.requireAgent(agentName);
|
|
97
97
|
await this.semaphore.acquire();
|
|
98
98
|
try {
|
|
99
|
-
return await agent.run(prompt);
|
|
99
|
+
return await agent.run(prompt, runOptions);
|
|
100
100
|
}
|
|
101
101
|
finally {
|
|
102
102
|
this.semaphore.release();
|
|
@@ -112,6 +112,7 @@ export class AgentPool {
|
|
|
112
112
|
*
|
|
113
113
|
* @param tasks - Array of `{ agent, prompt }` descriptors.
|
|
114
114
|
*/
|
|
115
|
+
// TODO(#18): accept RunOptions per task to forward trace context
|
|
115
116
|
async runParallel(tasks) {
|
|
116
117
|
const resultMap = new Map();
|
|
117
118
|
const settledResults = await Promise.allSettled(tasks.map(async (task) => {
|
|
@@ -143,6 +144,7 @@ export class AgentPool {
|
|
|
143
144
|
*
|
|
144
145
|
* @throws {Error} If the pool is empty.
|
|
145
146
|
*/
|
|
147
|
+
// TODO(#18): accept RunOptions to forward trace context
|
|
146
148
|
async runAny(prompt) {
|
|
147
149
|
const allAgents = this.list();
|
|
148
150
|
if (allAgents.length === 0) {
|
package/dist/agent/pool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/agent/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/agent/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAmBjD,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,OAAO,SAAS;IAUS;IATZ,MAAM,GAAuB,IAAI,GAAG,EAAE,CAAA;IACtC,SAAS,CAAW;IACrC,wDAAwD;IAChD,eAAe,GAAG,CAAC,CAAA;IAE3B;;;OAGG;IACH,YAA6B,iBAAyB,CAAC;QAA1B,mBAAc,GAAd,cAAc,CAAY;QACrD,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,CAAC,cAAc,CAAC,CAAA;IAChD,CAAC;IAED,4EAA4E;IAC5E,sBAAsB;IACtB,4EAA4E;IAE5E;;;;OAIG;IACH,GAAG,CAAC,KAAY;QACd,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,IAAI,2BAA2B;gBAC1D,gBAAgB,KAAK,CAAC,IAAI,sBAAsB,CACjD,CAAA;QACH,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACpC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,IAAY;QACjB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,sBAAsB,CAAC,CAAA;QAClE,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC1B,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,4EAA4E;IAC5E,gBAAgB;IAChB,4EAA4E;IAE5E;;;;;OAKG;IACH,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,MAAc,EACd,UAAgC;QAEhC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAA;QAE1C,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAA;QAC9B,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAC5C,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAA;QAC1B,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,iEAAiE;IACjE,KAAK,CAAC,WAAW,CACf,KAAyE;QAEzE,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0B,CAAA;QAEnD,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,UAAU,CAC7C,KAAK,CAAC,GAAG,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE;YACrB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YACtD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,CAAA;QACrC,CAAC,CAAC,CACH,CAAA;QAED,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACnC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACzD,CAAC;iBAAM,CAAC;gBACN,sEAAsE;gBACtE,sEAAsE;gBACtE,uEAAuE;gBACvE,gCAAgC;gBAChC,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;gBAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,SAAS,CAAA;gBAChD,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;YAC5D,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAED;;;;;;;;OAQG;IACH,wDAAwD;IACxD,KAAK,CAAC,MAAM,CAAC,MAAc;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;QAED,mEAAmE;QACnE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC,MAAM,CAAA;QAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,eAAe,CAAE,CAAA;QAC9C,IAAI,CAAC,eAAe,GAAG,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAA;QAEpE,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAA;QAC9B,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAA;QAC1B,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,gBAAgB;IAChB,4EAA4E;IAE5E;;OAEG;IACH,SAAS;QACP,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,IAAI,SAAS,GAAG,CAAC,CAAA;QACjB,IAAI,KAAK,GAAG,CAAC,CAAA;QAEb,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACzC,QAAQ,KAAK,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC;gBAChC,KAAK,MAAM;oBAAO,IAAI,EAAE,CAAC;oBAAM,MAAK;gBACpC,KAAK,SAAS;oBAAI,OAAO,EAAE,CAAC;oBAAG,MAAK;gBACpC,KAAK,WAAW;oBAAE,SAAS,EAAE,CAAC;oBAAC,MAAK;gBACpC,KAAK,OAAO;oBAAM,KAAK,EAAE,CAAC;oBAAK,MAAK;YACtC,CAAC;QACH,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;IACrE,CAAC;IAED,4EAA4E;IAC5E,YAAY;IACZ,4EAA4E;IAE5E;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ;QACZ,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACzC,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,kBAAkB;IAClB,4EAA4E;IAEpE,YAAY,CAAC,IAAY;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACnC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,uBAAuB;gBAChD,uBAAuB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACpE,CAAA;QACH,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,MAAe;QACjC,MAAM,OAAO,GAAG,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACzE,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE;YACjD,SAAS,EAAE,EAAE;SACd,CAAA;IACH,CAAC;CACF"}
|
package/dist/agent/runner.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* The loop follows a standard agentic conversation pattern:
|
|
12
12
|
* one outer `while (true)` that breaks on `end_turn` or maxTurns exhaustion.
|
|
13
13
|
*/
|
|
14
|
-
import type { LLMMessage, ToolCallRecord, TokenUsage, StreamEvent, ToolResult, LLMAdapter } from '../types.js';
|
|
14
|
+
import type { LLMMessage, ToolCallRecord, TokenUsage, StreamEvent, ToolResult, LLMAdapter, TraceEvent, LoopDetectionConfig } from '../types.js';
|
|
15
15
|
import type { ToolRegistry } from '../tool/framework.js';
|
|
16
16
|
import type { ToolExecutor } from '../tool/executor.js';
|
|
17
17
|
/**
|
|
@@ -44,6 +44,8 @@ export interface RunnerOptions {
|
|
|
44
44
|
readonly agentName?: string;
|
|
45
45
|
/** Short role description of the agent (used in tool context). */
|
|
46
46
|
readonly agentRole?: string;
|
|
47
|
+
/** Loop detection configuration. When set, detects stuck agent loops. */
|
|
48
|
+
readonly loopDetection?: LoopDetectionConfig;
|
|
47
49
|
}
|
|
48
50
|
/**
|
|
49
51
|
* Per-call callbacks for observing tool execution in real time.
|
|
@@ -56,6 +58,24 @@ export interface RunOptions {
|
|
|
56
58
|
readonly onToolResult?: (name: string, result: ToolResult) => void;
|
|
57
59
|
/** Fired after each complete {@link LLMMessage} is appended. */
|
|
58
60
|
readonly onMessage?: (message: LLMMessage) => void;
|
|
61
|
+
/**
|
|
62
|
+
* Fired when the runner detects a potential configuration issue.
|
|
63
|
+
* For example, when a model appears to ignore tool definitions.
|
|
64
|
+
*/
|
|
65
|
+
readonly onWarning?: (message: string) => void;
|
|
66
|
+
/** Trace callback for observability spans. Async callbacks are safe. */
|
|
67
|
+
readonly onTrace?: (event: TraceEvent) => void | Promise<void>;
|
|
68
|
+
/** Run ID for trace correlation. */
|
|
69
|
+
readonly runId?: string;
|
|
70
|
+
/** Task ID for trace correlation. */
|
|
71
|
+
readonly taskId?: string;
|
|
72
|
+
/** Agent name for trace correlation (overrides RunnerOptions.agentName). */
|
|
73
|
+
readonly traceAgent?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Per-call abort signal. When set, takes precedence over the static
|
|
76
|
+
* {@link RunnerOptions.abortSignal}. Useful for per-run timeouts.
|
|
77
|
+
*/
|
|
78
|
+
readonly abortSignal?: AbortSignal;
|
|
59
79
|
}
|
|
60
80
|
/** The aggregated result returned when a full run completes. */
|
|
61
81
|
export interface RunResult {
|
|
@@ -69,6 +89,8 @@ export interface RunResult {
|
|
|
69
89
|
readonly tokenUsage: TokenUsage;
|
|
70
90
|
/** Total number of LLM turns (including tool-call follow-ups). */
|
|
71
91
|
readonly turns: number;
|
|
92
|
+
/** True when the run was terminated or warned due to loop detection. */
|
|
93
|
+
readonly loopDetected?: boolean;
|
|
72
94
|
}
|
|
73
95
|
/**
|
|
74
96
|
* Drives a full agentic conversation: LLM calls, tool execution, and looping.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,UAAU,EAKV,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,EAEV,UAAU,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/runner.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* The loop follows a standard agentic conversation pattern:
|
|
12
12
|
* one outer `while (true)` that breaks on `end_turn` or maxTurns exhaustion.
|
|
13
13
|
*/
|
|
14
|
+
import { LoopDetector } from './loop-detector.js';
|
|
15
|
+
import { emitTrace } from '../utils/trace.js';
|
|
14
16
|
// ---------------------------------------------------------------------------
|
|
15
17
|
// Internal helpers
|
|
16
18
|
// ---------------------------------------------------------------------------
|
|
@@ -85,12 +87,7 @@ export class AgentRunner {
|
|
|
85
87
|
};
|
|
86
88
|
for await (const event of this.stream(messages, options)) {
|
|
87
89
|
if (event.type === 'done') {
|
|
88
|
-
|
|
89
|
-
accumulated.messages = result.messages;
|
|
90
|
-
accumulated.output = result.output;
|
|
91
|
-
accumulated.toolCalls = result.toolCalls;
|
|
92
|
-
accumulated.tokenUsage = result.tokenUsage;
|
|
93
|
-
accumulated.turns = result.turns;
|
|
90
|
+
Object.assign(accumulated, event.data);
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
93
|
return accumulated;
|
|
@@ -120,21 +117,30 @@ export class AgentRunner {
|
|
|
120
117
|
const toolDefs = this.options.allowedTools
|
|
121
118
|
? allDefs.filter(d => this.options.allowedTools.includes(d.name))
|
|
122
119
|
: allDefs;
|
|
120
|
+
// Per-call abortSignal takes precedence over the static one.
|
|
121
|
+
const effectiveAbortSignal = options.abortSignal ?? this.options.abortSignal;
|
|
123
122
|
const baseChatOptions = {
|
|
124
123
|
model: this.options.model,
|
|
125
124
|
tools: toolDefs.length > 0 ? toolDefs : undefined,
|
|
126
125
|
maxTokens: this.options.maxTokens,
|
|
127
126
|
temperature: this.options.temperature,
|
|
128
127
|
systemPrompt: this.options.systemPrompt,
|
|
129
|
-
abortSignal:
|
|
128
|
+
abortSignal: effectiveAbortSignal,
|
|
130
129
|
};
|
|
130
|
+
// Loop detection state — only allocated when configured.
|
|
131
|
+
const detector = this.options.loopDetection
|
|
132
|
+
? new LoopDetector(this.options.loopDetection)
|
|
133
|
+
: null;
|
|
134
|
+
let loopDetected = false;
|
|
135
|
+
let loopWarned = false;
|
|
136
|
+
const loopAction = this.options.loopDetection?.onLoopDetected ?? 'warn';
|
|
131
137
|
try {
|
|
132
138
|
// -----------------------------------------------------------------
|
|
133
139
|
// Main agentic loop — `while (true)` until end_turn or maxTurns
|
|
134
140
|
// -----------------------------------------------------------------
|
|
135
141
|
while (true) {
|
|
136
142
|
// Respect abort before each LLM call.
|
|
137
|
-
if (
|
|
143
|
+
if (effectiveAbortSignal?.aborted) {
|
|
138
144
|
break;
|
|
139
145
|
}
|
|
140
146
|
// Guard against unbounded loops.
|
|
@@ -145,7 +151,23 @@ export class AgentRunner {
|
|
|
145
151
|
// ------------------------------------------------------------------
|
|
146
152
|
// Step 1: Call the LLM and collect the full response for this turn.
|
|
147
153
|
// ------------------------------------------------------------------
|
|
154
|
+
const llmStartMs = Date.now();
|
|
148
155
|
const response = await this.adapter.chat(conversationMessages, baseChatOptions);
|
|
156
|
+
if (options.onTrace) {
|
|
157
|
+
const llmEndMs = Date.now();
|
|
158
|
+
emitTrace(options.onTrace, {
|
|
159
|
+
type: 'llm_call',
|
|
160
|
+
runId: options.runId ?? '',
|
|
161
|
+
taskId: options.taskId,
|
|
162
|
+
agent: options.traceAgent ?? this.options.agentName ?? 'unknown',
|
|
163
|
+
model: this.options.model,
|
|
164
|
+
turn: turns,
|
|
165
|
+
tokens: response.usage,
|
|
166
|
+
startMs: llmStartMs,
|
|
167
|
+
endMs: llmEndMs,
|
|
168
|
+
durationMs: llmEndMs - llmStartMs,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
149
171
|
totalUsage = addTokenUsage(totalUsage, response.usage);
|
|
150
172
|
// ------------------------------------------------------------------
|
|
151
173
|
// Step 2: Build the assistant message from the response content.
|
|
@@ -161,19 +183,70 @@ export class AgentRunner {
|
|
|
161
183
|
if (turnText.length > 0) {
|
|
162
184
|
yield { type: 'text', data: turnText };
|
|
163
185
|
}
|
|
164
|
-
//
|
|
186
|
+
// Extract tool-use blocks for detection and execution.
|
|
165
187
|
const toolUseBlocks = extractToolUseBlocks(response.content);
|
|
166
|
-
|
|
167
|
-
|
|
188
|
+
// ------------------------------------------------------------------
|
|
189
|
+
// Step 2.5: Loop detection — check before yielding tool_use events
|
|
190
|
+
// so that terminate mode doesn't emit orphaned tool_use without
|
|
191
|
+
// matching tool_result.
|
|
192
|
+
// ------------------------------------------------------------------
|
|
193
|
+
let injectWarning = false;
|
|
194
|
+
let injectWarningKind = 'tool_repetition';
|
|
195
|
+
if (detector && toolUseBlocks.length > 0) {
|
|
196
|
+
const toolInfo = detector.recordToolCalls(toolUseBlocks);
|
|
197
|
+
const textInfo = turnText.length > 0 ? detector.recordText(turnText) : null;
|
|
198
|
+
const info = toolInfo ?? textInfo;
|
|
199
|
+
if (info) {
|
|
200
|
+
yield { type: 'loop_detected', data: info };
|
|
201
|
+
options.onWarning?.(info.detail);
|
|
202
|
+
const action = typeof loopAction === 'function'
|
|
203
|
+
? await loopAction(info)
|
|
204
|
+
: loopAction;
|
|
205
|
+
if (action === 'terminate') {
|
|
206
|
+
loopDetected = true;
|
|
207
|
+
finalOutput = turnText;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
else if (action === 'warn' || action === 'inject') {
|
|
211
|
+
if (loopWarned) {
|
|
212
|
+
// Second detection after a warning — force terminate.
|
|
213
|
+
loopDetected = true;
|
|
214
|
+
finalOutput = turnText;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
loopWarned = true;
|
|
218
|
+
injectWarning = true;
|
|
219
|
+
injectWarningKind = info.kind;
|
|
220
|
+
// Fall through to execute tools, then inject warning.
|
|
221
|
+
}
|
|
222
|
+
// 'continue' — do nothing, let the loop proceed normally.
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// No loop detected this turn — agent has recovered, so reset
|
|
226
|
+
// the warning state. A future loop gets a fresh warning cycle.
|
|
227
|
+
loopWarned = false;
|
|
228
|
+
}
|
|
168
229
|
}
|
|
169
230
|
// ------------------------------------------------------------------
|
|
170
231
|
// Step 3: Decide whether to continue looping.
|
|
171
232
|
// ------------------------------------------------------------------
|
|
172
233
|
if (toolUseBlocks.length === 0) {
|
|
234
|
+
// Warn on first turn if tools were provided but model didn't use them.
|
|
235
|
+
if (turns === 1 && toolDefs.length > 0 && options.onWarning) {
|
|
236
|
+
const agentName = this.options.agentName ?? 'unknown';
|
|
237
|
+
options.onWarning(`Agent "${agentName}" has ${toolDefs.length} tool(s) available but the model ` +
|
|
238
|
+
`returned no tool calls. If using a local model, verify it supports tool calling ` +
|
|
239
|
+
`(see https://ollama.com/search?c=tools).`);
|
|
240
|
+
}
|
|
173
241
|
// No tools requested — this is the terminal assistant turn.
|
|
174
242
|
finalOutput = turnText;
|
|
175
243
|
break;
|
|
176
244
|
}
|
|
245
|
+
// Announce each tool-use block the model requested (after loop
|
|
246
|
+
// detection, so terminate mode never emits unpaired events).
|
|
247
|
+
for (const block of toolUseBlocks) {
|
|
248
|
+
yield { type: 'tool_use', data: block };
|
|
249
|
+
}
|
|
177
250
|
// ------------------------------------------------------------------
|
|
178
251
|
// Step 4: Execute all tool calls in PARALLEL.
|
|
179
252
|
//
|
|
@@ -193,8 +266,22 @@ export class AgentRunner {
|
|
|
193
266
|
const message = err instanceof Error ? err.message : String(err);
|
|
194
267
|
result = { data: message, isError: true };
|
|
195
268
|
}
|
|
196
|
-
const
|
|
269
|
+
const endTime = Date.now();
|
|
270
|
+
const duration = endTime - startTime;
|
|
197
271
|
options.onToolResult?.(block.name, result);
|
|
272
|
+
if (options.onTrace) {
|
|
273
|
+
emitTrace(options.onTrace, {
|
|
274
|
+
type: 'tool_call',
|
|
275
|
+
runId: options.runId ?? '',
|
|
276
|
+
taskId: options.taskId,
|
|
277
|
+
agent: options.traceAgent ?? this.options.agentName ?? 'unknown',
|
|
278
|
+
tool: block.name,
|
|
279
|
+
isError: result.isError ?? false,
|
|
280
|
+
startMs: startTime,
|
|
281
|
+
endMs: endTime,
|
|
282
|
+
durationMs: duration,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
198
285
|
const record = {
|
|
199
286
|
toolName: block.name,
|
|
200
287
|
input: block.input,
|
|
@@ -220,6 +307,19 @@ export class AgentRunner {
|
|
|
220
307
|
allToolCalls.push(record);
|
|
221
308
|
yield { type: 'tool_result', data: resultBlock };
|
|
222
309
|
}
|
|
310
|
+
// Inject a loop-detection warning into the tool-result message so
|
|
311
|
+
// the LLM sees it alongside the results (avoids two consecutive user
|
|
312
|
+
// messages which violates the alternating-role constraint).
|
|
313
|
+
if (injectWarning) {
|
|
314
|
+
const warningText = injectWarningKind === 'text_repetition'
|
|
315
|
+
? 'WARNING: You appear to be generating the same response repeatedly. ' +
|
|
316
|
+
'This suggests you are stuck in a loop. Please try a different approach ' +
|
|
317
|
+
'or provide new information.'
|
|
318
|
+
: 'WARNING: You appear to be repeating the same tool calls with identical arguments. ' +
|
|
319
|
+
'This suggests you are stuck in a loop. Please try a different approach, use different ' +
|
|
320
|
+
'parameters, or explain what you are trying to accomplish.';
|
|
321
|
+
toolResultBlocks.push({ type: 'text', text: warningText });
|
|
322
|
+
}
|
|
223
323
|
const toolResultMessage = {
|
|
224
324
|
role: 'user',
|
|
225
325
|
content: toolResultBlocks,
|
|
@@ -250,6 +350,7 @@ export class AgentRunner {
|
|
|
250
350
|
toolCalls: allToolCalls,
|
|
251
351
|
tokenUsage: totalUsage,
|
|
252
352
|
turns,
|
|
353
|
+
...(loopDetected ? { loopDetected: true } : {}),
|
|
253
354
|
};
|
|
254
355
|
yield { type: 'done', data: runResult };
|
|
255
356
|
}
|
package/dist/agent/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured output utilities for agent responses.
|
|
3
|
+
*
|
|
4
|
+
* Provides JSON extraction, Zod validation, and system-prompt injection so
|
|
5
|
+
* that agents can return typed, schema-validated output.
|
|
6
|
+
*/
|
|
7
|
+
import { type ZodSchema } from 'zod';
|
|
8
|
+
/**
|
|
9
|
+
* Build a JSON-mode instruction block to append to the agent's system prompt.
|
|
10
|
+
*
|
|
11
|
+
* Converts the Zod schema to JSON Schema and formats it as a clear directive
|
|
12
|
+
* for the LLM to respond with valid JSON matching the schema.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildStructuredOutputInstruction(schema: ZodSchema): string;
|
|
15
|
+
/**
|
|
16
|
+
* Attempt to extract and parse JSON from the agent's raw text output.
|
|
17
|
+
*
|
|
18
|
+
* Handles three cases in order:
|
|
19
|
+
* 1. The output is already valid JSON (ideal case)
|
|
20
|
+
* 2. The output contains a ` ```json ` fenced block
|
|
21
|
+
* 3. The output contains a bare JSON object/array (first `{`/`[` to last `}`/`]`)
|
|
22
|
+
*
|
|
23
|
+
* @throws {Error} when no valid JSON can be extracted
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractJSON(raw: string): unknown;
|
|
26
|
+
/**
|
|
27
|
+
* Validate a parsed JSON value against a Zod schema.
|
|
28
|
+
*
|
|
29
|
+
* @returns The validated (and potentially transformed) value on success.
|
|
30
|
+
* @throws {Error} with a human-readable Zod error message on failure.
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateOutput(schema: ZodSchema, data: unknown): unknown;
|
|
33
|
+
//# sourceMappingURL=structured-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-output.d.ts","sourceRoot":"","sources":["../../src/agent/structured-output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,CAAA;AAOpC;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAa1E;AAMD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAuDhD;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CASxE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured output utilities for agent responses.
|
|
3
|
+
*
|
|
4
|
+
* Provides JSON extraction, Zod validation, and system-prompt injection so
|
|
5
|
+
* that agents can return typed, schema-validated output.
|
|
6
|
+
*/
|
|
7
|
+
import { zodToJsonSchema } from '../tool/framework.js';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// System-prompt instruction builder
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* Build a JSON-mode instruction block to append to the agent's system prompt.
|
|
13
|
+
*
|
|
14
|
+
* Converts the Zod schema to JSON Schema and formats it as a clear directive
|
|
15
|
+
* for the LLM to respond with valid JSON matching the schema.
|
|
16
|
+
*/
|
|
17
|
+
export function buildStructuredOutputInstruction(schema) {
|
|
18
|
+
const jsonSchema = zodToJsonSchema(schema);
|
|
19
|
+
return [
|
|
20
|
+
'',
|
|
21
|
+
'## Output Format (REQUIRED)',
|
|
22
|
+
'You MUST respond with ONLY valid JSON that conforms to the following JSON Schema.',
|
|
23
|
+
'Do NOT include any text, markdown fences, or explanation outside the JSON object.',
|
|
24
|
+
'Do NOT wrap the JSON in ```json code fences.',
|
|
25
|
+
'',
|
|
26
|
+
'```',
|
|
27
|
+
JSON.stringify(jsonSchema, null, 2),
|
|
28
|
+
'```',
|
|
29
|
+
].join('\n');
|
|
30
|
+
}
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// JSON extraction
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Attempt to extract and parse JSON from the agent's raw text output.
|
|
36
|
+
*
|
|
37
|
+
* Handles three cases in order:
|
|
38
|
+
* 1. The output is already valid JSON (ideal case)
|
|
39
|
+
* 2. The output contains a ` ```json ` fenced block
|
|
40
|
+
* 3. The output contains a bare JSON object/array (first `{`/`[` to last `}`/`]`)
|
|
41
|
+
*
|
|
42
|
+
* @throws {Error} when no valid JSON can be extracted
|
|
43
|
+
*/
|
|
44
|
+
export function extractJSON(raw) {
|
|
45
|
+
const trimmed = raw.trim();
|
|
46
|
+
// Case 1: Direct parse
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(trimmed);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Continue to fallback strategies
|
|
52
|
+
}
|
|
53
|
+
// Case 2a: Prefer ```json tagged fence
|
|
54
|
+
const jsonFenceMatch = trimmed.match(/```json\s*([\s\S]*?)```/);
|
|
55
|
+
if (jsonFenceMatch?.[1]) {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(jsonFenceMatch[1].trim());
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Continue
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Case 2b: Fall back to bare ``` fence
|
|
64
|
+
const bareFenceMatch = trimmed.match(/```\s*([\s\S]*?)```/);
|
|
65
|
+
if (bareFenceMatch?.[1]) {
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(bareFenceMatch[1].trim());
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Continue
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Case 3: Find first { to last } (object)
|
|
74
|
+
const objStart = trimmed.indexOf('{');
|
|
75
|
+
const objEnd = trimmed.lastIndexOf('}');
|
|
76
|
+
if (objStart !== -1 && objEnd > objStart) {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(trimmed.slice(objStart, objEnd + 1));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Fall through
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Case 3b: Find first [ to last ] (array)
|
|
85
|
+
const arrStart = trimmed.indexOf('[');
|
|
86
|
+
const arrEnd = trimmed.lastIndexOf(']');
|
|
87
|
+
if (arrStart !== -1 && arrEnd > arrStart) {
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(trimmed.slice(arrStart, arrEnd + 1));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Fall through
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`Failed to extract JSON from output. Raw output begins with: "${trimmed.slice(0, 100)}"`);
|
|
96
|
+
}
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Zod validation
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
/**
|
|
101
|
+
* Validate a parsed JSON value against a Zod schema.
|
|
102
|
+
*
|
|
103
|
+
* @returns The validated (and potentially transformed) value on success.
|
|
104
|
+
* @throws {Error} with a human-readable Zod error message on failure.
|
|
105
|
+
*/
|
|
106
|
+
export function validateOutput(schema, data) {
|
|
107
|
+
const result = schema.safeParse(data);
|
|
108
|
+
if (result.success) {
|
|
109
|
+
return result.data;
|
|
110
|
+
}
|
|
111
|
+
const issues = result.error.issues
|
|
112
|
+
.map(issue => ` - ${issue.path.length > 0 ? issue.path.join('.') : '(root)'}: ${issue.message}`)
|
|
113
|
+
.join('\n');
|
|
114
|
+
throw new Error(`Output validation failed:\n${issues}`);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=structured-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-output.js","sourceRoot":"","sources":["../../src/agent/structured-output.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -49,10 +49,12 @@
|
|
|
49
49
|
* })
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
|
-
export { OpenMultiAgent } from './orchestrator/orchestrator.js';
|
|
52
|
+
export { OpenMultiAgent, executeWithRetry, computeRetryDelay } from './orchestrator/orchestrator.js';
|
|
53
53
|
export { Scheduler } from './orchestrator/scheduler.js';
|
|
54
54
|
export type { SchedulingStrategy } from './orchestrator/scheduler.js';
|
|
55
55
|
export { Agent } from './agent/agent.js';
|
|
56
|
+
export { LoopDetector } from './agent/loop-detector.js';
|
|
57
|
+
export { buildStructuredOutputInstruction, extractJSON, validateOutput } from './agent/structured-output.js';
|
|
56
58
|
export { AgentPool, Semaphore } from './agent/pool.js';
|
|
57
59
|
export type { PoolStatus } from './agent/pool.js';
|
|
58
60
|
export { Team } from './team/team.js';
|
|
@@ -69,5 +71,6 @@ export { createAdapter } from './llm/adapter.js';
|
|
|
69
71
|
export type { SupportedProvider } from './llm/adapter.js';
|
|
70
72
|
export { InMemoryStore } from './memory/store.js';
|
|
71
73
|
export { SharedMemory } from './memory/shared.js';
|
|
72
|
-
export type { TextBlock, ToolUseBlock, ToolResultBlock, ImageBlock, ContentBlock, LLMMessage, LLMResponse, LLMAdapter, LLMChatOptions, LLMStreamOptions, LLMToolDef, TokenUsage, StreamEvent, ToolDefinition, ToolResult, ToolUseContext, AgentInfo, TeamInfo, AgentConfig, AgentState, AgentRunResult, ToolCallRecord, TeamConfig, TeamRunResult, Task, TaskStatus, OrchestratorConfig, OrchestratorEvent, MemoryEntry, MemoryStore, } from './types.js';
|
|
74
|
+
export type { TextBlock, ToolUseBlock, ToolResultBlock, ImageBlock, ContentBlock, LLMMessage, LLMResponse, LLMAdapter, LLMChatOptions, LLMStreamOptions, LLMToolDef, TokenUsage, StreamEvent, ToolDefinition, ToolResult, ToolUseContext, AgentInfo, TeamInfo, AgentConfig, AgentState, AgentRunResult, BeforeRunHookContext, ToolCallRecord, LoopDetectionConfig, LoopDetectionInfo, TeamConfig, TeamRunResult, Task, TaskStatus, OrchestratorConfig, OrchestratorEvent, TraceEventType, TraceEventBase, TraceEvent, LLMCallTrace, ToolCallTrace, TaskTrace, AgentTrace, MemoryEntry, MemoryStore, } from './types.js';
|
|
75
|
+
export { generateRunId } from './utils/trace.js';
|
|
73
76
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAMH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AACpG,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AACvD,YAAY,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAMrE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,gCAAgC,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC5G,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACtD,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAMjD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAMlD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAC1G,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAMrD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC5E,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,QAAQ,GACT,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAMzD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAMjD,YAAY,EAEV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,UAAU,EACV,YAAY,EAGZ,UAAU,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,WAAW,EAGX,cAAc,EACd,UAAU,EACV,cAAc,EACd,SAAS,EACT,QAAQ,EAGR,WAAW,EACX,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EAGjB,UAAU,EACV,aAAa,EAGb,IAAI,EACJ,UAAU,EAGV,kBAAkB,EAClB,iBAAiB,EAGjB,cAAc,EACd,cAAc,EACd,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,UAAU,EAGV,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -52,12 +52,14 @@
|
|
|
52
52
|
// ---------------------------------------------------------------------------
|
|
53
53
|
// Orchestrator (primary entry point)
|
|
54
54
|
// ---------------------------------------------------------------------------
|
|
55
|
-
export { OpenMultiAgent } from './orchestrator/orchestrator.js';
|
|
55
|
+
export { OpenMultiAgent, executeWithRetry, computeRetryDelay } from './orchestrator/orchestrator.js';
|
|
56
56
|
export { Scheduler } from './orchestrator/scheduler.js';
|
|
57
57
|
// ---------------------------------------------------------------------------
|
|
58
58
|
// Agent layer
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
60
|
export { Agent } from './agent/agent.js';
|
|
61
|
+
export { LoopDetector } from './agent/loop-detector.js';
|
|
62
|
+
export { buildStructuredOutputInstruction, extractJSON, validateOutput } from './agent/structured-output.js';
|
|
61
63
|
export { AgentPool, Semaphore } from './agent/pool.js';
|
|
62
64
|
// ---------------------------------------------------------------------------
|
|
63
65
|
// Team layer
|
|
@@ -84,4 +86,5 @@ export { createAdapter } from './llm/adapter.js';
|
|
|
84
86
|
// ---------------------------------------------------------------------------
|
|
85
87
|
export { InMemoryStore } from './memory/store.js';
|
|
86
88
|
export { SharedMemory } from './memory/shared.js';
|
|
89
|
+
export { generateRunId } from './utils/trace.js';
|
|
87
90
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,8EAA8E;AAC9E,qCAAqC;AACrC,8EAA8E;AAE9E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,8EAA8E;AAC9E,qCAAqC;AACrC,8EAA8E;AAE9E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AACpG,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAGvD,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,gCAAgC,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC5G,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGtD,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAGhD,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAG1G,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,QAAQ,GACT,MAAM,0BAA0B,CAAA;AAEjC,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGhD,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAkEjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
|
package/dist/llm/adapter.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* const anthropic = createAdapter('anthropic')
|
|
13
13
|
* const openai = createAdapter('openai', process.env.OPENAI_API_KEY)
|
|
14
|
+
* const gemini = createAdapter('gemini', process.env.GEMINI_API_KEY)
|
|
14
15
|
* ```
|
|
15
16
|
*/
|
|
16
17
|
export type { LLMAdapter, LLMChatOptions, LLMStreamOptions, LLMToolDef, LLMMessage, LLMResponse, StreamEvent, TokenUsage, ContentBlock, TextBlock, ToolUseBlock, ToolResultBlock, ImageBlock, } from '../types.js';
|
|
@@ -20,19 +21,26 @@ import type { LLMAdapter } from '../types.js';
|
|
|
20
21
|
* Additional providers can be integrated by implementing {@link LLMAdapter}
|
|
21
22
|
* directly and bypassing this factory.
|
|
22
23
|
*/
|
|
23
|
-
export type SupportedProvider = 'anthropic' | 'openai';
|
|
24
|
+
export type SupportedProvider = 'anthropic' | 'copilot' | 'grok' | 'openai' | 'gemini';
|
|
24
25
|
/**
|
|
25
26
|
* Instantiate the appropriate {@link LLMAdapter} for the given provider.
|
|
26
27
|
*
|
|
27
|
-
* API keys fall back to the standard environment variables
|
|
28
|
-
*
|
|
28
|
+
* API keys fall back to the standard environment variables when not supplied
|
|
29
|
+
* explicitly:
|
|
30
|
+
* - `anthropic` → `ANTHROPIC_API_KEY`
|
|
31
|
+
* - `openai` → `OPENAI_API_KEY`
|
|
32
|
+
* - `gemini` → `GEMINI_API_KEY` / `GOOGLE_API_KEY`
|
|
33
|
+
* - `grok` → `XAI_API_KEY`
|
|
34
|
+
* - `copilot` → `GITHUB_COPILOT_TOKEN` / `GITHUB_TOKEN`, or interactive
|
|
35
|
+
* OAuth2 device flow if neither is set
|
|
29
36
|
*
|
|
30
37
|
* Adapters are imported lazily so that projects using only one provider
|
|
31
38
|
* are not forced to install the SDK for the other.
|
|
32
39
|
*
|
|
33
40
|
* @param provider - Which LLM provider to target.
|
|
34
41
|
* @param apiKey - Optional API key override; falls back to env var.
|
|
42
|
+
* @param baseURL - Optional base URL for OpenAI-compatible APIs (Ollama, vLLM, etc.).
|
|
35
43
|
* @throws {Error} When the provider string is not recognised.
|
|
36
44
|
*/
|
|
37
|
-
export declare function createAdapter(provider: SupportedProvider, apiKey?: string): Promise<LLMAdapter>;
|
|
45
|
+
export declare function createAdapter(provider: SupportedProvider, apiKey?: string, baseURL?: string): Promise<LLMAdapter>;
|
|
38
46
|
//# sourceMappingURL=adapter.d.ts.map
|