newmark-agent 0.4.8 → 0.4.9
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 +120 -18
- 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 +11 -8
- package/dist/core/conversationKernel.js +43 -0
- 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/wslAgentClient.d.ts +2 -8
- package/dist/core/wslAgentProtocol.d.ts +2 -8
- package/dist/core/wslAgentRuntimePool.d.ts +3 -15
- package/dist/main.js +201 -174
- package/dist/preload.js +2 -0
- package/dist/server.d.ts +16 -1
- package/dist/server.js +150 -6
- package/dist/ui/index.html +150 -14
- package/dist/wsl-agent-host.bundle.cjs +120 -18
- package/package.json +5 -2
|
@@ -340983,7 +340983,7 @@ async function runAgentKernel(agent) {
|
|
|
340983
340983
|
return;
|
|
340984
340984
|
}
|
|
340985
340985
|
const publicError = normalizePublicProviderError(error, [currentAgent.activeModelConfig()?.api_key]);
|
|
340986
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
340986
|
+
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
340987
|
currentAgent.noteProviderBalanceFailure();
|
|
340988
340988
|
}
|
|
340989
340989
|
const final = assistantMessage2(model, [{ type: "text", text: `[Error] ${publicError}` }], "error");
|
|
@@ -343051,8 +343051,8 @@ function classifyRouteFailure(error) {
|
|
|
343051
343051
|
if (statusCode === 400 || /bad request|invalid parameter|invalid request/i.test(text)) {
|
|
343052
343052
|
return { type: "invalid_request", retryable: false, switchAllowed: false, statusCode };
|
|
343053
343053
|
}
|
|
343054
|
-
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required
|
|
343055
|
-
return { type: "balance_exhausted", retryable: false, switchAllowed:
|
|
343054
|
+
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)) {
|
|
343055
|
+
return { type: "balance_exhausted", retryable: false, switchAllowed: true, statusCode: statusCode || 402 };
|
|
343056
343056
|
}
|
|
343057
343057
|
if (statusCode === 429 || /rate limit|too many requests/i.test(text)) {
|
|
343058
343058
|
return { type: "rate_limited", retryable: true, switchAllowed: true, statusCode: 429, retryAfterMs };
|
|
@@ -343190,13 +343190,13 @@ var AutoRouter = class {
|
|
|
343190
343190
|
}
|
|
343191
343191
|
planAttempts(decision, candidates, failure) {
|
|
343192
343192
|
const current = decision.resolvedDeployment;
|
|
343193
|
-
if (!current || !failure.error.
|
|
343193
|
+
if (!current || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
|
|
343194
343194
|
const remainingAttempts = Math.max(0, 3 - decision.attempts.length);
|
|
343195
343195
|
if (!remainingAttempts) return [];
|
|
343196
343196
|
const attempts = [];
|
|
343197
343197
|
const retryDelayMs = failure.error.retryAfterMs ?? 250;
|
|
343198
343198
|
const alreadyRetriedCurrent = decision.attempts.some((attempt) => attempt.kind === "retry_same_deployment" && sameDeployment(attempt.deployment, current));
|
|
343199
|
-
if (!alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343199
|
+
if (failure.error.retryable && !alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
|
|
343200
343200
|
attempts.push({
|
|
343201
343201
|
deployment: { ...current },
|
|
343202
343202
|
kind: "retry_same_deployment",
|
|
@@ -343217,11 +343217,16 @@ var AutoRouter = class {
|
|
|
343217
343217
|
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
343218
|
const equivalent = currentGroup ? eligible.find((candidate) => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly) : void 0;
|
|
343219
343219
|
const fallback = eligible.find((candidate) => candidate.fallbackOnly);
|
|
343220
|
-
|
|
343220
|
+
const rankedAlternates = decision.rankedCandidates.map((ranked) => eligible.find((candidate) => sameDeployment(candidate.deployment, ranked.deployment))).filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
|
|
343221
|
+
for (const candidate of eligible) {
|
|
343222
|
+
if (candidate === equivalent || candidate === fallback || candidate.fallbackOnly || rankedAlternates.some((existing) => sameDeployment(existing.deployment, candidate.deployment))) continue;
|
|
343223
|
+
rankedAlternates.push(candidate);
|
|
343224
|
+
}
|
|
343225
|
+
for (const next of [equivalent, fallback, ...rankedAlternates]) {
|
|
343221
343226
|
if (!next || attempts.length >= 2) continue;
|
|
343222
343227
|
attempts.push({
|
|
343223
343228
|
deployment: { ...next.deployment },
|
|
343224
|
-
kind: next === equivalent ? "equivalent_deployment" : "fallback_model",
|
|
343229
|
+
kind: next === equivalent ? "equivalent_deployment" : next === fallback ? "fallback_model" : "alternate_model",
|
|
343225
343230
|
status: "planned",
|
|
343226
343231
|
errorType: failure.error.type,
|
|
343227
343232
|
streamCommitted: false,
|
|
@@ -343464,7 +343469,7 @@ function percentile(values, fraction) {
|
|
|
343464
343469
|
}
|
|
343465
343470
|
function failureFromType(type) {
|
|
343466
343471
|
const retryable = type === "timeout" || type === "rate_limited" || type === "transport" || type === "server_error" || type === "empty_response";
|
|
343467
|
-
return { type, retryable, switchAllowed: retryable };
|
|
343472
|
+
return { type, retryable, switchAllowed: retryable || type === "balance_exhausted" };
|
|
343468
343473
|
}
|
|
343469
343474
|
|
|
343470
343475
|
// src/context/services/agent-context-manager.ts
|
|
@@ -345570,7 +345575,9 @@ var Agent4 = class _Agent {
|
|
|
345570
345575
|
}
|
|
345571
345576
|
updateProviders(value) {
|
|
345572
345577
|
const before = this.config.providers();
|
|
345573
|
-
|
|
345578
|
+
const merged = mergeProviderSecrets(value, before);
|
|
345579
|
+
resetEditedModelValidationEvidence(merged, before);
|
|
345580
|
+
this.config.set("models", "providers", merged);
|
|
345574
345581
|
const after = this.config.providers();
|
|
345575
345582
|
const beforeById = new Map(before.map((provider) => [provider.id, provider]));
|
|
345576
345583
|
const afterById = new Map(after.map((provider) => [provider.id, provider]));
|
|
@@ -347656,6 +347663,19 @@ Review this persisted peer result and summarize or continue the parent task as n
|
|
|
347656
347663
|
this.writeStoredConversationState(stored, targetWs);
|
|
347657
347664
|
return true;
|
|
347658
347665
|
}
|
|
347666
|
+
reorderConversationContinuations(orderedIds) {
|
|
347667
|
+
const currentIds = this.continuations.filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
347668
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
347669
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
347670
|
+
const byId = new Map(this.continuations.flatMap((item) => item.queueMode === "followUp" && item.clientMessageId ? [[String(item.clientMessageId), item]] : []));
|
|
347671
|
+
let nextIndex = 0;
|
|
347672
|
+
this.continuations = this.continuations.map((item) => {
|
|
347673
|
+
if (item.queueMode !== "followUp" || !item.clientMessageId) return item;
|
|
347674
|
+
return byId.get(orderedIds[nextIndex++]);
|
|
347675
|
+
});
|
|
347676
|
+
this.saveWorkspaceConversationState(true);
|
|
347677
|
+
return this.conversationContinuations();
|
|
347678
|
+
}
|
|
347659
347679
|
renameConversation(id, title, ws = this.workspace.current) {
|
|
347660
347680
|
const targetWs = ws || this.workspace.current;
|
|
347661
347681
|
if (!targetWs) return false;
|
|
@@ -350461,6 +350481,9 @@ ${msg.content}
|
|
|
350461
350481
|
const fallbackEnabled = this.config.getBool("models", "fallback_on_unavailable");
|
|
350462
350482
|
const observedFailure = classifyRouteFailure(errorText);
|
|
350463
350483
|
const observedDeployment = this.activeDeployment();
|
|
350484
|
+
if (observedFailure.type === "balance_exhausted" && observedDeployment) {
|
|
350485
|
+
this.providerBalanceBlockedUntilByDeployment.set(deploymentIdentity(observedDeployment), Date.now() + 5 * 6e4);
|
|
350486
|
+
}
|
|
350464
350487
|
const previousAttempt = observedDeployment && this.lastRouteDecision ? [...this.lastRouteDecision.attempts].reverse().find((attempt) => deploymentIdentity(attempt.deployment) === deploymentIdentity(observedDeployment)) : void 0;
|
|
350465
350488
|
if (this.model === "auto" && this.routeAttemptStartedAt === 0 && (this.lastRouteDecision?.finalStatus === "failed" || this.lastRouteDecision?.finalStatus === "blocked") && previousAttempt?.status === "failed" && previousAttempt.errorType === observedFailure.type) {
|
|
350466
350489
|
return null;
|
|
@@ -350511,14 +350534,12 @@ ${msg.content}
|
|
|
350511
350534
|
return current2.modelId;
|
|
350512
350535
|
}
|
|
350513
350536
|
if (!fallbackEnabled) return null;
|
|
350514
|
-
if (!observedFailure.
|
|
350537
|
+
if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
|
|
350515
350538
|
const current = this.model;
|
|
350516
|
-
const
|
|
350539
|
+
const currentDeployment = observedDeployment;
|
|
350540
|
+
const all = this.scopedSwitchModels(current).filter((m2) => !currentDeployment || deploymentIdentity(this.deploymentRef(m2)) !== deploymentIdentity(currentDeployment));
|
|
350517
350541
|
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
|
-
});
|
|
350542
|
+
const usable = all.filter((m2) => !this.isBalanceBlockedDeployment(this.deploymentRef(m2)) && !modelConfigIsUnavailable(m2));
|
|
350522
350543
|
if (!usable.length) return null;
|
|
350523
350544
|
const pref = this.config.autoSwitchPreference();
|
|
350524
350545
|
const ranked = [...usable].sort((a3, b2) => this.modelScore(b2, pref, false, false) - this.modelScore(a3, pref, false, false));
|
|
@@ -351194,7 +351215,7 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
|
|
|
351194
351215
|
throw e3;
|
|
351195
351216
|
}
|
|
351196
351217
|
const msg = e3 instanceof Error ? e3.message : String(e3);
|
|
351197
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
351218
|
+
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
351219
|
this.noteProviderBalanceFailure();
|
|
351199
351220
|
}
|
|
351200
351221
|
this.status = "error";
|
|
@@ -353102,11 +353123,63 @@ function routeProviderFingerprint(provider) {
|
|
|
353102
353123
|
enabled: provider.enabled,
|
|
353103
353124
|
models: (provider.models || []).map((model) => ({
|
|
353104
353125
|
name: model.name,
|
|
353126
|
+
display: model.display,
|
|
353127
|
+
description: model.description,
|
|
353128
|
+
maxTokens: model.max_tokens,
|
|
353129
|
+
vision: model.vision,
|
|
353130
|
+
thinking: !!model.thinking,
|
|
353131
|
+
imageOutput: !!model.image_output,
|
|
353105
353132
|
enabled: model.enabled !== false,
|
|
353106
|
-
|
|
353133
|
+
preview: !!model.preview,
|
|
353134
|
+
logicalModelGroupId: model.logical_model_group_id || "",
|
|
353135
|
+
privacy: model.privacy || [],
|
|
353136
|
+
capabilities: model.capabilities || [],
|
|
353137
|
+
supportedParameters: model.supported_parameters || [],
|
|
353138
|
+
routePreference: model.route_preference,
|
|
353139
|
+
fallbackOnly: !!model.fallback_only,
|
|
353140
|
+
thinkingTierMap: model.thinking_tier_map || {}
|
|
353107
353141
|
}))
|
|
353108
353142
|
});
|
|
353109
353143
|
}
|
|
353144
|
+
function modelConfigurationFingerprint(model) {
|
|
353145
|
+
const { validation, evaluation, _previous_name, previous_name, ...configuration } = model;
|
|
353146
|
+
void validation;
|
|
353147
|
+
void evaluation;
|
|
353148
|
+
void _previous_name;
|
|
353149
|
+
void previous_name;
|
|
353150
|
+
return JSON.stringify(configuration);
|
|
353151
|
+
}
|
|
353152
|
+
function resetEditedModelValidationEvidence(incomingProviders, existingProviders) {
|
|
353153
|
+
const existingById = new Map(existingProviders.map((provider) => [provider.id, provider]));
|
|
353154
|
+
const existingByName = new Map(existingProviders.map((provider) => [provider.name, provider]));
|
|
353155
|
+
for (const rawProvider of incomingProviders) {
|
|
353156
|
+
if (!rawProvider || typeof rawProvider !== "object" || Array.isArray(rawProvider)) continue;
|
|
353157
|
+
const provider = rawProvider;
|
|
353158
|
+
const previousProvider = existingById.get(String(provider.id || "")) || existingByName.get(String(provider._previous_name || provider.previous_name || provider.name || ""));
|
|
353159
|
+
const models = Array.isArray(provider.models) ? provider.models : [];
|
|
353160
|
+
const providerConnectionChanged = !!previousProvider && (String(provider.base_url || provider.endpoint || "") !== previousProvider.base_url || String(provider.protocol || "") !== previousProvider.protocol);
|
|
353161
|
+
for (const rawModel of models) {
|
|
353162
|
+
if (!rawModel || typeof rawModel !== "object" || Array.isArray(rawModel)) continue;
|
|
353163
|
+
const model = rawModel;
|
|
353164
|
+
const previousName = String(model._previous_name || model.previous_name || model.name || "");
|
|
353165
|
+
const previousModel = previousProvider?.models.find((candidate) => candidate.name === previousName);
|
|
353166
|
+
const edited = providerConnectionChanged || !!previousModel && modelConfigurationFingerprint(model) !== modelConfigurationFingerprint(previousModel);
|
|
353167
|
+
delete model._previous_name;
|
|
353168
|
+
delete model.previous_name;
|
|
353169
|
+
if (!edited) continue;
|
|
353170
|
+
model.validation = { level: "discovered", status: "degraded", checked_at: "", capabilities: {} };
|
|
353171
|
+
delete model.evaluation;
|
|
353172
|
+
model.speed_rating = "unknown";
|
|
353173
|
+
model.capability_rating = "unknown";
|
|
353174
|
+
}
|
|
353175
|
+
}
|
|
353176
|
+
}
|
|
353177
|
+
function modelConfigIsUnavailable(model) {
|
|
353178
|
+
const validationStatus = effectiveModelValidationStatus(model);
|
|
353179
|
+
if (model.validation?.level !== "discovered" && (validationStatus === "unavailable" || validationStatus === "auth_error" || validationStatus === "invalid_config")) return true;
|
|
353180
|
+
const evaluationStatus = validationStatus === "degraded" ? "degraded" : String(model.evaluation?.status || "").toLowerCase();
|
|
353181
|
+
return evaluationStatus === "unavailable" || evaluationStatus.startsWith("error");
|
|
353182
|
+
}
|
|
353110
353183
|
function parseDeploymentSelectionValue2(value) {
|
|
353111
353184
|
const marker = String(value || "").trim();
|
|
353112
353185
|
if (!marker.startsWith("deployment:")) return null;
|
|
@@ -353123,9 +353196,9 @@ function parseDeploymentSelectionValue2(value) {
|
|
|
353123
353196
|
function effectiveModelValidationStatus(model) {
|
|
353124
353197
|
const raw = String(model.validation?.status || "").toLowerCase();
|
|
353125
353198
|
if (raw === "auth_error") return raw;
|
|
353199
|
+
if (String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353126
353200
|
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
353201
|
if (textEvidence && raw === "unavailable") return "degraded";
|
|
353128
|
-
if (!raw && String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
|
|
353129
353202
|
return ["verified", "degraded", "unavailable", "auth_error", "rate_limited", "invalid_config"].includes(raw) ? raw : "unavailable";
|
|
353130
353203
|
}
|
|
353131
353204
|
function routeToolIsReadOnly(name50, rawArgs) {
|
|
@@ -353332,6 +353405,33 @@ ${text}`;
|
|
|
353332
353405
|
this.emitQueueUpdate(runtime);
|
|
353333
353406
|
return true;
|
|
353334
353407
|
}
|
|
353408
|
+
reorderQueueItems(target, orderedIdsInput) {
|
|
353409
|
+
const runtime = this.findRuntime(target);
|
|
353410
|
+
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
353411
|
+
const currentItems = this.queueItems(runtime.target);
|
|
353412
|
+
const orderedIds = Array.isArray(orderedIdsInput) ? orderedIdsInput.map((id) => String(id || "").trim()) : [];
|
|
353413
|
+
const currentIds = currentItems.map((item) => item.id);
|
|
353414
|
+
const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
|
|
353415
|
+
if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
|
|
353416
|
+
const persistedIds = runtime.runner.conversationContinuations().filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
|
|
353417
|
+
if (persistedIds.length !== currentIds.length || new Set(persistedIds).size !== persistedIds.length || persistedIds.some((id) => !currentIds.includes(id))) {
|
|
353418
|
+
throw new Error("Persisted queue does not match the complete queue order");
|
|
353419
|
+
}
|
|
353420
|
+
const pendingById = new Map(runtime.pendingNextTurn.flatMap((item) => {
|
|
353421
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return [];
|
|
353422
|
+
return [[String(item.message.clientMessageId), item]];
|
|
353423
|
+
}));
|
|
353424
|
+
const reorderedPending = orderedIds.map((id) => pendingById.get(id));
|
|
353425
|
+
let nextIndex = 0;
|
|
353426
|
+
runtime.pendingNextTurn = runtime.pendingNextTurn.map((item) => {
|
|
353427
|
+
if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return item;
|
|
353428
|
+
return reorderedPending[nextIndex++];
|
|
353429
|
+
});
|
|
353430
|
+
runtime.runner.reorderConversationContinuations(orderedIds);
|
|
353431
|
+
runtime.queued.followUp = orderedIds.map((id) => pendingById.get(id)).map((item) => typeof item.message === "string" ? item.message : item.message.text);
|
|
353432
|
+
this.emitQueueUpdate(runtime);
|
|
353433
|
+
return this.queueItems(runtime.target);
|
|
353434
|
+
}
|
|
353335
353435
|
setQueuePaused(target, paused) {
|
|
353336
353436
|
const runtime = this.findRuntime(target);
|
|
353337
353437
|
if (!runtime) throw new Error("Target conversation runtime is unavailable");
|
|
@@ -353358,6 +353458,8 @@ ${text}`;
|
|
|
353358
353458
|
this.updateQueueItem(runtime.target, String(input.id || ""), String(input.text || ""));
|
|
353359
353459
|
} else if (action === "delete") {
|
|
353360
353460
|
if (!this.deleteQueueItem(runtime.target, String(input.id || ""))) throw new Error("Queue item was not found");
|
|
353461
|
+
} else if (action === "reorder") {
|
|
353462
|
+
this.reorderQueueItems(runtime.target, input.orderedIds || []);
|
|
353361
353463
|
} else if (action === "toggle_pause") {
|
|
353362
353464
|
this.setQueuePaused(runtime.target, !runtime.queuePaused);
|
|
353363
353465
|
} else if (action === "guide") {
|
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): {
|
package/dist/core/agent.js
CHANGED
|
@@ -1051,7 +1051,9 @@ class Agent {
|
|
|
1051
1051
|
}
|
|
1052
1052
|
updateProviders(value) {
|
|
1053
1053
|
const before = this.config.providers();
|
|
1054
|
-
|
|
1054
|
+
const merged = (0, config_1.mergeProviderSecrets)(value, before);
|
|
1055
|
+
resetEditedModelValidationEvidence(merged, before);
|
|
1056
|
+
this.config.set('models', 'providers', merged);
|
|
1055
1057
|
const after = this.config.providers();
|
|
1056
1058
|
const beforeById = new Map(before.map(provider => [provider.id, provider]));
|
|
1057
1059
|
const afterById = new Map(after.map(provider => [provider.id, provider]));
|
|
@@ -3479,6 +3481,27 @@ class Agent {
|
|
|
3479
3481
|
this.writeStoredConversationState(stored, targetWs);
|
|
3480
3482
|
return true;
|
|
3481
3483
|
}
|
|
3484
|
+
reorderConversationContinuations(orderedIds) {
|
|
3485
|
+
const currentIds = this.continuations
|
|
3486
|
+
.filter(item => item.queueMode === 'followUp' && !!item.clientMessageId)
|
|
3487
|
+
.map(item => String(item.clientMessageId));
|
|
3488
|
+
const completeOrder = orderedIds.length === currentIds.length
|
|
3489
|
+
&& new Set(orderedIds).size === orderedIds.length
|
|
3490
|
+
&& orderedIds.every(id => currentIds.includes(id));
|
|
3491
|
+
if (!completeOrder)
|
|
3492
|
+
throw new Error('A complete queue order with unique current item ids is required');
|
|
3493
|
+
const byId = new Map(this.continuations.flatMap(item => item.queueMode === 'followUp' && item.clientMessageId
|
|
3494
|
+
? [[String(item.clientMessageId), item]]
|
|
3495
|
+
: []));
|
|
3496
|
+
let nextIndex = 0;
|
|
3497
|
+
this.continuations = this.continuations.map(item => {
|
|
3498
|
+
if (item.queueMode !== 'followUp' || !item.clientMessageId)
|
|
3499
|
+
return item;
|
|
3500
|
+
return byId.get(orderedIds[nextIndex++]);
|
|
3501
|
+
});
|
|
3502
|
+
this.saveWorkspaceConversationState(true);
|
|
3503
|
+
return this.conversationContinuations();
|
|
3504
|
+
}
|
|
3482
3505
|
renameConversation(id, title, ws = this.workspace.current) {
|
|
3483
3506
|
const targetWs = ws || this.workspace.current;
|
|
3484
3507
|
if (!targetWs)
|
|
@@ -6593,6 +6616,13 @@ class Agent {
|
|
|
6593
6616
|
const fallbackEnabled = this.config.getBool('models', 'fallback_on_unavailable');
|
|
6594
6617
|
const observedFailure = (0, autoRouter_1.classifyRouteFailure)(errorText);
|
|
6595
6618
|
const observedDeployment = this.activeDeployment();
|
|
6619
|
+
// Keep balance exhaustion scoped to the deployment that actually failed.
|
|
6620
|
+
// Provider adapters normally record this before returning an error, but
|
|
6621
|
+
// fallback callers are also a public recovery boundary and must not rely
|
|
6622
|
+
// on every adapter/error path having performed that side effect first.
|
|
6623
|
+
if (observedFailure.type === 'balance_exhausted' && observedDeployment) {
|
|
6624
|
+
this.providerBalanceBlockedUntilByDeployment.set(deploymentIdentity(observedDeployment), Date.now() + 5 * 60_000);
|
|
6625
|
+
}
|
|
6596
6626
|
const previousAttempt = observedDeployment && this.lastRouteDecision
|
|
6597
6627
|
? [...this.lastRouteDecision.attempts].reverse().find(attempt => deploymentIdentity(attempt.deployment) === deploymentIdentity(observedDeployment))
|
|
6598
6628
|
: undefined;
|
|
@@ -6654,16 +6684,15 @@ class Agent {
|
|
|
6654
6684
|
}
|
|
6655
6685
|
if (!fallbackEnabled)
|
|
6656
6686
|
return null;
|
|
6657
|
-
if (!observedFailure.
|
|
6687
|
+
if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted)
|
|
6658
6688
|
return null;
|
|
6659
6689
|
const current = this.model;
|
|
6660
|
-
const
|
|
6690
|
+
const currentDeployment = observedDeployment;
|
|
6691
|
+
const all = this.scopedSwitchModels(current).filter(m => !currentDeployment
|
|
6692
|
+
|| deploymentIdentity(this.deploymentRef(m)) !== deploymentIdentity(currentDeployment));
|
|
6661
6693
|
if (!all.length)
|
|
6662
6694
|
return null;
|
|
6663
|
-
const usable = all.filter(m =>
|
|
6664
|
-
const status = String(m.evaluation?.status || 'unknown').toLowerCase();
|
|
6665
|
-
return status !== 'unavailable' && !status.startsWith('error');
|
|
6666
|
-
});
|
|
6695
|
+
const usable = all.filter(m => !this.isBalanceBlockedDeployment(this.deploymentRef(m)) && !modelConfigIsUnavailable(m));
|
|
6667
6696
|
if (!usable.length)
|
|
6668
6697
|
return null;
|
|
6669
6698
|
const pref = this.config.autoSwitchPreference();
|
|
@@ -7436,7 +7465,7 @@ class Agent {
|
|
|
7436
7465
|
throw e;
|
|
7437
7466
|
}
|
|
7438
7467
|
const msg = e instanceof Error ? e.message : String(e);
|
|
7439
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
7468
|
+
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)) {
|
|
7440
7469
|
this.noteProviderBalanceFailure();
|
|
7441
7470
|
}
|
|
7442
7471
|
this.status = 'error';
|
|
@@ -9539,11 +9568,74 @@ function routeProviderFingerprint(provider) {
|
|
|
9539
9568
|
enabled: provider.enabled,
|
|
9540
9569
|
models: (provider.models || []).map(model => ({
|
|
9541
9570
|
name: model.name,
|
|
9571
|
+
display: model.display,
|
|
9572
|
+
description: model.description,
|
|
9573
|
+
maxTokens: model.max_tokens,
|
|
9574
|
+
vision: model.vision,
|
|
9575
|
+
thinking: !!model.thinking,
|
|
9576
|
+
imageOutput: !!model.image_output,
|
|
9542
9577
|
enabled: model.enabled !== false,
|
|
9578
|
+
preview: !!model.preview,
|
|
9543
9579
|
logicalModelGroupId: model.logical_model_group_id || '',
|
|
9580
|
+
privacy: model.privacy || [],
|
|
9581
|
+
capabilities: model.capabilities || [],
|
|
9582
|
+
supportedParameters: model.supported_parameters || [],
|
|
9583
|
+
routePreference: model.route_preference,
|
|
9584
|
+
fallbackOnly: !!model.fallback_only,
|
|
9585
|
+
thinkingTierMap: model.thinking_tier_map || {},
|
|
9544
9586
|
})),
|
|
9545
9587
|
});
|
|
9546
9588
|
}
|
|
9589
|
+
function modelConfigurationFingerprint(model) {
|
|
9590
|
+
const { validation, evaluation, _previous_name, previous_name, ...configuration } = model;
|
|
9591
|
+
void validation;
|
|
9592
|
+
void evaluation;
|
|
9593
|
+
void _previous_name;
|
|
9594
|
+
void previous_name;
|
|
9595
|
+
return JSON.stringify(configuration);
|
|
9596
|
+
}
|
|
9597
|
+
function resetEditedModelValidationEvidence(incomingProviders, existingProviders) {
|
|
9598
|
+
const existingById = new Map(existingProviders.map(provider => [provider.id, provider]));
|
|
9599
|
+
const existingByName = new Map(existingProviders.map(provider => [provider.name, provider]));
|
|
9600
|
+
for (const rawProvider of incomingProviders) {
|
|
9601
|
+
if (!rawProvider || typeof rawProvider !== 'object' || Array.isArray(rawProvider))
|
|
9602
|
+
continue;
|
|
9603
|
+
const provider = rawProvider;
|
|
9604
|
+
const previousProvider = existingById.get(String(provider.id || ''))
|
|
9605
|
+
|| existingByName.get(String(provider._previous_name || provider.previous_name || provider.name || ''));
|
|
9606
|
+
const models = Array.isArray(provider.models) ? provider.models : [];
|
|
9607
|
+
// Endpoint/protocol edits invalidate capability evidence. A display-name
|
|
9608
|
+
// change or credential rotation only resets runtime health/circuits via the
|
|
9609
|
+
// provider fingerprint and must not discard still-valid model capabilities.
|
|
9610
|
+
const providerConnectionChanged = !!previousProvider && (String(provider.base_url || provider.endpoint || '') !== previousProvider.base_url
|
|
9611
|
+
|| String(provider.protocol || '') !== previousProvider.protocol);
|
|
9612
|
+
for (const rawModel of models) {
|
|
9613
|
+
if (!rawModel || typeof rawModel !== 'object' || Array.isArray(rawModel))
|
|
9614
|
+
continue;
|
|
9615
|
+
const model = rawModel;
|
|
9616
|
+
const previousName = String(model._previous_name || model.previous_name || model.name || '');
|
|
9617
|
+
const previousModel = previousProvider?.models.find(candidate => candidate.name === previousName);
|
|
9618
|
+
const edited = providerConnectionChanged || (!!previousModel
|
|
9619
|
+
&& modelConfigurationFingerprint(model) !== modelConfigurationFingerprint(previousModel));
|
|
9620
|
+
delete model._previous_name;
|
|
9621
|
+
delete model.previous_name;
|
|
9622
|
+
if (!edited)
|
|
9623
|
+
continue;
|
|
9624
|
+
model.validation = { level: 'discovered', status: 'degraded', checked_at: '', capabilities: {} };
|
|
9625
|
+
delete model.evaluation;
|
|
9626
|
+
model.speed_rating = 'unknown';
|
|
9627
|
+
model.capability_rating = 'unknown';
|
|
9628
|
+
}
|
|
9629
|
+
}
|
|
9630
|
+
}
|
|
9631
|
+
function modelConfigIsUnavailable(model) {
|
|
9632
|
+
const validationStatus = effectiveModelValidationStatus(model);
|
|
9633
|
+
if (model.validation?.level !== 'discovered'
|
|
9634
|
+
&& (validationStatus === 'unavailable' || validationStatus === 'auth_error' || validationStatus === 'invalid_config'))
|
|
9635
|
+
return true;
|
|
9636
|
+
const evaluationStatus = validationStatus === 'degraded' ? 'degraded' : String(model.evaluation?.status || '').toLowerCase();
|
|
9637
|
+
return evaluationStatus === 'unavailable' || evaluationStatus.startsWith('error');
|
|
9638
|
+
}
|
|
9547
9639
|
function parseDeploymentSelectionValue(value) {
|
|
9548
9640
|
const marker = String(value || '').trim();
|
|
9549
9641
|
if (!marker.startsWith('deployment:'))
|
|
@@ -9564,6 +9656,8 @@ function effectiveModelValidationStatus(model) {
|
|
|
9564
9656
|
const raw = String(model.validation?.status || '').toLowerCase();
|
|
9565
9657
|
if (raw === 'auth_error')
|
|
9566
9658
|
return raw;
|
|
9659
|
+
if (String(model.validation?.level || '').toLowerCase() === 'discovered')
|
|
9660
|
+
return 'degraded';
|
|
9567
9661
|
const textEvidence = model.validation?.capabilities?.text === true
|
|
9568
9662
|
|| model.validation?.capabilities?.text_input === true
|
|
9569
9663
|
|| model.validation?.capabilities?.text_output === true
|
|
@@ -9571,8 +9665,6 @@ function effectiveModelValidationStatus(model) {
|
|
|
9571
9665
|
|| model.evaluation?.text_output === true;
|
|
9572
9666
|
if (textEvidence && raw === 'unavailable')
|
|
9573
9667
|
return 'degraded';
|
|
9574
|
-
if (!raw && String(model.validation?.level || '').toLowerCase() === 'discovered')
|
|
9575
|
-
return 'degraded';
|
|
9576
9668
|
return (['verified', 'degraded', 'unavailable', 'auth_error', 'rate_limited', 'invalid_config'].includes(raw)
|
|
9577
9669
|
? raw
|
|
9578
9670
|
: 'unavailable');
|
|
@@ -662,7 +662,7 @@ async function runAgentKernel(agent) {
|
|
|
662
662
|
return;
|
|
663
663
|
}
|
|
664
664
|
const publicError = normalizePublicProviderError(error, [currentAgent.activeModelConfig()?.api_key]);
|
|
665
|
-
if (/\b402\b|insufficient balance|insufficient funds|payment required
|
|
665
|
+
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)) {
|
|
666
666
|
currentAgent.noteProviderBalanceFailure();
|
|
667
667
|
}
|
|
668
668
|
const final = assistantMessage(model, [{ type: 'text', text: `[Error] ${publicError}` }], 'error');
|
|
@@ -85,7 +85,7 @@ export interface RankedRouteCandidate {
|
|
|
85
85
|
export type RouteAttemptStatus = 'planned' | 'success' | 'failed' | 'blocked';
|
|
86
86
|
export interface RouteAttempt {
|
|
87
87
|
deployment: DeploymentRef;
|
|
88
|
-
kind: 'initial' | 'retry_same_deployment' | 'equivalent_deployment' | 'fallback_model';
|
|
88
|
+
kind: 'initial' | 'retry_same_deployment' | 'equivalent_deployment' | 'fallback_model' | 'alternate_model';
|
|
89
89
|
status: RouteAttemptStatus;
|
|
90
90
|
errorType?: RouteFailureType;
|
|
91
91
|
durationMs?: number;
|
package/dist/core/autoRouter.js
CHANGED
|
@@ -115,8 +115,8 @@ function classifyRouteFailure(error) {
|
|
|
115
115
|
if (statusCode === 400 || /bad request|invalid parameter|invalid request/i.test(text)) {
|
|
116
116
|
return { type: 'invalid_request', retryable: false, switchAllowed: false, statusCode };
|
|
117
117
|
}
|
|
118
|
-
if (statusCode === 402 || /insufficient balance|insufficient funds|payment required
|
|
119
|
-
return { type: 'balance_exhausted', retryable: false, switchAllowed:
|
|
118
|
+
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)) {
|
|
119
|
+
return { type: 'balance_exhausted', retryable: false, switchAllowed: true, statusCode: statusCode || 402 };
|
|
120
120
|
}
|
|
121
121
|
if (statusCode === 429 || /rate limit|too many requests/i.test(text)) {
|
|
122
122
|
return { type: 'rate_limited', retryable: true, switchAllowed: true, statusCode: 429, retryAfterMs };
|
|
@@ -270,7 +270,7 @@ class AutoRouter {
|
|
|
270
270
|
}
|
|
271
271
|
planAttempts(decision, candidates, failure) {
|
|
272
272
|
const current = decision.resolvedDeployment;
|
|
273
|
-
if (!current || !failure.error.
|
|
273
|
+
if (!current || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted)
|
|
274
274
|
return [];
|
|
275
275
|
const remainingAttempts = Math.max(0, 3 - decision.attempts.length);
|
|
276
276
|
if (!remainingAttempts)
|
|
@@ -279,7 +279,7 @@ class AutoRouter {
|
|
|
279
279
|
const retryDelayMs = failure.error.retryAfterMs ?? 250;
|
|
280
280
|
const alreadyRetriedCurrent = decision.attempts.some(attempt => attempt.kind === 'retry_same_deployment'
|
|
281
281
|
&& sameDeployment(attempt.deployment, current));
|
|
282
|
-
if (!alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5_000)) {
|
|
282
|
+
if (failure.error.retryable && !alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5_000)) {
|
|
283
283
|
attempts.push({
|
|
284
284
|
deployment: { ...current },
|
|
285
285
|
kind: 'retry_same_deployment',
|
|
@@ -310,12 +310,21 @@ class AutoRouter {
|
|
|
310
310
|
? eligible.find(candidate => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly)
|
|
311
311
|
: undefined;
|
|
312
312
|
const fallback = eligible.find(candidate => candidate.fallbackOnly);
|
|
313
|
-
|
|
313
|
+
const rankedAlternates = decision.rankedCandidates
|
|
314
|
+
.map(ranked => eligible.find(candidate => sameDeployment(candidate.deployment, ranked.deployment)))
|
|
315
|
+
.filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
|
|
316
|
+
for (const candidate of eligible) {
|
|
317
|
+
if (candidate === equivalent || candidate === fallback || candidate.fallbackOnly
|
|
318
|
+
|| rankedAlternates.some(existing => sameDeployment(existing.deployment, candidate.deployment)))
|
|
319
|
+
continue;
|
|
320
|
+
rankedAlternates.push(candidate);
|
|
321
|
+
}
|
|
322
|
+
for (const next of [equivalent, fallback, ...rankedAlternates]) {
|
|
314
323
|
if (!next || attempts.length >= 2)
|
|
315
324
|
continue;
|
|
316
325
|
attempts.push({
|
|
317
326
|
deployment: { ...next.deployment },
|
|
318
|
-
kind: next === equivalent ? 'equivalent_deployment' : 'fallback_model',
|
|
327
|
+
kind: next === equivalent ? 'equivalent_deployment' : next === fallback ? 'fallback_model' : 'alternate_model',
|
|
319
328
|
status: 'planned',
|
|
320
329
|
errorType: failure.error.type,
|
|
321
330
|
streamCommitted: false,
|
|
@@ -578,6 +587,6 @@ function percentile(values, fraction) {
|
|
|
578
587
|
}
|
|
579
588
|
function failureFromType(type) {
|
|
580
589
|
const retryable = type === 'timeout' || type === 'rate_limited' || type === 'transport' || type === 'server_error' || type === 'empty_response';
|
|
581
|
-
return { type, retryable, switchAllowed: retryable };
|
|
590
|
+
return { type, retryable, switchAllowed: retryable || type === 'balance_exhausted' };
|
|
582
591
|
}
|
|
583
592
|
//# sourceMappingURL=autoRouter.js.map
|
|
@@ -12,7 +12,15 @@ export interface ConversationQueueItemSnapshot {
|
|
|
12
12
|
runId?: string;
|
|
13
13
|
createdAt: string;
|
|
14
14
|
}
|
|
15
|
-
export type ConversationQueueAction = 'enqueue' | 'update' | 'delete' | 'toggle_pause' | 'guide';
|
|
15
|
+
export type ConversationQueueAction = 'enqueue' | 'update' | 'delete' | 'reorder' | 'toggle_pause' | 'guide';
|
|
16
|
+
export interface ConversationQueueActionInput {
|
|
17
|
+
id?: string;
|
|
18
|
+
text?: string;
|
|
19
|
+
requestedMode?: string;
|
|
20
|
+
goalObjective?: string;
|
|
21
|
+
createdAt?: string;
|
|
22
|
+
orderedIds?: string[];
|
|
23
|
+
}
|
|
16
24
|
export interface AgentPromptMessage {
|
|
17
25
|
text: string;
|
|
18
26
|
/** Public transcript text when the execution prompt contains hidden orchestration instructions. */
|
|
@@ -196,14 +204,9 @@ export declare class ConversationKernel {
|
|
|
196
204
|
}): ConversationQueueItemSnapshot;
|
|
197
205
|
updateQueueItem(target: ConversationTargetInput, idInput: string, textInput: string): ConversationQueueItemSnapshot;
|
|
198
206
|
deleteQueueItem(target: ConversationTargetInput, idInput: string): boolean;
|
|
207
|
+
reorderQueueItems(target: ConversationTargetInput, orderedIdsInput: string[]): ConversationQueueItemSnapshot[];
|
|
199
208
|
setQueuePaused(target: ConversationTargetInput, paused: boolean): boolean;
|
|
200
|
-
queueAction(target: ConversationTargetInput, action: ConversationQueueAction, input?: {
|
|
201
|
-
id?: string;
|
|
202
|
-
text?: string;
|
|
203
|
-
requestedMode?: string;
|
|
204
|
-
goalObjective?: string;
|
|
205
|
-
createdAt?: string;
|
|
206
|
-
}): {
|
|
209
|
+
queueAction(target: ConversationTargetInput, action: ConversationQueueAction, input?: ConversationQueueActionInput): {
|
|
207
210
|
ok: boolean;
|
|
208
211
|
queueItems: ConversationQueueItemSnapshot[];
|
|
209
212
|
queuePaused: boolean;
|
|
@@ -160,6 +160,46 @@ class ConversationKernel {
|
|
|
160
160
|
this.emitQueueUpdate(runtime);
|
|
161
161
|
return true;
|
|
162
162
|
}
|
|
163
|
+
reorderQueueItems(target, orderedIdsInput) {
|
|
164
|
+
const runtime = this.findRuntime(target);
|
|
165
|
+
if (!runtime)
|
|
166
|
+
throw new Error('Target conversation runtime is unavailable');
|
|
167
|
+
const currentItems = this.queueItems(runtime.target);
|
|
168
|
+
const orderedIds = Array.isArray(orderedIdsInput)
|
|
169
|
+
? orderedIdsInput.map(id => String(id || '').trim())
|
|
170
|
+
: [];
|
|
171
|
+
const currentIds = currentItems.map(item => item.id);
|
|
172
|
+
const completeOrder = orderedIds.length === currentIds.length
|
|
173
|
+
&& new Set(orderedIds).size === orderedIds.length
|
|
174
|
+
&& orderedIds.every(id => currentIds.includes(id));
|
|
175
|
+
if (!completeOrder)
|
|
176
|
+
throw new Error('A complete queue order with unique current item ids is required');
|
|
177
|
+
const persistedIds = runtime.runner.conversationContinuations()
|
|
178
|
+
.filter(item => item.queueMode === 'followUp' && !!item.clientMessageId)
|
|
179
|
+
.map(item => String(item.clientMessageId));
|
|
180
|
+
if (persistedIds.length !== currentIds.length
|
|
181
|
+
|| new Set(persistedIds).size !== persistedIds.length
|
|
182
|
+
|| persistedIds.some(id => !currentIds.includes(id))) {
|
|
183
|
+
throw new Error('Persisted queue does not match the complete queue order');
|
|
184
|
+
}
|
|
185
|
+
const pendingById = new Map(runtime.pendingNextTurn.flatMap(item => {
|
|
186
|
+
if (item.queueMode !== 'followUp' || typeof item.message === 'string' || !item.message.clientMessageId)
|
|
187
|
+
return [];
|
|
188
|
+
return [[String(item.message.clientMessageId), item]];
|
|
189
|
+
}));
|
|
190
|
+
const reorderedPending = orderedIds.map(id => pendingById.get(id));
|
|
191
|
+
let nextIndex = 0;
|
|
192
|
+
runtime.pendingNextTurn = runtime.pendingNextTurn.map(item => {
|
|
193
|
+
if (item.queueMode !== 'followUp' || typeof item.message === 'string' || !item.message.clientMessageId)
|
|
194
|
+
return item;
|
|
195
|
+
return reorderedPending[nextIndex++];
|
|
196
|
+
});
|
|
197
|
+
runtime.runner.reorderConversationContinuations(orderedIds);
|
|
198
|
+
runtime.queued.followUp = orderedIds.map(id => pendingById.get(id))
|
|
199
|
+
.map(item => typeof item.message === 'string' ? item.message : item.message.text);
|
|
200
|
+
this.emitQueueUpdate(runtime);
|
|
201
|
+
return this.queueItems(runtime.target);
|
|
202
|
+
}
|
|
163
203
|
setQueuePaused(target, paused) {
|
|
164
204
|
const runtime = this.findRuntime(target);
|
|
165
205
|
if (!runtime)
|
|
@@ -192,6 +232,9 @@ class ConversationKernel {
|
|
|
192
232
|
if (!this.deleteQueueItem(runtime.target, String(input.id || '')))
|
|
193
233
|
throw new Error('Queue item was not found');
|
|
194
234
|
}
|
|
235
|
+
else if (action === 'reorder') {
|
|
236
|
+
this.reorderQueueItems(runtime.target, input.orderedIds || []);
|
|
237
|
+
}
|
|
195
238
|
else if (action === 'toggle_pause') {
|
|
196
239
|
this.setQueuePaused(runtime.target, !runtime.queuePaused);
|
|
197
240
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import { NormalizedConversationTarget } from './conversationTarget';
|
|
3
3
|
import { AgentMode, AgentWorkEvent, ConversationInputEnvelope, GuideReceipt } from './types';
|
|
4
|
-
import { ConversationQueueAction } from './conversationKernel';
|
|
4
|
+
import { ConversationQueueAction, ConversationQueueActionInput } from './conversationKernel';
|
|
5
5
|
import { UtilityAgentPromptResult, UtilityAutoRouteRatingResult, UtilityAgentSnapshotResult, UtilityAgentStopResult, UtilityConversationRewindResult, UtilityHostToolRequest, UtilityPromptRequest } from './utilityAgentProtocol';
|
|
6
6
|
type WindowsProcessTreeHelperRuntime = {
|
|
7
7
|
kind: 'precompiled' | 'runtime_compile';
|
|
@@ -95,13 +95,7 @@ export declare class ElectronUtilityAgentClient {
|
|
|
95
95
|
rewind(messageIndex: number): Promise<UtilityConversationRewindResult>;
|
|
96
96
|
requestStop(runId?: string): Promise<UtilityAgentStopResult>;
|
|
97
97
|
enqueueGuide(envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
|
|
98
|
-
queueAction(action: ConversationQueueAction, input?:
|
|
99
|
-
id?: string;
|
|
100
|
-
text?: string;
|
|
101
|
-
requestedMode?: string;
|
|
102
|
-
goalObjective?: string;
|
|
103
|
-
createdAt?: string;
|
|
104
|
-
}): Promise<Record<string, unknown>>;
|
|
98
|
+
queueAction(action: ConversationQueueAction, input?: ConversationQueueActionInput): Promise<Record<string, unknown>>;
|
|
105
99
|
checkpoint(): Promise<Record<string, unknown>>;
|
|
106
100
|
contextCompress(options?: {
|
|
107
101
|
keepRecent?: number;
|