@gajae-code/ai 0.14.2 → 0.15.0
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 +26 -0
- package/dist/types/auth-storage.d.ts +2 -2
- package/dist/types/model-cache.d.ts +2 -0
- package/dist/types/provider-models/special.d.ts +3 -1
- package/dist/types/providers/anthropic.d.ts +1 -0
- package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +3854 -107
- package/dist/types/providers/cursor-pi-args.d.ts +119 -0
- package/dist/types/providers/cursor.d.ts +8 -1
- package/dist/types/providers/openai-codex-responses.d.ts +2 -0
- package/dist/types/providers/openai-responses-shared.d.ts +1 -1
- package/dist/types/types.d.ts +41 -1
- package/dist/types/utils/block-symbols.d.ts +6 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +2 -0
- package/dist/types/utils/idle-iterator.d.ts +5 -2
- package/dist/types/utils/oauth/kimi.d.ts +3 -9
- package/dist/types/utils/oauth/openrouter.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/package.json +4 -4
- package/src/auth-broker/remote-store.ts +13 -2
- package/src/auth-storage.ts +10 -11
- package/src/model-cache.ts +78 -0
- package/src/model-manager.ts +194 -25
- package/src/provider-models/special.ts +67 -4
- package/src/providers/anthropic.ts +115 -40
- package/src/providers/aws-credential-config.ts +2 -3
- package/src/providers/aws-credentials.ts +2 -3
- package/src/providers/azure-openai-responses.ts +18 -2
- package/src/providers/cursor/exec-modern.ts +497 -0
- package/src/providers/cursor/gen/agent_pb.ts +4687 -181
- package/src/providers/cursor/proto/agent.proto +1007 -0
- package/src/providers/cursor-pi-args.ts +187 -0
- package/src/providers/cursor.ts +382 -47
- package/src/providers/google-auth.ts +2 -3
- package/src/providers/openai-codex-responses.ts +358 -73
- package/src/providers/openai-completions.ts +2 -2
- package/src/providers/openai-responses-shared.ts +55 -6
- package/src/providers/openai-responses.ts +27 -4
- package/src/stream.ts +8 -3
- package/src/types.ts +55 -0
- package/src/utils/block-symbols.ts +11 -0
- package/src/utils/discovery/openai-compatible.ts +21 -6
- package/src/utils/idle-iterator.ts +22 -4
- package/src/utils/oauth/index.ts +6 -0
- package/src/utils/oauth/kimi.ts +14 -8
- package/src/utils/oauth/kiro.ts +2 -2
- package/src/utils/oauth/openrouter.ts +16 -0
- package/src/utils/oauth/types.ts +1 -0
|
@@ -81,6 +81,7 @@ import {
|
|
|
81
81
|
parseStreamingJson,
|
|
82
82
|
} from "../utils/json-parse";
|
|
83
83
|
import { parseGitHubCopilotApiKey } from "../utils/oauth/github-copilot";
|
|
84
|
+
import { GLM_ZCODE_ANTHROPIC_BASE_URL } from "../utils/oauth/glm-zcode";
|
|
84
85
|
import { notifyProviderResponse } from "../utils/provider-response";
|
|
85
86
|
import { isCopilotTransientModelError } from "../utils/retry";
|
|
86
87
|
import { getRetryAfterMsFromHeaders } from "../utils/retry-after";
|
|
@@ -1144,6 +1145,29 @@ type FoundryTlsOptions = {
|
|
|
1144
1145
|
key?: string;
|
|
1145
1146
|
};
|
|
1146
1147
|
|
|
1148
|
+
export function resolveGlmZcodeAnthropicBaseUrl(): string {
|
|
1149
|
+
const configured = $credentialEnv("ZCODE_PLAN_ANTHROPIC_BASE_URL")?.trim();
|
|
1150
|
+
if (!configured || /[\u0000-\u001f\u007f-\u009f]/u.test(configured)) {
|
|
1151
|
+
return GLM_ZCODE_ANTHROPIC_BASE_URL;
|
|
1152
|
+
}
|
|
1153
|
+
try {
|
|
1154
|
+
const parsed = new URL(configured);
|
|
1155
|
+
if (
|
|
1156
|
+
parsed.protocol !== "https:" ||
|
|
1157
|
+
parsed.hostname.length === 0 ||
|
|
1158
|
+
parsed.username.length > 0 ||
|
|
1159
|
+
parsed.password.length > 0 ||
|
|
1160
|
+
parsed.search.length > 0 ||
|
|
1161
|
+
parsed.hash.length > 0
|
|
1162
|
+
) {
|
|
1163
|
+
return GLM_ZCODE_ANTHROPIC_BASE_URL;
|
|
1164
|
+
}
|
|
1165
|
+
return normalizeAnthropicBaseUrl(parsed.toString()) ?? GLM_ZCODE_ANTHROPIC_BASE_URL;
|
|
1166
|
+
} catch {
|
|
1167
|
+
return GLM_ZCODE_ANTHROPIC_BASE_URL;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1147
1171
|
function resolveAnthropicBaseUrl(model: Model<"anthropic-messages">, apiKey?: string): string | undefined {
|
|
1148
1172
|
if (model.provider === "github-copilot") {
|
|
1149
1173
|
return normalizeAnthropicBaseUrl(resolveGitHubCopilotBaseUrl(model.baseUrl, apiKey) ?? model.baseUrl);
|
|
@@ -1152,9 +1176,7 @@ function resolveAnthropicBaseUrl(model: Model<"anthropic-messages">, apiKey?: st
|
|
|
1152
1176
|
// calls api.z.ai directly (no zcode.z.ai gateway, no captcha). Pin the base so dynamic
|
|
1153
1177
|
// discovery / stale bundled catalogs / model cache can't redirect it elsewhere.
|
|
1154
1178
|
if (model.provider === "glm-zcode") {
|
|
1155
|
-
return (
|
|
1156
|
-
normalizeAnthropicBaseUrl($credentialEnv("ZCODE_PLAN_ANTHROPIC_BASE_URL")) ?? "https://api.z.ai/api/anthropic"
|
|
1157
|
-
);
|
|
1179
|
+
return resolveGlmZcodeAnthropicBaseUrl();
|
|
1158
1180
|
}
|
|
1159
1181
|
if (model.provider === "anthropic" && isFoundryEnabled()) {
|
|
1160
1182
|
const foundryBaseUrl = normalizeAnthropicBaseUrl($credentialEnv("FOUNDRY_BASE_URL"));
|
|
@@ -2023,7 +2045,21 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2023
2045
|
const blocks = output.content as Block[];
|
|
2024
2046
|
const blocksByAnthropicIndex = new Map<number, Block>();
|
|
2025
2047
|
const truncatedToolCalls = new Set<ToolCall>();
|
|
2026
|
-
|
|
2048
|
+
// Bounded diagnostic for degraded primitive increments: at most one
|
|
2049
|
+
// warning per delta type per stream invocation, naming only the
|
|
2050
|
+
// envelope shape (delta type and received typeof) — never the payload.
|
|
2051
|
+
const degradedIncrementDiagnostics = new Set<string>();
|
|
2052
|
+
const noteDegradedIncrement = (deltaType: string, received: unknown): void => {
|
|
2053
|
+
if (degradedIncrementDiagnostics.has(deltaType)) return;
|
|
2054
|
+
degradedIncrementDiagnostics.add(deltaType);
|
|
2055
|
+
logger.warn("anthropic: degraded non-string stream increment to empty string", {
|
|
2056
|
+
model: model.id,
|
|
2057
|
+
provider: model.provider,
|
|
2058
|
+
deltaType,
|
|
2059
|
+
receivedType: received === null ? "null" : typeof received,
|
|
2060
|
+
});
|
|
2061
|
+
};
|
|
2062
|
+
|
|
2027
2063
|
// Derive from the ACTUAL request shape, not the option default: the request
|
|
2028
2064
|
// only sends `display: "summarized"` on specific paths (adaptive display is
|
|
2029
2065
|
// omitted for models where supportsAdaptiveThinkingDisplay is false). Defaulting
|
|
@@ -2037,25 +2073,18 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2037
2073
|
return { block, contentIndex: blocks.indexOf(block) };
|
|
2038
2074
|
};
|
|
2039
2075
|
const trackBlockByAnthropicIndex = (anthropicIndex: number, block: Block) => {
|
|
2040
|
-
// A duplicate start for an active index is a provider-envelope violation;
|
|
2041
|
-
// finalize the orphaned block so no internal stream fields leak into output.
|
|
2042
2076
|
const orphaned = blocksByAnthropicIndex.get(anthropicIndex);
|
|
2043
2077
|
if (orphaned) {
|
|
2044
2078
|
if (orphaned.type === "toolCall") {
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
if (findUnnecessaryUnicodeEscape(orphaned.partialJson)) {
|
|
2053
|
-
orphaned.escapedNonAsciiArguments = true;
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2079
|
+
orphaned.incompleteArguments = true;
|
|
2080
|
+
orphaned.incompleteArgumentsReason = "ambiguous";
|
|
2081
|
+
truncatedToolCalls.add(orphaned);
|
|
2082
|
+
}
|
|
2083
|
+
if (block.type === "toolCall") {
|
|
2084
|
+
block.incompleteArguments = true;
|
|
2085
|
+
block.incompleteArgumentsReason = "ambiguous";
|
|
2056
2086
|
}
|
|
2057
|
-
|
|
2058
|
-
delete (orphaned as { partialJson?: string }).partialJson;
|
|
2087
|
+
throw new Error("Anthropic stream reused an active content block index");
|
|
2059
2088
|
}
|
|
2060
2089
|
blocksByAnthropicIndex.set(anthropicIndex, block);
|
|
2061
2090
|
};
|
|
@@ -2070,7 +2099,6 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2070
2099
|
output.stopReason = "stop";
|
|
2071
2100
|
firstTokenTime = undefined;
|
|
2072
2101
|
truncatedToolCalls.clear();
|
|
2073
|
-
sawTerminalStopReason = false;
|
|
2074
2102
|
};
|
|
2075
2103
|
const idleTimeoutMs =
|
|
2076
2104
|
options?.streamIdleTimeoutMs ??
|
|
@@ -2105,7 +2133,6 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2105
2133
|
// Retries reset output.content; drop stale block correlations from the aborted attempt.
|
|
2106
2134
|
blocksByAnthropicIndex.clear();
|
|
2107
2135
|
truncatedToolCalls.clear();
|
|
2108
|
-
sawTerminalStopReason = false;
|
|
2109
2136
|
activeAbortTracker = createAbortSourceTracker(options?.signal);
|
|
2110
2137
|
let firstEventTimeoutAbortError: FirstEventTimeoutError | undefined;
|
|
2111
2138
|
const idleTimeoutAbortError = new Error("Anthropic stream stalled while waiting for the next event");
|
|
@@ -2253,13 +2280,21 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2253
2280
|
trackBlockByAnthropicIndex(event.index, block);
|
|
2254
2281
|
} else if (event.content_block.type === "tool_use") {
|
|
2255
2282
|
streamedReplayUnsafeContent = true;
|
|
2283
|
+
const initialArguments: unknown = event.content_block.input;
|
|
2284
|
+
if (
|
|
2285
|
+
initialArguments === null ||
|
|
2286
|
+
typeof initialArguments !== "object" ||
|
|
2287
|
+
Array.isArray(initialArguments)
|
|
2288
|
+
) {
|
|
2289
|
+
throw new Error("Anthropic tool_use started with non-object arguments");
|
|
2290
|
+
}
|
|
2256
2291
|
const block: Block = {
|
|
2257
2292
|
type: "toolCall",
|
|
2258
2293
|
id: event.content_block.id,
|
|
2259
2294
|
name: isOAuthToken
|
|
2260
2295
|
? stripClaudeToolPrefix(event.content_block.name)
|
|
2261
2296
|
: event.content_block.name,
|
|
2262
|
-
arguments:
|
|
2297
|
+
arguments: initialArguments as Record<string, unknown>,
|
|
2263
2298
|
partialJson: "",
|
|
2264
2299
|
index: event.index,
|
|
2265
2300
|
};
|
|
@@ -2275,32 +2310,42 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2275
2310
|
if (event.delta.type === "text_delta") {
|
|
2276
2311
|
const { block, contentIndex: index } = getBlockByAnthropicIndex(event.index);
|
|
2277
2312
|
if (block && block.type === "text") {
|
|
2278
|
-
|
|
2313
|
+
const rawTextDelta: unknown = event.delta.text;
|
|
2314
|
+
if (typeof rawTextDelta !== "string") {
|
|
2315
|
+
noteDegradedIncrement("text_delta", rawTextDelta);
|
|
2316
|
+
}
|
|
2317
|
+
const textDelta = typeof rawTextDelta === "string" ? rawTextDelta : "";
|
|
2318
|
+
block.text += textDelta;
|
|
2279
2319
|
stream.push({
|
|
2280
2320
|
type: "text_delta",
|
|
2281
2321
|
contentIndex: index,
|
|
2282
|
-
delta:
|
|
2322
|
+
delta: textDelta,
|
|
2283
2323
|
partial: output,
|
|
2284
2324
|
});
|
|
2285
2325
|
}
|
|
2286
2326
|
} else if (event.delta.type === "thinking_delta") {
|
|
2287
2327
|
const { block, contentIndex: index } = getBlockByAnthropicIndex(event.index);
|
|
2288
2328
|
if (block && block.type === "thinking") {
|
|
2289
|
-
|
|
2329
|
+
const rawThinkingDelta: unknown = event.delta.thinking;
|
|
2330
|
+
if (typeof rawThinkingDelta !== "string") {
|
|
2331
|
+
noteDegradedIncrement("thinking_delta", rawThinkingDelta);
|
|
2332
|
+
}
|
|
2333
|
+
const thinkingDelta = typeof rawThinkingDelta === "string" ? rawThinkingDelta : "";
|
|
2334
|
+
block.thinking += thinkingDelta;
|
|
2290
2335
|
if (summarizedThinking) {
|
|
2291
|
-
const summary = (reasoningBuffers.get(block) ?? "") +
|
|
2336
|
+
const summary = (reasoningBuffers.get(block) ?? "") + thinkingDelta;
|
|
2292
2337
|
reasoningBuffers.set(block, summary);
|
|
2293
2338
|
stream.push({
|
|
2294
2339
|
type: "reasoning_summary_delta",
|
|
2295
2340
|
contentIndex: index,
|
|
2296
|
-
delta:
|
|
2341
|
+
delta: thinkingDelta,
|
|
2297
2342
|
partial: output,
|
|
2298
2343
|
});
|
|
2299
2344
|
} else {
|
|
2300
2345
|
stream.push({
|
|
2301
2346
|
type: "thinking_delta",
|
|
2302
2347
|
contentIndex: index,
|
|
2303
|
-
delta:
|
|
2348
|
+
delta: thinkingDelta,
|
|
2304
2349
|
partial: output,
|
|
2305
2350
|
});
|
|
2306
2351
|
}
|
|
@@ -2308,12 +2353,26 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2308
2353
|
} else if (event.delta.type === "input_json_delta") {
|
|
2309
2354
|
const { block, contentIndex: index } = getBlockByAnthropicIndex(event.index);
|
|
2310
2355
|
if (block && block.type === "toolCall") {
|
|
2311
|
-
|
|
2356
|
+
const rawJsonDelta: unknown = event.delta.partial_json;
|
|
2357
|
+
if (typeof rawJsonDelta !== "string") {
|
|
2358
|
+
// Tool-argument fragments are positional JSON text: erasing or
|
|
2359
|
+
// coercing any malformed increment (primitive OR object/function)
|
|
2360
|
+
// assembles valid-but-wrong arguments — e.g. `{"n":1` + numeric
|
|
2361
|
+
// primitive erased to "" + `3}` parses as {"n":13} and executes.
|
|
2362
|
+
// Prose/thinking/signature anomalies are safe to degrade; tool
|
|
2363
|
+
// arguments fail the turn closed. The payload never enters the
|
|
2364
|
+
// error.
|
|
2365
|
+
throw new Error(
|
|
2366
|
+
"Anthropic stream sent a non-string input_json_delta tool-argument increment; failing the turn instead of assembling wrong tool arguments",
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
const jsonDelta = rawJsonDelta;
|
|
2370
|
+
block.partialJson += jsonDelta;
|
|
2312
2371
|
block.arguments = parseStreamingJson(block.partialJson);
|
|
2313
2372
|
stream.push({
|
|
2314
2373
|
type: "toolcall_delta",
|
|
2315
2374
|
contentIndex: index,
|
|
2316
|
-
delta:
|
|
2375
|
+
delta: jsonDelta,
|
|
2317
2376
|
partial: output,
|
|
2318
2377
|
});
|
|
2319
2378
|
}
|
|
@@ -2321,7 +2380,12 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2321
2380
|
const { block } = getBlockByAnthropicIndex(event.index);
|
|
2322
2381
|
if (block && block.type === "thinking") {
|
|
2323
2382
|
block.thinkingSignature = block.thinkingSignature || "";
|
|
2324
|
-
|
|
2383
|
+
const rawSignatureDelta: unknown = event.delta.signature;
|
|
2384
|
+
if (typeof rawSignatureDelta === "string") {
|
|
2385
|
+
block.thinkingSignature += rawSignatureDelta;
|
|
2386
|
+
} else {
|
|
2387
|
+
noteDegradedIncrement("signature_delta", rawSignatureDelta);
|
|
2388
|
+
}
|
|
2325
2389
|
}
|
|
2326
2390
|
}
|
|
2327
2391
|
} else if (event.type === "content_block_stop") {
|
|
@@ -2359,9 +2423,21 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2359
2423
|
partial: output,
|
|
2360
2424
|
});
|
|
2361
2425
|
} else if (block.type === "toolCall") {
|
|
2362
|
-
if (!isCompleteJson(block.partialJson))
|
|
2426
|
+
if (!isCompleteJson(block.partialJson)) {
|
|
2427
|
+
truncatedToolCalls.add(block);
|
|
2428
|
+
block.incompleteArguments = true;
|
|
2429
|
+
block.incompleteArgumentsReason = "truncated";
|
|
2430
|
+
}
|
|
2363
2431
|
if (block.partialJson.trim()) {
|
|
2364
|
-
|
|
2432
|
+
const parsedArguments: unknown = parseStreamingJson(block.partialJson);
|
|
2433
|
+
if (
|
|
2434
|
+
parsedArguments === null ||
|
|
2435
|
+
typeof parsedArguments !== "object" ||
|
|
2436
|
+
Array.isArray(parsedArguments)
|
|
2437
|
+
) {
|
|
2438
|
+
throw new Error("Anthropic tool_use completed with non-object arguments");
|
|
2439
|
+
}
|
|
2440
|
+
block.arguments = parsedArguments as Record<string, unknown>;
|
|
2365
2441
|
if (findUnnecessaryUnicodeEscape(block.partialJson)) {
|
|
2366
2442
|
block.escapedNonAsciiArguments = true;
|
|
2367
2443
|
}
|
|
@@ -2383,7 +2459,6 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2383
2459
|
if (rawStopReason) {
|
|
2384
2460
|
output.stopReason = isProviderSafetyStop ? "error" : mapStopReason(rawStopReason);
|
|
2385
2461
|
sawTerminalEnvelope = true;
|
|
2386
|
-
sawTerminalStopReason = true;
|
|
2387
2462
|
}
|
|
2388
2463
|
if (isProviderSafetyStop) {
|
|
2389
2464
|
sawProviderSafetyStop = true;
|
|
@@ -2852,6 +2927,8 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2852
2927
|
delete (block as { index?: number }).index;
|
|
2853
2928
|
if (block.type === "toolCall") {
|
|
2854
2929
|
truncatedToolCalls.add(block);
|
|
2930
|
+
block.incompleteArguments = true;
|
|
2931
|
+
block.incompleteArgumentsReason = "truncated";
|
|
2855
2932
|
if (block.partialJson.trim()) {
|
|
2856
2933
|
block.arguments = parseStreamingJson(block.partialJson);
|
|
2857
2934
|
if (findUnnecessaryUnicodeEscape(block.partialJson)) {
|
|
@@ -2862,12 +2939,10 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
2862
2939
|
}
|
|
2863
2940
|
}
|
|
2864
2941
|
blocksByAnthropicIndex.clear();
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
block.incompleteArgumentsReason = "truncated";
|
|
2870
|
-
}
|
|
2942
|
+
for (const block of output.content) {
|
|
2943
|
+
if (block.type === "toolCall" && truncatedToolCalls.has(block)) {
|
|
2944
|
+
block.incompleteArguments = true;
|
|
2945
|
+
block.incompleteArgumentsReason = "truncated";
|
|
2871
2946
|
}
|
|
2872
2947
|
}
|
|
2873
2948
|
output.duration = Date.now() - startTime;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import * as os from "node:os";
|
|
3
2
|
import * as path from "node:path";
|
|
4
|
-
import { $credentialEnv } from "@gajae-code/utils";
|
|
3
|
+
import { $credentialEnv, getTrustedHomeDir } from "@gajae-code/utils";
|
|
5
4
|
import type { AwsCredentials } from "./aws-sigv4";
|
|
6
5
|
|
|
7
6
|
export type AwsIniFile = Record<string, Record<string, string>>;
|
|
@@ -64,7 +63,7 @@ export function parseAwsIni(text: string): AwsIniFile {
|
|
|
64
63
|
|
|
65
64
|
export function resolveAwsCredentialSource(options: AwsCredentialSourceOptions = {}): AwsCredentialSource {
|
|
66
65
|
const profile = options.profile || $credentialEnv("AWS_PROFILE") || "default";
|
|
67
|
-
const home =
|
|
66
|
+
const home = getTrustedHomeDir();
|
|
68
67
|
return {
|
|
69
68
|
profile,
|
|
70
69
|
credentialsPath: path.resolve(
|
|
@@ -20,9 +20,8 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import * as fs from "node:fs";
|
|
23
|
-
import * as os from "node:os";
|
|
24
23
|
import * as path from "node:path";
|
|
25
|
-
import { $env, isEnoent, logger } from "@gajae-code/utils";
|
|
24
|
+
import { $env, getTrustedHomeDir, isEnoent, logger } from "@gajae-code/utils";
|
|
26
25
|
import {
|
|
27
26
|
type AwsIniFile,
|
|
28
27
|
classifyAwsProfileCapability,
|
|
@@ -201,7 +200,7 @@ async function loadSsoCachedToken(
|
|
|
201
200
|
startUrl: string,
|
|
202
201
|
sessionName: string | undefined,
|
|
203
202
|
): Promise<SsoCachedToken | undefined> {
|
|
204
|
-
const cacheDir = path.join(
|
|
203
|
+
const cacheDir = path.join(getTrustedHomeDir(), ".aws", "sso", "cache");
|
|
205
204
|
let entries: string[];
|
|
206
205
|
try {
|
|
207
206
|
entries = await fs.promises.readdir(cacheDir);
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
StreamOptions,
|
|
16
16
|
Tool,
|
|
17
17
|
ToolChoice,
|
|
18
|
+
ToolResultMessage,
|
|
18
19
|
} from "../types";
|
|
19
20
|
import { normalizeSystemPrompts } from "../utils";
|
|
20
21
|
import { createAbortSourceTracker } from "../utils/abort";
|
|
@@ -396,7 +397,23 @@ function convertMessages(
|
|
|
396
397
|
}
|
|
397
398
|
|
|
398
399
|
let msgIndex = 0;
|
|
400
|
+
// Consecutive tool results are batched into one append call so every output
|
|
401
|
+
// of the turn stays contiguous before the collected image user message;
|
|
402
|
+
// per-result image user messages interleave with sibling outputs and break
|
|
403
|
+
// tool_use→tool_result adjacency through Anthropic-translating proxies (#4807).
|
|
404
|
+
let pendingToolResults: ToolResultMessage[] = [];
|
|
405
|
+
const flushPendingToolResults = (): void => {
|
|
406
|
+
if (pendingToolResults.length === 0) return;
|
|
407
|
+
appendResponsesToolResultMessages(messages, pendingToolResults, model, strictResponsesPairing, knownCallIds);
|
|
408
|
+
pendingToolResults = [];
|
|
409
|
+
};
|
|
399
410
|
for (const msg of transformedMessages) {
|
|
411
|
+
if (msg.role === "toolResult") {
|
|
412
|
+
pendingToolResults.push(msg);
|
|
413
|
+
msgIndex++;
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
flushPendingToolResults();
|
|
400
417
|
if (msg.role === "user" || msg.role === "developer") {
|
|
401
418
|
const content = convertResponsesInputContent(msg.content, model.input.includes("image"));
|
|
402
419
|
if (!content) continue;
|
|
@@ -408,11 +425,10 @@ function convertMessages(
|
|
|
408
425
|
const outputItems = convertResponsesAssistantMessage(msg as AssistantMessage, model, msgIndex, knownCallIds);
|
|
409
426
|
if (outputItems.length === 0) continue;
|
|
410
427
|
messages.push(...outputItems);
|
|
411
|
-
} else if (msg.role === "toolResult") {
|
|
412
|
-
appendResponsesToolResultMessages(messages, msg, model, strictResponsesPairing, knownCallIds);
|
|
413
428
|
}
|
|
414
429
|
msgIndex++;
|
|
415
430
|
}
|
|
431
|
+
flushPendingToolResults();
|
|
416
432
|
|
|
417
433
|
return messages;
|
|
418
434
|
}
|