@deepstrike/sdk 0.2.52 → 0.2.61

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 (151) hide show
  1. package/README.md +28 -28
  2. package/dist/agent-ir.d.ts +103 -0
  3. package/dist/agent-ir.js +134 -0
  4. package/dist/agent.d.ts +67 -0
  5. package/dist/agent.js +36 -0
  6. package/dist/collaboration/harness.js +1 -1
  7. package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
  8. package/dist/collaboration/modes/creator-verifier.js +4 -6
  9. package/dist/collaboration/pool.d.ts +8 -20
  10. package/dist/collaboration/pool.js +27 -97
  11. package/dist/compat/anthropic/mcp.d.ts +15 -0
  12. package/dist/compat/anthropic/mcp.js +10 -0
  13. package/dist/compat/openai/agent.d.ts +34 -0
  14. package/dist/compat/openai/agent.js +24 -0
  15. package/dist/governance.d.ts +1 -17
  16. package/dist/governance.js +1 -34
  17. package/dist/guardrail.d.ts +6 -0
  18. package/dist/guardrail.js +1 -0
  19. package/dist/handoff-target.d.ts +12 -0
  20. package/dist/handoff-target.js +1 -0
  21. package/dist/harness/manifest.js +0 -4
  22. package/dist/index.d.ts +19 -7
  23. package/dist/index.js +8 -5
  24. package/dist/kernel.d.ts +2 -20
  25. package/dist/knowledge/public.d.ts +29 -0
  26. package/dist/knowledge/public.js +1 -0
  27. package/dist/mcp-server.d.ts +28 -0
  28. package/dist/mcp-server.js +1 -0
  29. package/dist/memory/agent.d.ts +2 -2
  30. package/dist/memory/agent.js +2 -2
  31. package/dist/memory/durable.d.ts +16 -0
  32. package/dist/memory/durable.js +46 -0
  33. package/dist/memory/in-memory-store.d.ts +9 -7
  34. package/dist/memory/in-memory-store.js +8 -2
  35. package/dist/memory/protocols.d.ts +22 -4
  36. package/dist/memory/public.d.ts +4 -3
  37. package/dist/memory/public.js +3 -2
  38. package/dist/os/public.d.ts +1 -1
  39. package/dist/os/public.js +1 -1
  40. package/dist/providers/anthropic-adapter.d.ts +59 -0
  41. package/dist/providers/anthropic-adapter.js +530 -0
  42. package/dist/providers/anthropic-compatible.d.ts +2 -3
  43. package/dist/providers/anthropic-compatible.js +8 -5
  44. package/dist/providers/anthropic.d.ts +20 -23
  45. package/dist/providers/anthropic.js +176 -395
  46. package/dist/providers/base.d.ts +2 -2
  47. package/dist/providers/base.js +50 -8
  48. package/dist/providers/capability-router.d.ts +29 -0
  49. package/dist/providers/capability-router.js +43 -0
  50. package/dist/providers/catalog.d.ts +16 -4
  51. package/dist/providers/catalog.js +112 -36
  52. package/dist/providers/content-normalization.d.ts +57 -0
  53. package/dist/providers/content-normalization.js +238 -0
  54. package/dist/providers/content-policy.d.ts +16 -0
  55. package/dist/providers/content-policy.js +39 -0
  56. package/dist/providers/credentials.d.ts +83 -0
  57. package/dist/providers/credentials.js +190 -0
  58. package/dist/providers/endpoints.d.ts +137 -0
  59. package/dist/providers/endpoints.js +128 -0
  60. package/dist/providers/factories.js +25 -9
  61. package/dist/providers/gemini-adapter.d.ts +33 -0
  62. package/dist/providers/gemini-adapter.js +264 -0
  63. package/dist/providers/gemini.d.ts +16 -3
  64. package/dist/providers/gemini.js +97 -195
  65. package/dist/providers/model-catalog.d.ts +37 -0
  66. package/dist/providers/model-catalog.js +62 -0
  67. package/dist/providers/model-registry.d.ts +119 -0
  68. package/dist/providers/model-registry.js +379 -0
  69. package/dist/providers/ollama-adapter.d.ts +65 -0
  70. package/dist/providers/ollama-adapter.js +188 -0
  71. package/dist/providers/ollama.d.ts +9 -4
  72. package/dist/providers/ollama.js +96 -109
  73. package/dist/providers/openai-chat-dialects.d.ts +154 -0
  74. package/dist/providers/openai-chat-dialects.js +179 -0
  75. package/dist/providers/openai-chat.d.ts +46 -18
  76. package/dist/providers/openai-chat.js +416 -51
  77. package/dist/providers/openai-responses-adapter.d.ts +42 -0
  78. package/dist/providers/openai-responses-adapter.js +343 -0
  79. package/dist/providers/openai-responses.d.ts +19 -33
  80. package/dist/providers/openai-responses.js +164 -264
  81. package/dist/providers/openai.d.ts +29 -76
  82. package/dist/providers/openai.js +195 -292
  83. package/dist/providers/protocol-adapter.d.ts +39 -0
  84. package/dist/providers/protocol-adapter.js +13 -0
  85. package/dist/providers/protocol-capabilities.d.ts +34 -0
  86. package/dist/providers/protocol-capabilities.js +44 -0
  87. package/dist/providers/provider-error.d.ts +31 -0
  88. package/dist/providers/provider-error.js +153 -0
  89. package/dist/providers/public.d.ts +26 -3
  90. package/dist/providers/public.js +13 -1
  91. package/dist/providers/registry.d.ts +7 -6
  92. package/dist/providers/registry.js +47 -20
  93. package/dist/providers/request-plan.d.ts +89 -0
  94. package/dist/providers/request-plan.js +199 -0
  95. package/dist/providers/usage-normalizer.d.ts +48 -0
  96. package/dist/providers/usage-normalizer.js +139 -0
  97. package/dist/providers/vendor-profiles.d.ts +2 -15
  98. package/dist/providers/vendor-profiles.js +14 -60
  99. package/dist/runtime/canonical-kernel-step.d.ts +1 -2
  100. package/dist/runtime/canonical-kernel-step.js +47 -12
  101. package/dist/runtime/context-policy.d.ts +10 -12
  102. package/dist/runtime/context-policy.js +6 -8
  103. package/dist/runtime/durable-content.d.ts +50 -0
  104. package/dist/runtime/durable-content.js +159 -0
  105. package/dist/runtime/execution-plane.d.ts +2 -2
  106. package/dist/runtime/execution-plane.js +2 -2
  107. package/dist/runtime/kernel-event-log.js +0 -1
  108. package/dist/runtime/kernel-step.d.ts +0 -1
  109. package/dist/runtime/kernel-step.js +4 -2
  110. package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
  111. package/dist/runtime/mcp-proxy-plane.js +44 -6
  112. package/dist/runtime/output-schema.d.ts +1 -2
  113. package/dist/runtime/provider-replay.d.ts +5 -1
  114. package/dist/runtime/provider-replay.js +26 -27
  115. package/dist/runtime/reactive-session.d.ts +1 -1
  116. package/dist/runtime/reactive-session.js +2 -3
  117. package/dist/runtime/run-group.d.ts +1 -1
  118. package/dist/runtime/runner.d.ts +31 -45
  119. package/dist/runtime/runner.js +178 -63
  120. package/dist/runtime/session-log.d.ts +8 -1
  121. package/dist/runtime/session-log.js +42 -2
  122. package/dist/runtime/session-repair.d.ts +1 -1
  123. package/dist/runtime/session-repair.js +1 -1
  124. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  125. package/dist/runtime/sub-agent-orchestrator.js +8 -11
  126. package/dist/runtime/workflow-control-flow.d.ts +0 -4
  127. package/dist/runtime/workflow-control-flow.js +0 -16
  128. package/dist/session.d.ts +11 -0
  129. package/dist/session.js +1 -0
  130. package/dist/skill.d.ts +17 -0
  131. package/dist/skill.js +16 -0
  132. package/dist/skills/loader.d.ts +3 -0
  133. package/dist/tools/errors.d.ts +1 -3
  134. package/dist/tools/errors.js +1 -3
  135. package/dist/tools/index.d.ts +3 -0
  136. package/dist/types/agent.d.ts +21 -9
  137. package/dist/types/agent.js +30 -4
  138. package/dist/types.d.ts +135 -17
  139. package/package.json +4 -4
  140. package/dist/providers/deepseek.d.ts +0 -46
  141. package/dist/providers/deepseek.js +0 -97
  142. package/dist/providers/glm.d.ts +0 -25
  143. package/dist/providers/glm.js +0 -48
  144. package/dist/providers/kimi.d.ts +0 -23
  145. package/dist/providers/kimi.js +0 -30
  146. package/dist/providers/minimax.d.ts +0 -49
  147. package/dist/providers/minimax.js +0 -98
  148. package/dist/providers/profiles.d.ts +0 -1992
  149. package/dist/providers/profiles.js +0 -796
  150. package/dist/providers/qwen.d.ts +0 -38
  151. package/dist/providers/qwen.js +0 -97
