agent-framework-js 0.4.1 → 0.4.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/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.2] - 2026-06-17
11
+
12
+ ### Fixed
13
+
14
+ - **Tool-using agents no longer return a blank answer when a (typically local /
15
+ LM Studio) model loops on tool calls or stops without final text.** The run loop
16
+ (both streaming and non-streaming) now falls back to the best available content —
17
+ the model's last text, otherwise the most recent successful tool result — when it
18
+ hits the iteration cap (`limit-exceeded`) or ends a turn with empty content after
19
+ a successful tool call. This fixes the workflow example's Calculator node showing
20
+ empty output under LM Studio.
21
+
10
22
  ## [0.4.1] - 2026-06-17
11
23
 
12
24
  ### Fixed
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  require('../chunk-5M6ER4ZX.cjs');
4
- var chunk4RGMZII7_cjs = require('../chunk-4RGMZII7.cjs');
4
+ var chunkYKSNVWGX_cjs = require('../chunk-YKSNVWGX.cjs');
5
5
  require('../chunk-WSMYH2IN.cjs');
6
6
  require('../chunk-TAMJ5HSR.cjs');
7
7
  require('../chunk-FSDMBWQV.cjs');
@@ -13,15 +13,15 @@ require('../chunk-IJASUMIQ.cjs');
13
13
 
14
14
  Object.defineProperty(exports, "buildMessages", {
15
15
  enumerable: true,
16
- get: function () { return chunk4RGMZII7_cjs.buildMessages; }
16
+ get: function () { return chunkYKSNVWGX_cjs.buildMessages; }
17
17
  });
18
18
  Object.defineProperty(exports, "createAgent", {
19
19
  enumerable: true,
20
- get: function () { return chunk4RGMZII7_cjs.createAgent; }
20
+ get: function () { return chunkYKSNVWGX_cjs.createAgent; }
21
21
  });
22
22
  Object.defineProperty(exports, "runLoop", {
23
23
  enumerable: true,
24
- get: function () { return chunk4RGMZII7_cjs.runLoop; }
24
+ get: function () { return chunkYKSNVWGX_cjs.runLoop; }
25
25
  });
