newmark-agent 0.4.8 → 0.5.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/dist/conversation-utility-host.bundle.cjs +238 -29
- package/dist/core/agent.d.ts +1 -0
- package/dist/core/agent.js +102 -10
- package/dist/core/agentKernelRunner.js +1 -1
- package/dist/core/autoRouter.d.ts +1 -1
- package/dist/core/autoRouter.js +16 -7
- package/dist/core/conversationKernel.d.ts +13 -8
- package/dist/core/conversationKernel.js +111 -10
- package/dist/core/electronUtilityAgentClient.d.ts +2 -8
- package/dist/core/electronUtilityRuntimePool.d.ts +3 -15
- package/dist/core/utilityAgentProtocol.d.ts +2 -8
- package/dist/core/workEventCoalescer.d.ts +16 -0
- package/dist/core/workEventCoalescer.js +52 -0
- package/dist/core/wslAgentClient.d.ts +2 -8
- package/dist/core/wslAgentProtocol.d.ts +2 -8
- package/dist/core/wslAgentRuntimePool.d.ts +3 -15
- package/dist/llm/provider.d.ts +5 -0
- package/dist/llm/provider.js +63 -1
- package/dist/main.js +221 -175
- package/dist/preload.js +2 -0
- package/dist/server.d.ts +17 -1
- package/dist/server.js +331 -9
- package/dist/ui/index.html +295 -51
- package/dist/wsl-agent-host.bundle.cjs +238 -29
- package/package.json +10 -5
|
@@ -329452,6 +329452,7 @@ var LLMProvider = class _LLMProvider {
|
|
|
329452
329452
|
thinkingTierMaps;
|
|
329453
329453
|
static nodeHttpTransport = null;
|
|
329454
329454
|
static powershellTransport = null;
|
|
329455
|
+
temperatureUnsupported = /* @__PURE__ */ new Set();
|
|
329455
329456
|
effectiveRequestTimeout(timeoutMs) {
|
|
329456
329457
|
const requested = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
|
|
329457
329458
|
const configured = Number.isFinite(this.requestTimeoutMs) && this.requestTimeoutMs > 0 ? this.requestTimeoutMs : DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
|
|
@@ -329593,7 +329594,46 @@ var LLMProvider = class _LLMProvider {
|
|
|
329593
329594
|
"X-GitHub-Api-Version": "2022-11-28"
|
|
329594
329595
|
};
|
|
329595
329596
|
}
|
|
329597
|
+
temperatureCapabilityKey(url, body) {
|
|
329598
|
+
return `${url}|${String(body.model || "")}`;
|
|
329599
|
+
}
|
|
329600
|
+
unsupportedTemperatureError(status, raw) {
|
|
329601
|
+
if (status !== 400) return false;
|
|
329602
|
+
try {
|
|
329603
|
+
const parsed = JSON.parse(String(raw || ""));
|
|
329604
|
+
if (String(parsed?.error?.param || "").toLowerCase() === "temperature") return true;
|
|
329605
|
+
return /unsupported parameter[^\n]*temperature|temperature[^\n]*not supported/i.test(String(parsed?.error?.message || ""));
|
|
329606
|
+
} catch {
|
|
329607
|
+
return /unsupported parameter[^\n]*temperature|temperature[^\n]*not supported/i.test(String(raw || ""));
|
|
329608
|
+
}
|
|
329609
|
+
}
|
|
329610
|
+
requestBodyForTemperatureCapability(url, body) {
|
|
329611
|
+
const prepared = { ...body };
|
|
329612
|
+
if (this.temperatureUnsupported.has(this.temperatureCapabilityKey(url, body))) delete prepared.temperature;
|
|
329613
|
+
return prepared;
|
|
329614
|
+
}
|
|
329596
329615
|
async postJsonWithFetchFallback(url, headers, body, timeoutMs = 12e4, signal) {
|
|
329616
|
+
const prepared = this.requestBodyForTemperatureCapability(url, body);
|
|
329617
|
+
const response = await this.postJsonOnce(url, headers, prepared, timeoutMs, signal);
|
|
329618
|
+
if (prepared.temperature === void 0 || response.status !== 400) return response;
|
|
329619
|
+
const cloneable = typeof response.clone === "function";
|
|
329620
|
+
const errorText = await (cloneable ? response.clone() : response).text();
|
|
329621
|
+
if (!this.unsupportedTemperatureError(response.status, errorText)) {
|
|
329622
|
+
if (cloneable) return response;
|
|
329623
|
+
return {
|
|
329624
|
+
ok: response.ok,
|
|
329625
|
+
status: response.status,
|
|
329626
|
+
headers: response.headers,
|
|
329627
|
+
text: async () => errorText,
|
|
329628
|
+
json: async () => JSON.parse(errorText || "{}")
|
|
329629
|
+
};
|
|
329630
|
+
}
|
|
329631
|
+
this.temperatureUnsupported.add(this.temperatureCapabilityKey(url, body));
|
|
329632
|
+
const retryBody = { ...body };
|
|
329633
|
+
delete retryBody.temperature;
|
|
329634
|
+
return this.postJsonOnce(url, headers, retryBody, timeoutMs, signal);
|
|
329635
|
+
}
|
|
329636
|
+
async postJsonOnce(url, headers, body, timeoutMs = 12e4, signal) {
|
|
329597
329637
|
const effectiveTimeout = this.effectiveRequestTimeout(timeoutMs);
|
|
329598
329638
|
if (this.isPlainHttpLoopback(url)) {
|
|
329599
329639
|
const pathname = (() => {
|
|
@@ -330262,6 +330302,7 @@ ${responsePath}
|
|
|
330262
330302
|
*/
|
|
330263
330303
|
buildProviderAdapterTransport() {
|
|
330264
330304
|
return async (request, signal) => {
|
|
330305
|
+
request.body = this.requestBodyForTemperatureCapability(request.url, request.body);
|
|
330265
330306
|
if (request.body?.stream === true) {
|
|
330266
330307
|
const abort = new AbortController();
|
|
330267
330308
|
const forwardAbort = () => abort.abort(signal?.reason);
|
|
@@ -330271,12 +330312,27 @@ ${responsePath}
|
|
|
330271
330312
|
const timer = setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout);
|
|
330272
330313
|
try {
|
|
330273
330314
|
try {
|
|
330274
|
-
|
|
330315
|
+
let response2 = await fetch(request.url, {
|
|
330275
330316
|
method: "POST",
|
|
330276
330317
|
headers: request.headers,
|
|
330277
330318
|
body: JSON.stringify(request.body),
|
|
330278
330319
|
signal: abort.signal
|
|
330279
330320
|
});
|
|
330321
|
+
if (request.body.temperature !== void 0 && response2.status === 400) {
|
|
330322
|
+
const errorText = await response2.clone().text();
|
|
330323
|
+
if (this.unsupportedTemperatureError(response2.status, errorText)) {
|
|
330324
|
+
this.temperatureUnsupported.add(this.temperatureCapabilityKey(request.url, request.body));
|
|
330325
|
+
const retryBody = { ...request.body };
|
|
330326
|
+
delete retryBody.temperature;
|
|
330327
|
+
response2 = await fetch(request.url, {
|
|
330328
|
+
method: "POST",
|
|
330329
|
+
headers: request.headers,
|
|
330330
|
+
body: JSON.stringify(retryBody),
|
|
330331
|
+
signal: abort.signal
|
|
330332
|
+
});
|
|
330333
|
+
}
|
|
330334
|
+
}
|
|
330335
|
+
return response2;
|
|
330280
330336
|
} catch (error) {
|
|
330281
330337
|
if (signal?.aborted) throw abortFailure(signal);
|
|
330282
330338
|
if (abort.signal.aborted) throw abortFailure(abort.signal);
|
|
@@ -340983,7 +341039,7 @@ async function runAgentKernel(agent) {
|
|
|
340983
341039
|
return;
|
|
340984
341040
|
}
|
|
340985
341041
|
const publicError = normalizePublicProviderError(error, [currentAgent.activeModelConfig()?.api_key]);
|
|
340986
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
341042
|
+
if (/\b402\b|insufficient balance|insufficient funds|payment required|insufficient[_ -]?quota|quota (?:exceeded|exhausted)|credit(?:s| balance)? (?:exhausted|depleted)|billing hard limit|budget exhausted|余额不足|额度不足|配额(?:不足|耗尽|超限)/i.test(publicError)) {
|
|
340987
341043
|
currentAgent.noteProviderBalanceFailure();
|
|
340988
341044
|
}
|
|
340989
341045
|
const final = assistantMessage2(model, [{ type: "text", text: `[Error] ${publicError}` }], "error");
|
|
@@ -343051,8 +343107,8 @@ function classifyRouteFailure(error) {
|
|
|
343051
343107
|
if (statusCode === 400 || /bad request|invalid parameter|invalid request/i.test(text)) {
|
|
343052
343108
|
return { type: "invalid_request", retryable: false, switchAllowed: false, statusCode };
|
|
343053
343109
|
}
|
|
343054
|
-
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required
|
|
343055
|
-
return { type: "balance_exhausted", retryable: false, switchAllowed:
|
|
343110
|
+
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required|insufficient[_ -]?quota|quota (?:exceeded|exhausted)|credit(?:s| balance)? (?:exhausted|depleted)|billing hard limit|budget exhausted|余额不足|额度不足|配额(?:不足|耗尽|超限)/i.test(text)) {
|
|
343111
|
+
return { type: "balance_exhausted", retryable: false, switchAllowed: true, statusCode: statusCode || 402 };
|
|
343056
343112
|
}
|
|
343057
343113
|
if (statusCode === 429 || /rate limit|too many requests/i.test(text)) {
|
|
343058
343114
|
return { type: "rate_limited", retryable: true, switchAllowed: true, statusCode: 429, retryAfterMs };
|
|
@@ -343190,13 +343246,13 @@ var AutoRouter = class {
|
|
|
343190
343246
|
}
|
|
343191
343247
|
planAttempts(decision, candidates, failure) {
|
|
343192
343248
|
const current = decision.resolvedDeployment;
|
|
343193
|
-
if (!current || !failure.error.
|
|
343249
|
+
if (!current || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
|
|
343194
343250
|
const remainingAttempts = Math.max(0, 3 - decision.attempts.length);
|
|
343195
343251
|
if (!remainingAttempts) return [];
|
|
343196
343252
|
const attempts = [];
|
|
343197
343253
|
const retryDelayMs = failure.error.retryAfterMs ?? 250;
|
|
343198
343254
|
const alreadyRetriedCurrent = decision.attempts.some((attempt) => attempt.kind === "retry_same_deployment" && sameDeployment(attempt.deployment, current));
|
|
343199
|
-
if (!alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343255
|
+
if (failure.error.retryable && !alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343200
343256
|
attempts.push({
|
|
343201
343257
|
deployment: { ...current },
|
|
343202
343258
|
kind: "retry_same_deployment",
|
|
@@ -343217,11 +343273,16 @@ var AutoRouter = class {
|
|
|
343217
343273
|
const eligible = candidates.filter((candidate) => candidate.enabled && inScope(candidate.deployment, scope) && inSubset(candidate.deployment, subset) && !sameDeployment(candidate.deployment, current) && !attemptedDeployments.some((attempted) => sameDeployment(candidate.deployment, attempted)) && validationEligible(candidate, now2).length === 0 && this.passedInitialHardFilters(decision, candidate) && this.circuitState(candidate.deployment, now2, false) !== "open");
|
|
343218
343274
|
const equivalent = currentGroup ? eligible.find((candidate) => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly) : void 0;
|
|
343219
343275
|
const fallback = eligible.find((candidate) => candidate.fallbackOnly);
|
|
343220
|
-
|
|
343276
|
+
const rankedAlternates = decision.rankedCandidates.map((ranked) => eligible.find((candidate) => sameDeployment(candidate.deployment, ranked.deployment))).filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
|
|
343277
|
+
for (const candidate of eligible) {
|
|
343278
|
+
if (candidate === equivalent || candidate === fallback || candidate.fallbackOnly || rankedAlternates.some((existing) => sameDeployment(existing.deployment, candidate.deployment))) continue;
|
|
343279
|
+
rankedAlternates.push(candidate);
|
|
343280
|
+
}
|
|
343281
|
+
for (const next of [equivalent, fallback, ...rankedAlternates]) {
|
|
343221
343282
|
if (!next || attempts.length >= 2) continue;
|
|
343222
343283
|
attempts.push({
|
|
343223
343284
|
deployment: { ...next.deployment },
|
|
343224
|
-
kind: next === equivalent ? "equivalent_deployment" : "fallback_model",
|
|
343285
|
+
kind: next === equivalent ? "equivalent_deployment" : next === fallback ? "fallback_model" : "alternate_model",
|
|
343225
343286
|
status: "planned",
|
|
343226
343287
|
errorType: failure.error.type,
|
|
343227
343288
|
streamCommitted: false,
|
|
@@ -343464,7 +343525,7 @@ function percentile(values, fraction) {
|
|
|
343464
343525
|
}
|
|
343465
343526
|
function failureFromType(type) {
|
|
343466
343527
|
const retryable = type === "timeout" || type === "rate_limited" || type === "transport" || type === "server_error" || type === "empty_response";
|
|
343467
|
-
return { type, retryable, switchAllowed: retryable };
|
|
343528
|
+
return { type, retryable, switchAllowed: retryable || type === "balance_exhausted" };
|
|
343468
343529
|
}
|
|
343469
343530
|
|
|
343470
343531
|
// src/context/services/agent-context-manager.ts
|
|
@@ -345570,7 +345631,9 @@ var Agent4 = class _Agent {
|
|
|
345570
345631
|
}
|
|
345571
345632
|
updateProviders(value) {
|
|
345572
345633
|
const before = this.config.providers();
|
|
345573
|
-
|
|
345634
|
+
const merged = mergeProviderSecrets(value, before);
|
|
345635
|
+
resetEditedModelValidationEvidence(merged, before);
|
|
345636
|
+
this.config.set("models", "providers", merged);
|
|
345574
345637
|
const after = this.config.providers();
|
|
345575
345638
|
const beforeById = new Map(before.map((provider) => [provider.id, provider]));
|
|
345576
345639
|
const afterById = new Map(after.map((provider) => [provider.id, provider]));
|
|
@@ -347656,6 +347719,19 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347656
347719
|
this.writeStoredConversationState(stored, targetWs);
|
|
347657
347720
|
return true;
|
|
347658
347721
|
}
|
|
347722
|
+
reorderConversationContinuations(orderedIds) {
|
|
347723
|
+
const currentIds = this.continuations.filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
347724
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
347725
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
347726
|
+
const byId = new Map(this.continuations.flatMap((item) => item.queueMode === "followUp" && item.clientMessageId ? [[String(item.clientMessageId), item]] : []));
|
|
347727
|
+
let nextIndex = 0;
|
|
347728
|
+
this.continuations = this.continuations.map((item) => {
|
|
347729
|
+
if (item.queueMode !== "followUp" || !item.clientMessageId) return item;
|
|
347730
|
+
return byId.get(orderedIds[nextIndex++]);
|
|
347731
|
+
});
|
|
347732
|
+
this.saveWorkspaceConversationState(true);
|
|
347733
|
+
return this.conversationContinuations();
|
|
347734
|
+
}
|
|
347659
347735
|
renameConversation(id, title, ws = this.workspace.current) {
|
|
347660
347736
|
const targetWs = ws || this.workspace.current;
|
|
347661
347737
|
if (!targetWs) return false;
|
|
@@ -350461,6 +350537,9 @@ ${msg.content}
|
|
|
350461
350537
|
const fallbackEnabled = this.config.getBool("models", "fallback_on_unavailable");
|
|
350462
350538
|
const observedFailure = classifyRouteFailure(errorText);
|
|
350463
350539
|
const observedDeployment = this.activeDeployment();
|
|
350540
|
+
if (observedFailure.type === "balance_exhausted" && observedDeployment) {
|
|
350541
|
+
this.providerBalanceBlockedUntilByDeployment.set(deploymentIdentity(observedDeployment), Date.now() + 5 * 6e4);
|
|
350542
|
+
}
|
|
350464
350543
|
const previousAttempt = observedDeployment && this.lastRouteDecision ? [...this.lastRouteDecision.attempts].reverse().find((attempt) => deploymentIdentity(attempt.deployment) === deploymentIdentity(observedDeployment)) : void 0;
|
|
350465
350544
|
if (this.model === "auto" && this.routeAttemptStartedAt === 0 && (this.lastRouteDecision?.finalStatus === "failed" || this.lastRouteDecision?.finalStatus === "blocked") && previousAttempt?.status === "failed" && previousAttempt.errorType === observedFailure.type) {
|
|
350466
350545
|
return null;
|
|
@@ -350511,14 +350590,12 @@ ${msg.content}
|
|
|
350511
350590
|
return current2.modelId;
|
|
350512
350591
|
}
|
|
350513
350592
|
if (!fallbackEnabled) return null;
|
|
350514
|
-
if (!observedFailure.
|
|
350593
|
+
if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
|
|
350515
350594
|
const current = this.model;
|
|
350516
|
-
const
|
|
350595
|
+
const currentDeployment = observedDeployment;
|
|
350596
|
+
const all = this.scopedSwitchModels(current).filter((m2) => !currentDeployment || deploymentIdentity(this.deploymentRef(m2)) !== deploymentIdentity(currentDeployment));
|
|
350517
350597
|
if (!all.length) return null;
|
|
350518
|
-
const usable = all.filter((m2) =>
|
|
350519
|
-
const status = String(m2.evaluation?.status || "unknown").toLowerCase();
|
|
350520
|
-
return status !== "unavailable" && !status.startsWith("error");
|
|
350521
|
-
});
|
|
350598
|
+
const usable = all.filter((m2) => !this.isBalanceBlockedDeployment(this.deploymentRef(m2)) && !modelConfigIsUnavailable(m2));
|
|
350522
350599
|
if (!usable.length) return null;
|
|
350523
350600
|
const pref = this.config.autoSwitchPreference();
|
|
350524
350601
|
const ranked = [...usable].sort((a3, b2) => this.modelScore(b2, pref, false, false) - this.modelScore(a3, pref, false, false));
|
|
@@ -351194,7 +351271,7 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
|
|
|
351194
351271
|
throw e3;
|
|
351195
351272
|
}
|
|
351196
351273
|
const msg = e3 instanceof Error ? e3.message : String(e3);
|
|
351197
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
351274
|
+
if (/\b402\b|insufficient balance|insufficient funds|payment required|insufficient[_ -]?quota|quota (?:exceeded|exhausted)|credit(?:s| balance)? (?:exhausted|depleted)|billing hard limit|budget exhausted|余额不足|额度不足|配额(?:不足|耗尽|超限)/i.test(msg)) {
|
|
351198
351275
|
this.noteProviderBalanceFailure();
|
|
351199
351276
|
}
|
|
351200
351277
|
this.status = "error";
|
|
@@ -353102,11 +353179,63 @@ function routeProviderFingerprint(provider) {
|
|
|
353102
353179
|
enabled: provider.enabled,
|
|
353103
353180
|
models: (provider.models || []).map((model) => ({
|
|
353104
353181
|
name: model.name,
|
|
353182
|
+
display: model.display,
|
|
353183
|
+
description: model.description,
|
|
353184
|
+
maxTokens: model.max_tokens,
|
|
353185
|
+
vision: model.vision,
|
|
353186
|
+
thinking: !!model.thinking,
|
|
353187
|
+
imageOutput: !!model.image_output,
|
|
353105
353188
|
enabled: model.enabled !== false,
|
|
353106
|
-
|
|
353189
|
+
preview: !!model.preview,
|
|
353190
|
+
logicalModelGroupId: model.logical_model_group_id || "",
|
|
353191
|
+
privacy: model.privacy || [],
|
|
353192
|
+
capabilities: model.capabilities || [],
|
|
353193
|
+
supportedParameters: model.supported_parameters || [],
|
|
353194
|
+
routePreference: model.route_preference,
|
|
353195
|
+
fallbackOnly: !!model.fallback_only,
|
|
353196
|
+
thinkingTierMap: model.thinking_tier_map || {}
|
|
353107
353197
|
}))
|
|
353108
353198
|
});
|
|
353109
353199
|
}
|
|
353200
|
+
function modelConfigurationFingerprint(model) {
|
|
353201
|
+
const { validation, evaluation, _previous_name, previous_name, ...configuration } = model;
|
|
353202
|
+
void validation;
|
|
353203
|
+
void evaluation;
|
|
353204
|
+
void _previous_name;
|
|
353205
|
+
void previous_name;
|
|
353206
|
+
return JSON.stringify(configuration);
|
|
353207
|
+
}
|
|
353208
|
+
function resetEditedModelValidationEvidence(incomingProviders, existingProviders) {
|
|
353209
|
+
const existingById = new Map(existingProviders.map((provider) => [provider.id, provider]));
|
|
353210
|
+
const existingByName = new Map(existingProviders.map((provider) => [provider.name, provider]));
|
|
353211
|
+
for (const rawProvider of incomingProviders) {
|
|
353212
|
+
if (!rawProvider || typeof rawProvider !== "object" || Array.isArray(rawProvider)) continue;
|
|
353213
|
+
const provider = rawProvider;
|
|
353214
|
+
const previousProvider = existingById.get(String(provider.id || "")) || existingByName.get(String(provider._previous_name || provider.previous_name || provider.name || ""));
|
|
353215
|
+
const models = Array.isArray(provider.models) ? provider.models : [];
|
|
353216
|
+
const providerConnectionChanged = !!previousProvider && (String(provider.base_url || provider.endpoint || "") !== previousProvider.base_url || String(provider.protocol || "") !== previousProvider.protocol);
|
|
353217
|
+
for (const rawModel of models) {
|
|
353218
|
+
if (!rawModel || typeof rawModel !== "object" || Array.isArray(rawModel)) continue;
|
|
353219
|
+
const model = rawModel;
|
|
353220
|
+
const previousName = String(model._previous_name || model.previous_name || model.name || "");
|
|
353221
|
+
const previousModel = previousProvider?.models.find((candidate) => candidate.name === previousName);
|
|
353222
|
+
const edited = providerConnectionChanged || !!previousModel && modelConfigurationFingerprint(model) !== modelConfigurationFingerprint(previousModel);
|
|
353223
|
+
delete model._previous_name;
|
|
353224
|
+
delete model.previous_name;
|
|
353225
|
+
if (!edited) continue;
|
|
353226
|
+
model.validation = { level: "discovered", status: "degraded", checked_at: "", capabilities: {} };
|
|
353227
|
+
delete model.evaluation;
|
|
353228
|
+
model.speed_rating = "unknown";
|
|
353229
|
+
model.capability_rating = "unknown";
|
|
353230
|
+
}
|
|
353231
|
+
}
|
|
353232
|
+
}
|
|
353233
|
+
function modelConfigIsUnavailable(model) {
|
|
353234
|
+
const validationStatus = effectiveModelValidationStatus(model);
|
|
353235
|
+
if (model.validation?.level !== "discovered" && (validationStatus === "unavailable" || validationStatus === "auth_error" || validationStatus === "invalid_config")) return true;
|
|
353236
|
+
const evaluationStatus = validationStatus === "degraded" ? "degraded" : String(model.evaluation?.status || "").toLowerCase();
|
|
353237
|
+
return evaluationStatus === "unavailable" || evaluationStatus.startsWith("error");
|
|
353238
|
+
}
|
|
353110
353239
|
function parseDeploymentSelectionValue2(value) {
|
|
353111
353240
|
const marker = String(value || "").trim();
|
|
353112
353241
|
if (!marker.startsWith("deployment:")) return null;
|
|
@@ -353123,9 +353252,9 @@ function parseDeploymentSelectionValue2(value) {
|
|
|
353123
353252
|
function effectiveModelValidationStatus(model) {
|
|
353124
353253
|
const raw = String(model.validation?.status || "").toLowerCase();
|
|
353125
353254
|
if (raw === "auth_error") return raw;
|
|
353255
|
+
if (String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353126
353256
|
const textEvidence = model.validation?.capabilities?.text === true || model.validation?.capabilities?.text_input === true || model.validation?.capabilities?.text_output === true || model.evaluation?.text_input === true || model.evaluation?.text_output === true;
|
|
353127
353257
|
if (textEvidence && raw === "unavailable") return "degraded";
|
|
353128
|
-
if (!raw && String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353129
353258
|
return ["verified", "degraded", "unavailable", "auth_error", "rate_limited", "invalid_config"].includes(raw) ? raw : "unavailable";
|
|
353130
353259
|
}
|
|
353131
353260
|
function routeToolIsReadOnly(name50, rawArgs) {
|
|
@@ -353332,6 +353461,33 @@ ${text}`;
|
|
|
353332
353461
|
this.emitQueueUpdate(runtime);
|
|
353333
353462
|
return true;
|
|
353334
353463
|
}
|
|
353464
|
+
reorderQueueItems(target, orderedIdsInput) {
|
|
353465
|
+
const runtime = this.findRuntime(target);
|
|
353466
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353467
|
+
const currentItems = this.queueItems(runtime.target);
|
|
353468
|
+
const orderedIds = Array.isArray(orderedIdsInput) ? orderedIdsInput.map((id) => String(id || "").trim()) : [];
|
|
353469
|
+
const currentIds = currentItems.map((item) => item.id);
|
|
353470
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
353471
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
353472
|
+
const persistedIds = runtime.runner.conversationContinuations().filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
353473
|
+
if (persistedIds.length !== currentIds.length || new Set(persistedIds).size !== persistedIds.length || persistedIds.some((id) => !currentIds.includes(id))) {
|
|
353474
|
+
throw new Error("Persisted queue does not match the complete queue order");
|
|
353475
|
+
}
|
|
353476
|
+
const pendingById = new Map(runtime.pendingNextTurn.flatMap((item) => {
|
|
353477
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return [];
|
|
353478
|
+
return [[String(item.message.clientMessageId), item]];
|
|
353479
|
+
}));
|
|
353480
|
+
const reorderedPending = orderedIds.map((id) => pendingById.get(id));
|
|
353481
|
+
let nextIndex = 0;
|
|
353482
|
+
runtime.pendingNextTurn = runtime.pendingNextTurn.map((item) => {
|
|
353483
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return item;
|
|
353484
|
+
return reorderedPending[nextIndex++];
|
|
353485
|
+
});
|
|
353486
|
+
runtime.runner.reorderConversationContinuations(orderedIds);
|
|
353487
|
+
runtime.queued.followUp = orderedIds.map((id) => pendingById.get(id)).map((item) => typeof item.message === "string" ? item.message : item.message.text);
|
|
353488
|
+
this.emitQueueUpdate(runtime);
|
|
353489
|
+
return this.queueItems(runtime.target);
|
|
353490
|
+
}
|
|
353335
353491
|
setQueuePaused(target, paused) {
|
|
353336
353492
|
const runtime = this.findRuntime(target);
|
|
353337
353493
|
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
@@ -353358,6 +353514,8 @@ ${text}`;
|
|
|
353358
353514
|
this.updateQueueItem(runtime.target, String(input.id || ""), String(input.text || ""));
|
|
353359
353515
|
} else if (action === "delete") {
|
|
353360
353516
|
if (!this.deleteQueueItem(runtime.target, String(input.id || ""))) throw new Error("Queue item was not found");
|
|
353517
|
+
} else if (action === "reorder") {
|
|
353518
|
+
this.reorderQueueItems(runtime.target, input.orderedIds || []);
|
|
353361
353519
|
} else if (action === "toggle_pause") {
|
|
353362
353520
|
this.setQueuePaused(runtime.target, !runtime.queuePaused);
|
|
353363
353521
|
} else if (action === "guide") {
|
|
@@ -353469,7 +353627,7 @@ ${item.goalObjective}` : item.text,
|
|
|
353469
353627
|
if (!clientMessageId) return { ...base2, reason: "clientMessageId is required" };
|
|
353470
353628
|
const existing = runtime ? this.guideReceipt(runtime, clientMessageId) : void 0;
|
|
353471
353629
|
if (existing) return existing;
|
|
353472
|
-
if (!runtime?.
|
|
353630
|
+
if (!runtime?.runId) {
|
|
353473
353631
|
return { ...base2, reason: "Target conversation is not running" };
|
|
353474
353632
|
}
|
|
353475
353633
|
if (requestedRunId && requestedRunId !== runtime.runId) {
|
|
@@ -353477,6 +353635,10 @@ ${item.goalObjective}` : item.text,
|
|
|
353477
353635
|
runtime.guideReceipts.set(clientMessageId, rejected);
|
|
353478
353636
|
return runtime.runner.recordGuideReceipt(rejected);
|
|
353479
353637
|
}
|
|
353638
|
+
const canReactivateFinalizingRun = !runtime.activePromise && runtime.guideAcceptanceClosedRunId === runtime.runId && (!requestedRunId || requestedRunId === runtime.runId);
|
|
353639
|
+
if (!runtime.activePromise && !canReactivateFinalizingRun) {
|
|
353640
|
+
return { ...base2, reason: "Target conversation is not running" };
|
|
353641
|
+
}
|
|
353480
353642
|
let safeImages = [];
|
|
353481
353643
|
let safeAttachments = [];
|
|
353482
353644
|
try {
|
|
@@ -353571,6 +353733,8 @@ ${item.goalObjective}` : item.text,
|
|
|
353571
353733
|
attachments: safeAttachments.map((attachment) => ({ ...attachment })),
|
|
353572
353734
|
createdAt: deferred2.createdAt
|
|
353573
353735
|
}]);
|
|
353736
|
+
this.trackQueuedMessage(runtime, safeEnvelope.text, "steer");
|
|
353737
|
+
this.emitQueueUpdate(runtime);
|
|
353574
353738
|
this.activateAcceptedGoal(runtime, envelope.goalObjective);
|
|
353575
353739
|
this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
|
|
353576
353740
|
return deferred2;
|
|
@@ -353835,6 +353999,7 @@ ${item.goalObjective}` : item.text,
|
|
|
353835
353999
|
activePromise = (async () => {
|
|
353836
354000
|
let result = null;
|
|
353837
354001
|
let stopped = false;
|
|
354002
|
+
let failed = false;
|
|
353838
354003
|
try {
|
|
353839
354004
|
result = await this.run(runtime, message, options);
|
|
353840
354005
|
stopped = runtime.runId === runId && runtime.stopRequestedRunId === runId;
|
|
@@ -353842,6 +354007,8 @@ ${item.goalObjective}` : item.text,
|
|
|
353842
354007
|
if (runtime.runId === runId && runtime.stopRequestedRunId === runId) {
|
|
353843
354008
|
stopped = true;
|
|
353844
354009
|
} else {
|
|
354010
|
+
failed = true;
|
|
354011
|
+
this.stopAutomaticContinuationAfterError(runtime, runId);
|
|
353845
354012
|
runtime.runner.finishConversationWorkRun(
|
|
353846
354013
|
runId,
|
|
353847
354014
|
"error",
|
|
@@ -353856,12 +354023,12 @@ ${item.goalObjective}` : item.text,
|
|
|
353856
354023
|
if (runtime.stopRequestedRunId === runId) {
|
|
353857
354024
|
stopped = true;
|
|
353858
354025
|
this.settleCooperativeStop(runtime, runId);
|
|
353859
|
-
} else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
354026
|
+
} else if (!failed && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
|
|
353860
354027
|
this.schedulePendingRuntimeContinuation(runtime, runId);
|
|
353861
354028
|
}
|
|
353862
354029
|
}
|
|
353863
354030
|
}
|
|
353864
|
-
if (!stopped && runtime.runId === runId) this.scheduleGoalContinuation(runtime, runId);
|
|
354031
|
+
if (!failed && !stopped && runtime.runId === runId) this.scheduleGoalContinuation(runtime, runId);
|
|
353865
354032
|
if (stopped) {
|
|
353866
354033
|
const settled = this.result(runtime, []);
|
|
353867
354034
|
if (result?.tokens) settled.tokens = result.tokens;
|
|
@@ -353883,6 +354050,28 @@ ${item.goalObjective}` : item.text,
|
|
|
353883
354050
|
this.emitQueueUpdate(runtime);
|
|
353884
354051
|
return true;
|
|
353885
354052
|
}
|
|
354053
|
+
stopAutomaticContinuationAfterError(runtime, runId) {
|
|
354054
|
+
if (runtime.runId !== runId) return;
|
|
354055
|
+
if (runtime.goalContinuationTimer) {
|
|
354056
|
+
clearTimeout(runtime.goalContinuationTimer);
|
|
354057
|
+
runtime.goalContinuationTimer = void 0;
|
|
354058
|
+
}
|
|
354059
|
+
runtime.pendingContinuationRunId = void 0;
|
|
354060
|
+
this.rejectOutstandingGuides(runtime, "The provider failed before this Guide could be applied; submit again to retry.");
|
|
354061
|
+
runtime.pendingNextTurn = runtime.pendingNextTurn.filter((item) => {
|
|
354062
|
+
const automatic = item.queueMode === "steer" || typeof item.message !== "string" && item.message.hiddenUserInput === true;
|
|
354063
|
+
if (automatic) {
|
|
354064
|
+
runtime.runner.consumeConversationContinuation({
|
|
354065
|
+
content: typeof item.message === "string" ? item.message : item.message.text,
|
|
354066
|
+
queueMode: item.queueMode,
|
|
354067
|
+
clientMessageId: typeof item.message === "string" ? void 0 : item.message.clientMessageId
|
|
354068
|
+
});
|
|
354069
|
+
}
|
|
354070
|
+
return !automatic;
|
|
354071
|
+
});
|
|
354072
|
+
this.queueState(runtime);
|
|
354073
|
+
this.emitQueueUpdate(runtime);
|
|
354074
|
+
}
|
|
353886
354075
|
async run(runtime, message, options) {
|
|
353887
354076
|
this.applyOptions(runtime.runner, options);
|
|
353888
354077
|
let lastTokens = await this.runSingle(runtime, message);
|
|
@@ -353976,7 +354165,13 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353976
354165
|
this.consumeQueuedMessage(runtime, typeof message === "string" ? message : message.text);
|
|
353977
354166
|
const timeoutMs = this.processTimeoutMs(runtime);
|
|
353978
354167
|
if (timeoutMs <= 0) {
|
|
353979
|
-
|
|
354168
|
+
let tokens;
|
|
354169
|
+
try {
|
|
354170
|
+
tokens = await runtime.runner.process(message);
|
|
354171
|
+
} catch (error) {
|
|
354172
|
+
this.consumeFailedAutomaticContinuation(runtime, message, continuationMode);
|
|
354173
|
+
throw error;
|
|
354174
|
+
}
|
|
353980
354175
|
if (continuationMode) runtime.runner.consumeConversationContinuation({
|
|
353981
354176
|
content: typeof message === "string" ? message : message.text,
|
|
353982
354177
|
queueMode: continuationMode,
|
|
@@ -353986,12 +354181,18 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
353986
354181
|
}
|
|
353987
354182
|
let timeout;
|
|
353988
354183
|
try {
|
|
353989
|
-
|
|
353990
|
-
|
|
353991
|
-
|
|
353992
|
-
|
|
353993
|
-
|
|
353994
|
-
|
|
354184
|
+
let tokens;
|
|
354185
|
+
try {
|
|
354186
|
+
tokens = await Promise.race([
|
|
354187
|
+
runtime.runner.process(message),
|
|
354188
|
+
new Promise((_3, reject) => {
|
|
354189
|
+
timeout = setTimeout(() => reject(new Error(`Process timeout (${Math.round(timeoutMs / 1e3)}s)`)), timeoutMs);
|
|
354190
|
+
})
|
|
354191
|
+
]);
|
|
354192
|
+
} catch (error) {
|
|
354193
|
+
this.consumeFailedAutomaticContinuation(runtime, message, continuationMode);
|
|
354194
|
+
throw error;
|
|
354195
|
+
}
|
|
353995
354196
|
if (continuationMode) runtime.runner.consumeConversationContinuation({
|
|
353996
354197
|
content: typeof message === "string" ? message : message.text,
|
|
353997
354198
|
queueMode: continuationMode,
|
|
@@ -354002,6 +354203,14 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
354002
354203
|
if (timeout) clearTimeout(timeout);
|
|
354003
354204
|
}
|
|
354004
354205
|
}
|
|
354206
|
+
consumeFailedAutomaticContinuation(runtime, message, continuationMode) {
|
|
354207
|
+
if (!continuationMode || typeof message === "string" || message.hiddenUserInput !== true) return;
|
|
354208
|
+
runtime.runner.consumeConversationContinuation({
|
|
354209
|
+
content: message.text,
|
|
354210
|
+
queueMode: continuationMode,
|
|
354211
|
+
clientMessageId: message.clientMessageId
|
|
354212
|
+
});
|
|
354213
|
+
}
|
|
354005
354214
|
processTimeoutMs(runtime) {
|
|
354006
354215
|
const raw = runtime.runner.config.getNum("agent", "process_timeout_ms") || this.host.config.getNum("agent", "process_timeout_ms");
|
|
354007
354216
|
if (!Number.isFinite(raw) || raw <= 0) return 0;
|
package/dist/core/agent.d.ts
CHANGED
|
@@ -670,6 +670,7 @@ export declare class Agent {
|
|
|
670
670
|
isBranchCommunicationEnabled(): boolean;
|
|
671
671
|
switchConversationBranch(conversationId: string, branchId: string, branchGroupId?: string): ConversationSnapshot;
|
|
672
672
|
setConversationPinned(id: string, pinned: boolean, ws?: WorkspaceInfo | null): boolean;
|
|
673
|
+
reorderConversationContinuations(orderedIds: string[]): ConversationContinuation[];
|
|
673
674
|
renameConversation(id: string, title: string, ws?: WorkspaceInfo | null): boolean;
|
|
674
675
|
/** 为指定工作区创建空白对话,不临时切换全局前台工作区。 */
|
|
675
676
|
createConversationInWorkspace(ws: WorkspaceInfo, title?: string): {
|