theorum 0.1.14 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/README.md +178 -89
  2. package/esm/mod.d.ts +21 -11
  3. package/esm/mod.js +15 -8
  4. package/esm/src/cli/commands/bench.js +6 -3
  5. package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
  6. package/esm/src/cli/commands/fuzz-canary.js +195 -0
  7. package/esm/src/cli/commands/fuzz-guardrails.d.ts +3 -5
  8. package/esm/src/cli/commands/fuzz-guardrails.js +4 -581
  9. package/esm/src/cli/commands/profile.js +25 -14
  10. package/esm/src/cli/commands/run.d.ts +3 -0
  11. package/esm/src/cli/commands/run.js +22 -30
  12. package/esm/src/cli/commands/test.d.ts +10 -1
  13. package/esm/src/cli/commands/test.js +31 -31
  14. package/esm/src/cli/event-log.d.ts +19 -0
  15. package/esm/src/cli/event-log.js +147 -0
  16. package/esm/src/cli/index.js +45 -11
  17. package/esm/src/cli/matrix/synthesizer.d.ts +7 -9
  18. package/esm/src/cli/matrix/synthesizer.js +32 -106
  19. package/esm/src/guardrails/canary-gate.d.ts +20 -0
  20. package/esm/src/guardrails/canary-gate.js +31 -0
  21. package/esm/src/guardrails/canary.d.ts +26 -0
  22. package/esm/src/guardrails/canary.js +139 -0
  23. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +16 -0
  24. package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
  25. package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
  26. package/esm/src/guardrails/corpus/fuzz-inbound.js +216 -0
  27. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
  28. package/esm/src/guardrails/corpus/inbound-payloads.js +124 -0
  29. package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
  30. package/esm/src/guardrails/corpus/live-attacks.js +232 -0
  31. package/esm/src/guardrails/corpus/mod.d.ts +13 -0
  32. package/esm/src/guardrails/corpus/mod.js +11 -0
  33. package/esm/src/guardrails/corpus/secrets.d.ts +16 -0
  34. package/esm/src/guardrails/corpus/secrets.js +16 -0
  35. package/esm/src/guardrails/corpus/strings.d.ts +27 -0
  36. package/esm/src/guardrails/corpus/strings.js +33 -0
  37. package/esm/src/guardrails/corpus/types.d.ts +37 -0
  38. package/esm/src/guardrails/corpus/types.js +6 -0
  39. package/esm/src/guardrails/egress.d.ts +9 -0
  40. package/esm/src/guardrails/egress.js +36 -0
  41. package/esm/src/guardrails/error.js +6 -4
  42. package/esm/src/guardrails/injection.js +28 -5
  43. package/esm/src/guardrails/live-outbound-gate.d.ts +39 -0
  44. package/esm/src/guardrails/live-outbound-gate.js +180 -0
  45. package/esm/src/guardrails/mod.d.ts +13 -4
  46. package/esm/src/guardrails/mod.js +10 -4
  47. package/esm/src/guardrails/quota.js +1 -1
  48. package/esm/src/guardrails/sanitize.d.ts +11 -15
  49. package/esm/src/guardrails/sanitize.js +40 -49
  50. package/esm/src/guardrails/sensitive.js +2 -1
  51. package/esm/src/guardrails/testing.d.ts +10 -0
  52. package/esm/src/guardrails/testing.js +9 -0
  53. package/esm/src/host/client-turn.d.ts +19 -0
  54. package/esm/src/host/client-turn.js +32 -0
  55. package/esm/src/host/mod.d.ts +5 -3
  56. package/esm/src/host/mod.js +4 -3
  57. package/esm/src/interface/blocks.d.ts +20 -0
  58. package/esm/src/interface/blocks.js +180 -0
  59. package/esm/src/interface/from-profile.d.ts +14 -0
  60. package/esm/src/interface/from-profile.js +104 -0
  61. package/esm/src/interface/inputs.d.ts +8 -0
  62. package/esm/src/interface/inputs.js +127 -0
  63. package/esm/src/interface/mod.d.ts +10 -0
  64. package/esm/src/interface/mod.js +9 -0
  65. package/esm/src/interface/types.d.ts +153 -0
  66. package/esm/src/interface/types.js +13 -0
  67. package/esm/src/kernel/engine/delta.d.ts +24 -2
  68. package/esm/src/kernel/engine/delta.js +519 -29
  69. package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
  70. package/esm/src/kernel/engine/live-inbound.js +17 -0
  71. package/esm/src/kernel/engine/repair.js +1 -1
  72. package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
  73. package/esm/src/kernel/engine/runner/gates.js +7 -7
  74. package/esm/src/kernel/engine/runner/mod.js +13 -13
  75. package/esm/src/kernel/engine/runner/state.d.ts +7 -0
  76. package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
  77. package/esm/src/kernel/engine/runner/steps.js +171 -37
  78. package/esm/src/kernel/engine/runner/stream.d.ts +1 -2
  79. package/esm/src/kernel/engine/runner/stream.js +66 -29
  80. package/esm/src/kernel/engine/session/mod.d.ts +23 -0
  81. package/esm/src/kernel/engine/session/mod.js +205 -0
  82. package/esm/src/kernel/mod.d.ts +9 -10
  83. package/esm/src/kernel/mod.js +6 -8
  84. package/esm/src/kernel/registry/attachments.d.ts +4 -2
  85. package/esm/src/kernel/registry/attachments.js +6 -3
  86. package/esm/src/kernel/registry/catalog.d.ts +3 -16
  87. package/esm/src/kernel/registry/catalog.js +5 -81
  88. package/esm/src/kernel/registry/ingress.d.ts +9 -4
  89. package/esm/src/kernel/registry/ingress.js +73 -63
  90. package/esm/src/kernel/registry/profiles.d.ts +35 -12
  91. package/esm/src/kernel/registry/profiles.js +159 -66
  92. package/esm/src/kernel/registry/provider-request.js +11 -7
  93. package/esm/src/kernel/registry/resolve.d.ts +5 -6
  94. package/esm/src/kernel/registry/resolve.js +100 -70
  95. package/esm/src/kernel/registry/vault.d.ts +12 -7
  96. package/esm/src/kernel/registry/vault.js +30 -8
  97. package/esm/src/kernel/schema.d.ts +145 -0
  98. package/esm/src/kernel/schema.js +462 -0
  99. package/esm/src/kernel/stop.d.ts +15 -10
  100. package/esm/src/kernel/stop.js +5 -5
  101. package/esm/src/kernel/tools/execute.d.ts +45 -0
  102. package/esm/src/kernel/tools/execute.js +363 -0
  103. package/esm/src/kernel/tools/harness.d.ts +8 -0
  104. package/esm/src/kernel/tools/harness.js +44 -0
  105. package/esm/src/kernel/tools/invoke.d.ts +10 -0
  106. package/esm/src/kernel/tools/invoke.js +83 -0
  107. package/esm/src/kernel/tools/mod.d.ts +11 -0
  108. package/esm/src/kernel/tools/mod.js +10 -0
  109. package/esm/src/kernel/tools/project.d.ts +12 -0
  110. package/esm/src/kernel/tools/project.js +34 -0
  111. package/esm/src/kernel/tools/registry.d.ts +23 -0
  112. package/esm/src/kernel/tools/registry.js +71 -0
  113. package/esm/src/kernel/tools/resolve.d.ts +29 -0
  114. package/esm/src/kernel/tools/resolve.js +262 -0
  115. package/esm/src/kernel/tools/schema.d.ts +13 -0
  116. package/esm/src/kernel/tools/schema.js +159 -0
  117. package/esm/src/kernel/tools/types.d.ts +216 -0
  118. package/esm/src/kernel/tools/types.js +9 -0
  119. package/esm/src/kernel/types.d.ts +338 -193
  120. package/esm/src/observability/trace-attach.d.ts +6 -4
  121. package/esm/src/observability/trace-attach.js +39 -25
  122. package/esm/src/observability/trace-record.d.ts +11 -9
  123. package/esm/src/observability/trace-record.js +36 -23
  124. package/esm/src/observability/trace-usage.d.ts +10 -3
  125. package/esm/src/observability/trace-usage.js +70 -17
  126. package/esm/src/observability/trace.d.ts +9 -1
  127. package/esm/src/observability/trace.js +11 -3
  128. package/esm/src/presets/google/speech-voices.d.ts +11 -0
  129. package/esm/src/presets/google/speech-voices.js +41 -0
  130. package/esm/src/presets/google.d.ts +36 -24
  131. package/esm/src/presets/google.js +50 -63
  132. package/esm/src/presets/mod.d.ts +2 -2
  133. package/esm/src/presets/mod.js +1 -1
  134. package/esm/src/providers/create-provider.d.ts +14 -14
  135. package/esm/src/providers/create-provider.js +55 -23
  136. package/esm/src/providers/google/interactions/framing.d.ts +15 -0
  137. package/esm/src/providers/google/interactions/framing.js +208 -0
  138. package/esm/src/providers/google/interactions/mod.d.ts +7 -0
  139. package/esm/src/providers/google/interactions/mod.js +7 -0
  140. package/esm/src/providers/google/interactions/stream.d.ts +83 -0
  141. package/esm/src/providers/google/interactions/stream.js +588 -0
  142. package/esm/src/providers/google/keys.d.ts +26 -0
  143. package/esm/src/providers/{keys.js → google/keys.js} +19 -31
  144. package/esm/src/providers/google/live/framing.d.ts +46 -0
  145. package/esm/src/providers/google/live/framing.js +515 -0
  146. package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
  147. package/esm/src/providers/google/live/openapi-schema.js +45 -0
  148. package/esm/src/providers/google/live/session.d.ts +25 -0
  149. package/esm/src/providers/google/live/session.js +134 -0
  150. package/esm/src/providers/google/live/stream.d.ts +36 -0
  151. package/esm/src/providers/google/live/stream.js +201 -0
  152. package/esm/src/providers/google/urls.d.ts +6 -0
  153. package/esm/src/providers/google/urls.js +6 -0
  154. package/esm/src/providers/local/local.d.ts +30 -0
  155. package/esm/src/providers/{local.js → local/local.js} +66 -126
  156. package/esm/src/providers/local/mod.d.ts +9 -0
  157. package/esm/src/providers/local/mod.js +9 -0
  158. package/esm/src/providers/mod.d.ts +6 -3
  159. package/esm/src/providers/mod.js +3 -1
  160. package/esm/src/providers/openrouter/chat.d.ts +87 -0
  161. package/esm/src/providers/{openrouter.js → openrouter/chat.js} +70 -229
  162. package/esm/src/providers/openrouter/image.d.ts +34 -0
  163. package/esm/src/providers/openrouter/image.js +286 -0
  164. package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
  165. package/esm/src/providers/openrouter/openai/chat-payload.js +60 -0
  166. package/esm/src/providers/openrouter/openai/compat.d.ts +47 -0
  167. package/esm/src/providers/openrouter/openai/compat.js +194 -0
  168. package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
  169. package/esm/src/providers/openrouter/openai/image-payload.js +84 -0
  170. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
  171. package/esm/src/providers/openrouter/openai/sdk-messages.js +95 -0
  172. package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
  173. package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
  174. package/esm/src/providers/openrouter/speech.d.ts +23 -0
  175. package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
  176. package/esm/src/providers/probe.d.ts +1 -0
  177. package/esm/src/providers/probe.js +22 -0
  178. package/esm/src/providers/shared/pcm.d.ts +12 -0
  179. package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
  180. package/esm/src/providers/shared/sse.d.ts +18 -0
  181. package/esm/src/providers/shared/sse.js +87 -0
  182. package/esm/src/providers/shared/tool-args.d.ts +17 -0
  183. package/esm/src/providers/shared/tool-args.js +45 -0
  184. package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
  185. package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
  186. package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
  187. package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
  188. package/esm/src/providers/types.d.ts +27 -0
  189. package/esm/src/providers/types.js +1 -0
  190. package/package.json +11 -7
  191. package/docs/cli.md +0 -97
  192. package/docs/guardrails.md +0 -178
  193. package/docs/host.md +0 -97
  194. package/docs/kernel.md +0 -404
  195. package/docs/observability.md +0 -105
  196. package/docs/openrouter.md +0 -125
  197. package/docs/presets-google.md +0 -91
  198. package/docs/presets.md +0 -88
  199. package/docs/providers.md +0 -201
  200. package/docs/streaming.md +0 -96
  201. package/esm/src/kernel/engine/boundary.d.ts +0 -10
  202. package/esm/src/kernel/engine/boundary.js +0 -55
  203. package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
  204. package/esm/src/kernel/engine/runner/tools.js +0 -198
  205. package/esm/src/kernel/registry/tools.d.ts +0 -12
  206. package/esm/src/kernel/registry/tools.js +0 -36
  207. package/esm/src/providers/expose-for-tests.d.ts +0 -1
  208. package/esm/src/providers/expose-for-tests.js +0 -25
  209. package/esm/src/providers/gemini-tape.d.ts +0 -2
  210. package/esm/src/providers/google-tap.d.ts +0 -3
  211. package/esm/src/providers/interactions.d.ts +0 -5
  212. package/esm/src/providers/interactions.js +0 -169
  213. package/esm/src/providers/keys.d.ts +0 -19
  214. package/esm/src/providers/local.d.ts +0 -29
  215. package/esm/src/providers/openrouter-mod.d.ts +0 -13
  216. package/esm/src/providers/openrouter-mod.js +0 -12
  217. package/esm/src/providers/openrouter-payload.d.ts +0 -39
  218. package/esm/src/providers/openrouter-payload.js +0 -195
  219. package/esm/src/providers/openrouter.d.ts +0 -15
  220. package/esm/src/providers/pcm.d.ts +0 -7
  221. package/esm/src/providers/provider.d.ts +0 -15
  222. package/esm/src/providers/provider.js +0 -176
  223. package/esm/src/providers/speech.d.ts +0 -23
  224. package/esm/src/providers/sse.d.ts +0 -7
  225. package/esm/src/providers/sse.js +0 -55
  226. package/esm/src/streaming/mod.d.ts +0 -9
  227. package/esm/src/streaming/mod.js +0 -8
  228. /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
  229. /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
