@opencode-ai/ai 0.0.0-next-16897 → 0.0.0-next-16899
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.
|
@@ -207,7 +207,7 @@ export declare const OpenAIChatEvent: Schema.Struct<{
|
|
|
207
207
|
readonly reasoning_text: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
208
208
|
readonly reasoning_details: Schema.optional<Schema.NullOr<Schema.Unknown>>;
|
|
209
209
|
readonly tool_calls: Schema.optional<Schema.NullOr<Schema.$Array<Schema.Struct<{
|
|
210
|
-
readonly index: Schema.Number
|
|
210
|
+
readonly index: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
211
211
|
readonly id: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
212
212
|
readonly function: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
213
213
|
readonly name: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
@@ -218,18 +218,20 @@ export declare const OpenAIChatEvent: Schema.Struct<{
|
|
|
218
218
|
readonly finish_reason: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
219
219
|
readonly native_finish_reason: Schema.optional<Schema.NullOr<Schema.String>>;
|
|
220
220
|
}>>>>;
|
|
221
|
-
readonly usage: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
222
|
-
readonly prompt_tokens: Schema.optional<Schema.Number
|
|
223
|
-
readonly completion_tokens: Schema.optional<Schema.Number
|
|
224
|
-
readonly total_tokens: Schema.optional<Schema.Number
|
|
225
|
-
readonly prompt_tokens_details: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
226
|
-
readonly cached_tokens: Schema.optional<Schema.Number
|
|
227
|
-
readonly cache_write_tokens: Schema.optional<Schema.Number
|
|
228
|
-
}>>>;
|
|
229
|
-
readonly completion_tokens_details: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
230
|
-
readonly reasoning_tokens: Schema.optional<Schema.Number
|
|
231
|
-
|
|
232
|
-
|
|
221
|
+
readonly usage: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
|
|
222
|
+
readonly prompt_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
223
|
+
readonly completion_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
224
|
+
readonly total_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
225
|
+
readonly prompt_tokens_details: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
|
|
226
|
+
readonly cached_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
227
|
+
readonly cache_write_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
228
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
|
|
229
|
+
readonly completion_tokens_details: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
|
|
230
|
+
readonly reasoning_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
231
|
+
readonly accepted_prediction_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
232
|
+
readonly rejected_prediction_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
233
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
|
|
234
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
|
|
233
235
|
readonly error: Schema.optional<Schema.NullOr<Schema.Struct<{
|
|
234
236
|
readonly code: Schema.optional<Schema.NullOr<Schema.Union<readonly [Schema.String, Schema.Number]>>>;
|
|
235
237
|
readonly message: Schema.String;
|
|
@@ -252,6 +254,8 @@ export interface ParserState {
|
|
|
252
254
|
readonly reasoningDetails: Array<unknown>;
|
|
253
255
|
readonly reasoningDetailsObserved: boolean;
|
|
254
256
|
readonly reasoningEmitted: boolean;
|
|
257
|
+
readonly latestToolIndex?: number;
|
|
258
|
+
readonly nextToolIndex: number;
|
|
255
259
|
}
|
|
256
260
|
interface LoweringOptions {
|
|
257
261
|
readonly cacheControl?: (cache: CacheHint | undefined) => Schema.Schema.Type<typeof OpenAIChatCacheControl> | undefined;
|
|
@@ -552,15 +556,20 @@ export declare const protocol: Protocol<{
|
|
|
552
556
|
readonly code?: string | number | null | undefined;
|
|
553
557
|
} | null | undefined;
|
|
554
558
|
readonly usage?: {
|
|
555
|
-
readonly
|
|
556
|
-
readonly
|
|
557
|
-
readonly
|
|
559
|
+
readonly [x: string]: unknown;
|
|
560
|
+
readonly prompt_tokens?: number | null | undefined;
|
|
561
|
+
readonly completion_tokens?: number | null | undefined;
|
|
562
|
+
readonly total_tokens?: number | null | undefined;
|
|
558
563
|
readonly prompt_tokens_details?: {
|
|
559
|
-
readonly
|
|
560
|
-
readonly
|
|
564
|
+
readonly [x: string]: unknown;
|
|
565
|
+
readonly cached_tokens?: number | null | undefined;
|
|
566
|
+
readonly cache_write_tokens?: number | null | undefined;
|
|
561
567
|
} | null | undefined;
|
|
562
568
|
readonly completion_tokens_details?: {
|
|
563
|
-
readonly
|
|
569
|
+
readonly [x: string]: unknown;
|
|
570
|
+
readonly reasoning_tokens?: number | null | undefined;
|
|
571
|
+
readonly accepted_prediction_tokens?: number | null | undefined;
|
|
572
|
+
readonly rejected_prediction_tokens?: number | null | undefined;
|
|
564
573
|
} | null | undefined;
|
|
565
574
|
} | null | undefined;
|
|
566
575
|
readonly choices?: readonly {
|
|
@@ -571,12 +580,12 @@ export declare const protocol: Protocol<{
|
|
|
571
580
|
readonly reasoning_text?: string | null | undefined;
|
|
572
581
|
readonly content?: string | null | undefined;
|
|
573
582
|
readonly tool_calls?: readonly {
|
|
574
|
-
readonly index: number;
|
|
575
583
|
readonly function?: {
|
|
576
584
|
readonly name?: string | null | undefined;
|
|
577
585
|
readonly arguments?: string | null | undefined;
|
|
578
586
|
} | null | undefined;
|
|
579
587
|
readonly id?: string | null | undefined;
|
|
588
|
+
readonly index?: number | null | undefined;
|
|
580
589
|
}[] | null | undefined;
|
|
581
590
|
readonly reasoning_details?: unknown;
|
|
582
591
|
} | null | undefined;
|
|
@@ -45,6 +45,11 @@ const OpenAIChatAssistantToolCall = Schema.Struct({
|
|
|
45
45
|
arguments: Schema.String,
|
|
46
46
|
}),
|
|
47
47
|
});
|
|
48
|
+
// Intentionally omit Gemini's provider-specific `extra_content.google.thought_signature`
|
|
49
|
+
// extension until direct Google OpenAI-compatible routing is supported here:
|
|
50
|
+
// https://github.com/vercel/ai/issues/11590
|
|
51
|
+
// https://github.com/vercel/ai/pull/11745
|
|
52
|
+
// https://ai.google.dev/gemini-api/docs/thought-signatures#openai
|
|
48
53
|
const OpenAIChatUserContent = Schema.Union([
|
|
49
54
|
Schema.Struct({
|
|
50
55
|
type: Schema.Literal("text"),
|
|
@@ -114,24 +119,26 @@ const OpenAIChatBody = Schema.Struct(bodyFields);
|
|
|
114
119
|
// The event schema is one decoded SSE `data:` payload. `Framing.sse` splits the
|
|
115
120
|
// byte stream into strings, then `Protocol.jsonEvent` decodes each string into
|
|
116
121
|
// this provider-native event shape.
|
|
117
|
-
const OpenAIChatUsage = Schema.Struct({
|
|
118
|
-
prompt_tokens:
|
|
119
|
-
completion_tokens:
|
|
120
|
-
total_tokens:
|
|
121
|
-
prompt_tokens_details: optionalNull(Schema.Struct({
|
|
122
|
-
cached_tokens:
|
|
123
|
-
cache_write_tokens:
|
|
124
|
-
})),
|
|
125
|
-
completion_tokens_details: optionalNull(Schema.Struct({
|
|
126
|
-
reasoning_tokens:
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
const OpenAIChatUsage = Schema.StructWithRest(Schema.Struct({
|
|
123
|
+
prompt_tokens: optionalNull(Schema.Number),
|
|
124
|
+
completion_tokens: optionalNull(Schema.Number),
|
|
125
|
+
total_tokens: optionalNull(Schema.Number),
|
|
126
|
+
prompt_tokens_details: optionalNull(Schema.StructWithRest(Schema.Struct({
|
|
127
|
+
cached_tokens: optionalNull(Schema.Number),
|
|
128
|
+
cache_write_tokens: optionalNull(Schema.Number),
|
|
129
|
+
}), [Schema.Record(Schema.String, Schema.Unknown)])),
|
|
130
|
+
completion_tokens_details: optionalNull(Schema.StructWithRest(Schema.Struct({
|
|
131
|
+
reasoning_tokens: optionalNull(Schema.Number),
|
|
132
|
+
accepted_prediction_tokens: optionalNull(Schema.Number),
|
|
133
|
+
rejected_prediction_tokens: optionalNull(Schema.Number),
|
|
134
|
+
}), [Schema.Record(Schema.String, Schema.Unknown)])),
|
|
135
|
+
}), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
129
136
|
const OpenAIChatToolCallDeltaFunction = Schema.Struct({
|
|
130
137
|
name: optionalNull(Schema.String),
|
|
131
138
|
arguments: optionalNull(Schema.String),
|
|
132
139
|
});
|
|
133
140
|
const OpenAIChatToolCallDelta = Schema.Struct({
|
|
134
|
-
index: Schema.Number,
|
|
141
|
+
index: optionalNull(Schema.Number),
|
|
135
142
|
id: optionalNull(Schema.String),
|
|
136
143
|
function: optionalNull(OpenAIChatToolCallDeltaFunction),
|
|
137
144
|
});
|
|
@@ -449,21 +456,29 @@ const mapFinishReason = (reason) => {
|
|
|
449
456
|
const mapUsage = (usage) => {
|
|
450
457
|
if (!usage)
|
|
451
458
|
return undefined;
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
const
|
|
459
|
+
const input = usage.prompt_tokens ?? undefined;
|
|
460
|
+
const output = usage.completion_tokens ?? undefined;
|
|
461
|
+
const cached = usage.prompt_tokens_details?.cached_tokens ?? undefined;
|
|
462
|
+
const cacheWrite = usage.prompt_tokens_details?.cache_write_tokens ?? undefined;
|
|
463
|
+
const reasoning = usage.completion_tokens_details?.reasoning_tokens ?? undefined;
|
|
464
|
+
const nonCached = ProviderShared.subtractTokens(input, ProviderShared.sumTokens(cached, cacheWrite));
|
|
456
465
|
return new Usage({
|
|
457
|
-
inputTokens:
|
|
458
|
-
outputTokens:
|
|
466
|
+
inputTokens: input,
|
|
467
|
+
outputTokens: output,
|
|
459
468
|
nonCachedInputTokens: nonCached,
|
|
460
469
|
cacheReadInputTokens: cached,
|
|
461
470
|
cacheWriteInputTokens: cacheWrite,
|
|
462
471
|
reasoningTokens: reasoning,
|
|
463
|
-
totalTokens: ProviderShared.totalTokens(
|
|
472
|
+
totalTokens: ProviderShared.totalTokens(input, output, usage.total_tokens ?? undefined),
|
|
464
473
|
providerMetadata: { openai: usage },
|
|
465
474
|
});
|
|
466
475
|
};
|
|
476
|
+
const toolIndexByID = (tools, pendingTools, id) => {
|
|
477
|
+
if (!id)
|
|
478
|
+
return undefined;
|
|
479
|
+
const entry = Object.entries({ ...pendingTools, ...tools }).find(([, tool]) => tool?.id === id);
|
|
480
|
+
return entry ? Number(entry[0]) : undefined;
|
|
481
|
+
};
|
|
467
482
|
const reasoningDelta = (delta, configuredField) => {
|
|
468
483
|
if (!delta)
|
|
469
484
|
return undefined;
|
|
@@ -536,15 +551,27 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
536
551
|
const events = [];
|
|
537
552
|
const usage = mapUsage(event.usage) ?? state.usage;
|
|
538
553
|
const choice = event.choices?.[0];
|
|
539
|
-
const
|
|
540
|
-
|
|
554
|
+
const rawFinishReason = choice?.finish_reason;
|
|
555
|
+
const finishReason = rawFinishReason !== undefined && rawFinishReason !== null
|
|
556
|
+
? { normalized: mapFinishReason(rawFinishReason), raw: choice?.native_finish_reason ?? rawFinishReason }
|
|
541
557
|
: state.finishReason;
|
|
542
558
|
const delta = choice?.delta;
|
|
543
559
|
const toolDeltas = delta?.tool_calls ?? [];
|
|
544
560
|
let tools = state.tools;
|
|
545
561
|
let pendingTools = state.pendingTools;
|
|
562
|
+
let latestToolIndex = state.latestToolIndex;
|
|
563
|
+
let nextToolIndex = state.nextToolIndex;
|
|
546
564
|
let lifecycle = state.lifecycle;
|
|
547
565
|
const reasoning = reasoningDelta(delta, state.reasoningField);
|
|
566
|
+
const hasLateContent = Boolean(delta?.content) ||
|
|
567
|
+
reasoning !== undefined ||
|
|
568
|
+
(Array.isArray(delta?.reasoning_details) && delta.reasoning_details.length > 0) ||
|
|
569
|
+
toolDeltas.some((tool) => Boolean(tool.id) || Boolean(tool.function?.name) || Boolean(tool.function?.arguments));
|
|
570
|
+
if (state.finishReason !== undefined) {
|
|
571
|
+
if (hasLateContent)
|
|
572
|
+
return yield* ProviderShared.eventError(ADAPTER, "OpenAI Chat received content after the finish reason");
|
|
573
|
+
return [{ ...state, usage }, events];
|
|
574
|
+
}
|
|
548
575
|
const reasoningField = state.reasoningField ?? (!state.lifecycle.text.has("text-0") ? reasoning?.field : undefined);
|
|
549
576
|
const detailDelta = Array.isArray(delta?.reasoning_details) ? delta.reasoning_details : undefined;
|
|
550
577
|
if (detailDelta !== undefined)
|
|
@@ -563,21 +590,33 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
563
590
|
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
|
|
564
591
|
lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", delta.content);
|
|
565
592
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
593
|
+
// Compatible providers may omit indexes. Prefer durable identity, then use
|
|
594
|
+
// batch position for parallel deltas or the latest call for sparse chunks.
|
|
595
|
+
for (const [position, tool] of toolDeltas.entries()) {
|
|
596
|
+
const matched = toolIndexByID(tools, pendingTools, tool.id || undefined);
|
|
597
|
+
const fallback = toolDeltas.length > 1 ? position : (latestToolIndex ?? position);
|
|
598
|
+
const fallbackTool = tools[fallback] ?? pendingTools[fallback];
|
|
599
|
+
const index = tool.index ?? matched ??
|
|
600
|
+
(tool.id && fallbackTool?.id && fallbackTool.id !== tool.id ? nextToolIndex : fallback);
|
|
601
|
+
const current = tools[index];
|
|
602
|
+
const pending = pendingTools[index];
|
|
569
603
|
const id = current?.id ?? pending?.id ?? (tool.id || undefined);
|
|
570
604
|
const name = current?.name ?? pending?.name ?? (tool.function?.name || undefined);
|
|
571
605
|
const text = `${pending?.input ?? ""}${tool.function?.arguments ?? ""}`;
|
|
606
|
+
latestToolIndex = index;
|
|
607
|
+
nextToolIndex = Math.max(nextToolIndex, index + 1);
|
|
572
608
|
if (!current && (!id || !name)) {
|
|
573
|
-
pendingTools = {
|
|
609
|
+
pendingTools = {
|
|
610
|
+
...pendingTools,
|
|
611
|
+
[index]: { id: id || undefined, name: name || undefined, input: text },
|
|
612
|
+
};
|
|
574
613
|
continue;
|
|
575
614
|
}
|
|
576
615
|
if (pending) {
|
|
577
616
|
pendingTools = { ...pendingTools };
|
|
578
|
-
delete pendingTools[
|
|
617
|
+
delete pendingTools[index];
|
|
579
618
|
}
|
|
580
|
-
const result = ToolStream.appendOrStart(ADAPTER, tools,
|
|
619
|
+
const result = ToolStream.appendOrStart(ADAPTER, tools, index, { id: id || undefined, name: name || undefined, text }, "OpenAI Chat tool call delta is missing id or name");
|
|
581
620
|
if (ToolStream.isError(result))
|
|
582
621
|
return yield* result;
|
|
583
622
|
tools = result.tools;
|
|
@@ -604,6 +643,8 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
604
643
|
reasoningDetails: state.reasoningDetails,
|
|
605
644
|
reasoningDetailsObserved,
|
|
606
645
|
reasoningEmitted,
|
|
646
|
+
latestToolIndex,
|
|
647
|
+
nextToolIndex,
|
|
607
648
|
},
|
|
608
649
|
events,
|
|
609
650
|
];
|
|
@@ -654,6 +695,7 @@ export const protocol = Protocol.make({
|
|
|
654
695
|
reasoningDetails: [],
|
|
655
696
|
reasoningDetailsObserved: false,
|
|
656
697
|
reasoningEmitted: false,
|
|
698
|
+
nextToolIndex: 0,
|
|
657
699
|
}),
|
|
658
700
|
step,
|
|
659
701
|
onHalt: finishEvents,
|
|
@@ -285,15 +285,20 @@ export declare const protocol: Protocol<{
|
|
|
285
285
|
readonly code?: string | number | null | undefined;
|
|
286
286
|
} | null | undefined;
|
|
287
287
|
readonly usage?: {
|
|
288
|
-
readonly
|
|
289
|
-
readonly
|
|
290
|
-
readonly
|
|
288
|
+
readonly [x: string]: unknown;
|
|
289
|
+
readonly prompt_tokens?: number | null | undefined;
|
|
290
|
+
readonly completion_tokens?: number | null | undefined;
|
|
291
|
+
readonly total_tokens?: number | null | undefined;
|
|
291
292
|
readonly prompt_tokens_details?: {
|
|
292
|
-
readonly
|
|
293
|
-
readonly
|
|
293
|
+
readonly [x: string]: unknown;
|
|
294
|
+
readonly cached_tokens?: number | null | undefined;
|
|
295
|
+
readonly cache_write_tokens?: number | null | undefined;
|
|
294
296
|
} | null | undefined;
|
|
295
297
|
readonly completion_tokens_details?: {
|
|
296
|
-
readonly
|
|
298
|
+
readonly [x: string]: unknown;
|
|
299
|
+
readonly reasoning_tokens?: number | null | undefined;
|
|
300
|
+
readonly accepted_prediction_tokens?: number | null | undefined;
|
|
301
|
+
readonly rejected_prediction_tokens?: number | null | undefined;
|
|
297
302
|
} | null | undefined;
|
|
298
303
|
} | null | undefined;
|
|
299
304
|
readonly choices?: readonly {
|
|
@@ -304,12 +309,12 @@ export declare const protocol: Protocol<{
|
|
|
304
309
|
readonly reasoning_text?: string | null | undefined;
|
|
305
310
|
readonly content?: string | null | undefined;
|
|
306
311
|
readonly tool_calls?: readonly {
|
|
307
|
-
readonly index: number;
|
|
308
312
|
readonly function?: {
|
|
309
313
|
readonly name?: string | null | undefined;
|
|
310
314
|
readonly arguments?: string | null | undefined;
|
|
311
315
|
} | null | undefined;
|
|
312
316
|
readonly id?: string | null | undefined;
|
|
317
|
+
readonly index?: number | null | undefined;
|
|
313
318
|
}[] | null | undefined;
|
|
314
319
|
readonly reasoning_details?: unknown;
|
|
315
320
|
} | null | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-16899",
|
|
4
4
|
"name": "@opencode-ai/ai",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@clack/prompts": "1.0.0-alpha.1",
|
|
32
32
|
"@effect/platform-node": "4.0.0-beta.101",
|
|
33
|
-
"@opencode-ai/http-recorder": "0.0.0-next-
|
|
33
|
+
"@opencode-ai/http-recorder": "0.0.0-next-16899",
|
|
34
34
|
"@tsconfig/bun": "1.0.9",
|
|
35
35
|
"@types/bun": "1.3.13",
|
|
36
36
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@smithy/eventstream-codec": "4.2.14",
|
|
41
41
|
"@smithy/util-utf8": "4.2.2",
|
|
42
|
-
"@opencode-ai/schema": "0.0.0-next-
|
|
42
|
+
"@opencode-ai/schema": "0.0.0-next-16899",
|
|
43
43
|
"aws4fetch": "1.0.20",
|
|
44
44
|
"effect": "4.0.0-beta.101",
|
|
45
45
|
"google-auth-library": "10.5.0"
|