agent-framework-js 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +45 -0
  3. package/dist/agents/index.cjs +7 -7
  4. package/dist/agents/index.d.cts +4 -4
  5. package/dist/agents/index.d.ts +4 -4
  6. package/dist/agents/index.js +2 -2
  7. package/dist/{chunk-YKZJRE32.cjs → chunk-245NZAGV.cjs} +4 -4
  8. package/dist/{chunk-YKZJRE32.cjs.map → chunk-245NZAGV.cjs.map} +1 -1
  9. package/dist/{chunk-UVWQWOLO.js → chunk-7M3EAGCA.js} +41 -8
  10. package/dist/chunk-7M3EAGCA.js.map +1 -0
  11. package/dist/{chunk-XPXTXOYQ.js → chunk-E4VTVUYU.js} +4 -3
  12. package/dist/chunk-E4VTVUYU.js.map +1 -0
  13. package/dist/{chunk-V472N2PK.js → chunk-IGIFX6QO.js} +3 -3
  14. package/dist/{chunk-V472N2PK.js.map → chunk-IGIFX6QO.js.map} +1 -1
  15. package/dist/{chunk-LMN75W3W.cjs → chunk-ILBKDEEL.cjs} +4 -3
  16. package/dist/chunk-ILBKDEEL.cjs.map +1 -0
  17. package/dist/{chunk-YBFLWRO5.cjs → chunk-NURRGYIU.cjs} +18 -15
  18. package/dist/chunk-NURRGYIU.cjs.map +1 -0
  19. package/dist/{chunk-VLSVL5N2.js → chunk-S5776DOL.js} +3 -3
  20. package/dist/{chunk-VLSVL5N2.js.map → chunk-S5776DOL.js.map} +1 -1
  21. package/dist/{chunk-TLACSVEZ.cjs → chunk-U64OEHG6.cjs} +40 -6
  22. package/dist/chunk-U64OEHG6.cjs.map +1 -0
  23. package/dist/{chunk-QJ5XHA6S.cjs → chunk-UIXNKPLQ.cjs} +4 -4
  24. package/dist/{chunk-QJ5XHA6S.cjs.map → chunk-UIXNKPLQ.cjs.map} +1 -1
  25. package/dist/{chunk-RD5YUB2E.js → chunk-WEKU7735.js} +12 -9
  26. package/dist/chunk-WEKU7735.js.map +1 -0
  27. package/dist/declarative/index.cjs +4 -4
  28. package/dist/declarative/index.d.cts +4 -4
  29. package/dist/declarative/index.d.ts +4 -4
  30. package/dist/declarative/index.js +3 -3
  31. package/dist/{index-DdYZeNIu.d.cts → index-5eIhfrC1.d.cts} +5 -3
  32. package/dist/{index-D7-znzrc.d.ts → index-Dog-CyOK.d.ts} +5 -3
  33. package/dist/index.cjs +34 -30
  34. package/dist/index.d.cts +4 -4
  35. package/dist/index.d.ts +4 -4
  36. package/dist/index.js +6 -6
  37. package/dist/middleware/index.d.cts +5 -5
  38. package/dist/middleware/index.d.ts +5 -5
  39. package/dist/persistence/index.cjs +5 -5
  40. package/dist/persistence/index.d.cts +2 -2
  41. package/dist/persistence/index.d.ts +2 -2
  42. package/dist/persistence/index.js +2 -2
  43. package/dist/{provider-osAtfZ7x.d.ts → provider-C_rgZvmX.d.ts} +47 -2
  44. package/dist/{provider-CMAymr1b.d.cts → provider-IJnfNhCX.d.cts} +47 -2
  45. package/dist/providers/index.cjs +9 -5
  46. package/dist/providers/index.d.cts +32 -13
  47. package/dist/providers/index.d.ts +32 -13
  48. package/dist/providers/index.js +1 -1
  49. package/dist/{registry-D4fThGiN.d.cts → registry-B-hicOxp.d.cts} +1 -1
  50. package/dist/{registry-CpO0yH5v.d.ts → registry-KMWN0p4Z.d.ts} +1 -1
  51. package/dist/{thread-CWVzTyti.d.ts → thread-COV135Ja.d.ts} +4 -2
  52. package/dist/{thread-Dfo9LLf7.d.cts → thread-D3zaGK1Y.d.cts} +4 -2
  53. package/dist/tools/index.d.cts +2 -2
  54. package/dist/tools/index.d.ts +2 -2
  55. package/dist/workflows/index.d.cts +4 -4
  56. package/dist/workflows/index.d.ts +4 -4
  57. package/package.json +4 -4
  58. package/AGENT_USAGE.md +0 -207
  59. package/dist/chunk-LMN75W3W.cjs.map +0 -1
  60. package/dist/chunk-RD5YUB2E.js.map +0 -1
  61. package/dist/chunk-TLACSVEZ.cjs.map +0 -1
  62. package/dist/chunk-UVWQWOLO.js.map +0 -1
  63. package/dist/chunk-XPXTXOYQ.js.map +0 -1
  64. package/dist/chunk-YBFLWRO5.cjs.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,69 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-06-16
