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.
@@ -329456,6 +329456,7 @@ var LLMProvider = class _LLMProvider {
329456
329456
  thinkingTierMaps;
329457
329457
  static nodeHttpTransport = null;
329458
329458
  static powershellTransport = null;
329459
+ temperatureUnsupported = /* @__PURE__ */ new Set();
329459
329460
  effectiveRequestTimeout(timeoutMs) {
329460
329461
  const requested = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
329461
329462
  const configured = Number.isFinite(this.requestTimeoutMs) && this.requestTimeoutMs > 0 ? this.requestTimeoutMs : DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
@@ -329597,7 +329598,46 @@ var LLMProvider = class _LLMProvider {
329597
329598
  "X-GitHub-Api-Version": "2022-11-28"
329598
329599
  };
329599
329600
  }
329601
+ temperatureCapabilityKey(url, body) {
329602
+ return `${url}|${String(body.model || "")}`;
329603
+ }
329604
+ unsupportedTemperatureError(status, raw) {
329605
+ if (status !== 400) return false;
329606
+ try {
329607
+ const parsed = JSON.parse(String(raw || ""));
329608
+ if (String(parsed?.error?.param || "").toLowerCase() === "temperature") return true;
329609
+ return /unsupported parameter[^\n]*temperature|temperature[^\n]*not supported/i.test(String(parsed?.error?.message || ""));
329610
+ } catch {
329611
+ return /unsupported parameter[^\n]*temperature|temperature[^\n]*not supported/i.test(String(raw || ""));
329612
+ }
329613
+ }
329614
+ requestBodyForTemperatureCapability(url, body) {
329615
+ const prepared = { ...body };
329616
+ if (this.temperatureUnsupported.has(this.temperatureCapabilityKey(url, body))) delete prepared.temperature;
329617
+ return prepared;
329618
+ }
329600
329619
  async postJsonWithFetchFallback(url, headers, body, timeoutMs = 12e4, signal) {
329620
+ const prepared = this.requestBodyForTemperatureCapability(url, body);
329621
+ const response = await this.postJsonOnce(url, headers, prepared, timeoutMs, signal);
329622
+ if (prepared.temperature === void 0 || response.status !== 400) return response;
329623
+ const cloneable = typeof response.clone === "function";
329624
+ const errorText = await (cloneable ? response.clone() : response).text();
329625
+ if (!this.unsupportedTemperatureError(response.status, errorText)) {
329626
+ if (cloneable) return response;
329627
+ return {
329628
+ ok: response.ok,
329629
+ status: response.status,
329630
+ headers: response.headers,
329631
+ text: async () => errorText,
329632
+ json: async () => JSON.parse(errorText || "{}")
329633
+ };
329634
+ }
329635
+ this.temperatureUnsupported.add(this.temperatureCapabilityKey(url, body));
329636
+ const retryBody = { ...body };
329637
+ delete retryBody.temperature;
329638
+ return this.postJsonOnce(url, headers, retryBody, timeoutMs, signal);
329639
+ }
329640
+ async postJsonOnce(url, headers, body, timeoutMs = 12e4, signal) {
329601
329641
  const effectiveTimeout = this.effectiveRequestTimeout(timeoutMs);
329602
329642
  if (this.isPlainHttpLoopback(url)) {
329603
329643
  const pathname = (() => {
@@ -330266,6 +330306,7 @@ ${responsePath}
330266
330306
  */
330267
330307
  buildProviderAdapterTransport() {
330268
330308
  return async (request, signal) => {
330309
+ request.body = this.requestBodyForTemperatureCapability(request.url, request.body);
330269
330310
  if (request.body?.stream === true) {
330270
330311
  const abort = new AbortController();
330271
330312
  const forwardAbort = () => abort.abort(signal?.reason);
@@ -330275,12 +330316,27 @@ ${responsePath}
330275
330316
  const timer = setTimeout(() => abort.abort(providerTimeoutError(effectiveTimeout)), effectiveTimeout);
330276
330317
  try {
330277
330318
  try {
330278
- return await fetch(request.url, {
330319
+ let response2 = await fetch(request.url, {
330279
330320
  method: "POST",
330280
330321
  headers: request.headers,
330281
330322
  body: JSON.stringify(request.body),
330282
330323
  signal: abort.signal
330283
330324
  });
330325
+ if (request.body.temperature !== void 0 && response2.status === 400) {
330326
+ const errorText = await response2.clone().text();
330327
+ if (this.unsupportedTemperatureError(response2.status, errorText)) {
330328
+ this.temperatureUnsupported.add(this.temperatureCapabilityKey(request.url, request.body));
330329
+ const retryBody = { ...request.body };
330330
+ delete retryBody.temperature;
330331
+ response2 = await fetch(request.url, {
330332
+ method: "POST",
330333
+ headers: request.headers,
330334
+ body: JSON.stringify(retryBody),
330335
+ signal: abort.signal
330336
+ });
330337
+ }
330338
+ }
330339
+ return response2;
330284
330340
  } catch (error) {
330285
330341
  if (signal?.aborted) throw abortFailure(signal);
330286
330342
  if (abort.signal.aborted) throw abortFailure(abort.signal);
@@ -340987,7 +341043,7 @@ async function runAgentKernel(agent) {
340987
341043
  return;
340988
341044
  }
340989
341045
  const publicError = normalizePublicProviderError(error, [currentAgent.activeModelConfig()?.api_key]);
340990
- if (/\b402\b|insufficient balance|insufficient funds|payment required|余额不足/i.test(publicError)) {
341046
+ 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)) {
340991
341047
  currentAgent.noteProviderBalanceFailure();
340992
341048
  }
340993
341049
  const final = assistantMessage2(model, [{ type: "text", text: `[Error] ${publicError}` }], "error");
@@ -343055,8 +343111,8 @@ function classifyRouteFailure(error) {
343055
343111
  if (statusCode === 400 || /bad request|invalid parameter|invalid request/i.test(text)) {
343056
343112
  return { type: "invalid_request", retryable: false, switchAllowed: false, statusCode };
343057
343113
  }
343058
- if (statusCode === 402 || /insufficient balance|insufficient funds|payment required|余额不足/i.test(text)) {
343059
- return { type: "balance_exhausted", retryable: false, switchAllowed: false, statusCode: 402 };
343114
+ 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)) {
343115
+ return { type: "balance_exhausted", retryable: false, switchAllowed: true, statusCode: statusCode || 402 };
343060
343116
  }
343061
343117
  if (statusCode === 429 || /rate limit|too many requests/i.test(text)) {
343062
343118
  return { type: "rate_limited", retryable: true, switchAllowed: true, statusCode: 429, retryAfterMs };
@@ -343194,13 +343250,13 @@ var AutoRouter = class {
343194
343250
  }
343195
343251
  planAttempts(decision, candidates, failure) {
343196
343252
  const current = decision.resolvedDeployment;
343197
- if (!current || !failure.error.retryable || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
343253
+ if (!current || !failure.error.switchAllowed || failure.streamCommitted || failure.sideEffectCommitted) return [];
343198
343254
  const remainingAttempts = Math.max(0, 3 - decision.attempts.length);
343199
343255
  if (!remainingAttempts) return [];
343200
343256
  const attempts = [];
343201
343257
  const retryDelayMs = failure.error.retryAfterMs ?? 250;
343202
343258
  const alreadyRetriedCurrent = decision.attempts.some((attempt) => attempt.kind === "retry_same_deployment" && sameDeployment(attempt.deployment, current));
343203
- if (!alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
343259
+ if (failure.error.retryable && !alreadyRetriedCurrent && retryDelayMs <= (decision.retryBudgetMs ?? 5e3)) {
343204
343260
  attempts.push({
343205
343261
  deployment: { ...current },
343206
343262
  kind: "retry_same_deployment",
@@ -343221,11 +343277,16 @@ var AutoRouter = class {
343221
343277
  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");
343222
343278
  const equivalent = currentGroup ? eligible.find((candidate) => candidate.deployment.logicalModelGroupId === currentGroup && !candidate.fallbackOnly) : void 0;
343223
343279
  const fallback = eligible.find((candidate) => candidate.fallbackOnly);
343224
- for (const next of [equivalent, fallback]) {
343280
+ const rankedAlternates = decision.rankedCandidates.map((ranked) => eligible.find((candidate) => sameDeployment(candidate.deployment, ranked.deployment))).filter((candidate) => !!candidate && candidate !== equivalent && candidate !== fallback && !candidate.fallbackOnly);
343281
+ for (const candidate of eligible) {
343282
+ if (candidate === equivalent || candidate === fallback || candidate.fallbackOnly || rankedAlternates.some((existing) => sameDeployment(existing.deployment, candidate.deployment))) continue;
343283
+ rankedAlternates.push(candidate);
343284
+ }
343285
+ for (const next of [equivalent, fallback, ...rankedAlternates]) {
343225
343286
  if (!next || attempts.length >= 2) continue;
343226
343287
  attempts.push({
343227
343288
  deployment: { ...next.deployment },
343228
- kind: next === equivalent ? "equivalent_deployment" : "fallback_model",
343289
+ kind: next === equivalent ? "equivalent_deployment" : next === fallback ? "fallback_model" : "alternate_model",
343229
343290
  status: "planned",
343230
343291
  errorType: failure.error.type,
343231
343292
  streamCommitted: false,
@@ -343468,7 +343529,7 @@ function percentile(values, fraction) {
343468
343529
  }
343469
343530
  function failureFromType(type) {
343470
343531
  const retryable = type === "timeout" || type === "rate_limited" || type === "transport" || type === "server_error" || type === "empty_response";
343471
- return { type, retryable, switchAllowed: retryable };
343532
+ return { type, retryable, switchAllowed: retryable || type === "balance_exhausted" };
343472
343533
  }
343473
343534
 
343474
343535
  // src/context/services/agent-context-manager.ts
@@ -345574,7 +345635,9 @@ var Agent4 = class _Agent {
345574
345635
  }
345575
345636
  updateProviders(value) {
345576
345637
  const before = this.config.providers();
345577
- this.config.set("models", "providers", mergeProviderSecrets(value, before));
345638
+ const merged = mergeProviderSecrets(value, before);
345639
+ resetEditedModelValidationEvidence(merged, before);
345640
+ this.config.set("models", "providers", merged);
345578
345641
  const after = this.config.providers();
345579
345642
  const beforeById = new Map(before.map((provider) => [provider.id, provider]));
345580
345643
  const afterById = new Map(after.map((provider) => [provider.id, provider]));
@@ -347660,6 +347723,19 @@ Review this persisted peer result and summarize or continue the parent task as n
347660
347723
  this.writeStoredConversationState(stored, targetWs);
347661
347724
  return true;
347662
347725
  }
347726
+ reorderConversationContinuations(orderedIds) {
347727
+ const currentIds = this.continuations.filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
347728
+ const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
347729
+ if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
347730
+ const byId = new Map(this.continuations.flatMap((item) => item.queueMode === "followUp" && item.clientMessageId ? [[String(item.clientMessageId), item]] : []));
347731
+ let nextIndex = 0;
347732
+ this.continuations = this.continuations.map((item) => {
347733
+ if (item.queueMode !== "followUp" || !item.clientMessageId) return item;
347734
+ return byId.get(orderedIds[nextIndex++]);
347735
+ });
347736
+ this.saveWorkspaceConversationState(true);
347737
+ return this.conversationContinuations();
347738
+ }
347663
347739
  renameConversation(id, title, ws = this.workspace.current) {
347664
347740
  const targetWs = ws || this.workspace.current;
347665
347741
  if (!targetWs) return false;
@@ -350465,6 +350541,9 @@ ${msg.content}
350465
350541
  const fallbackEnabled = this.config.getBool("models", "fallback_on_unavailable");
350466
350542
  const observedFailure = classifyRouteFailure(errorText);
350467
350543
  const observedDeployment = this.activeDeployment();
350544
+ if (observedFailure.type === "balance_exhausted" && observedDeployment) {
350545
+ this.providerBalanceBlockedUntilByDeployment.set(deploymentIdentity(observedDeployment), Date.now() + 5 * 6e4);
350546
+ }
350468
350547
  const previousAttempt = observedDeployment && this.lastRouteDecision ? [...this.lastRouteDecision.attempts].reverse().find((attempt) => deploymentIdentity(attempt.deployment) === deploymentIdentity(observedDeployment)) : void 0;
350469
350548
  if (this.model === "auto" && this.routeAttemptStartedAt === 0 && (this.lastRouteDecision?.finalStatus === "failed" || this.lastRouteDecision?.finalStatus === "blocked") && previousAttempt?.status === "failed" && previousAttempt.errorType === observedFailure.type) {
350470
350549
  return null;
@@ -350515,14 +350594,12 @@ ${msg.content}
350515
350594
  return current2.modelId;
350516
350595
  }
350517
350596
  if (!fallbackEnabled) return null;
350518
- if (!observedFailure.retryable || !observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
350597
+ if (!observedFailure.switchAllowed || this.routeStreamCommitted || this.routeSideEffectCommitted) return null;
350519
350598
  const current = this.model;
350520
- const all = this.scopedSwitchModels(current).filter((m2) => m2.name !== current);
350599
+ const currentDeployment = observedDeployment;
350600
+ const all = this.scopedSwitchModels(current).filter((m2) => !currentDeployment || deploymentIdentity(this.deploymentRef(m2)) !== deploymentIdentity(currentDeployment));
350521
350601
  if (!all.length) return null;
350522
- const usable = all.filter((m2) => {
350523
- const status = String(m2.evaluation?.status || "unknown").toLowerCase();
350524
- return status !== "unavailable" && !status.startsWith("error");
350525
- });
350602
+ const usable = all.filter((m2) => !this.isBalanceBlockedDeployment(this.deploymentRef(m2)) && !modelConfigIsUnavailable(m2));
350526
350603
  if (!usable.length) return null;
350527
350604
  const pref = this.config.autoSwitchPreference();
350528
350605
  const ranked = [...usable].sort((a3, b2) => this.modelScore(b2, pref, false, false) - this.modelScore(a3, pref, false, false));
@@ -351198,7 +351275,7 @@ ${persisted.map((guide, index) => `Guide ${index + 1}: ${guide.text}`).join("\n"
351198
351275
  throw e3;
351199
351276
  }
351200
351277
  const msg = e3 instanceof Error ? e3.message : String(e3);
351201
- if (/\b402\b|insufficient balance|insufficient funds|payment required|余额不足/i.test(msg)) {
351278
+ 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)) {
351202
351279
  this.noteProviderBalanceFailure();
351203
351280
  }
351204
351281
  this.status = "error";
@@ -353106,11 +353183,63 @@ function routeProviderFingerprint(provider) {
353106
353183
  enabled: provider.enabled,
353107
353184
  models: (provider.models || []).map((model) => ({
353108
353185
  name: model.name,
353186
+ display: model.display,
353187
+ description: model.description,
353188
+ maxTokens: model.max_tokens,
353189
+ vision: model.vision,
353190
+ thinking: !!model.thinking,
353191
+ imageOutput: !!model.image_output,
353109
353192
  enabled: model.enabled !== false,
353110
- logicalModelGroupId: model.logical_model_group_id || ""
353193
+ preview: !!model.preview,
353194
+ logicalModelGroupId: model.logical_model_group_id || "",
353195
+ privacy: model.privacy || [],
353196
+ capabilities: model.capabilities || [],
353197
+ supportedParameters: model.supported_parameters || [],
353198
+ routePreference: model.route_preference,
353199
+ fallbackOnly: !!model.fallback_only,
353200
+ thinkingTierMap: model.thinking_tier_map || {}
353111
353201
  }))
353112
353202
  });
353113
353203
  }
353204
+ function modelConfigurationFingerprint(model) {
353205
+ const { validation, evaluation, _previous_name, previous_name, ...configuration } = model;
353206
+ void validation;
353207
+ void evaluation;
353208
+ void _previous_name;
353209
+ void previous_name;
353210
+ return JSON.stringify(configuration);
353211
+ }
353212
+ function resetEditedModelValidationEvidence(incomingProviders, existingProviders) {
353213
+ const existingById = new Map(existingProviders.map((provider) => [provider.id, provider]));
353214
+ const existingByName = new Map(existingProviders.map((provider) => [provider.name, provider]));
353215
+ for (const rawProvider of incomingProviders) {
353216
+ if (!rawProvider || typeof rawProvider !== "object" || Array.isArray(rawProvider)) continue;
353217
+ const provider = rawProvider;
353218
+ const previousProvider = existingById.get(String(provider.id || "")) || existingByName.get(String(provider._previous_name || provider.previous_name || provider.name || ""));
353219
+ const models = Array.isArray(provider.models) ? provider.models : [];
353220
+ const providerConnectionChanged = !!previousProvider && (String(provider.base_url || provider.endpoint || "") !== previousProvider.base_url || String(provider.protocol || "") !== previousProvider.protocol);
353221
+ for (const rawModel of models) {
353222
+ if (!rawModel || typeof rawModel !== "object" || Array.isArray(rawModel)) continue;
353223
+ const model = rawModel;
353224
+ const previousName = String(model._previous_name || model.previous_name || model.name || "");
353225
+ const previousModel = previousProvider?.models.find((candidate) => candidate.name === previousName);
353226
+ const edited = providerConnectionChanged || !!previousModel && modelConfigurationFingerprint(model) !== modelConfigurationFingerprint(previousModel);
353227
+ delete model._previous_name;
353228
+ delete model.previous_name;
353229
+ if (!edited) continue;
353230
+ model.validation = { level: "discovered", status: "degraded", checked_at: "", capabilities: {} };
353231
+ delete model.evaluation;
353232
+ model.speed_rating = "unknown";
353233
+ model.capability_rating = "unknown";
353234
+ }
353235
+ }
353236
+ }
353237
+ function modelConfigIsUnavailable(model) {
353238
+ const validationStatus = effectiveModelValidationStatus(model);
353239
+ if (model.validation?.level !== "discovered" && (validationStatus === "unavailable" || validationStatus === "auth_error" || validationStatus === "invalid_config")) return true;
353240
+ const evaluationStatus = validationStatus === "degraded" ? "degraded" : String(model.evaluation?.status || "").toLowerCase();
353241
+ return evaluationStatus === "unavailable" || evaluationStatus.startsWith("error");
353242
+ }
353114
353243
  function parseDeploymentSelectionValue2(value) {
353115
353244
  const marker = String(value || "").trim();
353116
353245
  if (!marker.startsWith("deployment:")) return null;
@@ -353127,9 +353256,9 @@ function parseDeploymentSelectionValue2(value) {
353127
353256
  function effectiveModelValidationStatus(model) {
353128
353257
  const raw = String(model.validation?.status || "").toLowerCase();
353129
353258
  if (raw === "auth_error") return raw;
353259
+ if (String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
353130
353260
  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;
353131
353261
  if (textEvidence && raw === "unavailable") return "degraded";
353132
- if (!raw && String(model.validation?.level || "").toLowerCase() === "discovered") return "degraded";
353133
353262
  return ["verified", "degraded", "unavailable", "auth_error", "rate_limited", "invalid_config"].includes(raw) ? raw : "unavailable";
353134
353263
  }
353135
353264
  function routeToolIsReadOnly(name50, rawArgs) {
@@ -353336,6 +353465,33 @@ ${text}`;
353336
353465
  this.emitQueueUpdate(runtime);
353337
353466
  return true;
353338
353467
  }
353468
+ reorderQueueItems(target, orderedIdsInput) {
353469
+ const runtime = this.findRuntime(target);
353470
+ if (!runtime) throw new Error("Target conversation runtime is unavailable");
353471
+ const currentItems = this.queueItems(runtime.target);
353472
+ const orderedIds = Array.isArray(orderedIdsInput) ? orderedIdsInput.map((id) => String(id || "").trim()) : [];
353473
+ const currentIds = currentItems.map((item) => item.id);
353474
+ const completeOrder = orderedIds.length === currentIds.length && new Set(orderedIds).size === orderedIds.length && orderedIds.every((id) => currentIds.includes(id));
353475
+ if (!completeOrder) throw new Error("A complete queue order with unique current item ids is required");
353476
+ const persistedIds = runtime.runner.conversationContinuations().filter((item) => item.queueMode === "followUp" && !!item.clientMessageId).map((item) => String(item.clientMessageId));
353477
+ if (persistedIds.length !== currentIds.length || new Set(persistedIds).size !== persistedIds.length || persistedIds.some((id) => !currentIds.includes(id))) {
353478
+ throw new Error("Persisted queue does not match the complete queue order");
353479
+ }
353480
+ const pendingById = new Map(runtime.pendingNextTurn.flatMap((item) => {
353481
+ if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return [];
353482
+ return [[String(item.message.clientMessageId), item]];
353483
+ }));
353484
+ const reorderedPending = orderedIds.map((id) => pendingById.get(id));
353485
+ let nextIndex = 0;
353486
+ runtime.pendingNextTurn = runtime.pendingNextTurn.map((item) => {
353487
+ if (item.queueMode !== "followUp" || typeof item.message === "string" || !item.message.clientMessageId) return item;
353488
+ return reorderedPending[nextIndex++];
353489
+ });
353490
+ runtime.runner.reorderConversationContinuations(orderedIds);
353491
+ runtime.queued.followUp = orderedIds.map((id) => pendingById.get(id)).map((item) => typeof item.message === "string" ? item.message : item.message.text);
353492
+ this.emitQueueUpdate(runtime);
353493
+ return this.queueItems(runtime.target);
353494
+ }
353339
353495
  setQueuePaused(target, paused) {
353340
353496
  const runtime = this.findRuntime(target);
353341
353497
  if (!runtime) throw new Error("Target conversation runtime is unavailable");
@@ -353362,6 +353518,8 @@ ${text}`;
353362
353518
  this.updateQueueItem(runtime.target, String(input2.id || ""), String(input2.text || ""));
353363
353519
  } else if (action === "delete") {
353364
353520
  if (!this.deleteQueueItem(runtime.target, String(input2.id || ""))) throw new Error("Queue item was not found");
353521
+ } else if (action === "reorder") {
353522
+ this.reorderQueueItems(runtime.target, input2.orderedIds || []);
353365
353523
  } else if (action === "toggle_pause") {
353366
353524
  this.setQueuePaused(runtime.target, !runtime.queuePaused);
353367
353525
  } else if (action === "guide") {
@@ -353473,7 +353631,7 @@ ${item.goalObjective}` : item.text,
353473
353631
  if (!clientMessageId) return { ...base2, reason: "clientMessageId is required" };
353474
353632
  const existing = runtime ? this.guideReceipt(runtime, clientMessageId) : void 0;
353475
353633
  if (existing) return existing;
353476
- if (!runtime?.activePromise || !runtime.runId) {
353634
+ if (!runtime?.runId) {
353477
353635
  return { ...base2, reason: "Target conversation is not running" };
353478
353636
  }
353479
353637
  if (requestedRunId && requestedRunId !== runtime.runId) {
@@ -353481,6 +353639,10 @@ ${item.goalObjective}` : item.text,
353481
353639
  runtime.guideReceipts.set(clientMessageId, rejected);
353482
353640
  return runtime.runner.recordGuideReceipt(rejected);
353483
353641
  }
353642
+ const canReactivateFinalizingRun = !runtime.activePromise && runtime.guideAcceptanceClosedRunId === runtime.runId && (!requestedRunId || requestedRunId === runtime.runId);
353643
+ if (!runtime.activePromise && !canReactivateFinalizingRun) {
353644
+ return { ...base2, reason: "Target conversation is not running" };
353645
+ }
353484
353646
  let safeImages = [];
353485
353647
  let safeAttachments = [];
353486
353648
  try {
@@ -353575,6 +353737,8 @@ ${item.goalObjective}` : item.text,
353575
353737
  attachments: safeAttachments.map((attachment) => ({ ...attachment })),
353576
353738
  createdAt: deferred2.createdAt
353577
353739
  }]);
353740
+ this.trackQueuedMessage(runtime, safeEnvelope.text, "steer");
353741
+ this.emitQueueUpdate(runtime);
353578
353742
  this.activateAcceptedGoal(runtime, envelope.goalObjective);
353579
353743
  this.schedulePendingRuntimeContinuation(runtime, runtime.runId);
353580
353744
  return deferred2;
@@ -353839,6 +354003,7 @@ ${item.goalObjective}` : item.text,
353839
354003
  activePromise = (async () => {
353840
354004
  let result = null;
353841
354005
  let stopped = false;
354006
+ let failed = false;
353842
354007
  try {
353843
354008
  result = await this.run(runtime, message, options);
353844
354009
  stopped = runtime.runId === runId && runtime.stopRequestedRunId === runId;
@@ -353846,6 +354011,8 @@ ${item.goalObjective}` : item.text,
353846
354011
  if (runtime.runId === runId && runtime.stopRequestedRunId === runId) {
353847
354012
  stopped = true;
353848
354013
  } else {
354014
+ failed = true;
354015
+ this.stopAutomaticContinuationAfterError(runtime, runId);
353849
354016
  runtime.runner.finishConversationWorkRun(
353850
354017
  runId,
353851
354018
  "error",
@@ -353860,12 +354027,12 @@ ${item.goalObjective}` : item.text,
353860
354027
  if (runtime.stopRequestedRunId === runId) {
353861
354028
  stopped = true;
353862
354029
  this.settleCooperativeStop(runtime, runId);
353863
- } else if (!runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
354030
+ } else if (!failed && !runtime.queuePaused && runtime.pendingNextTurn.length > 0) {
353864
354031
  this.schedulePendingRuntimeContinuation(runtime, runId);
353865
354032
  }
353866
354033
  }
353867
354034
  }
353868
- if (!stopped && runtime.runId === runId) this.scheduleGoalContinuation(runtime, runId);
354035
+ if (!failed && !stopped && runtime.runId === runId) this.scheduleGoalContinuation(runtime, runId);
353869
354036
  if (stopped) {
353870
354037
  const settled = this.result(runtime, []);
353871
354038
  if (result?.tokens) settled.tokens = result.tokens;
@@ -353887,6 +354054,28 @@ ${item.goalObjective}` : item.text,
353887
354054
  this.emitQueueUpdate(runtime);
353888
354055
  return true;
353889
354056
  }
354057
+ stopAutomaticContinuationAfterError(runtime, runId) {
354058
+ if (runtime.runId !== runId) return;
354059
+ if (runtime.goalContinuationTimer) {
354060
+ clearTimeout(runtime.goalContinuationTimer);
354061
+ runtime.goalContinuationTimer = void 0;
354062
+ }
354063
+ runtime.pendingContinuationRunId = void 0;
354064
+ this.rejectOutstandingGuides(runtime, "The provider failed before this Guide could be applied; submit again to retry.");
354065
+ runtime.pendingNextTurn = runtime.pendingNextTurn.filter((item) => {
354066
+ const automatic = item.queueMode === "steer" || typeof item.message !== "string" && item.message.hiddenUserInput === true;
354067
+ if (automatic) {
354068
+ runtime.runner.consumeConversationContinuation({
354069
+ content: typeof item.message === "string" ? item.message : item.message.text,
354070
+ queueMode: item.queueMode,
354071
+ clientMessageId: typeof item.message === "string" ? void 0 : item.message.clientMessageId
354072
+ });
354073
+ }
354074
+ return !automatic;
354075
+ });
354076
+ this.queueState(runtime);
354077
+ this.emitQueueUpdate(runtime);
354078
+ }
353890
354079
  async run(runtime, message, options) {
353891
354080
  this.applyOptions(runtime.runner, options);
353892
354081
  let lastTokens = await this.runSingle(runtime, message);
@@ -353980,7 +354169,13 @@ Review this persisted peer result and summarize or continue the parent task as n
353980
354169
  this.consumeQueuedMessage(runtime, typeof message === "string" ? message : message.text);
353981
354170
  const timeoutMs = this.processTimeoutMs(runtime);
353982
354171
  if (timeoutMs <= 0) {
353983
- const tokens = await runtime.runner.process(message);
354172
+ let tokens;
354173
+ try {
354174
+ tokens = await runtime.runner.process(message);
354175
+ } catch (error) {
354176
+ this.consumeFailedAutomaticContinuation(runtime, message, continuationMode);
354177
+ throw error;
354178
+ }
353984
354179
  if (continuationMode) runtime.runner.consumeConversationContinuation({
353985
354180
  content: typeof message === "string" ? message : message.text,
353986
354181
  queueMode: continuationMode,
@@ -353990,12 +354185,18 @@ Review this persisted peer result and summarize or continue the parent task as n
353990
354185
  }
353991
354186
  let timeout;
353992
354187
  try {
353993
- const tokens = await Promise.race([
353994
- runtime.runner.process(message),
353995
- new Promise((_3, reject) => {
353996
- timeout = setTimeout(() => reject(new Error(`Process timeout (${Math.round(timeoutMs / 1e3)}s)`)), timeoutMs);
353997
- })
353998
- ]);
354188
+ let tokens;
354189
+ try {
354190
+ tokens = await Promise.race([
354191
+ runtime.runner.process(message),
354192
+ new Promise((_3, reject) => {
354193
+ timeout = setTimeout(() => reject(new Error(`Process timeout (${Math.round(timeoutMs / 1e3)}s)`)), timeoutMs);
354194
+ })
354195
+ ]);
354196
+ } catch (error) {
354197
+ this.consumeFailedAutomaticContinuation(runtime, message, continuationMode);
354198
+ throw error;
354199
+ }
353999
354200
  if (continuationMode) runtime.runner.consumeConversationContinuation({
354000
354201
  content: typeof message === "string" ? message : message.text,
354001
354202
  queueMode: continuationMode,
@@ -354006,6 +354207,14 @@ Review this persisted peer result and summarize or continue the parent task as n
354006
354207
  if (timeout) clearTimeout(timeout);
354007
354208
  }
354008
354209
  }
354210
+ consumeFailedAutomaticContinuation(runtime, message, continuationMode) {
354211
+ if (!continuationMode || typeof message === "string" || message.hiddenUserInput !== true) return;
354212
+ runtime.runner.consumeConversationContinuation({
354213
+ content: message.text,
354214
+ queueMode: continuationMode,
354215
+ clientMessageId: message.clientMessageId
354216
+ });
354217
+ }
354009
354218
  processTimeoutMs(runtime) {
354010
354219
  const raw = runtime.runner.config.getNum("agent", "process_timeout_ms") || this.host.config.getNum("agent", "process_timeout_ms");
354011
354220
  if (!Number.isFinite(raw) || raw <= 0) return 0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "newmark-agent",
3
3
  "productName": "Newmark Agent",
4
- "version": "0.4.8",
4
+ "version": "0.5.0",
5
5
  "description": "Newmark Agent — Portable AI coding agent with rich GUI and CLI (TypeScript)",
6
6
  "homepage": "https://github.com/positer/Newmark-Agent",
7
7
  "repository": {
@@ -44,16 +44,16 @@
44
44
  "typecheck": "tsc --noEmit",
45
45
  "lint": "oxlint src",
46
46
  "test": "npm run test:full-release",
47
- "test:full-release": "npm run build && npm run test:desktop:built && npm run test:intelligence-tier:built && npm run test:tui:built && npm run test:mode-conversation-stress:built && npm run check-cross-platform-env && npm run test:ssh-tui-stress:built && npm run test:wsl-tui-stress:built && npm run test:cli:built && npm run test:gui-tui-cli-stress:built",
47
+ "test:full-release": "npm run build && node dist/tests/conversationHistoryFirstVerify.js && npm run test:desktop:built && npm run test:intelligence-tier:built && npm run test:tui:built && npm run test:mode-conversation-stress:built && npm run check-cross-platform-env && npm run test:ssh-tui-stress:built && npm run test:wsl-tui-stress:built && npm run test:cli:built && npm run test:gui-tui-cli-stress:built",
48
48
  "test:intelligence-tier:built": "node dist/tests/intelligenceTierVerify.js",
49
49
  "test:mode-conversation-stress": "node scripts/mode-conversation-state-stress.cjs",
50
50
  "test:mode-conversation-stress:built": "node scripts/mode-conversation-state-stress.cjs",
51
51
  "check-cross-platform-env": "node scripts/check-cross-platform-env.cjs",
52
52
  "dist:harmonyos": "node scripts/dist-harmonyos.cjs",
53
- "test:desktop": "npm run build && npm run test:desktop:built",
53
+ "test:desktop": "npm run build && node dist/tests/conversationHistoryFirstVerify.js && npm run test:desktop:built",
54
54
  "test:deletion-safety": "npm run build && npm run test:deletion-safety:built",
55
55
  "test:deletion-safety:built": "node scripts/deletion-safety-stress.cjs",
56
- "test:desktop:built": "node dist/tests/verify.js && node dist/tests/thinkingTierMapCacheStressVerify.js && node dist/tests/computerUseSessionVerify.js && node dist/tests/contextSystemV2Verify.js && node dist/tests/contextSystemV2StressVerify.js && node dist/tests/providerAdapterV2Verify.js && node dist/tests/providerTimeoutRecoveryVerify.js && node dist/tests/agentRuntimeV2Verify.js && node dist/tests/toolchainExposureV2Verify.js && node dist/tests/localOcrFallbackVerify.js && node dist/tests/dev018ModeSubagentStressVerify.js && node dist/tests/conversationBranchStressVerify.js && node dist/tests/conversationArchiveConcurrencyVerify.js && node dist/tests/conversationArchiveRuntimeVerify.js && node dist/tests/dev040ComprehensiveStressVerify.js && node dist/tests/memoryPolicyVerify.js && node dist/tests/newmarkSelectVerify.js && node dist/tests/mcpManagerVerify.js && node dist/tests/dshCompatibilityVerify.js && node dist/tests/performanceOptimizationVerify.js && node scripts/compression-pressure-stress.cjs && node dist/tests/compressionFidelityVerify.js && node dist/tests/responseTrajectoryVerify.js && node dist/tests/normalChatRegressionVerify.js && node dist/tests/dev008-subagent.js && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/runtimePoolCapacityVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/modelSwitchBehaviorVerify.js && node scripts/flow-pause-stop-draft-stress.cjs && node dist/tests/guideUiReconcileVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/displayImageVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/toolProvisioningVerify.js && node dist/tests/taskToolsVerify.js && node dist/tests/contextCacheHitStressVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/terminalTakeoverVerify.js && node dist/tests/workspaceFileRouterVerify.js && node dist/tests/screenCaptureIndependentVerify.js && node dist/tests/computerUsePerformanceVerify.js && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node scripts/deletion-safety-stress.cjs",
56
+ "test:desktop:built": "node dist/tests/verify.js && node dist/tests/thinkingTierMapCacheStressVerify.js && node dist/tests/computerUseSessionVerify.js && node dist/tests/contextSystemV2Verify.js && node dist/tests/contextSystemV2StressVerify.js && node dist/tests/providerAdapterV2Verify.js && node dist/tests/providerTimeoutRecoveryVerify.js && node dist/tests/agentRuntimeV2Verify.js && node dist/tests/toolchainExposureV2Verify.js && node dist/tests/localOcrFallbackVerify.js && node dist/tests/dev018ModeSubagentStressVerify.js && node dist/tests/conversationBranchStressVerify.js && node dist/tests/conversationArchiveConcurrencyVerify.js && node dist/tests/conversationArchiveRuntimeVerify.js && node dist/tests/dev040ComprehensiveStressVerify.js && node dist/tests/memoryPolicyVerify.js && node dist/tests/newmarkSelectVerify.js && node dist/tests/mcpManagerVerify.js && node dist/tests/dshCompatibilityVerify.js && node dist/tests/performanceOptimizationVerify.js && node scripts/compression-pressure-stress.cjs && node dist/tests/compressionFidelityVerify.js && node dist/tests/responseTrajectoryVerify.js && node dist/tests/normalChatRegressionVerify.js && node dist/tests/dev008-subagent.js && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/runtimePoolCapacityVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/modelSwitchBehaviorVerify.js && node scripts/flow-pause-stop-draft-stress.cjs && node dist/tests/guideUiReconcileVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/displayImageVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/toolProvisioningVerify.js && node dist/tests/taskToolsVerify.js && node dist/tests/contextCacheHitStressVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/terminalTakeoverVerify.js && node dist/tests/workspaceFileRouterVerify.js && node dist/tests/screenCaptureIndependentVerify.js && node dist/tests/computerUsePerformanceVerify.js && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/modelRecoveryStressVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node scripts/deletion-safety-stress.cjs",
57
57
  "test:conversation-branch-stress": "npm run build && node dist/tests/conversationBranchStressVerify.js",
58
58
  "test:conversation-archive-concurrency": "npm run build && node dist/tests/conversationArchiveConcurrencyVerify.js",
59
59
  "test:memory-policy": "npm run build && node dist/tests/memoryPolicyVerify.js",
@@ -85,6 +85,8 @@
85
85
  "test:dev009": "npm run build && node dist/tests/dev009Verify.js && node dist/tests/runtimeIsolationVerify.js && node dist/tests/guideWorkRunVerify.js && node dist/tests/guideUiReconcileVerify.js && node dist/tests/queueAttachmentIsolationVerify.js && node dist/tests/workspaceMenuVerify.js && node dist/tests/userImagePersistenceVerify.js && node dist/tests/visualPreferencesVerify.js && node dist/tests/browserUseVerify.js && node dist/tests/toolProcessVerify.js && node dist/tests/startupPrewarmVerify.js && node dist/tests/pdfPreviewServerVerify.js && node dist/tests/editorLifecycleVerify.js && node dist/tests/computerUsePerformanceVerify.js && electron dist/tests/browserUseElectronVerify.js",
86
86
  "test:dev008": "npm run build && node dist/tests/dev008-subagent.js",
87
87
  "test:auto-router": "npm run build && node dist/tests/autoRouterVerify.js && node dist/tests/autoAgentIntegrationVerify.js && node dist/tests/autoRouteRatingVerify.js && node dist/tests/providerIdentityVerify.js",
88
+ "test:model-recovery-stress": "npm run build && node dist/tests/modelRecoveryStressVerify.js",
89
+ "test:remote-touch-status": "npm run build && node dist/tests/remoteTouchServerStatusVerify.js",
88
90
  "test:model-validation": "npm run build && node dist/tests/modelValidationVerify.js && node dist/tests/modelValidationAgentIntegrationVerify.js && node dist/tests/intelligenceTierVerify.js",
89
91
  "test:runtime-pool": "npm run build && node dist/tests/runtimePoolCapacityVerify.js",
90
92
  "test:cli-tools": "npm run build && node dist/tests/cliToolContractVerify.js && node dist/tests/openAIHubAnthropicSmokeContractVerify.js && node dist/tests/cliComputerUseAccuracyVerify.js",
@@ -95,7 +97,9 @@
95
97
  "test:native-bash": "npm run build && node dist/tests/nativeBashVerify.js",
96
98
  "test:automation-bash-stress": "npm run build && node dist/tests/automationBashStressVerify.js",
97
99
  "dist:win": "npm run build:clean && node scripts/dist-portable.cjs",
98
- "release": "npm run test:full-release && npm run build:clean && node scripts/dist-portable.cjs",
100
+ "release": "node scripts/release-all.cjs",
101
+ "release:version-check": "node scripts/sync-release-version.cjs --check",
102
+ "release:version-set": "node scripts/sync-release-version.cjs --set",
99
103
  "dist:portable": "npm run test:full-release && npm run build:clean && node scripts/dist-portable.cjs",
100
104
  "release:cli-smoke": "node scripts/release-cli-smoke.cjs",
101
105
  "release:context-compress-cli-stress": "node scripts/release-context-compress-cli-stress.cjs",
@@ -104,6 +108,7 @@
104
108
  "release:safe-blackbox-gates": "node scripts/release-safe-blackbox-gates.cjs",
105
109
  "release:gui-no-model-smoke": "node scripts/release-gui-no-model-smoke.cjs",
106
110
  "release:safe-shared-root-restart-stress": "node scripts/release-safe-shared-root-restart-stress.cjs",
111
+ "release:pc-gui-tui-remote-service-stress": "node scripts/release-pc-gui-tui-remote-service-stress.cjs",
107
112
  "release:111-cli-smoke": "node scripts/release-111-cli-smoke.cjs",
108
113
  "release:111-ui-smoke": "node scripts/release-111-ui-smoke.cjs",
109
114
  "release:computer-use-vision-smoke": "node scripts/release-computer-use-vision-smoke.cjs",