@atlasharness/atlascode 0.1.57 → 0.1.58
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/dist/cli.js +183 -78
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -26920,6 +26920,63 @@ function gatewayUnreachableRemediationHint(error) {
|
|
|
26920
26920
|
return null;
|
|
26921
26921
|
return "IFF 不可达:已切人工确认 —— /doctor 排查";
|
|
26922
26922
|
}
|
|
26923
|
+
function modelRetryBackoffMs(attempt, baseMs = MODEL_RETRY_BACKOFF_BASE_MS, capMs = MODEL_RETRY_BACKOFF_CAP_MS) {
|
|
26924
|
+
const base = Math.max(0, baseMs);
|
|
26925
|
+
const cap = Math.max(base, capMs);
|
|
26926
|
+
if (attempt <= 0)
|
|
26927
|
+
return Math.min(base, cap);
|
|
26928
|
+
return Math.min(base * 2 ** attempt, cap);
|
|
26929
|
+
}
|
|
26930
|
+
function sleepSignalAware(ms, signal) {
|
|
26931
|
+
if (ms <= 0)
|
|
26932
|
+
return Promise.resolve();
|
|
26933
|
+
return new Promise((resolve) => {
|
|
26934
|
+
if (signal?.aborted) {
|
|
26935
|
+
resolve();
|
|
26936
|
+
return;
|
|
26937
|
+
}
|
|
26938
|
+
let settled = false;
|
|
26939
|
+
const timer = setTimeout(() => {
|
|
26940
|
+
settled = true;
|
|
26941
|
+
if (signal)
|
|
26942
|
+
signal.removeEventListener("abort", onAbort);
|
|
26943
|
+
resolve();
|
|
26944
|
+
}, ms);
|
|
26945
|
+
function onAbort() {
|
|
26946
|
+
if (settled)
|
|
26947
|
+
return;
|
|
26948
|
+
settled = true;
|
|
26949
|
+
clearTimeout(timer);
|
|
26950
|
+
resolve();
|
|
26951
|
+
}
|
|
26952
|
+
if (signal)
|
|
26953
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
26954
|
+
});
|
|
26955
|
+
}
|
|
26956
|
+
function buildStreamErrorEvent(err, signal) {
|
|
26957
|
+
const message = err instanceof Error ? err.message || err.name : String(err);
|
|
26958
|
+
const code = isClientRequestTimeout(err) ? "TIMEOUT" : "API_ERROR";
|
|
26959
|
+
return { type: "error", code, message, retryable: shouldRetryModelError(err, signal) };
|
|
26960
|
+
}
|
|
26961
|
+
function buildStreamContentBlocks(reasoningText, fullText, toolCalls) {
|
|
26962
|
+
const blocks = [];
|
|
26963
|
+
if (reasoningText)
|
|
26964
|
+
blocks.push({ type: "thinking", thinking: reasoningText, signature: "first-party" });
|
|
26965
|
+
if (fullText)
|
|
26966
|
+
blocks.push({ type: "text", text: fullText });
|
|
26967
|
+
blocks.push(...[...toolCalls.values()].filter((t) => t.name).map((t) => {
|
|
26968
|
+
let input = {};
|
|
26969
|
+
if (t.args) {
|
|
26970
|
+
try {
|
|
26971
|
+
input = JSON.parse(t.args);
|
|
26972
|
+
} catch {
|
|
26973
|
+
input = { _raw_arguments: t.args };
|
|
26974
|
+
}
|
|
26975
|
+
}
|
|
26976
|
+
return { type: "tool_use", id: t.id || `toolu_${randomUUID()}`, name: t.name, input };
|
|
26977
|
+
}));
|
|
26978
|
+
return blocks;
|
|
26979
|
+
}
|
|
26923
26980
|
function startLlmWaitHeartbeat(modelId, attempt, totalRetries) {
|
|
26924
26981
|
const startedAt = Date.now();
|
|
26925
26982
|
const id = setInterval(() => {
|
|
@@ -26934,10 +26991,16 @@ class OpenAIProvider {
|
|
|
26934
26991
|
maxRetriesPerModel;
|
|
26935
26992
|
timeoutMs;
|
|
26936
26993
|
timeoutResolver;
|
|
26937
|
-
|
|
26994
|
+
retryBackoffBaseMs;
|
|
26995
|
+
retryBackoffCapMs;
|
|
26996
|
+
retryBackoffSleep;
|
|
26997
|
+
constructor(maxRetriesPerModel = 3, timeoutMs = LLM_TIMEOUT_DEFAULT_MS, timeoutResolver, retryBackoff) {
|
|
26938
26998
|
this.maxRetriesPerModel = maxRetriesPerModel;
|
|
26939
26999
|
this.timeoutMs = timeoutMs;
|
|
26940
27000
|
this.timeoutResolver = timeoutResolver;
|
|
27001
|
+
this.retryBackoffBaseMs = retryBackoff?.baseMs ?? MODEL_RETRY_BACKOFF_BASE_MS;
|
|
27002
|
+
this.retryBackoffCapMs = retryBackoff?.capMs ?? MODEL_RETRY_BACKOFF_CAP_MS;
|
|
27003
|
+
this.retryBackoffSleep = retryBackoff?.sleep ?? ((ms, signal) => sleepSignalAware(ms, signal));
|
|
26941
27004
|
}
|
|
26942
27005
|
getTimeoutMs() {
|
|
26943
27006
|
return this.timeoutResolver ? this.timeoutResolver() : this.timeoutMs;
|
|
@@ -27030,6 +27093,9 @@ class OpenAIProvider {
|
|
|
27030
27093
|
lastErr = err;
|
|
27031
27094
|
if (!shouldRetryModelError(err, args.signal))
|
|
27032
27095
|
break;
|
|
27096
|
+
if (attempt < this.maxRetriesPerModel - 1) {
|
|
27097
|
+
await this.retryBackoffSleep(modelRetryBackoffMs(attempt, this.retryBackoffBaseMs, this.retryBackoffCapMs), args.signal);
|
|
27098
|
+
}
|
|
27033
27099
|
}
|
|
27034
27100
|
}
|
|
27035
27101
|
}
|
|
@@ -27045,6 +27111,7 @@ class OpenAIProvider {
|
|
|
27045
27111
|
const attemptRefs = refs;
|
|
27046
27112
|
let lastErr = null;
|
|
27047
27113
|
let succeeded = false;
|
|
27114
|
+
let partialRetained = false;
|
|
27048
27115
|
for (const ref of attemptRefs) {
|
|
27049
27116
|
const entry = resolveModel(ref);
|
|
27050
27117
|
if (!entry) {
|
|
@@ -27073,22 +27140,27 @@ class OpenAIProvider {
|
|
|
27073
27140
|
if (args.signal?.aborted)
|
|
27074
27141
|
return;
|
|
27075
27142
|
try {
|
|
27076
|
-
yield* this.streamOneAttempt(client, params, entry, args.signal, attempt, this.maxRetriesPerModel);
|
|
27143
|
+
const outcome = yield* this.streamOneAttempt(client, params, entry, args.signal, attempt, this.maxRetriesPerModel);
|
|
27144
|
+
if (outcome.partialRetained) {
|
|
27145
|
+
partialRetained = true;
|
|
27146
|
+
break;
|
|
27147
|
+
}
|
|
27077
27148
|
succeeded = true;
|
|
27078
27149
|
break;
|
|
27079
27150
|
} catch (err) {
|
|
27080
27151
|
lastErr = err;
|
|
27081
27152
|
if (!shouldRetryModelError(err, args.signal))
|
|
27082
27153
|
break;
|
|
27154
|
+
if (attempt < this.maxRetriesPerModel - 1) {
|
|
27155
|
+
await this.retryBackoffSleep(modelRetryBackoffMs(attempt, this.retryBackoffBaseMs, this.retryBackoffCapMs), args.signal);
|
|
27156
|
+
}
|
|
27083
27157
|
}
|
|
27084
27158
|
}
|
|
27085
|
-
if (succeeded || args.signal?.aborted)
|
|
27159
|
+
if (succeeded || partialRetained || args.signal?.aborted)
|
|
27086
27160
|
return;
|
|
27087
27161
|
}
|
|
27088
27162
|
if (lastErr) {
|
|
27089
|
-
|
|
27090
|
-
const code = isClientRequestTimeout(lastErr) ? "TIMEOUT" : "API_ERROR";
|
|
27091
|
-
yield { type: "error", code, message, retryable: shouldRetryModelError(lastErr, args.signal) };
|
|
27163
|
+
yield buildStreamErrorEvent(lastErr, args.signal);
|
|
27092
27164
|
return;
|
|
27093
27165
|
}
|
|
27094
27166
|
throw new Error(`No models configured for role '${args.role}'.`);
|
|
@@ -27107,66 +27179,111 @@ class OpenAIProvider {
|
|
|
27107
27179
|
const toolCalls = new Map;
|
|
27108
27180
|
let finishReason = null;
|
|
27109
27181
|
let usage = null;
|
|
27110
|
-
|
|
27111
|
-
|
|
27112
|
-
const
|
|
27113
|
-
|
|
27114
|
-
|
|
27115
|
-
|
|
27116
|
-
|
|
27117
|
-
|
|
27118
|
-
|
|
27119
|
-
|
|
27120
|
-
|
|
27121
|
-
|
|
27122
|
-
const
|
|
27123
|
-
|
|
27124
|
-
cur
|
|
27125
|
-
|
|
27126
|
-
|
|
27127
|
-
if (
|
|
27128
|
-
|
|
27129
|
-
if (currentToolCall
|
|
27130
|
-
|
|
27131
|
-
|
|
27132
|
-
|
|
27133
|
-
|
|
27182
|
+
let streamError = null;
|
|
27183
|
+
try {
|
|
27184
|
+
for await (const chunk of stream) {
|
|
27185
|
+
const choice = chunk.choices?.[0];
|
|
27186
|
+
const delta = choice?.delta;
|
|
27187
|
+
if (delta?.content) {
|
|
27188
|
+
fullText += delta.content;
|
|
27189
|
+
yield { type: "text_delta", text: delta.content };
|
|
27190
|
+
}
|
|
27191
|
+
if (delta?.reasoning_content)
|
|
27192
|
+
reasoningText += delta.reasoning_content;
|
|
27193
|
+
if (delta?.tool_calls) {
|
|
27194
|
+
for (const tc of delta.tool_calls) {
|
|
27195
|
+
const idx = tc.index ?? 0;
|
|
27196
|
+
const cur = toolCalls.get(idx) ?? { id: "", name: "", args: "" };
|
|
27197
|
+
if (tc.id)
|
|
27198
|
+
cur.id = tc.id;
|
|
27199
|
+
if (tc.function?.name) {
|
|
27200
|
+
cur.name = tc.function.name;
|
|
27201
|
+
if (currentToolCall) {
|
|
27202
|
+
let input = {};
|
|
27203
|
+
if (currentToolCall.args) {
|
|
27204
|
+
try {
|
|
27205
|
+
input = JSON.parse(currentToolCall.args);
|
|
27206
|
+
} catch {
|
|
27207
|
+
input = { _raw_arguments: currentToolCall.args };
|
|
27208
|
+
}
|
|
27134
27209
|
}
|
|
27210
|
+
yield { type: "tool_use_end", id: currentToolCall.id, name: currentToolCall.name, input };
|
|
27135
27211
|
}
|
|
27136
|
-
|
|
27212
|
+
currentToolCall = { id: cur.id, name: cur.name, args: cur.args };
|
|
27213
|
+
yield { type: "tool_use_start", id: cur.id, name: cur.name };
|
|
27137
27214
|
}
|
|
27138
|
-
|
|
27139
|
-
|
|
27140
|
-
|
|
27141
|
-
|
|
27142
|
-
|
|
27143
|
-
|
|
27144
|
-
currentToolCall.args = cur.args;
|
|
27145
|
-
yield { type: "tool_use_delta", id: cur.id, inputJsonDelta: tc.function.arguments };
|
|
27215
|
+
if (tc.function?.arguments) {
|
|
27216
|
+
cur.args += tc.function.arguments;
|
|
27217
|
+
if (currentToolCall && cur.name) {
|
|
27218
|
+
currentToolCall.args = cur.args;
|
|
27219
|
+
yield { type: "tool_use_delta", id: cur.id, inputJsonDelta: tc.function.arguments };
|
|
27220
|
+
}
|
|
27146
27221
|
}
|
|
27222
|
+
toolCalls.set(idx, cur);
|
|
27147
27223
|
}
|
|
27148
|
-
toolCalls.set(idx, cur);
|
|
27149
27224
|
}
|
|
27150
|
-
|
|
27151
|
-
|
|
27152
|
-
|
|
27153
|
-
|
|
27154
|
-
|
|
27155
|
-
|
|
27156
|
-
|
|
27157
|
-
|
|
27158
|
-
|
|
27225
|
+
if (choice?.finish_reason) {
|
|
27226
|
+
if (currentToolCall) {
|
|
27227
|
+
let input = {};
|
|
27228
|
+
if (currentToolCall.args) {
|
|
27229
|
+
try {
|
|
27230
|
+
input = JSON.parse(currentToolCall.args);
|
|
27231
|
+
} catch {
|
|
27232
|
+
input = { _raw_arguments: currentToolCall.args };
|
|
27233
|
+
}
|
|
27159
27234
|
}
|
|
27235
|
+
yield { type: "tool_use_end", id: currentToolCall.id, name: currentToolCall.name, input };
|
|
27236
|
+
currentToolCall = null;
|
|
27160
27237
|
}
|
|
27161
|
-
|
|
27162
|
-
currentToolCall = null;
|
|
27238
|
+
finishReason = choice.finish_reason;
|
|
27163
27239
|
}
|
|
27164
|
-
|
|
27240
|
+
if (chunk.usage)
|
|
27241
|
+
usage = mapOpenAIUsage(chunk.usage);
|
|
27242
|
+
if (signal?.aborted)
|
|
27243
|
+
break;
|
|
27165
27244
|
}
|
|
27166
|
-
|
|
27167
|
-
|
|
27168
|
-
|
|
27169
|
-
|
|
27245
|
+
} catch (err) {
|
|
27246
|
+
streamError = err;
|
|
27247
|
+
}
|
|
27248
|
+
if (streamError !== null) {
|
|
27249
|
+
const partialBlocks = buildStreamContentBlocks(reasoningText, fullText, toolCalls);
|
|
27250
|
+
if (partialBlocks.length === 0)
|
|
27251
|
+
throw streamError;
|
|
27252
|
+
yield {
|
|
27253
|
+
type: "message_stop",
|
|
27254
|
+
stopReason: "interrupted",
|
|
27255
|
+
usage: usage ? {
|
|
27256
|
+
input_tokens: usage.input_tokens ?? 0,
|
|
27257
|
+
output_tokens: usage.output_tokens ?? 0,
|
|
27258
|
+
cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
|
|
27259
|
+
cache_read_input_tokens: usage.cache_read_input_tokens ?? 0
|
|
27260
|
+
} : undefined
|
|
27261
|
+
};
|
|
27262
|
+
const emptyUsage = mapOpenAIUsage(null);
|
|
27263
|
+
const partialMsg = {
|
|
27264
|
+
uuid: randomUUID(),
|
|
27265
|
+
timestamp: new Date().toISOString(),
|
|
27266
|
+
message: {
|
|
27267
|
+
id: randomUUID(),
|
|
27268
|
+
container: null,
|
|
27269
|
+
model: entry.modelId,
|
|
27270
|
+
role: "assistant",
|
|
27271
|
+
stop_reason: "interrupted",
|
|
27272
|
+
stop_sequence: "",
|
|
27273
|
+
type: "message",
|
|
27274
|
+
usage: usage || emptyUsage,
|
|
27275
|
+
content: partialBlocks
|
|
27276
|
+
}
|
|
27277
|
+
};
|
|
27278
|
+
yield {
|
|
27279
|
+
type: "assistant",
|
|
27280
|
+
uuid: partialMsg.uuid,
|
|
27281
|
+
timestamp: partialMsg.timestamp,
|
|
27282
|
+
message: partialMsg.message,
|
|
27283
|
+
interrupted: true
|
|
27284
|
+
};
|
|
27285
|
+
yield buildStreamErrorEvent(streamError, signal);
|
|
27286
|
+
return { partialRetained: true };
|
|
27170
27287
|
}
|
|
27171
27288
|
yield {
|
|
27172
27289
|
type: "message_stop",
|
|
@@ -27178,27 +27295,11 @@ class OpenAIProvider {
|
|
|
27178
27295
|
cache_read_input_tokens: usage.cache_read_input_tokens ?? 0
|
|
27179
27296
|
} : undefined
|
|
27180
27297
|
};
|
|
27181
|
-
const contentBlocks =
|
|
27182
|
-
if (reasoningText)
|
|
27183
|
-
contentBlocks.push({ type: "thinking", thinking: reasoningText, signature: "first-party" });
|
|
27184
|
-
if (fullText)
|
|
27185
|
-
contentBlocks.push({ type: "text", text: fullText });
|
|
27186
|
-
const toolUseBlocks = [...toolCalls.values()].filter((t) => t.name).map((t) => {
|
|
27187
|
-
let input = {};
|
|
27188
|
-
if (t.args) {
|
|
27189
|
-
try {
|
|
27190
|
-
input = JSON.parse(t.args);
|
|
27191
|
-
} catch {
|
|
27192
|
-
input = { _raw_arguments: t.args };
|
|
27193
|
-
}
|
|
27194
|
-
}
|
|
27195
|
-
return { type: "tool_use", id: t.id || `toolu_${randomUUID()}`, name: t.name, input };
|
|
27196
|
-
});
|
|
27197
|
-
contentBlocks.push(...toolUseBlocks);
|
|
27298
|
+
const contentBlocks = buildStreamContentBlocks(reasoningText, fullText, toolCalls);
|
|
27198
27299
|
if (contentBlocks.length === 0) {
|
|
27199
27300
|
contentBlocks.push({ type: "text", text: PROVIDER_EMPTY_CONTENT_PLACEHOLDER });
|
|
27200
27301
|
}
|
|
27201
|
-
const stopReason =
|
|
27302
|
+
const stopReason = contentBlocks.some((b) => b.type === "tool_use") ? "tool_use" : finishReason === "length" ? "max_tokens" : "end_turn";
|
|
27202
27303
|
const emptyUsage = mapOpenAIUsage(null);
|
|
27203
27304
|
const finalMsg = {
|
|
27204
27305
|
uuid: randomUUID(),
|
|
@@ -27216,6 +27317,7 @@ class OpenAIProvider {
|
|
|
27216
27317
|
}
|
|
27217
27318
|
};
|
|
27218
27319
|
yield { type: "assistant", uuid: finalMsg.uuid, timestamp: finalMsg.timestamp, message: finalMsg.message };
|
|
27320
|
+
return { partialRetained: false };
|
|
27219
27321
|
}
|
|
27220
27322
|
async healthCheck(role) {
|
|
27221
27323
|
const refs = getRoleModels(role);
|
|
@@ -27332,7 +27434,7 @@ class OpenAIProvider {
|
|
|
27332
27434
|
}
|
|
27333
27435
|
}
|
|
27334
27436
|
}
|
|
27335
|
-
var PROVIDER_EMPTY_CONTENT_PLACEHOLDER = "(provider: empty response)";
|
|
27437
|
+
var PROVIDER_EMPTY_CONTENT_PLACEHOLDER = "(provider: empty response)", MODEL_RETRY_BACKOFF_BASE_MS = 500, MODEL_RETRY_BACKOFF_CAP_MS = 8000;
|
|
27336
27438
|
var init_modelprovider = __esm(() => {
|
|
27337
27439
|
init_openai();
|
|
27338
27440
|
init_clients();
|
|
@@ -27786,7 +27888,7 @@ function turnRecoveryBackoffMs(attempt, baseMs, capMs) {
|
|
|
27786
27888
|
return Math.min(base, cap);
|
|
27787
27889
|
return Math.min(base * 2 ** attempt, cap);
|
|
27788
27890
|
}
|
|
27789
|
-
function
|
|
27891
|
+
function sleepSignalAware2(ms, signal) {
|
|
27790
27892
|
if (ms <= 0)
|
|
27791
27893
|
return Promise.resolve();
|
|
27792
27894
|
return new Promise((resolve) => {
|
|
@@ -27829,7 +27931,7 @@ async function withTurnRecovery(attempt, options = {}) {
|
|
|
27829
27931
|
if (i < cfg.maxRetries && shouldRetryModelError(err, options.signal)) {
|
|
27830
27932
|
const backoff = turnRecoveryBackoffMs(i, cfg.backoffBaseMs, cfg.backoffCapMs);
|
|
27831
27933
|
if (backoff > 0) {
|
|
27832
|
-
await
|
|
27934
|
+
await sleepSignalAware2(backoff, options.signal);
|
|
27833
27935
|
}
|
|
27834
27936
|
continue;
|
|
27835
27937
|
}
|
|
@@ -430373,7 +430475,10 @@ async function streamCompactSummary({
|
|
|
430373
430475
|
context.setResponseLength?.((length) => length + deltaEvent.text.length);
|
|
430374
430476
|
}
|
|
430375
430477
|
if (event.type === "assistant") {
|
|
430376
|
-
|
|
430478
|
+
const assistantEvent = event;
|
|
430479
|
+
if (!assistantEvent.interrupted) {
|
|
430480
|
+
response = assistantEvent;
|
|
430481
|
+
}
|
|
430377
430482
|
}
|
|
430378
430483
|
}
|
|
430379
430484
|
if (response) {
|
package/package.json
CHANGED