@@ -0,0 +1,379 @@
1
+ import { endpointProfiles, } from "./endpoints.js";
2
+ import { ANTHROPIC_PROTOCOL_CAPABILITIES, GEMINI_PROTOCOL_CAPABILITIES, OLLAMA_PROTOCOL_CAPABILITIES, OPENAI_CHAT_PROTOCOL_CAPABILITIES, OPENAI_RESPONSES_PROTOCOL_CAPABILITIES, } from "./protocol-capabilities.js";
3
+ export const MODEL_CAPABILITY_STATES = [
4
+ "supported",
5
+ "unsupported",
6
+ "unknown",
7
+ ];
8
+ export const registryEvidence = [
9
+ {
10
+ ruleId: "provider-prefix-routing",
11
+ classification: "routing",
12
+ source: "node/tests/model-registry.test.ts",
13
+ verifiedAt: "2026-08-12",
14
+ },
15
+ {
16
+ ruleId: "runtime-policy-resolution",
17
+ classification: "policy",
18
+ source: "node/tests/model-registry.test.ts",
19
+ verifiedAt: "2026-08-12",
20
+ },
21
+ {
22
+ ruleId: "protocol-wire-capabilities",
23
+ classification: "protocol",
24
+ source: "node/tests/characterization/wire-request.test.ts",
25
+ verifiedAt: "2026-08-12",
26
+ },
27
+ {
28
+ ruleId: "native-token-counting",
29
+ classification: "endpoint",
30
+ source: "node/tests/anthropic-count-tokens.test.ts; node/tests/gemini-count-tokens.test.ts",
31
+ verifiedAt: "2026-08-12",
32
+ },
33
+ ];
34
+ export const cacheCapabilityEvidence = [
35
+ {
36
+ endpointId: "anthropic.messages",
37
+ source: "https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching",
38
+ verifiedAt: "2026-08-26",
39
+ classification: "documentation",
40
+ usageFields: ["cache_read_input_tokens", "cache_creation_input_tokens"],
41
+ },
42
+ {
43
+ endpointId: "deepseek.openai",
44
+ source: "https://api-docs.deepseek.com/guides/kv_cache",
45
+ verifiedAt: "2026-08-26",
46
+ classification: "documentation",
47
+ usageFields: ["prompt_cache_hit_tokens", "prompt_cache_miss_tokens"],
48
+ },
49
+ ];
50
+ export const tokenMeasurementEvidence = [
51
+ {
52
+ endpointId: "anthropic.messages",
53
+ source: "https://github.com/anthropics/anthropic-sdk-typescript/blob/main/api.md#count-tokens",
54
+ verifiedAt: "2026-08-26",
55
+ providerApiState: "supported",
56
+ adapterState: "available",
57
+ method: "provider_preflight",
58
+ coverage: ["system", "messages", "tools"],
59
+ sdk: "@anthropic-ai/sdk ^0.99.0",
60
+ },
61
+ {
62
+ endpointId: "gemini.google",
63
+ source: "https://ai.google.dev/api/tokens#method-models.countTokens",
64
+ verifiedAt: "2026-08-26",
65
+ providerApiState: "supported",
66
+ adapterState: "available",
67
+ method: "provider_preflight",
68
+ coverage: ["contents", "system", "tools", "provider_options"],
69
+ sdk: "@google/generative-ai ^0.24.1",
70
+ },
71
+ {
72
+ endpointId: "openai.responses",
73
+ source: "https://github.com/openai/openai-node/tree/master/src/resources/responses/input-tokens.ts",
74
+ verifiedAt: "2026-08-26",
75
+ providerApiState: "supported",
76
+ adapterState: "available",
77
+ method: "provider_preflight",
78
+ coverage: ["input", "instructions", "tools", "provider_options"],
79
+ sdk: "openai ^7.5.0",
80
+ },
81
+ ];
82
+ const POLICY = {
83
+ "anthropic/claude-opus-4-1": { maxTurns: 50 },
84
+ "anthropic/claude-opus-4-7": { maxTurns: 50 },
85
+ "anthropic/claude-opus-4-6": { maxTurns: 50 },
86
+ "anthropic/claude-opus-4-0": { maxTurns: 50 },
87
+ "anthropic/claude-sonnet-4-6": { maxTurns: 25 },
88
+ "anthropic/claude-sonnet-4-0": { maxTurns: 25 },
89
+ "anthropic/claude-haiku-4-5": { maxTurns: 15 },
90
+ "anthropic/claude-3-5-haiku-latest": { maxTurns: 15 },
91
+ "deepseek/deepseek-chat": { maxTurns: 25 },
92
+ "deepseek/deepseek-reasoner": { maxTurns: 50 },
93
+ "deepseek/deepseek-v4-flash": { maxTurns: 20 },
94
+ "deepseek/deepseek-v4-pro": { maxTurns: 35 },
95
+ "kimi/moonshot-v1-8k": { maxTurns: 15 },
96
+ "kimi/moonshot-v1-32k": { maxTurns: 20 },
97
+ "kimi/moonshot-v1-128k": { maxTurns: 30 },
98
+ "kimi/kimi-k2.5": { maxTurns: 30 },
99
+ "kimi/kimi-k2.6": { maxTurns: 35 },
100
+ "kimi/kimi-k2-thinking": { maxTurns: 50 },
101
+ "kimi/kimi-k2-thinking-turbo": { maxTurns: 40 },
102
+ "qwen/qwen3.7-max-preview": { maxTurns: 45 },
103
+ "qwen/qwen3.7-plus-preview": { maxTurns: 40 },
104
+ "qwen/qwen3.6-max-preview": { maxTurns: 40 },
105
+ "qwen/qwen3.6-plus": { maxTurns: 35 },
106
+ "qwen/qwen3.6-flash": { maxTurns: 20 },
107
+ "qwen/qwen3.6-35b-a3b": { maxTurns: 25 },
108
+ "qwen/qwen3.6-27b": { maxTurns: 25 },
109
+ "qwen/qwen3.5-plus": { maxTurns: 35 },
110
+ "qwen/qwen3.5-flash": { maxTurns: 20 },
111
+ "qwen/qwen3.5-397b-a17b": { maxTurns: 35 },
112
+ "qwen/qwen3.5-122b-a10b": { maxTurns: 25 },
113
+ "qwen/qwen3.5-35b-a3b": { maxTurns: 20 },
114
+ "qwen/qwen3.5-27b": { maxTurns: 20 },
115
+ "glm/glm-5.2": { maxTurns: 50 },
116
+ "glm/glm-5.1": { maxTurns: 50 },
117
+ "glm/glm-4-plus": { maxTurns: 35 },
118
+ "glm/glm-4-flash": { maxTurns: 15 },
119
+ "glm/glm-4-air": { maxTurns: 20 },
120
+ "minimax/MiniMax-M3": { maxTurns: 35 },
121
+ "minimax/MiniMax-M3-highspeed": { maxTurns: 35 },
122
+ "minimax/MiniMax-M2.7": { maxTurns: 35 },
123
+ "minimax/MiniMax-M2.7-highspeed": { maxTurns: 35 },
124
+ "minimax/MiniMax-M2.5": { maxTurns: 25 },
125
+ "minimax/MiniMax-M2.5-highspeed": { maxTurns: 25 },
126
+ "minimax/MiniMax-M2.1": { maxTurns: 25 },
127
+ "minimax/MiniMax-M2.1-highspeed": { maxTurns: 25 },
128
+ "minimax/MiniMax-M2": { maxTurns: 20 },
129
+ "minimax/MiniMax-Text-01": { maxTurns: 20 },
130
+ "gemini/gemini-3-pro-preview": { maxTurns: 50 },
131
+ "gemini/gemini-3-flash-preview": { maxTurns: 25 },
132
+ "gemini/gemini-3.5-flash": { maxTurns: 30 },
133
+ "gemini/gemini-2.5-pro": { maxTurns: 35 },
134
+ "gemini/gemini-2.5-flash": { maxTurns: 20 },
135
+ "gemini/gemini-2.0-flash": { maxTurns: 15 },
136
+ "gemini/gemini-2.0-flash-lite": { maxTurns: 10 },
137
+ "gemini/gemini-1.5-pro": { maxTurns: 30 },
138
+ "gemini/gemini-1.5-flash": { maxTurns: 15 },
139
+ "openai/gpt-5.5": { maxTurns: 60 },
140
+ "openai/gpt-5.4": { maxTurns: 50 },
141
+ "openai/gpt-5.4-mini": { maxTurns: 25 },
142
+ "openai/gpt-5.4-nano": { maxTurns: 15 },
143
+ "openai/gpt-5.2": { maxTurns: 50 },
144
+ "openai/gpt-5.2-pro": { maxTurns: 60 },
145
+ "openai/gpt-5.1": { maxTurns: 50 },
146
+ "openai/gpt-4o": { maxTurns: 25 },
147
+ "openai/gpt-4o-mini": { maxTurns: 15 },
148
+ "openai/gpt-4.1": { maxTurns: 35 },
149
+ "openai/gpt-4.1-mini": { maxTurns: 20 },
150
+ "openai/gpt-4.1-nano": { maxTurns: 15 },
151
+ "openai/gpt-5": { maxTurns: 50 },
152
+ "openai/gpt-5-pro": { maxTurns: 60 },
153
+ "openai/gpt-5-mini": { maxTurns: 25 },
154
+ "openai/gpt-5-nano": { maxTurns: 15 },
155
+ "openai/o1": { maxTurns: 50 },
156
+ "openai/o1-mini": { maxTurns: 25 },
157
+ "openai/o3": { maxTurns: 50 },
158
+ "openai/o3-mini": { maxTurns: 25 },
159
+ "openai/o4-mini": { maxTurns: 25 },
160
+ };
161
+ const DEFAULT_ENDPOINT = {
162
+ anthropic: "anthropic.messages",
163
+ openai: "openai.chat",
164
+ minimax: "minimax.anthropic",
165
+ deepseek: "deepseek.openai",
166
+ kimi: "kimi.openai",
167
+ qwen: "qwen.dashscope",
168
+ gemini: "gemini.google",
169
+ glm: "glm.openai",
170
+ baai: "baai.self-hosted.embeddings",
171
+ ollama: "ollama.local",
172
+ };
173
+ const DEFAULT_MODEL = {
174
+ anthropic: "claude-sonnet-4-6",
175
+ openai: "gpt-4o",
176
+ minimax: "MiniMax-M3",
177
+ deepseek: "deepseek-v4-flash",
178
+ kimi: "kimi-k2.6",
179
+ qwen: "qwen3.6-plus",
180
+ gemini: "gemini-2.0-flash",
181
+ glm: "glm-5.2",
182
+ baai: "bge-m3",
183
+ ollama: "llama3",
184
+ };
185
+ export function defaultModelForProvider(providerId) {
186
+ return DEFAULT_MODEL[providerId];
187
+ }
188
+ export function defaultEndpointForProvider(providerId) {
189
+ return DEFAULT_ENDPOINT[providerId];
190
+ }
191
+ function endpointFor(providerId, modelId) {
192
+ if (providerId === "openai") {
193
+ if (modelId.startsWith("text-embedding-"))
194
+ return "openai.embeddings";
195
+ if (/^(gpt-5|gpt-4\.1|o3|o4-mini)/.test(modelId))
196
+ return "openai.responses";
197
+ }
198
+ if (providerId === "qwen") {
199
+ if (modelId.startsWith("text-embedding-"))
200
+ return "qwen.dashscope.embeddings";
201
+ if (/^(qwen2\.5-vl-embedding|qwen3-vl-embedding)$/.test(modelId)) {
202
+ return "qwen.dashscope.multimodal-embeddings";
203
+ }
204
+ }
205
+ if (providerId === "gemini" && modelId.startsWith("gemini-embedding-")) {
206
+ return "gemini.google.embeddings";
207
+ }
208
+ if (providerId === "glm" && modelId.startsWith("embedding-")) {
209
+ return "glm.openai.embeddings";
210
+ }
211
+ return DEFAULT_ENDPOINT[providerId];
212
+ }
213
+ function modelKind(endpointId) {
214
+ return generationProtocol(endpointProfiles[endpointId].protocol) ? "generation" : "embedding";
215
+ }
216
+ function registration(providerId, rawModelId) {
217
+ const modelId = normalizeModelId(providerId, rawModelId);
218
+ const endpointId = endpointFor(providerId, modelId);
219
+ const policy = providerId === "ollama" ? ollamaPolicy(modelId) : POLICY[`${providerId}/${modelId}`];
220
+ return {
221
+ descriptor: {
222
+ id: `${providerId}/${modelId}`,
223
+ providerId,
224
+ kind: modelKind(endpointId),
225
+ intrinsic: {},
226
+ },
227
+ defaultEndpointId: endpointId,
228
+ ...(policy ? { recommendedRuntimePolicy: policy } : {}),
229
+ };
230
+ }
231
+ const dynamicResolvers = Object.fromEntries(Object.keys(DEFAULT_ENDPOINT).map(providerId => [providerId, {
232
+ providerId,
233
+ resolve(modelId) {
234
+ return registration(providerId, modelId);
235
+ },
236
+ }]));
237
+ export class ModelRegistry {
238
+ resolve(modelId, providerId) {
239
+ const resolvedProvider = providerId ?? providerPrefix(modelId);
240
+ if (!resolvedProvider)
241
+ return undefined;
242
+ return dynamicResolvers[resolvedProvider].resolve(modelId);
243
+ }
244
+ }
245
+ export const modelRegistry = new ModelRegistry();
246
+ export function normalizeModelId(providerId, modelId) {
247
+ const prefix = `${providerId}/`;
248
+ return modelId.startsWith(prefix) ? modelId.slice(prefix.length) : modelId;
249
+ }
250
+ export function getRuntimePolicy(providerId, modelId) {
251
+ if (!isKnownProviderId(providerId))
252
+ return {};
253
+ return modelRegistry.resolve(modelId, providerId)?.recommendedRuntimePolicy ?? {};
254
+ }
255
+ function providerPrefix(modelId) {
256
+ const slash = modelId.indexOf("/");
257
+ if (slash <= 0)
258
+ return undefined;
259
+ const value = modelId.slice(0, slash);
260
+ return isKnownProviderId(value) ? value : undefined;
261
+ }
262
+ function ollamaPolicy(modelId) {
263
+ const lower = modelId.toLowerCase();
264
+ const rows = [
265
+ ["deepseek-r1", 40], ["qwq", 35], ["llama3.3", 25], ["llama3.2", 20],
266
+ ["llama3.1", 20], ["llama3", 20], ["mistral", 20], ["gemma2", 20],
267
+ ["phi4", 20], ["phi3", 15], ["codellama", 20],
268
+ ];
269
+ return { maxTurns: rows.find(([prefix]) => lower.startsWith(prefix))?.[1] ?? 20 };
270
+ }
271
+ export const protocolRuntimeCapabilities = {
272
+ "anthropic-messages": ANTHROPIC_PROTOCOL_CAPABILITIES,
273
+ "openai-chat": OPENAI_CHAT_PROTOCOL_CAPABILITIES,
274
+ "openai-responses": OPENAI_RESPONSES_PROTOCOL_CAPABILITIES,
275
+ gemini: GEMINI_PROTOCOL_CAPABILITIES,
276
+ "ollama-chat": OLLAMA_PROTOCOL_CAPABILITIES,
277
+ };
278
+ export const endpointRuntimeCapabilities = {
279
+ "anthropic.messages": { nativeTokenCounting: true, promptCaching: true },
280
+ "deepseek.openai": { promptCaching: true },
281
+ "gemini.google": { nativeTokenCounting: true },
282
+ "openai.responses": { nativeTokenCounting: true },
283
+ };
284
+ export function resolveEffectiveCapability(layers) {
285
+ const evidence = layers.filter(layer => layer.state !== "unknown").map(layer => layer.layer);
286
+ if (layers.some(layer => layer.state === "unsupported"))
287
+ return { state: "unsupported", evidence };
288
+ if (layers.length > 0 && layers.every(layer => layer.state === "supported")) {
289
+ const valued = [...layers].reverse().find(layer => layer.value !== undefined);
290
+ return { state: "supported", ...(valued ? { value: valued.value } : {}), evidence };
291
+ }
292
+ return { state: "unknown", evidence };
293
+ }
294
+ const inputModalities = ["text", "image", "audio", "video", "file"];
295
+ const outputModalities = ["text", "image", "audio", "embedding"];
296
+ function booleanState(value) {
297
+ return value === undefined ? "unknown" : value ? "supported" : "unsupported";
298
+ }
299
+ function membershipState(values, value) {
300
+ return values === undefined ? "unknown" : values.includes(value) ? "supported" : "unsupported";
301
+ }
302
+ export function resolveEffectiveModelCapabilities(input) {
303
+ const protocol = protocolRuntimeCapabilities[input.protocol];
304
+ const overrides = input.endpointCapabilities?.protocolOverrides;
305
+ const modality = (layer, value) => {
306
+ const modelValues = layer === "input"
307
+ ? input.model.intrinsic.inputModalities
308
+ : input.model.intrinsic.outputModalities;
309
+ const protocolValues = layer === "input"
310
+ ? protocol.acceptedInputModalities
311
+ : protocol.emittedOutputModalities;
312
+ const overrideValues = layer === "input"
313
+ ? overrides?.acceptedInputModalities
314
+ : overrides?.emittedOutputModalities;
315
+ return resolveEffectiveCapability([
316
+ { layer: "model", state: membershipState(modelValues, value) },
317
+ { layer: "protocol", state: membershipState(protocolValues, value) },
318
+ ...(overrideValues ? [{ layer: "endpoint", state: membershipState(overrideValues, value) }] : []),
319
+ ]);
320
+ };
321
+ const booleanCapability = (modelValue, protocolValue, endpointValue) => resolveEffectiveCapability([
322
+ { layer: "model", state: booleanState(modelValue) },
323
+ { layer: "protocol", state: booleanState(protocolValue) },
324
+ ...(endpointValue === undefined ? [] : [{ layer: "endpoint", state: booleanState(endpointValue) }]),
325
+ ]);
326
+ const protocolBoolean = (protocolValue, endpointValue) => resolveEffectiveCapability([
327
+ { layer: "protocol", state: booleanState(protocolValue) },
328
+ ...(endpointValue === undefined ? [] : [{ layer: "endpoint", state: booleanState(endpointValue) }]),
329
+ ]);
330
+ const media = (key) => protocolBoolean(protocol.mediaForms[key], overrides?.mediaForms?.[key]);
331
+ return {
332
+ inputModalities: Object.fromEntries(inputModalities.map(value => [value, modality("input", value)])),
333
+ outputModalities: Object.fromEntries(outputModalities.map(value => [value, modality("output", value)])),
334
+ tools: booleanCapability(input.model.intrinsic.tools, protocol.tools, overrides?.tools),
335
+ reasoning: resolveEffectiveCapability([
336
+ { layer: "model", state: booleanState(input.model.intrinsic.reasoning) },
337
+ { layer: "protocol", state: protocol.reasoningReplay === "none" ? "unknown" : "supported" },
338
+ ]),
339
+ parallelToolCalls: protocolBoolean(protocol.parallelToolCalls, overrides?.parallelToolCalls),
340
+ structuredOutput: protocolBoolean(protocol.structuredOutput, overrides?.structuredOutput),
341
+ promptCaching: resolveEffectiveCapability([
342
+ { layer: "protocol", state: booleanState(protocol.promptCaching), value: protocol.promptCaching },
343
+ {
344
+ layer: "endpoint",
345
+ state: booleanState(input.endpointCapabilities?.promptCaching),
346
+ value: input.endpointCapabilities?.promptCaching,
347
+ },
348
+ ]),
349
+ nativeTokenCounting: resolveEffectiveCapability([
350
+ { layer: "endpoint", state: booleanState(input.endpointCapabilities?.nativeTokenCounting) },
351
+ ]),
352
+ mediaForms: {
353
+ imageUrl: media("imageUrl"), imageBase64: media("imageBase64"), fileId: media("fileId"),
354
+ audioUrl: media("audioUrl"), audioBase64: media("audioBase64"),
355
+ },
356
+ };
357
+ }
358
+ export function generationProtocol(protocol) {
359
+ switch (protocol) {
360
+ case "anthropic-messages":
361
+ case "openai-chat":
362
+ case "openai-responses":
363
+ case "gemini":
364
+ case "ollama-chat":
365
+ return protocol;
366
+ default:
367
+ return undefined;
368
+ }
369
+ }
370
+ export function endpointCapabilitiesFor(endpointId, preserveEndpointIdentity, preserveCacheEvidence = preserveEndpointIdentity) {
371
+ const capabilities = preserveEndpointIdentity ? endpointRuntimeCapabilities[endpointId] : undefined;
372
+ if (!capabilities || preserveCacheEvidence)
373
+ return capabilities;
374
+ const { promptCaching: _promptCaching, ...withoutCacheEvidence } = capabilities;
375
+ return withoutCacheEvidence;
376
+ }
377
+ export function isKnownProviderId(value) {
378
+ return value in DEFAULT_ENDPOINT;
379
+ }
@@ -0,0 +1,65 @@
1
+ import type { Message, ProviderUsage } from "../types.js";
2
+ import type { CanonicalAdapterInput } from "./content-normalization.js";
3
+ import { type AdapterDecodeInput, type AdapterOutput, type AdapterStreamInput, type CanonicalStopReason, type ProtocolAdapter } from "./protocol-adapter.js";
4
+ export interface OllamaMessage {
5
+ role: string;
6
+ content: string;
7
+ images?: string[];
8
+ }
9
+ export interface OllamaRequest {
10
+ model: string;
11
+ messages: OllamaMessage[];
12
+ tools?: Array<{
13
+ type: "function";
14
+ function: {
15
+ name: string;
16
+ description: string;
17
+ parameters: unknown;
18
+ };
19
+ }>;
20
+ [key: string]: unknown;
21
+ }
22
+ export interface OllamaChunk {
23
+ message?: {
24
+ content?: string;
25
+ tool_calls?: Array<{
26
+ function: {
27
+ name: string;
28
+ arguments: unknown;
29
+ };
30
+ }>;
31
+ };
32
+ done?: boolean;
33
+ done_reason?: string;
34
+ prompt_eval_count?: number;
35
+ eval_count?: number;
36
+ }
37
+ export interface OllamaStreamState {
38
+ readonly input: CanonicalAdapterInput;
39
+ readonly pendingToolCalls: Map<string, {
40
+ id: string;
41
+ name: string;
42
+ arguments: Record<string, unknown>;
43
+ }>;
44
+ finalChunk?: OllamaChunk;
45
+ }
46
+ export declare class OllamaNdjsonDecoder {
47
+ private buffer;
48
+ push(text: string): OllamaChunk[];
49
+ finish(text?: string): OllamaChunk[];
50
+ private parse;
51
+ }
52
+ export declare class OllamaAdapter implements ProtocolAdapter<OllamaRequest, OllamaChunk, OllamaChunk, OllamaStreamState, OllamaChunk | undefined> {
53
+ readonly protocol: "ollama-chat";
54
+ readonly protocolCapabilities: import("./protocol-capabilities.js").ProtocolRuntimeCapabilities;
55
+ buildRequest(input: CanonicalAdapterInput): OllamaRequest;
56
+ decodeComplete(raw: OllamaChunk, _input: AdapterDecodeInput): {
57
+ message: Message;
58
+ };
59
+ createStreamState(input: AdapterStreamInput): OllamaStreamState;
60
+ pushStreamChunk(chunk: OllamaChunk, state: OllamaStreamState): AdapterOutput;
61
+ finishStream(state: OllamaStreamState, final: OllamaChunk | undefined): AdapterOutput;
62
+ normalizeUsage(raw: unknown): ProviderUsage | undefined;
63
+ normalizeStopReason(raw: string | undefined): CanonicalStopReason | undefined;
64
+ createNdjsonDecoder(): OllamaNdjsonDecoder;
65
+ }
@@ -0,0 +1,188 @@
1
+ import { projectToolOutputToText } from "./content-normalization.js";
2
+ import { normalizeToolCall } from "./base.js";
3
+ import { ProtocolResponseError, OLLAMA_PROTOCOL_CAPABILITIES, } from "./protocol-adapter.js";
4
+ function messageContent(message) {
5
+ const text = [];
6
+ const images = [];
7
+ for (const item of message.blocks) {
8
+ if (item.type === "tool_result") {
9
+ text.push(projectToolOutputToText(item.blocks));
10
+ }
11
+ else if (item.type === "text") {
12
+ text.push(item.text);
13
+ }
14
+ else if (item.type === "image" && item.source.kind === "base64") {
15
+ images.push(item.source.data);
16
+ text.push("[image]");
17
+ }
18
+ else {
19
+ throw new ProtocolResponseError("ollama-chat", `cannot serialize ${item.type}`);
20
+ }
21
+ }
22
+ return {
23
+ role: message.role,
24
+ content: text.join("\n"),
25
+ ...(images.length ? { images } : {}),
26
+ };
27
+ }
28
+ function requestExtensions(extensions) {
29
+ const blocked = new Set([
30
+ "model",
31
+ "messages",
32
+ "tools",
33
+ "stream",
34
+ "__deepstrikeThinkingEnabled",
35
+ "degradeMissingReasoningReplay",
36
+ ]);
37
+ return Object.fromEntries(Object.entries(extensions).filter(([key]) => !blocked.has(key)));
38
+ }
39
+ function validCount(raw, field) {
40
+ const value = raw[field];
41
+ if (value === undefined)
42
+ return undefined;
43
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
44
+ throw new ProtocolResponseError("ollama-chat", `${field} must be a non-negative safe integer`);
45
+ }
46
+ return value;
47
+ }
48
+ export class OllamaNdjsonDecoder {
49
+ buffer = "";
50
+ push(text) {
51
+ this.buffer += text;
52
+ const lines = this.buffer.split("\n");
53
+ this.buffer = lines.pop() ?? "";
54
+ return this.parse(lines);
55
+ }
56
+ finish(text = "") {
57
+ this.buffer += text;
58
+ const tail = this.buffer;
59
+ this.buffer = "";
60
+ return this.parse(tail ? [tail] : []);
61
+ }
62
+ parse(lines) {
63
+ const chunks = [];
64
+ for (const line of lines) {
65
+ if (!line.trim())
66
+ continue;
67
+ try {
68
+ const value = JSON.parse(line);
69
+ if (value && typeof value === "object" && !Array.isArray(value)) {
70
+ chunks.push(value);
71
+ }
72
+ }
73
+ catch {
74
+ // Preserve the established Ollama behavior: malformed complete lines are skipped.
75
+ }
76
+ }
77
+ return chunks;
78
+ }
79
+ }
80
+ export class OllamaAdapter {
81
+ protocol = "ollama-chat";
82
+ protocolCapabilities = OLLAMA_PROTOCOL_CAPABILITIES;
83
+ buildRequest(input) {
84
+ const messages = [];
85
+ if (input.context.systemText) {
86
+ messages.push({ role: "system", content: input.context.systemText });
87
+ }
88
+ const turns = input.context.stateTurn
89
+ ? [...input.context.turns, input.context.stateTurn]
90
+ : input.context.turns;
91
+ messages.push(...turns.map(messageContent));
92
+ return {
93
+ ...requestExtensions(input.extensions),
94
+ model: input.resolved.identity.modelId,
95
+ messages,
96
+ ...(input.tools.length ? {
97
+ tools: input.tools.map(tool => ({
98
+ type: "function",
99
+ function: {
100
+ name: tool.name,
101
+ description: tool.description,
102
+ parameters: JSON.parse(tool.parameters),
103
+ },
104
+ })),
105
+ } : {}),
106
+ };
107
+ }
108
+ decodeComplete(raw, _input) {
109
+ return {
110
+ message: {
111
+ role: "assistant",
112
+ content: raw.message?.content ?? "",
113
+ },
114
+ };
115
+ }
116
+ createStreamState(input) {
117
+ return { input: input.input, pendingToolCalls: new Map() };
118
+ }
119
+ pushStreamChunk(chunk, state) {
120
+ const events = [];
121
+ if (chunk.message?.content) {
122
+ events.push({ type: "text_delta", delta: chunk.message.content });
123
+ }
124
+ for (const call of chunk.message?.tool_calls ?? []) {
125
+ const normalized = normalizeToolCall("", call.function.name, call.function.arguments);
126
+ if (!normalized)
127
+ continue;
128
+ const key = `${normalized.name}:${normalized.arguments}`;
129
+ if (!state.pendingToolCalls.has(key)) {
130
+ state.pendingToolCalls.set(key, {
131
+ id: `call_${state.pendingToolCalls.size + 1}`,
132
+ name: normalized.name,
133
+ arguments: JSON.parse(normalized.arguments),
134
+ });
135
+ }
136
+ }
137
+ if (chunk.done)
138
+ state.finalChunk = chunk;
139
+ return { events };
140
+ }
141
+ finishStream(state, final) {
142
+ const terminal = final ?? state.finalChunk;
143
+ const events = Array.from(state.pendingToolCalls.values(), call => ({ type: "tool_call", ...call }));
144
+ const usage = this.normalizeUsage(terminal);
145
+ if (usage) {
146
+ const rawStopReason = terminal?.done_reason;
147
+ const stopReason = this.normalizeStopReason(rawStopReason);
148
+ events.push({
149
+ type: "usage",
150
+ totalTokens: usage.inputTokens + usage.outputTokens,
151
+ inputTokens: usage.inputTokens,
152
+ outputTokens: usage.outputTokens,
153
+ providerUsage: usage,
154
+ ...(stopReason ? { stopReason } : {}),
155
+ ...(rawStopReason ? { rawStopReason } : {}),
156
+ });
157
+ }
158
+ return { events };
159
+ }
160
+ normalizeUsage(raw) {
161
+ if (raw === undefined || raw === null)
162
+ return undefined;
163
+ if (typeof raw !== "object" || Array.isArray(raw)) {
164
+ throw new ProtocolResponseError("ollama-chat", "usage source must be an object");
165
+ }
166
+ const record = raw;
167
+ const inputTokens = validCount(record, "prompt_eval_count");
168
+ const outputTokens = validCount(record, "eval_count");
169
+ if (inputTokens === undefined && outputTokens === undefined)
170
+ return undefined;
171
+ return {
172
+ inputTokens: inputTokens ?? 0,
173
+ outputTokens: outputTokens ?? 0,
174
+ };
175
+ }
176
+ normalizeStopReason(raw) {
177
+ if (raw === undefined)
178
+ return undefined;
179
+ switch (raw) {
180
+ case "stop": return "end_turn";
181
+ case "length": return "max_tokens";
182
+ default: return "other";
183
+ }
184
+ }
185
+ createNdjsonDecoder() {
186
+ return new OllamaNdjsonDecoder();
187
+ }
188
+ }
@@ -1,12 +1,17 @@
1
1
  import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
2
+ import { type CanonicalAdapterInput } from "./content-normalization.js";
3
+ type ResolvedOllamaRuntime = CanonicalAdapterInput["resolved"];
2
4
  export declare class OllamaProvider implements LLMProvider {
3
5
  private readonly model;
4
6
  private readonly baseUrl;
5
- constructor(model?: string, baseUrl?: string);
7
+ private readonly resolvedRuntimePolicy;
8
+ private resolvedRuntime?;
9
+ private readonly adapter;
10
+ constructor(model?: string, baseUrl?: string, resolvedRuntimePolicy?: RuntimePolicy, resolvedRuntime?: ResolvedOllamaRuntime | undefined);
6
11
  runtimePolicy(): RuntimePolicy;
7
- private toOllamaMessages;
8
- private buildTools;
9
- private requestExtensions;
12
+ bindResolvedRuntime(resolved: ResolvedOllamaRuntime): void;
13
+ private adapterInput;
10
14
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
11
15
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
12
16
  }
17
+ export {};