@gajae-code/ai 0.7.3 → 0.7.5
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 +15 -0
- package/dist/types/model-thinking.d.ts +1 -1
- package/dist/types/utils/oauth/index.d.ts +1 -0
- package/package.json +2 -2
- package/src/auth-storage.ts +35 -27
- package/src/model-thinking.ts +2 -9
- package/src/models.json +1 -1
- package/src/providers/openai-codex-responses.ts +10 -9
- package/src/providers/openai-completions-compat.ts +2 -1
- package/src/utils/oauth/index.ts +3 -0
- package/src/utils.ts +52 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.7.5] - 2026-06-27
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Sanitized Codex history replay text fields so malformed/non-string replay text no longer corrupts the rebuilt request payload (#1199).
|
|
10
|
+
- Preserved object-valued tool replay fields when rebuilding Codex history payloads instead of coercing them to strings (#1200).
|
|
11
|
+
|
|
12
|
+
## [0.7.4] - 2026-06-27
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Treated `openai-codex-device` as an auth-storage alias for `openai-codex`, so headless/device Codex logins show as authenticated and logout/remove the stored Codex credential instead of appearing unsaved (#1151).
|
|
17
|
+
- Disabled thinking for OpenCode Go forced tool calls so forced-tool turns no longer emit unsupported thinking content (#1185).
|
|
18
|
+
- Restored the GPT-5.5 context window to its correct size (#1186).
|
|
19
|
+
|
|
5
20
|
## [0.7.3] - 2026-06-25
|
|
6
21
|
### Added
|
|
7
22
|
|
|
@@ -41,7 +41,7 @@ export declare function applyGeneratedModelPolicies(models: ApiModel<Api>[]): vo
|
|
|
41
41
|
* model with a larger context window on the same provider:
|
|
42
42
|
* - `OpenAI code backend-spark` variants promote to `gpt-5.5`.
|
|
43
43
|
*
|
|
44
|
-
* `gpt-5.5` itself is a
|
|
44
|
+
* `gpt-5.5` itself is a 1M-context model and is not demoted to `gpt-5.4`
|
|
45
45
|
* (which has a smaller window), so it has no promotion target.
|
|
46
46
|
*/
|
|
47
47
|
export declare function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void;
|
|
@@ -32,6 +32,7 @@ export declare function getOAuthApiKey(provider: OAuthProvider, credentials: Rec
|
|
|
32
32
|
newCredentials: OAuthCredentials;
|
|
33
33
|
apiKey: string;
|
|
34
34
|
} | null>;
|
|
35
|
+
export declare function resolveOAuthStorageProvider(provider: OAuthProviderId): OAuthProviderId;
|
|
35
36
|
/**
|
|
36
37
|
* Get list of OAuth providers.
|
|
37
38
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.5",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://gaebal-gajae.dev",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
45
45
|
"@bufbuild/protobuf": "^2.12.0",
|
|
46
|
-
"@gajae-code/utils": "0.7.
|
|
46
|
+
"@gajae-code/utils": "0.7.5",
|
|
47
47
|
"openai": "^6.36.0",
|
|
48
48
|
"partial-json": "^0.1.7",
|
|
49
49
|
"zod": "4.4.3"
|
package/src/auth-storage.ts
CHANGED
|
@@ -31,7 +31,7 @@ import { grokCliRankingStrategy, grokCliUsageProvider } from "./usage/grok-cli";
|
|
|
31
31
|
import { kimiUsageProvider } from "./usage/kimi";
|
|
32
32
|
import { codexRankingStrategy, openaiCodexUsageProvider } from "./usage/openai-codex";
|
|
33
33
|
import { zaiUsageProvider } from "./usage/zai";
|
|
34
|
-
import { getOAuthApiKey, getOAuthProvider, refreshOAuthToken } from "./utils/oauth";
|
|
34
|
+
import { getOAuthApiKey, getOAuthProvider, refreshOAuthToken, resolveOAuthStorageProvider } from "./utils/oauth";
|
|
35
35
|
import { loginDeepSeek } from "./utils/oauth/deepseek";
|
|
36
36
|
import { loginOpenAICodexDevice } from "./utils/oauth/openai-codex";
|
|
37
37
|
import type { OAuthController, OAuthCredentials, OAuthProvider, OAuthProviderId } from "./utils/oauth/types";
|
|
@@ -918,7 +918,8 @@ export class AuthStorage {
|
|
|
918
918
|
* @returns Array of stored credentials, empty if none exist
|
|
919
919
|
*/
|
|
920
920
|
#getStoredCredentials(provider: string): StoredCredential[] {
|
|
921
|
-
|
|
921
|
+
const storageProvider = resolveOAuthStorageProvider(provider);
|
|
922
|
+
return this.#data.get(storageProvider) ?? [];
|
|
922
923
|
}
|
|
923
924
|
|
|
924
925
|
/**
|
|
@@ -1250,16 +1251,17 @@ export class AuthStorage {
|
|
|
1250
1251
|
* Set credential for a provider.
|
|
1251
1252
|
*/
|
|
1252
1253
|
async set(provider: string, credential: AuthCredentialEntry): Promise<void> {
|
|
1254
|
+
const storageProvider = resolveOAuthStorageProvider(provider);
|
|
1253
1255
|
const normalized = Array.isArray(credential) ? credential : [credential];
|
|
1254
|
-
const deduped = this.#dedupeOAuthCredentials(
|
|
1256
|
+
const deduped = this.#dedupeOAuthCredentials(storageProvider, normalized);
|
|
1255
1257
|
const stored = this.#store.replaceAuthCredentialsRemote
|
|
1256
|
-
? await this.#store.replaceAuthCredentialsRemote(
|
|
1257
|
-
: this.#store.replaceAuthCredentialsForProvider(
|
|
1258
|
+
? await this.#store.replaceAuthCredentialsRemote(storageProvider, deduped)
|
|
1259
|
+
: this.#store.replaceAuthCredentialsForProvider(storageProvider, deduped);
|
|
1258
1260
|
this.#setStoredCredentials(
|
|
1259
|
-
|
|
1261
|
+
storageProvider,
|
|
1260
1262
|
stored.map(record => ({ id: record.id, credential: record.credential })),
|
|
1261
1263
|
);
|
|
1262
|
-
this.#resetProviderAssignments(
|
|
1264
|
+
this.#resetProviderAssignments(storageProvider);
|
|
1263
1265
|
}
|
|
1264
1266
|
|
|
1265
1267
|
#toSnapshotEntries(provider: string, stored: StoredAuthCredential[]): AuthCredentialSnapshotEntry[] {
|
|
@@ -1289,26 +1291,30 @@ export class AuthStorage {
|
|
|
1289
1291
|
provider: string,
|
|
1290
1292
|
credential: AuthCredential,
|
|
1291
1293
|
): Promise<AuthCredentialIfAbsentSnapshotResult> {
|
|
1292
|
-
|
|
1293
|
-
if (this.#
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
if (this.#
|
|
1294
|
+
const storageProvider = resolveOAuthStorageProvider(provider);
|
|
1295
|
+
if (this.#runtimeOverrides.has(storageProvider))
|
|
1296
|
+
return this.#snapshotSkipResult(storageProvider, "skipped-existing-runtime");
|
|
1297
|
+
if (this.#configOverrides.has(storageProvider))
|
|
1298
|
+
return this.#snapshotSkipResult(storageProvider, "skipped-existing-config");
|
|
1299
|
+
if (this.#getCredentialsForProvider(storageProvider).length > 0)
|
|
1300
|
+
return this.#snapshotSkipResult(storageProvider, "skipped-existing");
|
|
1301
|
+
if (getEnvApiKey(storageProvider)) return this.#snapshotSkipResult(storageProvider, "skipped-existing-env");
|
|
1302
|
+
if (this.#fallbackResolver?.(storageProvider))
|
|
1303
|
+
return this.#snapshotSkipResult(storageProvider, "skipped-existing-fallback");
|
|
1298
1304
|
|
|
1299
1305
|
const result = this.#store.upsertAuthCredentialRemoteIfAbsent
|
|
1300
|
-
? await this.#store.upsertAuthCredentialRemoteIfAbsent(
|
|
1301
|
-
: this.#store.upsertAuthCredentialForProviderIfAbsent(
|
|
1306
|
+
? await this.#store.upsertAuthCredentialRemoteIfAbsent(storageProvider, credential)
|
|
1307
|
+
: this.#store.upsertAuthCredentialForProviderIfAbsent(storageProvider, credential);
|
|
1302
1308
|
this.#setStoredCredentials(
|
|
1303
|
-
|
|
1309
|
+
storageProvider,
|
|
1304
1310
|
result.entries.map(entry => ({ id: entry.id, credential: entry.credential })),
|
|
1305
1311
|
);
|
|
1306
|
-
this.#resetProviderAssignments(
|
|
1312
|
+
this.#resetProviderAssignments(storageProvider);
|
|
1307
1313
|
return {
|
|
1308
1314
|
inserted: result.inserted,
|
|
1309
1315
|
reason: result.reason,
|
|
1310
1316
|
provider: result.provider,
|
|
1311
|
-
entries: this.#toSnapshotEntries(
|
|
1317
|
+
entries: this.#toSnapshotEntries(storageProvider, result.entries),
|
|
1312
1318
|
};
|
|
1313
1319
|
}
|
|
1314
1320
|
|
|
@@ -1327,13 +1333,14 @@ export class AuthStorage {
|
|
|
1327
1333
|
* Remove credential for a provider.
|
|
1328
1334
|
*/
|
|
1329
1335
|
async remove(provider: string): Promise<void> {
|
|
1336
|
+
const storageProvider = resolveOAuthStorageProvider(provider);
|
|
1330
1337
|
if (this.#store.deleteAuthCredentialsRemote) {
|
|
1331
|
-
await this.#store.deleteAuthCredentialsRemote(
|
|
1338
|
+
await this.#store.deleteAuthCredentialsRemote(storageProvider, "deleted by user");
|
|
1332
1339
|
} else {
|
|
1333
|
-
this.#store.deleteAuthCredentialsForProvider(
|
|
1340
|
+
this.#store.deleteAuthCredentialsForProvider(storageProvider, "deleted by user");
|
|
1334
1341
|
}
|
|
1335
|
-
this.#setStoredCredentials(
|
|
1336
|
-
this.#resetProviderAssignments(
|
|
1342
|
+
this.#setStoredCredentials(storageProvider, []);
|
|
1343
|
+
this.#resetProviderAssignments(storageProvider);
|
|
1337
1344
|
}
|
|
1338
1345
|
|
|
1339
1346
|
/**
|
|
@@ -1355,11 +1362,12 @@ export class AuthStorage {
|
|
|
1355
1362
|
* Unlike getApiKey(), this doesn't refresh OAuth tokens.
|
|
1356
1363
|
*/
|
|
1357
1364
|
hasAuth(provider: string): boolean {
|
|
1358
|
-
|
|
1359
|
-
if (this.#
|
|
1360
|
-
if (this.#
|
|
1361
|
-
if (
|
|
1362
|
-
if (
|
|
1365
|
+
const storageProvider = resolveOAuthStorageProvider(provider);
|
|
1366
|
+
if (this.#runtimeOverrides.has(storageProvider)) return true;
|
|
1367
|
+
if (this.#configOverrides.has(storageProvider)) return true;
|
|
1368
|
+
if (this.#getCredentialsForProvider(storageProvider).length > 0) return true;
|
|
1369
|
+
if (getEnvApiKey(storageProvider)) return true;
|
|
1370
|
+
if (this.#fallbackResolver?.(storageProvider)) return true;
|
|
1363
1371
|
return false;
|
|
1364
1372
|
}
|
|
1365
1373
|
|
package/src/model-thinking.ts
CHANGED
|
@@ -197,7 +197,7 @@ export function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void {
|
|
|
197
197
|
* model with a larger context window on the same provider:
|
|
198
198
|
* - `OpenAI code backend-spark` variants promote to `gpt-5.5`.
|
|
199
199
|
*
|
|
200
|
-
* `gpt-5.5` itself is a
|
|
200
|
+
* `gpt-5.5` itself is a 1M-context model and is not demoted to `gpt-5.4`
|
|
201
201
|
* (which has a smaller window), so it has no promotion target.
|
|
202
202
|
*/
|
|
203
203
|
export function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void {
|
|
@@ -453,15 +453,8 @@ function inferGeneratedApplyPatchToolType(
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
function applyGpt55ContextWindow(model: ApiModel<Api>, parsedModel: OpenAIModel): boolean {
|
|
456
|
-
// OpenAI Codex reports GPT-5.5 with a 272K prompt budget. Keep the generated
|
|
457
|
-
// bundle aligned with the backend limit so compaction fires before the prompt
|
|
458
|
-
// crosses the usable Codex window instead of trusting stale 400K snapshots.
|
|
459
|
-
if (model.provider === "openai-codex" && parsedModel.variant === "base" && semverEqual(parsedModel.version, "5.5")) {
|
|
460
|
-
model.contextWindow = 272000;
|
|
461
|
-
return true;
|
|
462
|
-
}
|
|
463
456
|
if (parsedModel.variant === "base" && semverEqual(parsedModel.version, "5.5")) {
|
|
464
|
-
model.contextWindow =
|
|
457
|
+
model.contextWindow = 1_000_000;
|
|
465
458
|
return true;
|
|
466
459
|
}
|
|
467
460
|
return false;
|
package/src/models.json
CHANGED
|
@@ -56310,7 +56310,7 @@
|
|
|
56310
56310
|
"cacheRead": 0.5,
|
|
56311
56311
|
"cacheWrite": 0
|
|
56312
56312
|
},
|
|
56313
|
-
"contextWindow":
|
|
56313
|
+
"contextWindow": 1000000,
|
|
56314
56314
|
"maxTokens": 128000,
|
|
56315
56315
|
"preferWebsockets": true,
|
|
56316
56316
|
"priority": 9,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
getOpenAIResponsesHistoryItems,
|
|
45
45
|
getOpenAIResponsesHistoryPayload,
|
|
46
46
|
normalizeSystemPrompts,
|
|
47
|
+
sanitizeOpenAIResponsesHistoryItemsForReplay,
|
|
47
48
|
} from "../utils";
|
|
48
49
|
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
49
50
|
import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-inspector";
|
|
@@ -2550,17 +2551,16 @@ function convertMessages(model: Model<"openai-codex-responses">, context: Contex
|
|
|
2550
2551
|
for (const msg of transformedMessages) {
|
|
2551
2552
|
if (msg.role === "user" || msg.role === "developer") {
|
|
2552
2553
|
const providerPayload = (msg as { providerPayload?: AssistantMessage["providerPayload"] }).providerPayload;
|
|
2553
|
-
const historyItems = getOpenAIResponsesHistoryItems(providerPayload, model.provider)
|
|
2554
|
-
| Array<ResponseInput[number]>
|
|
2555
|
-
| undefined;
|
|
2554
|
+
const historyItems = getOpenAIResponsesHistoryItems(providerPayload, model.provider);
|
|
2556
2555
|
if (historyItems) {
|
|
2557
|
-
|
|
2556
|
+
const sanitizedHistoryItems = sanitizeOpenAIResponsesHistoryItemsForReplay(historyItems);
|
|
2557
|
+
for (const item of sanitizedHistoryItems) {
|
|
2558
2558
|
const maybe = item as { type?: string; call_id?: string };
|
|
2559
2559
|
if (maybe.type === "custom_tool_call" && typeof maybe.call_id === "string") {
|
|
2560
2560
|
customCallIds.add(maybe.call_id);
|
|
2561
2561
|
}
|
|
2562
2562
|
}
|
|
2563
|
-
messages.push(...
|
|
2563
|
+
messages.push(...sanitizedHistoryItems);
|
|
2564
2564
|
msgIndex += 1;
|
|
2565
2565
|
continue;
|
|
2566
2566
|
}
|
|
@@ -2579,18 +2579,19 @@ function convertMessages(model: Model<"openai-codex-responses">, context: Contex
|
|
|
2579
2579
|
model.provider,
|
|
2580
2580
|
assistantMsg.provider,
|
|
2581
2581
|
);
|
|
2582
|
-
const historyItems = providerPayload?.items
|
|
2582
|
+
const historyItems = providerPayload?.items;
|
|
2583
2583
|
if (historyItems) {
|
|
2584
|
-
|
|
2584
|
+
const sanitizedHistoryItems = sanitizeOpenAIResponsesHistoryItemsForReplay(historyItems);
|
|
2585
|
+
for (const item of sanitizedHistoryItems) {
|
|
2585
2586
|
const maybe = item as { type?: string; call_id?: string };
|
|
2586
2587
|
if (maybe.type === "custom_tool_call" && typeof maybe.call_id === "string") {
|
|
2587
2588
|
customCallIds.add(maybe.call_id);
|
|
2588
2589
|
}
|
|
2589
2590
|
}
|
|
2590
2591
|
if (providerPayload?.dt) {
|
|
2591
|
-
messages.push(...
|
|
2592
|
+
messages.push(...sanitizedHistoryItems);
|
|
2592
2593
|
} else {
|
|
2593
|
-
messages.splice(0, messages.length, ...
|
|
2594
|
+
messages.splice(0, messages.length, ...sanitizedHistoryItems);
|
|
2594
2595
|
// Keep customCallIds from the pre-splice state since historyItems may re-introduce them.
|
|
2595
2596
|
}
|
|
2596
2597
|
msgIndex += 1;
|
|
@@ -103,6 +103,7 @@ export function detectOpenAICompat(model: Model<"openai-completions">, resolvedB
|
|
|
103
103
|
provider === "opencode-go" ||
|
|
104
104
|
baseUrl.includes("opencode.ai");
|
|
105
105
|
const isOpenCodeProvider = provider === "opencode-go" || provider === "opencode-zen";
|
|
106
|
+
const isOpenCodeGoReasoning = provider === "opencode-go" && Boolean(model.reasoning);
|
|
106
107
|
|
|
107
108
|
const useMaxTokens =
|
|
108
109
|
provider === "mistral" ||
|
|
@@ -194,7 +195,7 @@ export function detectOpenAICompat(model: Model<"openai-completions">, resolvedB
|
|
|
194
195
|
supportsReasoningEffort: !isGrok && !isZai,
|
|
195
196
|
reasoningEffortMap,
|
|
196
197
|
supportsUsageInStreaming: !isCerebras,
|
|
197
|
-
disableReasoningOnForcedToolChoice: isKimiModel || isAnthropicModel,
|
|
198
|
+
disableReasoningOnForcedToolChoice: isKimiModel || isAnthropicModel || isOpenCodeGoReasoning,
|
|
198
199
|
disableReasoningOnToolChoice: isDeepseekFamily && Boolean(model.reasoning) && !isOpenRouter,
|
|
199
200
|
supportsToolChoice: !isDirectDeepseekReasoning,
|
|
200
201
|
supportsForcedToolChoice: true,
|
package/src/utils/oauth/index.ts
CHANGED
|
@@ -472,6 +472,9 @@ export async function getOAuthApiKey(
|
|
|
472
472
|
return { newCredentials: creds, apiKey };
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
+
export function resolveOAuthStorageProvider(provider: OAuthProviderId): OAuthProviderId {
|
|
476
|
+
return provider === "openai-codex-device" ? "openai-codex" : provider;
|
|
477
|
+
}
|
|
475
478
|
/**
|
|
476
479
|
* Get list of OAuth providers.
|
|
477
480
|
*/
|
package/src/utils.ts
CHANGED
|
@@ -91,6 +91,57 @@ export function sanitizeOpenAIResponsesHistoryItemsForReplay(items: Array<Record
|
|
|
91
91
|
return sanitized ? [sanitized] : [];
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
|
+
function stringifyResponsesStringParamForReplay(value: unknown): string {
|
|
95
|
+
if (typeof value === "string") return value.toWellFormed();
|
|
96
|
+
try {
|
|
97
|
+
const encoded = JSON.stringify(value);
|
|
98
|
+
if (typeof encoded === "string") return encoded.toWellFormed();
|
|
99
|
+
} catch {
|
|
100
|
+
// Fall through to String().
|
|
101
|
+
}
|
|
102
|
+
return String(value ?? "").toWellFormed();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function normalizeResponsesMessageTextForReplay(value: unknown): string {
|
|
106
|
+
if (typeof value === "string") return value.toWellFormed();
|
|
107
|
+
if (value && typeof value === "object") {
|
|
108
|
+
const nestedText = (value as { text?: unknown }).text;
|
|
109
|
+
if (typeof nestedText === "string") return nestedText.toWellFormed();
|
|
110
|
+
}
|
|
111
|
+
return stringifyResponsesStringParamForReplay(value);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function sanitizeResponsesMessageContentForReplay(content: unknown): unknown {
|
|
115
|
+
if (typeof content === "string") return content.toWellFormed();
|
|
116
|
+
if (!Array.isArray(content)) return content;
|
|
117
|
+
return content.map(part => {
|
|
118
|
+
if (!part || typeof part !== "object") return part;
|
|
119
|
+
const sanitizedPart = { ...(part as Record<string, unknown>) };
|
|
120
|
+
if ("text" in sanitizedPart) {
|
|
121
|
+
sanitizedPart.text = normalizeResponsesMessageTextForReplay(sanitizedPart.text);
|
|
122
|
+
}
|
|
123
|
+
return sanitizedPart;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function sanitizeResponsesStringFieldsForReplay(item: Record<string, unknown>): void {
|
|
128
|
+
if (item.type === "message") {
|
|
129
|
+
item.content = sanitizeResponsesMessageContentForReplay(item.content);
|
|
130
|
+
}
|
|
131
|
+
if (item.type === "function_call" && "arguments" in item && typeof item.arguments !== "string") {
|
|
132
|
+
item.arguments = stringifyResponsesStringParamForReplay(item.arguments);
|
|
133
|
+
}
|
|
134
|
+
if (item.type === "custom_tool_call" && "input" in item && typeof item.input !== "string") {
|
|
135
|
+
item.input = stringifyResponsesStringParamForReplay(item.input);
|
|
136
|
+
}
|
|
137
|
+
if (
|
|
138
|
+
(item.type === "function_call_output" || item.type === "custom_tool_call_output") &&
|
|
139
|
+
"output" in item &&
|
|
140
|
+
typeof item.output !== "string"
|
|
141
|
+
) {
|
|
142
|
+
item.output = stringifyResponsesStringParamForReplay(item.output);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
94
145
|
|
|
95
146
|
function sanitizeOpenAIResponsesHistoryItemForReplay(
|
|
96
147
|
item: Record<string, unknown>,
|
|
@@ -105,6 +156,7 @@ function sanitizeOpenAIResponsesHistoryItemForReplay(
|
|
|
105
156
|
if (typeof item.call_id === "string") {
|
|
106
157
|
sanitizedItem.call_id = normalizeReplayedResponsesHistoryCallId(item.call_id, normalizedCallIds);
|
|
107
158
|
}
|
|
159
|
+
sanitizeResponsesStringFieldsForReplay(sanitizedItem);
|
|
108
160
|
|
|
109
161
|
return sanitizedItem as unknown as OpenAIResponsesReplayItem;
|
|
110
162
|
}
|