11
+
12
+ ### Added
13
+
14
+ - **Multi-model providers**: providers can now be configured with multiple models via `models`
15
+ (with an optional `defaultModel`) — GitHub Copilot commonly exposes several, while
16
+ OpenAI-compatible endpoints stay single-model via the `capabilities` shorthand. Select a model
17
+ per request (`generate({ ..., model })`) or per agent (`createAgent({ ..., model })`). The
18
+ `Provider` interface gains `models` and `model(name?)`, and `resolveModels()` is exported.
19
+ Backward compatible: existing single-`capabilities` usage is unchanged.
20
+
21
+ ### Changed
22
+
23
+ - The agent-facing usage guide is now shipped as a loadable skill at
24
+ `.github/skills/agent-framework-usage/SKILL.md` (replacing the former `AGENT_USAGE.md`). All
25
+ references (copilot-instructions, CONTRIBUTING, constitution, package.json) were updated and the
26
+ README now points to the skill.
27
+
28
+ ## [0.1.2] - 2026-06-16
29
+
30
+ ### Changed
31
+
32
+ - Release pipeline switched to npm **trusted publishing (OIDC)** — token-free publishes
33
+ with provenance from GitHub Actions.
34
+
35
+ ## [0.1.1] - 2026-06-16
36
+
37
+ ### Added
38
+
39
+ - npm publish metadata: `repository`, `bugs`, `homepage`, `publishConfig` (public access,
40
+ provenance), and a `prepublishOnly` build/test guard.
41
+
42
+ ## [0.1.0] - 2026-06-16
43
+
44
+ ### Added
45
+
46
+ - Initial release of `agent-framework-js`, a modular, tree-shakeable agent framework for
47
+ no-backend deployments (browser, edge, Node).
48
+ - **Agents**: create/run, streaming, reasoning output, multimodal (text + image) input gating,
49
+ conversation threads with automatic compaction.
50
+ - **Providers**: GitHub Copilot and OpenAI-compatible (e.g. LM Studio) behind a pluggable
51
+ abstraction, caller-injected credentials, exponential-backoff retry.
52
+ - **Tools**: uniform JSON-Schema tool contract, argument validation, source namespacing,
53
+ per-tool enable/disable, per-call timeout, bounded tool-call loop with self-correction.
54
+ - **MCP**: remote (HTTP/SSE) transport everywhere and stdio in Node, adapted onto the tool
55
+ contract with runtime capability gating.
56
+ - **Skills**: progressive disclosure with a client-side keyword index.
57
+ - **Workflows**: sequential, concurrent, handoff, and group patterns; completion signal +
58
+ max-rounds cap; fail-soft/fail-fast policy; bounded concurrency; human-in-the-loop
59
+ yield/resume; fail-closed checkpoints.
60
+ - **Middleware**: request/response pipeline around provider calls.
61
+ - **Persistence**: pluggable store with in-memory and browser (localStorage/IndexedDB) adapters.
62
+ - **Observability**: OpenTelemetry spans with centralized secret redaction.
63
+ - **Declarative**: YAML/JSON agent definitions with format auto-detection.
64
+ - Dual ESM + CJS build with TypeScript types and deep-import subpaths for tree-shaking.
65
+
66
+ [Unreleased]: https://github.com/Varun-Patkar/agent-framework-js/compare/v0.1.2...HEAD
67
+ [0.1.2]: https://github.com/Varun-Patkar/agent-framework-js/compare/v0.1.1...v0.1.2
68
+ [0.1.1]: https://github.com/Varun-Patkar/agent-framework-js/releases/tag/v0.1.1
69
+ [0.1.0]: https://github.com/Varun-Patkar/agent-framework-js/tree/v0.1.1
package/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # agent-framework-js
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/agent-framework-js.svg)](https://www.npmjs.com/package/agent-framework-js)
4
+ [![CI](https://github.com/Varun-Patkar/agent-framework-js/actions/workflows/ci.yml/badge.svg)](https://github.com/Varun-Patkar/agent-framework-js/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/npm/l/agent-framework-js.svg)](LICENSE)
6
+ [![Types](https://img.shields.io/npm/types/agent-framework-js.svg)](https://www.npmjs.com/package/agent-framework-js)
7
+ [![Node](https://img.shields.io/node/v/agent-framework-js.svg)](https://www.npmjs.com/package/agent-framework-js)
8
+
3
9
  A modular, tree-shakeable JavaScript/TypeScript framework for building and orchestrating AI agents
4
10
  in **no-backend** deployments — browser, edge runtimes (e.g. Vercel without serverless functions),
5
11
  and Node. It mirrors the in-scope capability set of Microsoft Agent Framework: agents, code tools,
@@ -36,6 +42,36 @@ const res = await agent.run("Say hello.");
36
42
  console.log(res.status, res.output);
37
43
  ```
38
44
 
45
+ ### Multiple models (e.g. GitHub Copilot)
46
+
47
+ A provider can expose several models. Supply `models` (with an optional `defaultModel`), then pick
48
+ one per agent (`model`) or per request. OpenAI-compatible endpoints are usually single-model, so the
49
+ `capabilities` shorthand still works there.
50
+
51
+ ```ts
52
+ import { createAgent, createCopilotProvider } from "agent-framework-js";
53
+
54
+ const copilot = createCopilotProvider({
55
+ getCredential: () => myCopilotToken,
56
+ models: [
57
+ { model: "gpt-4o", maxInputTokens: 128000, maxOutputTokens: 16000, supportsVision: true },
58
+ { model: "o3-mini", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },
59
+ ],
60
+ defaultModel: "gpt-4o",
61
+ });
62
+
63
+ // Per agent — capabilities (vision/reasoning/context) follow the chosen model:
64
+ const reasoner = createAgent({
65
+ name: "Thinker",
66
+ instructions: "Reason.",
67
+ provider: copilot,
68
+ model: "o3-mini",
69
+ });
70
+
71
+ // Per request:
72
+ await copilot.generate({ messages, model: "o3-mini" });
73
+ ```
74
+
39
75
  Prefer **deep imports** for the smallest bundle: `agent-framework-js/agents`,
40
76
  `/providers`, `/tools`, `/mcp`, `/skills`, `/workflows`, `/middleware`, `/persistence`,
41
77
  `/observability`, `/declarative`.
@@ -94,6 +130,15 @@ npm run lint
94
130
  npm run typecheck
95
131
  ```
96
132
 
133
+ ## Agent usage guide
134
+
135
+ A complete, agent-facing usage guide is bundled as a skill at
136
+ [.github/skills/agent-framework-usage/SKILL.md](.github/skills/agent-framework-usage/SKILL.md). Any
137
+ AI coding agent working in this repository can load that skill to understand how to install,
138
+ configure, and use the entire public API (providers, agents, tools, MCP, skills, workflows,
139
+ persistence, observability, declarative agents, safeguards, and the typed error model). It is kept in
140
+ sync with the implemented surface.
141
+
97
142
  ## License
98
143
 
99
144
  MIT
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  require('../chunk-5M6ER4ZX.cjs');
4
- var chunkYBFLWRO5_cjs = require('../chunk-YBFLWRO5.cjs');
4
+ var chunkNURRGYIU_cjs = require('../chunk-NURRGYIU.cjs');
5
5
  require('../chunk-WSMYH2IN.cjs');
6
6
  require('../chunk-TAMJ5HSR.cjs');
7
7
  require('../chunk-FSDMBWQV.cjs');
8
- var chunkLMN75W3W_cjs = require('../chunk-LMN75W3W.cjs');
8
+ var chunkILBKDEEL_cjs = require('../chunk-ILBKDEEL.cjs');
9
9
  require('../chunk-MQ2XTH3S.cjs');
10
10
  require('../chunk-IJASUMIQ.cjs');
11
11
 
@@ -13,23 +13,23 @@ require('../chunk-IJASUMIQ.cjs');
13
13
 
14
14
  Object.defineProperty(exports, "buildMessages", {
15
15
  enumerable: true,
16
- get: function () { return chunkYBFLWRO5_cjs.buildMessages; }
16
+ get: function () { return chunkNURRGYIU_cjs.buildMessages; }
17
17
  });
18
18
  Object.defineProperty(exports, "createAgent", {
19
19
  enumerable: true,
20
- get: function () { return chunkYBFLWRO5_cjs.createAgent; }
20
+ get: function () { return chunkNURRGYIU_cjs.createAgent; }
21
21
  });
22
22
  Object.defineProperty(exports, "runLoop", {
23
23
  enumerable: true,
24
- get: function () { return chunkYBFLWRO5_cjs.runLoop; }
24
+ get: function () { return chunkNURRGYIU_cjs.runLoop; }
25
25
  });
26
26
  Object.defineProperty(exports, "Thread", {
27
27
  enumerable: true,
28
- get: function () { return chunkLMN75W3W_cjs.Thread; }
28
+ get: function () { return chunkILBKDEEL_cjs.Thread; }
29
29
  });
30
30
  Object.defineProperty(exports, "estimateTokens", {
31
31
  enumerable: true,
32
- get: function () { return chunkLMN75W3W_cjs.estimateTokens; }
32
+ get: function () { return chunkILBKDEEL_cjs.estimateTokens; }
33
33
  });
34
34
  //# sourceMappingURL=index.cjs.map
35
35
  //# sourceMappingURL=index.cjs.map
@@ -1,8 +1,8 @@
1
- export { A as Agent, a as AgentConfig, b as AgentInput, G as GenerateFn, L as LoopOptions, c as LoopResult, R as RunChunk, e as RunOptions, f as RunResult, g as RunStatus, h as buildMessages, j as createAgent, r as runLoop } from '../index-DdYZeNIu.cjs';
2
- export { T as Thread, a as ThreadOptions, e as estimateTokens } from '../thread-Dfo9LLf7.cjs';
1
+ export { A as Agent, a as AgentConfig, b as AgentInput, G as GenerateFn, L as LoopOptions, c as LoopResult, R as RunChunk, e as RunOptions, f as RunResult, g as RunStatus, h as buildMessages, j as createAgent, r as runLoop } from '../index-5eIhfrC1.cjs';
2
+ export { T as Thread, a as ThreadOptions, e as estimateTokens } from '../thread-D3zaGK1Y.cjs';
3
3
  export { C as ContentPart } from '../types-Cn1g9Tg4.cjs';
4
4
  import '../errors-CjVz4W_5.cjs';
5
- import '../provider-CMAymr1b.cjs';
5
+ import '../provider-IJnfNhCX.cjs';
6
6
  import '../tool-BZg_znMZ.cjs';
7
7
  import '../skill-DfNChtJN.cjs';
8
- import '../registry-D4fThGiN.cjs';
8
+ import '../registry-B-hicOxp.cjs';
@@ -1,8 +1,8 @@
1
- export { A as Agent, a as AgentConfig, b as AgentInput, G as GenerateFn, L as LoopOptions, c as LoopResult, R as RunChunk, e as RunOptions, f as RunResult, g as RunStatus, h as buildMessages, j as createAgent, r as runLoop } from '../index-D7-znzrc.js';
2
- export { T as Thread, a as ThreadOptions, e as estimateTokens } from '../thread-CWVzTyti.js';
1
+ export { A as Agent, a as AgentConfig, b as AgentInput, G as GenerateFn, L as LoopOptions, c as LoopResult, R as RunChunk, e as RunOptions, f as RunResult, g as RunStatus, h as buildMessages, j as createAgent, r as runLoop } from '../index-Dog-CyOK.js';
2
+ export { T as Thread, a as ThreadOptions, e as estimateTokens } from '../thread-COV135Ja.js';
3
3
  export { C as ContentPart } from '../types-Cn1g9Tg4.js';
4
4
  import '../errors-CjVz4W_5.js';
5
- import '../provider-osAtfZ7x.js';
5
+ import '../provider-C_rgZvmX.js';
6
6
  import '../tool-CSCC87OD.js';
7
7
  import '../skill-DfNChtJN.js';
8
- import '../registry-CpO0yH5v.js';
8
+ import '../registry-KMWN0p4Z.js';
@@ -1,9 +1,9 @@
1
1
  import '../chunk-MCLVWCOB.js';
2
- export { buildMessages, createAgent, runLoop } from '../chunk-RD5YUB2E.js';
2
+ export { buildMessages, createAgent, runLoop } from '../chunk-WEKU7735.js';
3
3
  import '../chunk-YCBDEEAV.js';
4
4
  import '../chunk-HGEPXJDG.js';
5
5
  import '../chunk-7ZXUIHLH.js';
6
- export { Thread, estimateTokens } from '../chunk-XPXTXOYQ.js';
6
+ export { Thread, estimateTokens } from '../chunk-E4VTVUYU.js';
7
7
  import '../chunk-IXV4UIF5.js';
8
8
  import '../chunk-DEABART4.js';
9
9
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkYBFLWRO5_cjs = require('./chunk-YBFLWRO5.cjs');
3
+ var chunkNURRGYIU_cjs = require('./chunk-NURRGYIU.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 chunkYBFLWRO5_cjs.createAgent({
38
+ return chunkNURRGYIU_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-YKZJRE32.cjs.map
50
- //# sourceMappingURL=chunk-YKZJRE32.cjs.map
49
+ //# sourceMappingURL=chunk-245NZAGV.cjs.map
50
+ //# sourceMappingURL=chunk-245NZAGV.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-YKZJRE32.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-245NZAGV.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,4 +1,25 @@
1
- import { ProviderError } from './chunk-IXV4UIF5.js';
1
+ import { ValidationError, ProviderError } from './chunk-IXV4UIF5.js';
2
+
3
+ // src/providers/provider.ts
4
+ function resolveModels(options) {
5
+ const models = options.models ?? (options.capabilities ? [options.capabilities] : []);
6
+ if (models.length === 0) {
7
+ throw new ValidationError("Provider requires at least one model (set `capabilities` or `models`)");
8
+ }
9
+ const defaultModel = options.defaultModel ? models.find((m) => m.model === options.defaultModel) : models[0];
10
+ if (!defaultModel) {
11
+ throw new ValidationError(`defaultModel "${options.defaultModel}" is not present in models`);
12
+ }
13
+ const modelOf = (name) => {
14
+ if (!name) return defaultModel;
15
+ const found = models.find((m) => m.model === name);
16
+ if (!found) {
17
+ throw new ValidationError(`Model "${name}" is not configured for this provider`);
18
+ }
19
+ return found;
20
+ };
21
+ return { models, defaultModel, modelOf };
22
+ }
2
23
 
3
24
  // src/providers/retry.ts
4
25
  var DEFAULTS = {
@@ -58,6 +79,7 @@ function toOpenAIMessages(messages) {
58
79
  function createOpenAICompatibleProvider(options) {
59
80
  const doFetch = options.fetchImpl ?? globalThis.fetch;
60
81
  const url = `${options.baseUrl.replace(/\/$/, "")}/chat/completions`;
82
+ const { models, defaultModel, modelOf } = resolveModels(options);
61
83
  async function authHeaders() {
62
84
  const cred = await options.getCredential();
63
85
  const headers = { "content-type": "application/json" };
@@ -66,7 +88,7 @@ function createOpenAICompatibleProvider(options) {
66
88
  }
67
89
  function body(req, stream) {
68
90
  return JSON.stringify({
69
- model: options.capabilities.model,
91
+ model: modelOf(req.model).model,
70
92
  messages: toOpenAIMessages(req.messages),
71
93
  stream,
72
94
  ...req.tools && req.tools.length > 0 ? {
@@ -111,7 +133,7 @@ function createOpenAICompatibleProvider(options) {
111
133
  const message = choice.message;
112
134
  return {
113
135
  text: message["content"] ?? "",
114
- reasoning: options.capabilities.supportsReasoning ? message["reasoning"] ?? void 0 : void 0,
136
+ reasoning: modelOf(req.model).supportsReasoning ? message["reasoning"] ?? void 0 : void 0,
115
137
  toolCalls: parseToolCalls(message)
116
138
  };
117
139
  }, options.retry);
@@ -152,7 +174,7 @@ function createOpenAICompatibleProvider(options) {
152
174
  text += delta.content;
153
175
  yield { type: "text", text: delta.content };
154
176
  }
155
- if (delta?.reasoning && options.capabilities.supportsReasoning) {
177
+ if (delta?.reasoning && modelOf(req.model).supportsReasoning) {
156
178
  reasoning += delta.reasoning;
157
179
  yield { type: "reasoning", text: delta.reasoning };
158
180
  }
@@ -163,7 +185,14 @@ function createOpenAICompatibleProvider(options) {
163
185
  response: { text, reasoning: reasoning || void 0 }
164
186
  };
165
187
  }
166
- return { name: "openai-compatible", capabilities: options.capabilities, generate, generateStream };
188
+ return {
189
+ name: "openai-compatible",
190
+ capabilities: defaultModel,
191
+ models,
192
+ model: modelOf,
193
+ generate,
194
+ generateStream
195
+ };
167
196
  }
168
197
  function safeJson(s) {
169
198
  try {
@@ -180,17 +209,21 @@ function createCopilotProvider(options) {
180
209
  baseUrl: options.baseUrl ?? DEFAULT_COPILOT_BASE_URL,
181
210
  getCredential: options.getCredential,
182
211
  capabilities: options.capabilities,
212
+ models: options.models,
213
+ defaultModel: options.defaultModel,
183
214
  retry: options.retry,
184
215
  fetchImpl: options.fetchImpl
185
216
  });
186
217
  return {
187
218
  name: "copilot",
188
219
  capabilities: inner.capabilities,
220
+ models: inner.models,
221
+ model: inner.model.bind(inner),
189
222
  generate: inner.generate.bind(inner),
190
223
  generateStream: inner.generateStream.bind(inner)
191
224
  };
192
225
  }
193
226
 
194
- export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, withRetry };
195
- //# sourceMappingURL=chunk-UVWQWOLO.js.map
196
- //# sourceMappingURL=chunk-UVWQWOLO.js.map
227
+ export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry };
228
+ //# sourceMappingURL=chunk-7M3EAGCA.js.map
229
+ //# sourceMappingURL=chunk-7M3EAGCA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/provider.ts","../src/providers/retry.ts","../src/providers/openai-compatible.ts","../src/providers/copilot.ts"],"names":[],"mappings":"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","file":"chunk-7M3EAGCA.js","sourcesContent":["/**\n * LLM provider abstraction. Agents and workflows depend only on this interface,\n * never on a concrete provider, so new providers can be added without changing\n * agent/workflow code. (FR-007)\n *\n * Credentials are always obtained via a caller-supplied callback and are never\n * bundled, persisted, or logged by the framework. (FR-005a, FR-008)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** A caller-supplied source of credentials. The framework never stores the value. */\nexport interface CredentialSource {\n\t/** Return the current credential (token/api key). May be async. */\n\tgetCredential(): string | Promise<string>;\n}\n\n/**\n * Model configuration for a provider. A provider may expose **one or more** models\n * (e.g. GitHub Copilot offers several; an OpenAI-compatible endpoint is usually one).\n * Supply either a single `capabilities` object or an array via `models`.\n */\nexport interface ModelSelectionOptions {\n\t/** Single-model shorthand. */\n\tcapabilities?: ModelCapabilities;\n\t/** One or more models this provider can use. */\n\tmodels?: ModelCapabilities[];\n\t/** Name of the default model (defaults to the first entry). */\n\tdefaultModel?: string;\n}\n\n/** Resolved model set with a default and a lookup helper. */\nexport interface ResolvedModels {\n\t/** All configured models (at least one). */\n\tmodels: ModelCapabilities[];\n\t/** The default model used when a request does not specify one. */\n\tdefaultModel: ModelCapabilities;\n\t/** Look up a model by name, or return the default when omitted. */\n\tmodelOf(name?: string): ModelCapabilities;\n}\n\n/**\n * Normalize {@link ModelSelectionOptions} into a model list, a default, and a\n * lookup helper. Throws {@link ValidationError} if no model is configured or a\n * named model is missing.\n *\n * @example\n * ```ts\n * const { defaultModel, modelOf } = resolveModels({\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * ```\n */\nexport function resolveModels(options: ModelSelectionOptions): ResolvedModels {\n\tconst models = options.models ?? (options.capabilities ? [options.capabilities] : []);\n\tif (models.length === 0) {\n\t\tthrow new ValidationError(\"Provider requires at least one model (set `capabilities` or `models`)\");\n\t}\n\tconst defaultModel = options.defaultModel\n\t\t? models.find((m) => m.model === options.defaultModel)\n\t\t: models[0];\n\tif (!defaultModel) {\n\t\tthrow new ValidationError(`defaultModel \"${options.defaultModel}\" is not present in models`);\n\t}\n\tconst modelOf = (name?: string): ModelCapabilities => {\n\t\tif (!name) return defaultModel;\n\t\tconst found = models.find((m) => m.model === name);\n\t\tif (!found) {\n\t\t\tthrow new ValidationError(`Model \"${name}\" is not configured for this provider`);\n\t\t}\n\t\treturn found;\n\t};\n\treturn { models, defaultModel, modelOf };\n}\n\n/** A tool description passed to the provider so the model can decide to call it. */\nexport interface ToolSpec {\n\tname: string;\n\tdescription: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/** A request to generate a model response. */\nexport interface GenerateRequest {\n\tmessages: Message[];\n\ttools?: ToolSpec[];\n\t/** Which configured model to use; defaults to the provider's default model. */\n\tmodel?: string;\n\t/** Abort signal to cancel an in-flight request. */\n\tsignal?: AbortSignal;\n}\n\n/** A tool call requested by the model. */\nexport interface ToolCall {\n\tid: string;\n\tname: string;\n\t/** Raw JSON arguments (validated by the tools module before invocation). */\n\targuments: unknown;\n}\n\n/** A complete (non-streaming) model response. */\nexport interface GenerateResponse {\n\t/** Final answer text. */\n\ttext: string;\n\t/** Reasoning/thinking content — only present for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\t/** Tool calls the model wants to make, if any. */\n\ttoolCalls?: ToolCall[];\n\t/** Approximate token usage if reported by the provider. */\n\tusage?: { inputTokens?: number; outputTokens?: number };\n}\n\n/** An incremental streaming chunk. */\nexport type GenerateChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"tool-call\"; toolCall: ToolCall }\n\t| { type: \"done\"; response: GenerateResponse };\n\n/**\n * An LLM backend. Implementations adapt a concrete API (Copilot, OpenAI-compatible)\n * onto this uniform surface.\n */\nexport interface Provider {\n\t/** Stable provider identifier, e.g. `\"openai-compatible\"`. */\n\treadonly name: string;\n\t/** The default model's capability configuration. (FR-007a) */\n\treadonly capabilities: ModelCapabilities;\n\t/** All models this provider is configured with (one or more). */\n\treadonly models: ModelCapabilities[];\n\t/** Look up a configured model by name, or the default when omitted. */\n\tmodel(name?: string): ModelCapabilities;\n\t/** Generate a complete response. */\n\tgenerate(req: GenerateRequest): Promise<GenerateResponse>;\n\t/** Generate a streamed response. */\n\tgenerateStream(req: GenerateRequest): AsyncIterable<GenerateChunk>;\n}\n","/**\n * Exponential-backoff retry for transient provider failures. Transient errors\n * (429 with Retry-After, 5xx, network/timeout) are retried; auth/4xx fail fast.\n * (FR-008a)\n *\n * @packageDocumentation\n */\n\nimport { ProviderError } from \"../core/errors.js\";\n\n/** Retry tuning. All fields have safe defaults. */\nexport interface RetryOptions {\n\t/** Maximum retry attempts after the first try. Default 3. */\n\tmaxRetries?: number;\n\t/** Base delay in ms for backoff. Default 250. */\n\tbaseDelayMs?: number;\n\t/** Maximum delay cap in ms. Default 8000. */\n\tmaxDelayMs?: number;\n}\n\nconst DEFAULTS: Required<RetryOptions> = {\n\tmaxRetries: 3,\n\tbaseDelayMs: 250,\n\tmaxDelayMs: 8000,\n};\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Run `fn`, retrying transient {@link ProviderError}s with exponential backoff\n * and jitter. Non-transient errors are rethrown immediately (fail fast).\n *\n * @param fn - The operation to attempt. It should throw a {@link ProviderError}.\n * @param opts - Retry tuning.\n * @param retryAfterMs - Optional hook returning a server-specified delay (Retry-After).\n */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\topts?: RetryOptions,\n\tretryAfterMs?: (err: ProviderError) => number | undefined,\n): Promise<T> {\n\tconst cfg = { ...DEFAULTS, ...opts };\n\tlet attempt = 0;\n\n\tfor (; ;) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst isRetryable = err instanceof ProviderError && err.retryable;\n\t\t\tif (!isRetryable || attempt >= cfg.maxRetries) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tconst serverDelay = retryAfterMs?.(err as ProviderError);\n\t\t\tconst backoff = Math.min(cfg.baseDelayMs * 2 ** attempt, cfg.maxDelayMs);\n\t\t\tconst jitter = Math.random() * cfg.baseDelayMs;\n\t\t\tawait sleep(serverDelay ?? backoff + jitter);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\n/** Map an HTTP status to a {@link ProviderError} with the right retry semantics. */\nexport function providerErrorFromStatus(status: number, message: string): ProviderError {\n\tif (status === 429 || status >= 500) {\n\t\treturn new ProviderError(message, \"transient\", { status });\n\t}\n\tif (status === 401 || status === 403) {\n\t\treturn new ProviderError(message, \"auth\", { status });\n\t}\n\treturn new ProviderError(message, \"client\", { status });\n}\n","/**\n * OpenAI-compatible provider. Targets any endpoint speaking the OpenAI\n * `/chat/completions` API, including local servers such as LM Studio via a custom\n * `baseUrl`. (FR-006)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type {\n\tProvider,\n\tCredentialSource,\n\tGenerateRequest,\n\tGenerateResponse,\n\tGenerateChunk,\n\tToolCall,\n} from \"./provider.js\";\nimport { resolveModels, type ModelSelectionOptions } from \"./provider.js\";\nimport { withRetry, providerErrorFromStatus, type RetryOptions } from \"./retry.js\";\n\n/**\n * Options for {@link createOpenAICompatibleProvider}.\n *\n * Supply a single model via `capabilities`, or multiple via `models` (most\n * OpenAI-compatible endpoints expose one model, but multiple are supported).\n */\nexport interface OpenAICompatibleProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Base URL of the OpenAI-compatible API, e.g. `http://localhost:1234/v1`. */\n\tbaseUrl: string;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\ninterface OpenAIMessage {\n\trole: string;\n\tcontent: unknown;\n\ttool_calls?: Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }>;\n\ttool_call_id?: string;\n\tname?: string;\n}\n\nfunction toOpenAIContent(parts: ContentPart[]): unknown {\n\tif (parts.every((p) => p.type === \"text\")) {\n\t\treturn parts.map((p) => (p as { text: string }).text).join(\"\");\n\t}\n\treturn parts.map((p) =>\n\t\tp.type === \"text\"\n\t\t\t? { type: \"text\", text: p.text }\n\t\t\t: { type: \"image_url\", image_url: { url: p.data } },\n\t);\n}\n\nfunction toOpenAIMessages(messages: Message[]): OpenAIMessage[] {\n\treturn messages.map((m) => {\n\t\tconst msg: OpenAIMessage = { role: m.role, content: toOpenAIContent(m.parts) };\n\t\tif (m.toolCallId) msg.tool_call_id = m.toolCallId;\n\t\tif (m.name) msg.name = m.name;\n\t\treturn msg;\n\t});\n}\n\n/**\n * Create an OpenAI-compatible provider (works with LM Studio, vLLM, etc.).\n *\n * @example\n * ```ts\n * const provider = createOpenAICompatibleProvider({\n * baseUrl: \"http://localhost:1234/v1\",\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * capabilities: { model: \"local\", maxInputTokens: 262144, maxOutputTokens: 32000 },\n * });\n * ```\n */\nexport function createOpenAICompatibleProvider(\n\toptions: OpenAICompatibleProviderOptions,\n): Provider {\n\tconst doFetch = options.fetchImpl ?? globalThis.fetch;\n\tconst url = `${options.baseUrl.replace(/\\/$/, \"\")}/chat/completions`;\n\tconst { models, defaultModel, modelOf } = resolveModels(options);\n\n\tasync function authHeaders(): Promise<Record<string, string>> {\n\t\tconst cred = await options.getCredential();\n\t\tconst headers: Record<string, string> = { \"content-type\": \"application/json\" };\n\t\tif (cred) headers[\"authorization\"] = `Bearer ${cred}`;\n\t\treturn headers;\n\t}\n\n\tfunction body(req: GenerateRequest, stream: boolean): string {\n\t\treturn JSON.stringify({\n\t\t\tmodel: modelOf(req.model).model,\n\t\t\tmessages: toOpenAIMessages(req.messages),\n\t\t\tstream,\n\t\t\t...(req.tools && req.tools.length > 0\n\t\t\t\t? {\n\t\t\t\t\ttools: req.tools.map((t) => ({\n\t\t\t\t\t\ttype: \"function\",\n\t\t\t\t\t\tfunction: { name: t.name, description: t.description, parameters: t.inputSchema },\n\t\t\t\t\t})),\n\t\t\t\t}\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\tfunction parseToolCalls(raw: unknown): ToolCall[] | undefined {\n\t\tconst calls = (raw as { tool_calls?: Array<{ id: string; function: { name: string; arguments: string } }> })\n\t\t\t?.tool_calls;\n\t\tif (!calls || calls.length === 0) return undefined;\n\t\treturn calls.map((c) => ({\n\t\t\tid: c.id,\n\t\t\tname: c.function.name,\n\t\t\targuments: safeJson(c.function.arguments),\n\t\t}));\n\t}\n\n\tasync function generate(req: GenerateRequest): Promise<GenerateResponse> {\n\t\treturn withRetry(async () => {\n\t\t\tlet res: Response;\n\t\t\ttry {\n\t\t\t\tres = await doFetch(url, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: await authHeaders(),\n\t\t\t\t\tbody: body(req, false),\n\t\t\t\t\tsignal: req.signal,\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t\t}\n\t\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\n\t\t\tlet json: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tjson = (await res.json()) as Record<string, unknown>;\n\t\t\t} catch {\n\t\t\t\tthrow new ProviderError(\"Malformed provider response\", \"malformed\");\n\t\t\t}\n\t\t\tconst choice = (json[\"choices\"] as Array<{ message: Record<string, unknown> }>)?.[0];\n\t\t\tif (!choice) throw new ProviderError(\"Provider returned no choices\", \"malformed\");\n\t\t\tconst message = choice.message;\n\t\t\treturn {\n\t\t\t\ttext: (message[\"content\"] as string) ?? \"\",\n\t\t\t\treasoning: modelOf(req.model).supportsReasoning\n\t\t\t\t\t? ((message[\"reasoning\"] as string) ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t\ttoolCalls: parseToolCalls(message),\n\t\t\t};\n\t\t}, options.retry);\n\t}\n\n\tasync function* generateStream(req: GenerateRequest): AsyncIterable<GenerateChunk> {\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await doFetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: await authHeaders(),\n\t\t\t\tbody: body(req, true),\n\t\t\t\tsignal: req.signal,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t}\n\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\t\tif (!res.body) throw new ProviderError(\"Provider returned no stream body\", \"malformed\");\n\n\t\tconst reader = res.body.getReader();\n\t\tconst decoder = new TextDecoder();\n\t\tlet buffer = \"\";\n\t\tlet text = \"\";\n\t\tlet reasoning = \"\";\n\n\t\tfor (; ;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst trimmed = line.trim();\n\t\t\t\tif (!trimmed.startsWith(\"data:\")) continue;\n\t\t\t\tconst data = trimmed.slice(5).trim();\n\t\t\t\tif (data === \"[DONE]\") continue;\n\t\t\t\tconst parsed = safeJson(data) as\n\t\t\t\t\t| { choices?: Array<{ delta?: { content?: string; reasoning?: string } }> }\n\t\t\t\t\t| undefined;\n\t\t\t\tconst delta = parsed?.choices?.[0]?.delta;\n\t\t\t\tif (delta?.content) {\n\t\t\t\t\ttext += delta.content;\n\t\t\t\t\tyield { type: \"text\", text: delta.content };\n\t\t\t\t}\n\t\t\t\tif (delta?.reasoning && modelOf(req.model).supportsReasoning) {\n\t\t\t\t\treasoning += delta.reasoning;\n\t\t\t\t\tyield { type: \"reasoning\", text: delta.reasoning };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresponse: { text, reasoning: reasoning || undefined },\n\t\t};\n\t}\n\n\treturn {\n\t\tname: \"openai-compatible\",\n\t\tcapabilities: defaultModel,\n\t\tmodels,\n\t\tmodel: modelOf,\n\t\tgenerate,\n\t\tgenerateStream,\n\t};\n}\n\nfunction safeJson(s: string): unknown {\n\ttry {\n\t\treturn JSON.parse(s);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n","/**\n * GitHub Copilot provider. (FR-005)\n *\n * Copilot's chat API is OpenAI-compatible, so this provider configures the shared\n * OpenAI-compatible transport with Copilot's endpoint and the caller-supplied\n * credential (a Copilot/GitHub token). The token is obtained via callback and is\n * never bundled, persisted, or logged. (FR-005a)\n *\n * In a frontend-only deployment the end user supplies their own token (it stays\n * client-side); in a backend deployment the developer may supply it, or the user\n * sends it per request over SSL/TLS and the backend must not log or persist it.\n *\n * @packageDocumentation\n */\n\nimport type { Provider, CredentialSource, ModelSelectionOptions } from \"./provider.js\";\nimport type { RetryOptions } from \"./retry.js\";\nimport { createOpenAICompatibleProvider } from \"./openai-compatible.js\";\n\n/** Default Copilot-compatible chat completions base URL. */\nconst DEFAULT_COPILOT_BASE_URL = \"https://api.githubcopilot.com\";\n\n/**\n * Options for {@link createCopilotProvider}.\n *\n * GitHub Copilot exposes several models, so configure them via `models` (with an\n * optional `defaultModel`). A single `capabilities` object is also accepted.\n */\nexport interface CopilotProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Override the Copilot base URL if needed. */\n\tbaseUrl?: string;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\n/**\n * Create a GitHub Copilot provider.\n *\n * @example Single model\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken, // never logged or persisted\n * capabilities: { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * });\n * ```\n *\n * @example Multiple models\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken,\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000, supportsVision: true },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * // Pick a model per request: provider.generate({ messages, model: \"o3-mini\" })\n * ```\n */\nexport function createCopilotProvider(options: CopilotProviderOptions): Provider {\n\tconst inner = createOpenAICompatibleProvider({\n\t\tbaseUrl: options.baseUrl ?? DEFAULT_COPILOT_BASE_URL,\n\t\tgetCredential: options.getCredential,\n\t\tcapabilities: options.capabilities,\n\t\tmodels: options.models,\n\t\tdefaultModel: options.defaultModel,\n\t\tretry: options.retry,\n\t\tfetchImpl: options.fetchImpl,\n\t});\n\t// Preserve the provider contract but report the Copilot name.\n\treturn {\n\t\tname: \"copilot\",\n\t\tcapabilities: inner.capabilities,\n\t\tmodels: inner.models,\n\t\tmodel: inner.model.bind(inner),\n\t\tgenerate: inner.generate.bind(inner),\n\t\tgenerateStream: inner.generateStream.bind(inner),\n\t};\n}\n"]}
@@ -45,7 +45,8 @@ var Thread = class _Thread {
45
45
  */
46
46
  async maybeCompact(provider, options) {
47
47
  const threshold = options?.compactionThreshold ?? 0.9;
48
- const limit = provider.capabilities.maxInputTokens * threshold;
48
+ const caps = options?.modelCapabilities ?? provider.capabilities;
49
+ const limit = caps.maxInputTokens * threshold;
49
50
  if (estimateTokens(this.messages) < limit) return false;
50
51
  const summarizer = options?.compactionModel ?? provider;
51
52
  const system = this.messages.filter((m) => m.role === "system");
@@ -77,5 +78,5 @@ function cryptoRandomId() {
77
78
  }
78
79
 
79
80
  export { Thread, estimateTokens, hasImage, messageText, textMessage };
80
- //# sourceMappingURL=chunk-XPXTXOYQ.js.map
81
- //# sourceMappingURL=chunk-XPXTXOYQ.js.map
81
+ //# sourceMappingURL=chunk-E4VTVUYU.js.map
82
+ //# sourceMappingURL=chunk-E4VTVUYU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts","../src/agents/thread.ts"],"names":[],"mappings":"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","file":"chunk-E4VTVUYU.js","sourcesContent":["/**\n * Shared content, message, and model-capability types used across the framework.\n *\n * These are the lowest-level building blocks: every higher-level module (agents,\n * providers, tools, workflows) speaks in terms of {@link Message} and\n * {@link ContentPart}. Keeping them dependency-free keeps the core tree-shakeable.\n *\n * @packageDocumentation\n */\n\n/** A JSON Schema object (draft 2020-12 compatible), as popularized by MCP. */\nexport type JSONSchema = Record<string, unknown>;\n\n/** Role of a message in a conversation. */\nexport type Role = \"system\" | \"user\" | \"assistant\" | \"tool\";\n\n/** A single piece of message content. Images are only valid for vision-capable models. */\nexport type ContentPart =\n\t| { type: \"text\"; text: string }\n\t| { type: \"image\"; data: string; mimeType: string };\n\n/**\n * A conversation message.\n *\n * @example\n * ```ts\n * const msg: Message = { role: \"user\", parts: [{ type: \"text\", text: \"Hi\" }] };\n * ```\n */\nexport interface Message {\n\trole: Role;\n\tparts: ContentPart[];\n\t/** Optional tool-call linkage for assistant/tool messages. */\n\ttoolCallId?: string;\n\t/** Optional display name (e.g., the tool name for a tool message). */\n\tname?: string;\n}\n\n/**\n * Per-model capabilities supplied by the caller. The framework cannot reliably\n * discover these for arbitrary OpenAI-compatible/LM Studio models, so they are\n * provided explicitly. (FR-007a)\n */\nexport interface ModelCapabilities {\n\t/** Model id/name. */\n\tmodel: string;\n\t/** Maximum input/context tokens; drives compaction threshold. */\n\tmaxInputTokens: number;\n\t/** Maximum output tokens. */\n\tmaxOutputTokens: number;\n\t/** Whether the model accepts image input. Defaults to false. */\n\tsupportsVision?: boolean;\n\t/** Whether the model emits separate reasoning/thinking content. Defaults to false. */\n\tsupportsReasoning?: boolean;\n}\n\n/** Convenience: build a user message from a plain string. */\nexport function textMessage(role: Role, text: string): Message {\n\treturn { role, parts: [{ type: \"text\", text }] };\n}\n\n/** Returns true if a message contains any image content part. */\nexport function hasImage(message: Message): boolean {\n\treturn message.parts.some((p) => p.type === \"image\");\n}\n\n/** Extract the concatenated text from a message. */\nexport function messageText(message: Message): string {\n\treturn message.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 * Conversation thread with automatic compaction. When a thread approaches the\n * model's input-token budget it is summarized into a compact form so the\n * conversation can continue. (FR-004, FR-004a, FR-004b)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { messageText, textMessage } from \"../core/types.js\";\nimport type { Provider } from \"../providers/provider.js\";\n\n/** Options controlling a thread's compaction behavior. */\nexport interface ThreadOptions {\n\t/** Fraction of `maxInputTokens` at which compaction triggers. Default 0.9. */\n\tcompactionThreshold?: number;\n\t/** Provider used to summarize; defaults to the agent's own provider. (FR-004b) */\n\tcompactionModel?: Provider;\n\t/** Capabilities of the model in use; defaults to the provider's default model. */\n\tmodelCapabilities?: ModelCapabilities;\n}\n\n/** Rough token estimate (~4 chars/token) — avoids a tokenizer dependency. */\nexport function estimateTokens(messages: Message[]): number {\n\tconst chars = messages.reduce((sum, m) => sum + messageText(m).length, 0);\n\treturn Math.ceil(chars / 4);\n}\n\n/** A multi-turn conversation that preserves context and compacts when large. */\nexport class Thread {\n\treadonly id: string;\n\tmessages: Message[];\n\t/** Whether the thread has been compacted at least once. */\n\tcompacted = false;\n\n\tconstructor(id?: string, messages: Message[] = []) {\n\t\tthis.id = id ?? cryptoRandomId();\n\t\tthis.messages = messages;\n\t}\n\n\t/** Append a message. */\n\tadd(message: Message): void {\n\t\tthis.messages.push(message);\n\t}\n\n\t/** Serializable snapshot for persistence. */\n\ttoJSON(): { id: string; messages: Message[]; compacted: boolean } {\n\t\treturn { id: this.id, messages: this.messages, compacted: this.compacted };\n\t}\n\n\t/** Restore a thread from a snapshot. */\n\tstatic fromJSON(data: { id: string; messages: Message[]; compacted?: boolean }): Thread {\n\t\tconst t = new Thread(data.id, data.messages);\n\t\tt.compacted = data.compacted ?? false;\n\t\treturn t;\n\t}\n\n\t/**\n\t * Compact the thread if it exceeds the threshold. System messages and the most\n\t * recent turn are preserved; older turns are summarized via the model.\n\t *\n\t * @returns true if compaction occurred.\n\t */\n\tasync maybeCompact(provider: Provider, options?: ThreadOptions): Promise<boolean> {\n\t\tconst threshold = options?.compactionThreshold ?? 0.9;\n\t\tconst caps = options?.modelCapabilities ?? provider.capabilities;\n\t\tconst limit = caps.maxInputTokens * threshold;\n\t\tif (estimateTokens(this.messages) < limit) return false;\n\n\t\tconst summarizer = options?.compactionModel ?? provider;\n\t\tconst system = this.messages.filter((m) => m.role === \"system\");\n\t\tconst recent = this.messages.slice(-2);\n\t\tconst toSummarize = this.messages.filter((m) => m.role !== \"system\").slice(0, -2);\n\t\tif (toSummarize.length === 0) return false;\n\n\t\tconst summary = await summarizer.generate({\n\t\t\tmessages: [\n\t\t\t\ttextMessage(\n\t\t\t\t\t\"system\",\n\t\t\t\t\t\"Summarize the following conversation compactly, preserving facts, decisions, and open questions.\",\n\t\t\t\t),\n\t\t\t\ttextMessage(\"user\", toSummarize.map((m) => `${m.role}: ${messageText(m)}`).join(\"\\n\")),\n\t\t\t],\n\t\t});\n\n\t\tthis.messages = [\n\t\t\t...system,\n\t\t\ttextMessage(\"system\", `Summary of earlier conversation: ${summary.text}`),\n\t\t\t...recent,\n\t\t];\n\t\tthis.compacted = true;\n\t\treturn true;\n\t}\n}\n\nfunction cryptoRandomId(): string {\n\tconst c = (globalThis as { crypto?: Crypto }).crypto;\n\tif (c?.randomUUID) return c.randomUUID();\n\treturn `thread-${Math.random().toString(36).slice(2)}-${Date.now()}`;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Thread } from './chunk-XPXTXOYQ.js';
1
+ import { Thread } from './chunk-E4VTVUYU.js';
2
2
  import { requireCapability } from './chunk-ACBIHS5H.js';
3
3
 
4
4
  // src/persistence/store.ts
@@ -87,5 +87,5 @@ function indexedDbStore(ns) {
87
87
  }
88
88
 
89
89
  export { ThreadPersistence, createBrowserStore, createMemoryStore };
90
- //# sourceMappingURL=chunk-V472N2PK.js.map
91
- //# sourceMappingURL=chunk-V472N2PK.js.map
90
+ //# sourceMappingURL=chunk-IGIFX6QO.js.map
91
+ //# sourceMappingURL=chunk-IGIFX6QO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/persistence/store.ts","../src/persistence/memory.ts","../src/persistence/browser.ts"],"names":[],"mappings":"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","file":"chunk-V472N2PK.js","sourcesContent":["/**\n * Pluggable storage abstraction for persisting conversation/thread state in a\n * no-backend environment. No database server is assumed. (FR-024)\n *\n * @packageDocumentation\n */\n\nimport type { Thread } from \"../agents/thread.js\";\nimport { Thread as ThreadClass } from \"../agents/thread.js\";\n\n/** A minimal key/value store. */\nexport interface Store {\n\tget(key: string): Promise<unknown | undefined>;\n\tset(key: string, value: unknown): Promise<void>;\n\tdelete(key: string): Promise<void>;\n}\n\n/** Save and load threads via a {@link Store}. */\nexport const ThreadPersistence = {\n\t/** Persist a thread under the key `thread:<id>`. */\n\tasync save(store: Store, thread: Thread): Promise<void> {\n\t\tawait store.set(`thread:${thread.id}`, thread.toJSON());\n\t},\n\t/** Load and rehydrate a thread, or undefined if absent. */\n\tasync load(store: Store, id: string): Promise<Thread | undefined> {\n\t\tconst data = (await store.get(`thread:${id}`)) as\n\t\t\t| { id: string; messages: never[]; compacted?: boolean }\n\t\t\t| undefined;\n\t\treturn data ? ThreadClass.fromJSON(data) : undefined;\n\t},\n};\n","/**\n * In-memory store adapter. Works in every runtime; ideal as a default and for tests.\n * @packageDocumentation\n */\n\nimport type { Store } from \"./store.js\";\n\n/** Create an in-memory {@link Store}. */\nexport function createMemoryStore(): Store {\n\tconst map = new Map<string, unknown>();\n\treturn {\n\t\tasync get(key) {\n\t\t\treturn map.get(key);\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tmap.set(key, value);\n\t\t},\n\t\tasync delete(key) {\n\t\t\tmap.delete(key);\n\t\t},\n\t};\n}\n","/**\n * Browser store adapters backed by `localStorage` or `IndexedDB`. Capability-gated\n * so a clear typed error is thrown if used where unavailable. (FR-024, FR-030a)\n *\n * @packageDocumentation\n */\n\nimport type { Store } from \"./store.js\";\nimport { requireCapability } from \"../core/runtime.js\";\n\n/** Options for {@link createBrowserStore}. */\nexport interface BrowserStoreOptions {\n\t/** Storage backend. Default \"local\". */\n\tbackend?: \"local\" | \"indexeddb\";\n\t/** Key namespace/prefix. Default \"afjs\". */\n\tnamespace?: string;\n}\n\n/** Create a browser-backed {@link Store}. */\nexport function createBrowserStore(options: BrowserStoreOptions = {}): Store {\n\tconst backend = options.backend ?? \"local\";\n\tconst ns = options.namespace ?? \"afjs\";\n\treturn backend === \"indexeddb\" ? indexedDbStore(ns) : localStorageStore(ns);\n}\n\nfunction localStorageStore(ns: string): Store {\n\trequireCapability(\"hasLocalStorage\", \"localStorage store\");\n\tconst ls = (globalThis as unknown as { localStorage: Storage }).localStorage;\n\tconst k = (key: string) => `${ns}:${key}`;\n\treturn {\n\t\tasync get(key) {\n\t\t\tconst raw = ls.getItem(k(key));\n\t\t\treturn raw == null ? undefined : JSON.parse(raw);\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tls.setItem(k(key), JSON.stringify(value));\n\t\t},\n\t\tasync delete(key) {\n\t\t\tls.removeItem(k(key));\n\t\t},\n\t};\n}\n\nfunction indexedDbStore(ns: string): Store {\n\trequireCapability(\"hasIndexedDB\", \"IndexedDB store\");\n\tconst idb = (globalThis as unknown as { indexedDB: IDBFactory }).indexedDB;\n\n\tfunction open(): Promise<IDBDatabase> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst req = idb.open(ns, 1);\n\t\t\treq.onupgradeneeded = () => req.result.createObjectStore(\"kv\");\n\t\t\treq.onsuccess = () => resolve(req.result);\n\t\t\treq.onerror = () => reject(req.error);\n\t\t});\n\t}\n\n\tasync function tx<T>(mode: IDBTransactionMode, fn: (s: IDBObjectStore) => IDBRequest): Promise<T> {\n\t\tconst db = await open();\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst store = db.transaction(\"kv\", mode).objectStore(\"kv\");\n\t\t\tconst req = fn(store);\n\t\t\treq.onsuccess = () => resolve(req.result as T);\n\t\t\treq.onerror = () => reject(req.error);\n\t\t});\n\t}\n\n\treturn {\n\t\tasync get(key) {\n\t\t\treturn tx<unknown>(\"readonly\", (s) => s.get(key));\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tawait tx(\"readwrite\", (s) => s.put(value, key));\n\t\t},\n\t\tasync delete(key) {\n\t\t\tawait tx(\"readwrite\", (s) => s.delete(key));\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../src/persistence/store.ts","../src/persistence/memory.ts","../src/persistence/browser.ts"],"names":[],"mappings":"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","file":"chunk-IGIFX6QO.js","sourcesContent":["/**\n * Pluggable storage abstraction for persisting conversation/thread state in a\n * no-backend environment. No database server is assumed. (FR-024)\n *\n * @packageDocumentation\n */\n\nimport type { Thread } from \"../agents/thread.js\";\nimport { Thread as ThreadClass } from \"../agents/thread.js\";\n\n/** A minimal key/value store. */\nexport interface Store {\n\tget(key: string): Promise<unknown | undefined>;\n\tset(key: string, value: unknown): Promise<void>;\n\tdelete(key: string): Promise<void>;\n}\n\n/** Save and load threads via a {@link Store}. */\nexport const ThreadPersistence = {\n\t/** Persist a thread under the key `thread:<id>`. */\n\tasync save(store: Store, thread: Thread): Promise<void> {\n\t\tawait store.set(`thread:${thread.id}`, thread.toJSON());\n\t},\n\t/** Load and rehydrate a thread, or undefined if absent. */\n\tasync load(store: Store, id: string): Promise<Thread | undefined> {\n\t\tconst data = (await store.get(`thread:${id}`)) as\n\t\t\t| { id: string; messages: never[]; compacted?: boolean }\n\t\t\t| undefined;\n\t\treturn data ? ThreadClass.fromJSON(data) : undefined;\n\t},\n};\n","/**\n * In-memory store adapter. Works in every runtime; ideal as a default and for tests.\n * @packageDocumentation\n */\n\nimport type { Store } from \"./store.js\";\n\n/** Create an in-memory {@link Store}. */\nexport function createMemoryStore(): Store {\n\tconst map = new Map<string, unknown>();\n\treturn {\n\t\tasync get(key) {\n\t\t\treturn map.get(key);\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tmap.set(key, value);\n\t\t},\n\t\tasync delete(key) {\n\t\t\tmap.delete(key);\n\t\t},\n\t};\n}\n","/**\n * Browser store adapters backed by `localStorage` or `IndexedDB`. Capability-gated\n * so a clear typed error is thrown if used where unavailable. (FR-024, FR-030a)\n *\n * @packageDocumentation\n */\n\nimport type { Store } from \"./store.js\";\nimport { requireCapability } from \"../core/runtime.js\";\n\n/** Options for {@link createBrowserStore}. */\nexport interface BrowserStoreOptions {\n\t/** Storage backend. Default \"local\". */\n\tbackend?: \"local\" | \"indexeddb\";\n\t/** Key namespace/prefix. Default \"afjs\". */\n\tnamespace?: string;\n}\n\n/** Create a browser-backed {@link Store}. */\nexport function createBrowserStore(options: BrowserStoreOptions = {}): Store {\n\tconst backend = options.backend ?? \"local\";\n\tconst ns = options.namespace ?? \"afjs\";\n\treturn backend === \"indexeddb\" ? indexedDbStore(ns) : localStorageStore(ns);\n}\n\nfunction localStorageStore(ns: string): Store {\n\trequireCapability(\"hasLocalStorage\", \"localStorage store\");\n\tconst ls = (globalThis as unknown as { localStorage: Storage }).localStorage;\n\tconst k = (key: string) => `${ns}:${key}`;\n\treturn {\n\t\tasync get(key) {\n\t\t\tconst raw = ls.getItem(k(key));\n\t\t\treturn raw == null ? undefined : JSON.parse(raw);\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tls.setItem(k(key), JSON.stringify(value));\n\t\t},\n\t\tasync delete(key) {\n\t\t\tls.removeItem(k(key));\n\t\t},\n\t};\n}\n\nfunction indexedDbStore(ns: string): Store {\n\trequireCapability(\"hasIndexedDB\", \"IndexedDB store\");\n\tconst idb = (globalThis as unknown as { indexedDB: IDBFactory }).indexedDB;\n\n\tfunction open(): Promise<IDBDatabase> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst req = idb.open(ns, 1);\n\t\t\treq.onupgradeneeded = () => req.result.createObjectStore(\"kv\");\n\t\t\treq.onsuccess = () => resolve(req.result);\n\t\t\treq.onerror = () => reject(req.error);\n\t\t});\n\t}\n\n\tasync function tx<T>(mode: IDBTransactionMode, fn: (s: IDBObjectStore) => IDBRequest): Promise<T> {\n\t\tconst db = await open();\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst store = db.transaction(\"kv\", mode).objectStore(\"kv\");\n\t\t\tconst req = fn(store);\n\t\t\treq.onsuccess = () => resolve(req.result as T);\n\t\t\treq.onerror = () => reject(req.error);\n\t\t});\n\t}\n\n\treturn {\n\t\tasync get(key) {\n\t\t\treturn tx<unknown>(\"readonly\", (s) => s.get(key));\n\t\t},\n\t\tasync set(key, value) {\n\t\t\tawait tx(\"readwrite\", (s) => s.put(value, key));\n\t\t},\n\t\tasync delete(key) {\n\t\t\tawait tx(\"readwrite\", (s) => s.delete(key));\n\t\t},\n\t};\n}\n"]}
@@ -47,7 +47,8 @@ var Thread = class _Thread {
47
47
  */
48
48
  async maybeCompact(provider, options) {
49
49
  const threshold = options?.compactionThreshold ?? 0.9;
50
- const limit = provider.capabilities.maxInputTokens * threshold;
50
+ const caps = options?.modelCapabilities ?? provider.capabilities;
51
+ const limit = caps.maxInputTokens * threshold;
51
52
  if (estimateTokens(this.messages) < limit) return false;
52
53
  const summarizer = options?.compactionModel ?? provider;
53
54
  const system = this.messages.filter((m) => m.role === "system");
@@ -83,5 +84,5 @@ exports.estimateTokens = estimateTokens;
83
84
  exports.hasImage = hasImage;
84
85
  exports.messageText = messageText;
85
86
  exports.textMessage = textMessage;
86
- //# sourceMappingURL=chunk-LMN75W3W.cjs.map
87
- //# sourceMappingURL=chunk-LMN75W3W.cjs.map
87
+ //# sourceMappingURL=chunk-ILBKDEEL.cjs.map
88
+ //# sourceMappingURL=chunk-ILBKDEEL.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts","../src/agents/thread.ts"],"names":[],"mappings":";;;AAyDO,SAAS,WAAA,CAAY,MAAY,IAAA,EAAuB;AAC9D,EAAA,OAAO,EAAE,MAAM,KAAA,EAAO,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAE;AAChD;AAGO,SAAS,SAAS,OAAA,EAA2B;AACnD,EAAA,OAAO,QAAQ,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,OAAO,CAAA;AACpD;AAGO,SAAS,YAAY,OAAA,EAA0B;AACrD,EAAA,OAAO,QAAQ,KAAA,CACb,MAAA,CAAO,CAAC,CAAA,KAA2C,EAAE,IAAA,KAAS,MAAM,CAAA,CACpE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,CACjB,KAAK,EAAE,CAAA;AACV;;;ACjDO,SAAS,eAAe,QAAA,EAA6B;AAC3D,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,WAAA,CAAY,CAAC,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA;AACxE,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,KAAA,GAAQ,CAAC,CAAA;AAC3B;AAGO,IAAM,MAAA,GAAN,MAAM,OAAA,CAAO;AAAA,EACV,EAAA;AAAA,EACT,QAAA;AAAA;AAAA,EAEA,SAAA,GAAY,KAAA;AAAA,EAEZ,WAAA,CAAY,EAAA,EAAa,QAAA,GAAsB,EAAC,EAAG;AAClD,IAAA,IAAA,CAAK,EAAA,GAAK,MAAM,cAAA,EAAe;AAC/B,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EACjB;AAAA;AAAA,EAGA,IAAI,OAAA,EAAwB;AAC3B,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,OAAO,CAAA;AAAA,EAC3B;AAAA;AAAA,EAGA,MAAA,GAAkE;AACjE,IAAA,OAAO,EAAE,IAAI,IAAA,CAAK,EAAA,EAAI,UAAU,IAAA,CAAK,QAAA,EAAU,SAAA,EAAW,IAAA,CAAK,SAAA,EAAU;AAAA,EAC1E;AAAA;AAAA,EAGA,OAAO,SAAS,IAAA,EAAwE;AACvF,IAAA,MAAM,IAAI,IAAI,OAAA,CAAO,IAAA,CAAK,EAAA,EAAI,KAAK,QAAQ,CAAA;AAC3C,IAAA,CAAA,CAAE,SAAA,GAAY,KAAK,SAAA,IAAa,KAAA;AAChC,IAAA,OAAO,CAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YAAA,CAAa,QAAA,EAAoB,OAAA,EAA2C;AACjF,IAAA,MAAM,SAAA,GAAY,SAAS,mBAAA,IAAuB,GAAA;AAClD,IAAA,MAAM,IAAA,GAAO,OAAA,EAAS,iBAAA,IAAqB,QAAA,CAAS,YAAA;AACpD,IAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,GAAiB,SAAA;AACpC,IAAA,IAAI,cAAA,CAAe,IAAA,CAAK,QAAQ,CAAA,GAAI,OAAO,OAAO,KAAA;AAElD,IAAA,MAAM,UAAA,GAAa,SAAS,eAAA,IAAmB,QAAA;AAC/C,IAAA,MAAM,MAAA,GAAS,KAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,QAAQ,CAAA;AAC9D,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,KAAA,CAAM,EAAE,CAAA;AACrC,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,QAAQ,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAChF,IAAA,IAAI,WAAA,CAAY,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAErC,IAAA,MAAM,OAAA,GAAU,MAAM,UAAA,CAAW,QAAA,CAAS;AAAA,MACzC,QAAA,EAAU;AAAA,QACT,WAAA;AAAA,UACC,QAAA;AAAA,UACA;AAAA,SACD;AAAA,QACA,YAAY,MAAA,EAAQ,WAAA,CAAY,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,YAAY,CAAC,CAAC,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC;AAAA;AACtF,KACA,CAAA;AAED,IAAA,IAAA,CAAK,QAAA,GAAW;AAAA,MACf,GAAG,MAAA;AAAA,MACH,WAAA,CAAY,QAAA,EAAU,CAAA,iCAAA,EAAoC,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAA;AAAA,MACxE,GAAG;AAAA,KACJ;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACR;AACD;AAEA,SAAS,cAAA,GAAyB;AACjC,EAAA,MAAM,IAAK,UAAA,CAAmC,MAAA;AAC9C,EAAA,IAAI,CAAA,EAAG,UAAA,EAAY,OAAO,CAAA,CAAE,UAAA,EAAW;AACvC,EAAA,OAAO,CAAA,OAAA,EAAU,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,CAAA;AACnE","file":"chunk-ILBKDEEL.cjs","sourcesContent":["/**\n * Shared content, message, and model-capability types used across the framework.\n *\n * These are the lowest-level building blocks: every higher-level module (agents,\n * providers, tools, workflows) speaks in terms of {@link Message} and\n * {@link ContentPart}. Keeping them dependency-free keeps the core tree-shakeable.\n *\n * @packageDocumentation\n */\n\n/** A JSON Schema object (draft 2020-12 compatible), as popularized by MCP. */\nexport type JSONSchema = Record<string, unknown>;\n\n/** Role of a message in a conversation. */\nexport type Role = \"system\" | \"user\" | \"assistant\" | \"tool\";\n\n/** A single piece of message content. Images are only valid for vision-capable models. */\nexport type ContentPart =\n\t| { type: \"text\"; text: string }\n\t| { type: \"image\"; data: string; mimeType: string };\n\n/**\n * A conversation message.\n *\n * @example\n * ```ts\n * const msg: Message = { role: \"user\", parts: [{ type: \"text\", text: \"Hi\" }] };\n * ```\n */\nexport interface Message {\n\trole: Role;\n\tparts: ContentPart[];\n\t/** Optional tool-call linkage for assistant/tool messages. */\n\ttoolCallId?: string;\n\t/** Optional display name (e.g., the tool name for a tool message). */\n\tname?: string;\n}\n\n/**\n * Per-model capabilities supplied by the caller. The framework cannot reliably\n * discover these for arbitrary OpenAI-compatible/LM Studio models, so they are\n * provided explicitly. (FR-007a)\n */\nexport interface ModelCapabilities {\n\t/** Model id/name. */\n\tmodel: string;\n\t/** Maximum input/context tokens; drives compaction threshold. */\n\tmaxInputTokens: number;\n\t/** Maximum output tokens. */\n\tmaxOutputTokens: number;\n\t/** Whether the model accepts image input. Defaults to false. */\n\tsupportsVision?: boolean;\n\t/** Whether the model emits separate reasoning/thinking content. Defaults to false. */\n\tsupportsReasoning?: boolean;\n}\n\n/** Convenience: build a user message from a plain string. */\nexport function textMessage(role: Role, text: string): Message {\n\treturn { role, parts: [{ type: \"text\", text }] };\n}\n\n/** Returns true if a message contains any image content part. */\nexport function hasImage(message: Message): boolean {\n\treturn message.parts.some((p) => p.type === \"image\");\n}\n\n/** Extract the concatenated text from a message. */\nexport function messageText(message: Message): string {\n\treturn message.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 * Conversation thread with automatic compaction. When a thread approaches the\n * model's input-token budget it is summarized into a compact form so the\n * conversation can continue. (FR-004, FR-004a, FR-004b)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { messageText, textMessage } from \"../core/types.js\";\nimport type { Provider } from \"../providers/provider.js\";\n\n/** Options controlling a thread's compaction behavior. */\nexport interface ThreadOptions {\n\t/** Fraction of `maxInputTokens` at which compaction triggers. Default 0.9. */\n\tcompactionThreshold?: number;\n\t/** Provider used to summarize; defaults to the agent's own provider. (FR-004b) */\n\tcompactionModel?: Provider;\n\t/** Capabilities of the model in use; defaults to the provider's default model. */\n\tmodelCapabilities?: ModelCapabilities;\n}\n\n/** Rough token estimate (~4 chars/token) — avoids a tokenizer dependency. */\nexport function estimateTokens(messages: Message[]): number {\n\tconst chars = messages.reduce((sum, m) => sum + messageText(m).length, 0);\n\treturn Math.ceil(chars / 4);\n}\n\n/** A multi-turn conversation that preserves context and compacts when large. */\nexport class Thread {\n\treadonly id: string;\n\tmessages: Message[];\n\t/** Whether the thread has been compacted at least once. */\n\tcompacted = false;\n\n\tconstructor(id?: string, messages: Message[] = []) {\n\t\tthis.id = id ?? cryptoRandomId();\n\t\tthis.messages = messages;\n\t}\n\n\t/** Append a message. */\n\tadd(message: Message): void {\n\t\tthis.messages.push(message);\n\t}\n\n\t/** Serializable snapshot for persistence. */\n\ttoJSON(): { id: string; messages: Message[]; compacted: boolean } {\n\t\treturn { id: this.id, messages: this.messages, compacted: this.compacted };\n\t}\n\n\t/** Restore a thread from a snapshot. */\n\tstatic fromJSON(data: { id: string; messages: Message[]; compacted?: boolean }): Thread {\n\t\tconst t = new Thread(data.id, data.messages);\n\t\tt.compacted = data.compacted ?? false;\n\t\treturn t;\n\t}\n\n\t/**\n\t * Compact the thread if it exceeds the threshold. System messages and the most\n\t * recent turn are preserved; older turns are summarized via the model.\n\t *\n\t * @returns true if compaction occurred.\n\t */\n\tasync maybeCompact(provider: Provider, options?: ThreadOptions): Promise<boolean> {\n\t\tconst threshold = options?.compactionThreshold ?? 0.9;\n\t\tconst caps = options?.modelCapabilities ?? provider.capabilities;\n\t\tconst limit = caps.maxInputTokens * threshold;\n\t\tif (estimateTokens(this.messages) < limit) return false;\n\n\t\tconst summarizer = options?.compactionModel ?? provider;\n\t\tconst system = this.messages.filter((m) => m.role === \"system\");\n\t\tconst recent = this.messages.slice(-2);\n\t\tconst toSummarize = this.messages.filter((m) => m.role !== \"system\").slice(0, -2);\n\t\tif (toSummarize.length === 0) return false;\n\n\t\tconst summary = await summarizer.generate({\n\t\t\tmessages: [\n\t\t\t\ttextMessage(\n\t\t\t\t\t\"system\",\n\t\t\t\t\t\"Summarize the following conversation compactly, preserving facts, decisions, and open questions.\",\n\t\t\t\t),\n\t\t\t\ttextMessage(\"user\", toSummarize.map((m) => `${m.role}: ${messageText(m)}`).join(\"\\n\")),\n\t\t\t],\n\t\t});\n\n\t\tthis.messages = [\n\t\t\t...system,\n\t\t\ttextMessage(\"system\", `Summary of earlier conversation: ${summary.text}`),\n\t\t\t...recent,\n\t\t];\n\t\tthis.compacted = true;\n\t\treturn true;\n\t}\n}\n\nfunction cryptoRandomId(): string {\n\tconst c = (globalThis as { crypto?: Crypto }).crypto;\n\tif (c?.randomUUID) return c.randomUUID();\n\treturn `thread-${Math.random().toString(36).slice(2)}-${Date.now()}`;\n}\n"]}