@rarebit-one/harness-kernel 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +286 -0
  3. package/dist/agent.d.ts +71 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +258 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/connectors/mcpClient.d.ts +22 -0
  8. package/dist/connectors/mcpClient.d.ts.map +1 -0
  9. package/dist/connectors/mcpClient.js +63 -0
  10. package/dist/connectors/mcpClient.js.map +1 -0
  11. package/dist/context/types.d.ts +68 -0
  12. package/dist/context/types.d.ts.map +1 -0
  13. package/dist/context/types.js +43 -0
  14. package/dist/context/types.js.map +1 -0
  15. package/dist/engines/capability.d.ts +67 -0
  16. package/dist/engines/capability.d.ts.map +1 -0
  17. package/dist/engines/capability.js +73 -0
  18. package/dist/engines/capability.js.map +1 -0
  19. package/dist/engines/capabilityEmissions.d.ts +27 -0
  20. package/dist/engines/capabilityEmissions.d.ts.map +1 -0
  21. package/dist/engines/capabilityEmissions.js +37 -0
  22. package/dist/engines/capabilityEmissions.js.map +1 -0
  23. package/dist/engines/capabilityMcp.d.ts +23 -0
  24. package/dist/engines/capabilityMcp.d.ts.map +1 -0
  25. package/dist/engines/capabilityMcp.js +36 -0
  26. package/dist/engines/capabilityMcp.js.map +1 -0
  27. package/dist/engines/capabilityStdio.d.ts +46 -0
  28. package/dist/engines/capabilityStdio.d.ts.map +1 -0
  29. package/dist/engines/capabilityStdio.js +39 -0
  30. package/dist/engines/capabilityStdio.js.map +1 -0
  31. package/dist/engines/claudeCode.d.ts +73 -0
  32. package/dist/engines/claudeCode.d.ts.map +1 -0
  33. package/dist/engines/claudeCode.js +100 -0
  34. package/dist/engines/claudeCode.js.map +1 -0
  35. package/dist/engines/claudeCodeDriver.d.ts +14 -0
  36. package/dist/engines/claudeCodeDriver.d.ts.map +1 -0
  37. package/dist/engines/claudeCodeDriver.js +90 -0
  38. package/dist/engines/claudeCodeDriver.js.map +1 -0
  39. package/dist/engines/codex.d.ts +72 -0
  40. package/dist/engines/codex.d.ts.map +1 -0
  41. package/dist/engines/codex.js +157 -0
  42. package/dist/engines/codex.js.map +1 -0
  43. package/dist/engines/codexDriver.d.ts +43 -0
  44. package/dist/engines/codexDriver.d.ts.map +1 -0
  45. package/dist/engines/codexDriver.js +110 -0
  46. package/dist/engines/codexDriver.js.map +1 -0
  47. package/dist/engines/connectorMcp.d.ts +60 -0
  48. package/dist/engines/connectorMcp.d.ts.map +1 -0
  49. package/dist/engines/connectorMcp.js +137 -0
  50. package/dist/engines/connectorMcp.js.map +1 -0
  51. package/dist/engines/index.d.ts +33 -0
  52. package/dist/engines/index.d.ts.map +1 -0
  53. package/dist/engines/index.js +29 -0
  54. package/dist/engines/index.js.map +1 -0
  55. package/dist/engines/native.d.ts +55 -0
  56. package/dist/engines/native.d.ts.map +1 -0
  57. package/dist/engines/native.js +117 -0
  58. package/dist/engines/native.js.map +1 -0
  59. package/dist/engines/types.d.ts +107 -0
  60. package/dist/engines/types.d.ts.map +1 -0
  61. package/dist/engines/types.js +2 -0
  62. package/dist/engines/types.js.map +1 -0
  63. package/dist/events.d.ts +211 -0
  64. package/dist/events.d.ts.map +1 -0
  65. package/dist/events.js +69 -0
  66. package/dist/events.js.map +1 -0
  67. package/dist/index.d.ts +63 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +82 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/loop.d.ts +132 -0
  72. package/dist/loop.d.ts.map +1 -0
  73. package/dist/loop.js +77 -0
  74. package/dist/loop.js.map +1 -0
  75. package/dist/models/chat.d.ts +65 -0
  76. package/dist/models/chat.d.ts.map +1 -0
  77. package/dist/models/chat.js +66 -0
  78. package/dist/models/chat.js.map +1 -0
  79. package/dist/models/middleware.d.ts +63 -0
  80. package/dist/models/middleware.d.ts.map +1 -0
  81. package/dist/models/middleware.js +139 -0
  82. package/dist/models/middleware.js.map +1 -0
  83. package/dist/models/registry.d.ts +78 -0
  84. package/dist/models/registry.d.ts.map +1 -0
  85. package/dist/models/registry.js +0 -0
  86. package/dist/models/registry.js.map +1 -0
  87. package/dist/models/types.d.ts +149 -0
  88. package/dist/models/types.d.ts.map +1 -0
  89. package/dist/models/types.js +64 -0
  90. package/dist/models/types.js.map +1 -0
  91. package/dist/primitives/codeExec.d.ts +25 -0
  92. package/dist/primitives/codeExec.d.ts.map +1 -0
  93. package/dist/primitives/codeExec.js +69 -0
  94. package/dist/primitives/codeExec.js.map +1 -0
  95. package/dist/primitives/download.d.ts +19 -0
  96. package/dist/primitives/download.d.ts.map +1 -0
  97. package/dist/primitives/download.js +113 -0
  98. package/dist/primitives/download.js.map +1 -0
  99. package/dist/primitives/fs.d.ts +5 -0
  100. package/dist/primitives/fs.d.ts.map +1 -0
  101. package/dist/primitives/fs.js +59 -0
  102. package/dist/primitives/fs.js.map +1 -0
  103. package/dist/primitives/http.d.ts +100 -0
  104. package/dist/primitives/http.d.ts.map +1 -0
  105. package/dist/primitives/http.js +257 -0
  106. package/dist/primitives/http.js.map +1 -0
  107. package/dist/providers/anthropic.d.ts +15 -0
  108. package/dist/providers/anthropic.d.ts.map +1 -0
  109. package/dist/providers/anthropic.js +90 -0
  110. package/dist/providers/anthropic.js.map +1 -0
  111. package/dist/providers/clientOptions.d.ts +14 -0
  112. package/dist/providers/clientOptions.d.ts.map +1 -0
  113. package/dist/providers/clientOptions.js +26 -0
  114. package/dist/providers/clientOptions.js.map +1 -0
  115. package/dist/providers/index.d.ts +24 -0
  116. package/dist/providers/index.d.ts.map +1 -0
  117. package/dist/providers/index.js +51 -0
  118. package/dist/providers/index.js.map +1 -0
  119. package/dist/providers/mock.d.ts +25 -0
  120. package/dist/providers/mock.d.ts.map +1 -0
  121. package/dist/providers/mock.js +85 -0
  122. package/dist/providers/mock.js.map +1 -0
  123. package/dist/providers/openai.d.ts +32 -0
  124. package/dist/providers/openai.d.ts.map +1 -0
  125. package/dist/providers/openai.js +118 -0
  126. package/dist/providers/openai.js.map +1 -0
  127. package/dist/providers/openrouter.d.ts +29 -0
  128. package/dist/providers/openrouter.d.ts.map +1 -0
  129. package/dist/providers/openrouter.js +35 -0
  130. package/dist/providers/openrouter.js.map +1 -0
  131. package/dist/providers/types.d.ts +60 -0
  132. package/dist/providers/types.d.ts.map +1 -0
  133. package/dist/providers/types.js +2 -0
  134. package/dist/providers/types.js.map +1 -0
  135. package/dist/routing/staticResolver.d.ts +41 -0
  136. package/dist/routing/staticResolver.d.ts.map +1 -0
  137. package/dist/routing/staticResolver.js +67 -0
  138. package/dist/routing/staticResolver.js.map +1 -0
  139. package/dist/routing/types.d.ts +72 -0
  140. package/dist/routing/types.d.ts.map +1 -0
  141. package/dist/routing/types.js +11 -0
  142. package/dist/routing/types.js.map +1 -0
  143. package/dist/secrets.d.ts +8 -0
  144. package/dist/secrets.d.ts.map +1 -0
  145. package/dist/secrets.js +14 -0
  146. package/dist/secrets.js.map +1 -0
  147. package/dist/tools/metadata.d.ts +93 -0
  148. package/dist/tools/metadata.d.ts.map +1 -0
  149. package/dist/tools/metadata.js +49 -0
  150. package/dist/tools/metadata.js.map +1 -0
  151. package/dist/tools/modelTool.d.ts +35 -0
  152. package/dist/tools/modelTool.d.ts.map +1 -0
  153. package/dist/tools/modelTool.js +37 -0
  154. package/dist/tools/modelTool.js.map +1 -0
  155. package/dist/tools/registry.d.ts +65 -0
  156. package/dist/tools/registry.d.ts.map +1 -0
  157. package/dist/tools/registry.js +166 -0
  158. package/dist/tools/registry.js.map +1 -0
  159. package/dist/types.d.ts +71 -0
  160. package/dist/types.d.ts.map +1 -0
  161. package/dist/types.js +10 -0
  162. package/dist/types.js.map +1 -0
  163. package/package.json +72 -0
