@agent-native/core 0.84.38 → 0.84.40

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.
Files changed (41) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/action-continuation-guidance.ts +38 -0
  5. package/corpus/core/src/agent/production-agent.ts +209 -4
  6. package/corpus/core/src/agent/run-loop-with-resume.ts +128 -16
  7. package/corpus/core/src/agent/types.ts +8 -0
  8. package/corpus/core/src/client/agent-chat-adapter.ts +2 -40
  9. package/corpus/templates/design/app/components/design/CodeWorkbenchHost.tsx +486 -341
  10. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +13 -0
  11. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +76 -58
  12. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +6 -0
  13. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +80 -8
  14. package/corpus/templates/design/app/i18n/zh-TW.ts +2 -2
  15. package/corpus/templates/design/app/i18n-data.ts +22 -30
  16. package/corpus/templates/design/app/lib/design-import.ts +42 -0
  17. package/corpus/templates/design/app/pages/DesignEditor.tsx +180 -109
  18. package/corpus/templates/design/changelog/2026-07-01-code-workspace-now-opens-a-vs-code-like-editor-with-real-cod.md +6 -0
  19. package/corpus/templates/design/changelog/2026-07-01-import-is-more-compact-local-app-setup-is-clearer-and-figma.md +6 -0
  20. package/corpus/templates/design/package.json +1 -0
  21. package/dist/agent/action-continuation-guidance.d.ts +3 -0
  22. package/dist/agent/action-continuation-guidance.d.ts.map +1 -0
  23. package/dist/agent/action-continuation-guidance.js +38 -0
  24. package/dist/agent/action-continuation-guidance.js.map +1 -0
  25. package/dist/agent/production-agent.d.ts +6 -2
  26. package/dist/agent/production-agent.d.ts.map +1 -1
  27. package/dist/agent/production-agent.js +160 -4
  28. package/dist/agent/production-agent.js.map +1 -1
  29. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  30. package/dist/agent/run-loop-with-resume.js +69 -18
  31. package/dist/agent/run-loop-with-resume.js.map +1 -1
  32. package/dist/agent/types.d.ts +2 -0
  33. package/dist/agent/types.d.ts.map +1 -1
  34. package/dist/agent/types.js.map +1 -1
  35. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  36. package/dist/client/agent-chat-adapter.js +2 -39
  37. package/dist/client/agent-chat-adapter.js.map +1 -1
  38. package/dist/collab/routes.d.ts +1 -1
  39. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  40. package/dist/observability/routes.d.ts +5 -5
  41. package/package.json +1 -1
