@agent-native/core 0.79.7 → 0.79.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +13 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/run-manager.ts +9 -1
- package/corpus/core/src/client/agent-chat-adapter.ts +24 -16
- package/corpus/core/src/client/session-replay.ts +67 -13
- package/corpus/core/src/onboarding/default-steps.ts +3 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +82 -162
- package/corpus/core/src/server/agent-run-context.ts +204 -0
- package/corpus/core/src/server/credential-provider.ts +20 -4
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +14 -4
- package/corpus/templates/analytics/changelog/2026-06-26-session-replay-uploads-now-accept-compressed-payloads-so-lar.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-sql-chart-tooltips-now-stay-stable-while-moving-across-dense.md +6 -0
- package/corpus/templates/analytics/server/handlers/session-replay.ts +56 -8
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +44 -16
- package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -9
- package/corpus/templates/clips/app/i18n/de-DE.ts +12 -9
- package/corpus/templates/clips/app/i18n/en-US.ts +19 -16
- package/corpus/templates/clips/app/i18n/es-ES.ts +12 -9
- package/corpus/templates/clips/app/i18n/fr-FR.ts +12 -9
- package/corpus/templates/clips/app/i18n/hi-IN.ts +13 -9
- package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -9
- package/corpus/templates/clips/app/i18n/ko-KR.ts +12 -9
- package/corpus/templates/clips/app/i18n/pt-BR.ts +12 -9
- package/corpus/templates/clips/app/i18n/zh-CN.ts +19 -14
- package/corpus/templates/clips/app/i18n/zh-TW.ts +19 -14
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -0
- package/corpus/templates/clips/app/routes/record.tsx +2 -2
- package/corpus/templates/clips/changelog/2026-06-26-desktop-recordings-recover-more-reliably-when-macos-reports-.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-slack-unfurls-now-recognize-recording-dashboard-links-pasted.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-26-storage-setup-now-explains-why-clips-needs-connected-storage.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/background.ts +24 -3
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +28 -2
- package/corpus/templates/clips/chrome-extension/src/popup.html +16 -0
- package/corpus/templates/clips/chrome-extension/src/popup.ts +59 -7
- package/corpus/templates/clips/chrome-extension/src/sentry.ts +28 -1
- package/corpus/templates/clips/chrome-extension/src/styles.css +74 -0
- package/corpus/templates/clips/desktop/src/app.tsx +85 -18
- package/corpus/templates/clips/desktop/src/styles.css +55 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +88 -51
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +12 -3
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +5 -2
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +12 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +15 -8
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +55 -14
- package/dist/client/session-replay.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/onboarding/default-steps.js +3 -3
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +69 -154
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +2 -2
- package/dist/server/agent-run-context.d.ts +35 -0
- package/dist/server/agent-run-context.d.ts.map +1 -0
- package/dist/server/agent-run-context.js +137 -0
- package/dist/server/agent-run-context.js.map +1 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +15 -4
- package/dist/server/credential-provider.js.map +1 -1
- package/package.json +1 -1
- package/corpus/templates/.retired/README.md +0 -9
- package/corpus/templates/.retired/calls/package.json +0 -8
- package/corpus/templates/.retired/code/package.json +0 -8
- package/corpus/templates/.retired/contracts/package.json +0 -8
- package/corpus/templates/.retired/images/package.json +0 -8
- package/corpus/templates/.retired/issues/package.json +0 -8
- package/corpus/templates/.retired/meeting-notes/package.json +0 -8
- package/corpus/templates/.retired/migration/package.json +0 -8
- package/corpus/templates/.retired/recruiting/package.json +0 -8
- package/corpus/templates/.retired/scheduling/package.json +0 -8
- package/corpus/templates/.retired/visual-plans/package.json +0 -8
- package/corpus/templates/.retired/voice/package.json +0 -8
- package/corpus/templates/.retired/workbench/package.json +0 -8
|
@@ -28,10 +28,12 @@ import { normalizeDatabaseToolsMode, } from "../scripts/db/tool-mode.js";
|
|
|
28
28
|
import { dbExecToolParameters } from "../scripts/db/tool-schemas.js";
|
|
29
29
|
import { getSetting, putSetting } from "../settings/store.js";
|
|
30
30
|
import { discoverAgents } from "./agent-discovery.js";
|
|
31
|
+
import { resolveAgentRunOwnerContext, runWithAgentRunContext, seedBackgroundAgentRunOwnerContext, } from "./agent-run-context.js";
|
|
31
32
|
import { AGENT_TEAM_PROCESS_RUN_PATH, getCurrentDelegationDepth, processAgentTeamRun, reconcileAgentTeamRunsForOwner, } from "./agent-teams.js";
|
|
32
33
|
import { withConfiguredAppBasePath } from "./app-base-path.js";
|
|
33
34
|
import { getSession } from "./auth.js";
|
|
34
35
|
import { getBuilderBrowserConnectUrlForOwner, resolveBuilderBranchProjectId, } from "./builder-browser.js";
|
|
36
|
+
import { captureError } from "./capture-error.js";
|
|
35
37
|
import { captureCliOutput } from "./cli-capture.js";
|
|
36
38
|
import { getH3App, markDefaultPluginProvided, trackPluginInit, } from "./framework-request-handler.js";
|
|
37
39
|
import { getOrigin } from "./google-oauth.js";
|
|
@@ -581,13 +583,47 @@ function resolveArtifactBaseUrl(event) {
|
|
|
581
583
|
return undefined;
|
|
582
584
|
}
|
|
583
585
|
export function assembleA2AFinalResponse(events, toolResults, options = {}) {
|
|
584
|
-
const
|
|
586
|
+
const terminalError = getA2ATerminalErrorEvent(events);
|
|
587
|
+
const responseText = collectFinalResponseTextFromAgentEvents(events, {
|
|
588
|
+
fallbackToPreToolText: !terminalError,
|
|
589
|
+
});
|
|
585
590
|
const finalText = appendA2AArtifactLinks(responseText, [...toolResults], {
|
|
586
591
|
baseUrl: options.baseUrl ?? resolveArtifactBaseUrl(options.event),
|
|
587
592
|
includeReferencedArtifacts: true,
|
|
588
593
|
});
|
|
594
|
+
if (terminalError && !finalText.trim()) {
|
|
595
|
+
throw new Error(formatA2ATerminalError(terminalError));
|
|
596
|
+
}
|
|
589
597
|
return { responseText, finalText };
|
|
590
598
|
}
|
|
599
|
+
function getA2ATerminalErrorEvent(events) {
|
|
600
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
601
|
+
const event = events[i];
|
|
602
|
+
if (event.type === "clear")
|
|
603
|
+
continue;
|
|
604
|
+
if (event.type === "done")
|
|
605
|
+
return null;
|
|
606
|
+
if (event.type === "error")
|
|
607
|
+
return event;
|
|
608
|
+
if (event.type === "auto_continue") {
|
|
609
|
+
return {
|
|
610
|
+
type: "error",
|
|
611
|
+
error: `Agent stopped before finishing (${event.reason}).`,
|
|
612
|
+
errorCode: event.reason,
|
|
613
|
+
recoverable: true,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
function formatA2ATerminalError(event) {
|
|
620
|
+
const parts = [
|
|
621
|
+
event.error || "Agent failed before producing a final response.",
|
|
622
|
+
event.errorCode ? `code: ${event.errorCode}` : "",
|
|
623
|
+
event.details ? `details: ${event.details}` : "",
|
|
624
|
+
].filter(Boolean);
|
|
625
|
+
return parts.join("\n");
|
|
626
|
+
}
|
|
591
627
|
/**
|
|
592
628
|
* Creates the `get-framework-context` tool. Returns detailed instructions
|
|
593
629
|
* for framework capabilities that are summarized in the compact prompt.
|
|
@@ -2149,6 +2185,8 @@ In Act mode, if the user asks for generated interactive UI in chat, choose the s
|
|
|
2149
2185
|
|
|
2150
2186
|
These are **NOT** source-code changes and do **NOT** go through \`connect-builder\`. Extensions are sandboxed mini-apps — no source files are touched, no PR is opened, no build is required. Saved extensions can be edited later via \`update-extension\`.
|
|
2151
2187
|
|
|
2188
|
+
If the app exposes native actions or instructions for dashboards, reports, analyses, charts, documents, decks, or other domain artifacts, use those app-native actions first. Choose an extension only when the user explicitly asks for an extension/custom mini-app, or when the app's native artifact format cannot faithfully express the requested interaction.
|
|
2189
|
+
|
|
2152
2190
|
Keep \`create-extension\` payloads compact enough to finish quickly. For complex extensions, create a useful working v1 first, then call \`update-extension\` with focused edits for refinements instead of trying to assemble one enormous initial tool input.
|
|
2153
2191
|
|
|
2154
2192
|
Generated UI content can use appAction(), appFetch(), dbQuery(), dbExec(), extensionFetch(), extensionData, agentNative.ui.output(value, opts?), and agentNative.chat.send(...)/sendToAgentChat(...). It can receive chat inputs through slotContext/window.onSlotContext. Use agentNative.ui.output for passive current values from knobs, sliders, selections, and controls; it writes application state at \`inline-ui:<extensionId>:output\` scoped to the inline extension id returned by \`render-inline-extension\` or \`show-extension-inline\`. When the user later says "use that value", "apply the current setting", or similar, read it with \`readAppState("inline-ui:<id>:output")\` instead of asking them to send it again. Use agentNative.chat.send for visible submit/apply actions that should put a message into chat. Transient extensionData is browser-local and not agent-readable, synced, promoted, or garbage-collected; use application_state/appFetch, appAction, ui.output, or chat.send for anything the agent or app must observe. Use semantic Tailwind classes like bg-background, text-foreground, bg-primary, border-border, and text-muted-foreground so the UI inherits the parent app theme.
|
|
@@ -2176,7 +2214,7 @@ Route by what the request changes, not how it is phrased. Extensions render in t
|
|
|
2176
2214
|
| Ambiguous, satisfiable either way (e.g. "give me an unread view") | \`render-inline-extension\` for chat-only, \`create-extension\` for reusable |
|
|
2177
2215
|
</routing>
|
|
2178
2216
|
|
|
2179
|
-
Worked examples: "a widget showing unread emails grouped by sender", "a
|
|
2217
|
+
Worked examples: "a widget showing unread emails grouped by sender", "a tracker for my newsletter subscriptions", "a custom kanban board with drag-and-drop rules the app does not have" → \`create-extension\`. "Add an Unread tab to the left navigation", "make the subject lines wrap", "change the inbox grouping logic", "add a field to the compose form" → \`connect-builder\`.`
|
|
2180
2218
|
: `### Extensions Disabled
|
|
2181
2219
|
|
|
2182
2220
|
Extension creation and management tools are disabled for this app. Do not claim you can create, edit, hide, or delete Agent-Native extensions unless the template exposes its own typed action for that workflow. For requests that would otherwise be handled as an extension/widget/dashboard/calculator mini-app, explain that this app has disabled extension tools and use the app's available actions instead.`;
|
|
@@ -2185,6 +2223,8 @@ Extension creation and management tools are disabled for this app. Do not claim
|
|
|
2185
2223
|
|
|
2186
2224
|
In Act mode, if the user asks for generated interactive UI in chat, call \`render-inline-extension\` for one-time inline controls/knobs/calculators/visualizers that do not need saving. If the user asks for an **extension**, **widget**, **dashboard**, **calculator**, or **mini-app** that should be reusable or saved, call \`create-extension\` with a self-contained Alpine.js HTML body. To load a saved extension inline, call \`show-extension-inline\`. These are NOT code changes — extensions are sandboxed mini-apps. Do not preface with "let me build…" — just call the right extension action.
|
|
2187
2225
|
|
|
2226
|
+
Use app-native artifact actions first when they exist for dashboards, reports, analyses, charts, documents, decks, or similar domain artifacts. Pick \`create-extension\` only for explicit extension/custom mini-app requests or for behavior the native artifact format cannot support.
|
|
2227
|
+
|
|
2188
2228
|
Keep the first \`create-extension\` call compact and working. If the request is complex, create the v1 first and then refine with focused \`update-extension\` edits.
|
|
2189
2229
|
|
|
2190
2230
|
Generated UI can read chat inputs from slotContext/window.onSlotContext, see/update app state through appFetch/appAction, use extensionData, record passive current values through agentNative.ui.output(value, opts?), and send visible results through agentNative.chat.send(...) or sendToAgentChat(...). ui.output writes \`inline-ui:<extensionId>:output\` in application state; when the user asks to use the current slider/selection/value, read \`readAppState("inline-ui:<id>:output")\`. Transient extensionData is browser-local only, so do not rely on it for values the agent or app must observe. Use semantic Tailwind theme classes.
|
|
@@ -3798,36 +3838,11 @@ export function createAgentChatPlugin(options) {
|
|
|
3798
3838
|
},
|
|
3799
3839
|
});
|
|
3800
3840
|
}
|
|
3801
|
-
const OWNER_CONTEXT_KEY = "__agentNativeOwnerContext";
|
|
3802
3841
|
// Resolve owner from the H3 event's session, with an optional
|
|
3803
3842
|
// template-provided anonymous owner for public read-only surfaces.
|
|
3804
3843
|
const resolveOwnerContext = async (event) => {
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
return eventContext[OWNER_CONTEXT_KEY];
|
|
3808
|
-
}
|
|
3809
|
-
const session = await getSession(event);
|
|
3810
|
-
if (session?.email) {
|
|
3811
|
-
const resolved = {
|
|
3812
|
-
owner: session.email,
|
|
3813
|
-
anonymous: false,
|
|
3814
|
-
name: session.name,
|
|
3815
|
-
};
|
|
3816
|
-
if (eventContext)
|
|
3817
|
-
eventContext[OWNER_CONTEXT_KEY] = resolved;
|
|
3818
|
-
return resolved;
|
|
3819
|
-
}
|
|
3820
|
-
const anonymousOwner = await options?.anonymousOwner?.(event);
|
|
3821
|
-
if (anonymousOwner) {
|
|
3822
|
-
const resolved = { owner: anonymousOwner, anonymous: true };
|
|
3823
|
-
if (eventContext)
|
|
3824
|
-
eventContext[OWNER_CONTEXT_KEY] = resolved;
|
|
3825
|
-
return resolved;
|
|
3826
|
-
}
|
|
3827
|
-
const { createError } = await import("h3");
|
|
3828
|
-
throw createError({
|
|
3829
|
-
statusCode: 401,
|
|
3830
|
-
statusMessage: "Unauthenticated",
|
|
3844
|
+
return resolveAgentRunOwnerContext(event, {
|
|
3845
|
+
anonymousOwner: options?.anonymousOwner,
|
|
3831
3846
|
});
|
|
3832
3847
|
};
|
|
3833
3848
|
const getOwnerFromEvent = async (event) => {
|
|
@@ -6078,91 +6093,13 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6078
6093
|
// the background worker), so both go through identical context + handler
|
|
6079
6094
|
// selection.
|
|
6080
6095
|
const invokeAgentChatHandler = async (event) => {
|
|
6081
|
-
// Resolve per-request auth context
|
|
6096
|
+
// Resolve per-request auth context.
|
|
6082
6097
|
const ownerContext = await resolveOwnerContext(event);
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
// no org-scoped credentials. getOrgContext() does the same DB lookup
|
|
6089
|
-
// the /builder/status endpoint uses to decide "Connected".
|
|
6090
|
-
let resolvedOrgId;
|
|
6091
|
-
if (options?.resolveOrgId) {
|
|
6092
|
-
resolvedOrgId = (await options.resolveOrgId(event)) ?? undefined;
|
|
6093
|
-
}
|
|
6094
|
-
else {
|
|
6095
|
-
try {
|
|
6096
|
-
const session = await getSession(event);
|
|
6097
|
-
resolvedOrgId = session?.orgId ?? undefined;
|
|
6098
|
-
}
|
|
6099
|
-
catch {
|
|
6100
|
-
// Session not available
|
|
6101
|
-
}
|
|
6102
|
-
if (!resolvedOrgId) {
|
|
6103
|
-
try {
|
|
6104
|
-
const { getOrgContext } = await import("../org/context.js");
|
|
6105
|
-
const ctx = await getOrgContext(event);
|
|
6106
|
-
resolvedOrgId = ctx.orgId ?? undefined;
|
|
6107
|
-
}
|
|
6108
|
-
catch {
|
|
6109
|
-
// org_members table may not exist yet on first boot
|
|
6110
|
-
}
|
|
6111
|
-
}
|
|
6112
|
-
}
|
|
6113
|
-
// Cookieless durable background worker: getSession()/getOrgContext()
|
|
6114
|
-
// resolve from the (absent) session, so org-scoped credential resolution
|
|
6115
|
-
// (the Builder engine) would miss the owner's org and resolveEngine would
|
|
6116
|
-
// fall back to the anthropic default — bailing on a missing key before
|
|
6117
|
-
// the worker claims its run. The owner IS known here (seeded via
|
|
6118
|
-
// OWNER_CONTEXT_KEY from the run's thread), so resolve the org directly
|
|
6119
|
-
// from the owner email, the same active-org logic the foreground session
|
|
6120
|
-
// would yield.
|
|
6121
|
-
if (!resolvedOrgId && owner) {
|
|
6122
|
-
try {
|
|
6123
|
-
const { resolveOrgIdForEmail } = await import("../org/context.js");
|
|
6124
|
-
resolvedOrgId = (await resolveOrgIdForEmail(owner)) ?? undefined;
|
|
6125
|
-
}
|
|
6126
|
-
catch {
|
|
6127
|
-
// org tables unavailable — proceed without org (foreground-equivalent)
|
|
6128
|
-
}
|
|
6129
|
-
}
|
|
6130
|
-
// DURABLE OWNER CONTEXT, PART 2: ORG.
|
|
6131
|
-
// The cookieless `_process-run` self-dispatch (and any other background
|
|
6132
|
-
// re-entry) resolves the owner from the run row, but has NO session —
|
|
6133
|
-
// every org resolver above ultimately derives identity from
|
|
6134
|
-
// getSession(event), so they all come back null here. That silently
|
|
6135
|
-
// scopes the agent to `org_id IS NULL` rows only: it sees and writes
|
|
6136
|
-
// resources outside the user's org, while the foreground UI — which
|
|
6137
|
-
// carries the session cookie — resolves the real org. The result is the
|
|
6138
|
-
// observed split where the agent can't list/read the same resources the
|
|
6139
|
-
// UI shows and writes new rows with a null org. Resolve the org from the
|
|
6140
|
-
// now-known owner email (the same active-org / membership logic
|
|
6141
|
-
// getOrgContext uses, minus the session) so the agent and the UI operate
|
|
6142
|
-
// over the same org-scoped data.
|
|
6143
|
-
if (!resolvedOrgId && owner && !ownerContext.anonymous) {
|
|
6144
|
-
try {
|
|
6145
|
-
const { resolveOrgIdForEmail } = await import("../org/context.js");
|
|
6146
|
-
resolvedOrgId = (await resolveOrgIdForEmail(owner)) ?? undefined;
|
|
6147
|
-
}
|
|
6148
|
-
catch {
|
|
6149
|
-
// org tables unavailable (first boot) — leave org unscoped
|
|
6150
|
-
}
|
|
6151
|
-
}
|
|
6152
|
-
// Propagate the caller's IANA timezone from `x-user-timezone` so that
|
|
6153
|
-
// tool calls made by the agent (e.g. log-meal with no explicit date)
|
|
6154
|
-
// resolve "today" in the user's local timezone instead of server UTC.
|
|
6155
|
-
const tzRaw = getHeader(event, "x-user-timezone");
|
|
6156
|
-
const timezone = typeof tzRaw === "string" &&
|
|
6157
|
-
tzRaw.trim().length > 0 &&
|
|
6158
|
-
tzRaw.trim().length < 64
|
|
6159
|
-
? tzRaw.trim()
|
|
6160
|
-
: undefined;
|
|
6161
|
-
return runWithRequestContext({
|
|
6162
|
-
userEmail: owner,
|
|
6163
|
-
userName: ownerContext.name,
|
|
6164
|
-
orgId: resolvedOrgId,
|
|
6165
|
-
timezone,
|
|
6098
|
+
return runWithAgentRunContext({
|
|
6099
|
+
event,
|
|
6100
|
+
ownerContext,
|
|
6101
|
+
resolveOrgId: options?.resolveOrgId,
|
|
6102
|
+
isBackgroundWorker: Boolean(event.context?.__agentChatBackgroundBody),
|
|
6166
6103
|
}, () => {
|
|
6167
6104
|
// App-rendered chat can't host direct code edits — HMR/full
|
|
6168
6105
|
// reloads would kill the same chat surface mid-run. Force the
|
|
@@ -6256,51 +6193,29 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6256
6193
|
// is already consumed, so the handler reads this instead.
|
|
6257
6194
|
event.context = event.context ?? {};
|
|
6258
6195
|
event.context.__agentChatBackgroundBody = prepared.body;
|
|
6259
|
-
//
|
|
6260
|
-
// the
|
|
6261
|
-
//
|
|
6262
|
-
//
|
|
6263
|
-
//
|
|
6264
|
-
|
|
6265
|
-
// circuit-breaker's inline recovery). The run's chat thread already
|
|
6266
|
-
// records the authenticated owner (written by the foreground under the
|
|
6267
|
-
// signed-in user), so resolve the owner from the run row — NOT from the
|
|
6268
|
-
// request body, which the HMAC does not cover and a caller could forge —
|
|
6269
|
-
// and pre-seed the owner context the handler reads (resolveOwnerContext
|
|
6270
|
-
// returns it before attempting any session lookup).
|
|
6271
|
-
let backgroundOwner = null;
|
|
6272
|
-
try {
|
|
6273
|
-
const { getRunOwnerEmail } = await import("../agent/run-store.js");
|
|
6274
|
-
backgroundOwner = await getRunOwnerEmail(prepared.runId);
|
|
6275
|
-
if (backgroundOwner) {
|
|
6276
|
-
event.context[OWNER_CONTEXT_KEY] = {
|
|
6277
|
-
owner: backgroundOwner,
|
|
6278
|
-
anonymous: false,
|
|
6279
|
-
};
|
|
6280
|
-
}
|
|
6281
|
-
}
|
|
6282
|
-
catch {
|
|
6283
|
-
// Best-effort: if the lookup fails, resolveOwnerContext runs as before
|
|
6284
|
-
// and throws its normal 401, surfaced via the route_threw diagnostic.
|
|
6285
|
-
}
|
|
6196
|
+
// Durable owner context: this self-dispatch is cookieless (HMAC-only).
|
|
6197
|
+
// Resolve the owner from the persisted run row, never the request body,
|
|
6198
|
+
// then invoke the normal handler. The shared agent-run context helper
|
|
6199
|
+
// expands that owner into the same user/org AsyncLocalStorage context the
|
|
6200
|
+
// foreground request uses, so credential and data scoping stay aligned.
|
|
6201
|
+
await seedBackgroundAgentRunOwnerContext(event, prepared.runId);
|
|
6286
6202
|
try {
|
|
6287
|
-
|
|
6288
|
-
// Seeding OWNER_CONTEXT_KEY (above) only feeds getOwnerFromEvent; the
|
|
6289
|
-
// engine-resolution path (detectEngineFromUserSecrets) and other
|
|
6290
|
-
// owner-scoped reads use getRequestUserEmail()/getRequestOrgId(),
|
|
6291
|
-
// which a cookieless background worker otherwise leaves empty. Without
|
|
6292
|
-
// this, resolveEngine can't see the owner's Builder credential, falls
|
|
6293
|
-
// back to the anthropic default, and — when the owner has no stored
|
|
6294
|
-
// anthropic key and deploy-credential fallback is blocked — bails at
|
|
6295
|
-
// the API-key check BEFORE claiming its run (the analytics durable
|
|
6296
|
-
// worker's "stalls at post_model, never claims" bug).
|
|
6297
|
-
const invoke = () => invokeAgentChatHandler(event);
|
|
6298
|
-
return await (backgroundOwner
|
|
6299
|
-
? runWithRequestContext({ userEmail: backgroundOwner }, invoke)
|
|
6300
|
-
: invoke());
|
|
6203
|
+
return await invokeAgentChatHandler(event);
|
|
6301
6204
|
}
|
|
6302
6205
|
catch (err) {
|
|
6303
6206
|
console.error("[agent-chat] _process-run failed:", err);
|
|
6207
|
+
captureError(err, {
|
|
6208
|
+
route: AGENT_CHAT_PROCESS_RUN_PATH,
|
|
6209
|
+
method: getMethod(event),
|
|
6210
|
+
userAgent: getHeader(event, "user-agent"),
|
|
6211
|
+
tags: {
|
|
6212
|
+
source: "agent-chat-bg-worker",
|
|
6213
|
+
phase: "process-run",
|
|
6214
|
+
},
|
|
6215
|
+
extra: {
|
|
6216
|
+
runId: prepared.runId,
|
|
6217
|
+
},
|
|
6218
|
+
});
|
|
6304
6219
|
// DIAGNOSTIC: the worker invocation threw at the route boundary —
|
|
6305
6220
|
// record the message so the failure cause is readable client-side.
|
|
6306
6221
|
if (diag) {
|