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.
@@ -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
- return await fetch(request.url, {
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|余额不足/i.test(publicError)) {
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|余额不足/i.test(text)) {
343055
- return { type: "balance_exhausted", retryable: false, switchAllowed: false, statusCode: 402 };
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.retryable || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
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
- for (const next of [equivalent, fallback]) {
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
- this.config.set("models", "providers", mergeProviderSecrets(value, before));
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.retryable || !observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
350593
+ if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
350515
350594
  const current = this.model;
350516
- const all = this.scopedSwitchModels(current).filter((m2) => m2.name !== current);
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|余额不足/i.test(msg)) {
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
- logicalModelGroupId: model.logical_model_group_id || ""
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?.activePromise || !runtime.runId) {
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
- const tokens = await runtime.runner.process(message);
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
- const tokens = await Promise.race([
353990
- runtime.runner.process(message),
353991
- new Promise((_3, reject) => {
353992
- timeout = setTimeout(() => reject(new Error(`Process timeout (${Math.round(timeoutMs / 1e3)}s)`)), timeoutMs);
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;
@@ -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): {