@@ -5,14 +5,19 @@
5
5
  * Streams SSE from `/v1/chat/completions`, accumulates tool calls, and yields
6
6
  * normalized `TurnEvent` objects. No external SDK dependency — raw fetch + SSE.
7
7
  *
8
+ * Wire-format message building delegates to the shared `openai/compat` module.
9
+ * SSE parsing delegates to the shared `parseSseStream` from `sse.ts`.
10
+ *
8
11
  * Hosts pass `baseUrl` explicitly. THEORUM does not read `OLLAMA_HOST` or other
9
- * environment variables (see src/providers/CONTRACT.md).
12
+ * environment variables (see docs/contracts/providers.md).
10
13
  *
11
14
  * @module
12
15
  */
13
- import { isAbortError, toErrorEvent } from '../guardrails/error.js';
14
- import { turnStopFromOpenRouter } from '../kernel/stop.js';
15
- import { exposeForTests } from './expose-for-tests.js';
16
+ import { isAbortError, toErrorEvent } from '../../guardrails/error.js';
17
+ import { turnStopFromOpenAiFinishReason } from '../../kernel/stop.js';
18
+ import { buildChatMessages, wireTools } from '../openrouter/openai/compat.js';
19
+ import { parseSseStream } from '../shared/sse.js';
20
+ import { parseToolArgumentsObject } from '../shared/tool-args.js';
16
21
  /** Default OpenAI-compat base when the host omits `baseUrl` (Ollama's default port). */
