@opencode-ai/ai 0.0.0-dev-18035 → 0.0.0-dev-18040

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.
@@ -57,6 +57,9 @@ const driver = (options, body) => {
57
57
  responseID = created;
58
58
  return { type: "frame", frame };
59
59
  }
60
+ // Keepalives carry no response state and may arrive before response.created.
61
+ if (event.type === "keepalive")
62
+ return { type: "frame", frame };
60
63
  if (!responseID)
61
64
  return yield* ProviderShared.eventError(options.id, `${options.name} emitted ${event.type} before response.created`, frame);
62
65
  if (event.response?.id && event.response.id !== responseID)
@@ -416,8 +416,12 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
416
416
  const id = itemID(part.providerMetadata, providerMetadataKey);
417
417
  if (store !== false && id && !hostedToolReferences.has(id))
418
418
  input.push({ type: "item_reference", id });
419
- if (store === false && part.result.type === "content") {
420
- const content = part.result.value;
419
+ if (store === false) {
420
+ // The server is not storing this exchange, so the tool outcome has to
421
+ // travel in the input. Non-content results degrade to their text form.
422
+ const content = part.result.type === "content"
423
+ ? part.result.value
424
+ : [{ type: "text", text: ProviderShared.toolResultText(part) }];
421
425
  input.push({
422
426
  role: "user",
423
427
  content: yield* Effect.forEach(content, (item) => lowerHostedToolResultContentItem(item, request, extension)),
@@ -456,6 +460,7 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
456
460
  });
457
461
  const lowerOptions = (request) => {
458
462
  const options = OpenResponsesOptions.resolve(request);
463
+ const cacheKey = ProviderShared.clampPromptCacheKey(request.promptCacheKey);
459
464
  return {
460
465
  ...(options.instructions ? { instructions: options.instructions } : {}),
461
466
  ...(options.store !== undefined ? { store: options.store } : {}),
@@ -465,7 +470,7 @@ const lowerOptions = (request) => {
465
470
  ? { stream_options: { include_obfuscation: options.streamOptions.includeObfuscation } }
466
471
  : {}),
467
472
  ...(options.topLogprobs !== undefined ? { top_logprobs: options.topLogprobs } : {}),
468
- ...(request.promptCacheKey ? { prompt_cache_key: request.promptCacheKey } : {}),
473
+ ...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
469
474
  ...(options.include ? { include: options.include } : {}),
470
475
  ...(options.reasoningEffort || options.reasoningSummary
471
476
  ? { reasoning: { effort: options.reasoningEffort, summary: options.reasoningSummary } }
@@ -415,9 +415,10 @@ const hasToolHistory = (messages) => {
415
415
  };
416
416
  const lowerOptions = (request) => {
417
417
  const options = OpenAIOptions.resolve(request);
418
+ const cacheKey = ProviderShared.clampPromptCacheKey(request.promptCacheKey);
418
419
  return {
419
420
  ...(options.store !== undefined ? { store: options.store } : {}),
420
- ...(request.promptCacheKey ? { prompt_cache_key: request.promptCacheKey } : {}),
421
+ ...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
421
422
  ...(options.reasoningEffort ? { reasoning_effort: options.reasoningEffort } : {}),
422
423
  };
423
424
  };
@@ -10,6 +10,8 @@ export declare const encodeJson: (input: unknown, options?: import("effect/Schem
10
10
  export declare const JsonObject: Schema.$Record<Schema.String, Schema.Unknown>;
11
11
  export declare const optionalArray: <const S extends Schema.Top>(schema: S) => Schema.optional<Schema.$Array<S>>;
12
12
  export declare const optionalNull: <const S extends Schema.Top>(schema: S) => Schema.optional<Schema.NullOr<S>>;
13
+ export declare const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
14
+ export declare const clampPromptCacheKey: (key: string | undefined) => string | undefined;
13
15
  /**
14
16
  * Streaming tool-call accumulator. Adapters that build a tool call across
15
17
  * multiple `tool-input-delta` chunks store the partial JSON input string here
@@ -13,6 +13,17 @@ const isJson = Schema.is(Schema.Json);
13
13
  export const JsonObject = Schema.Record(Schema.String, Schema.Unknown);
14
14
  export const optionalArray = (schema) => Schema.optional(Schema.Array(schema));
15
15
  export const optionalNull = (schema) => Schema.optional(Schema.NullOr(schema));
16
+ export const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
17
+ // OpenAI limits `prompt_cache_key` to 64 chars; DeepSeek and Zai inherit the same
18
+ // limit via their OpenAI-compatible APIs. Clamp with unicode-aware slicing.
19
+ export const clampPromptCacheKey = (key) => {
20
+ if (key === undefined)
21
+ return undefined;
22
+ const chars = Array.from(key);
23
+ if (chars.length <= OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH)
24
+ return key;
25
+ return chars.slice(0, OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH).join("");
26
+ };
16
27
  /**
17
28
  * `Usage.totalTokens` policy shared by every route. Honors a provider-
18
29
  * supplied total; otherwise falls back to `inputTokens + outputTokens` only
@@ -8,7 +8,7 @@ import { ProviderID } from "../schema/index.js";
8
8
  import * as OpenAICompatibleProfiles from "./openai-compatible-profile.js";
9
9
  import * as OpenAIChat from "../protocols/openai-chat.js";
10
10
  import { newBreakpoints, ttlBucket } from "../protocols/utils/cache.js";
11
- import { isRecord } from "../protocols/shared.js";
11
+ import { isRecord, ProviderShared } from "../protocols/shared.js";
12
12
  export const profile = OpenAICompatibleProfiles.profiles.openrouter;
13
13
  export const id = ProviderID.make(profile.provider);
14
14
  const ADAPTER = "openrouter";
@@ -39,11 +39,12 @@ export const protocol = Protocol.make({
39
39
  reasoning_details: reasoningDetails,
40
40
  };
41
41
  });
42
+ const cacheKey = ProviderShared.clampPromptCacheKey(request.promptCacheKey);
42
43
  return {
43
44
  ...body,
44
45
  messages,
45
46
  ...bodyOptions(request.providerOptions),
46
- ...(request.promptCacheKey ? { prompt_cache_key: request.promptCacheKey } : {}),
47
+ ...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
47
48
  };
48
49
  })),
49
50
  },
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-18035",
3
+ "version": "0.0.0-dev-18040",
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-rc.111",
33
- "@opencode-ai/http-recorder": "0.0.0-dev-18035",
33
+ "@opencode-ai/http-recorder": "0.0.0-dev-18040",
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-dev-18035",
42
+ "@opencode-ai/schema": "0.0.0-dev-18040",
43
43
  "aws4fetch": "1.0.20",
44
44
  "effect": "4.0.0-rc.111",
45
45
  "google-auth-library": "10.5.0"