26
26
  Object.defineProperty(exports, "Thread", {
27
27
  enumerable: true,
@@ -1,5 +1,5 @@
1
1
  import '../chunk-MCLVWCOB.js';
2
- export { buildMessages, createAgent, runLoop } from '../chunk-YSJG2MHD.js';
2
+ export { buildMessages, createAgent, runLoop } from '../chunk-IEX6XUZV.js';
3
3
  import '../chunk-YCBDEEAV.js';
4
4
  import '../chunk-HGEPXJDG.js';
5
5
  import '../chunk-7ZXUIHLH.js';
@@ -1,4 +1,4 @@
1
- import { createAgent } from './chunk-YSJG2MHD.js';
1
+ import { createAgent } from './chunk-IEX6XUZV.js';
2
2
  import { ValidationError } from './chunk-IXV4UIF5.js';
3
3
 
4
4
  // src/declarative/loader.ts
@@ -44,5 +44,5 @@ async function loadAgentDefinition(source, deps) {
44
44
  }
45
45
 
46
46
  export { loadAgentDefinition };
47
- //# sourceMappingURL=chunk-7S75TBCI.js.map
48
- //# sourceMappingURL=chunk-7S75TBCI.js.map
47
+ //# sourceMappingURL=chunk-DZFJ5MIF.js.map
48
+ //# sourceMappingURL=chunk-DZFJ5MIF.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/declarative/loader.ts"],"names":[],"mappings":";;;;AA+CA,SAAS,cAAc,MAAA,EAAyB;AAC/C,EAAA,MAAM,CAAA,GAAI,OAAO,SAAA,EAAU;AAC3B,EAAA,OAAO,EAAE,UAAA,CAAW,GAAG,CAAA,IAAK,CAAA,CAAE,WAAW,GAAG,CAAA;AAC7C;AAEA,eAAe,MAAM,MAAA,EAAkC;AACtD,EAAA,IAAI,aAAA,CAAc,MAAM,CAAA,EAAG;AAC1B,IAAA,IAAI;AACH,MAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IACzB,SAAS,CAAA,EAAG;AACX,MAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC7E;AAAA,EACD;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,OAAO,MAAM,CAAA;AAChC,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,EACzB,SAAS,CAAA,EAAG;AACX,IAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,EAC7E;AACD;AAEA,SAAS,iBAAiB,KAAA,EAAkD;AAC3E,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,IAAY,OAAO,CAAA,CAAE,YAAA,KAAiB,QAAA,IAAY,CAAC,CAAA,CAAE,QAAA,EAAU;AAC1F,IAAA,MAAM,IAAI,gBAAgB,0DAA0D,CAAA;AAAA,EACrF;AACD;AAaA,eAAsB,mBAAA,CAAoB,QAAgB,IAAA,EAAkC;AAC3F,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,MAAM,CAAA;AACjC,EAAA,gBAAA,CAAiB,MAAM,CAAA;AAEvB,EAAA,MAAM,WAAW,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,QAAA,EAAU,KAAK,aAAa,CAAA;AACzE,EAAA,MAAM,SAAS,MAAA,CAAO,KAAA,IAAS,EAAC,EAC9B,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,GAAQ,IAAI,CAAC,CAAA,CAChC,MAAA,CAAO,CAAC,CAAA,KAAiB,CAAC,CAAC,CAAC,CAAA;AAC9B,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,IAAU,EAAC,EAChC,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,GAAS,IAAI,CAAC,CAAA,CACjC,MAAA,CAAO,CAAC,CAAA,KAAkB,CAAC,CAAC,CAAC,CAAA;AAE/B,EAAA,OAAO,WAAA,CAAY;AAAA,IAClB,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,QAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,eAAe,MAAA,CAAO;AAAA,GACtB,CAAA;AACF","file":"chunk-7S75TBCI.js","sourcesContent":["/**\n * Declarative agent definitions. Agents can be defined in YAML or JSON against a\n * single shared schema; the loader auto-detects the format (the YAML parser is\n * lazy-loaded so JSON-only/browser use pays no cost) and builds an equivalent\n * runnable agent. Credentials are still injected via callback, never embedded.\n * (FR-027, FR-005a)\n *\n * @packageDocumentation\n */\n\nimport type { ModelCapabilities } from \"../core/types.js\";\nimport type { Provider } from \"../providers/provider.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { createAgent, type Agent } from \"../agents/agent.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** Provider section of a declarative definition. */\nexport interface ProviderDefinition extends ModelCapabilities {\n\ttype: \"copilot\" | \"openai-compatible\";\n\tbaseUrl?: string;\n}\n\n/** A declarative agent definition (shared by YAML and JSON). */\nexport interface AgentDefinition {\n\tname: string;\n\tinstructions: string;\n\tprovider: ProviderDefinition;\n\t/** Names referencing tools provided in `deps.tools`. */\n\ttools?: string[];\n\t/** Names referencing skills provided in `deps.skills`. */\n\tskills?: string[];\n\tmaxIterations?: number;\n}\n\n/** Dependencies the loader needs to construct a live agent. */\nexport interface LoaderDeps {\n\t/** Build a provider from the definition + injected credential. */\n\tproviderFactory: (def: ProviderDefinition, getCredential: () => string | Promise<string>) => Provider;\n\t/** Credential callback — never embedded in the definition. (FR-005a) */\n\tgetCredential: () => string | Promise<string>;\n\t/** Registered tools available for reference by name. */\n\ttools?: Record<string, Tool>;\n\t/** Registered skills available for reference by name. */\n\tskills?: Record<string, Skill>;\n}\n\nfunction looksLikeJson(source: string): boolean {\n\tconst t = source.trimStart();\n\treturn t.startsWith(\"{\") || t.startsWith(\"[\");\n}\n\nasync function parse(source: string): Promise<unknown> {\n\tif (looksLikeJson(source)) {\n\t\ttry {\n\t\t\treturn JSON.parse(source);\n\t\t} catch (e) {\n\t\t\tthrow new ValidationError(`Invalid JSON definition: ${(e as Error).message}`);\n\t\t}\n\t}\n\t// Lazy-load the YAML parser only when needed. (FR-027)\n\tconst YAML = await import(\"yaml\");\n\ttry {\n\t\treturn YAML.parse(source);\n\t} catch (e) {\n\t\tthrow new ValidationError(`Invalid YAML definition: ${(e as Error).message}`);\n\t}\n}\n\nfunction assertDefinition(value: unknown): asserts value is AgentDefinition {\n\tconst d = value as Partial<AgentDefinition>;\n\tif (!d || typeof d.name !== \"string\" || typeof d.instructions !== \"string\" || !d.provider) {\n\t\tthrow new ValidationError(\"Definition must include name, instructions, and provider\");\n\t}\n}\n\n/**\n * Load an agent from a YAML or JSON definition string.\n *\n * @example\n * ```ts\n * const agent = await loadAgentDefinition(yamlOrJson, {\n * providerFactory,\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * });\n * ```\n */\nexport async function loadAgentDefinition(source: string, deps: LoaderDeps): Promise<Agent> {\n\tconst parsed = await parse(source);\n\tassertDefinition(parsed);\n\n\tconst provider = deps.providerFactory(parsed.provider, deps.getCredential);\n\tconst tools = (parsed.tools ?? [])\n\t\t.map((name) => deps.tools?.[name])\n\t\t.filter((t): t is Tool => !!t);\n\tconst skills = (parsed.skills ?? [])\n\t\t.map((name) => deps.skills?.[name])\n\t\t.filter((s): s is Skill => !!s);\n\n\treturn createAgent({\n\t\tname: parsed.name,\n\t\tinstructions: parsed.instructions,\n\t\tprovider,\n\t\ttools,\n\t\tskills,\n\t\tmaxIterations: parsed.maxIterations,\n\t});\n}\n"]}
1
+ {"version":3,"sources":["../src/declarative/loader.ts"],"names":[],"mappings":";;;;AA+CA,SAAS,cAAc,MAAA,EAAyB;AAC/C,EAAA,MAAM,CAAA,GAAI,OAAO,SAAA,EAAU;AAC3B,EAAA,OAAO,EAAE,UAAA,CAAW,GAAG,CAAA,IAAK,CAAA,CAAE,WAAW,GAAG,CAAA;AAC7C;AAEA,eAAe,MAAM,MAAA,EAAkC;AACtD,EAAA,IAAI,aAAA,CAAc,MAAM,CAAA,EAAG;AAC1B,IAAA,IAAI;AACH,MAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IACzB,SAAS,CAAA,EAAG;AACX,MAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC7E;AAAA,EACD;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,OAAO,MAAM,CAAA;AAChC,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,EACzB,SAAS,CAAA,EAAG;AACX,IAAA,MAAM,IAAI,eAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,EAC7E;AACD;AAEA,SAAS,iBAAiB,KAAA,EAAkD;AAC3E,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,IAAY,OAAO,CAAA,CAAE,YAAA,KAAiB,QAAA,IAAY,CAAC,CAAA,CAAE,QAAA,EAAU;AAC1F,IAAA,MAAM,IAAI,gBAAgB,0DAA0D,CAAA;AAAA,EACrF;AACD;AAaA,eAAsB,mBAAA,CAAoB,QAAgB,IAAA,EAAkC;AAC3F,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,MAAM,CAAA;AACjC,EAAA,gBAAA,CAAiB,MAAM,CAAA;AAEvB,EAAA,MAAM,WAAW,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,QAAA,EAAU,KAAK,aAAa,CAAA;AACzE,EAAA,MAAM,SAAS,MAAA,CAAO,KAAA,IAAS,EAAC,EAC9B,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,GAAQ,IAAI,CAAC,CAAA,CAChC,MAAA,CAAO,CAAC,CAAA,KAAiB,CAAC,CAAC,CAAC,CAAA;AAC9B,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,IAAU,EAAC,EAChC,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,GAAS,IAAI,CAAC,CAAA,CACjC,MAAA,CAAO,CAAC,CAAA,KAAkB,CAAC,CAAC,CAAC,CAAA;AAE/B,EAAA,OAAO,WAAA,CAAY;AAAA,IAClB,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,QAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,eAAe,MAAA,CAAO;AAAA,GACtB,CAAA;AACF","file":"chunk-DZFJ5MIF.js","sourcesContent":["/**\n * Declarative agent definitions. Agents can be defined in YAML or JSON against a\n * single shared schema; the loader auto-detects the format (the YAML parser is\n * lazy-loaded so JSON-only/browser use pays no cost) and builds an equivalent\n * runnable agent. Credentials are still injected via callback, never embedded.\n * (FR-027, FR-005a)\n *\n * @packageDocumentation\n */\n\nimport type { ModelCapabilities } from \"../core/types.js\";\nimport type { Provider } from \"../providers/provider.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { createAgent, type Agent } from \"../agents/agent.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** Provider section of a declarative definition. */\nexport interface ProviderDefinition extends ModelCapabilities {\n\ttype: \"copilot\" | \"openai-compatible\";\n\tbaseUrl?: string;\n}\n\n/** A declarative agent definition (shared by YAML and JSON). */\nexport interface AgentDefinition {\n\tname: string;\n\tinstructions: string;\n\tprovider: ProviderDefinition;\n\t/** Names referencing tools provided in `deps.tools`. */\n\ttools?: string[];\n\t/** Names referencing skills provided in `deps.skills`. */\n\tskills?: string[];\n\tmaxIterations?: number;\n}\n\n/** Dependencies the loader needs to construct a live agent. */\nexport interface LoaderDeps {\n\t/** Build a provider from the definition + injected credential. */\n\tproviderFactory: (def: ProviderDefinition, getCredential: () => string | Promise<string>) => Provider;\n\t/** Credential callback — never embedded in the definition. (FR-005a) */\n\tgetCredential: () => string | Promise<string>;\n\t/** Registered tools available for reference by name. */\n\ttools?: Record<string, Tool>;\n\t/** Registered skills available for reference by name. */\n\tskills?: Record<string, Skill>;\n}\n\nfunction looksLikeJson(source: string): boolean {\n\tconst t = source.trimStart();\n\treturn t.startsWith(\"{\") || t.startsWith(\"[\");\n}\n\nasync function parse(source: string): Promise<unknown> {\n\tif (looksLikeJson(source)) {\n\t\ttry {\n\t\t\treturn JSON.parse(source);\n\t\t} catch (e) {\n\t\t\tthrow new ValidationError(`Invalid JSON definition: ${(e as Error).message}`);\n\t\t}\n\t}\n\t// Lazy-load the YAML parser only when needed. (FR-027)\n\tconst YAML = await import(\"yaml\");\n\ttry {\n\t\treturn YAML.parse(source);\n\t} catch (e) {\n\t\tthrow new ValidationError(`Invalid YAML definition: ${(e as Error).message}`);\n\t}\n}\n\nfunction assertDefinition(value: unknown): asserts value is AgentDefinition {\n\tconst d = value as Partial<AgentDefinition>;\n\tif (!d || typeof d.name !== \"string\" || typeof d.instructions !== \"string\" || !d.provider) {\n\t\tthrow new ValidationError(\"Definition must include name, instructions, and provider\");\n\t}\n}\n\n/**\n * Load an agent from a YAML or JSON definition string.\n *\n * @example\n * ```ts\n * const agent = await loadAgentDefinition(yamlOrJson, {\n * providerFactory,\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * });\n * ```\n */\nexport async function loadAgentDefinition(source: string, deps: LoaderDeps): Promise<Agent> {\n\tconst parsed = await parse(source);\n\tassertDefinition(parsed);\n\n\tconst provider = deps.providerFactory(parsed.provider, deps.getCredential);\n\tconst tools = (parsed.tools ?? [])\n\t\t.map((name) => deps.tools?.[name])\n\t\t.filter((t): t is Tool => !!t);\n\tconst skills = (parsed.skills ?? [])\n\t\t.map((name) => deps.skills?.[name])\n\t\t.filter((s): s is Skill => !!s);\n\n\treturn createAgent({\n\t\tname: parsed.name,\n\t\tinstructions: parsed.instructions,\n\t\tprovider,\n\t\ttools,\n\t\tskills,\n\t\tmaxIterations: parsed.maxIterations,\n\t});\n}\n"]}
@@ -9,11 +9,13 @@ async function runLoop(generate, registry, messages, options) {
9
9
  const maxIterations = options?.maxIterations ?? 10;
10
10
  const working = [...messages];
11
11
  let iteration = 0;
12
+ let lastText = "";
13
+ let lastToolText = "";
12
14
  for (; ; ) {
13
15
  if (maxIterations !== -1 && iteration >= maxIterations) {
14
16
  return {
15
17
  messages: working,
16
- final: { text: "" },
18
+ final: { text: lastText || lastToolText },
17
19
  status: "limit-exceeded"
18
20
  };
19
21
  }
@@ -24,7 +26,11 @@ async function runLoop(generate, registry, messages, options) {
24
26
  tools: specs.length > 0 ? specs : void 0,
25
27
  signal: options?.signal
26
28
  });
29
+ if (response.text) lastText = response.text;
27
30
  if (!response.toolCalls || response.toolCalls.length === 0) {
31
+ if (!response.text && lastToolText) {
32
+ return { messages: working, final: { ...response, text: lastToolText }, status: "completed" };
33
+ }
28
34
  return { messages: working, final: response, status: "completed" };
29
35
  }
30
36
  working.push({
@@ -36,6 +42,7 @@ async function runLoop(generate, registry, messages, options) {
36
42
  for (const call of response.toolCalls) {
37
43
  const result = await registry.invoke(call.name, call.arguments, options?.toolTimeoutMs);
38
44
  const payload = result.error ? `ERROR (${result.error.reason}): ${result.error.message}` : JSON.stringify(result.value ?? null);
45
+ if (!result.error) lastToolText = payload;
39
46
  working.push({
40
47
  role: "tool",
41
48
  name: call.name,
@@ -152,12 +159,14 @@ ${contents.join("\n\n")}`
152
159
  let finalText = "";
153
160
  let finalReasoning = "";
154
161
  let iteration = 0;
162
+ let lastText = "";
163
+ let lastToolText = "";
155
164
  try {
156
165
  for (; ; ) {
157
166
  if (maxIterations !== -1 && iteration >= maxIterations) {
158
167
  yield {
159
168
  type: "done",
160
- result: { output: "", status: "limit-exceeded", partial: false, thread }
169
+ result: { output: lastText || lastToolText, status: "limit-exceeded", partial: false, thread }
161
170
  };
162
171
  return;
163
172
  }
@@ -181,9 +190,10 @@ ${contents.join("\n\n")}`
181
190
  response = chunk.response;
182
191
  }
183
192
  }
193
+ if (turnText) lastText = turnText;
184
194
  const toolCalls = response?.toolCalls;
185
195
  if (!toolCalls || toolCalls.length === 0) {
186
- finalText = response?.text || turnText;
196
+ finalText = response?.text || turnText || lastToolText;
187
197
  finalReasoning = response?.reasoning || turnReasoning;
188
198
  break;
189
199
  }
@@ -196,6 +206,7 @@ ${contents.join("\n\n")}`
196
206
  for (const call of toolCalls) {
197
207
  const result = await registry.invoke(call.name, call.arguments, config.toolTimeoutMs);
198
208
  const payload = result.error ? `ERROR (${result.error.reason}): ${result.error.message}` : JSON.stringify(result.value ?? null);
209
+ if (!result.error) lastToolText = payload;
199
210
  working.push({
200
211
  role: "tool",
201
212
  name: call.name,
@@ -228,5 +239,5 @@ ${contents.join("\n\n")}`
228
239
  }
229
240
 
230
241
  export { buildMessages, createAgent, runLoop };
231
- //# sourceMappingURL=chunk-YSJG2MHD.js.map
232
- //# sourceMappingURL=chunk-YSJG2MHD.js.map
242
+ //# sourceMappingURL=chunk-IEX6XUZV.js.map
243
+ //# sourceMappingURL=chunk-IEX6XUZV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/loop.ts","../src/agents/agent.ts"],"names":[],"mappings":"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","file":"chunk-IEX6XUZV.js","sourcesContent":["/**\n * The agent run loop: drives provider calls, executes requested tool calls,\n * feeds typed results (including errors, for self-correction) back to the model,\n * and stops on a final answer, the iteration cap, or an abort. (FR-011a, FR-012b)\n *\n * @packageDocumentation\n */\n\nimport type { Message } from \"../core/types.js\";\nimport { textMessage } from \"../core/types.js\";\nimport type { GenerateRequest, GenerateResponse } from \"../providers/provider.js\";\nimport type { ToolRegistry } from \"../tools/registry.js\";\n\n/** Outcome status of a run. */\nexport type RunStatus = \"completed\" | \"failed\" | \"incomplete\" | \"limit-exceeded\";\n\n/** A function that produces a model response (optionally through middleware). */\nexport type GenerateFn = (req: GenerateRequest) => Promise<GenerateResponse>;\n\n/** Settings controlling the loop. */\nexport interface LoopOptions {\n\t/** Maximum iterations; -1 means unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** Result of running the loop. */\nexport interface LoopResult {\n\tmessages: Message[];\n\tfinal: GenerateResponse;\n\tstatus: RunStatus;\n}\n\n/**\n * Execute the tool-call loop against a generate function and tool registry.\n *\n * @param generate - Produces a model response (typically the middleware pipeline).\n * @param registry - Tools available to the agent (may be empty).\n * @param messages - Initial conversation (system + user, etc.).\n * @param options - Loop tuning.\n */\nexport async function runLoop(\n\tgenerate: GenerateFn,\n\tregistry: ToolRegistry,\n\tmessages: Message[],\n\toptions?: LoopOptions,\n): Promise<LoopResult> {\n\tconst maxIterations = options?.maxIterations ?? 10;\n\tconst working = [...messages];\n\tlet iteration = 0;\n\t// Best-available content to surface if the model never settles on a final\n\t// answer and we hit the iteration cap (common with small local models that\n\t// loop on tool calls). Prefer the model's own last text; otherwise fall back\n\t// to the most recent successful tool result so the run never returns blank.\n\tlet lastText = \"\";\n\tlet lastToolText = \"\";\n\n\tfor (; ;) {\n\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\treturn {\n\t\t\t\tmessages: working,\n\t\t\t\tfinal: { text: lastText || lastToolText },\n\t\t\t\tstatus: \"limit-exceeded\",\n\t\t\t};\n\t\t}\n\t\titeration++;\n\n\t\tconst specs = registry.specs();\n\t\tconst response = await generate({\n\t\t\tmessages: working,\n\t\t\ttools: specs.length > 0 ? specs : undefined,\n\t\t\tsignal: options?.signal,\n\t\t});\n\n\t\tif (response.text) lastText = response.text;\n\n\t\tif (!response.toolCalls || response.toolCalls.length === 0) {\n\t\t\t// If the model ends its turn without text but has already produced a\n\t\t\t// successful tool result, surface that result rather than an empty answer\n\t\t\t// (some local models compute via a tool then return blank content).\n\t\t\tif (!response.text && lastToolText) {\n\t\t\t\treturn { messages: working, final: { ...response, text: lastToolText }, status: \"completed\" };\n\t\t\t}\n\t\t\treturn { messages: working, final: response, status: \"completed\" };\n\t\t}\n\n\t\t// Record the assistant's tool-call turn, preserving the tool calls (so strict\n\t\t// providers can pair each result with its call) and any opaque reasoning blob\n\t\t// (for thinking continuity across turns).\n\t\tworking.push({\n\t\t\trole: \"assistant\",\n\t\t\tparts: response.text ? [{ type: \"text\", text: response.text }] : [],\n\t\t\ttoolCalls: response.toolCalls,\n\t\t\t...(response.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t});\n\n\t\t// Execute each requested tool and feed results (or typed errors) back.\n\t\tfor (const call of response.toolCalls) {\n\t\t\tconst result = await registry.invoke(call.name, call.arguments, options?.toolTimeoutMs);\n\t\t\tconst payload = result.error\n\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\tif (!result.error) lastToolText = payload;\n\t\t\tworking.push({\n\t\t\t\trole: \"tool\",\n\t\t\t\tname: call.name,\n\t\t\t\ttoolCallId: call.id,\n\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t});\n\t\t}\n\t}\n}\n\n/** Build the initial message list from instructions + input. */\nexport function buildMessages(instructions: string, input: Message[]): Message[] {\n\treturn [textMessage(\"system\", instructions), ...input];\n}\n","/**\n * The agent: a configured actor that runs against a provider, optionally using\n * tools and skills, with streaming, reasoning output, multimodal input gating,\n * conversation threads with compaction, and a middleware pipeline.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart } from \"../core/types.js\";\nimport { hasImage, textMessage } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type { Provider, GenerateResponse, GenerateRequest } from \"../providers/provider.js\";\nimport { ToolRegistry } from \"../tools/registry.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { SkillIndex } from \"../skills/index.js\";\nimport type { Middleware, MiddlewareContext } from \"../middleware/middleware.js\";\nimport { composeMiddleware } from \"../middleware/middleware.js\";\nimport { Thread, type ThreadOptions } from \"./thread.js\";\nimport { runLoop, type RunStatus } from \"./loop.js\";\n\n/** Configuration for {@link createAgent}. */\nexport interface AgentConfig {\n\tname: string;\n\tinstructions: string;\n\tprovider: Provider;\n\t/** Which of the provider's models to use; defaults to the provider's default model. */\n\tmodel?: string;\n\ttools?: Tool[];\n\tskills?: Skill[];\n\t/** Max tool-call iterations per run; -1 = unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Compaction threshold as a fraction of maxInputTokens. Default 0.9. (FR-004a) */\n\tcompactionThreshold?: number;\n\t/** Optional override model for compaction summaries. (FR-004b) */\n\tcompactionModel?: Provider;\n\t/** Middleware applied around provider calls. (FR-023) */\n\tmiddleware?: Middleware[];\n}\n\n/** Options for a single run. */\nexport interface RunOptions {\n\t/** Continue an existing conversation. (FR-004) */\n\tthread?: Thread;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** The result of a non-streaming run. */\nexport interface RunResult {\n\toutput: string;\n\t/** Reasoning content — only for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\tstatus: RunStatus;\n\t/** True when the run was interrupted before completing. (FR-003b) */\n\tpartial: boolean;\n\terror?: ProviderError;\n\t/** The thread used/updated by this run. */\n\tthread: Thread;\n}\n\n/** Streamed run chunk. */\nexport type RunChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"done\"; result: RunResult };\n\n/** Agent input: plain text or structured (multimodal) messages. (FR-002) */\nexport type AgentInput = string | Message | Message[];\n\n/** A runnable agent. */\nexport interface Agent {\n\treadonly name: string;\n\trun(input: AgentInput, opts?: RunOptions): Promise<RunResult>;\n\trunStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk>;\n}\n\nfunction normalizeInput(input: AgentInput): Message[] {\n\tif (typeof input === \"string\") return [textMessage(\"user\", input)];\n\treturn Array.isArray(input) ? input : [input];\n}\n\nfunction promptText(messages: Message[]): string {\n\treturn messages\n\t\t.flatMap((m) => m.parts)\n\t\t.filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n\t\t.map((p) => p.text)\n\t\t.join(\" \");\n}\n\n/**\n * Create an agent.\n *\n * @example\n * ```ts\n * const agent = createAgent({ name: \"Helper\", instructions: \"Be concise.\", provider });\n * const res = await agent.run(\"Say hello.\");\n * console.log(res.status, res.output);\n * ```\n */\nexport function createAgent(config: AgentConfig): Agent {\n\tconst registry = new ToolRegistry(config.tools ?? []);\n\tconst skillIndex = new SkillIndex(config.skills ?? []);\n\tconst middleware = config.middleware ?? [];\n\t/** Capabilities of the model this agent uses (selected from the provider). */\n\tconst modelCaps = () => config.provider.model(config.model);\n\n\tfunction gateVision(messages: Message[]): void {\n\t\tif (!modelCaps().supportsVision && messages.some(hasImage)) {\n\t\t\tthrow new ProviderError(\n\t\t\t\t\"Image input was provided but the configured model does not support vision\",\n\t\t\t\t\"client\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync function injectSkills(userMessages: Message[]): Promise<Message[]> {\n\t\tif ((config.skills ?? []).length === 0) return userMessages;\n\t\tconst selected = skillIndex.select(promptText(userMessages));\n\t\tif (selected.length === 0) return userMessages;\n\t\tconst contents = await Promise.all(selected.map((s) => skillIndex.load(s)));\n\t\tconst skillBlock = textMessage(\n\t\t\t\"system\",\n\t\t\t`Relevant skill knowledge:\\n${contents.join(\"\\n\\n\")}`,\n\t\t);\n\t\treturn [skillBlock, ...userMessages];\n\t}\n\n\tasync function callProvider(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tconst ctx: MiddlewareContext = {\n\t\t\tagentName: config.name,\n\t\t\trequest: { ...req, model: req.model ?? config.model },\n\t\t};\n\t\tconst pipeline = composeMiddleware(middleware, (c) => config.provider.generate(c.request));\n\t\treturn pipeline(ctx);\n\t}\n\n\tasync function prepare(input: AgentInput, opts?: RunOptions): Promise<Thread> {\n\t\tconst userMessages = normalizeInput(input);\n\t\tgateVision(userMessages);\n\t\tconst thread =\n\t\t\topts?.thread ??\n\t\t\tnew Thread(undefined, [textMessage(\"system\", config.instructions)]);\n\t\tconst withSkills = await injectSkills(userMessages);\n\t\tfor (const m of withSkills) thread.add(m);\n\t\tawait thread.maybeCompact(config.provider, {\n\t\t\tcompactionThreshold: config.compactionThreshold,\n\t\t\tcompactionModel: config.compactionModel,\n\t\t\tmodelCapabilities: modelCaps(),\n\t\t} satisfies ThreadOptions);\n\t\treturn thread;\n\t}\n\n\tasync function run(input: AgentInput, opts?: RunOptions): Promise<RunResult> {\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\ttry {\n\t\t\tconst loop = await runLoop(callProvider, registry, thread.messages, {\n\t\t\t\tmaxIterations: config.maxIterations,\n\t\t\t\ttoolTimeoutMs: config.toolTimeoutMs,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t});\n\t\t\tif (loop.final.text) {\n\t\t\t\tthread.add({ role: \"assistant\", parts: [{ type: \"text\", text: loop.final.text }] });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toutput: loop.final.text,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? loop.final.reasoning : undefined,\n\t\t\t\tstatus: loop.status,\n\t\t\t\tpartial: loop.status === \"incomplete\",\n\t\t\t\tthread,\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync function* runStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk> {\n\t\t// Streaming path: drives the same tool-call loop as the non-streaming `run`,\n\t\t// but streams the model's text/reasoning for each turn. Tool-call turns are\n\t\t// executed and their results fed back; the final (tool-free) turn's text is\n\t\t// the answer. (FR-011a, FR-012b)\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\tyield { type: \"done\", result: { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() } };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\tconst maxIterations = config.maxIterations ?? 10;\n\t\t// Working transcript the loop appends to (assistant tool-call turns + tool results).\n\t\tconst working: Message[] = [...thread.messages];\n\t\tlet finalText = \"\";\n\t\tlet finalReasoning = \"\";\n\t\tlet iteration = 0;\n\t\t// Best-available content if the model loops until the iteration cap: prefer\n\t\t// its own last text, else the most recent successful tool result, so a\n\t\t// looping local model surfaces something instead of an empty answer.\n\t\tlet lastText = \"\";\n\t\tlet lastToolText = \"\";\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tresult: { output: lastText || lastToolText, status: \"limit-exceeded\", partial: false, thread },\n\t\t\t\t\t};\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\titeration++;\n\n\t\t\t\t// Stream one provider turn, accumulating this turn's text/reasoning and\n\t\t\t\t// capturing the complete response (which carries any tool calls).\n\t\t\t\tlet turnText = \"\";\n\t\t\t\tlet turnReasoning = \"\";\n\t\t\t\tlet response: GenerateResponse | undefined;\n\t\t\t\tfor await (const chunk of config.provider.generateStream({\n\t\t\t\t\tmessages: working,\n\t\t\t\t\ttools: registry.specs(),\n\t\t\t\t\tmodel: config.model,\n\t\t\t\t\tsignal: opts?.signal,\n\t\t\t\t})) {\n\t\t\t\t\tif (chunk.type === \"text\") {\n\t\t\t\t\t\tturnText += chunk.text;\n\t\t\t\t\t\tyield { type: \"text\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"reasoning\" && modelCaps().supportsReasoning) {\n\t\t\t\t\t\tturnReasoning += chunk.text;\n\t\t\t\t\t\tyield { type: \"reasoning\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"done\") {\n\t\t\t\t\t\tresponse = chunk.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (turnText) lastText = turnText;\n\n\t\t\t\tconst toolCalls = response?.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\t// Final answer reached. If the model ends without text but already\n\t\t\t\t\t// produced a successful tool result, surface that instead of blank.\n\t\t\t\t\tfinalText = response?.text || turnText || lastToolText;\n\t\t\t\t\tfinalReasoning = response?.reasoning || turnReasoning;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Record the assistant's tool-call turn (preserving any reasoning blob),\n\t\t\t\t// then execute each requested tool and feed results back for self-correction.\n\t\t\t\tworking.push({\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tparts: turnText ? [{ type: \"text\", text: turnText }] : [],\n\t\t\t\t\ttoolCalls,\n\t\t\t\t\t...(response?.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t\t\t});\n\t\t\t\tfor (const call of toolCalls) {\n\t\t\t\t\tconst result = await registry.invoke(call.name, call.arguments, config.toolTimeoutMs);\n\t\t\t\t\tconst payload = result.error\n\t\t\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\t\t\tif (!result.error) lastToolText = payload;\n\t\t\t\t\tworking.push({\n\t\t\t\t\t\trole: \"tool\",\n\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\ttoolCallId: call.id,\n\t\t\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst error = e instanceof ProviderError ? e : new ProviderError((e as Error).message, \"transient\");\n\t\t\tyield {\n\t\t\t\ttype: \"done\",\n\t\t\t\tresult: { output: finalText, status: \"incomplete\", partial: true, error, thread },\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\n\t\tif (finalText) thread.add({ role: \"assistant\", parts: [{ type: \"text\", text: finalText }] });\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresult: {\n\t\t\t\toutput: finalText,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? finalReasoning || undefined : undefined,\n\t\t\t\tstatus: \"completed\",\n\t\t\t\tpartial: false,\n\t\t\t\tthread,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn { name: config.name, run, runStream };\n}\n\nexport type { ContentPart };\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk4RGMZII7_cjs = require('./chunk-4RGMZII7.cjs');
3
+ var chunkYKSNVWGX_cjs = require('./chunk-YKSNVWGX.cjs');
4
4
  var chunkMQ2XTH3S_cjs = require('./chunk-MQ2XTH3S.cjs');
5
5
 
6
6
  // src/declarative/loader.ts
@@ -35,7 +35,7 @@ async function loadAgentDefinition(source, deps) {
35
35
  const provider = deps.providerFactory(parsed.provider, deps.getCredential);
36
36
  const tools = (parsed.tools ?? []).map((name) => deps.tools?.[name]).filter((t) => !!t);
37
37
  const skills = (parsed.skills ?? []).map((name) => deps.skills?.[name]).filter((s) => !!s);
38
- return chunk4RGMZII7_cjs.createAgent({
38
+ return chunkYKSNVWGX_cjs.createAgent({
39
39
  name: parsed.name,
40
40
  instructions: parsed.instructions,
41
41
  provider,
@@ -46,5 +46,5 @@ async function loadAgentDefinition(source, deps) {
46
46
  }
47
47
 
48
48
  exports.loadAgentDefinition = loadAgentDefinition;
49
- //# sourceMappingURL=chunk-IIANZWIQ.cjs.map
50
- //# sourceMappingURL=chunk-IIANZWIQ.cjs.map
49
+ //# sourceMappingURL=chunk-J2YO7BBV.cjs.map
50
+ //# sourceMappingURL=chunk-J2YO7BBV.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/declarative/loader.ts"],"names":["ValidationError","createAgent"],"mappings":";;;;;;AA+CA,SAAS,cAAc,MAAA,EAAyB;AAC/C,EAAA,MAAM,CAAA,GAAI,OAAO,SAAA,EAAU;AAC3B,EAAA,OAAO,EAAE,UAAA,CAAW,GAAG,CAAA,IAAK,CAAA,CAAE,WAAW,GAAG,CAAA;AAC7C;AAEA,eAAe,MAAM,MAAA,EAAkC;AACtD,EAAA,IAAI,aAAA,CAAc,MAAM,CAAA,EAAG;AAC1B,IAAA,IAAI;AACH,MAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IACzB,SAAS,CAAA,EAAG;AACX,MAAA,MAAM,IAAIA,iCAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC7E;AAAA,EACD;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,OAAO,MAAM,CAAA;AAChC,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,EACzB,SAAS,CAAA,EAAG;AACX,IAAA,MAAM,IAAIA,iCAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,EAC7E;AACD;AAEA,SAAS,iBAAiB,KAAA,EAAkD;AAC3E,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,IAAY,OAAO,CAAA,CAAE,YAAA,KAAiB,QAAA,IAAY,CAAC,CAAA,CAAE,QAAA,EAAU;AAC1F,IAAA,MAAM,IAAIA,kCAAgB,0DAA0D,CAAA;AAAA,EACrF;AACD;AAaA,eAAsB,mBAAA,CAAoB,QAAgB,IAAA,EAAkC;AAC3F,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,MAAM,CAAA;AACjC,EAAA,gBAAA,CAAiB,MAAM,CAAA;AAEvB,EAAA,MAAM,WAAW,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,QAAA,EAAU,KAAK,aAAa,CAAA;AACzE,EAAA,MAAM,SAAS,MAAA,CAAO,KAAA,IAAS,EAAC,EAC9B,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,GAAQ,IAAI,CAAC,CAAA,CAChC,MAAA,CAAO,CAAC,CAAA,KAAiB,CAAC,CAAC,CAAC,CAAA;AAC9B,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,IAAU,EAAC,EAChC,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,GAAS,IAAI,CAAC,CAAA,CACjC,MAAA,CAAO,CAAC,CAAA,KAAkB,CAAC,CAAC,CAAC,CAAA;AAE/B,EAAA,OAAOC,6BAAA,CAAY;AAAA,IAClB,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,QAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,eAAe,MAAA,CAAO;AAAA,GACtB,CAAA;AACF","file":"chunk-IIANZWIQ.cjs","sourcesContent":["/**\n * Declarative agent definitions. Agents can be defined in YAML or JSON against a\n * single shared schema; the loader auto-detects the format (the YAML parser is\n * lazy-loaded so JSON-only/browser use pays no cost) and builds an equivalent\n * runnable agent. Credentials are still injected via callback, never embedded.\n * (FR-027, FR-005a)\n *\n * @packageDocumentation\n */\n\nimport type { ModelCapabilities } from \"../core/types.js\";\nimport type { Provider } from \"../providers/provider.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { createAgent, type Agent } from \"../agents/agent.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** Provider section of a declarative definition. */\nexport interface ProviderDefinition extends ModelCapabilities {\n\ttype: \"copilot\" | \"openai-compatible\";\n\tbaseUrl?: string;\n}\n\n/** A declarative agent definition (shared by YAML and JSON). */\nexport interface AgentDefinition {\n\tname: string;\n\tinstructions: string;\n\tprovider: ProviderDefinition;\n\t/** Names referencing tools provided in `deps.tools`. */\n\ttools?: string[];\n\t/** Names referencing skills provided in `deps.skills`. */\n\tskills?: string[];\n\tmaxIterations?: number;\n}\n\n/** Dependencies the loader needs to construct a live agent. */\nexport interface LoaderDeps {\n\t/** Build a provider from the definition + injected credential. */\n\tproviderFactory: (def: ProviderDefinition, getCredential: () => string | Promise<string>) => Provider;\n\t/** Credential callback — never embedded in the definition. (FR-005a) */\n\tgetCredential: () => string | Promise<string>;\n\t/** Registered tools available for reference by name. */\n\ttools?: Record<string, Tool>;\n\t/** Registered skills available for reference by name. */\n\tskills?: Record<string, Skill>;\n}\n\nfunction looksLikeJson(source: string): boolean {\n\tconst t = source.trimStart();\n\treturn t.startsWith(\"{\") || t.startsWith(\"[\");\n}\n\nasync function parse(source: string): Promise<unknown> {\n\tif (looksLikeJson(source)) {\n\t\ttry {\n\t\t\treturn JSON.parse(source);\n\t\t} catch (e) {\n\t\t\tthrow new ValidationError(`Invalid JSON definition: ${(e as Error).message}`);\n\t\t}\n\t}\n\t// Lazy-load the YAML parser only when needed. (FR-027)\n\tconst YAML = await import(\"yaml\");\n\ttry {\n\t\treturn YAML.parse(source);\n\t} catch (e) {\n\t\tthrow new ValidationError(`Invalid YAML definition: ${(e as Error).message}`);\n\t}\n}\n\nfunction assertDefinition(value: unknown): asserts value is AgentDefinition {\n\tconst d = value as Partial<AgentDefinition>;\n\tif (!d || typeof d.name !== \"string\" || typeof d.instructions !== \"string\" || !d.provider) {\n\t\tthrow new ValidationError(\"Definition must include name, instructions, and provider\");\n\t}\n}\n\n/**\n * Load an agent from a YAML or JSON definition string.\n *\n * @example\n * ```ts\n * const agent = await loadAgentDefinition(yamlOrJson, {\n * providerFactory,\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * });\n * ```\n */\nexport async function loadAgentDefinition(source: string, deps: LoaderDeps): Promise<Agent> {\n\tconst parsed = await parse(source);\n\tassertDefinition(parsed);\n\n\tconst provider = deps.providerFactory(parsed.provider, deps.getCredential);\n\tconst tools = (parsed.tools ?? [])\n\t\t.map((name) => deps.tools?.[name])\n\t\t.filter((t): t is Tool => !!t);\n\tconst skills = (parsed.skills ?? [])\n\t\t.map((name) => deps.skills?.[name])\n\t\t.filter((s): s is Skill => !!s);\n\n\treturn createAgent({\n\t\tname: parsed.name,\n\t\tinstructions: parsed.instructions,\n\t\tprovider,\n\t\ttools,\n\t\tskills,\n\t\tmaxIterations: parsed.maxIterations,\n\t});\n}\n"]}
1
+ {"version":3,"sources":["../src/declarative/loader.ts"],"names":["ValidationError","createAgent"],"mappings":";;;;;;AA+CA,SAAS,cAAc,MAAA,EAAyB;AAC/C,EAAA,MAAM,CAAA,GAAI,OAAO,SAAA,EAAU;AAC3B,EAAA,OAAO,EAAE,UAAA,CAAW,GAAG,CAAA,IAAK,CAAA,CAAE,WAAW,GAAG,CAAA;AAC7C;AAEA,eAAe,MAAM,MAAA,EAAkC;AACtD,EAAA,IAAI,aAAA,CAAc,MAAM,CAAA,EAAG;AAC1B,IAAA,IAAI;AACH,MAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IACzB,SAAS,CAAA,EAAG;AACX,MAAA,MAAM,IAAIA,iCAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC7E;AAAA,EACD;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,OAAO,MAAM,CAAA;AAChC,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,EACzB,SAAS,CAAA,EAAG;AACX,IAAA,MAAM,IAAIA,iCAAA,CAAgB,CAAA,yBAAA,EAA6B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,EAC7E;AACD;AAEA,SAAS,iBAAiB,KAAA,EAAkD;AAC3E,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,IAAY,OAAO,CAAA,CAAE,YAAA,KAAiB,QAAA,IAAY,CAAC,CAAA,CAAE,QAAA,EAAU;AAC1F,IAAA,MAAM,IAAIA,kCAAgB,0DAA0D,CAAA;AAAA,EACrF;AACD;AAaA,eAAsB,mBAAA,CAAoB,QAAgB,IAAA,EAAkC;AAC3F,EAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,MAAM,CAAA;AACjC,EAAA,gBAAA,CAAiB,MAAM,CAAA;AAEvB,EAAA,MAAM,WAAW,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,QAAA,EAAU,KAAK,aAAa,CAAA;AACzE,EAAA,MAAM,SAAS,MAAA,CAAO,KAAA,IAAS,EAAC,EAC9B,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,KAAA,GAAQ,IAAI,CAAC,CAAA,CAChC,MAAA,CAAO,CAAC,CAAA,KAAiB,CAAC,CAAC,CAAC,CAAA;AAC9B,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,IAAU,EAAC,EAChC,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,GAAS,IAAI,CAAC,CAAA,CACjC,MAAA,CAAO,CAAC,CAAA,KAAkB,CAAC,CAAC,CAAC,CAAA;AAE/B,EAAA,OAAOC,6BAAA,CAAY;AAAA,IAClB,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,QAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,eAAe,MAAA,CAAO;AAAA,GACtB,CAAA;AACF","file":"chunk-J2YO7BBV.cjs","sourcesContent":["/**\n * Declarative agent definitions. Agents can be defined in YAML or JSON against a\n * single shared schema; the loader auto-detects the format (the YAML parser is\n * lazy-loaded so JSON-only/browser use pays no cost) and builds an equivalent\n * runnable agent. Credentials are still injected via callback, never embedded.\n * (FR-027, FR-005a)\n *\n * @packageDocumentation\n */\n\nimport type { ModelCapabilities } from \"../core/types.js\";\nimport type { Provider } from \"../providers/provider.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { createAgent, type Agent } from \"../agents/agent.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** Provider section of a declarative definition. */\nexport interface ProviderDefinition extends ModelCapabilities {\n\ttype: \"copilot\" | \"openai-compatible\";\n\tbaseUrl?: string;\n}\n\n/** A declarative agent definition (shared by YAML and JSON). */\nexport interface AgentDefinition {\n\tname: string;\n\tinstructions: string;\n\tprovider: ProviderDefinition;\n\t/** Names referencing tools provided in `deps.tools`. */\n\ttools?: string[];\n\t/** Names referencing skills provided in `deps.skills`. */\n\tskills?: string[];\n\tmaxIterations?: number;\n}\n\n/** Dependencies the loader needs to construct a live agent. */\nexport interface LoaderDeps {\n\t/** Build a provider from the definition + injected credential. */\n\tproviderFactory: (def: ProviderDefinition, getCredential: () => string | Promise<string>) => Provider;\n\t/** Credential callback — never embedded in the definition. (FR-005a) */\n\tgetCredential: () => string | Promise<string>;\n\t/** Registered tools available for reference by name. */\n\ttools?: Record<string, Tool>;\n\t/** Registered skills available for reference by name. */\n\tskills?: Record<string, Skill>;\n}\n\nfunction looksLikeJson(source: string): boolean {\n\tconst t = source.trimStart();\n\treturn t.startsWith(\"{\") || t.startsWith(\"[\");\n}\n\nasync function parse(source: string): Promise<unknown> {\n\tif (looksLikeJson(source)) {\n\t\ttry {\n\t\t\treturn JSON.parse(source);\n\t\t} catch (e) {\n\t\t\tthrow new ValidationError(`Invalid JSON definition: ${(e as Error).message}`);\n\t\t}\n\t}\n\t// Lazy-load the YAML parser only when needed. (FR-027)\n\tconst YAML = await import(\"yaml\");\n\ttry {\n\t\treturn YAML.parse(source);\n\t} catch (e) {\n\t\tthrow new ValidationError(`Invalid YAML definition: ${(e as Error).message}`);\n\t}\n}\n\nfunction assertDefinition(value: unknown): asserts value is AgentDefinition {\n\tconst d = value as Partial<AgentDefinition>;\n\tif (!d || typeof d.name !== \"string\" || typeof d.instructions !== \"string\" || !d.provider) {\n\t\tthrow new ValidationError(\"Definition must include name, instructions, and provider\");\n\t}\n}\n\n/**\n * Load an agent from a YAML or JSON definition string.\n *\n * @example\n * ```ts\n * const agent = await loadAgentDefinition(yamlOrJson, {\n * providerFactory,\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * });\n * ```\n */\nexport async function loadAgentDefinition(source: string, deps: LoaderDeps): Promise<Agent> {\n\tconst parsed = await parse(source);\n\tassertDefinition(parsed);\n\n\tconst provider = deps.providerFactory(parsed.provider, deps.getCredential);\n\tconst tools = (parsed.tools ?? [])\n\t\t.map((name) => deps.tools?.[name])\n\t\t.filter((t): t is Tool => !!t);\n\tconst skills = (parsed.skills ?? [])\n\t\t.map((name) => deps.skills?.[name])\n\t\t.filter((s): s is Skill => !!s);\n\n\treturn createAgent({\n\t\tname: parsed.name,\n\t\tinstructions: parsed.instructions,\n\t\tprovider,\n\t\ttools,\n\t\tskills,\n\t\tmaxIterations: parsed.maxIterations,\n\t});\n}\n"]}
@@ -11,11 +11,13 @@ async function runLoop(generate, registry, messages, options) {
11
11
  const maxIterations = options?.maxIterations ?? 10;
12
12
  const working = [...messages];
13
13
  let iteration = 0;
14
+ let lastText = "";
15
+ let lastToolText = "";
14
16
  for (; ; ) {
15
17
  if (maxIterations !== -1 && iteration >= maxIterations) {
16
18
  return {
17
19
  messages: working,
18
- final: { text: "" },
20
+ final: { text: lastText || lastToolText },
19
21
  status: "limit-exceeded"
20
22
  };
21
23
  }
@@ -26,7 +28,11 @@ async function runLoop(generate, registry, messages, options) {
26
28
  tools: specs.length > 0 ? specs : void 0,
27
29
  signal: options?.signal
28
30
  });
31
+ if (response.text) lastText = response.text;
29
32
  if (!response.toolCalls || response.toolCalls.length === 0) {
33
+ if (!response.text && lastToolText) {
34
+ return { messages: working, final: { ...response, text: lastToolText }, status: "completed" };
35
+ }
30
36
  return { messages: working, final: response, status: "completed" };
31
37
  }
32
38
  working.push({
@@ -38,6 +44,7 @@ async function runLoop(generate, registry, messages, options) {
38
44
  for (const call of response.toolCalls) {
39
45
  const result = await registry.invoke(call.name, call.arguments, options?.toolTimeoutMs);
40
46
  const payload = result.error ? `ERROR (${result.error.reason}): ${result.error.message}` : JSON.stringify(result.value ?? null);
47
+ if (!result.error) lastToolText = payload;
41
48
  working.push({
42
49
  role: "tool",
43
50
  name: call.name,
@@ -154,12 +161,14 @@ ${contents.join("\n\n")}`
154
161
  let finalText = "";
155
162
  let finalReasoning = "";
156
163
  let iteration = 0;
164
+ let lastText = "";
165
+ let lastToolText = "";
157
166
  try {
158
167
  for (; ; ) {
159
168
  if (maxIterations !== -1 && iteration >= maxIterations) {
160
169
  yield {
161
170
  type: "done",
162
- result: { output: "", status: "limit-exceeded", partial: false, thread }
171
+ result: { output: lastText || lastToolText, status: "limit-exceeded", partial: false, thread }
163
172
  };
164
173
  return;
165
174
  }
@@ -183,9 +192,10 @@ ${contents.join("\n\n")}`
183
192
  response = chunk.response;
184
193
  }
185
194
  }
195
+ if (turnText) lastText = turnText;
186
196
  const toolCalls = response?.toolCalls;
187
197
  if (!toolCalls || toolCalls.length === 0) {
188
- finalText = response?.text || turnText;
198
+ finalText = response?.text || turnText || lastToolText;
189
199
  finalReasoning = response?.reasoning || turnReasoning;
190
200
  break;
191
201
  }
@@ -198,6 +208,7 @@ ${contents.join("\n\n")}`
198
208
  for (const call of toolCalls) {
199
209
  const result = await registry.invoke(call.name, call.arguments, config.toolTimeoutMs);
200
210
  const payload = result.error ? `ERROR (${result.error.reason}): ${result.error.message}` : JSON.stringify(result.value ?? null);
211
+ if (!result.error) lastToolText = payload;
201
212
  working.push({
202
213
  role: "tool",
203
214
  name: call.name,
@@ -232,5 +243,5 @@ ${contents.join("\n\n")}`
232
243
  exports.buildMessages = buildMessages;
233
244
  exports.createAgent = createAgent;
234
245
  exports.runLoop = runLoop;
235
- //# sourceMappingURL=chunk-4RGMZII7.cjs.map
236
- //# sourceMappingURL=chunk-4RGMZII7.cjs.map
246
+ //# sourceMappingURL=chunk-YKSNVWGX.cjs.map
247
+ //# sourceMappingURL=chunk-YKSNVWGX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/loop.ts","../src/agents/agent.ts"],"names":["textMessage","ToolRegistry","SkillIndex","hasImage","ProviderError","composeMiddleware","Thread"],"mappings":"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","file":"chunk-YKSNVWGX.cjs","sourcesContent":["/**\n * The agent run loop: drives provider calls, executes requested tool calls,\n * feeds typed results (including errors, for self-correction) back to the model,\n * and stops on a final answer, the iteration cap, or an abort. (FR-011a, FR-012b)\n *\n * @packageDocumentation\n */\n\nimport type { Message } from \"../core/types.js\";\nimport { textMessage } from \"../core/types.js\";\nimport type { GenerateRequest, GenerateResponse } from \"../providers/provider.js\";\nimport type { ToolRegistry } from \"../tools/registry.js\";\n\n/** Outcome status of a run. */\nexport type RunStatus = \"completed\" | \"failed\" | \"incomplete\" | \"limit-exceeded\";\n\n/** A function that produces a model response (optionally through middleware). */\nexport type GenerateFn = (req: GenerateRequest) => Promise<GenerateResponse>;\n\n/** Settings controlling the loop. */\nexport interface LoopOptions {\n\t/** Maximum iterations; -1 means unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** Result of running the loop. */\nexport interface LoopResult {\n\tmessages: Message[];\n\tfinal: GenerateResponse;\n\tstatus: RunStatus;\n}\n\n/**\n * Execute the tool-call loop against a generate function and tool registry.\n *\n * @param generate - Produces a model response (typically the middleware pipeline).\n * @param registry - Tools available to the agent (may be empty).\n * @param messages - Initial conversation (system + user, etc.).\n * @param options - Loop tuning.\n */\nexport async function runLoop(\n\tgenerate: GenerateFn,\n\tregistry: ToolRegistry,\n\tmessages: Message[],\n\toptions?: LoopOptions,\n): Promise<LoopResult> {\n\tconst maxIterations = options?.maxIterations ?? 10;\n\tconst working = [...messages];\n\tlet iteration = 0;\n\t// Best-available content to surface if the model never settles on a final\n\t// answer and we hit the iteration cap (common with small local models that\n\t// loop on tool calls). Prefer the model's own last text; otherwise fall back\n\t// to the most recent successful tool result so the run never returns blank.\n\tlet lastText = \"\";\n\tlet lastToolText = \"\";\n\n\tfor (; ;) {\n\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\treturn {\n\t\t\t\tmessages: working,\n\t\t\t\tfinal: { text: lastText || lastToolText },\n\t\t\t\tstatus: \"limit-exceeded\",\n\t\t\t};\n\t\t}\n\t\titeration++;\n\n\t\tconst specs = registry.specs();\n\t\tconst response = await generate({\n\t\t\tmessages: working,\n\t\t\ttools: specs.length > 0 ? specs : undefined,\n\t\t\tsignal: options?.signal,\n\t\t});\n\n\t\tif (response.text) lastText = response.text;\n\n\t\tif (!response.toolCalls || response.toolCalls.length === 0) {\n\t\t\t// If the model ends its turn without text but has already produced a\n\t\t\t// successful tool result, surface that result rather than an empty answer\n\t\t\t// (some local models compute via a tool then return blank content).\n\t\t\tif (!response.text && lastToolText) {\n\t\t\t\treturn { messages: working, final: { ...response, text: lastToolText }, status: \"completed\" };\n\t\t\t}\n\t\t\treturn { messages: working, final: response, status: \"completed\" };\n\t\t}\n\n\t\t// Record the assistant's tool-call turn, preserving the tool calls (so strict\n\t\t// providers can pair each result with its call) and any opaque reasoning blob\n\t\t// (for thinking continuity across turns).\n\t\tworking.push({\n\t\t\trole: \"assistant\",\n\t\t\tparts: response.text ? [{ type: \"text\", text: response.text }] : [],\n\t\t\ttoolCalls: response.toolCalls,\n\t\t\t...(response.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t});\n\n\t\t// Execute each requested tool and feed results (or typed errors) back.\n\t\tfor (const call of response.toolCalls) {\n\t\t\tconst result = await registry.invoke(call.name, call.arguments, options?.toolTimeoutMs);\n\t\t\tconst payload = result.error\n\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\tif (!result.error) lastToolText = payload;\n\t\t\tworking.push({\n\t\t\t\trole: \"tool\",\n\t\t\t\tname: call.name,\n\t\t\t\ttoolCallId: call.id,\n\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t});\n\t\t}\n\t}\n}\n\n/** Build the initial message list from instructions + input. */\nexport function buildMessages(instructions: string, input: Message[]): Message[] {\n\treturn [textMessage(\"system\", instructions), ...input];\n}\n","/**\n * The agent: a configured actor that runs against a provider, optionally using\n * tools and skills, with streaming, reasoning output, multimodal input gating,\n * conversation threads with compaction, and a middleware pipeline.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart } from \"../core/types.js\";\nimport { hasImage, textMessage } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type { Provider, GenerateResponse, GenerateRequest } from \"../providers/provider.js\";\nimport { ToolRegistry } from \"../tools/registry.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { SkillIndex } from \"../skills/index.js\";\nimport type { Middleware, MiddlewareContext } from \"../middleware/middleware.js\";\nimport { composeMiddleware } from \"../middleware/middleware.js\";\nimport { Thread, type ThreadOptions } from \"./thread.js\";\nimport { runLoop, type RunStatus } from \"./loop.js\";\n\n/** Configuration for {@link createAgent}. */\nexport interface AgentConfig {\n\tname: string;\n\tinstructions: string;\n\tprovider: Provider;\n\t/** Which of the provider's models to use; defaults to the provider's default model. */\n\tmodel?: string;\n\ttools?: Tool[];\n\tskills?: Skill[];\n\t/** Max tool-call iterations per run; -1 = unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Compaction threshold as a fraction of maxInputTokens. Default 0.9. (FR-004a) */\n\tcompactionThreshold?: number;\n\t/** Optional override model for compaction summaries. (FR-004b) */\n\tcompactionModel?: Provider;\n\t/** Middleware applied around provider calls. (FR-023) */\n\tmiddleware?: Middleware[];\n}\n\n/** Options for a single run. */\nexport interface RunOptions {\n\t/** Continue an existing conversation. (FR-004) */\n\tthread?: Thread;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** The result of a non-streaming run. */\nexport interface RunResult {\n\toutput: string;\n\t/** Reasoning content — only for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\tstatus: RunStatus;\n\t/** True when the run was interrupted before completing. (FR-003b) */\n\tpartial: boolean;\n\terror?: ProviderError;\n\t/** The thread used/updated by this run. */\n\tthread: Thread;\n}\n\n/** Streamed run chunk. */\nexport type RunChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"done\"; result: RunResult };\n\n/** Agent input: plain text or structured (multimodal) messages. (FR-002) */\nexport type AgentInput = string | Message | Message[];\n\n/** A runnable agent. */\nexport interface Agent {\n\treadonly name: string;\n\trun(input: AgentInput, opts?: RunOptions): Promise<RunResult>;\n\trunStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk>;\n}\n\nfunction normalizeInput(input: AgentInput): Message[] {\n\tif (typeof input === \"string\") return [textMessage(\"user\", input)];\n\treturn Array.isArray(input) ? input : [input];\n}\n\nfunction promptText(messages: Message[]): string {\n\treturn messages\n\t\t.flatMap((m) => m.parts)\n\t\t.filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n\t\t.map((p) => p.text)\n\t\t.join(\" \");\n}\n\n/**\n * Create an agent.\n *\n * @example\n * ```ts\n * const agent = createAgent({ name: \"Helper\", instructions: \"Be concise.\", provider });\n * const res = await agent.run(\"Say hello.\");\n * console.log(res.status, res.output);\n * ```\n */\nexport function createAgent(config: AgentConfig): Agent {\n\tconst registry = new ToolRegistry(config.tools ?? []);\n\tconst skillIndex = new SkillIndex(config.skills ?? []);\n\tconst middleware = config.middleware ?? [];\n\t/** Capabilities of the model this agent uses (selected from the provider). */\n\tconst modelCaps = () => config.provider.model(config.model);\n\n\tfunction gateVision(messages: Message[]): void {\n\t\tif (!modelCaps().supportsVision && messages.some(hasImage)) {\n\t\t\tthrow new ProviderError(\n\t\t\t\t\"Image input was provided but the configured model does not support vision\",\n\t\t\t\t\"client\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync function injectSkills(userMessages: Message[]): Promise<Message[]> {\n\t\tif ((config.skills ?? []).length === 0) return userMessages;\n\t\tconst selected = skillIndex.select(promptText(userMessages));\n\t\tif (selected.length === 0) return userMessages;\n\t\tconst contents = await Promise.all(selected.map((s) => skillIndex.load(s)));\n\t\tconst skillBlock = textMessage(\n\t\t\t\"system\",\n\t\t\t`Relevant skill knowledge:\\n${contents.join(\"\\n\\n\")}`,\n\t\t);\n\t\treturn [skillBlock, ...userMessages];\n\t}\n\n\tasync function callProvider(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tconst ctx: MiddlewareContext = {\n\t\t\tagentName: config.name,\n\t\t\trequest: { ...req, model: req.model ?? config.model },\n\t\t};\n\t\tconst pipeline = composeMiddleware(middleware, (c) => config.provider.generate(c.request));\n\t\treturn pipeline(ctx);\n\t}\n\n\tasync function prepare(input: AgentInput, opts?: RunOptions): Promise<Thread> {\n\t\tconst userMessages = normalizeInput(input);\n\t\tgateVision(userMessages);\n\t\tconst thread =\n\t\t\topts?.thread ??\n\t\t\tnew Thread(undefined, [textMessage(\"system\", config.instructions)]);\n\t\tconst withSkills = await injectSkills(userMessages);\n\t\tfor (const m of withSkills) thread.add(m);\n\t\tawait thread.maybeCompact(config.provider, {\n\t\t\tcompactionThreshold: config.compactionThreshold,\n\t\t\tcompactionModel: config.compactionModel,\n\t\t\tmodelCapabilities: modelCaps(),\n\t\t} satisfies ThreadOptions);\n\t\treturn thread;\n\t}\n\n\tasync function run(input: AgentInput, opts?: RunOptions): Promise<RunResult> {\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\ttry {\n\t\t\tconst loop = await runLoop(callProvider, registry, thread.messages, {\n\t\t\t\tmaxIterations: config.maxIterations,\n\t\t\t\ttoolTimeoutMs: config.toolTimeoutMs,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t});\n\t\t\tif (loop.final.text) {\n\t\t\t\tthread.add({ role: \"assistant\", parts: [{ type: \"text\", text: loop.final.text }] });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toutput: loop.final.text,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? loop.final.reasoning : undefined,\n\t\t\t\tstatus: loop.status,\n\t\t\t\tpartial: loop.status === \"incomplete\",\n\t\t\t\tthread,\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync function* runStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk> {\n\t\t// Streaming path: drives the same tool-call loop as the non-streaming `run`,\n\t\t// but streams the model's text/reasoning for each turn. Tool-call turns are\n\t\t// executed and their results fed back; the final (tool-free) turn's text is\n\t\t// the answer. (FR-011a, FR-012b)\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\tyield { type: \"done\", result: { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() } };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\tconst maxIterations = config.maxIterations ?? 10;\n\t\t// Working transcript the loop appends to (assistant tool-call turns + tool results).\n\t\tconst working: Message[] = [...thread.messages];\n\t\tlet finalText = \"\";\n\t\tlet finalReasoning = \"\";\n\t\tlet iteration = 0;\n\t\t// Best-available content if the model loops until the iteration cap: prefer\n\t\t// its own last text, else the most recent successful tool result, so a\n\t\t// looping local model surfaces something instead of an empty answer.\n\t\tlet lastText = \"\";\n\t\tlet lastToolText = \"\";\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tresult: { output: lastText || lastToolText, status: \"limit-exceeded\", partial: false, thread },\n\t\t\t\t\t};\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\titeration++;\n\n\t\t\t\t// Stream one provider turn, accumulating this turn's text/reasoning and\n\t\t\t\t// capturing the complete response (which carries any tool calls).\n\t\t\t\tlet turnText = \"\";\n\t\t\t\tlet turnReasoning = \"\";\n\t\t\t\tlet response: GenerateResponse | undefined;\n\t\t\t\tfor await (const chunk of config.provider.generateStream({\n\t\t\t\t\tmessages: working,\n\t\t\t\t\ttools: registry.specs(),\n\t\t\t\t\tmodel: config.model,\n\t\t\t\t\tsignal: opts?.signal,\n\t\t\t\t})) {\n\t\t\t\t\tif (chunk.type === \"text\") {\n\t\t\t\t\t\tturnText += chunk.text;\n\t\t\t\t\t\tyield { type: \"text\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"reasoning\" && modelCaps().supportsReasoning) {\n\t\t\t\t\t\tturnReasoning += chunk.text;\n\t\t\t\t\t\tyield { type: \"reasoning\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"done\") {\n\t\t\t\t\t\tresponse = chunk.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (turnText) lastText = turnText;\n\n\t\t\t\tconst toolCalls = response?.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\t// Final answer reached. If the model ends without text but already\n\t\t\t\t\t// produced a successful tool result, surface that instead of blank.\n\t\t\t\t\tfinalText = response?.text || turnText || lastToolText;\n\t\t\t\t\tfinalReasoning = response?.reasoning || turnReasoning;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Record the assistant's tool-call turn (preserving any reasoning blob),\n\t\t\t\t// then execute each requested tool and feed results back for self-correction.\n\t\t\t\tworking.push({\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tparts: turnText ? [{ type: \"text\", text: turnText }] : [],\n\t\t\t\t\ttoolCalls,\n\t\t\t\t\t...(response?.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t\t\t});\n\t\t\t\tfor (const call of toolCalls) {\n\t\t\t\t\tconst result = await registry.invoke(call.name, call.arguments, config.toolTimeoutMs);\n\t\t\t\t\tconst payload = result.error\n\t\t\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\t\t\tif (!result.error) lastToolText = payload;\n\t\t\t\t\tworking.push({\n\t\t\t\t\t\trole: \"tool\",\n\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\ttoolCallId: call.id,\n\t\t\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst error = e instanceof ProviderError ? e : new ProviderError((e as Error).message, \"transient\");\n\t\t\tyield {\n\t\t\t\ttype: \"done\",\n\t\t\t\tresult: { output: finalText, status: \"incomplete\", partial: true, error, thread },\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\n\t\tif (finalText) thread.add({ role: \"assistant\", parts: [{ type: \"text\", text: finalText }] });\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresult: {\n\t\t\t\toutput: finalText,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? finalReasoning || undefined : undefined,\n\t\t\t\tstatus: \"completed\",\n\t\t\t\tpartial: false,\n\t\t\t\tthread,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn { name: config.name, run, runStream };\n}\n\nexport type { ContentPart };\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkIIANZWIQ_cjs = require('../chunk-IIANZWIQ.cjs');
4
- require('../chunk-4RGMZII7.cjs');
3
+ var chunkJ2YO7BBV_cjs = require('../chunk-J2YO7BBV.cjs');
4
+ require('../chunk-YKSNVWGX.cjs');
5
5
  require('../chunk-WSMYH2IN.cjs');
6
6
  require('../chunk-TAMJ5HSR.cjs');
7
7
  require('../chunk-FSDMBWQV.cjs');
@@ -13,7 +13,7 @@ require('../chunk-IJASUMIQ.cjs');
13
13
 
14
14
  Object.defineProperty(exports, "loadAgentDefinition", {
15
15
  enumerable: true,
16
- get: function () { return chunkIIANZWIQ_cjs.loadAgentDefinition; }
16
+ get: function () { return chunkJ2YO7BBV_cjs.loadAgentDefinition; }
17
17
  });
18
18
  //# sourceMappingURL=index.cjs.map
19
19
  //# sourceMappingURL=index.cjs.map
@@ -1,5 +1,5 @@
1
- export { loadAgentDefinition } from '../chunk-7S75TBCI.js';
2
- import '../chunk-YSJG2MHD.js';
1
+ export { loadAgentDefinition } from '../chunk-DZFJ5MIF.js';
2
+ import '../chunk-IEX6XUZV.js';
3
3
  import '../chunk-YCBDEEAV.js';
4
4
  import '../chunk-HGEPXJDG.js';
5
5
  import '../chunk-7ZXUIHLH.js';
package/dist/index.cjs CHANGED
@@ -3,14 +3,14 @@
3
3
  var chunkIU3LS5FC_cjs = require('./chunk-IU3LS5FC.cjs');
4
4
  var chunkRZP2ZUUX_cjs = require('./chunk-RZP2ZUUX.cjs');
5
5
  require('./chunk-5M6ER4ZX.cjs');
6
- var chunkIIANZWIQ_cjs = require('./chunk-IIANZWIQ.cjs');
7
- var chunk4RGMZII7_cjs = require('./chunk-4RGMZII7.cjs');
6
+ var chunkJ2YO7BBV_cjs = require('./chunk-J2YO7BBV.cjs');
7
+ var chunkYKSNVWGX_cjs = require('./chunk-YKSNVWGX.cjs');
8
8
  var chunkWSMYH2IN_cjs = require('./chunk-WSMYH2IN.cjs');
9
9
  var chunkTAMJ5HSR_cjs = require('./chunk-TAMJ5HSR.cjs');
10
10
  var chunkU3ULJMNH_cjs = require('./chunk-U3ULJMNH.cjs');
11
- var chunkV6O6SYAN_cjs = require('./chunk-V6O6SYAN.cjs');
12
11
  var chunkKEI3EALJ_cjs = require('./chunk-KEI3EALJ.cjs');
13
12
  var chunkFSDMBWQV_cjs = require('./chunk-FSDMBWQV.cjs');
13
+ var chunkV6O6SYAN_cjs = require('./chunk-V6O6SYAN.cjs');
14
14
  var chunk5KC6X2T5_cjs = require('./chunk-5KC6X2T5.cjs');
15
15
  var chunkI55OVD23_cjs = require('./chunk-I55OVD23.cjs');
16
16
  var chunkJLPLGU7O_cjs = require('./chunk-JLPLGU7O.cjs');
@@ -66,19 +66,19 @@ Object.defineProperty(exports, "stepSequential", {
66
66
  });
67
67
  Object.defineProperty(exports, "loadAgentDefinition", {
68
68
  enumerable: true,
69
- get: function () { return chunkIIANZWIQ_cjs.loadAgentDefinition; }
69
+ get: function () { return chunkJ2YO7BBV_cjs.loadAgentDefinition; }
70
70
  });
71
71
  Object.defineProperty(exports, "buildMessages", {
72
72
  enumerable: true,
73
- get: function () { return chunk4RGMZII7_cjs.buildMessages; }
73
+ get: function () { return chunkYKSNVWGX_cjs.buildMessages; }
74
74
  });
75
75
  Object.defineProperty(exports, "createAgent", {
76
76
  enumerable: true,
77
- get: function () { return chunk4RGMZII7_cjs.createAgent; }
77
+ get: function () { return chunkYKSNVWGX_cjs.createAgent; }
78
78
  });
79
79
  Object.defineProperty(exports, "runLoop", {
80
80
  enumerable: true,
81
- get: function () { return chunk4RGMZII7_cjs.runLoop; }
81
+ get: function () { return chunkYKSNVWGX_cjs.runLoop; }
82
82
  });
83
83
  Object.defineProperty(exports, "SkillIndex", {
84
84
  enumerable: true,
@@ -112,6 +112,14 @@ Object.defineProperty(exports, "mcpToolToTool", {
112
112
  enumerable: true,
113
113
  get: function () { return chunkU3ULJMNH_cjs.mcpToolToTool; }
114
114
  });
115
+ Object.defineProperty(exports, "useMiddleware", {
116
+ enumerable: true,
117
+ get: function () { return chunkKEI3EALJ_cjs.useMiddleware; }
118
+ });
119
+ Object.defineProperty(exports, "composeMiddleware", {
120
+ enumerable: true,
121
+ get: function () { return chunkFSDMBWQV_cjs.composeMiddleware; }
122
+ });
115
123
  Object.defineProperty(exports, "configureObservability", {
116
124
  enumerable: true,
117
125
  get: function () { return chunkV6O6SYAN_cjs.configureObservability; }
@@ -128,14 +136,6 @@ Object.defineProperty(exports, "withSpan", {
128
136
  enumerable: true,
129
137
  get: function () { return chunkV6O6SYAN_cjs.withSpan; }
130
138
  });
131
- Object.defineProperty(exports, "useMiddleware", {
132
- enumerable: true,
133
- get: function () { return chunkKEI3EALJ_cjs.useMiddleware; }
134
- });
135
- Object.defineProperty(exports, "composeMiddleware", {
136
- enumerable: true,
137
- get: function () { return chunkFSDMBWQV_cjs.composeMiddleware; }
138
- });
139
139
  Object.defineProperty(exports, "ThreadPersistence", {
140
140
  enumerable: true,
141
141
  get: function () { return chunk5KC6X2T5_cjs.ThreadPersistence; }
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  export { defineTool } from './chunk-RZ43WNHR.js';
2
2
  export { CHECKPOINT_VERSION, createCheckpoint, createWorkflow, restoreCheckpoint, runBounded, serializeCheckpoint, stepConcurrent, stepGroup, stepHandoff, stepSequential } from './chunk-T2GHJ5R4.js';
3
3
  import './chunk-MCLVWCOB.js';
4
- export { loadAgentDefinition } from './chunk-7S75TBCI.js';
5
- export { buildMessages, createAgent, runLoop } from './chunk-YSJG2MHD.js';
4
+ export { loadAgentDefinition } from './chunk-DZFJ5MIF.js';
5
+ export { buildMessages, createAgent, runLoop } from './chunk-IEX6XUZV.js';
6
6
  export { SkillIndex, defineSkill, loadSource } from './chunk-YCBDEEAV.js';
7
7
  export { ToolRegistry, namespacedName, validateArgs } from './chunk-HGEPXJDG.js';
8
8
  export { connectMCP, mcpToolToTool } from './chunk-QYG4HLIC.js';
9
- export { configureObservability, isObservabilityEnabled, resetObservability, withSpan } from './chunk-5PDJOBTD.js';
10
9
  export { useMiddleware } from './chunk-IUKD54F7.js';
11
10
  export { composeMiddleware } from './chunk-7ZXUIHLH.js';
11
+ export { configureObservability, isObservabilityEnabled, resetObservability, withSpan } from './chunk-5PDJOBTD.js';
12
12
  export { ThreadPersistence, createBrowserStore, createMemoryStore } from './chunk-3KU76DCP.js';
13
13
  export { Thread, estimateTokens, hasImage, messageText, textMessage } from './chunk-LC54DGGR.js';
14
14
  export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry } from './chunk-YVJGF4HQ.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-framework-js",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Modular, tree-shakeable JavaScript/TypeScript agent framework for no-backend deployments (browser, edge, Node). Agents, tools, MCP, skills, multi-agent workflows, middleware, persistence, and OpenTelemetry observability.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/agents/loop.ts","../src/agents/agent.ts"],"names":["textMessage","ToolRegistry","SkillIndex","hasImage","ProviderError","composeMiddleware","Thread"],"mappings":"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","file":"chunk-4RGMZII7.cjs","sourcesContent":["/**\n * The agent run loop: drives provider calls, executes requested tool calls,\n * feeds typed results (including errors, for self-correction) back to the model,\n * and stops on a final answer, the iteration cap, or an abort. (FR-011a, FR-012b)\n *\n * @packageDocumentation\n */\n\nimport type { Message } from \"../core/types.js\";\nimport { textMessage } from \"../core/types.js\";\nimport type { GenerateRequest, GenerateResponse } from \"../providers/provider.js\";\nimport type { ToolRegistry } from \"../tools/registry.js\";\n\n/** Outcome status of a run. */\nexport type RunStatus = \"completed\" | \"failed\" | \"incomplete\" | \"limit-exceeded\";\n\n/** A function that produces a model response (optionally through middleware). */\nexport type GenerateFn = (req: GenerateRequest) => Promise<GenerateResponse>;\n\n/** Settings controlling the loop. */\nexport interface LoopOptions {\n\t/** Maximum iterations; -1 means unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** Result of running the loop. */\nexport interface LoopResult {\n\tmessages: Message[];\n\tfinal: GenerateResponse;\n\tstatus: RunStatus;\n}\n\n/**\n * Execute the tool-call loop against a generate function and tool registry.\n *\n * @param generate - Produces a model response (typically the middleware pipeline).\n * @param registry - Tools available to the agent (may be empty).\n * @param messages - Initial conversation (system + user, etc.).\n * @param options - Loop tuning.\n */\nexport async function runLoop(\n\tgenerate: GenerateFn,\n\tregistry: ToolRegistry,\n\tmessages: Message[],\n\toptions?: LoopOptions,\n): Promise<LoopResult> {\n\tconst maxIterations = options?.maxIterations ?? 10;\n\tconst working = [...messages];\n\tlet iteration = 0;\n\n\tfor (; ;) {\n\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\treturn {\n\t\t\t\tmessages: working,\n\t\t\t\tfinal: { text: \"\" },\n\t\t\t\tstatus: \"limit-exceeded\",\n\t\t\t};\n\t\t}\n\t\titeration++;\n\n\t\tconst specs = registry.specs();\n\t\tconst response = await generate({\n\t\t\tmessages: working,\n\t\t\ttools: specs.length > 0 ? specs : undefined,\n\t\t\tsignal: options?.signal,\n\t\t});\n\n\t\tif (!response.toolCalls || response.toolCalls.length === 0) {\n\t\t\treturn { messages: working, final: response, status: \"completed\" };\n\t\t}\n\n\t\t// Record the assistant's tool-call turn, preserving the tool calls (so strict\n\t\t// providers can pair each result with its call) and any opaque reasoning blob\n\t\t// (for thinking continuity across turns).\n\t\tworking.push({\n\t\t\trole: \"assistant\",\n\t\t\tparts: response.text ? [{ type: \"text\", text: response.text }] : [],\n\t\t\ttoolCalls: response.toolCalls,\n\t\t\t...(response.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t});\n\n\t\t// Execute each requested tool and feed results (or typed errors) back.\n\t\tfor (const call of response.toolCalls) {\n\t\t\tconst result = await registry.invoke(call.name, call.arguments, options?.toolTimeoutMs);\n\t\t\tconst payload = result.error\n\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\tworking.push({\n\t\t\t\trole: \"tool\",\n\t\t\t\tname: call.name,\n\t\t\t\ttoolCallId: call.id,\n\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t});\n\t\t}\n\t}\n}\n\n/** Build the initial message list from instructions + input. */\nexport function buildMessages(instructions: string, input: Message[]): Message[] {\n\treturn [textMessage(\"system\", instructions), ...input];\n}\n","/**\n * The agent: a configured actor that runs against a provider, optionally using\n * tools and skills, with streaming, reasoning output, multimodal input gating,\n * conversation threads with compaction, and a middleware pipeline.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart } from \"../core/types.js\";\nimport { hasImage, textMessage } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type { Provider, GenerateResponse, GenerateRequest } from \"../providers/provider.js\";\nimport { ToolRegistry } from \"../tools/registry.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { SkillIndex } from \"../skills/index.js\";\nimport type { Middleware, MiddlewareContext } from \"../middleware/middleware.js\";\nimport { composeMiddleware } from \"../middleware/middleware.js\";\nimport { Thread, type ThreadOptions } from \"./thread.js\";\nimport { runLoop, type RunStatus } from \"./loop.js\";\n\n/** Configuration for {@link createAgent}. */\nexport interface AgentConfig {\n\tname: string;\n\tinstructions: string;\n\tprovider: Provider;\n\t/** Which of the provider's models to use; defaults to the provider's default model. */\n\tmodel?: string;\n\ttools?: Tool[];\n\tskills?: Skill[];\n\t/** Max tool-call iterations per run; -1 = unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Compaction threshold as a fraction of maxInputTokens. Default 0.9. (FR-004a) */\n\tcompactionThreshold?: number;\n\t/** Optional override model for compaction summaries. (FR-004b) */\n\tcompactionModel?: Provider;\n\t/** Middleware applied around provider calls. (FR-023) */\n\tmiddleware?: Middleware[];\n}\n\n/** Options for a single run. */\nexport interface RunOptions {\n\t/** Continue an existing conversation. (FR-004) */\n\tthread?: Thread;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** The result of a non-streaming run. */\nexport interface RunResult {\n\toutput: string;\n\t/** Reasoning content — only for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\tstatus: RunStatus;\n\t/** True when the run was interrupted before completing. (FR-003b) */\n\tpartial: boolean;\n\terror?: ProviderError;\n\t/** The thread used/updated by this run. */\n\tthread: Thread;\n}\n\n/** Streamed run chunk. */\nexport type RunChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"done\"; result: RunResult };\n\n/** Agent input: plain text or structured (multimodal) messages. (FR-002) */\nexport type AgentInput = string | Message | Message[];\n\n/** A runnable agent. */\nexport interface Agent {\n\treadonly name: string;\n\trun(input: AgentInput, opts?: RunOptions): Promise<RunResult>;\n\trunStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk>;\n}\n\nfunction normalizeInput(input: AgentInput): Message[] {\n\tif (typeof input === \"string\") return [textMessage(\"user\", input)];\n\treturn Array.isArray(input) ? input : [input];\n}\n\nfunction promptText(messages: Message[]): string {\n\treturn messages\n\t\t.flatMap((m) => m.parts)\n\t\t.filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n\t\t.map((p) => p.text)\n\t\t.join(\" \");\n}\n\n/**\n * Create an agent.\n *\n * @example\n * ```ts\n * const agent = createAgent({ name: \"Helper\", instructions: \"Be concise.\", provider });\n * const res = await agent.run(\"Say hello.\");\n * console.log(res.status, res.output);\n * ```\n */\nexport function createAgent(config: AgentConfig): Agent {\n\tconst registry = new ToolRegistry(config.tools ?? []);\n\tconst skillIndex = new SkillIndex(config.skills ?? []);\n\tconst middleware = config.middleware ?? [];\n\t/** Capabilities of the model this agent uses (selected from the provider). */\n\tconst modelCaps = () => config.provider.model(config.model);\n\n\tfunction gateVision(messages: Message[]): void {\n\t\tif (!modelCaps().supportsVision && messages.some(hasImage)) {\n\t\t\tthrow new ProviderError(\n\t\t\t\t\"Image input was provided but the configured model does not support vision\",\n\t\t\t\t\"client\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync function injectSkills(userMessages: Message[]): Promise<Message[]> {\n\t\tif ((config.skills ?? []).length === 0) return userMessages;\n\t\tconst selected = skillIndex.select(promptText(userMessages));\n\t\tif (selected.length === 0) return userMessages;\n\t\tconst contents = await Promise.all(selected.map((s) => skillIndex.load(s)));\n\t\tconst skillBlock = textMessage(\n\t\t\t\"system\",\n\t\t\t`Relevant skill knowledge:\\n${contents.join(\"\\n\\n\")}`,\n\t\t);\n\t\treturn [skillBlock, ...userMessages];\n\t}\n\n\tasync function callProvider(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tconst ctx: MiddlewareContext = {\n\t\t\tagentName: config.name,\n\t\t\trequest: { ...req, model: req.model ?? config.model },\n\t\t};\n\t\tconst pipeline = composeMiddleware(middleware, (c) => config.provider.generate(c.request));\n\t\treturn pipeline(ctx);\n\t}\n\n\tasync function prepare(input: AgentInput, opts?: RunOptions): Promise<Thread> {\n\t\tconst userMessages = normalizeInput(input);\n\t\tgateVision(userMessages);\n\t\tconst thread =\n\t\t\topts?.thread ??\n\t\t\tnew Thread(undefined, [textMessage(\"system\", config.instructions)]);\n\t\tconst withSkills = await injectSkills(userMessages);\n\t\tfor (const m of withSkills) thread.add(m);\n\t\tawait thread.maybeCompact(config.provider, {\n\t\t\tcompactionThreshold: config.compactionThreshold,\n\t\t\tcompactionModel: config.compactionModel,\n\t\t\tmodelCapabilities: modelCaps(),\n\t\t} satisfies ThreadOptions);\n\t\treturn thread;\n\t}\n\n\tasync function run(input: AgentInput, opts?: RunOptions): Promise<RunResult> {\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\ttry {\n\t\t\tconst loop = await runLoop(callProvider, registry, thread.messages, {\n\t\t\t\tmaxIterations: config.maxIterations,\n\t\t\t\ttoolTimeoutMs: config.toolTimeoutMs,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t});\n\t\t\tif (loop.final.text) {\n\t\t\t\tthread.add({ role: \"assistant\", parts: [{ type: \"text\", text: loop.final.text }] });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toutput: loop.final.text,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? loop.final.reasoning : undefined,\n\t\t\t\tstatus: loop.status,\n\t\t\t\tpartial: loop.status === \"incomplete\",\n\t\t\t\tthread,\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync function* runStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk> {\n\t\t// Streaming path: drives the same tool-call loop as the non-streaming `run`,\n\t\t// but streams the model's text/reasoning for each turn. Tool-call turns are\n\t\t// executed and their results fed back; the final (tool-free) turn's text is\n\t\t// the answer. (FR-011a, FR-012b)\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\tyield { type: \"done\", result: { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() } };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\tconst maxIterations = config.maxIterations ?? 10;\n\t\t// Working transcript the loop appends to (assistant tool-call turns + tool results).\n\t\tconst working: Message[] = [...thread.messages];\n\t\tlet finalText = \"\";\n\t\tlet finalReasoning = \"\";\n\t\tlet iteration = 0;\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tresult: { output: \"\", status: \"limit-exceeded\", partial: false, thread },\n\t\t\t\t\t};\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\titeration++;\n\n\t\t\t\t// Stream one provider turn, accumulating this turn's text/reasoning and\n\t\t\t\t// capturing the complete response (which carries any tool calls).\n\t\t\t\tlet turnText = \"\";\n\t\t\t\tlet turnReasoning = \"\";\n\t\t\t\tlet response: GenerateResponse | undefined;\n\t\t\t\tfor await (const chunk of config.provider.generateStream({\n\t\t\t\t\tmessages: working,\n\t\t\t\t\ttools: registry.specs(),\n\t\t\t\t\tmodel: config.model,\n\t\t\t\t\tsignal: opts?.signal,\n\t\t\t\t})) {\n\t\t\t\t\tif (chunk.type === \"text\") {\n\t\t\t\t\t\tturnText += chunk.text;\n\t\t\t\t\t\tyield { type: \"text\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"reasoning\" && modelCaps().supportsReasoning) {\n\t\t\t\t\t\tturnReasoning += chunk.text;\n\t\t\t\t\t\tyield { type: \"reasoning\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"done\") {\n\t\t\t\t\t\tresponse = chunk.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst toolCalls = response?.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\t// Final answer reached.\n\t\t\t\t\tfinalText = response?.text || turnText;\n\t\t\t\t\tfinalReasoning = response?.reasoning || turnReasoning;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Record the assistant's tool-call turn (preserving any reasoning blob),\n\t\t\t\t// then execute each requested tool and feed results back for self-correction.\n\t\t\t\tworking.push({\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tparts: turnText ? [{ type: \"text\", text: turnText }] : [],\n\t\t\t\t\ttoolCalls,\n\t\t\t\t\t...(response?.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t\t\t});\n\t\t\t\tfor (const call of toolCalls) {\n\t\t\t\t\tconst result = await registry.invoke(call.name, call.arguments, config.toolTimeoutMs);\n\t\t\t\t\tconst payload = result.error\n\t\t\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\t\t\tworking.push({\n\t\t\t\t\t\trole: \"tool\",\n\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\ttoolCallId: call.id,\n\t\t\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst error = e instanceof ProviderError ? e : new ProviderError((e as Error).message, \"transient\");\n\t\t\tyield {\n\t\t\t\ttype: \"done\",\n\t\t\t\tresult: { output: finalText, status: \"incomplete\", partial: true, error, thread },\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\n\t\tif (finalText) thread.add({ role: \"assistant\", parts: [{ type: \"text\", text: finalText }] });\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresult: {\n\t\t\t\toutput: finalText,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? finalReasoning || undefined : undefined,\n\t\t\t\tstatus: \"completed\",\n\t\t\t\tpartial: false,\n\t\t\t\tthread,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn { name: config.name, run, runStream };\n}\n\nexport type { ContentPart };\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/agents/loop.ts","../src/agents/agent.ts"],"names":[],"mappings":"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","file":"chunk-YSJG2MHD.js","sourcesContent":["/**\n * The agent run loop: drives provider calls, executes requested tool calls,\n * feeds typed results (including errors, for self-correction) back to the model,\n * and stops on a final answer, the iteration cap, or an abort. (FR-011a, FR-012b)\n *\n * @packageDocumentation\n */\n\nimport type { Message } from \"../core/types.js\";\nimport { textMessage } from \"../core/types.js\";\nimport type { GenerateRequest, GenerateResponse } from \"../providers/provider.js\";\nimport type { ToolRegistry } from \"../tools/registry.js\";\n\n/** Outcome status of a run. */\nexport type RunStatus = \"completed\" | \"failed\" | \"incomplete\" | \"limit-exceeded\";\n\n/** A function that produces a model response (optionally through middleware). */\nexport type GenerateFn = (req: GenerateRequest) => Promise<GenerateResponse>;\n\n/** Settings controlling the loop. */\nexport interface LoopOptions {\n\t/** Maximum iterations; -1 means unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** Result of running the loop. */\nexport interface LoopResult {\n\tmessages: Message[];\n\tfinal: GenerateResponse;\n\tstatus: RunStatus;\n}\n\n/**\n * Execute the tool-call loop against a generate function and tool registry.\n *\n * @param generate - Produces a model response (typically the middleware pipeline).\n * @param registry - Tools available to the agent (may be empty).\n * @param messages - Initial conversation (system + user, etc.).\n * @param options - Loop tuning.\n */\nexport async function runLoop(\n\tgenerate: GenerateFn,\n\tregistry: ToolRegistry,\n\tmessages: Message[],\n\toptions?: LoopOptions,\n): Promise<LoopResult> {\n\tconst maxIterations = options?.maxIterations ?? 10;\n\tconst working = [...messages];\n\tlet iteration = 0;\n\n\tfor (; ;) {\n\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\treturn {\n\t\t\t\tmessages: working,\n\t\t\t\tfinal: { text: \"\" },\n\t\t\t\tstatus: \"limit-exceeded\",\n\t\t\t};\n\t\t}\n\t\titeration++;\n\n\t\tconst specs = registry.specs();\n\t\tconst response = await generate({\n\t\t\tmessages: working,\n\t\t\ttools: specs.length > 0 ? specs : undefined,\n\t\t\tsignal: options?.signal,\n\t\t});\n\n\t\tif (!response.toolCalls || response.toolCalls.length === 0) {\n\t\t\treturn { messages: working, final: response, status: \"completed\" };\n\t\t}\n\n\t\t// Record the assistant's tool-call turn, preserving the tool calls (so strict\n\t\t// providers can pair each result with its call) and any opaque reasoning blob\n\t\t// (for thinking continuity across turns).\n\t\tworking.push({\n\t\t\trole: \"assistant\",\n\t\t\tparts: response.text ? [{ type: \"text\", text: response.text }] : [],\n\t\t\ttoolCalls: response.toolCalls,\n\t\t\t...(response.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t});\n\n\t\t// Execute each requested tool and feed results (or typed errors) back.\n\t\tfor (const call of response.toolCalls) {\n\t\t\tconst result = await registry.invoke(call.name, call.arguments, options?.toolTimeoutMs);\n\t\t\tconst payload = result.error\n\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\tworking.push({\n\t\t\t\trole: \"tool\",\n\t\t\t\tname: call.name,\n\t\t\t\ttoolCallId: call.id,\n\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t});\n\t\t}\n\t}\n}\n\n/** Build the initial message list from instructions + input. */\nexport function buildMessages(instructions: string, input: Message[]): Message[] {\n\treturn [textMessage(\"system\", instructions), ...input];\n}\n","/**\n * The agent: a configured actor that runs against a provider, optionally using\n * tools and skills, with streaming, reasoning output, multimodal input gating,\n * conversation threads with compaction, and a middleware pipeline.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart } from \"../core/types.js\";\nimport { hasImage, textMessage } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type { Provider, GenerateResponse, GenerateRequest } from \"../providers/provider.js\";\nimport { ToolRegistry } from \"../tools/registry.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { SkillIndex } from \"../skills/index.js\";\nimport type { Middleware, MiddlewareContext } from \"../middleware/middleware.js\";\nimport { composeMiddleware } from \"../middleware/middleware.js\";\nimport { Thread, type ThreadOptions } from \"./thread.js\";\nimport { runLoop, type RunStatus } from \"./loop.js\";\n\n/** Configuration for {@link createAgent}. */\nexport interface AgentConfig {\n\tname: string;\n\tinstructions: string;\n\tprovider: Provider;\n\t/** Which of the provider's models to use; defaults to the provider's default model. */\n\tmodel?: string;\n\ttools?: Tool[];\n\tskills?: Skill[];\n\t/** Max tool-call iterations per run; -1 = unlimited. Default 10. (FR-012b) */\n\tmaxIterations?: number;\n\t/** Per-tool-call timeout in ms. (FR-012c) */\n\ttoolTimeoutMs?: number;\n\t/** Compaction threshold as a fraction of maxInputTokens. Default 0.9. (FR-004a) */\n\tcompactionThreshold?: number;\n\t/** Optional override model for compaction summaries. (FR-004b) */\n\tcompactionModel?: Provider;\n\t/** Middleware applied around provider calls. (FR-023) */\n\tmiddleware?: Middleware[];\n}\n\n/** Options for a single run. */\nexport interface RunOptions {\n\t/** Continue an existing conversation. (FR-004) */\n\tthread?: Thread;\n\t/** Abort signal. */\n\tsignal?: AbortSignal;\n}\n\n/** The result of a non-streaming run. */\nexport interface RunResult {\n\toutput: string;\n\t/** Reasoning content — only for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\tstatus: RunStatus;\n\t/** True when the run was interrupted before completing. (FR-003b) */\n\tpartial: boolean;\n\terror?: ProviderError;\n\t/** The thread used/updated by this run. */\n\tthread: Thread;\n}\n\n/** Streamed run chunk. */\nexport type RunChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"done\"; result: RunResult };\n\n/** Agent input: plain text or structured (multimodal) messages. (FR-002) */\nexport type AgentInput = string | Message | Message[];\n\n/** A runnable agent. */\nexport interface Agent {\n\treadonly name: string;\n\trun(input: AgentInput, opts?: RunOptions): Promise<RunResult>;\n\trunStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk>;\n}\n\nfunction normalizeInput(input: AgentInput): Message[] {\n\tif (typeof input === \"string\") return [textMessage(\"user\", input)];\n\treturn Array.isArray(input) ? input : [input];\n}\n\nfunction promptText(messages: Message[]): string {\n\treturn messages\n\t\t.flatMap((m) => m.parts)\n\t\t.filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n\t\t.map((p) => p.text)\n\t\t.join(\" \");\n}\n\n/**\n * Create an agent.\n *\n * @example\n * ```ts\n * const agent = createAgent({ name: \"Helper\", instructions: \"Be concise.\", provider });\n * const res = await agent.run(\"Say hello.\");\n * console.log(res.status, res.output);\n * ```\n */\nexport function createAgent(config: AgentConfig): Agent {\n\tconst registry = new ToolRegistry(config.tools ?? []);\n\tconst skillIndex = new SkillIndex(config.skills ?? []);\n\tconst middleware = config.middleware ?? [];\n\t/** Capabilities of the model this agent uses (selected from the provider). */\n\tconst modelCaps = () => config.provider.model(config.model);\n\n\tfunction gateVision(messages: Message[]): void {\n\t\tif (!modelCaps().supportsVision && messages.some(hasImage)) {\n\t\t\tthrow new ProviderError(\n\t\t\t\t\"Image input was provided but the configured model does not support vision\",\n\t\t\t\t\"client\",\n\t\t\t);\n\t\t}\n\t}\n\n\tasync function injectSkills(userMessages: Message[]): Promise<Message[]> {\n\t\tif ((config.skills ?? []).length === 0) return userMessages;\n\t\tconst selected = skillIndex.select(promptText(userMessages));\n\t\tif (selected.length === 0) return userMessages;\n\t\tconst contents = await Promise.all(selected.map((s) => skillIndex.load(s)));\n\t\tconst skillBlock = textMessage(\n\t\t\t\"system\",\n\t\t\t`Relevant skill knowledge:\\n${contents.join(\"\\n\\n\")}`,\n\t\t);\n\t\treturn [skillBlock, ...userMessages];\n\t}\n\n\tasync function callProvider(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tconst ctx: MiddlewareContext = {\n\t\t\tagentName: config.name,\n\t\t\trequest: { ...req, model: req.model ?? config.model },\n\t\t};\n\t\tconst pipeline = composeMiddleware(middleware, (c) => config.provider.generate(c.request));\n\t\treturn pipeline(ctx);\n\t}\n\n\tasync function prepare(input: AgentInput, opts?: RunOptions): Promise<Thread> {\n\t\tconst userMessages = normalizeInput(input);\n\t\tgateVision(userMessages);\n\t\tconst thread =\n\t\t\topts?.thread ??\n\t\t\tnew Thread(undefined, [textMessage(\"system\", config.instructions)]);\n\t\tconst withSkills = await injectSkills(userMessages);\n\t\tfor (const m of withSkills) thread.add(m);\n\t\tawait thread.maybeCompact(config.provider, {\n\t\t\tcompactionThreshold: config.compactionThreshold,\n\t\t\tcompactionModel: config.compactionModel,\n\t\t\tmodelCapabilities: modelCaps(),\n\t\t} satisfies ThreadOptions);\n\t\treturn thread;\n\t}\n\n\tasync function run(input: AgentInput, opts?: RunOptions): Promise<RunResult> {\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\ttry {\n\t\t\tconst loop = await runLoop(callProvider, registry, thread.messages, {\n\t\t\t\tmaxIterations: config.maxIterations,\n\t\t\t\ttoolTimeoutMs: config.toolTimeoutMs,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t});\n\t\t\tif (loop.final.text) {\n\t\t\t\tthread.add({ role: \"assistant\", parts: [{ type: \"text\", text: loop.final.text }] });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toutput: loop.final.text,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? loop.final.reasoning : undefined,\n\t\t\t\tstatus: loop.status,\n\t\t\t\tpartial: loop.status === \"incomplete\",\n\t\t\t\tthread,\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\treturn { output: \"\", status: \"failed\", partial: false, error: e, thread };\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync function* runStream(input: AgentInput, opts?: RunOptions): AsyncIterable<RunChunk> {\n\t\t// Streaming path: drives the same tool-call loop as the non-streaming `run`,\n\t\t// but streams the model's text/reasoning for each turn. Tool-call turns are\n\t\t// executed and their results fed back; the final (tool-free) turn's text is\n\t\t// the answer. (FR-011a, FR-012b)\n\t\tlet thread: Thread;\n\t\ttry {\n\t\t\tthread = await prepare(input, opts);\n\t\t} catch (e) {\n\t\t\tif (e instanceof ProviderError) {\n\t\t\t\tyield { type: \"done\", result: { output: \"\", status: \"failed\", partial: false, error: e, thread: opts?.thread ?? new Thread() } };\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\n\t\tconst maxIterations = config.maxIterations ?? 10;\n\t\t// Working transcript the loop appends to (assistant tool-call turns + tool results).\n\t\tconst working: Message[] = [...thread.messages];\n\t\tlet finalText = \"\";\n\t\tlet finalReasoning = \"\";\n\t\tlet iteration = 0;\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (maxIterations !== -1 && iteration >= maxIterations) {\n\t\t\t\t\tyield {\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tresult: { output: \"\", status: \"limit-exceeded\", partial: false, thread },\n\t\t\t\t\t};\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\titeration++;\n\n\t\t\t\t// Stream one provider turn, accumulating this turn's text/reasoning and\n\t\t\t\t// capturing the complete response (which carries any tool calls).\n\t\t\t\tlet turnText = \"\";\n\t\t\t\tlet turnReasoning = \"\";\n\t\t\t\tlet response: GenerateResponse | undefined;\n\t\t\t\tfor await (const chunk of config.provider.generateStream({\n\t\t\t\t\tmessages: working,\n\t\t\t\t\ttools: registry.specs(),\n\t\t\t\t\tmodel: config.model,\n\t\t\t\t\tsignal: opts?.signal,\n\t\t\t\t})) {\n\t\t\t\t\tif (chunk.type === \"text\") {\n\t\t\t\t\t\tturnText += chunk.text;\n\t\t\t\t\t\tyield { type: \"text\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"reasoning\" && modelCaps().supportsReasoning) {\n\t\t\t\t\t\tturnReasoning += chunk.text;\n\t\t\t\t\t\tyield { type: \"reasoning\", text: chunk.text };\n\t\t\t\t\t} else if (chunk.type === \"done\") {\n\t\t\t\t\t\tresponse = chunk.response;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst toolCalls = response?.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\t// Final answer reached.\n\t\t\t\t\tfinalText = response?.text || turnText;\n\t\t\t\t\tfinalReasoning = response?.reasoning || turnReasoning;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Record the assistant's tool-call turn (preserving any reasoning blob),\n\t\t\t\t// then execute each requested tool and feed results back for self-correction.\n\t\t\t\tworking.push({\n\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\tparts: turnText ? [{ type: \"text\", text: turnText }] : [],\n\t\t\t\t\ttoolCalls,\n\t\t\t\t\t...(response?.reasoningOpaque ? { reasoningOpaque: response.reasoningOpaque } : {}),\n\t\t\t\t});\n\t\t\t\tfor (const call of toolCalls) {\n\t\t\t\t\tconst result = await registry.invoke(call.name, call.arguments, config.toolTimeoutMs);\n\t\t\t\t\tconst payload = result.error\n\t\t\t\t\t\t? `ERROR (${result.error.reason}): ${result.error.message}`\n\t\t\t\t\t\t: JSON.stringify(result.value ?? null);\n\t\t\t\t\tworking.push({\n\t\t\t\t\t\trole: \"tool\",\n\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\ttoolCallId: call.id,\n\t\t\t\t\t\tparts: [{ type: \"text\", text: payload }],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst error = e instanceof ProviderError ? e : new ProviderError((e as Error).message, \"transient\");\n\t\t\tyield {\n\t\t\t\ttype: \"done\",\n\t\t\t\tresult: { output: finalText, status: \"incomplete\", partial: true, error, thread },\n\t\t\t};\n\t\t\treturn;\n\t\t}\n\n\t\tif (finalText) thread.add({ role: \"assistant\", parts: [{ type: \"text\", text: finalText }] });\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresult: {\n\t\t\t\toutput: finalText,\n\t\t\t\treasoning: modelCaps().supportsReasoning ? finalReasoning || undefined : undefined,\n\t\t\t\tstatus: \"completed\",\n\t\t\t\tpartial: false,\n\t\t\t\tthread,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn { name: config.name, run, runStream };\n}\n\nexport type { ContentPart };\n"]}