17
22
  export const DEFAULT_LOCAL_BASE_URL = 'http://127.0.0.1:11434';
18
23
  // ── request mapping ─────────────────────────────────
@@ -22,132 +27,48 @@ function normalizeBaseUrl(baseUrl) {
22
27
  end -= 1;
23
28
  return baseUrl.slice(0, end);
24
29
  }
25
- function resolveBaseUrl(config) {
30
+ export function resolveBaseUrl(config) {
26
31
  return normalizeBaseUrl(config?.baseUrl?.trim() || DEFAULT_LOCAL_BASE_URL);
27
32
  }
28
- function inputToContent(parts) {
29
- if (parts.every((p) => p.type === 'text')) {
30
- return parts.map((p) => ('text' in p ? p.text : '')).join('\n');
31
- }
32
- return parts.map((p) => {
33
- if (p.type === 'text')
34
- return { type: 'text', text: p.text };
35
- return {
36
- type: 'image_url',
37
- image_url: { url: `data:${p.mimeType};base64,${p.data}` },
38
- };
39
- });
40
- }
41
- function historyMessageContent(msg) {
42
- if (msg.parts && msg.parts.length > 0) {
43
- return inputToContent(msg.parts);
44
- }
45
- if (msg.content != null)
46
- return msg.content;
47
- return undefined;
48
- }
49
- function historyToWire(req) {
50
- const msgs = [];
51
- if (req.system)
52
- msgs.push({ role: 'system', content: req.system });
53
- for (const msg of req.history ?? []) {
54
- msgs.push(historyMessageToWire(msg));
55
- }
56
- if (req.input.length > 0) {
57
- msgs.push({ role: 'user', content: inputToContent(req.input) });
58
- }
59
- return msgs;
60
- }
61
- function historyMessageToWire(msg) {
62
- if (msg.role === 'tool') {
63
- return {
64
- role: 'tool',
65
- tool_call_id: msg.tool_call_id ?? `call_${msg.name ?? 'tool'}`,
66
- name: msg.name,
67
- content: msg.content ?? '',
68
- };
69
- }
70
- if (msg.role === 'assistant' && msg.tool_calls && msg.tool_calls.length > 0) {
71
- return {
72
- role: 'assistant',
73
- content: historyMessageContent(msg) ?? undefined,
74
- tool_calls: msg.tool_calls.map((tc) => ({
75
- id: tc.id,
76
- type: 'function',
77
- function: { name: tc.function.name, arguments: tc.function.arguments },
78
- })),
79
- };
80
- }
81
- return { role: msg.role, content: historyMessageContent(msg) ?? '' };
82
- }
83
- function toolsToWire(dynamicTools) {
84
- if (!dynamicTools || dynamicTools.length === 0)
85
- return undefined;
86
- return dynamicTools.map((t) => ({
87
- type: 'function',
88
- function: {
89
- name: t.name,
90
- description: t.description ?? '',
91
- parameters: t.parameters ?? { type: 'object', properties: {} },
92
- },
93
- }));
94
- }
95
33
  function buildBody(req) {
96
34
  const body = {
97
35
  model: req.apiId,
98
- messages: historyToWire(req),
36
+ messages: buildChatMessages(req),
99
37
  stream: true,
100
38
  stream_options: { include_usage: true },
101
39
  temperature: req.temperature,
102
40
  max_tokens: req.maxOutputTokens,
103
41
  };
104
- const tools = toolsToWire(req.dynamicTools);
42
+ const tools = wireTools(req.wireTools);
105
43
  if (tools)
106
44
  body.tools = tools;
107
45
  return body;
108
46
  }
109
- // ── SSE parsing ─────────────────────────────────────
110
- async function* parseSse(body) {
111
- const reader = body.getReader();
112
- const decoder = new TextDecoder();
113
- let buffer = '';
114
- for (;;) {
115
- const { done, value } = await reader.read();
116
- if (done)
117
- break;
118
- buffer += decoder.decode(value, { stream: true });
119
- const lines = buffer.split('\n');
120
- buffer = lines.pop() ?? '';
121
- for (const line of lines) {
122
- const trimmed = line.trim();
123
- if (!trimmed.startsWith('data: '))
124
- continue;
125
- const data = trimmed.slice(6);
126
- if (data === '[DONE]')
127
- return;
128
- try {
129
- yield JSON.parse(data);
130
- }
131
- catch {
132
- // skip malformed
133
- }
134
- }
135
- }
136
- }
137
47
  // ── stream → TurnEvent ──────────────────────────────
138
- function flushPending(pending) {
48
+ export function flushPending(pending) {
139
49
  const events = [];
140
50
  for (const [, tc] of pending) {
141
- let parsed = {};
142
- try {
143
- parsed = JSON.parse(tc.args);
144
- }
145
- catch {
146
- // empty
51
+ const parsed = parseToolArgumentsObject(tc.args);
52
+ if (!parsed.ok) {
53
+ events.push({
54
+ type: 'tool',
55
+ tool: {
56
+ name: tc.name,
57
+ arguments: {},
58
+ id: tc.id,
59
+ phase: 'error',
60
+ failure: {
61
+ code: 'malformed_arguments',
62
+ message: parsed.error,
63
+ details: { raw: parsed.raw },
64
+ },
65
+ },
66
+ });
67
+ continue;
147
68
  }
148
69
  events.push({
149
70
  type: 'tool',
150
- tool: { name: tc.name, arguments: parsed, id: tc.id },
71
+ tool: { name: tc.name, arguments: parsed.value, id: tc.id },
151
72
  });
152
73
  }
153
74
  pending.clear();
@@ -174,11 +95,11 @@ async function* streamComplete(baseUrl, req, fetchFn) {
174
95
  async function* streamOpenAiBody(body) {
175
96
  const pending = new Map();
176
97
  let finishReason;
177
- for await (const chunk of parseSse(body)) {
178
- const usageEvent = tokensFromUsage(chunk.usage);
98
+ for await (const raw of parseSseStream(body)) {
99
+ const usageEvent = tokensFromUsage(readOpenAiUsage(raw));
179
100
  if (usageEvent)
180
101
  yield usageEvent;
181
- const choice = chunk.choices?.[0];
102
+ const choice = firstOpenAiChoice(raw);
182
103
  if (!choice)
183
104
  continue;
184
105
  yield* eventsFromChoiceDelta(choice.delta, pending);
@@ -190,7 +111,37 @@ async function* streamOpenAiBody(body) {
190
111
  }
191
112
  for (const event of flushPending(pending))
192
113
  yield event;
193
- yield { type: 'done', stop: turnStopFromOpenRouter(finishReason) };
114
+ yield { type: 'done', stop: turnStopFromOpenAiFinishReason(finishReason) };
115
+ }
116
+ function readOpenAiUsage(raw) {
117
+ const usage = raw.usage;
118
+ if (!usage || typeof usage !== 'object' || Array.isArray(usage))
119
+ return undefined;
120
+ const row = usage;
121
+ return {
122
+ prompt_tokens: typeof row.prompt_tokens === 'number' ? row.prompt_tokens : undefined,
123
+ completion_tokens: typeof row.completion_tokens === 'number' ? row.completion_tokens : undefined,
124
+ total_tokens: typeof row.total_tokens === 'number' ? row.total_tokens : undefined,
125
+ };
126
+ }
127
+ function firstOpenAiChoice(raw) {
128
+ if (!Array.isArray(raw.choices) || raw.choices.length === 0)
129
+ return undefined;
130
+ const choice = raw.choices[0];
131
+ if (!choice || typeof choice !== 'object' || Array.isArray(choice))
132
+ return undefined;
133
+ const row = choice;
134
+ const deltaRaw = row.delta;
135
+ const delta = deltaRaw && typeof deltaRaw === 'object' && !Array.isArray(deltaRaw)
136
+ ? deltaRaw
137
+ : undefined;
138
+ return {
139
+ index: typeof row.index === 'number' ? row.index : 0,
140
+ delta,
141
+ finish_reason: typeof row.finish_reason === 'string' || row.finish_reason === null
142
+ ? row.finish_reason
143
+ : undefined,
144
+ };
194
145
  }
195
146
  function tokensFromUsage(usage) {
196
147
  if (!usage)
@@ -245,15 +196,4 @@ function createLocalProvider(config) {
245
196
  },
246
197
  };
247
198
  }
248
- export { createLocalProvider };
249
- exposeForTests('local', {
250
- inputToContent,
251
- historyMessageContent,
252
- historyToWire,
253
- toolsToWire,
254
- buildBody,
255
- parseSse,
256
- flushPending,
257
- resolveBaseUrl,
258
- DEFAULT_LOCAL_BASE_URL,
259
- });
199
+ export { buildChatMessages as historyToWire, createLocalProvider, wireTools as toolsToWire };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Direct entry for local OpenAI-compat providers (Ollama, vLLM, etc.).
3
+ * Importing this module loads the local adapter graph — prefer `createProvider`
4
+ * when routing from a profile unless you intentionally bypass the factory.
5
+ *
6
+ * @module
7
+ */
8
+ import "../../../_dnt.polyfills.js";
9
+ export { createLocalProvider, DEFAULT_LOCAL_BASE_URL } from './local.js';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Direct entry for local OpenAI-compat providers (Ollama, vLLM, etc.).
3
+ * Importing this module loads the local adapter graph — prefer `createProvider`
4
+ * when routing from a profile unless you intentionally bypass the factory.
5
+ *
6
+ * @module
7
+ */
8
+ import "../../../_dnt.polyfills.js";
9
+ export { createLocalProvider, DEFAULT_LOCAL_BASE_URL } from './local.js';
@@ -4,11 +4,14 @@
4
4
  * Host apps should use `createProvider(profile, options)` — the single door.
5
5
  * Credentials are always supplied by the host application.
6
6
  *
7
+ * For direct local adapter access (bypassing the factory), import
8
+ * `@theorum/core/providers/local`.
9
+ *
7
10
  * @module
8
11
  */
9
12
  import "../../_dnt.polyfills.js";
13
+ export type { KeyVault } from '../kernel/types.js';
10
14
  export type { CreateProviderOptions } from './create-provider.js';
11
15
  export { createProvider } from './create-provider.js';
12
- export type { GeminiTransport, GeminiVault } from './keys.js';
13
- export type { LocalProviderConfig } from './local.js';
14
- export { createLocalProvider, DEFAULT_LOCAL_BASE_URL } from './local.js';
16
+ export type { GeminiTransport } from './google/keys.js';
17
+ export type { LocalProviderConfig, OpenAiGatewayConfig } from './types.js';
@@ -4,8 +4,10 @@
4
4
  * Host apps should use `createProvider(profile, options)` — the single door.
5
5
  * Credentials are always supplied by the host application.
6
6
  *
7
+ * For direct local adapter access (bypassing the factory), import
8
+ * `@theorum/core/providers/local`.
9
+ *
7
10
  * @module
8
11
  */
9
12
  import "../../_dnt.polyfills.js";
10
13
  export { createProvider } from './create-provider.js';
11
- export { createLocalProvider, DEFAULT_LOCAL_BASE_URL } from './local.js';
@@ -0,0 +1,87 @@
1
+ /**
2
+ * OpenRouter provider adapter powered by Vercel AI SDK Core.
3
+ *
4
+ * THEORUM keeps the public `ModelProvider` and `TurnEvent` contract; AI SDK
5
+ * owns the OpenRouter call, stream parsing, provider compatibility, and tool
6
+ * call normalization. Message assembly delegates to `openai/sdk-messages.ts`.
7
+ *
8
+ * @module
9
+ */
10
+ import { type TextStreamPart, type ToolSet } from 'ai';
11
+ import type { ModelProvider, ProviderCompleteRequest, TurnEvent, TurnTokens, WireFunctionTool } from '../../kernel/types.js';
12
+ import type { OpenAiGatewayConfig } from '../types.js';
13
+ export interface StreamAccumulator {
14
+ text: string;
15
+ evidenceSeen: boolean;
16
+ emittedTokens: boolean;
17
+ errored: boolean;
18
+ finishReason?: string | null;
19
+ nativeFinishReason?: string | null;
20
+ }
21
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
22
+ [key: string]: JsonValue;
23
+ };
24
+ export type ProviderOptions = Record<string, {
25
+ [key: string]: JsonValue;
26
+ }>;
27
+ export declare function trimApiKey(explicitKey?: string): string | undefined;
28
+ export declare function createAccumulator(): StreamAccumulator;
29
+ export declare function sourceEvent(part: {
30
+ sourceType?: string;
31
+ title?: string | null;
32
+ url?: string;
33
+ }): TurnEvent;
34
+ export declare function schemaForTool(decl: WireFunctionTool): Record<string, unknown>;
35
+ export declare function buildTools(wireTools?: WireFunctionTool[]): ToolSet | undefined;
36
+ export declare function tokensFromUsage(usage: {
37
+ inputTokens?: number | null;
38
+ outputTokens?: number | null;
39
+ totalTokens?: number | null;
40
+ }): TurnTokens | undefined;
41
+ export declare function rawRecord(value: unknown): Record<string, unknown> | undefined;
42
+ export declare function stringArray(value: unknown): string[] | undefined;
43
+ export declare function metadataRecord(raw: Record<string, unknown>, key: string): Record<string, unknown> | undefined;
44
+ export declare function citationCandidates(raw: Record<string, unknown>): unknown[];
45
+ export declare function nestedCitations(raw: Record<string, unknown>): string[] | undefined;
46
+ export declare function metadataAnnotations(raw: Record<string, unknown>): unknown[] | undefined;
47
+ export declare function evidenceFromMetadata(metadata: unknown, acc: StreamAccumulator): TurnEvent | undefined;
48
+ export declare function toolArguments(input: unknown): Record<string, unknown> | undefined;
49
+ export declare function toolResultData(output: unknown): Record<string, unknown> | undefined;
50
+ export declare function rawThoughtEvent(raw: Record<string, unknown>): TurnEvent | undefined;
51
+ export declare function rawChoiceMessageEvidence(raw: Record<string, unknown>, acc: StreamAccumulator): TurnEvent | undefined;
52
+ export declare function rawEvents(raw: unknown, acc: StreamAccumulator): TurnEvent[];
53
+ export declare function toolCallEvent(part: {
54
+ toolName: string;
55
+ toolCallId: string;
56
+ input?: unknown;
57
+ }): TurnEvent;
58
+ export declare function toolResultEvent(part: {
59
+ toolName: string;
60
+ toolCallId: string;
61
+ input?: unknown;
62
+ output?: unknown;
63
+ }): TurnEvent;
64
+ export declare function tokenEvent(part: {
65
+ totalUsage: {
66
+ inputTokens?: number | null;
67
+ outputTokens?: number | null;
68
+ totalTokens?: number | null;
69
+ };
70
+ }): TurnEvent | undefined;
71
+ export declare function providerMetadataEvent(part: TextStreamPart<ToolSet>, acc: StreamAccumulator): TurnEvent | undefined;
72
+ export declare function eventFromPart(part: TextStreamPart<ToolSet>, acc: StreamAccumulator): TurnEvent[];
73
+ export declare function primaryEventFromPart(part: TextStreamPart<ToolSet>, acc: StreamAccumulator): TurnEvent | undefined;
74
+ export declare function finishEvent(part: {
75
+ finishReason?: string | null;
76
+ totalUsage?: {
77
+ inputTokens?: number | null;
78
+ outputTokens?: number | null;
79
+ totalTokens?: number | null;
80
+ };
81
+ }, acc: StreamAccumulator): TurnEvent | undefined;
82
+ export declare function finalEvents(req: ProviderCompleteRequest, acc: StreamAccumulator): Generator<TurnEvent>;
83
+ export declare function missingOpenRouterKey(): TurnEvent;
84
+ export declare function providerOptionsFor(req: ProviderCompleteRequest): ProviderOptions | undefined;
85
+ /** Create a `ModelProvider` backed by OpenRouter through AI SDK Core. */
86
+ export declare function createOpenRouterProvider(config?: OpenAiGatewayConfig): ModelProvider;
87
+ export type { OpenAiGatewayConfig };