@opencode-ai/ai 0.0.0-dev-17534 → 0.0.0-dev-17582

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.
@@ -38,7 +38,7 @@ declare const GeminiBody: Schema.Struct<{
38
38
  readonly functionCall: Schema.Struct<{
39
39
  readonly id: Schema.optional<Schema.String>;
40
40
  readonly name: Schema.String;
41
- readonly args: Schema.Unknown;
41
+ readonly args: Schema.optional<Schema.Unknown>;
42
42
  }>;
43
43
  readonly thoughtSignature: Schema.optional<Schema.String>;
44
44
  }>, Schema.Struct<{
@@ -55,6 +55,7 @@ declare const GeminiBody: Schema.Struct<{
55
55
  }>;
56
56
  }>]>>;
57
57
  }>>;
58
+ labels: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
58
59
  safetySettings: Schema.optional<Schema.$Array<Schema.Struct<{
59
60
  readonly category: Schema.String;
60
61
  readonly threshold: Schema.String;
@@ -115,8 +116,8 @@ export declare const protocol: Protocol<{
115
116
  } | {
116
117
  readonly functionCall: {
117
118
  readonly name: string;
118
- readonly args: unknown;
119
119
  readonly id?: string | undefined;
120
+ readonly args?: unknown;
120
121
  };
121
122
  readonly thoughtSignature?: string | undefined;
122
123
  } | {
@@ -154,6 +155,9 @@ export declare const protocol: Protocol<{
154
155
  readonly threshold: string;
155
156
  }[] | undefined;
156
157
  readonly serviceTier?: string | undefined;
158
+ readonly labels?: {
159
+ readonly [x: string]: string;
160
+ } | undefined;
157
161
  readonly systemInstruction?: {
158
162
  readonly parts: readonly {
159
163
  readonly text: string;
@@ -190,8 +194,8 @@ export declare const protocol: Protocol<{
190
194
  } | {
191
195
  readonly functionCall: {
192
196
  readonly name: string;
193
- readonly args: unknown;
194
197
  readonly id?: string | undefined;
198
+ readonly args?: unknown;
195
199
  };
196
200
  readonly thoughtSignature?: string | undefined;
197
201
  } | {
@@ -210,6 +214,12 @@ export declare const protocol: Protocol<{
210
214
  } | undefined;
211
215
  readonly finishReason?: string | undefined;
212
216
  }[] | undefined;
217
+ readonly promptFeedback?: {
218
+ readonly [x: string]: unknown;
219
+ readonly blockReason?: string | undefined;
220
+ readonly blockReasonMessage?: string | undefined;
221
+ readonly safetyRatings?: unknown;
222
+ } | undefined;
213
223
  readonly usageMetadata?: {
214
224
  readonly cachedContentTokenCount?: number | undefined;
215
225
  readonly thoughtsTokenCount?: number | undefined;
@@ -237,8 +247,8 @@ export declare const route: Route<{
237
247
  } | {
238
248
  readonly functionCall: {
239
249
  readonly name: string;
240
- readonly args: unknown;
241
250
  readonly id?: string | undefined;
251
+ readonly args?: unknown;
242
252
  };
243
253
  readonly thoughtSignature?: string | undefined;
244
254
  } | {
@@ -276,6 +286,9 @@ export declare const route: Route<{
276
286
  readonly threshold: string;
277
287
  }[] | undefined;
278
288
  readonly serviceTier?: string | undefined;
289
+ readonly labels?: {
290
+ readonly [x: string]: string;
291
+ } | undefined;
279
292
  readonly systemInstruction?: {
280
293
  readonly parts: readonly {
281
294
  readonly text: string;
@@ -44,7 +44,7 @@ const GeminiFunctionCallPart = Schema.Struct({
44
44
  functionCall: Schema.Struct({
45
45
  id: Schema.optional(Schema.String),
46
46
  name: Schema.String,
47
- args: Schema.Unknown,
47
+ args: Schema.optional(Schema.Unknown),
48
48
  }),
49
49
  thoughtSignature: Schema.optional(Schema.String),
50
50
  });
@@ -106,6 +106,7 @@ const GeminiGenerationConfig = Schema.Struct({
106
106
  const GeminiBodyFields = {
107
107
  cachedContent: Schema.optional(Schema.String),
108
108
  contents: Schema.Array(GeminiContent),
109
+ labels: Schema.optional(Schema.Record(Schema.String, Schema.String)),
109
110
  safetySettings: optionalArray(GeminiSafetySetting),
110
111
  serviceTier: Schema.optional(Schema.String),
111
112
  systemInstruction: Schema.optional(GeminiSystemInstruction),
@@ -125,8 +126,14 @@ const GeminiCandidate = Schema.Struct({
125
126
  content: Schema.optional(GeminiContent),
126
127
  finishReason: Schema.optional(Schema.String),
127
128
  });
129
+ const GeminiPromptFeedback = Schema.StructWithRest(Schema.Struct({
130
+ blockReason: Schema.optional(Schema.String),
131
+ blockReasonMessage: Schema.optional(Schema.String),
132
+ safetyRatings: Schema.optional(Schema.Unknown),
133
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
128
134
  const GeminiEvent = Schema.Struct({
129
135
  candidates: optionalArray(GeminiCandidate),
136
+ promptFeedback: Schema.optional(GeminiPromptFeedback),
130
137
  usageMetadata: Schema.optional(GeminiUsage),
131
138
  });
132
139
  // =============================================================================
@@ -401,25 +408,29 @@ const mapFinishReason = (finishReason, hasToolCalls) => {
401
408
  return "error";
402
409
  return "unknown";
403
410
  };
404
- const finish = (state) => state.finishReason || state.usage
405
- ? (() => {
406
- const events = [];
407
- const lifecycle = state.reasoningSignature
408
- ? Lifecycle.reasoningEnd(state.lifecycle, events, "reasoning-0", googleMetadata({ thoughtSignature: state.reasoningSignature }))
409
- : state.lifecycle;
410
- Lifecycle.finish(lifecycle, events, {
411
- reason: {
412
- normalized: mapFinishReason(state.finishReason, state.hasToolCalls),
413
- raw: state.finishReason,
414
- },
415
- usage: state.usage,
416
- });
417
- return events;
418
- })()
419
- : [];
411
+ const finish = (state) => {
412
+ const promptBlockReason = state.finishReason === undefined ? state.promptFeedback?.blockReason : undefined;
413
+ const finishReason = state.finishReason ?? promptBlockReason;
414
+ if (finishReason === undefined && state.usage === undefined)
415
+ return [];
416
+ const events = [];
417
+ const lifecycle = state.reasoningSignature
418
+ ? Lifecycle.reasoningEnd(state.lifecycle, events, "reasoning-0", googleMetadata({ thoughtSignature: state.reasoningSignature }))
419
+ : state.lifecycle;
420
+ Lifecycle.finish(lifecycle, events, {
421
+ reason: {
422
+ normalized: promptBlockReason === undefined ? mapFinishReason(finishReason, state.hasToolCalls) : "content-filter",
423
+ raw: finishReason,
424
+ },
425
+ usage: state.usage,
426
+ providerMetadata: state.promptFeedback === undefined ? undefined : googleMetadata({ promptFeedback: state.promptFeedback }),
427
+ });
428
+ return events;
429
+ };
420
430
  const step = (state, event) => {
421
431
  const nextState = {
422
432
  ...state,
433
+ promptFeedback: event.promptFeedback ?? state.promptFeedback,
423
434
  usage: event.usageMetadata ? (mapUsage(event.usageMetadata) ?? state.usage) : state.usage,
424
435
  };
425
436
  const candidate = event.candidates?.[0];
@@ -446,7 +457,7 @@ const step = (state, event) => {
446
457
  continue;
447
458
  }
448
459
  if ("functionCall" in part) {
449
- const input = part.functionCall.args;
460
+ const input = part.functionCall.args === undefined ? {} : part.functionCall.args;
450
461
  const id = `tool_${nextToolCallId++}`;
451
462
  const metadata = {
452
463
  ...(part.functionCall.id === undefined ? {} : { functionCallId: part.functionCall.id }),
@@ -120,8 +120,8 @@ export declare const errorText: (error: unknown) => string;
120
120
  * decoder, and drops empty / `[DONE]` keep-alive events so the downstream
121
121
  * `decodeChunk` sees one JSON string per element. The SSE channel emits a
122
122
  * `Retry` control event on its error channel; we drop it here (we don't
123
- * implement client-driven retries) so the public error channel stays
124
- * `AIError`.
123
+ * implement client-driven retries). Decoder failures become provider output
124
+ * errors so the public error channel stays `AIError`.
125
125
  */
126
126
  export declare const sseFraming: (bytes: Stream.Stream<Uint8Array, AIError>) => Stream.Stream<string, AIError>;
127
127
  /**
@@ -154,10 +154,10 @@ export const errorText = (error) => {
154
154
  * decoder, and drops empty / `[DONE]` keep-alive events so the downstream
155
155
  * `decodeChunk` sees one JSON string per element. The SSE channel emits a
156
156
  * `Retry` control event on its error channel; we drop it here (we don't
157
- * implement client-driven retries) so the public error channel stays
158
- * `AIError`.
157
+ * implement client-driven retries). Decoder failures become provider output
158
+ * errors so the public error channel stays `AIError`.
159
159
  */
160
- export const sseFraming = (bytes) => bytes.pipe(Stream.decodeText(), Stream.pipeThroughChannel(Sse.decode()), Stream.catchTag("Retry", () => Stream.empty), Stream.filter((event) => event.data.length > 0 && event.data !== "[DONE]"), Stream.map((event) => event.data));
160
+ export const sseFraming = (bytes) => bytes.pipe(Stream.decodeText(), Stream.pipeThroughChannel(Sse.decode()), Stream.catchTag("Retry", () => Stream.empty), Stream.catchTag("SseError", (error) => Stream.fail(eventError("sse", error.message))), Stream.filter((event) => event.data.length > 0 && event.data !== "[DONE]"), Stream.map((event) => event.data));
161
161
  /**
162
162
  * Canonical invalid-request constructor. Lift one-line `const invalid =
163
163
  * (message) => invalidRequest(message)` aliases out of every
@@ -35,7 +35,7 @@ export const isPayloadTooLarge = (message) => payloadPatterns.some((pattern) =>
35
35
  export const isContextOverflowFailure = (failure) => failure instanceof AIError
36
36
  ? failure.reason._tag === "InvalidRequest" && failure.reason.classification === "context-overflow"
37
37
  : Schema.is(ProviderErrorEvent)(failure) && failure.classification === "context-overflow";
38
- const decodeJson = Schema.decodeUnknownOption(Schema.UnknownFromJsonString);
38
+ const decodeJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Unknown));
39
39
  const QUOTA_CODES = new Set(["insufficient_quota", "usage_not_included", "billing_error"]);
40
40
  const SERVER_CODES = new Set([
41
41
  "api_error",
@@ -1,16 +1,20 @@
1
1
  import type { ProviderPackage } from "../provider-package.js";
2
2
  import { Gemini } from "../protocols/gemini.js";
3
3
  import { Route, type RouteDefaultsInput } from "../route/client.js";
4
- import { type ModelID } from "../schema/index.js";
4
+ import { type ModelID, type ProviderOptions } from "../schema/index.js";
5
5
  import { GoogleVertexShared } from "./google-vertex-shared.js";
6
- export type GeminiOptionsInput = Gemini.OptionsInput;
7
- export type GeminiProviderOptionsInput = Gemini.ProviderOptionsInput;
6
+ export interface GeminiOptionsInput extends Gemini.OptionsInput {
7
+ readonly labels?: Readonly<Record<string, string>>;
8
+ }
9
+ export type GeminiProviderOptionsInput = ProviderOptions & {
10
+ readonly gemini?: GeminiOptionsInput;
11
+ };
8
12
  export declare const id: string & import("effect/Brand").Brand<"AI.ProviderID">;
9
13
  export type Config = RouteDefaultsInput & GoogleVertexShared.ApiKeyOptions & {
10
14
  readonly baseURL?: string;
11
15
  readonly location?: string;
12
16
  readonly project?: string;
13
- readonly providerOptions?: Gemini.ProviderOptionsInput;
17
+ readonly providerOptions?: GeminiProviderOptionsInput;
14
18
  };
15
19
  export type Settings = ProviderPackage.Settings & ({
16
20
  readonly accessToken?: string;
@@ -22,7 +26,7 @@ export type Settings = ProviderPackage.Settings & ({
22
26
  readonly baseURL?: string;
23
27
  readonly location?: string;
24
28
  readonly project?: string;
25
- readonly providerOptions?: Gemini.ProviderOptionsInput;
29
+ readonly providerOptions?: GeminiProviderOptionsInput;
26
30
  };
27
31
  export declare const routes: Route<{
28
32
  readonly contents: readonly {
@@ -39,8 +43,8 @@ export declare const routes: Route<{
39
43
  } | {
40
44
  readonly functionCall: {
41
45
  readonly name: string;
42
- readonly args: unknown;
43
46
  readonly id?: string | undefined;
47
+ readonly args?: unknown;
44
48
  };
45
49
  readonly thoughtSignature?: string | undefined;
46
50
  } | {
@@ -78,6 +82,9 @@ export declare const routes: Route<{
78
82
  readonly threshold: string;
79
83
  }[] | undefined;
80
84
  readonly serviceTier?: string | undefined;
85
+ readonly labels?: {
86
+ readonly [x: string]: string;
87
+ } | undefined;
81
88
  readonly systemInstruction?: {
82
89
  readonly parts: readonly {
83
90
  readonly text: string;
@@ -101,15 +108,15 @@ export declare const routes: Route<{
101
108
  }, import("../route/transport/http.js").HttpPrepared<string>>[];
102
109
  export declare const configure: (input?: Config) => {
103
110
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
104
- model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<Gemini.ProviderOptionsInput>;
111
+ model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<GeminiProviderOptionsInput>;
105
112
  configure: (input?: Config) => /*elided*/ any;
106
113
  };
107
114
  export declare const provider: {
108
115
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
109
116
  configure: (input?: Config) => {
110
117
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
111
- model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<Gemini.ProviderOptionsInput>;
118
+ model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<GeminiProviderOptionsInput>;
112
119
  configure: /*elided*/ any;
113
120
  };
114
121
  };
115
- export declare const model: ProviderPackage.Definition<Settings, Gemini.ProviderOptionsInput>["model"];
122
+ export declare const model: ProviderPackage.Definition<Settings, GeminiProviderOptionsInput>["model"];
@@ -1,4 +1,6 @@
1
+ import { Effect } from "effect";
1
2
  import { Gemini } from "../protocols/gemini.js";
3
+ import { ProviderShared } from "../protocols/shared.js";
2
4
  import { Auth } from "../route/auth.js";
3
5
  import { Route } from "../route/client.js";
4
6
  import { Endpoint } from "../route/endpoint.js";
@@ -6,11 +8,26 @@ import { Framing } from "../route/framing.js";
6
8
  import { ProviderID } from "../schema/index.js";
7
9
  import { GoogleVertexShared } from "./google-vertex-shared.js";
8
10
  export const id = ProviderID.make("google-vertex");
11
+ const fromRequest = Effect.fn("GoogleVertex.fromRequest")(function* (request) {
12
+ const body = yield* Gemini.protocol.body.from(request);
13
+ const value = request.providerOptions?.gemini?.labels;
14
+ const labels = ProviderShared.isRecord(value)
15
+ ? Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"))
16
+ : undefined;
17
+ return { ...body, labels };
18
+ });
19
+ const protocol = {
20
+ ...Gemini.protocol,
21
+ body: {
22
+ ...Gemini.protocol.body,
23
+ from: fromRequest,
24
+ },
25
+ };
9
26
  const route = Route.make({
10
27
  id: "google-vertex-gemini",
11
28
  provider: id,
12
29
  providerMetadataKey: "google",
13
- protocol: Gemini.protocol,
30
+ protocol,
14
31
  endpoint: Endpoint.path(({ request }) => {
15
32
  const model = String(request.model.id);
16
33
  return `/${model.startsWith("endpoints/") ? model : `models/${model}`}:streamGenerateContent?alt=sse`;
@@ -22,8 +22,8 @@ export declare const routes: import("../route/client.js").Route<{
22
22
  } | {
23
23
  readonly functionCall: {
24
24
  readonly name: string;
25
- readonly args: unknown;
26
25
  readonly id?: string | undefined;
26
+ readonly args?: unknown;
27
27
  };
28
28
  readonly thoughtSignature?: string | undefined;
29
29
  } | {
@@ -61,6 +61,9 @@ export declare const routes: import("../route/client.js").Route<{
61
61
  readonly threshold: string;
62
62
  }[] | undefined;
63
63
  readonly serviceTier?: string | undefined;
64
+ readonly labels?: {
65
+ readonly [x: string]: string;
66
+ } | undefined;
64
67
  readonly systemInstruction?: {
65
68
  readonly parts: readonly {
66
69
  readonly text: string;
@@ -132,7 +132,7 @@ export const AIErrorReason = Schema.Union([
132
132
  InvalidProviderOutputReason,
133
133
  UnknownProviderReason,
134
134
  ]).pipe(Schema.toTaggedUnion("_tag"));
135
- export class AIError extends Schema.TaggedErrorClass()("AI.Error", {
135
+ export class AIError extends Schema.TaggedError()("AI.Error", {
136
136
  module: Schema.String,
137
137
  method: Schema.String,
138
138
  reason: AIErrorReason,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.0.0-dev-17534",
3
+ "version": "0.0.0-dev-17582",
4
4
  "name": "@opencode-ai/ai",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "devDependencies": {
31
31
  "@clack/prompts": "1.0.0-alpha.1",
32
- "@effect/platform-node": "4.0.0-beta.101",
33
- "@opencode-ai/http-recorder": "0.0.0-dev-17534",
32
+ "@effect/platform-node": "4.0.0-beta.107",
33
+ "@opencode-ai/http-recorder": "0.0.0-dev-17582",
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,9 +39,9 @@
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-dev-17534",
42
+ "@opencode-ai/schema": "0.0.0-dev-17582",
43
43
  "aws4fetch": "1.0.20",
44
- "effect": "4.0.0-beta.101",
44
+ "effect": "4.0.0-beta.107",
45
45
  "google-auth-library": "10.5.0"
46
46
  }
47
47
  }