@agent-native/core 0.78.5 → 0.78.8

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 (35) hide show
  1. package/corpus/core/CHANGELOG.md +18 -0
  2. package/corpus/core/docs/content/agent-teams.md +1 -1
  3. package/corpus/core/docs/content/locales/ar-SA/agent-teams.md +1 -1
  4. package/corpus/core/docs/content/locales/de-DE/agent-teams.md +1 -1
  5. package/corpus/core/docs/content/locales/es-ES/agent-teams.md +1 -1
  6. package/corpus/core/docs/content/locales/fr-FR/agent-teams.md +1 -1
  7. package/corpus/core/docs/content/locales/hi-IN/agent-teams.md +1 -1
  8. package/corpus/core/docs/content/locales/ja-JP/agent-teams.md +1 -1
  9. package/corpus/core/docs/content/locales/ko-KR/agent-teams.md +1 -1
  10. package/corpus/core/docs/content/locales/pt-BR/agent-teams.md +1 -1
  11. package/corpus/core/docs/content/locales/zh-CN/agent-teams.md +1 -1
  12. package/corpus/core/package.json +1 -1
  13. package/corpus/core/src/agent/production-agent.ts +97 -13
  14. package/corpus/templates/assets/actions/_helpers.ts +15 -2
  15. package/corpus/templates/assets/actions/get-library.ts +2 -2
  16. package/corpus/templates/assets/actions/view-screen.ts +98 -36
  17. package/dist/agent/production-agent.d.ts.map +1 -1
  18. package/dist/agent/production-agent.js +71 -8
  19. package/dist/agent/production-agent.js.map +1 -1
  20. package/dist/collab/routes.d.ts +1 -1
  21. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  22. package/dist/notifications/routes.d.ts +2 -2
  23. package/dist/observability/routes.d.ts +7 -7
  24. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  25. package/docs/content/agent-teams.md +1 -1
  26. package/docs/content/locales/ar-SA/agent-teams.md +1 -1
  27. package/docs/content/locales/de-DE/agent-teams.md +1 -1
  28. package/docs/content/locales/es-ES/agent-teams.md +1 -1
  29. package/docs/content/locales/fr-FR/agent-teams.md +1 -1
  30. package/docs/content/locales/hi-IN/agent-teams.md +1 -1
  31. package/docs/content/locales/ja-JP/agent-teams.md +1 -1
  32. package/docs/content/locales/ko-KR/agent-teams.md +1 -1
  33. package/docs/content/locales/pt-BR/agent-teams.md +1 -1
  34. package/docs/content/locales/zh-CN/agent-teams.md +1 -1
  35. package/package.json +1 -1