@@ -16,6 +16,7 @@ import { readBody } from "../server/h3-helpers.js";
16
16
  import { getRequestRunContext, ensureRequestRunContext, getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
17
17
  import { fireInternalDispatch } from "../server/self-dispatch.js";
18
18
  import { isReasoningEffort, normalizeReasoningEffortForModel, } from "../shared/reasoning-effort.js";
19
+ import { actionPreparationContinuationNote } from "./action-continuation-guidance.js";
19
20
  import { applyContextDirectives } from "./context-xray/apply-directives.js";
20
21
  import { loadContextDirectives } from "./context-xray/directives-store.js";
21
22
  import { buildManifest, writeContextManifest, } from "./context-xray/manifest.js";
@@ -558,6 +559,7 @@ function maxRetriesForError(err) {
558
559
  return MAX_RETRIES;
559
560
  }
560
561
  const TOOL_INPUT_ACTIVITY_INTERVAL_MS = 1500;
562
+ const ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS = 90_000;
561
563
  const MAX_TEXT_ATTACHMENT_CHARS = 60_000;
562
564
  const MAX_SELECTION_CONTEXT_CHARS = 8_000;
563
565
  const MAX_RESOURCE_INVENTORY_ITEMS = 40;
@@ -1098,7 +1100,7 @@ function collectTextParts(parts) {
1098
1100
  .join("");
1099
1101
  }
1100
1102
  export const AGENT_INTERNAL_CONTINUE_PROMPT = "Continue from where you left off and finish the user's original request. Do not repeat completed work, do not mention internal reconnects, time limits, or step limits, and continue as if this is the same uninterrupted run.";
1101
- export function appendAgentLoopContinuation(messages, reason) {
1103
+ export function appendAgentLoopContinuation(messages, reason, options = {}) {
1102
1104
  const note = reason === "loop_limit"
1103
1105
  ? "The previous run reached an internal step budget."
1104
1106
  : reason === "max_tokens"
@@ -1109,17 +1111,31 @@ export function appendAgentLoopContinuation(messages, reason) {
1109
1111
  ? "The previous LLM call hit an upstream gateway timeout before the response finished streaming."
1110
1112
  : reason === "network_interrupted"
1111
1113
  ? "The previous LLM call was cut off by a transport-level interruption (socket dropped, connection reset, or stream closed unexpectedly)."
1112
- : "The previous run reached an internal execution budget.";
1114
+ : reason === "no_progress"
1115
+ ? "The previous run stopped producing progress events while the connection stayed open."
1116
+ : "The previous run reached an internal execution budget.";
1117
+ const actionInputNote = options.actionPreparationTool
1118
+ ? actionPreparationContinuationNote(options.actionPreparationTool)
1119
+ : "";
1113
1120
  messages.push({
1114
1121
  role: "user",
1115
1122
  content: [
1116
1123
  {
1117
1124
  type: "text",
1118
- text: `${AGENT_INTERNAL_CONTINUE_PROMPT}\n\nInternal note: ${note}`,
1125
+ text: `${AGENT_INTERNAL_CONTINUE_PROMPT}\n\nInternal note: ${note}${actionInputNote}`,
1119
1126
  },
1120
1127
  ],
1121
1128
  });
1122
1129
  }
1130
+ function isAgentLoopContinuationReason(reason) {
1131
+ return (reason === "run_timeout" ||
1132
+ reason === "loop_limit" ||
1133
+ reason === "max_tokens" ||
1134
+ reason === "stream_ended" ||
1135
+ reason === "gateway_timeout" ||
1136
+ reason === "network_interrupted" ||
1137
+ reason === "no_progress");
1138
+ }
1123
1139
  /**
1124
1140
  * True when an error thrown by `runAgentLoop` is a recoverable transport- or
1125
1141
  * gateway-level interruption that the agent can resume from rather than a
@@ -1960,6 +1976,8 @@ export async function runAgentLoop(opts) {
1960
1976
  const toolInputNames = new Map();
1961
1977
  const toolInputBytes = new Map();
1962
1978
  let lastToolInputActivityAt = 0;
1979
+ const activeToolInputs = new Map();
1980
+ let endedForActionPreparationNoProgress = false;
1963
1981
  const sendToolInputActivity = (toolName, toolInputId, progressBytes, force = false) => {
1964
1982
  const now = Date.now();
1965
1983
  if (!force &&
@@ -1975,7 +1993,56 @@ export async function runAgentLoop(opts) {
1975
1993
  ...(typeof progressBytes === "number" ? { progressBytes } : {}),
1976
1994
  });
1977
1995
  };
1996
+ const resetActiveToolInput = (toolName, toolInputId) => {
1997
+ if (toolInputId) {
1998
+ activeToolInputs.delete(toolInputId);
1999
+ return;
2000
+ }
2001
+ if (toolName) {
2002
+ for (const [id, active] of activeToolInputs) {
2003
+ if (active.toolName === toolName) {
2004
+ activeToolInputs.delete(id);
2005
+ }
2006
+ }
2007
+ }
2008
+ };
2009
+ const hasActionPreparationStalled = () => {
2010
+ if (activeToolInputs.size === 0)
2011
+ return false;
2012
+ const now = Date.now();
2013
+ for (const active of activeToolInputs.values()) {
2014
+ if (now - active.lastProgressAt >=
2015
+ ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS) {
2016
+ return true;
2017
+ }
2018
+ }
2019
+ return false;
2020
+ };
2021
+ const trackActiveToolInput = (key, toolName, bytes) => {
2022
+ const now = Date.now();
2023
+ const previous = activeToolInputs.get(key);
2024
+ activeToolInputs.set(key, {
2025
+ id: key,
2026
+ ...((toolName ?? previous?.toolName)
2027
+ ? { toolName: toolName ?? previous?.toolName }
2028
+ : {}),
2029
+ startedAt: previous?.startedAt ?? now,
2030
+ lastProgressAt: now,
2031
+ bytes,
2032
+ });
2033
+ };
2034
+ const clearActiveToolInputs = () => {
2035
+ activeToolInputs.clear();
2036
+ };
1978
2037
  for await (const event of eventStream) {
2038
+ if (hasActionPreparationStalled()) {
2039
+ send({
2040
+ type: "auto_continue",
2041
+ reason: "no_progress",
2042
+ });
2043
+ endedForActionPreparationNoProgress = true;
2044
+ break;
2045
+ }
1979
2046
  // In-loop processor seam (stream hook). Each chunk is offered to every
1980
2047
  // processor's `processOutputStream` before the loop handles it. A
1981
2048
  // processor `abort()` throws a TripWire; catch it locally so it is not
@@ -2008,6 +2075,7 @@ export async function runAgentLoop(opts) {
2008
2075
  if (key && event.name) {
2009
2076
  toolInputNames.set(key, event.name);
2010
2077
  toolInputBytes.set(key, 0);
2078
+ trackActiveToolInput(key, event.name, 0);
2011
2079
  }
2012
2080
  sendToolInputActivity(event.name, key, undefined, true);
2013
2081
  }
@@ -2022,6 +2090,9 @@ export async function runAgentLoop(opts) {
2022
2090
  previous +
2023
2091
  new TextEncoder().encode(event.text ?? "").byteLength;
2024
2092
  toolInputBytes.set(key, progressBytes);
2093
+ if (progressBytes > previous) {
2094
+ trackActiveToolInput(key, toolName, progressBytes);
2095
+ }
2025
2096
  }
2026
2097
  sendToolInputActivity(toolName, key, progressBytes);
2027
2098
  }
@@ -2030,8 +2101,10 @@ export async function runAgentLoop(opts) {
2030
2101
  }
2031
2102
  else if (event.type === "tool-call") {
2032
2103
  // The authoritative tool-call blocks arrive in assistant-content.
2104
+ resetActiveToolInput(event.name, event.id);
2033
2105
  }
2034
2106
  else if (event.type === "tool-call-error") {
2107
+ resetActiveToolInput(event.name, event.id);
2035
2108
  toolCallErrors.set(event.id, {
2036
2109
  name: event.name,
2037
2110
  input: event.input,
@@ -2039,6 +2112,7 @@ export async function runAgentLoop(opts) {
2039
2112
  });
2040
2113
  }
2041
2114
  else if (event.type === "assistant-content") {
2115
+ clearActiveToolInputs();
2042
2116
  assistantContent = event.parts;
2043
2117
  }
2044
2118
  else if (event.type === "usage") {
@@ -2058,6 +2132,17 @@ export async function runAgentLoop(opts) {
2058
2132
  });
2059
2133
  }
2060
2134
  }
2135
+ if (hasActionPreparationStalled()) {
2136
+ send({
2137
+ type: "auto_continue",
2138
+ reason: "no_progress",
2139
+ });
2140
+ endedForActionPreparationNoProgress = true;
2141
+ break;
2142
+ }
2143
+ }
2144
+ if (endedForActionPreparationNoProgress) {
2145
+ return usage;
2061
2146
  }
2062
2147
  break;
2063
2148
  }
@@ -3043,6 +3128,62 @@ function endsAtInternalContinuationBoundary(run) {
3043
3128
  }
3044
3129
  return last.type === "error" && isRecoverableContinuationError(last);
3045
3130
  }
3131
+ function isPreparingActionActivityEvent(event) {
3132
+ if (event.type !== "activity")
3133
+ return false;
3134
+ const label = event.label.trim().toLowerCase();
3135
+ return label.startsWith("preparing ") && label.includes(" action");
3136
+ }
3137
+ export function lastUnfinishedPreparingActionToolFromEvents(events) {
3138
+ let active = null;
3139
+ for (const event of events) {
3140
+ if (isPreparingActionActivityEvent(event)) {
3141
+ const tool = event.tool?.trim();
3142
+ if (tool) {
3143
+ active = {
3144
+ tool,
3145
+ ...(event.id?.trim() ? { id: event.id.trim() } : {}),
3146
+ };
3147
+ }
3148
+ continue;
3149
+ }
3150
+ if (event.type === "tool_start" || event.type === "tool_done") {
3151
+ const tool = event.tool?.trim();
3152
+ const id = event.id?.trim();
3153
+ if (active &&
3154
+ ((id && active.id === id) || (!id && tool && active.tool === tool))) {
3155
+ active = null;
3156
+ }
3157
+ continue;
3158
+ }
3159
+ if (event.type === "error" && isRecoverableContinuationError(event)) {
3160
+ continue;
3161
+ }
3162
+ if (event.type === "clear" ||
3163
+ event.type === "done" ||
3164
+ event.type === "error" ||
3165
+ event.type === "missing_api_key") {
3166
+ active = null;
3167
+ }
3168
+ }
3169
+ return active?.tool;
3170
+ }
3171
+ function lastUnfinishedPreparingActionTool(run) {
3172
+ return lastUnfinishedPreparingActionToolFromEvents(run.events.map(({ event }) => event));
3173
+ }
3174
+ export function backgroundContinuationReasonForRun(run) {
3175
+ const last = run.events.at(-1)?.event;
3176
+ if (last?.type === "loop_limit")
3177
+ return "loop_limit";
3178
+ if (last?.type === "auto_continue" &&
3179
+ isAgentLoopContinuationReason(last.reason)) {
3180
+ return last.reason;
3181
+ }
3182
+ if (last?.type === "error" && isRecoverableContinuationError(last)) {
3183
+ return continuationReasonForResumableError(new EngineError(last.error, { errorCode: last.errorCode }));
3184
+ }
3185
+ return "run_timeout";
3186
+ }
3046
3187
  /**
3047
3188
  * Hard cap on server-driven background→background continuation chunks for a
3048
3189
  * single logical turn. A `backgroundFunction` run gets a ~13-min soft timeout,
@@ -3809,7 +3950,16 @@ export function createProductionAgentHandler(options) {
3809
3950
  ?.threadData;
3810
3951
  const resumed = threadDataToEngineMessages(priorThreadData);
3811
3952
  if (resumed.length > 0) {
3812
- appendAgentLoopContinuation(resumed, "run_timeout");
3953
+ const actionPreparationTool = typeof backgroundRunMarker?.actionPreparationTool === "string" &&
3954
+ backgroundRunMarker.actionPreparationTool.trim()
3955
+ ? backgroundRunMarker.actionPreparationTool.trim()
3956
+ : undefined;
3957
+ const continuationReason = isAgentLoopContinuationReason(backgroundRunMarker?.continuationReason)
3958
+ ? backgroundRunMarker.continuationReason
3959
+ : "run_timeout";
3960
+ appendAgentLoopContinuation(resumed, continuationReason, {
3961
+ ...(actionPreparationTool ? { actionPreparationTool } : {}),
3962
+ });
3813
3963
  messages.length = 0;
3814
3964
  messages.push(...resumed);
3815
3965
  }
@@ -4109,6 +4259,8 @@ export function createProductionAgentHandler(options) {
4109
4259
  // its seq log starts clean; same turnId folds the assistant
4110
4260
  // message across chunks.
4111
4261
  const nextRunId = generateRunId();
4262
+ const actionPreparationTool = lastUnfinishedPreparingActionTool(run);
4263
+ const continuationReason = backgroundContinuationReasonForRun(run);
4112
4264
  const continuationDispatchPath = resolveAgentChatProcessRunDispatchPath();
4113
4265
  const continuationExpectsNetlifyBackgroundFunction = dispatchPathTargetsNetlifyBackgroundFunction(continuationDispatchPath);
4114
4266
  try {
@@ -4129,6 +4281,10 @@ export function createProductionAgentHandler(options) {
4129
4281
  runId: nextRunId,
4130
4282
  turnId: effectiveTurnId,
4131
4283
  continuationCount: backgroundContinuationCount + 1,
4284
+ continuationReason,
4285
+ ...(actionPreparationTool
4286
+ ? { actionPreparationTool }
4287
+ : {}),
4132
4288
  backgroundFunctionRuntimeExpected: continuationExpectsNetlifyBackgroundFunction,
4133
4289
  },
4134
4290
  },