@opencode/ai 0.0.0-dev-20141 → 0.0.0-dev-20142

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.
@@ -725,6 +725,9 @@ export declare const lowerTool: (protocolName: string, tool: ToolDefinition) =>
725
725
  };
726
726
  strict: boolean;
727
727
  }, AIError, never>;
728
+ export declare const lowerTools: (tools: ReadonlyArray<ToolDefinition>, adapter: ProviderAdapter) => Effect.Effect<{
729
+ readonly type: string;
730
+ }[], AIError, never>;
728
731
  export declare const lowerToolChoice: (protocolName: string, toolChoice: NonNullable<LLMRequest["toolChoice"]>) => Effect.Effect<"required" | "auto" | "none" | {
729
732
  type: "function";
730
733
  name: string;
@@ -292,6 +292,7 @@ export const lowerTool = Effect.fn("OpenResponses.lowerTool")(function* (protoco
292
292
  strict: false,
293
293
  };
294
294
  });
295
+ export const lowerTools = (tools, adapter) => Effect.forEach(tools, (tool) => tool.native !== undefined && adapter.nativeTool ? adapter.nativeTool(tool.native) : lowerTool(adapter.name, tool));
295
296
  export const lowerToolChoice = (protocolName, toolChoice) => ProviderShared.matchToolChoice(protocolName, toolChoice, {
296
297
  auto: () => "auto",
297
298
  none: () => "none",
@@ -605,11 +606,7 @@ export const fromRequestWithAdapter = Effect.fn("OpenResponses.fromRequestWithAd
605
606
  return {
606
607
  ...(yield* lowerConversation(projected.request, adapter)),
607
608
  ...lowerGeneration(request),
608
- tools: projected.tools.length === 0
609
- ? undefined
610
- : yield* Effect.forEach(projected.tools, (tool) => tool.native !== undefined && adapter.nativeTool
611
- ? adapter.nativeTool(tool.native)
612
- : lowerTool(adapter.name, tool)),
609
+ tools: projected.tools.length === 0 ? undefined : yield* lowerTools(projected.tools, adapter),
613
610
  tool_choice: allowedToolChoice(request) ??
614
611
  (request.toolChoice ? yield* lowerToolChoice(adapter.name, request.toolChoice) : undefined),
615
612
  };
@@ -5,7 +5,7 @@ import { Auth } from "../route/auth.js";
5
5
  import { Endpoint } from "../route/endpoint.js";
6
6
  import { Protocol } from "../route/protocol.js";
7
7
  import { HttpTransport } from "../route/transport/index.js";
8
- import { LLMRequest, mergeJsonRecords } from "../schema/index.js";
8
+ import { LLMRequest } from "../schema/index.js";
9
9
  import { resolveEffortUpdates } from "../effort-updates.js";
10
10
  import { OpenResponses } from "./open-responses.js";
11
11
  import { OpenResponsesOptions } from "./utils/open-responses-options.js";
@@ -105,9 +105,6 @@ export const CompactionTrigger = Schema.Struct({ type: Schema.Literal("compactio
105
105
  const CheckpointBody = Schema.Struct({
106
106
  ...OpenAIResponsesBody.fields,
107
107
  input: Schema.Array(Schema.Union([OpenAIResponsesInputItem, CompactionTrigger])),
108
- store: Schema.Literal(false),
109
- prompt_cache_retention: optionalNull(Schema.String),
110
- prompt_cache_options: optionalNull(Schema.Struct({ mode: Schema.optional(Schema.String), ttl: Schema.optional(Schema.String) })),
111
108
  });
112
109
  const adapter = {
113
110
  id: ADAPTER,
@@ -154,6 +151,7 @@ const lowerToolEntry = Effect.fn("OpenAIResponses.lowerToolEntry")(function* (to
154
151
  tools: yield* Effect.forEach(ProviderShared.flattenTools(tool.tools), (leaf) => OpenResponses.lowerTool(NAME, leaf)),
155
152
  };
156
153
  });
154
+ const lowerTools = (request) => Effect.forEach(request.tools, lowerToolEntry);
157
155
  const lowerToolChoice = (toolChoice, tools) => ProviderShared.matchToolChoice(NAME, toolChoice, {
158
156
  auto: () => "auto",
159
157
  none: () => "none",
@@ -171,7 +169,7 @@ const fromRequest = Effect.fn("OpenAIResponses.fromRequest")(function* (request)
171
169
  ...(yield* OpenResponses.lowerConversation(updates.request, adapter)),
172
170
  ...OpenResponses.lowerGeneration(request, { ...options, reasoningEffort: updates.effort }),
173
171
  context_management: management?.map((edit) => ({ type: edit.type, compact_threshold: edit.compactThreshold })),
174
- tools: request.tools.length === 0 ? undefined : yield* Effect.forEach(request.tools, lowerToolEntry),
172
+ tools: request.tools.length === 0 ? undefined : yield* lowerTools(request),
175
173
  tool_choice: request.tools.length === 0
176
174
  ? undefined
177
175
  : (OpenResponses.allowedToolChoice(request) ??
@@ -181,25 +179,19 @@ const fromRequest = Effect.fn("OpenAIResponses.fromRequest")(function* (request)
181
179
  const checkpointBody = {
182
180
  schema: CheckpointBody,
183
181
  from: Effect.fn("OpenAIResponses.checkpointBody")(function* (request) {
184
- const native = yield* fromRequest(LLMRequest.update(request, { toolChoice: undefined }));
185
182
  const overlay = request.http?.body;
186
183
  // Complete history is required for stateless replay and SSE recovery. Raw input overrides bypass that contract.
187
184
  if (overlay?.input !== undefined ||
188
185
  overlay?.previous_response_id !== undefined ||
189
186
  overlay?.conversation !== undefined)
190
187
  return yield* ProviderShared.invalidRequest("Trigger compaction requires complete canonical history, not an input or continuation override");
191
- return yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(CheckpointBody))({
192
- ...mergeJsonRecords(native, overlay),
188
+ if (overlay?.stream !== undefined && overlay.stream !== true)
189
+ return yield* ProviderShared.invalidRequest("Trigger compaction requires a streamed response");
190
+ const native = yield* fromRequest(request);
191
+ return {
192
+ ...native,
193
193
  input: [...native.input, { type: "compaction_trigger" }],
194
- stream: true,
195
- store: false,
196
- parallel_tool_calls: true,
197
- tool_choice: undefined,
198
- context_management: undefined,
199
- text: undefined,
200
- max_output_tokens: undefined,
201
- max_tool_calls: undefined,
202
- });
194
+ };
203
195
  }),
204
196
  };
205
197
  const hostedToolResult = Effect.fn("OpenAIResponses.hostedToolResult")(function* (item) {
@@ -270,7 +262,10 @@ export const transport = channelTransport({
270
262
  headers: (headers) => Headers.set(headers, "openai-beta", headers["openai-beta"] ?? WEBSOCKET_PROTOCOL_HEADER),
271
263
  });
272
264
  export const route = Route.make({
273
- compact: { endpoint: ResponsesCompaction.make(adapter), trigger: ResponsesCheckpoint.make(checkpointBody) },
265
+ compact: {
266
+ endpoint: ResponsesCompaction.make(adapter, lowerTools),
267
+ trigger: ResponsesCheckpoint.make(checkpointBody),
268
+ },
274
269
  id: ADAPTER,
275
270
  provider: "openai",
276
271
  providerMetadataKey: "openai",
@@ -1,7 +1,7 @@
1
1
  import { Effect, Schema, Stream } from "effect";
2
2
  import { Route } from "../../route/client.js";
3
3
  import { Protocol } from "../../route/protocol.js";
4
- import { CompactionCheckpointResponse, HttpOptions, LLMEvent, LLMRequest } from "../../schema/index.js";
4
+ import { CompactionCheckpointResponse, LLMEvent, LLMRequest } from "../../schema/index.js";
5
5
  import { OpenResponses } from "../open-responses.js";
6
6
  import { ProviderShared } from "../shared.js";
7
7
  const onOutputItem = Effect.fn("ResponsesCheckpoint.onOutputItem")(function* (state, input) {
@@ -94,12 +94,8 @@ export const make = (body) => Effect.fn("ResponsesCheckpoint.execute")(function*
94
94
  transport: source.transport,
95
95
  });
96
96
  const native = yield* body.from(request);
97
- // The body builder already applied and validated overlays. Do not let transport reapply them.
98
- const preparedRequest = LLMRequest.update(request, {
99
- http: request.http === undefined ? undefined : new HttpOptions({ ...request.http, body: undefined }),
100
- });
101
- const prepared = yield* route.prepareTransport(native, preparedRequest, options);
102
- yield* route.streamPrepared(prepared, preparedRequest, { http: executor }, options).pipe(Stream.runDrain);
97
+ const prepared = yield* route.prepareTransport(native, request, options);
98
+ yield* route.streamPrepared(prepared, request, { http: executor }, options).pipe(Stream.runDrain);
103
99
  if (!result)
104
100
  return yield* ProviderShared.eventError(source.id, "Compaction response ended without a checkpoint");
105
101
  return result;
@@ -1,4 +1,6 @@
1
+ import { Effect } from "effect";
2
+ import { AIError, LLMRequest } from "../../schema/index.js";
1
3
  import type { CompactOperation } from "../../route/client.js";
2
4
  import { OpenResponses } from "../open-responses.js";
3
- export declare const make: (adapter: OpenResponses.ProviderAdapter) => CompactOperation;
5
+ export declare const make: (adapter: OpenResponses.ProviderAdapter, lowerTools: (request: LLMRequest) => Effect.Effect<ReadonlyArray<Record<string, unknown>>, AIError>) => CompactOperation;
4
6
  export * as ResponsesCompaction from "./responses-compaction.js";
@@ -7,12 +7,18 @@ import { HttpTransport } from "../../route/transport/index.js";
7
7
  import { OpenResponses } from "../open-responses.js";
8
8
  import { JsonObject, optionalNull, ProviderShared } from "../shared.js";
9
9
  import { Media } from "../../media.js";
10
+ // /compact has a smaller wire contract than /responses; keep the request controls it accepts.
10
11
  const Body = Schema.Struct({
11
12
  model: Schema.String,
12
13
  input: Schema.Array(Schema.Unknown),
13
14
  instructions: optionalNull(Schema.String),
14
15
  previous_response_id: optionalNull(Schema.String),
15
16
  service_tier: optionalNull(Schema.String),
17
+ reasoning: Schema.optional(JsonObject),
18
+ text: Schema.optional(JsonObject),
19
+ include: OpenResponses.coreFields.include,
20
+ parallel_tool_calls: OpenResponses.coreFields.parallel_tool_calls,
21
+ tools: Schema.optional(Schema.Array(JsonObject)),
16
22
  prompt_cache_key: optionalNull(Schema.String),
17
23
  prompt_cache_retention: optionalNull(Schema.String),
18
24
  prompt_cache_options: optionalNull(Schema.Struct({ mode: Schema.optional(Schema.String), ttl: Schema.optional(Schema.String) })),
@@ -54,14 +60,21 @@ const Response = Schema.Struct({
54
60
  ])),
55
61
  usage: Schema.optional(Schema.StructWithRest(OpenResponses.OpenResponsesUsage, [JsonObject])),
56
62
  });
57
- export const make = (adapter) => Effect.fn("ResponsesCompaction.execute")(function* (request, executor, options) {
63
+ export const make = (adapter, lowerTools) => Effect.fn("ResponsesCompaction.execute")(function* (request, executor, options) {
58
64
  const route = request.model.route;
59
65
  // The standalone compaction endpoint rejects histories containing configuration updates.
60
66
  const native = yield* OpenResponses.lowerConversation(stripEffortUpdates(request), adapter);
67
+ const generation = OpenResponses.lowerGeneration(request);
68
+ const tools = request.tools.length === 0 ? undefined : yield* lowerTools(request);
61
69
  const body = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Body))(mergeJsonRecords({
62
70
  ...native,
63
- service_tier: request.providerOptions?.serviceTier,
64
- prompt_cache_key: ProviderShared.promptCacheKey(request),
71
+ service_tier: generation.service_tier,
72
+ reasoning: generation.reasoning,
73
+ text: generation.text,
74
+ include: generation.include,
75
+ parallel_tool_calls: generation.parallel_tool_calls,
76
+ tools,
77
+ prompt_cache_key: generation.prompt_cache_key,
65
78
  }, request.http?.body));
66
79
  const url = Endpoint.render(route.endpoint, { request, body: native });
67
80
  url.pathname = `${url.pathname.replace(/\/$/, "")}/compact`;
@@ -77,5 +77,5 @@ export const protocol = Protocol.make({
77
77
  terminal: OpenResponses.terminal,
78
78
  },
79
79
  });
80
- export const compact = ResponsesCompaction.make(adapter);
80
+ export const compact = ResponsesCompaction.make(adapter, (request) => OpenResponses.lowerTools(ProviderShared.flattenTools(request.tools), adapter));
81
81
  export * as XAIResponses from "./xai-responses.js";
@@ -10,17 +10,11 @@ export type OpenAIOptionsInput = Omit<Options, "serviceTier"> & {
10
10
  readonly [key: string]: unknown;
11
11
  };
12
12
  export type OpenAIProviderOptionsInput = OpenAIOptionsInput;
13
- export declare const gpt5DefaultOptions: (modelID: string, options?: {
14
- readonly textVerbosity?: boolean;
15
- }) => ProviderOptions | undefined;
16
- export declare const openAIDefaultOptions: (modelID: string, options?: {
17
- readonly textVerbosity?: boolean;
18
- }) => ProviderOptions | undefined;
13
+ export declare const gpt5DefaultOptions: (modelID: string) => ProviderOptions | undefined;
14
+ export declare const openAIDefaultOptions: (modelID: string) => ProviderOptions | undefined;
19
15
  export declare const withOpenAIOptions: <Options extends {
20
16
  readonly providerOptions?: OpenAIProviderOptionsInput;
21
- }>(modelID: string, options: Options, defaults?: {
22
- readonly textVerbosity?: boolean;
23
- }) => Omit<Options, "providerOptions"> & {
17
+ }>(modelID: string, options: Options) => Omit<Options, "providerOptions"> & {
24
18
  readonly providerOptions?: ProviderOptions;
25
19
  };
26
20
  export * as OpenAIProviderOptions from "./openai-options.js";
@@ -13,7 +13,7 @@ const openAIProviderOptions = (options) => {
13
13
  return undefined;
14
14
  return result;
15
15
  };
16
- export const gpt5DefaultOptions = (modelID, options = {}) => {
16
+ export const gpt5DefaultOptions = (modelID) => {
17
17
  const id = modelID.toLowerCase();
18
18
  if (!id.includes("gpt-5") || id.includes("gpt-5-chat") || id.includes("gpt-5-pro"))
19
19
  return undefined;
@@ -26,16 +26,13 @@ export const gpt5DefaultOptions = (modelID, options = {}) => {
26
26
  // this, callers using the default model facade get reasoning summaries
27
27
  // they cannot replay statelessly.
28
28
  include: ["reasoning.encrypted_content"],
29
- textVerbosity: options.textVerbosity === true && id.includes("gpt-5.") && !id.includes("codex") && !id.includes("-chat")
30
- ? "low"
31
- : undefined,
32
29
  });
33
30
  };
34
- export const openAIDefaultOptions = (modelID, options = {}) => mergeProviderOptions(openAIProviderOptions({ store: false }), gpt5DefaultOptions(modelID, options));
35
- export const withOpenAIOptions = (modelID, options, defaults = {}) => {
31
+ export const openAIDefaultOptions = (modelID) => mergeProviderOptions(openAIProviderOptions({ store: false }), gpt5DefaultOptions(modelID));
32
+ export const withOpenAIOptions = (modelID, options) => {
36
33
  return {
37
34
  ...options,
38
- providerOptions: mergeProviderOptions(openAIDefaultOptions(modelID, defaults), options.providerOptions),
35
+ providerOptions: mergeProviderOptions(openAIDefaultOptions(modelID), options.providerOptions),
39
36
  };
40
37
  };
41
38
  export * as OpenAIProviderOptions from "./openai-options.js";
@@ -41,7 +41,7 @@ export const configure = (input = {}) => {
41
41
  const chatRoute = configuredRoute(OpenAIChat.route, input);
42
42
  const modelDefaults = defaults(input);
43
43
  const responses = (id) => responsesRoute
44
- .with(withOpenAIOptions(id, modelDefaults, { textVerbosity: true }))
44
+ .with(withOpenAIOptions(id, modelDefaults))
45
45
  .model({ id });
46
46
  const chat = (id) => chatRoute.with(withOpenAIOptions(id, modelDefaults)).model({
47
47
  id,
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-20141",
3
+ "version": "0.0.0-dev-20142",
4
4
  "name": "@opencode/ai",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@clack/prompts": "1.0.0-alpha.1",
36
36
  "@effect/platform-node": "4.0.0-rc.112",
37
- "@opencode/http-recorder": "0.0.0-dev-20141",
37
+ "@opencode/http-recorder": "0.0.0-dev-20142",
38
38
  "@tsconfig/bun": "1.0.9",
39
39
  "@types/bun": "1.4.0",
40
40
  "@typescript/native-preview": "7.0.0-dev.20251207.1",
@@ -44,7 +44,7 @@
44
44
  "@aws-sdk/credential-providers": "3.1057.0",
45
45
  "@smithy/eventstream-codec": "4.2.14",
46
46
  "@smithy/util-utf8": "4.2.2",
47
- "@opencode/schema": "0.0.0-dev-20141",
47
+ "@opencode/schema": "0.0.0-dev-20142",
48
48
  "aws4fetch": "1.0.20",
49
49
  "effect": "4.0.0-rc.112",
50
50
  "google-auth-library": "10.5.0"