@opencode-ai/ai 0.0.0-bootstrap.0 → 0.0.0-next-15618

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 +176 -1
  2. package/dist/cache-policy.d.ts +2 -0
  3. package/dist/cache-policy.js +108 -0
  4. package/dist/index.d.ts +14 -0
  5. package/dist/index.js +9 -0
  6. package/dist/llm.d.ts +223 -0
  7. package/dist/llm.js +81 -0
  8. package/dist/protocols/anthropic-messages.d.ts +503 -0
  9. package/dist/protocols/anthropic-messages.js +745 -0
  10. package/dist/protocols/bedrock-converse.d.ts +476 -0
  11. package/dist/protocols/bedrock-converse.js +526 -0
  12. package/dist/protocols/bedrock-event-stream.d.ts +9 -0
  13. package/dist/protocols/bedrock-event-stream.js +64 -0
  14. package/dist/protocols/gemini.d.ts +220 -0
  15. package/dist/protocols/gemini.js +420 -0
  16. package/dist/protocols/google-vertex-anthropic.d.ts +494 -0
  17. package/dist/protocols/google-vertex-anthropic.js +33 -0
  18. package/dist/protocols/google-vertex-gemini.d.ts +59 -0
  19. package/dist/protocols/google-vertex-gemini.js +18 -0
  20. package/dist/protocols/index.d.ts +9 -0
  21. package/dist/protocols/index.js +9 -0
  22. package/dist/protocols/openai-chat.d.ts +391 -0
  23. package/dist/protocols/openai-chat.js +423 -0
  24. package/dist/protocols/openai-compatible-chat.d.ts +73 -0
  25. package/dist/protocols/openai-compatible-chat.js +20 -0
  26. package/dist/protocols/openai-compatible-responses.d.ts +85 -0
  27. package/dist/protocols/openai-compatible-responses.js +18 -0
  28. package/dist/protocols/openai-responses.d.ts +613 -0
  29. package/dist/protocols/openai-responses.js +828 -0
  30. package/dist/protocols/shared.d.ts +192 -0
  31. package/dist/protocols/shared.js +236 -0
  32. package/dist/protocols/utils/bedrock-auth.d.ts +18 -0
  33. package/dist/protocols/utils/bedrock-auth.js +41 -0
  34. package/dist/protocols/utils/bedrock-cache.d.ts +15 -0
  35. package/dist/protocols/utils/bedrock-cache.js +29 -0
  36. package/dist/protocols/utils/bedrock-media.d.ts +49 -0
  37. package/dist/protocols/utils/bedrock-media.js +68 -0
  38. package/dist/protocols/utils/cache.d.ts +6 -0
  39. package/dist/protocols/utils/cache.js +8 -0
  40. package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
  41. package/dist/protocols/utils/gemini-tool-schema.js +83 -0
  42. package/dist/protocols/utils/lifecycle.d.ts +19 -0
  43. package/dist/protocols/utils/lifecycle.js +65 -0
  44. package/dist/protocols/utils/openai-options.d.ts +22 -0
  45. package/dist/protocols/utils/openai-options.js +64 -0
  46. package/dist/protocols/utils/tool-schema.d.ts +7 -0
  47. package/dist/protocols/utils/tool-schema.js +79 -0
  48. package/dist/protocols/utils/tool-stream.d.ts +155 -0
  49. package/dist/protocols/utils/tool-stream.js +136 -0
  50. package/dist/protocols.d.ts +1 -0
  51. package/dist/protocols.js +1 -0
  52. package/dist/provider-error.d.ts +13 -0
  53. package/dist/provider-error.js +122 -0
  54. package/dist/provider-package.d.ts +13 -0
  55. package/dist/provider-package.js +1 -0
  56. package/dist/provider.d.ts +23 -0
  57. package/dist/provider.js +2 -0
  58. package/dist/providers/amazon-bedrock.d.ts +150 -0
  59. package/dist/providers/amazon-bedrock.js +41 -0
  60. package/dist/providers/anthropic-compatible.d.ts +183 -0
  61. package/dist/providers/anthropic-compatible.js +44 -0
  62. package/dist/providers/anthropic.d.ts +181 -0
  63. package/dist/providers/anthropic.js +39 -0
  64. package/dist/providers/azure/chat.d.ts +2 -0
  65. package/dist/providers/azure/chat.js +1 -0
  66. package/dist/providers/azure/responses.d.ts +2 -0
  67. package/dist/providers/azure/responses.js +1 -0
  68. package/dist/providers/azure.d.ts +183 -0
  69. package/dist/providers/azure.js +89 -0
  70. package/dist/providers/cloudflare.d.ts +232 -0
  71. package/dist/providers/cloudflare.js +87 -0
  72. package/dist/providers/github-copilot.d.ts +167 -0
  73. package/dist/providers/github-copilot.js +47 -0
  74. package/dist/providers/google-vertex/anthropic.d.ts +2 -0
  75. package/dist/providers/google-vertex/anthropic.js +1 -0
  76. package/dist/providers/google-vertex-anthropic.d.ts +181 -0
  77. package/dist/providers/google-vertex-anthropic.js +46 -0
  78. package/dist/providers/google-vertex-shared.d.ts +22 -0
  79. package/dist/providers/google-vertex-shared.js +61 -0
  80. package/dist/providers/google-vertex.d.ts +93 -0
  81. package/dist/providers/google-vertex.js +49 -0
  82. package/dist/providers/google.d.ts +85 -0
  83. package/dist/providers/google.js +33 -0
  84. package/dist/providers/index.d.ts +15 -0
  85. package/dist/providers/index.js +15 -0
  86. package/dist/providers/openai/chat.d.ts +2 -0
  87. package/dist/providers/openai/chat.js +1 -0
  88. package/dist/providers/openai/responses.d.ts +2 -0
  89. package/dist/providers/openai/responses.js +1 -0
  90. package/dist/providers/openai-compatible/responses.d.ts +1 -0
  91. package/dist/providers/openai-compatible/responses.js +1 -0
  92. package/dist/providers/openai-compatible-profile.d.ts +43 -0
  93. package/dist/providers/openai-compatible-profile.js +12 -0
  94. package/dist/providers/openai-compatible-responses.d.ts +107 -0
  95. package/dist/providers/openai-compatible-responses.js +33 -0
  96. package/dist/providers/openai-compatible.d.ts +130 -0
  97. package/dist/providers/openai-compatible.js +55 -0
  98. package/dist/providers/openai-options.d.ts +30 -0
  99. package/dist/providers/openai-options.js +42 -0
  100. package/dist/providers/openai.d.ts +264 -0
  101. package/dist/providers/openai.js +62 -0
  102. package/dist/providers/openrouter.d.ts +321 -0
  103. package/dist/providers/openrouter.js +65 -0
  104. package/dist/providers/xai.d.ts +169 -0
  105. package/dist/providers/xai.js +43 -0
  106. package/dist/providers.d.ts +1 -0
  107. package/dist/providers.js +1 -0
  108. package/dist/route/auth-options.d.ts +34 -0
  109. package/dist/route/auth-options.js +14 -0
  110. package/dist/route/auth.d.ts +49 -0
  111. package/dist/route/auth.js +89 -0
  112. package/dist/route/client.d.ts +330 -0
  113. package/dist/route/client.js +211 -0
  114. package/dist/route/endpoint.d.ts +28 -0
  115. package/dist/route/endpoint.js +21 -0
  116. package/dist/route/executor.d.ts +12 -0
  117. package/dist/route/executor.js +229 -0
  118. package/dist/route/framing.d.ts +23 -0
  119. package/dist/route/framing.js +4 -0
  120. package/dist/route/index.d.ts +16 -0
  121. package/dist/route/index.js +9 -0
  122. package/dist/route/protocol.d.ts +76 -0
  123. package/dist/route/protocol.js +17 -0
  124. package/dist/route/transport/http.d.ts +33 -0
  125. package/dist/route/transport/http.js +98 -0
  126. package/dist/route/transport/index.d.ts +27 -0
  127. package/dist/route/transport/index.js +4 -0
  128. package/dist/route/transport/websocket.d.ts +56 -0
  129. package/dist/route/transport/websocket.js +181 -0
  130. package/dist/route.d.ts +1 -0
  131. package/dist/route.js +1 -0
  132. package/dist/schema/errors.d.ts +153 -0
  133. package/dist/schema/errors.js +150 -0
  134. package/dist/schema/events.d.ts +4292 -0
  135. package/dist/schema/events.js +482 -0
  136. package/dist/schema/ids.d.ts +30 -0
  137. package/dist/schema/ids.js +18 -0
  138. package/dist/schema/index.d.ts +5 -0
  139. package/dist/schema/index.js +5 -0
  140. package/dist/schema/messages.d.ts +385 -0
  141. package/dist/schema/messages.js +246 -0
  142. package/dist/schema/options.d.ts +143 -0
  143. package/dist/schema/options.js +195 -0
  144. package/dist/tool-runtime.d.ts +15 -0
  145. package/dist/tool-runtime.js +35 -0
  146. package/dist/tool.d.ts +134 -0
  147. package/dist/tool.js +66 -0
  148. package/dist/utils/record.d.ts +2 -0
  149. package/dist/utils/record.js +2 -0
  150. package/package.json +36 -9
  151. package/index.js +0 -1
