@opencode/ai 0.0.0-dev-20546 → 0.0.0-dev-20549

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.
package/README.md CHANGED
@@ -106,6 +106,41 @@ for await (const event of ai.llm.stream(ai.llm.request(input))) {
106
106
  await ai.dispose()
107
107
  ```
108
108
 
109
+ ## Venice AI
110
+
111
+ `Venice` provides native Chat Completions with streaming tools and reasoning. `model` and `chat`
112
+ select the same API; credentials default to `VENICE_API_KEY`.
113
+
114
+ ```ts
115
+ import { LLM } from "@opencode/ai"
116
+ import { Venice } from "@opencode/ai/providers"
117
+ import { Effect } from "effect"
118
+
119
+ const program = Effect.gen(function* () {
120
+ const response = yield* LLM.generate({
121
+ model: Venice.configure({ apiKey: process.env.VENICE_API_KEY }).chat("qwen3-6-27b"),
122
+ prompt: "Explain this design.",
123
+ providerOptions: {
124
+ reasoningEffort: "high",
125
+ veniceParameters: { includeVeniceSystemPrompt: false },
126
+ },
127
+ })
128
+ console.log(response.text)
129
+ })
130
+ ```
131
+
132
+ Effort lowers to `reasoning.effort`; `reasoning.enabled` and `reasoning.summary` are also available.
133
+ Supported effort levels and toggles depend on the selected model. Omitted controls preserve its defaults.
134
+ Venice's added system prompt is disabled by default, matching the previous OpenCode Venice SDK behavior.
135
+
136
+ Replay complete `response.message` values to retain signed/encrypted reasoning and Gemini thought
137
+ signatures, including per-tool signatures. Venice's encrypted scalar trailers are excluded from visible
138
+ reasoning but retained in provider metadata for replay. Cache affinity uses `promptCacheKey`, and cache-write
139
+ usage reads Venice's `cache_creation_input_tokens` field.
140
+
141
+ The native package entrypoint is `@opencode/ai/providers/venice`. Image generation, embeddings, Responses, and
142
+ client-side E2EE are not implemented by this provider.
143
+
109
144
  ## Experimental evaluation
110
145
 
111
146
  Evaluation models compare shared state with typed choice, score, and boolean questions. The API is
@@ -18,6 +18,19 @@ declare const ExtraContent: Schema.Struct<{
18
18
  readonly thought_signature: Schema.String;
19
19
  }>;
20
20
  }>;
21
+ export declare const OpenAIChatAssistantToolCall: Schema.Struct<{
22
+ readonly id: Schema.String;
23
+ readonly type: Schema.tag<"function">;
24
+ readonly function: Schema.Struct<{
25
+ readonly name: Schema.String;
26
+ readonly arguments: Schema.String;
27
+ }>;
28
+ readonly extra_content: Schema.optional<Schema.Struct<{
29
+ readonly google: Schema.Struct<{
30
+ readonly thought_signature: Schema.String;
31
+ }>;
32
+ }>>;
33
+ }>;
21
34
  declare const ReasoningDetail: Schema.Union<readonly [Schema.StructWithRest<Schema.Struct<{
22
35
  readonly id: Schema.optional<Schema.NullOr<Schema.String>>;
23
36
  readonly format: Schema.optional<Schema.String>;
@@ -49,6 +62,88 @@ declare const ReasoningDetail: Schema.Union<readonly [Schema.StructWithRest<Sche
49
62
  readonly index: Schema.optional<Schema.Number>;
50
63
  }>]>;
51
64
  type ReasoningDetail = Schema.Schema.Type<typeof ReasoningDetail>;
65
+ export declare const OpenAIChatMessage: Schema.toTaggedUnion<"role", readonly [Schema.Struct<{
66
+ readonly role: Schema.Literal<"system">;
67
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{
68
+ readonly type: Schema.Literal<"text">;
69
+ readonly text: Schema.String;
70
+ readonly cache_control: Schema.optional<Schema.Struct<{
71
+ readonly type: Schema.Literal<"ephemeral">;
72
+ readonly ttl: Schema.optional<Schema.String>;
73
+ }>>;
74
+ }>, Schema.Struct<{
75
+ readonly type: Schema.Literal<"image_url">;
76
+ readonly image_url: Schema.Struct<{
77
+ readonly url: Schema.String;
78
+ }>;
79
+ }>, Schema.Struct<{
80
+ readonly type: Schema.Literal<"file">;
81
+ readonly file: Schema.Struct<{
82
+ readonly filename: Schema.String;
83
+ readonly file_data: Schema.String;
84
+ }>;
85
+ }>]>>]>;
86
+ }>, Schema.Struct<{
87
+ readonly role: Schema.Literal<"user">;
88
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{
89
+ readonly type: Schema.Literal<"text">;
90
+ readonly text: Schema.String;
91
+ readonly cache_control: Schema.optional<Schema.Struct<{
92
+ readonly type: Schema.Literal<"ephemeral">;
93
+ readonly ttl: Schema.optional<Schema.String>;
94
+ }>>;
95
+ }>, Schema.Struct<{
96
+ readonly type: Schema.Literal<"image_url">;
97
+ readonly image_url: Schema.Struct<{
98
+ readonly url: Schema.String;
99
+ }>;
100
+ }>, Schema.Struct<{
101
+ readonly type: Schema.Literal<"file">;
102
+ readonly file: Schema.Struct<{
103
+ readonly filename: Schema.String;
104
+ readonly file_data: Schema.String;
105
+ }>;
106
+ }>]>>]>;
107
+ }>, Schema.StructWithRest<Schema.Struct<{
108
+ readonly role: Schema.Literal<"assistant">;
109
+ readonly content: Schema.NullOr<Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Struct<{
110
+ readonly type: Schema.Literal<"text">;
111
+ readonly text: Schema.String;
112
+ readonly cache_control: Schema.optional<Schema.Struct<{
113
+ readonly type: Schema.Literal<"ephemeral">;
114
+ readonly ttl: Schema.optional<Schema.String>;
115
+ }>>;
116
+ }>>]>>;
117
+ readonly tool_calls: Schema.optional<Schema.$Array<Schema.Struct<{
118
+ readonly id: Schema.String;
119
+ readonly type: Schema.tag<"function">;
120
+ readonly function: Schema.Struct<{
121
+ readonly name: Schema.String;
122
+ readonly arguments: Schema.String;
123
+ }>;
124
+ readonly extra_content: Schema.optional<Schema.Struct<{
125
+ readonly google: Schema.Struct<{
126
+ readonly thought_signature: Schema.String;
127
+ }>;
128
+ }>>;
129
+ }>>>;
130
+ readonly reasoning_content: Schema.optional<Schema.String>;
131
+ readonly reasoning: Schema.optional<Schema.String>;
132
+ readonly reasoning_text: Schema.optional<Schema.String>;
133
+ readonly reasoning_details: Schema.optional<Schema.Unknown>;
134
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>, Schema.Struct<{
135
+ readonly role: Schema.Literal<"tool">;
136
+ readonly tool_call_id: Schema.String;
137
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Struct<{
138
+ readonly type: Schema.Literal<"text">;
139
+ readonly text: Schema.String;
140
+ readonly cache_control: Schema.optional<Schema.Struct<{
141
+ readonly type: Schema.Literal<"ephemeral">;
142
+ readonly ttl: Schema.optional<Schema.String>;
143
+ }>>;
144
+ }>>]>;
145
+ }>]>;
146
+ type OpenAIChatMessage = Schema.Schema.Type<typeof OpenAIChatMessage>;
52
147
  export declare const bodyFields: {
53
148
  model: Schema.String;
54
149
  messages: Schema.$Array<Schema.toTaggedUnion<"role", readonly [Schema.Struct<{
@@ -288,6 +383,89 @@ declare const OpenAIChatBody: Schema.Struct<{
288
383
  stop: Schema.optional<Schema.$Array<Schema.String>>;
289
384
  }>;
290
385
  export type OpenAIChatBody = Schema.Schema.Type<typeof OpenAIChatBody>;
386
+ export declare const OpenAIChatUsage: Schema.StructWithRest<Schema.Struct<{
387
+ readonly prompt_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
388
+ readonly completion_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
389
+ readonly total_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
390
+ readonly cached_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
391
+ readonly prompt_cache_hit_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
392
+ readonly cache_read_input_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
393
+ readonly cache_created_input_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
394
+ readonly prompt_tokens_details: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
395
+ readonly cached_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
396
+ readonly cache_write_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
397
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
398
+ readonly completion_tokens_details: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
399
+ readonly reasoning_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
400
+ readonly accepted_prediction_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
401
+ readonly rejected_prediction_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
402
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
403
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>;
404
+ export declare const OpenAIChatToolCallDelta: Schema.Struct<{
405
+ readonly index: Schema.optional<Schema.NullOr<Schema.Number>>;
406
+ readonly id: Schema.optional<Schema.NullOr<Schema.String>>;
407
+ readonly function: Schema.optional<Schema.NullOr<Schema.Struct<{
408
+ readonly name: Schema.optional<Schema.NullOr<Schema.String>>;
409
+ readonly arguments: Schema.optional<Schema.NullOr<Schema.String>>;
410
+ }>>>;
411
+ readonly extra_content: Schema.optional<Schema.NullOr<Schema.Unknown>>;
412
+ }>;
413
+ export declare const OpenAIChatDelta: Schema.StructWithRest<Schema.Struct<{
414
+ readonly content: Schema.optional<Schema.NullOr<Schema.String>>;
415
+ readonly refusal: Schema.optional<Schema.NullOr<Schema.String>>;
416
+ readonly reasoning_content: Schema.optional<Schema.NullOr<Schema.String>>;
417
+ readonly reasoning: Schema.optional<Schema.NullOr<Schema.String>>;
418
+ readonly reasoning_text: Schema.optional<Schema.NullOr<Schema.String>>;
419
+ readonly reasoning_details: Schema.optional<Schema.NullOr<Schema.Unknown>>;
420
+ readonly tool_calls: Schema.optional<Schema.NullOr<Schema.$Array<Schema.Struct<{
421
+ readonly index: Schema.optional<Schema.NullOr<Schema.Number>>;
422
+ readonly id: Schema.optional<Schema.NullOr<Schema.String>>;
423
+ readonly function: Schema.optional<Schema.NullOr<Schema.Struct<{
424
+ readonly name: Schema.optional<Schema.NullOr<Schema.String>>;
425
+ readonly arguments: Schema.optional<Schema.NullOr<Schema.String>>;
426
+ }>>>;
427
+ readonly extra_content: Schema.optional<Schema.NullOr<Schema.Unknown>>;
428
+ }>>>>;
429
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>;
430
+ export declare const OpenAIChatChoice: Schema.StructWithRest<Schema.Struct<{
431
+ readonly delta: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
432
+ readonly content: Schema.optional<Schema.NullOr<Schema.String>>;
433
+ readonly refusal: Schema.optional<Schema.NullOr<Schema.String>>;
434
+ readonly reasoning_content: Schema.optional<Schema.NullOr<Schema.String>>;
435
+ readonly reasoning: Schema.optional<Schema.NullOr<Schema.String>>;
436
+ readonly reasoning_text: Schema.optional<Schema.NullOr<Schema.String>>;
437
+ readonly reasoning_details: Schema.optional<Schema.NullOr<Schema.Unknown>>;
438
+ readonly tool_calls: Schema.optional<Schema.NullOr<Schema.$Array<Schema.Struct<{
439
+ readonly index: Schema.optional<Schema.NullOr<Schema.Number>>;
440
+ readonly id: Schema.optional<Schema.NullOr<Schema.String>>;
441
+ readonly function: Schema.optional<Schema.NullOr<Schema.Struct<{
442
+ readonly name: Schema.optional<Schema.NullOr<Schema.String>>;
443
+ readonly arguments: Schema.optional<Schema.NullOr<Schema.String>>;
444
+ }>>>;
445
+ readonly extra_content: Schema.optional<Schema.NullOr<Schema.Unknown>>;
446
+ }>>>>;
447
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
448
+ readonly finish_reason: Schema.optional<Schema.NullOr<Schema.String>>;
449
+ readonly native_finish_reason: Schema.optional<Schema.NullOr<Schema.String>>;
450
+ readonly usage: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
451
+ readonly prompt_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
452
+ readonly completion_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
453
+ readonly total_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
454
+ readonly cached_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
455
+ readonly prompt_cache_hit_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
456
+ readonly cache_read_input_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
457
+ readonly cache_created_input_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
458
+ readonly prompt_tokens_details: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
459
+ readonly cached_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
460
+ readonly cache_write_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
461
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
462
+ readonly completion_tokens_details: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
463
+ readonly reasoning_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
464
+ readonly accepted_prediction_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
465
+ readonly rejected_prediction_tokens: Schema.optional<Schema.NullOr<Schema.Number>>;
466
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
467
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
468
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>;
291
469
  export declare const OpenAIChatEvent: Schema.StructWithRest<Schema.Struct<{
292
470
  readonly choices: Schema.optional<Schema.NullOr<Schema.$Array<Schema.StructWithRest<Schema.Struct<{
293
471
  readonly delta: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
@@ -379,6 +557,8 @@ export interface ParserState {
379
557
  interface LoweringOptions {
380
558
  readonly cacheControl?: (cache: CacheHint | undefined) => OpenAIChatCacheControl | undefined;
381
559
  readonly toolCallID?: (id: string) => string;
560
+ /** Project provider-specific fields from the exact source, even when other messages are dropped during lowering. */
561
+ readonly assistant?: (source: LLMRequest["messages"][number], message: OpenAIChatMessage) => OpenAIChatMessage;
382
562
  }
383
563
  export declare const fromRequest: (request: LLMRequest<import("../schema/options.js").LanguageModel<{
384
564
  readonly [x: string]: unknown;
@@ -623,6 +803,222 @@ export declare const fromRequest: (request: LLMRequest<import("../schema/options
623
803
  } | undefined;
624
804
  stream: true;
625
805
  }, AIError, never>;
806
+ export declare const finishEvents: (state: ParserState) => Effect.Effect<(({
807
+ readonly type: "compaction";
808
+ readonly provider: string & import("effect/Brand").Brand<"AI.ProviderID">;
809
+ readonly id?: string | undefined;
810
+ readonly text?: string | null | undefined;
811
+ readonly encrypted?: string | undefined;
812
+ } & ({
813
+ readonly encrypted: string;
814
+ readonly text?: never;
815
+ } | {
816
+ readonly text: string | null;
817
+ readonly encrypted?: never;
818
+ })) | {
819
+ readonly type: "step-start";
820
+ readonly index: number;
821
+ } | {
822
+ readonly id: string;
823
+ readonly type: "text-start";
824
+ readonly providerMetadata?: {
825
+ readonly [x: string]: {
826
+ readonly [x: string]: unknown;
827
+ };
828
+ } | undefined;
829
+ } | {
830
+ readonly id: string;
831
+ readonly type: "text-delta";
832
+ readonly text: string;
833
+ readonly providerMetadata?: {
834
+ readonly [x: string]: {
835
+ readonly [x: string]: unknown;
836
+ };
837
+ } | undefined;
838
+ } | {
839
+ readonly id: string;
840
+ readonly type: "text-end";
841
+ readonly text?: string | undefined;
842
+ readonly providerMetadata?: {
843
+ readonly [x: string]: {
844
+ readonly [x: string]: unknown;
845
+ };
846
+ } | undefined;
847
+ } | {
848
+ readonly id: string;
849
+ readonly type: "reasoning-start";
850
+ readonly providerMetadata?: {
851
+ readonly [x: string]: {
852
+ readonly [x: string]: unknown;
853
+ };
854
+ } | undefined;
855
+ } | {
856
+ readonly id: string;
857
+ readonly type: "reasoning-delta";
858
+ readonly text: string;
859
+ readonly providerMetadata?: {
860
+ readonly [x: string]: {
861
+ readonly [x: string]: unknown;
862
+ };
863
+ } | undefined;
864
+ } | {
865
+ readonly id: string;
866
+ readonly type: "reasoning-end";
867
+ readonly text?: string | undefined;
868
+ readonly providerMetadata?: {
869
+ readonly [x: string]: {
870
+ readonly [x: string]: unknown;
871
+ };
872
+ } | undefined;
873
+ } | {
874
+ readonly id: string;
875
+ readonly type: "tool-input-start";
876
+ readonly name: string;
877
+ readonly providerMetadata?: {
878
+ readonly [x: string]: {
879
+ readonly [x: string]: unknown;
880
+ };
881
+ } | undefined;
882
+ readonly namespace?: string | undefined;
883
+ readonly providerExecuted?: boolean | undefined;
884
+ } | {
885
+ readonly id: string;
886
+ readonly type: "tool-input-delta";
887
+ readonly name: string;
888
+ readonly text: string;
889
+ readonly input?: unknown;
890
+ readonly namespace?: string | undefined;
891
+ } | {
892
+ readonly id: string;
893
+ readonly type: "tool-input-end";
894
+ readonly name: string;
895
+ readonly providerMetadata?: {
896
+ readonly [x: string]: {
897
+ readonly [x: string]: unknown;
898
+ };
899
+ } | undefined;
900
+ readonly namespace?: string | undefined;
901
+ } | {
902
+ readonly id: string;
903
+ readonly type: "tool-input-error";
904
+ readonly name: string;
905
+ readonly raw: string;
906
+ readonly namespace?: string | undefined;
907
+ } | {
908
+ readonly id: string;
909
+ readonly type: "tool-call";
910
+ readonly name: string;
911
+ readonly input: unknown;
912
+ readonly providerMetadata?: {
913
+ readonly [x: string]: {
914
+ readonly [x: string]: unknown;
915
+ };
916
+ } | undefined;
917
+ readonly namespace?: string | undefined;
918
+ readonly providerExecuted?: boolean | undefined;
919
+ } | {
920
+ readonly id: string;
921
+ readonly type: "tool-result";
922
+ readonly name: string;
923
+ readonly result: {
924
+ readonly type: "json";
925
+ readonly value: unknown;
926
+ } | {
927
+ readonly type: "text";
928
+ readonly value: unknown;
929
+ } | {
930
+ readonly type: "error";
931
+ readonly value: unknown;
932
+ } | {
933
+ readonly type: "content";
934
+ readonly value: readonly ({
935
+ readonly type: "text";
936
+ readonly text: string;
937
+ } | {
938
+ readonly type: "file";
939
+ readonly uri: string;
940
+ readonly mime: string;
941
+ readonly name?: string | undefined;
942
+ })[];
943
+ };
944
+ readonly output?: {
945
+ readonly structured: unknown;
946
+ readonly content: readonly ({
947
+ readonly type: "text";
948
+ readonly text: string;
949
+ } | {
950
+ readonly type: "file";
951
+ readonly uri: string;
952
+ readonly mime: string;
953
+ readonly name?: string | undefined;
954
+ })[];
955
+ } | undefined;
956
+ readonly providerMetadata?: {
957
+ readonly [x: string]: {
958
+ readonly [x: string]: unknown;
959
+ };
960
+ } | undefined;
961
+ readonly namespace?: string | undefined;
962
+ readonly providerExecuted?: boolean | undefined;
963
+ } | {
964
+ readonly id: string;
965
+ readonly type: "tool-error";
966
+ readonly message: string;
967
+ readonly name: string;
968
+ readonly error?: unknown;
969
+ readonly providerMetadata?: {
970
+ readonly [x: string]: {
971
+ readonly [x: string]: unknown;
972
+ };
973
+ } | undefined;
974
+ readonly namespace?: string | undefined;
975
+ } | {
976
+ readonly type: "media";
977
+ readonly media: import("../media.js").Asset;
978
+ readonly providerMetadata?: {
979
+ readonly [x: string]: {
980
+ readonly [x: string]: unknown;
981
+ };
982
+ } | undefined;
983
+ } | {
984
+ readonly type: "step-finish";
985
+ readonly reason: {
986
+ readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
987
+ readonly raw?: string | undefined;
988
+ readonly category?: string | undefined;
989
+ readonly explanation?: string | undefined;
990
+ };
991
+ readonly index: number;
992
+ readonly providerMetadata?: {
993
+ readonly [x: string]: {
994
+ readonly [x: string]: unknown;
995
+ };
996
+ } | undefined;
997
+ readonly usage?: Usage | undefined;
998
+ } | {
999
+ readonly type: "finish";
1000
+ readonly reason: {
1001
+ readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1002
+ readonly raw?: string | undefined;
1003
+ readonly category?: string | undefined;
1004
+ readonly explanation?: string | undefined;
1005
+ };
1006
+ readonly providerMetadata?: {
1007
+ readonly [x: string]: {
1008
+ readonly [x: string]: unknown;
1009
+ };
1010
+ } | undefined;
1011
+ readonly usage?: Usage | undefined;
1012
+ } | {
1013
+ readonly type: "provider-error";
1014
+ readonly message: string;
1015
+ readonly classification?: "context-overflow" | "payload-too-large" | undefined;
1016
+ readonly providerMetadata?: {
1017
+ readonly [x: string]: {
1018
+ readonly [x: string]: unknown;
1019
+ };
1020
+ } | undefined;
1021
+ })[], AIError, never>;
626
1022
  /**
627
1023
  * The OpenAI Chat protocol — request body construction, body schema, and the
628
1024
  * streaming-event state machine. Reused by every route that speaks OpenAI Chat
@@ -43,7 +43,7 @@ const ExtraContent = Schema.Struct({
43
43
  google: Schema.Struct({ thought_signature: Schema.String }),
44
44
  });
45
45
  const decodeExtraContent = (value) => Option.getOrUndefined(Schema.decodeUnknownOption(ExtraContent)(value));
46
- const OpenAIChatAssistantToolCall = Schema.Struct({
46
+ export const OpenAIChatAssistantToolCall = Schema.Struct({
47
47
  id: Schema.String,
48
48
  type: Schema.tag("function"),
49
49
  function: Schema.Struct({
@@ -94,7 +94,7 @@ const OpenAIChatUserContent = Schema.Union([
94
94
  file: Schema.Struct({ filename: Schema.String, file_data: Schema.String }),
95
95
  }),
96
96
  ]);
97
- const OpenAIChatMessage = Schema.Union([
97
+ export const OpenAIChatMessage = Schema.Union([
98
98
  Schema.Struct({
99
99
  role: Schema.Literal("system"),
100
100
  content: Schema.Union([Schema.String, Schema.Array(OpenAIChatUserContent)]),
@@ -152,7 +152,7 @@ const OpenAIChatBody = Schema.Struct(bodyFields);
152
152
  // The event schema is one decoded SSE `data:` payload. `Framing.sse` splits the
153
153
  // byte stream into strings, then `Protocol.jsonEvent` decodes each string into
154
154
  // this provider-native event shape.
155
- const OpenAIChatUsage = Schema.StructWithRest(Schema.Struct({
155
+ export const OpenAIChatUsage = Schema.StructWithRest(Schema.Struct({
156
156
  prompt_tokens: optionalNull(Schema.Number),
157
157
  completion_tokens: optionalNull(Schema.Number),
158
158
  total_tokens: optionalNull(Schema.Number),
@@ -175,13 +175,13 @@ const OpenAIChatToolCallDeltaFunction = Schema.Struct({
175
175
  name: optionalNull(Schema.String),
176
176
  arguments: optionalNull(Schema.String),
177
177
  });
178
- const OpenAIChatToolCallDelta = Schema.Struct({
178
+ export const OpenAIChatToolCallDelta = Schema.Struct({
179
179
  index: optionalNull(Schema.Number),
180
180
  id: optionalNull(Schema.String),
181
181
  function: optionalNull(OpenAIChatToolCallDeltaFunction),
182
182
  extra_content: optionalNull(Schema.Unknown),
183
183
  });
184
- const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
184
+ export const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
185
185
  content: optionalNull(Schema.String),
186
186
  refusal: optionalNull(Schema.String),
187
187
  reasoning_content: optionalNull(Schema.String),
@@ -190,7 +190,7 @@ const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
190
190
  reasoning_details: optionalNull(Schema.Unknown),
191
191
  tool_calls: optionalNull(Schema.Array(OpenAIChatToolCallDelta)),
192
192
  }), [Schema.Record(Schema.String, Schema.Unknown)]);
193
- const OpenAIChatChoice = Schema.StructWithRest(Schema.Struct({
193
+ export const OpenAIChatChoice = Schema.StructWithRest(Schema.Struct({
194
194
  delta: optionalNull(OpenAIChatDelta),
195
195
  finish_reason: optionalNull(Schema.String),
196
196
  native_finish_reason: optionalNull(Schema.String),
@@ -386,8 +386,10 @@ const toolMessage = (toolCallID, text, cacheControl) => ({
386
386
  const lowerMessage = Effect.fnUntraced(function* (message, reasoningField, requireReasoning, options) {
387
387
  if (message.role === "user")
388
388
  return [yield* lowerUserMessage(message, options)];
389
- if (message.role === "assistant")
390
- return [yield* lowerAssistantMessage(message, reasoningField, requireReasoning, options)];
389
+ if (message.role === "assistant") {
390
+ const lowered = yield* lowerAssistantMessage(message, reasoningField, requireReasoning, options);
391
+ return [options.assistant?.(message, lowered) ?? lowered];
392
+ }
391
393
  return (yield* lowerToolMessages(message, options)).messages;
392
394
  });
393
395
  const lowerMessages = Effect.fnUntraced(function* (request, options) {
@@ -981,7 +983,7 @@ const step = (state, event) => Effect.gen(function* () {
981
983
  events,
982
984
  ];
983
985
  });
984
- const finishEvents = Effect.fnUntraced(function* (state) {
986
+ export const finishEvents = Effect.fnUntraced(function* (state) {
985
987
  if (state.finishReason === undefined && state.requireFinishReason)
986
988
  return yield* new AIError({
987
989
  reason: new InvalidProviderOutputError({