@@ -0,0 +1,25 @@
1
+ import type { CompletionRequest, ConverseRequest, ConverseResult, Provider } from "./types.js";
2
+ import type { ProviderSelection } from "./index.js";
3
+ /**
4
+ * Deterministic, offline provider. Used when no API key is configured — or when a
5
+ * workflow explicitly asks for `preferred: mock` — so the end-to-end loop (and
6
+ * tests) run without network access or credentials.
7
+ *
8
+ * It cannot call a model, but it is handed the SAME provider selection a real
9
+ * provider would receive (the resolved per-run model + per-org BYO keys) and
10
+ * self-documents what a real run WOULD have used. That makes model/key
11
+ * resolution OBSERVABLE offline — a caller's e2e harness can read it back out of
12
+ * the run's output artifact to assert key precedence. It never echoes a key,
13
+ * only its last-4 marker.
14
+ */
15
+ export declare class MockProvider implements Provider {
16
+ readonly name = "mock";
17
+ private readonly selection;
18
+ constructor(selection?: ProviderSelection);
19
+ private resolvedModel;
20
+ private byoKeyMarker;
21
+ private selectionLines;
22
+ complete(req: CompletionRequest): Promise<string>;
23
+ converse(req: ConverseRequest): Promise<ConverseResult>;
24
+ }
25
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/providers/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC9F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD;;;;;;;;;;;GAWG;AACH,qBAAa,YAAa,YAAW,QAAQ;IAC3C,QAAQ,CAAC,IAAI,UAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;gBAEjC,SAAS,GAAE,iBAAsB;IAS7C,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,cAAc;IAWtB,QAAQ,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB3C,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CAS9D"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Deterministic, offline provider. Used when no API key is configured — or when a
3
+ * workflow explicitly asks for `preferred: mock` — so the end-to-end loop (and
4
+ * tests) run without network access or credentials.
5
+ *
6
+ * It cannot call a model, but it is handed the SAME provider selection a real
7
+ * provider would receive (the resolved per-run model + per-org BYO keys) and
8
+ * self-documents what a real run WOULD have used. That makes model/key
9
+ * resolution OBSERVABLE offline — a caller's e2e harness can read it back out of
10
+ * the run's output artifact to assert key precedence. It never echoes a key,
11
+ * only its last-4 marker.
12
+ */
13
+ export class MockProvider {
14
+ name = "mock";
15
+ selection;
16
+ constructor(selection = {}) {
17
+ this.selection = selection;
18
+ }
19
+ // "What a real provider would have used" for the model: the model the caller
20
+ // resolved (workflow YAML → org default), else the host's
21
+ // env-default model (the SAME env vars the real providers read), else
22
+ // the provider's built-in default. `source` labels which rung of that fallback
23
+ // won, so the offline observer can tell the org-default case from the env case.
24
+ resolvedModel() {
25
+ if (this.selection.model)
26
+ return { value: this.selection.model, source: "resolved" };
27
+ const envModel = process.env.ANTHROPIC_MODEL ?? process.env.OPENAI_MODEL ?? process.env.OPENROUTER_MODEL;
28
+ if (envModel)
29
+ return { value: envModel, source: "runner env default" };
30
+ return { value: "(provider built-in default)", source: "provider built-in default" };
31
+ }
32
+ // Which per-org BYO key WOULD have been threaded, by masked last-4 ONLY — never
33
+ // the key itself. `(none …)` means the org set no key for that provider, so the
34
+ // runner's own env key would be used.
35
+ byoKeyMarker() {
36
+ const creds = this.selection.credentials ?? {};
37
+ const present = ["anthropic", "openai", "openrouter"]
38
+ .filter((p) => creds[p])
39
+ .map((p) => `${p}:…${creds[p].slice(-4)}`);
40
+ return present.length ? present.join(", ") : "(none — runner env key would be used)";
41
+ }
42
+ // The block the e2e harness parses out of output.md. Deterministic and offline.
43
+ selectionLines() {
44
+ const model = this.resolvedModel();
45
+ return [
46
+ "## Provider selection (mock — dry run)",
47
+ "",
48
+ `model: ${model.value} (${model.source}; would be used)`,
49
+ `org BYO key: ${this.byoKeyMarker()}`,
50
+ "",
51
+ ];
52
+ }
53
+ complete(req) {
54
+ const preview = req.prompt.slice(0, 600);
55
+ return Promise.resolve([
56
+ "# Workflow Output (mock provider)",
57
+ "",
58
+ "_Generated offline by the harness-kernel mock provider. Set ANTHROPIC_API_KEY",
59
+ "or OPENAI_API_KEY to use a real model._",
60
+ "",
61
+ ...this.selectionLines(),
62
+ "## System",
63
+ "",
64
+ req.system,
65
+ "",
66
+ "## Context + Inputs (excerpt)",
67
+ "",
68
+ "```",
69
+ preview,
70
+ "```",
71
+ ].join("\n"));
72
+ }
73
+ // The mock never calls tools, so the agent loop terminates after one turn. It
74
+ // echoes which tools were available, which is handy when running offline.
75
+ async converse(req) {
76
+ const lastUser = [...req.messages].reverse().find((m) => m.role === "user");
77
+ const prompt = lastUser && lastUser.role === "user" ? lastUser.text : "";
78
+ const text = await this.complete({
79
+ system: `${req.system}\n\nAvailable tools: ${req.tools.map((t) => t.name).join(", ") || "(none)"}`,
80
+ prompt,
81
+ });
82
+ return { text, toolCalls: [] };
83
+ }
84
+ }
85
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/providers/mock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import OpenAI from "openai";
2
+ import type { AgentMessage, CompletionRequest, ConverseRequest, ConverseResult, Provider } from "./types.js";
3
+ /** Map provider-neutral messages to OpenAI chat messages (pure; tested). */
4
+ export declare function toOpenAIMessages(messages: AgentMessage[]): OpenAI.Chat.Completions.ChatCompletionMessageParam[];
5
+ /** Reduce an OpenAI response message to text + tool calls (pure; tested). */
6
+ export declare function parseOpenAIMessage(message: OpenAI.Chat.Completions.ChatCompletionMessage): ConverseResult;
7
+ /** Constructor options for an OpenAI-compatible (chat.completions) provider. */
8
+ export interface OpenAICompatibleOptions {
9
+ apiKey: string;
10
+ model: string;
11
+ /** Alternate chat.completions endpoint (e.g. OpenRouter); omit for api.openai.com. */
12
+ baseURL?: string;
13
+ /** Extra headers sent on every request (e.g. OpenRouter attribution). */
14
+ defaultHeaders?: Record<string, string>;
15
+ }
16
+ /**
17
+ * Shared core for providers speaking the OpenAI chat.completions dialect
18
+ * (including tools). OpenAI proper and OpenRouter both instantiate this —
19
+ * they differ only in name, endpoint, headers, and env defaults.
20
+ */
21
+ export declare class OpenAICompatibleProvider implements Provider {
22
+ readonly name: string;
23
+ private client;
24
+ private model;
25
+ constructor(name: string, opts: OpenAICompatibleOptions);
26
+ complete(req: CompletionRequest): Promise<string>;
27
+ converse(req: ConverseRequest): Promise<ConverseResult>;
28
+ }
29
+ export declare class OpenAIProvider extends OpenAICompatibleProvider {
30
+ constructor(apiKey: string, model?: string);
31
+ }
32
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,QAAQ,EAET,MAAM,YAAY,CAAA;AAEnB,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,YAAY,EAAE,GACvB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CA0BtD;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,qBAAqB,GACrD,cAAc,CAchB;AAaD,gFAAgF;AAChF,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC;AAED;;;;GAIG;AACH,qBAAa,wBAAyB,YAAW,QAAQ;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,KAAK,CAAQ;gBAET,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB;IAejD,QAAQ,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAajD,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CAiB9D;AAED,qBAAa,cAAe,SAAQ,wBAAwB;gBAC9C,MAAM,EAAE,MAAM,EAAE,KAAK,SAAwC;CAG1E"}
@@ -0,0 +1,118 @@
1
+ import OpenAI from "openai";
2
+ import { maxTokens, providerMaxRetries, providerTimeoutMs } from "./clientOptions.js";
3
+ /** Map provider-neutral messages to OpenAI chat messages (pure; tested). */
4
+ export function toOpenAIMessages(messages) {
5
+ const out = [];
6
+ for (const m of messages) {
7
+ if (m.role === "user") {
8
+ out.push({ role: "user", content: m.text });
9
+ }
10
+ else if (m.role === "assistant") {
11
+ const msg = {
12
+ role: "assistant",
13
+ content: m.text,
14
+ };
15
+ if (m.toolCalls.length > 0) {
16
+ msg.tool_calls = m.toolCalls.map((tc) => ({
17
+ id: tc.id,
18
+ type: "function",
19
+ function: { name: tc.name, arguments: JSON.stringify(tc.input) },
20
+ }));
21
+ }
22
+ out.push(msg);
23
+ }
24
+ else {
25
+ // Each tool result becomes its own `tool` message keyed by the call id.
26
+ for (const r of m.results) {
27
+ out.push({ role: "tool", tool_call_id: r.toolCallId, content: r.content });
28
+ }
29
+ }
30
+ }
31
+ return out;
32
+ }
33
+ /** Reduce an OpenAI response message to text + tool calls (pure; tested). */
34
+ export function parseOpenAIMessage(message) {
35
+ // Surface a refusal as text so a refused turn is distinguishable from a normal
36
+ // empty-but-final one (otherwise the agent loop ends silently with no signal).
37
+ const text = message.content ?? (message.refusal ? `Refused: ${message.refusal}` : "");
38
+ const toolCalls = [];
39
+ for (const tc of message.tool_calls ?? []) {
40
+ if (tc.type !== "function")
41
+ continue;
42
+ toolCalls.push({
43
+ id: tc.id,
44
+ name: tc.function.name,
45
+ input: parseArguments(tc.function.arguments),
46
+ });
47
+ }
48
+ return { text, toolCalls };
49
+ }
50
+ /** Parse a tool-call arguments JSON string, tolerating empty/invalid input. */
51
+ function parseArguments(raw) {
52
+ if (!raw)
53
+ return {};
54
+ try {
55
+ const parsed = JSON.parse(raw);
56
+ return parsed && typeof parsed === "object" ? parsed : {};
57
+ }
58
+ catch {
59
+ return {};
60
+ }
61
+ }
62
+ /**
63
+ * Shared core for providers speaking the OpenAI chat.completions dialect
64
+ * (including tools). OpenAI proper and OpenRouter both instantiate this —
65
+ * they differ only in name, endpoint, headers, and env defaults.
66
+ */
67
+ export class OpenAICompatibleProvider {
68
+ name;
69
+ client;
70
+ model;
71
+ constructor(name, opts) {
72
+ // The SDK retries transient 429/5xx/network errors with exponential backoff
73
+ // internally, so a blip doesn't fail the whole run; `timeout` bounds each
74
+ // request. Both are env-overridable.
75
+ this.name = name;
76
+ this.client = new OpenAI({
77
+ apiKey: opts.apiKey,
78
+ timeout: providerTimeoutMs(),
79
+ maxRetries: providerMaxRetries(),
80
+ ...(opts.baseURL !== undefined ? { baseURL: opts.baseURL } : {}),
81
+ ...(opts.defaultHeaders !== undefined ? { defaultHeaders: opts.defaultHeaders } : {}),
82
+ });
83
+ this.model = opts.model;
84
+ }
85
+ async complete(req) {
86
+ const completion = await this.client.chat.completions.create({
87
+ model: this.model,
88
+ max_tokens: maxTokens(), // match AnthropicProvider rather than the model default
89
+ messages: [
90
+ { role: "system", content: req.system },
91
+ { role: "user", content: req.prompt },
92
+ ],
93
+ });
94
+ return completion.choices[0]?.message?.content ?? "";
95
+ }
96
+ async converse(req) {
97
+ const tools = req.tools.map((t) => ({
98
+ type: "function",
99
+ function: { name: t.name, description: t.description, parameters: t.inputSchema },
100
+ }));
101
+ const completion = await this.client.chat.completions.create({
102
+ model: this.model,
103
+ max_tokens: maxTokens(), // match AnthropicProvider rather than the model default
104
+ messages: [{ role: "system", content: req.system }, ...toOpenAIMessages(req.messages)],
105
+ ...(tools.length > 0 ? { tools } : {}),
106
+ });
107
+ const message = completion.choices[0]?.message;
108
+ if (!message)
109
+ return { text: "", toolCalls: [] };
110
+ return parseOpenAIMessage(message);
111
+ }
112
+ }
113
+ export class OpenAIProvider extends OpenAICompatibleProvider {
114
+ constructor(apiKey, model = process.env.OPENAI_MODEL ?? "gpt-4.1") {
115
+ super("openai", { apiKey, model });
116
+ }
117
+ }
118
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { OpenAICompatibleProvider } from "./openai.js";
2
+ export declare const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
3
+ /**
4
+ * Default model when neither the payload nor OPENROUTER_MODEL specifies one.
5
+ * OpenRouter model ids are provider-namespaced (`anthropic/...`, `openai/...`)
6
+ * and pass through to the API untouched.
7
+ */
8
+ export declare const OPENROUTER_DEFAULT_MODEL = "anthropic/claude-sonnet-4.5";
9
+ /**
10
+ * The optional attribution OpenRouter's convention asks apps to send, used for
11
+ * its public rankings. The kernel has no app identity of its own, so it sends
12
+ * nothing unless the embedding application supplies one.
13
+ */
14
+ export interface OpenRouterAttribution {
15
+ /** App URL, sent as the `HTTP-Referer` header. */
16
+ referer?: string;
17
+ /** App name, sent as the `X-Title` header. */
18
+ title?: string;
19
+ }
20
+ /**
21
+ * OpenRouter speaks the OpenAI chat.completions dialect (including tools), so
22
+ * this is the shared OpenAI-compatible core pointed at openrouter.ai. Pass
23
+ * `attribution` to identify your app in OpenRouter's rankings; omit it and no
24
+ * attribution headers are sent.
25
+ */
26
+ export declare class OpenRouterProvider extends OpenAICompatibleProvider {
27
+ constructor(apiKey: string, model?: string, attribution?: OpenRouterAttribution);
28
+ }
29
+ //# sourceMappingURL=openrouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEtD,eAAO,MAAM,mBAAmB,iCAAiC,CAAA;AAEjE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,gCAAgC,CAAA;AAErE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAUD;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,wBAAwB;gBAE5D,MAAM,EAAE,MAAM,EACd,KAAK,SAA2D,EAChE,WAAW,GAAE,qBAA0B;CAU1C"}
@@ -0,0 +1,35 @@
1
+ import { OpenAICompatibleProvider } from "./openai.js";
2
+ export const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
3
+ /**
4
+ * Default model when neither the payload nor OPENROUTER_MODEL specifies one.
5
+ * OpenRouter model ids are provider-namespaced (`anthropic/...`, `openai/...`)
6
+ * and pass through to the API untouched.
7
+ */
8
+ export const OPENROUTER_DEFAULT_MODEL = "anthropic/claude-sonnet-4.5";
9
+ /** Build the attribution headers, omitting any the caller left unset. */
10
+ function attributionHeaders(attribution) {
11
+ const headers = {};
12
+ if (attribution.referer)
13
+ headers["HTTP-Referer"] = attribution.referer;
14
+ if (attribution.title)
15
+ headers["X-Title"] = attribution.title;
16
+ return headers;
17
+ }
18
+ /**
19
+ * OpenRouter speaks the OpenAI chat.completions dialect (including tools), so
20
+ * this is the shared OpenAI-compatible core pointed at openrouter.ai. Pass
21
+ * `attribution` to identify your app in OpenRouter's rankings; omit it and no
22
+ * attribution headers are sent.
23
+ */
24
+ export class OpenRouterProvider extends OpenAICompatibleProvider {
25
+ constructor(apiKey, model = process.env.OPENROUTER_MODEL ?? OPENROUTER_DEFAULT_MODEL, attribution = {}) {
26
+ const headers = attributionHeaders(attribution);
27
+ super("openrouter", {
28
+ apiKey,
29
+ model,
30
+ baseURL: OPENROUTER_BASE_URL,
31
+ ...(Object.keys(headers).length > 0 ? { defaultHeaders: headers } : {}),
32
+ });
33
+ }
34
+ }
35
+ //# sourceMappingURL=openrouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAA;AAEjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,6BAA6B,CAAA;AAcrE,yEAAyE;AACzE,SAAS,kBAAkB,CAAC,WAAkC;IAC5D,MAAM,OAAO,GAA2B,EAAE,CAAA;IAC1C,IAAI,WAAW,CAAC,OAAO;QAAE,OAAO,CAAC,cAAc,CAAC,GAAG,WAAW,CAAC,OAAO,CAAA;IACtE,IAAI,WAAW,CAAC,KAAK;QAAE,OAAO,CAAC,SAAS,CAAC,GAAG,WAAW,CAAC,KAAK,CAAA;IAC7D,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,kBAAmB,SAAQ,wBAAwB;IAC9D,YACE,MAAc,EACd,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,wBAAwB,EAChE,cAAqC,EAAE;QAEvC,MAAM,OAAO,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAA;QAC/C,KAAK,CAAC,YAAY,EAAE;YAClB,MAAM;YACN,KAAK;YACL,OAAO,EAAE,mBAAmB;YAC5B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,60 @@
1
+ export interface CompletionRequest {
2
+ system: string;
3
+ prompt: string;
4
+ }
5
+ /** A tool offered to the model, described by a JSON-Schema input shape. */
6
+ export interface ToolSpec {
7
+ name: string;
8
+ description: string;
9
+ inputSchema: Record<string, unknown>;
10
+ }
11
+ /** The model's request to invoke a tool. */
12
+ export interface ToolCall {
13
+ id: string;
14
+ name: string;
15
+ input: Record<string, unknown>;
16
+ }
17
+ /** The reply to a ToolCall. */
18
+ export interface ToolResult {
19
+ toolCallId: string;
20
+ /** The string projection sent to the model — the only part a provider serializes. */
21
+ content: string;
22
+ /**
23
+ * The typed payload `content` was projected from, when the tool produced one.
24
+ * Providers ignore it; callers and clients read it to avoid re-parsing a
25
+ * struct back out of the string.
26
+ */
27
+ structured?: unknown;
28
+ isError?: boolean;
29
+ }
30
+ /** Provider-neutral conversation turn (mapped to each provider's wire format). */
31
+ export type AgentMessage = {
32
+ role: "user";
33
+ text: string;
34
+ } | {
35
+ role: "assistant";
36
+ text: string;
37
+ toolCalls: ToolCall[];
38
+ } | {
39
+ role: "tool";
40
+ results: ToolResult[];
41
+ };
42
+ export interface ConverseRequest {
43
+ system: string;
44
+ messages: AgentMessage[];
45
+ tools: ToolSpec[];
46
+ }
47
+ export interface ConverseResult {
48
+ /** Assistant prose for this turn (may be empty when it only calls tools). */
49
+ text: string;
50
+ /** Tools the model wants run; empty means the turn is final. */
51
+ toolCalls: ToolCall[];
52
+ }
53
+ export interface Provider {
54
+ readonly name: string;
55
+ /** One-shot completion (no tools) — kept for simple callers. */
56
+ complete(req: CompletionRequest): Promise<string>;
57
+ /** One step of a tool-use conversation; the agent loop drives the rest. */
58
+ converse(req: ConverseRequest): Promise<ConverseResult>;
59
+ }
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,2EAA2E;AAC3E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC;AAED,4CAA4C;AAC5C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,+BAA+B;AAC/B,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,kFAAkF;AAClF,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,QAAQ,EAAE,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,CAAA;AAE3C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,KAAK,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAA;IACZ,gEAAgE;IAChE,SAAS,EAAE,QAAQ,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;CACxD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,41 @@
1
+ import { type CapabilityDefinition, type ResolvedRoute, type RouteContext, type RouteResolver } from "./types.js";
2
+ /**
3
+ * The kernel's built-in resolver: capabilities as code.
4
+ *
5
+ * It takes a list of {@link CapabilityDefinition}s — from a literal, a JSON
6
+ * file, environment config, anything the application already has — and resolves
7
+ * names against them in memory. No database, no migration, no service to stand
8
+ * up. That matters beyond convenience: it means the whole seam is exercisable
9
+ * in a unit test, and an application that never wants dynamic routing never
10
+ * needs any infrastructure at all.
11
+ *
12
+ * An application that *does* want dynamic routing writes its own
13
+ * {@link RouteResolver} against the same interface. That adapter — with its
14
+ * tables, its prompt versioning, its per-tenant overrides — lives in the app
15
+ * layer. It does not live here.
16
+ */
17
+ export declare class StaticRouteResolver implements RouteResolver {
18
+ readonly name = "static";
19
+ private readonly definitions;
20
+ constructor(definitions?: CapabilityDefinition[]);
21
+ /**
22
+ * Add or replace a capability. Unlike the model registry, redefinition is
23
+ * allowed: a resolver is configuration, and layering a config file over a
24
+ * built-in default is a normal thing to want.
25
+ */
26
+ define(definition: CapabilityDefinition): this;
27
+ has(capability: string): boolean;
28
+ /** Every defined capability name. */
29
+ capabilities(): string[];
30
+ /**
31
+ * Resolve a name to its route, filling defaults for the optional parts so
32
+ * callers get a fully-determined {@link ResolvedRoute}. Throws
33
+ * {@link UnknownCapabilityError} when the name isn't defined.
34
+ *
35
+ * `ctx` is accepted for interface parity and ignored here — static routing is
36
+ * by definition context-free. A resolver that varies by invocation mode or
37
+ * tenant is exactly the app-layer adapter this interface exists to admit.
38
+ */
39
+ resolve(capability: string, _ctx?: RouteContext): Promise<ResolvedRoute>;
40
+ }
41
+ //# sourceMappingURL=staticResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staticResolver.d.ts","sourceRoot":"","sources":["../../src/routing/staticResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IACvD,QAAQ,CAAC,IAAI,YAAW;IAExB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0C;gBAE1D,WAAW,GAAE,oBAAoB,EAAO;IAIpD;;;;OAIG;IACH,MAAM,CAAC,UAAU,EAAE,oBAAoB,GAAG,IAAI;IAK9C,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAIhC,qCAAqC;IACrC,YAAY,IAAI,MAAM,EAAE;IAIxB;;;;;;;;OAQG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAkBzE"}
@@ -0,0 +1,67 @@
1
+ import { UnknownCapabilityError, } from "./types.js";
2
+ /**
3
+ * The kernel's built-in resolver: capabilities as code.
4
+ *
5
+ * It takes a list of {@link CapabilityDefinition}s — from a literal, a JSON
6
+ * file, environment config, anything the application already has — and resolves
7
+ * names against them in memory. No database, no migration, no service to stand
8
+ * up. That matters beyond convenience: it means the whole seam is exercisable
9
+ * in a unit test, and an application that never wants dynamic routing never
10
+ * needs any infrastructure at all.
11
+ *
12
+ * An application that *does* want dynamic routing writes its own
13
+ * {@link RouteResolver} against the same interface. That adapter — with its
14
+ * tables, its prompt versioning, its per-tenant overrides — lives in the app
15
+ * layer. It does not live here.
16
+ */
17
+ export class StaticRouteResolver {
18
+ name = "static";
19
+ definitions = new Map();
20
+ constructor(definitions = []) {
21
+ for (const definition of definitions)
22
+ this.define(definition);
23
+ }
24
+ /**
25
+ * Add or replace a capability. Unlike the model registry, redefinition is
26
+ * allowed: a resolver is configuration, and layering a config file over a
27
+ * built-in default is a normal thing to want.
28
+ */
29
+ define(definition) {
30
+ this.definitions.set(definition.name, definition);
31
+ return this;
32
+ }
33
+ has(capability) {
34
+ return this.definitions.has(capability);
35
+ }
36
+ /** Every defined capability name. */
37
+ capabilities() {
38
+ return [...this.definitions.keys()];
39
+ }
40
+ /**
41
+ * Resolve a name to its route, filling defaults for the optional parts so
42
+ * callers get a fully-determined {@link ResolvedRoute}. Throws
43
+ * {@link UnknownCapabilityError} when the name isn't defined.
44
+ *
45
+ * `ctx` is accepted for interface parity and ignored here — static routing is
46
+ * by definition context-free. A resolver that varies by invocation mode or
47
+ * tenant is exactly the app-layer adapter this interface exists to admit.
48
+ */
49
+ resolve(capability, _ctx) {
50
+ const definition = this.definitions.get(capability);
51
+ if (!definition) {
52
+ // Rejected, not thrown: the interface promises a Promise, and a caller
53
+ // that attached `.catch()` instead of awaiting would otherwise be hit by
54
+ // a synchronous throw it never had a chance to handle.
55
+ return Promise.reject(new UnknownCapabilityError(capability, this.capabilities()));
56
+ }
57
+ return Promise.resolve({
58
+ capability: definition.name,
59
+ model: definition.model,
60
+ prompt: definition.prompt ?? "",
61
+ tools: definition.tools ?? [],
62
+ limits: definition.limits ?? {},
63
+ ...(definition.meta ? { meta: definition.meta } : {}),
64
+ });
65
+ }
66
+ }
67
+ //# sourceMappingURL=staticResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staticResolver.js","sourceRoot":"","sources":["../../src/routing/staticResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAKvB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,mBAAmB;IACrB,IAAI,GAAG,QAAQ,CAAA;IAEP,WAAW,GAAG,IAAI,GAAG,EAAgC,CAAA;IAEtE,YAAY,cAAsC,EAAE;QAClD,KAAK,MAAM,UAAU,IAAI,WAAW;YAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IAC/D,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,UAAgC;QACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QACjD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,GAAG,CAAC,UAAkB;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACzC,CAAC;IAED,qCAAqC;IACrC,YAAY;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAA;IACrC,CAAC;IAED;;;;;;;;OAQG;IACH,OAAO,CAAC,UAAkB,EAAE,IAAmB;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACnD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,uEAAuE;YACvE,yEAAyE;YACzE,uDAAuD;YACvD,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,sBAAsB,CAAC,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;QACpF,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,UAAU,EAAE,UAAU,CAAC,IAAI;YAC3B,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,EAAE;YAC/B,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,EAAE;YAC/B,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,72 @@
1
+ import type { ModelRef } from "../models/registry.js";
2
+ import type { InvocationMode } from "../tools/metadata.js";
3
+ /**
4
+ * Route resolution: "which model, prompt and tools should capability X use?"
5
+ *
6
+ * This sits **one layer above** the model registry. A resolver picks the whole
7
+ * bundle for a named capability; the {@link ModelRef} it returns is then bound
8
+ * to a concrete implementation by `ModelRegistry.resolve`. The two are not the
9
+ * same question and must not be conflated:
10
+ *
11
+ * resolver: "summarise-thread" → { model: chat:anthropic, prompt, tools }
12
+ * registry: { kind: "chat", id: "anthropic" } → the ModelInvocation
13
+ *
14
+ * The kernel ships exactly one resolver — {@link StaticRouteResolver}, backed by
15
+ * plain code or config, usable with zero infrastructure. A database-backed
16
+ * resolver is an **app-layer adapter behind this interface**, never a kernel
17
+ * concern: the kernel has no database, no schema and no control plane, and the
18
+ * moment a field here exists only to serve one product's tables, this seam has
19
+ * drifted across the line.
20
+ */
21
+ /** A capability as declared by the application: the bundle, before resolution. */
22
+ export interface CapabilityDefinition {
23
+ /** The name callers route by. */
24
+ name: string;
25
+ /** Which model kind + id serves it. */
26
+ model: ModelRef;
27
+ /** System prompt for the capability. */
28
+ prompt?: string;
29
+ /** Tool names this capability may use; absent means "no restriction". */
30
+ tools?: string[];
31
+ /** Budgets an engine or loop should honour. */
32
+ limits?: RouteLimits;
33
+ /** Free-form application detail carried through resolution untouched. */
34
+ meta?: Record<string, unknown>;
35
+ }
36
+ export interface RouteLimits {
37
+ maxSteps?: number;
38
+ maxDurationMs?: number;
39
+ }
40
+ /** What a resolver returns: a fully-determined route for one capability. */
41
+ export interface ResolvedRoute {
42
+ capability: string;
43
+ model: ModelRef;
44
+ prompt: string;
45
+ tools: string[];
46
+ limits: RouteLimits;
47
+ meta?: Record<string, unknown>;
48
+ }
49
+ /**
50
+ * The little a resolver is told about the call site. Deliberately thin — the
51
+ * moment this grows product-shaped fields, resolution has stopped being generic.
52
+ */
53
+ export interface RouteContext {
54
+ /** How the turn was invoked; a resolver may route differently per mode. */
55
+ mode?: InvocationMode;
56
+ correlationId?: string;
57
+ }
58
+ /** Thrown when a capability name has no route. */
59
+ export declare class UnknownCapabilityError extends Error {
60
+ readonly capability: string;
61
+ constructor(capability: string, known: string[]);
62
+ }
63
+ /**
64
+ * Resolves a capability name to a route. Implementations must **fail loud** on
65
+ * an unknown capability rather than returning a default — a silently-defaulted
66
+ * route sends traffic to the wrong model with no signal.
67
+ */
68
+ export interface RouteResolver {
69
+ readonly name: string;
70
+ resolve(capability: string, ctx?: RouteContext): Promise<ResolvedRoute>;
71
+ }
72
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D;;;;;;;;;;;;;;;;;GAiBG;AAEH,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,KAAK,EAAE,QAAQ,CAAA;IACf,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,QAAQ,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,WAAW,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,kDAAkD;AAClD,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;gBAEf,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CAMhD;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CACxE"}
@@ -0,0 +1,11 @@
1
+ /** Thrown when a capability name has no route. */
2
+ export class UnknownCapabilityError extends Error {
3
+ capability;
4
+ constructor(capability, known) {
5
+ const alternatives = known.length > 0 ? known.join(", ") : "(none defined)";
6
+ super(`no route defined for capability "${capability}" — defined: ${alternatives}`);
7
+ this.name = "UnknownCapabilityError";
8
+ this.capability = capability;
9
+ }
10
+ }
11
+ //# sourceMappingURL=types.js.map