@@ -0,0 +1,482 @@
1
+ import { Schema } from "effect";
2
+ import { ContentBlockID, FinishReason, ProtocolID, ProviderMetadata, RouteID, ToolCallID } from "./ids";
3
+ import { ModelSchema } from "./options";
4
+ import { Message, ToolCallPart, ToolOutput, ToolResultPart, ToolResultValue } from "./messages";
5
+ import { ProviderFailureClassification } from "./errors";
6
+ /**
7
+ * Token usage reported by an LLM provider.
8
+ *
9
+ * **Inclusive totals** (match AI SDK / OpenAI / LangChain convention — a
10
+ * reader from any of those ecosystems sees the number they expect):
11
+ *
12
+ * - `inputTokens` — total prompt tokens, *including* cached reads/writes.
13
+ * - `outputTokens` — total output tokens, *including* reasoning.
14
+ * - `totalTokens` — provider-supplied total, or `inputTokens + outputTokens`.
15
+ *
16
+ * **Non-overlapping breakdown** (every field is independently meaningful;
17
+ * consumers never have to subtract):
18
+ *
19
+ * - `nonCachedInputTokens` — the "fresh" portion of the prompt.
20
+ * - `cacheReadInputTokens` — input tokens served from cache.
21
+ * - `cacheWriteInputTokens` — input tokens written to cache.
22
+ * - `reasoningTokens` — subset of `outputTokens` spent on hidden reasoning.
23
+ *
24
+ * **Invariant**: `nonCachedInputTokens + cacheReadInputTokens +
25
+ * cacheWriteInputTokens = inputTokens`, and `reasoningTokens ≤ outputTokens`.
26
+ * Each protocol mapper computes whichever side it doesn't get natively,
27
+ * with `Math.max(0, …)` clamping for defense against provider bugs. Because
28
+ * every breakdown field is stored independently, downstream consumers can
29
+ * read whatever they need (cost-by-category, context-pressure, AI-SDK-style
30
+ * inclusive total) without ever subtracting — eliminating the underflow
31
+ * class of bug where a clamped difference would silently store the wrong
32
+ * value.
33
+ *
34
+ * **Semantics by provider**:
35
+ *
36
+ * - OpenAI Chat / Responses / Gemini / Bedrock: provider reports inclusive
37
+ * `inputTokens` and an inclusive `outputTokens`; mapper subtracts to
38
+ * derive the breakdown.
39
+ * - Anthropic: provider reports the breakdown natively (`input_tokens` is
40
+ * non-cached only); mapper sums to derive the inclusive `inputTokens`.
41
+ * Anthropic does *not* break extended-thinking out of `output_tokens`, so
42
+ * `reasoningTokens` is `undefined` and `outputTokens` carries the
43
+ * combined total — a documented limitation of the Anthropic API.
44
+ *
45
+ * `providerMetadata` always carries the provider's raw usage payload —
46
+ * keyed by provider name (`{ openai: ... }`, `{ anthropic: ... }`, etc.)
47
+ * — for fields we don't normalize and for billing-level audit trails.
48
+ * Matches the same escape-hatch field on `LLMEvent`.
49
+ */
50
+ export class Usage extends Schema.Class("LLM.Usage")({
51
+ inputTokens: Schema.optional(Schema.Number),
52
+ outputTokens: Schema.optional(Schema.Number),
53
+ nonCachedInputTokens: Schema.optional(Schema.Number),
54
+ cacheReadInputTokens: Schema.optional(Schema.Number),
55
+ cacheWriteInputTokens: Schema.optional(Schema.Number),
56
+ reasoningTokens: Schema.optional(Schema.Number),
57
+ totalTokens: Schema.optional(Schema.Number),
58
+ providerMetadata: Schema.optional(ProviderMetadata),
59
+ }) {
60
+ /**
61
+ * Visible output tokens — `outputTokens` minus `reasoningTokens`, clamped
62
+ * to zero. The one place subtraction happens in this contract; the clamp
63
+ * means a provider reporting `reasoningTokens > outputTokens` produces a
64
+ * harmless zero rather than a negative that crashes downstream schemas.
65
+ */
66
+ get visibleOutputTokens() {
67
+ return Math.max(0, (this.outputTokens ?? 0) - (this.reasoningTokens ?? 0));
68
+ }
69
+ static from(input) {
70
+ return input instanceof Usage ? input : new Usage(input);
71
+ }
72
+ }
73
+ export const StepStart = Schema.Struct({
74
+ type: Schema.tag("step-start"),
75
+ index: Schema.Number,
76
+ }).annotate({ identifier: "LLM.Event.StepStart" });
77
+ export const TextStart = Schema.Struct({
78
+ type: Schema.tag("text-start"),
79
+ id: ContentBlockID,
80
+ providerMetadata: Schema.optional(ProviderMetadata),
81
+ }).annotate({ identifier: "LLM.Event.TextStart" });
82
+ export const TextDelta = Schema.Struct({
83
+ type: Schema.tag("text-delta"),
84
+ id: ContentBlockID,
85
+ text: Schema.String,
86
+ providerMetadata: Schema.optional(ProviderMetadata),
87
+ }).annotate({ identifier: "LLM.Event.TextDelta" });
88
+ export const TextEnd = Schema.Struct({
89
+ type: Schema.tag("text-end"),
90
+ id: ContentBlockID,
91
+ providerMetadata: Schema.optional(ProviderMetadata),
92
+ }).annotate({ identifier: "LLM.Event.TextEnd" });
93
+ export const ReasoningStart = Schema.Struct({
94
+ type: Schema.tag("reasoning-start"),
95
+ id: ContentBlockID,
96
+ providerMetadata: Schema.optional(ProviderMetadata),
97
+ }).annotate({ identifier: "LLM.Event.ReasoningStart" });
98
+ export const ReasoningDelta = Schema.Struct({
99
+ type: Schema.tag("reasoning-delta"),
100
+ id: ContentBlockID,
101
+ text: Schema.String,
102
+ providerMetadata: Schema.optional(ProviderMetadata),
103
+ }).annotate({ identifier: "LLM.Event.ReasoningDelta" });
104
+ export const ReasoningEnd = Schema.Struct({
105
+ type: Schema.tag("reasoning-end"),
106
+ id: ContentBlockID,
107
+ providerMetadata: Schema.optional(ProviderMetadata),
108
+ }).annotate({ identifier: "LLM.Event.ReasoningEnd" });
109
+ export const ToolInputStart = Schema.Struct({
110
+ type: Schema.tag("tool-input-start"),
111
+ id: ToolCallID,
112
+ name: Schema.String,
113
+ providerMetadata: Schema.optional(ProviderMetadata),
114
+ }).annotate({ identifier: "LLM.Event.ToolInputStart" });
115
+ export const ToolInputDelta = Schema.Struct({
116
+ type: Schema.tag("tool-input-delta"),
117
+ id: ToolCallID,
118
+ name: Schema.String,
119
+ text: Schema.String,
120
+ }).annotate({ identifier: "LLM.Event.ToolInputDelta" });
121
+ export const ToolInputEnd = Schema.Struct({
122
+ type: Schema.tag("tool-input-end"),
123
+ id: ToolCallID,
124
+ name: Schema.String,
125
+ providerMetadata: Schema.optional(ProviderMetadata),
126
+ }).annotate({ identifier: "LLM.Event.ToolInputEnd" });
127
+ export const ToolCall = Schema.Struct({
128
+ type: Schema.tag("tool-call"),
129
+ id: ToolCallID,
130
+ name: Schema.String,
131
+ input: Schema.Unknown,
132
+ providerExecuted: Schema.optional(Schema.Boolean),
133
+ providerMetadata: Schema.optional(ProviderMetadata),
134
+ }).annotate({ identifier: "LLM.Event.ToolCall" });
135
+ export const ToolResult = Schema.Struct({
136
+ type: Schema.tag("tool-result"),
137
+ id: ToolCallID,
138
+ name: Schema.String,
139
+ result: ToolResultValue,
140
+ output: Schema.optional(ToolOutput),
141
+ providerExecuted: Schema.optional(Schema.Boolean),
142
+ providerMetadata: Schema.optional(ProviderMetadata),
143
+ }).annotate({ identifier: "LLM.Event.ToolResult" });
144
+ export const ToolError = Schema.Struct({
145
+ type: Schema.tag("tool-error"),
146
+ id: ToolCallID,
147
+ name: Schema.String,
148
+ message: Schema.String,
149
+ error: Schema.optional(Schema.Defect()),
150
+ providerMetadata: Schema.optional(ProviderMetadata),
151
+ }).annotate({ identifier: "LLM.Event.ToolError" });
152
+ export const StepFinish = Schema.Struct({
153
+ type: Schema.tag("step-finish"),
154
+ index: Schema.Number,
155
+ reason: FinishReason,
156
+ usage: Schema.optional(Usage),
157
+ providerMetadata: Schema.optional(ProviderMetadata),
158
+ }).annotate({ identifier: "LLM.Event.StepFinish" });
159
+ export const Finish = Schema.Struct({
160
+ type: Schema.tag("finish"),
161
+ reason: FinishReason,
162
+ usage: Schema.optional(Usage),
163
+ providerMetadata: Schema.optional(ProviderMetadata),
164
+ }).annotate({ identifier: "LLM.Event.Finish" });
165
+ export const ProviderErrorEvent = Schema.Struct({
166
+ type: Schema.tag("provider-error"),
167
+ message: Schema.String,
168
+ classification: Schema.optional(ProviderFailureClassification),
169
+ providerMetadata: Schema.optional(ProviderMetadata),
170
+ }).annotate({ identifier: "LLM.Event.ProviderError" });
171
+ const llmEventTagged = Schema.Union([
172
+ StepStart,
173
+ TextStart,
174
+ TextDelta,
175
+ TextEnd,
176
+ ReasoningStart,
177
+ ReasoningDelta,
178
+ ReasoningEnd,
179
+ ToolInputStart,
180
+ ToolInputDelta,
181
+ ToolInputEnd,
182
+ ToolCall,
183
+ ToolResult,
184
+ ToolError,
185
+ StepFinish,
186
+ Finish,
187
+ ProviderErrorEvent,
188
+ ]).pipe(Schema.toTaggedUnion("type"));
189
+ const contentBlockID = (value) => ContentBlockID.make(value);
190
+ const toolCallID = (value) => ToolCallID.make(value);
191
+ /**
192
+ * camelCase aliases for `LLMEvent.guards` (provided by `Schema.toTaggedUnion`).
193
+ * Lets consumers write `events.filter(LLMEvent.is.toolCall)` instead of
194
+ * `events.filter(LLMEvent.guards["tool-call"])`.
195
+ */
196
+ export const LLMEvent = Object.assign(llmEventTagged, {
197
+ stepStart: StepStart.make,
198
+ textStart: (input) => TextStart.make({ ...input, id: contentBlockID(input.id) }),
199
+ textDelta: (input) => TextDelta.make({ ...input, id: contentBlockID(input.id) }),
200
+ textEnd: (input) => TextEnd.make({ ...input, id: contentBlockID(input.id) }),
201
+ reasoningStart: (input) => ReasoningStart.make({ ...input, id: contentBlockID(input.id) }),
202
+ reasoningDelta: (input) => ReasoningDelta.make({ ...input, id: contentBlockID(input.id) }),
203
+ reasoningEnd: (input) => ReasoningEnd.make({ ...input, id: contentBlockID(input.id) }),
204
+ toolInputStart: (input) => ToolInputStart.make({ ...input, id: toolCallID(input.id) }),
205
+ toolInputDelta: (input) => ToolInputDelta.make({ ...input, id: toolCallID(input.id) }),
206
+ toolInputEnd: (input) => ToolInputEnd.make({ ...input, id: toolCallID(input.id) }),
207
+ toolCall: (input) => ToolCall.make({ ...input, id: toolCallID(input.id) }),
208
+ toolResult: (input) => ToolResult.make({
209
+ ...input,
210
+ id: toolCallID(input.id),
211
+ output: input.output === undefined ? undefined : ToolOutput.make(input.output.structured, input.output.content),
212
+ }),
213
+ toolError: (input) => ToolError.make({ ...input, id: toolCallID(input.id) }),
214
+ stepFinish: (input) => StepFinish.make({
215
+ ...input,
216
+ usage: input.usage === undefined ? undefined : Usage.from(input.usage),
217
+ }),
218
+ finish: (input) => Finish.make({
219
+ ...input,
220
+ usage: input.usage === undefined ? undefined : Usage.from(input.usage),
221
+ }),
222
+ providerError: ProviderErrorEvent.make,
223
+ is: {
224
+ stepStart: llmEventTagged.guards["step-start"],
225
+ textStart: llmEventTagged.guards["text-start"],
226
+ textDelta: llmEventTagged.guards["text-delta"],
227
+ textEnd: llmEventTagged.guards["text-end"],
228
+ reasoningStart: llmEventTagged.guards["reasoning-start"],
229
+ reasoningDelta: llmEventTagged.guards["reasoning-delta"],
230
+ reasoningEnd: llmEventTagged.guards["reasoning-end"],
231
+ toolInputStart: llmEventTagged.guards["tool-input-start"],
232
+ toolInputDelta: llmEventTagged.guards["tool-input-delta"],
233
+ toolInputEnd: llmEventTagged.guards["tool-input-end"],
234
+ toolCall: llmEventTagged.guards["tool-call"],
235
+ toolResult: llmEventTagged.guards["tool-result"],
236
+ toolError: llmEventTagged.guards["tool-error"],
237
+ stepFinish: llmEventTagged.guards["step-finish"],
238
+ finish: llmEventTagged.guards.finish,
239
+ providerError: llmEventTagged.guards["provider-error"],
240
+ },
241
+ });
242
+ export class PreparedRequest extends Schema.Class("LLM.PreparedRequest")({
243
+ id: Schema.String,
244
+ route: RouteID,
245
+ protocol: ProtocolID,
246
+ model: ModelSchema,
247
+ body: Schema.Unknown,
248
+ metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
249
+ }) {
250
+ }
251
+ const responseText = (events) => events
252
+ .filter(LLMEvent.is.textDelta)
253
+ .map((event) => event.text)
254
+ .join("");
255
+ const responseReasoning = (events) => events
256
+ .filter(LLMEvent.is.reasoningDelta)
257
+ .map((event) => event.text)
258
+ .join("");
259
+ const responseUsage = (events) => events.reduce((usage, event) => ("usage" in event && event.usage !== undefined ? event.usage : usage), undefined);
260
+ const emptyResponseState = () => ({
261
+ events: [],
262
+ message: Message.assistant([]),
263
+ textParts: {},
264
+ reasoningParts: {},
265
+ toolInputs: {},
266
+ });
267
+ const appendEvent = (state, event) => {
268
+ const events = [...state.events, event];
269
+ if (LLMEvent.is.finish(event)) {
270
+ return {
271
+ ...state,
272
+ events,
273
+ usage: event.usage ?? state.usage,
274
+ finishReason: event.reason,
275
+ };
276
+ }
277
+ if (LLMEvent.is.providerError(event)) {
278
+ return {
279
+ ...state,
280
+ events,
281
+ finishReason: state.finishReason ?? "error",
282
+ };
283
+ }
284
+ return {
285
+ ...state,
286
+ events,
287
+ usage: "usage" in event && event.usage !== undefined ? event.usage : state.usage,
288
+ };
289
+ };
290
+ const textContent = (text, providerMetadata) => providerMetadata === undefined ? { type: "text", text } : { type: "text", text, providerMetadata };
291
+ const reasoningContent = (text, providerMetadata) => providerMetadata === undefined ? { type: "reasoning", text } : { type: "reasoning", text, providerMetadata };
292
+ const contentWith = (state, content) => ({
293
+ ...state,
294
+ message: Message.assistant(content),
295
+ });
296
+ const appendContent = (state, part) => contentWith(state, [...state.message.content, part]);
297
+ const replaceContent = (state, index, part) => contentWith(state, state.message.content.map((item, itemIndex) => (itemIndex === index ? part : item)));
298
+ const ensureText = (state, id, providerMetadata) => {
299
+ if (state.textParts[id])
300
+ return state;
301
+ return {
302
+ ...appendContent(state, textContent("", providerMetadata)),
303
+ textParts: {
304
+ ...state.textParts,
305
+ [id]: { contentIndex: state.message.content.length, text: "", providerMetadata },
306
+ },
307
+ };
308
+ };
309
+ const reduceTextDelta = (state, event) => {
310
+ const started = ensureText(state, event.id, event.providerMetadata);
311
+ const current = started.textParts[event.id];
312
+ if (!current)
313
+ return started;
314
+ const text = current.text + event.text;
315
+ const providerMetadata = event.providerMetadata ?? current.providerMetadata;
316
+ return {
317
+ ...replaceContent(started, current.contentIndex, textContent(text, providerMetadata)),
318
+ textParts: { ...started.textParts, [event.id]: { ...current, text, providerMetadata } },
319
+ };
320
+ };
321
+ const reduceTextEnd = (state, event) => {
322
+ const current = state.textParts[event.id];
323
+ if (!current)
324
+ return state;
325
+ const providerMetadata = event.providerMetadata ?? current.providerMetadata;
326
+ return {
327
+ ...replaceContent(state, current.contentIndex, textContent(current.text, providerMetadata)),
328
+ textParts: { ...state.textParts, [event.id]: { ...current, providerMetadata } },
329
+ };
330
+ };
331
+ const ensureReasoning = (state, id, providerMetadata) => {
332
+ if (state.reasoningParts[id])
333
+ return state;
334
+ return {
335
+ ...appendContent(state, reasoningContent("", providerMetadata)),
336
+ reasoningParts: {
337
+ ...state.reasoningParts,
338
+ [id]: { contentIndex: state.message.content.length, text: "", providerMetadata },
339
+ },
340
+ };
341
+ };
342
+ const reduceReasoningDelta = (state, event) => {
343
+ const started = ensureReasoning(state, event.id, event.providerMetadata);
344
+ const current = started.reasoningParts[event.id];
345
+ if (!current)
346
+ return started;
347
+ const text = current.text + event.text;
348
+ const providerMetadata = event.providerMetadata ?? current.providerMetadata;
349
+ return {
350
+ ...replaceContent(started, current.contentIndex, reasoningContent(text, providerMetadata)),
351
+ reasoningParts: { ...started.reasoningParts, [event.id]: { ...current, text, providerMetadata } },
352
+ };
353
+ };
354
+ const reduceReasoningEnd = (state, event) => {
355
+ const current = state.reasoningParts[event.id];
356
+ if (!current)
357
+ return state;
358
+ const providerMetadata = event.providerMetadata ?? current.providerMetadata;
359
+ return {
360
+ ...replaceContent(state, current.contentIndex, reasoningContent(current.text, providerMetadata)),
361
+ reasoningParts: { ...state.reasoningParts, [event.id]: { ...current, providerMetadata } },
362
+ };
363
+ };
364
+ const reduceToolInputStart = (state, event) => ({
365
+ ...state,
366
+ toolInputs: {
367
+ ...state.toolInputs,
368
+ [event.id]: { name: event.name, text: "", providerMetadata: event.providerMetadata },
369
+ },
370
+ });
371
+ const reduceToolInputDelta = (state, event) => {
372
+ const current = state.toolInputs[event.id] ?? { name: event.name, text: "" };
373
+ return {
374
+ ...state,
375
+ toolInputs: { ...state.toolInputs, [event.id]: { ...current, text: current.text + event.text } },
376
+ };
377
+ };
378
+ const reduceToolInputEnd = (state, event) => {
379
+ const current = state.toolInputs[event.id] ?? { name: event.name, text: "" };
380
+ return {
381
+ ...state,
382
+ toolInputs: {
383
+ ...state.toolInputs,
384
+ [event.id]: {
385
+ ...current,
386
+ name: event.name,
387
+ providerMetadata: event.providerMetadata ?? current.providerMetadata,
388
+ },
389
+ },
390
+ };
391
+ };
392
+ const toolCallContent = (event) => ToolCallPart.make({
393
+ id: event.id,
394
+ name: event.name,
395
+ input: event.input,
396
+ ...(event.providerExecuted === undefined ? {} : { providerExecuted: event.providerExecuted }),
397
+ ...(event.providerMetadata === undefined ? {} : { providerMetadata: event.providerMetadata }),
398
+ });
399
+ const toolResultContent = (event) => ToolResultPart.make({
400
+ id: event.id,
401
+ name: event.name,
402
+ result: event.result,
403
+ ...(event.providerExecuted === undefined ? {} : { providerExecuted: event.providerExecuted }),
404
+ ...(event.providerMetadata === undefined ? {} : { providerMetadata: event.providerMetadata }),
405
+ });
406
+ const reduceToolCall = (state, event) => {
407
+ const { [event.id]: _finished, ...toolInputs } = state.toolInputs;
408
+ return { ...appendContent(state, toolCallContent(event)), toolInputs };
409
+ };
410
+ const reduceResponseState = (state, event) => {
411
+ const next = appendEvent(state, event);
412
+ switch (event.type) {
413
+ case "text-start":
414
+ return ensureText(next, event.id, event.providerMetadata);
415
+ case "text-delta":
416
+ return reduceTextDelta(next, event);
417
+ case "text-end":
418
+ return reduceTextEnd(next, event);
419
+ case "reasoning-start":
420
+ return ensureReasoning(next, event.id, event.providerMetadata);
421
+ case "reasoning-delta":
422
+ return reduceReasoningDelta(next, event);
423
+ case "reasoning-end":
424
+ return reduceReasoningEnd(next, event);
425
+ case "tool-input-start":
426
+ return reduceToolInputStart(next, event);
427
+ case "tool-input-delta":
428
+ return reduceToolInputDelta(next, event);
429
+ case "tool-input-end":
430
+ return reduceToolInputEnd(next, event);
431
+ case "tool-call":
432
+ return reduceToolCall(next, event);
433
+ case "tool-result":
434
+ return appendContent(next, toolResultContent(event));
435
+ default:
436
+ return next;
437
+ }
438
+ };
439
+ export class LLMResponse extends Schema.Class("LLM.Response")({
440
+ message: Message,
441
+ events: Schema.Array(LLMEvent),
442
+ usage: Schema.optional(Usage),
443
+ finishReason: FinishReason,
444
+ }) {
445
+ /** Concatenated assistant text assembled from streamed `text-delta` events. */
446
+ get text() {
447
+ return responseText(this.events);
448
+ }
449
+ /** Concatenated reasoning text assembled from streamed `reasoning-delta` events. */
450
+ get reasoning() {
451
+ return responseReasoning(this.events);
452
+ }
453
+ /** Completed tool calls emitted by the provider. */
454
+ get toolCalls() {
455
+ return this.events.filter(LLMEvent.is.toolCall);
456
+ }
457
+ }
458
+ (function (LLMResponse) {
459
+ /** Initial reducer state for assembling one provider attempt. */
460
+ LLMResponse.empty = emptyResponseState;
461
+ /** Purely fold one provider-neutral event into the attempt assembly state. */
462
+ LLMResponse.reduce = reduceResponseState;
463
+ /** Return a completed response only after a terminal finish or provider error. */
464
+ LLMResponse.complete = (state) => state.finishReason === undefined
465
+ ? undefined
466
+ : new LLMResponse({
467
+ message: state.message,
468
+ events: [...state.events],
469
+ usage: state.usage,
470
+ finishReason: state.finishReason,
471
+ });
472
+ /** Convenience reducer for callers that already have a collected event list. */
473
+ LLMResponse.fromEvents = (events) => LLMResponse.complete(events.reduce(LLMResponse.reduce, LLMResponse.empty()));
474
+ /** Concatenate assistant text from a response or collected event list. */
475
+ LLMResponse.text = (response) => responseText(response.events);
476
+ /** Return response usage, falling back to the latest usage-bearing event. */
477
+ LLMResponse.usage = (response) => response.usage ?? responseUsage(response.events);
478
+ /** Return completed tool calls from a response or collected event list. */
479
+ LLMResponse.toolCalls = (response) => response.events.filter(LLMEvent.is.toolCall);
480
+ /** Concatenate reasoning text from a response or collected event list. */
481
+ LLMResponse.reasoning = (response) => responseReasoning(response.events);
482
+ })(LLMResponse || (LLMResponse = {}));
@@ -0,0 +1,30 @@
1
+ import { Schema } from "effect";
2
+ import { ProviderMetadata } from "@opencode-ai/schema/llm";
3
+ export { ProviderMetadata };
4
+ /** Stable string identifier for a protocol implementation. */
5
+ export declare const ProtocolID: Schema.String;
6
+ export type ProtocolID = Schema.Schema.Type<typeof ProtocolID>;
7
+ /** Stable string identifier for the runnable route. */
8
+ export declare const RouteID: Schema.String;
9
+ export type RouteID = Schema.Schema.Type<typeof RouteID>;
10
+ export declare const ModelID: Schema.brand<Schema.String, "LLM.ModelID">;
11
+ export type ModelID = typeof ModelID.Type;
12
+ export declare const ProviderID: Schema.brand<Schema.String, "LLM.ProviderID">;
13
+ export type ProviderID = typeof ProviderID.Type;
14
+ export declare const ResponseID: Schema.String;
15
+ export type ResponseID = Schema.Schema.Type<typeof ResponseID>;
16
+ export declare const ContentBlockID: Schema.String;
17
+ export type ContentBlockID = Schema.Schema.Type<typeof ContentBlockID>;
18
+ export declare const ToolCallID: Schema.String;
19
+ export type ToolCallID = Schema.Schema.Type<typeof ToolCallID>;
20
+ export declare const ReasoningEfforts: readonly ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
21
+ export declare const ReasoningEffort: Schema.String;
22
+ export type ReasoningEffort = Schema.Schema.Type<typeof ReasoningEffort>;
23
+ export declare const TextVerbosity: Schema.Literals<readonly ["low", "medium", "high"]>;
24
+ export type TextVerbosity = Schema.Schema.Type<typeof TextVerbosity>;
25
+ export declare const MessageRole: Schema.Literals<readonly ["system", "user", "assistant", "tool"]>;
26
+ export type MessageRole = Schema.Schema.Type<typeof MessageRole>;
27
+ export declare const FinishReason: Schema.Literals<readonly ["stop", "length", "tool-calls", "content-filter", "error", "unknown"]>;
28
+ export type FinishReason = Schema.Schema.Type<typeof FinishReason>;
29
+ export declare const JsonSchema: Schema.$Record<Schema.String, Schema.Unknown>;
30
+ export type JsonSchema = Schema.Schema.Type<typeof JsonSchema>;
@@ -0,0 +1,18 @@
1
+ import { Schema } from "effect";
2
+ import { LLM, ProviderMetadata } from "@opencode-ai/schema/llm";
3
+ export { ProviderMetadata };
4
+ /** Stable string identifier for a protocol implementation. */
5
+ export const ProtocolID = Schema.String;
6
+ /** Stable string identifier for the runnable route. */
7
+ export const RouteID = Schema.String;
8
+ export const ModelID = Schema.String.pipe(Schema.brand("LLM.ModelID"));
9
+ export const ProviderID = Schema.String.pipe(Schema.brand("LLM.ProviderID"));
10
+ export const ResponseID = Schema.String;
11
+ export const ContentBlockID = Schema.String;
12
+ export const ToolCallID = Schema.String;
13
+ export const ReasoningEfforts = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
14
+ export const ReasoningEffort = Schema.String;
15
+ export const TextVerbosity = Schema.Literals(["low", "medium", "high"]);
16
+ export const MessageRole = Schema.Literals(["system", "user", "assistant", "tool"]);
17
+ export const FinishReason = LLM.FinishReason;
18
+ export const JsonSchema = Schema.Record(Schema.String, Schema.Unknown);
@@ -0,0 +1,5 @@
1
+ export * from "./ids";
2
+ export * from "./options";
3
+ export * from "./messages";
4
+ export * from "./events";
5
+ export * from "./errors";
@@ -0,0 +1,5 @@
1
+ export * from "./ids";
2
+ export * from "./options";
3
+ export * from "./messages";
4
+ export * from "./events";
5
+ export * from "./errors";