@oh-my-pi/pi-ai 14.8.0 → 14.8.1

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/CHANGELOG.md CHANGED
@@ -7,6 +7,7 @@
7
7
  ### Fixed
8
8
  - Fixed Gemini 3 Pro thinking metadata so `medium` effort is rejected with the expected error instead of being silently accepted: `ThinkingConfig` now carries an optional explicit `levels` list that survives `expandEffortRange`, letting non-contiguous supported sets (e.g. `[low, high]`) round-trip through enrichment.
9
9
  - Fixed Kimi Code OAuth expiry handling to refresh access tokens 5 minutes before server expiry, avoiding daily 401s from using tokens right up to the cutoff.
10
+ - Fixed OpenAI Responses custom tool replay to preserve custom tool call item IDs with the `ctc_` prefix instead of rewriting them as `fc_` function-call IDs ([#977](https://github.com/can1357/oh-my-pi/issues/977)).
10
11
 
11
12
  ## [14.7.6] - 2026-05-07
12
13
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "14.8.0",
4
+ "version": "14.8.1",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Can Boluk",
@@ -46,8 +46,8 @@
46
46
  "@aws-sdk/credential-provider-node": "^3.972.39",
47
47
  "@bufbuild/protobuf": "^2.12.0",
48
48
  "@google/genai": "^1.52.0",
49
- "@oh-my-pi/pi-natives": "14.8.0",
50
- "@oh-my-pi/pi-utils": "14.8.0",
49
+ "@oh-my-pi/pi-natives": "14.8.1",
50
+ "@oh-my-pi/pi-utils": "14.8.1",
51
51
  "@sinclair/typebox": "^0.34.49",
52
52
  "@smithy/node-http-handler": "^4.6.1",
53
53
  "ajv": "^8.20.0",
@@ -2438,7 +2438,7 @@ function convertMessages(model: Model<"openai-codex-responses">, context: Contex
2438
2438
  }
2439
2439
  if (block.type === "toolCall") {
2440
2440
  const toolCall = block as ToolCall;
2441
- const normalized = normalizeResponsesToolCallId(toolCall.id);
2441
+ const normalized = normalizeResponsesToolCallId(toolCall.id, toolCall.customWireName ? "ctc" : "fc");
2442
2442
  if (toolCall.customWireName) {
2443
2443
  const rawInput = typeof toolCall.arguments?.input === "string" ? toolCall.arguments.input : "";
2444
2444
  customCallIds.add(normalized.callId);
@@ -187,9 +187,9 @@ export function convertResponsesAssistantMessage<TApi extends Api>(
187
187
  continue;
188
188
  }
189
189
 
190
- const normalized = normalizeResponsesToolCallId(block.id);
190
+ const normalized = normalizeResponsesToolCallId(block.id, block.customWireName ? "ctc" : "fc");
191
191
  let itemId: string | undefined = normalized.itemId;
192
- if (isDifferentModel && (itemId?.startsWith("fc_") || itemId?.startsWith("fcr_"))) {
192
+ if (isDifferentModel && (itemId?.startsWith("fc_") || itemId?.startsWith("fcr_") || itemId?.startsWith("ctc_"))) {
193
193
  itemId = undefined;
194
194
  }
195
195
  knownCallIds.add(normalized.callId);
package/src/utils.ts CHANGED
@@ -36,16 +36,21 @@ export function normalizeToolCallId(id: string): string {
36
36
  return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;
37
37
  }
38
38
 
39
- export function normalizeResponsesToolCallId(id: string): { callId: string; itemId: string } {
39
+ type ResponsesToolItemIdPrefix = "fc" | "ctc";
40
+
41
+ export function normalizeResponsesToolCallId(
42
+ id: string,
43
+ itemPrefix: ResponsesToolItemIdPrefix = "fc",
44
+ ): { callId: string; itemId: string } {
40
45
  const [callId, itemId] = id.split("|");
41
46
  if (callId && itemId) {
42
47
  const normalizedCallId = truncateResponseItemId(callId, getIdPrefix(callId, "call"));
43
- const normalizedItemId = normalizeResponsesItemId(itemId);
48
+ const normalizedItemId = normalizeResponsesItemId(itemId, itemPrefix);
44
49
  return { callId: normalizedCallId, itemId: normalizedItemId };
45
50
  }
46
51
  const hash = Bun.hash(id).toString(36);
47
52
  const normalizedCallId = id.startsWith("call_") ? truncateResponseItemId(id, "call") : `call_${hash}`;
48
- return { callId: normalizedCallId, itemId: `fc_${hash}` };
53
+ return { callId: normalizedCallId, itemId: `${itemPrefix}_${hash}` };
49
54
  }
50
55
 
51
56
  function getIdPrefix(id: string, fallback: string): string {
@@ -53,10 +58,19 @@ function getIdPrefix(id: string, fallback: string): string {
53
58
  return prefix || fallback;
54
59
  }
55
60
 
56
- function normalizeResponsesItemId(itemId: string): string {
57
- const prefix = getIdPrefix(itemId, "fc");
58
- if (prefix !== "fc" && prefix !== "fcr") {
59
- return `fc_${Bun.hash(itemId).toString(36)}`;
61
+ function getExplicitIdPrefix(id: string): string | undefined {
62
+ return id.match(/^([a-zA-Z][a-zA-Z0-9]*)_/)?.[1];
63
+ }
64
+
65
+ function normalizeResponsesItemId(itemId: string, fallbackPrefix: ResponsesToolItemIdPrefix): string {
66
+ const prefix = getExplicitIdPrefix(itemId);
67
+ const isAllowedPrefix = prefix
68
+ ? fallbackPrefix === "ctc"
69
+ ? prefix === "ctc"
70
+ : prefix === "fc" || prefix === "fcr"
71
+ : false;
72
+ if (!prefix || !isAllowedPrefix) {
73
+ return `${fallbackPrefix}_${Bun.hash(itemId).toString(36)}`;
60
74
  }
61
75
  return truncateResponseItemId(itemId, prefix);
62
76
  }