@@ -13,7 +13,7 @@ import { completeRun as completeProgressRun, startRun as startProgressRun, updat
13
13
  import { getFrontmatterValue, parseFrontmatter, } from "../resources/metadata.js";
14
14
  import { isDeployCredentialFallbackAllowed, readDeployCredentialEnv, } from "../server/credential-provider.js";
15
15
  import { readBody } from "../server/h3-helpers.js";
16
- import { getRequestRunContext, ensureRequestRunContext, getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
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
19
  import { applyContextDirectives } from "./context-xray/apply-directives.js";
@@ -2537,13 +2537,12 @@ export async function runAgentLoop(opts) {
2537
2537
  let mcpApp;
2538
2538
  try {
2539
2539
  const timeoutSignal = AbortSignal.timeout(toolTimeoutMs);
2540
- // Keep a reference to the action promise so we can attach a zombie-
2541
- // detection continuation AFTER Promise.race abandons it on run abort.
2542
- // The promise itself is not awaited here — Promise.race owns the await.
2543
- const actionPromise = Promise.resolve(actionEntry.run(toolCall.input, {
2540
+ const actionUserEmail = opts.ownerEmail ?? getRequestUserEmail();
2541
+ const actionOrgId = opts.orgId ?? getRequestOrgId() ?? null;
2542
+ const actionContext = {
2544
2543
  send,
2545
- userEmail: getRequestUserEmail(),
2546
- orgId: getRequestOrgId() ?? null,
2544
+ userEmail: actionUserEmail ?? undefined,
2545
+ orgId: actionOrgId,
2547
2546
  caller: "tool",
2548
2547
  attachments: opts.attachments,
2549
2548
  signal,
@@ -2552,7 +2551,18 @@ export async function runAgentLoop(opts) {
2552
2551
  actionName: toolCall.name,
2553
2552
  ...(opts.threadId ? { threadId: opts.threadId } : {}),
2554
2553
  ...(opts.turnId ? { turnId: opts.turnId } : {}),
2555
- }));
2554
+ };
2555
+ const requestContext = getRequestContext();
2556
+ const invokeAction = () => actionEntry.run(toolCall.input, actionContext);
2557
+ // Keep a reference to the action promise so we can attach a zombie-
2558
+ // detection continuation AFTER Promise.race abandons it on run abort.
2559
+ // The promise itself is not awaited here — Promise.race owns the await.
2560
+ const actionPromise = Promise.resolve(runWithRequestContext({
2561
+ ...(requestContext ?? {}),
2562
+ ...(actionUserEmail ? { userEmail: actionUserEmail } : {}),
2563
+ ...(actionOrgId ? { orgId: actionOrgId } : {}),
2564
+ ...(requestContext?.run ? { run: requestContext.run } : {}),
2565
+ }, invokeAction));
2556
2566
  // When the run is aborted (soft-timeout / user cancel) while this tool
2557
2567
  // call is in flight, Promise.race below will throw "Run aborted" and the
2558
2568
  // action's promise becomes a zombie — it keeps running but its result is
@@ -2975,6 +2985,23 @@ export function createProductionAgentHandler(options) {
2975
2985
  if (bgRunId)
2976
2986
  void recordRunDiagnostic(bgRunId, RUN_DIAG_STAGE.workerSetupStep, `${s}=${Date.now() - setupT0}ms`).catch(() => { });
2977
2987
  };
2988
+ // DIAGNOSTIC-ONLY: AWAITED worker mark. Fire-and-forget workerStep marks
2989
+ // after `post_model_ok` stopped landing even though writes still work
2990
+ // there — so the worker's MAIN FLOW stalls between post_model and pre_claim
2991
+ // (not a write hang). Awaited marks block until they land (or withDbTimeout-
2992
+ // reject), so `worker_stage` reliably advances to the last phase the main
2993
+ // flow actually reached — pinpointing the stall. Bg worker only.
2994
+ const awaitedWorkerMark = async (s) => {
2995
+ if (!isBackgroundWorker || !bgRunId)
2996
+ return;
2997
+ try {
2998
+ await recordRunDiagnostic(bgRunId, RUN_DIAG_STAGE.workerSetupStep, `${s}=${Date.now() - setupT0}ms`);
2999
+ }
3000
+ catch {
3001
+ // bounded by withDbTimeout; ignore — the absence of the next mark is
3002
+ // itself the signal.
3003
+ }
3004
+ };
2978
3005
  // Whether this worker is REALLY executing inside a 15-min Netlify
2979
3006
  // `-background` function (proven by the runtime function name), not merely a
2980
3007
  // `_process-run` re-entry that may have landed on the ~60s synchronous
@@ -3177,6 +3204,23 @@ export function createProductionAgentHandler(options) {
3177
3204
  // hang right after model resolution (DB connection); if it's
3178
3205
  // `engine_resolved`/`systemprompt_enter`, the stall is in the named step.
3179
3206
  workerStep("engine_resolved");
3207
+ // DIAGNOSTIC-ONLY: AWAITED probe (bg worker only). worker_stage stalls at
3208
+ // `model_done` even though the code right after is trivial sync — this
3209
+ // distinguishes the two causes: if `post_model_awaited` lands, DB writes
3210
+ // still work after model_done and the stall is later in the main flow; if it
3211
+ // never lands (stays `model_done`), the bg-fn DB connection itself is hung
3212
+ // right after model resolution. `recordRunDiagnostic` is `withDbTimeout`-
3213
+ // bounded, so a hung write rejects (caught) rather than blocking forever.
3214
+ if (isBackgroundWorker && bgRunId) {
3215
+ const probeStart = Date.now();
3216
+ try {
3217
+ await recordRunDiagnostic(bgRunId, RUN_DIAG_STAGE.workerSetupStep, "post_model_awaited");
3218
+ workerStep(`post_model_ok=${Date.now() - probeStart}ms`);
3219
+ }
3220
+ catch (e) {
3221
+ workerStep(`post_model_threw=${Date.now() - probeStart}ms:${String(e?.message ?? e).slice(0, 80)}`);
3222
+ }
3223
+ }
3180
3224
  // One-line per-turn resolution log so it's obvious in dev which engine
3181
3225
  // is actually handling the request. `requestEngine` is what the client
3182
3226
  // sent from the model picker; `engine.name` is what resolveEngine picked.
@@ -3205,6 +3249,7 @@ export function createProductionAgentHandler(options) {
3205
3249
  // reached db_request_ctx but not env_config hung in attachment upload or
3206
3250
  // engine/model resolution.
3207
3251
  workerStep("env_config");
3252
+ await awaitedWorkerMark("aw_env");
3208
3253
  // Run all independent pre-send steps in parallel. Each of these hits
3209
3254
  // the DB or invokes an action; running them sequentially was the
3210
3255
  // single biggest contributor to pre-LLM latency.
@@ -3461,6 +3506,7 @@ export function createProductionAgentHandler(options) {
3461
3506
  // DIAGNOSTIC-ONLY: all parallel context gathering (system prompt, screen,
3462
3507
  // files, loop settings, enriched message) resolved.
3463
3508
  workerStep("context_all");
3509
+ await awaitedWorkerMark("aw_presend");
3464
3510
  if (systemPromptError) {
3465
3511
  setResponseHeader(event, "Content-Type", "text/event-stream");
3466
3512
  setResponseHeader(event, "Cache-Control", "no-cache");
@@ -3482,6 +3528,7 @@ export function createProductionAgentHandler(options) {
3482
3528
  setupMark("actions");
3483
3529
  // DIAGNOSTIC-ONLY: action/tool resolution + engine-tool filtering finished.
3484
3530
  workerStep("action_tool_setup");
3531
+ await awaitedWorkerMark("aw_actions");
3485
3532
  const requestSystemPrompt = requestMode === "plan"
3486
3533
  ? `${systemPrompt}\n\n${PLAN_MODE_SYSTEM_PROMPT}`
3487
3534
  : systemPrompt;
@@ -3581,6 +3628,7 @@ export function createProductionAgentHandler(options) {
3581
3628
  // DIAGNOSTIC-ONLY: owner/thread resolution + runId/effectiveThreadId +
3582
3629
  // chained-continuation thread fetch finished.
3583
3630
  workerStep("owner_thread");
3631
+ await awaitedWorkerMark("aw_owner");
3584
3632
  // Persist the user's turn exactly once. The foreground POST does this
3585
3633
  // before dispatching; the background worker must NOT repeat it (it re-enters
3586
3634
  // with the same body, which would double-persist the user message).
@@ -3937,6 +3985,21 @@ export function createProductionAgentHandler(options) {
3937
3985
  // DIAGNOSTIC-ONLY: last stage before startRun fires. A worker that reaches
3938
3986
  // prestart but never workerStarted is hanging inside startRun itself.
3939
3987
  workerStep("prestart");
3988
+ // DIAGNOSTIC-ONLY: AWAITED probe right before startRun (bg worker only). If
3989
+ // worker_stage reaches `pre_claim_ok` but the run never flips to
3990
+ // `worker_started`, the stall is inside startRun's claim itself; if it never
3991
+ // reaches `pre_claim_*`, the stall is somewhere in the setup between
3992
+ // post_model and here.
3993
+ if (isBackgroundWorker && bgRunId) {
3994
+ const claimProbeStart = Date.now();
3995
+ try {
3996
+ await recordRunDiagnostic(bgRunId, RUN_DIAG_STAGE.workerSetupStep, "pre_claim");
3997
+ workerStep(`pre_claim_ok=${Date.now() - claimProbeStart}ms`);
3998
+ }
3999
+ catch (e) {
4000
+ workerStep(`pre_claim_threw=${Date.now() - claimProbeStart}ms:${String(e?.message ?? e).slice(0, 80)}`);
4001
+ }
4002
+ }
3940
4003
  // DIAGNOSTIC-ONLY: peak-ish RSS (MB) + assembled system-prompt size (KB) at
3941
4004
  // prestart. The analytics bg worker dies right after model_done; if the
3942
4005
  // FOREGROUND (identical build, writes land) is already near the ~1024MB