@agent-native/core 0.114.9 → 0.114.10
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/engine/ai-sdk-engine.ts +31 -3
- package/corpus/core/src/agent/engine/anthropic-engine.ts +20 -3
- package/corpus/core/src/agent/engine/builder-engine.ts +56 -9
- package/corpus/core/src/agent/engine/first-event-timeout.ts +64 -0
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -3
- package/corpus/core/src/client/AssistantChat.tsx +7 -3
- package/corpus/core/src/client/resources/ResourcesPanel.tsx +1 -1
- package/corpus/core/src/integrations/computer-supervision-store.ts +4 -4
- package/corpus/core/src/integrations/pending-tasks-store.ts +1 -1
- package/corpus/core/src/integrations/remote-commands-store.ts +5 -5
- package/corpus/core/src/integrations/remote-devices-store.ts +3 -3
- package/corpus/core/src/integrations/remote-push-store.ts +3 -3
- package/corpus/core/src/observability/traces.ts +38 -1
- package/corpus/core/src/server/action-routes.ts +23 -1
- package/corpus/core/src/server/http-response-telemetry.ts +6 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/corpus/templates/analytics/actions/account-deep-dive.ts +41 -6
- package/corpus/templates/analytics/changelog/2026-07-20-account-deep-dives-finish-with-partial-data-when-hubspot-lo.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-20-dashboard-email-reports-now-include-an-image-when-a-single-p.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +11 -3
- package/corpus/templates/calendar/actions/create-event.ts +5 -0
- package/corpus/templates/calendar/app/components/ThemeToggle.tsx +4 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +0 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +309 -421
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +349 -0
- package/corpus/templates/calendar/app/i18n-data.ts +110 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +6 -0
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +3 -0
- package/corpus/templates/calendar/app/root.tsx +4 -2
- package/corpus/templates/calendar/changelog/2026-07-20-events-can-be-updated-inline-with-date-time-timezone-and-rep.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-20-public-booking-pages-no-longer-hydrate-with-a-theme-mismatch.md +6 -0
- package/corpus/templates/calendar/shared/api.ts +1 -0
- package/corpus/templates/clips/AGENTS.md +7 -0
- package/corpus/templates/clips/actions/create-recording.ts +51 -10
- package/corpus/templates/clips/actions/get-recording-player-data.ts +34 -5
- package/corpus/templates/clips/actions/lib/transcript-preview.ts +48 -0
- package/corpus/templates/clips/actions/list-recordings.ts +15 -4
- package/corpus/templates/clips/actions/regenerate-summary.ts +32 -0
- package/corpus/templates/clips/actions/search-recordings.ts +28 -6
- package/corpus/templates/clips/actions/view-screen.ts +54 -47
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -5
- package/corpus/templates/clips/app/components/library/recording-card.tsx +29 -32
- package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +13 -0
- package/corpus/templates/clips/changelog/2026-07-20-agent-summaries-use-bounded-transcript-context.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-clip-summaries-now-finish-without-sending-a-long-transcript-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-clips-agents-only-discover-recordings-you-own-or-have-alread.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-hosted-recordings-no-longer-start-with-an-impossible-buffered-upload.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-meeting-recordings-now-offer-a-cleaner-transcript-view-with-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-shared-clips-can-be-shared-with-limited-access-and-cards-sho.md +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +12 -8
- package/corpus/templates/clips/desktop/src/overlays/pill-logo.tsx +2 -15
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +107 -340
- package/corpus/templates/clips/desktop/src/styles.css +27 -145
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +6 -7
- package/corpus/templates/clips/server/lib/agent-recording-access.ts +73 -0
- package/corpus/templates/clips/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +18 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +10 -11
- package/corpus/templates/plan/changelog/2026-07-20-bridged-local-plans-now-load-comments-from-the-local-workspace.md +6 -0
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +27 -4
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +19 -4
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +40 -7
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/first-event-timeout.d.ts +25 -0
- package/dist/agent/engine/first-event-timeout.d.ts.map +1 -0
- package/dist/agent/engine/first-event-timeout.js +49 -0
- package/dist/agent/engine/first-event-timeout.js.map +1 -0
- package/dist/cli/pr-visual-recap-workflow.d.ts +2 -2
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +2 -2
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +7 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +1 -1
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/integrations/computer-supervision-store.js +4 -4
- package/dist/integrations/computer-supervision-store.js.map +1 -1
- package/dist/integrations/pending-tasks-store.js +1 -1
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/remote-commands-store.js +5 -5
- package/dist/integrations/remote-commands-store.js.map +1 -1
- package/dist/integrations/remote-devices-store.js +3 -3
- package/dist/integrations/remote-devices-store.js.map +1 -1
- package/dist/integrations/remote-push-store.js +3 -3
- package/dist/integrations/remote-push-store.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +23 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +23 -1
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/http-response-telemetry.d.ts +2 -0
- package/dist/server/http-response-telemetry.d.ts.map +1 -1
- package/dist/server/http-response-telemetry.js +5 -1
- package/dist/server/http-response-telemetry.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/package.json +2 -2
- package/src/agent/engine/ai-sdk-engine.ts +31 -3
- package/src/agent/engine/anthropic-engine.ts +20 -3
- package/src/agent/engine/builder-engine.ts +56 -9
- package/src/agent/engine/first-event-timeout.ts +64 -0
- package/src/cli/pr-visual-recap-workflow.ts +2 -3
- package/src/client/AssistantChat.tsx +7 -3
- package/src/client/resources/ResourcesPanel.tsx +1 -1
- package/src/integrations/computer-supervision-store.ts +4 -4
- package/src/integrations/pending-tasks-store.ts +1 -1
- package/src/integrations/remote-commands-store.ts +5 -5
- package/src/integrations/remote-devices-store.ts +3 -3
- package/src/integrations/remote-push-store.ts +3 -3
- package/src/observability/traces.ts +38 -1
- package/src/server/action-routes.ts +23 -1
- package/src/server/http-response-telemetry.ts +6 -1
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder-engine.js","sourceRoot":"","sources":["../../../src/agent/engine/builder-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * BuilderEngine — HTTP client for the Builder.io managed LLM gateway.\n *\n * The gateway accepts an Anthropic-shaped request body and streams events as\n * JSONL. This engine translates the framework's EngineStreamOptions into the\n * gateway request, parses the streamed events into EngineEvent items, and\n * maps gateway error responses (402 quota, 403 disabled, 401 auth, 429\n * concurrency) into structured stop events that carry an upgrade URL when\n * the chat UI needs to prompt the user to upgrade.\n *\n * Credentials come from BUILDER_PRIVATE_KEY + BUILDER_PUBLIC_KEY (set via the\n * Builder CLI-auth onboarding flow). Base URL is overridable via\n * BUILDER_GATEWAY_BASE_URL.\n */\n\nimport { captureError } from \"../../server/capture-error.js\";\nimport {\n clearBuilderCredentialAuthFailure,\n resolveBuilderCredentials,\n getBuilderGatewayBaseUrl,\n recordBuilderCredentialAuthFailure,\n} from \"../../server/credential-provider.js\";\nimport {\n normalizeReasoningEffortForModel,\n type ReasoningEffort,\n} from \"../../shared/reasoning-effort.js\";\nimport { isInBackgroundFunctionRuntime } from \"../durable-background.js\";\nimport { BUILDER_MODEL_CONFIG } from \"../model-config.js\";\nimport { getBuilderGatewayRequestHeaders } from \"./builder-gateway-headers.js\";\nimport {\n LLM_MISSING_CREDENTIALS_ERROR_CODE,\n LLM_MISSING_CREDENTIALS_MESSAGE,\n} from \"./credential-errors.js\";\nimport { resolveMaxOutputTokensForEngine } from \"./output-tokens.js\";\nimport {\n engineMessagesToBuilderGatewayAnthropic,\n engineToolsToAnthropic,\n} from \"./translate-anthropic.js\";\nimport type {\n AgentEngine,\n EngineCapabilities,\n EngineContentPart,\n EngineEvent,\n EngineStreamOptions,\n} from \"./types.js\";\n\nexport const BUILDER_CAPABILITIES: EngineCapabilities = {\n thinking: true,\n promptCaching: true,\n vision: true,\n computerUse: false,\n parallelToolCalls: true,\n};\n\nexport const BUILDER_SUPPORTED_MODELS = BUILDER_MODEL_CONFIG.supportedModels;\n\n// Keep the foreground hosted gateway timeout below the synchronous serverless\n// wall so the agent loop can append a continuation and persist terminal state\n// before the host hard-kills the invocation.\nconst DEFAULT_BUILDER_GATEWAY_TIMEOUT_MS = 45_000;\nconst MAX_HOSTED_FOREGROUND_BUILDER_GATEWAY_TIMEOUT_MS = 45_000;\n/**\n * Netlify background functions have a 15-minute wall. Keep the Builder gateway\n * ceiling below that, but above the run-manager's 13-minute soft-timeout so\n * durable background runs checkpoint before this timer wins.\n */\nconst MAX_BACKGROUND_BUILDER_GATEWAY_TIMEOUT_MS = 14 * 60_000;\n/** Local and non-hosted runtimes have no synchronous serverless wall. */\nconst MAX_LOCAL_BUILDER_GATEWAY_TIMEOUT_MS =\n MAX_BACKGROUND_BUILDER_GATEWAY_TIMEOUT_MS;\nconst BUILDER_GATEWAY_NETWORK_ERROR_CODE = \"builder_gateway_network_error\";\n\nexport const BUILDER_DEFAULT_MODEL = BUILDER_MODEL_CONFIG.defaultModel;\n\n/**\n * Bucket an Anthropic `thinking.budgetTokens` value into the gateway's\n * legacy three-level `reasoning_effort` enum.\n *\n * The thresholds are chosen to align with typical Anthropic extended-thinking\n * budgets we see in the wild:\n * • < 2000 → short one-step reasoning (\"low\")\n * • 2000–8000 → multi-step thinking (\"medium\")\n * • ≥ 8000 → deep planning / long chains (\"high\")\n *\n * 8000 is Anthropic's documented default in our framework (see\n * engine/types.ts:195), so callers that don't explicitly set\n * `budgetTokens` map to \"high\" via the default. If the gateway later\n * exposes more granular knobs or different thresholds, revisit this map.\n */\nfunction mapReasoningEffort(budgetTokens: number): ReasoningEffort {\n if (budgetTokens < 2000) return \"low\";\n if (budgetTokens < 8000) return \"medium\";\n return \"high\";\n}\n\n/**\n * Build the URL the chat UI should link to when a user hits a quota error.\n *\n * We can't deep-link to a per-org billing page from `BUILDER_ORG_NAME` because\n * that field is the org's display name (e.g. \"Nicholas kipchumba Space\"), not\n * a URL-safe slug or id. URL-encoding the display name produces segments like\n * `/app/organizations/Nicholas%20kipchumba%20Space/billing` which Builder's\n * router treats as unknown and silently bounces to `/app/projects`. The\n * Builder CLI-auth callback doesn't expose the org slug/id today, so we route\n * to the org-agnostic subscription page. Agent Native attribution lets Builder\n * skip generic onboarding for new users who land there from an upgrade CTA.\n */\nasync function buildUpgradeUrl(): Promise<string> {\n const url = new URL(\"https://builder.io/account/subscription\");\n url.searchParams.set(\"signupSource\", \"agent-native\");\n url.searchParams.set(\"agentNativeConnectSource\", \"gateway_quota_upgrade\");\n url.searchParams.set(\"agentNativeFlow\", \"connect_llm\");\n url.searchParams.set(\"framework\", \"agent-native\");\n return url.toString();\n}\n\ninterface GatewayErrorBody {\n code?: string;\n message?: string;\n usageInfo?: {\n plan?: string;\n limitExceeded?: string;\n isEnterprise?: boolean;\n };\n}\n\nclass BuilderEngine implements AgentEngine {\n readonly name = \"builder\";\n readonly label = \"Builder.io Gateway\";\n readonly defaultModel = BUILDER_DEFAULT_MODEL;\n readonly supportedModels = BUILDER_SUPPORTED_MODELS;\n readonly capabilities = BUILDER_CAPABILITIES;\n\n async *stream(opts: EngineStreamOptions): AsyncIterable<EngineEvent> {\n const creds = await resolveBuilderCredentials();\n const authHeader = creds.privateKey ? `Bearer ${creds.privateKey}` : null;\n const spaceId = creds.publicKey;\n const builderUserId = creds.userId;\n if (!authHeader || !spaceId) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: LLM_MISSING_CREDENTIALS_MESSAGE,\n errorCode: LLM_MISSING_CREDENTIALS_ERROR_CODE,\n };\n return;\n }\n\n const messages = engineMessagesToBuilderGatewayAnthropic(opts.messages);\n const tools = engineToolsToAnthropic(opts.tools);\n const thinkingBudget =\n opts.providerOptions?.anthropic?.thinking?.budgetTokens;\n const reasoningEffort = normalizeReasoningEffortForModel(\n opts.model,\n opts.reasoningEffort ??\n (typeof thinkingBudget === \"number\"\n ? mapReasoningEffort(thinkingBudget)\n : undefined),\n );\n\n // Apply prompt caching to system + tools (stable prefix) and to the last\n // user message (moving cache breakpoint so growing history gets cached\n // across tool-loop iterations at ~90% off input cost).\n // Templates can opt out by setting providerOptions.anthropic.cacheControl=false.\n const cacheEnabled =\n opts.providerOptions?.anthropic?.cacheControl !== false;\n\n // System: wrap in array with cache_control when caching is on.\n const systemValue: unknown = opts.systemPrompt\n ? cacheEnabled\n ? [\n {\n type: \"text\",\n text: opts.systemPrompt,\n cache_control: { type: \"ephemeral\" },\n },\n ]\n : opts.systemPrompt\n : undefined;\n\n // Tools: add cache_control to the last tool definition.\n let cachedTools = tools;\n if (cacheEnabled && tools.length > 0) {\n cachedTools = [...tools];\n const last = { ...cachedTools[cachedTools.length - 1] } as any;\n last.cache_control = { type: \"ephemeral\" };\n cachedTools[cachedTools.length - 1] = last;\n }\n\n // Messages: add a moving cache breakpoint on the last user message's last\n // content block so the entire conversation prefix is cached.\n let cachedMessages = messages;\n if (cacheEnabled && messages.length > 0) {\n let lastUserIdx = -1;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if ((messages[i] as any).role === \"user\") {\n lastUserIdx = i;\n break;\n }\n }\n if (lastUserIdx >= 0) {\n cachedMessages = [...messages];\n const lastMsg = { ...cachedMessages[lastUserIdx] } as any;\n if (Array.isArray(lastMsg.content) && lastMsg.content.length > 0) {\n const content = [...lastMsg.content];\n const lastBlock = { ...content[content.length - 1] } as any;\n lastBlock.cache_control = { type: \"ephemeral\" };\n content[content.length - 1] = lastBlock;\n lastMsg.content = content;\n cachedMessages[lastUserIdx] = lastMsg;\n }\n }\n }\n\n const body: Record<string, unknown> = {\n model: opts.model,\n messages: cachedMessages,\n ...(systemValue !== undefined ? { system: systemValue } : {}),\n ...(cachedTools.length > 0 ? { tools: cachedTools } : {}),\n max_tokens: resolveMaxOutputTokensForEngine(\n this.name,\n opts.maxOutputTokens,\n opts.model,\n ),\n ...(typeof opts.temperature === \"number\"\n ? { temperature: opts.temperature }\n : {}),\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n };\n\n const gatewayBaseUrl = getBuilderGatewayBaseUrl();\n const gatewayUrl = new URL(\n \"messages\",\n gatewayBaseUrl.endsWith(\"/\") ? gatewayBaseUrl : `${gatewayBaseUrl}/`,\n );\n gatewayUrl.searchParams.set(\"apiKey\", spaceId);\n const orgLabel = creds.orgName || \"unknown-org\";\n const tStart = Date.now();\n console.log(\n `[builder-engine] → POST ${gatewayUrl.origin}${gatewayUrl.pathname} model=${opts.model} tools=${tools.length} org=${orgLabel}`,\n );\n\n const gatewayTimeoutMs = getBuilderGatewayTimeoutMs();\n const gatewayAbort = createGatewayAbortSignal(\n opts.abortSignal,\n gatewayTimeoutMs,\n );\n try {\n let response: Response;\n try {\n response = await fetch(gatewayUrl.toString(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: authHeader,\n \"x-builder-api-key\": spaceId,\n ...getBuilderGatewayRequestHeaders(),\n ...(builderUserId ? { \"x-builder-user-id\": builderUserId } : {}),\n },\n body: JSON.stringify(body),\n signal: gatewayAbort.signal,\n });\n } catch (err) {\n const timedOut = gatewayAbort.didTimeout();\n if (gatewayAbort.didTimeout()) {\n console.warn(\n `[builder-engine] gateway timed out after ${Date.now() - tStart}ms`,\n );\n }\n if (timedOut || isBuilderGatewayNetworkError(err)) {\n captureBuilderGatewayTransportError(err, {\n phase: \"request\",\n model: opts.model,\n gatewayUrl,\n timeoutMs: gatewayTimeoutMs,\n timedOut,\n elapsedMs: Date.now() - tStart,\n });\n }\n yield createBuilderGatewayTimeoutStop(err, timedOut, gatewayTimeoutMs);\n return;\n }\n\n console.log(\n `[builder-engine] ← ${response.status} ${response.statusText} in ${Date.now() - tStart}ms`,\n );\n\n if (!response.ok) {\n yield* emitHttpError(response);\n return;\n }\n\n // A successful gateway call proves the connected credentials are valid\n // again. Clear any prior auth-failure marker so status / chat-card\n // surfaces stop flagging the connection as broken. This is the only\n // self-healing path for workspace/env-managed credentials, which never\n // flow through writeBuilderCredentials.\n try {\n const creds = await resolveBuilderCredentials();\n await clearBuilderCredentialAuthFailure({\n privateKey: creds.privateKey,\n publicKey: creds.publicKey,\n });\n } catch {\n // Marker clearing is best-effort; a stale marker just means the user\n // sees \"reconnect Builder\" until the next successful call clears it.\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/html\")) {\n const rawText = await response.text().catch(() => \"\");\n yield {\n type: \"stop\",\n reason: \"error\",\n error: normalizeGatewayErrorText(rawText, response.status || 502),\n errorCode: `http_${response.status || 502}`,\n };\n return;\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder gateway response has no body\",\n };\n return;\n }\n\n yield* parseJsonlStream(reader, opts.model, {\n abortSignal: gatewayAbort.signal,\n didGatewayTimeout: gatewayAbort.didTimeout,\n gatewayTimeoutMs,\n gatewayUrl,\n requestStartedAt: tStart,\n });\n } finally {\n gatewayAbort.cleanup();\n }\n }\n}\n\nasync function* emitHttpError(response: Response): AsyncIterable<EngineEvent> {\n const status = response.status;\n // Read the body once as text and then try to parse — calling `.json()`\n // and then `.text()` as a fallback fails because the body stream is\n // already consumed (TypeError: Body has already been read), so we'd\n // silently lose non-JSON error payloads like HTML proxy 502s.\n let errBody: GatewayErrorBody = {};\n const rawText = await response.text().catch(() => \"\");\n if (rawText) {\n try {\n errBody = JSON.parse(rawText) as GatewayErrorBody;\n } catch {\n errBody.message = normalizeGatewayErrorText(rawText, status);\n }\n }\n const code = errBody.code ?? `http_${status}`;\n const message = errBody.message ?? `Builder gateway returned ${status}`;\n\n // Belt-and-suspenders: 402 without a structured `credits-limit` code\n // (e.g. bare proxy response) still means quota → show upgrade CTA.\n if (code.startsWith(\"credits-limit\") || status === 402) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n upgradeUrl: await buildUpgradeUrl(),\n };\n return;\n }\n if (code === \"gateway_not_enabled\") {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n return;\n }\n if (status === 401 || code === \"unauthorized\") {\n await recordBuilderCredentialAuthFailure({ status, code, message });\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder authentication failed. Reconnect Builder via Settings.\",\n errorCode: \"builder_auth_error\",\n };\n return;\n }\n if (status === 403 && isBuilderCredentialAuthError(message)) {\n await recordBuilderCredentialAuthFailure({ status, code, message });\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder authentication failed. Reconnect Builder via Settings.\",\n errorCode: \"builder_auth_error\",\n };\n return;\n }\n if (status === 403) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n return;\n }\n if (code === \"rate_limit_exceeded\") {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n return;\n }\n if (status === 429 || code === \"too_many_concurrent_requests\") {\n // Include \"too many requests\" in the message so production-agent's\n // isRetryableError picks up transient concurrency throttles and retries\n // the turn. Daily gateway caps use `rate_limit_exceeded` above and must\n // not loop.\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `${message} (too many requests)`,\n errorCode: code,\n };\n return;\n }\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n}\n\n// Yields one non-empty JSONL line at a time. Flushes any trailing content\n// after the stream ends so a final event without a newline terminator\n// isn't silently dropped — some gateway proxies close the connection on\n// a complete line and the client must still process it.\nasync function* readJsonlLines(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n abortSignal?: AbortSignal,\n): AsyncIterable<string> {\n const decoder = new TextDecoder();\n let buffer = \"\";\n while (true) {\n const { done, value } = await readStreamChunk(reader, abortSignal);\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let newlineIdx = buffer.indexOf(\"\\n\");\n while (newlineIdx !== -1) {\n const line = buffer.slice(0, newlineIdx).trim();\n buffer = buffer.slice(newlineIdx + 1);\n newlineIdx = buffer.indexOf(\"\\n\");\n if (line) yield line;\n }\n }\n // Flush any bytes the streaming decoder buffered for an incomplete multibyte\n // sequence at the end of the stream; otherwise a trailing multibyte char in\n // the final chunk is silently dropped from the last line.\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) yield tail;\n}\n\nasync function* parseJsonlStream(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n model: string,\n captureContext: {\n abortSignal?: AbortSignal;\n didGatewayTimeout?: () => boolean;\n gatewayTimeoutMs?: number;\n gatewayUrl?: URL;\n requestStartedAt?: number;\n } = {},\n): AsyncIterable<EngineEvent> {\n const gatewayTimeoutMs =\n captureContext.gatewayTimeoutMs ?? DEFAULT_BUILDER_GATEWAY_TIMEOUT_MS;\n const parts: EngineContentPart[] = [];\n let pendingText = \"\";\n let pendingThinking: { text: string; signature?: string } | null = null;\n\n const flushPendingText = () => {\n if (pendingText) {\n parts.push({ type: \"text\", text: pendingText });\n pendingText = \"\";\n }\n };\n\n const flushPendingThinking = () => {\n if (pendingThinking) {\n parts.push({\n type: \"thinking\",\n text: pendingThinking.text,\n ...(pendingThinking.signature !== undefined\n ? { signature: pendingThinking.signature }\n : {}),\n });\n pendingThinking = null;\n }\n };\n\n const flushPending = () => {\n flushPendingText();\n flushPendingThinking();\n };\n\n try {\n for await (const line of readJsonlLines(\n reader,\n captureContext.abortSignal,\n )) {\n let event: any;\n try {\n event = JSON.parse(line);\n } catch {\n const normalized = normalizeGatewayErrorText(line, 502);\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `Builder gateway returned invalid JSONL: ${normalized.slice(\n 0,\n 240,\n )}`,\n errorCode: \"http_502\",\n };\n return;\n }\n\n switch (event.type) {\n case \"text-delta\": {\n const text = event.text ?? \"\";\n flushPendingThinking();\n pendingText += text;\n yield { type: \"text-delta\", text };\n break;\n }\n\n case \"thinking-delta\":\n case \"reasoning-delta\": {\n const text = event.text ?? \"\";\n flushPendingText();\n if (!pendingThinking) pendingThinking = { text: \"\" };\n pendingThinking.text += text;\n if (event.signature) pendingThinking.signature = event.signature;\n yield {\n type: \"thinking-delta\",\n text,\n ...(event.signature ? { signature: event.signature } : {}),\n };\n break;\n }\n\n case \"tool-call-delta\":\n yield {\n type: \"tool-input-delta\",\n id: event.id,\n name: event.name,\n text:\n typeof event.argsTextDelta === \"string\"\n ? event.argsTextDelta\n : typeof event.delta === \"string\"\n ? event.delta\n : \"\",\n };\n break;\n\n case \"heartbeat\":\n yield { type: \"gateway-heartbeat\" };\n break;\n\n case \"tool-call\": {\n flushPending();\n parts.push({\n type: \"tool-call\",\n id: event.id,\n name: event.name,\n input: event.input,\n });\n yield {\n type: \"tool-call\",\n id: event.id,\n name: event.name,\n input: event.input,\n };\n break;\n }\n\n case \"usage\": {\n const cacheWrite =\n (event.cacheCreatedTokens ?? 0) + (event.cacheCreated1hTokens ?? 0);\n yield {\n type: \"usage\",\n inputTokens: event.inputTokens ?? 0,\n outputTokens: event.outputTokens ?? 0,\n ...(event.cacheInputTokens !== undefined\n ? { cacheReadTokens: event.cacheInputTokens }\n : {}),\n ...(cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n };\n break;\n }\n\n case \"stop\": {\n flushPending();\n yield { type: \"assistant-content\", parts };\n\n const reason = event.reason ?? \"end_turn\";\n if (reason === \"rate_limited\") {\n // Include \"rate_limit\" in the message so production-agent's\n // isRetryableError picks it up and retries.\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `rate_limit exceeded: ${event.error ?? \"upstream provider rate limited\"}`,\n errorCode: \"rate_limited\",\n };\n } else if (reason === \"invalid_request\") {\n // errorCode has no retry-trigger keywords, so isRetryableError\n // won't loop on broken history.\n const errMsg =\n event.error ||\n event.message ||\n \"Builder gateway rejected the request as malformed.\";\n const errCode =\n typeof event.errorCode === \"string\"\n ? event.errorCode\n : typeof event.code === \"string\"\n ? event.code\n : \"invalid_request\";\n console.warn(\n `[builder-engine] stop reason=invalid_request model=${model} code=${errCode} error=${errMsg}`,\n );\n yield {\n type: \"stop\",\n reason: \"error\",\n error: errMsg,\n errorCode: errCode,\n };\n } else if (reason === \"error\") {\n // Surface every diagnostic the gateway gave us so the user (and\n // our logs) get more than a bare \"Gateway error\". The gateway\n // sometimes emits an error stop event with no message — most\n // commonly when the upstream provider rejects the model for\n // this account (Opus quotas have hit this in practice).\n const explicitErrMsg = event.error || event.message || event.detail;\n const errMsg =\n explicitErrMsg ??\n `Gateway error (no detail; raw event: ${JSON.stringify(event)})`;\n const gatewayErrCode = event.errorCode ?? event.code;\n const isCredentialAuthError =\n Boolean(explicitErrMsg) &&\n isBuilderCredentialAuthError(String(errMsg));\n // Anthropic's bare \"Connection error.\" often arrives here with no\n // gateway code. Tag it as a network error so in-run retries and\n // run-level resume treat it as transient instead of terminal.\n const isProviderConnectionError =\n typeof explicitErrMsg === \"string\" &&\n isProviderConnectionErrorMessage(String(explicitErrMsg));\n const errCode = isCredentialAuthError\n ? \"builder_auth_error\"\n : isProviderConnectionError\n ? BUILDER_GATEWAY_NETWORK_ERROR_CODE\n : (gatewayErrCode ??\n (!explicitErrMsg ? \"builder_gateway_error\" : undefined));\n console.error(\n `[builder-engine] stop reason=error model=${model} code=${errCode ?? \"(none)\"} error=${errMsg}`,\n );\n if (isCredentialAuthError) {\n await recordBuilderCredentialAuthFailure({\n code:\n typeof gatewayErrCode === \"string\" ? gatewayErrCode : errCode,\n message: String(errMsg),\n });\n }\n // No-detail gateway errors are opaque to the chat client — the\n // only way to debug them is from the gateway side. Capture rich\n // tags here (model, gatewayOrigin, requestId) so the gateway\n // team can search Sentry by requestId or filter by model. The\n // downstream run-manager will also capture the EngineError once\n // it's thrown, but without these tags.\n if (!explicitErrMsg) {\n captureBuilderGatewayNoDetailError({\n requestId:\n typeof event.requestId === \"string\"\n ? event.requestId\n : undefined,\n model,\n gatewayUrl: captureContext.gatewayUrl,\n rawEvent: event,\n });\n }\n yield {\n type: \"stop\",\n reason: \"error\",\n error: errMsg,\n ...(errCode ? { errorCode: errCode } : {}),\n };\n } else if (\n reason === \"end_turn\" ||\n reason === \"tool_use\" ||\n reason === \"max_tokens\" ||\n reason === \"stop_sequence\"\n ) {\n yield { type: \"stop\", reason };\n } else {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `Unknown stop reason: ${reason}`,\n };\n }\n return;\n }\n\n default:\n // Unknown event type — ignore for forward compat.\n break;\n }\n }\n\n // Stream ended without a stop event — synthesize one so callers don't hang.\n flushPending();\n yield { type: \"assistant-content\", parts };\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder gateway stream ended without a stop event\",\n };\n } catch (err) {\n const timedOut = captureContext.didGatewayTimeout?.() ?? false;\n if (timedOut || isBuilderGatewayNetworkError(err)) {\n captureBuilderGatewayTransportError(err, {\n phase: \"stream\",\n model,\n gatewayUrl: captureContext.gatewayUrl,\n timeoutMs: gatewayTimeoutMs,\n timedOut,\n elapsedMs:\n typeof captureContext.requestStartedAt === \"number\"\n ? Date.now() - captureContext.requestStartedAt\n : undefined,\n });\n }\n yield createBuilderGatewayTimeoutStop(err, timedOut, gatewayTimeoutMs);\n } finally {\n // Release the reader on every exit path — early returns (invalid JSONL,\n // stop event) and generator abandonment both leave the underlying\n // Response body locked otherwise. cancel() also closes the socket.\n try {\n await reader.cancel();\n } catch {\n // Already cancelled or closed\n }\n }\n}\n\nfunction readStreamChunk(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n abortSignal?: AbortSignal,\n): Promise<ReadableStreamReadResult<Uint8Array>> {\n if (!abortSignal) return reader.read();\n if (abortSignal.aborted) {\n return Promise.reject(abortSignal.reason ?? new Error(\"Stream aborted\"));\n }\n return new Promise((resolve, reject) => {\n const onAbort = () => {\n reject(abortSignal.reason ?? new Error(\"Stream aborted\"));\n };\n abortSignal.addEventListener(\"abort\", onAbort, { once: true });\n reader.read().then(\n (value) => {\n abortSignal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (err) => {\n abortSignal.removeEventListener(\"abort\", onAbort);\n reject(err);\n },\n );\n });\n}\n\nfunction normalizeGatewayErrorText(raw: string, status: number): string {\n const text = raw.trim();\n const looksHtml = /<html[\\s>]|<body[\\s>]|<head[\\s>]/i.test(text);\n const readable = looksHtml ? htmlToText(text) : text;\n if (/inactivity timeout/i.test(readable)) {\n return `Builder gateway returned ${status}: Inactivity Timeout. The upstream connection was idle too long before sending data.`;\n }\n if (looksHtml) {\n return `Builder gateway returned ${status}: ${readable.slice(0, 240)}`;\n }\n return readable;\n}\n\nfunction htmlToText(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/(p|div|h1|h2|h3|li|tr)>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \" \")\n .replace(/ /gi, \" \")\n .replace(/</gi, \"<\")\n .replace(/>/gi, \">\")\n .replace(/&/gi, \"&\")\n .replace(/"/gi, '\"')\n .replace(/'/gi, \"'\")\n .replace(/[ \\t]+/g, \" \")\n .replace(/\\n\\s+/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nexport function createBuilderEngine(\n _config: Record<string, unknown> = {},\n): AgentEngine {\n return new BuilderEngine();\n}\n\nfunction resolveMaxBuilderGatewayTimeoutMs(): number {\n if (isInBackgroundFunctionRuntime()) {\n return MAX_BACKGROUND_BUILDER_GATEWAY_TIMEOUT_MS;\n }\n\n if (!isHostedBuilderRuntime()) {\n return MAX_LOCAL_BUILDER_GATEWAY_TIMEOUT_MS;\n }\n\n try {\n const base = getBuilderGatewayBaseUrl();\n if (/^https?:\\/\\/(localhost|127\\.0\\.0\\.1)([:/]|$)/i.test(base)) {\n return MAX_LOCAL_BUILDER_GATEWAY_TIMEOUT_MS;\n }\n } catch {\n // ignore malformed override\n }\n return MAX_HOSTED_FOREGROUND_BUILDER_GATEWAY_TIMEOUT_MS;\n}\n\nfunction isHostedBuilderRuntime(): boolean {\n if (\n process.env.NETLIFY &&\n process.env.NETLIFY !== \"false\" &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n if (\n process.env.AWS_LAMBDA_FUNCTION_NAME &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n return Boolean(\n process.env.CF_PAGES ||\n process.env.VERCEL ||\n process.env.VERCEL_ENV ||\n process.env.RENDER ||\n process.env.FLY_APP_NAME ||\n process.env.K_SERVICE,\n );\n}\n\nfunction getBuilderGatewayTimeoutMs(): number {\n const raw = process.env.AGENT_NATIVE_BUILDER_GATEWAY_TIMEOUT_MS;\n const maxMs = resolveMaxBuilderGatewayTimeoutMs();\n if (!raw) return maxMs;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n return maxMs;\n }\n return Math.min(parsed, maxMs);\n}\n\nfunction createGatewayAbortSignal(\n parentSignal: AbortSignal,\n timeoutMs: number,\n): {\n signal: AbortSignal;\n didTimeout: () => boolean;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n let timedOut = false;\n\n const abortFromParent = () => {\n if (!controller.signal.aborted) {\n controller.abort(parentSignal.reason);\n }\n };\n\n const timeout = setTimeout(() => {\n timedOut = true;\n if (!controller.signal.aborted) {\n controller.abort(new Error(\"Builder gateway request timed out\"));\n }\n }, timeoutMs);\n\n if (parentSignal.aborted) abortFromParent();\n parentSignal.addEventListener(\"abort\", abortFromParent, { once: true });\n\n return {\n signal: controller.signal,\n didTimeout: () => timedOut,\n cleanup: () => {\n clearTimeout(timeout);\n parentSignal.removeEventListener(\"abort\", abortFromParent);\n },\n };\n}\n\nfunction isBuilderCredentialAuthError(message: string): boolean {\n const lowerMessage = message.toLowerCase();\n const referencesAccessToken =\n lowerMessage.includes(\"personal access token\") ||\n lowerMessage.includes(\"access token\");\n const rejectedToken =\n lowerMessage.includes(\"invalid\") ||\n lowerMessage.includes(\"inactive\") ||\n lowerMessage.includes(\"expired\") ||\n lowerMessage.includes(\"revoked\");\n return (\n lowerMessage.includes(\"unauthorized\") ||\n lowerMessage.includes(\"private key\") ||\n lowerMessage.includes(\"invalid token\") ||\n lowerMessage.includes(\"invalid_token\") ||\n lowerMessage.includes(\"token invalid\") ||\n (referencesAccessToken && rejectedToken)\n );\n}\n\nfunction normalizeBuilderGatewayFetchError(\n err: unknown,\n timedOut: boolean,\n timeoutMs: number,\n): string {\n if (timedOut) {\n return `Builder gateway timed out after ${formatTimeoutMs(\n timeoutMs,\n )} before the hosting function limit. Please retry; if this keeps happening, reduce the prompt size or try again when the gateway is less busy.`;\n }\n const message = errorMessage(err);\n if (isBuilderGatewayNetworkError(err)) {\n return `Builder gateway network error: ${message}`;\n }\n return message;\n}\n\nfunction createBuilderGatewayTimeoutStop(\n err: unknown,\n timedOut: boolean,\n timeoutMs: number,\n): EngineEvent {\n const networkError = !timedOut && isBuilderGatewayNetworkError(err);\n return {\n type: \"stop\",\n reason: \"error\",\n error: normalizeBuilderGatewayFetchError(err, timedOut, timeoutMs),\n ...(timedOut\n ? { errorCode: \"builder_gateway_timeout\" }\n : networkError\n ? { errorCode: BUILDER_GATEWAY_NETWORK_ERROR_CODE }\n : {}),\n };\n}\n\nfunction formatTimeoutMs(timeoutMs: number): string {\n if (timeoutMs < 1000) return `${timeoutMs}ms`;\n return `${Math.round(timeoutMs / 1000)}s`;\n}\n\nfunction errorMessage(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nfunction errorSearchText(err: unknown): string {\n const parts: string[] = [];\n if (err instanceof Error) {\n parts.push(err.name, err.message);\n const maybe = err as Error & {\n code?: unknown;\n cause?: unknown;\n };\n if (typeof maybe.code === \"string\") parts.push(maybe.code);\n if (maybe.cause) parts.push(errorSearchText(maybe.cause));\n } else {\n parts.push(String(err));\n }\n return parts.join(\" \").toLowerCase();\n}\n\nfunction isBuilderGatewayNetworkError(err: unknown): boolean {\n const text = errorSearchText(err);\n return (\n text.includes(\"socket hang up\") ||\n text.includes(\"econnreset\") ||\n text.includes(\"enetreset\") ||\n text.includes(\"econnaborted\") ||\n text.includes(\"fetch failed\") ||\n text.includes(\"network error\") ||\n // Anthropic SDK's APIConnectionError default (\"Connection error.\") is\n // often forwarded by the Builder gateway as a stop event with no code.\n text.includes(\"connection error\") ||\n text.includes(\"connection reset\") ||\n text.includes(\"connection closed\") ||\n text.includes(\"stream closed\") ||\n text.includes(\"terminated\")\n );\n}\n\nfunction isProviderConnectionErrorMessage(message: string): boolean {\n return message.trim().toLowerCase() === \"connection error.\";\n}\n\nfunction captureBuilderGatewayTransportError(\n err: unknown,\n context: {\n phase: \"request\" | \"stream\";\n model: string;\n gatewayUrl?: URL;\n timeoutMs: number;\n timedOut: boolean;\n elapsedMs?: number;\n },\n): void {\n captureError(err, {\n route: \"/_agent-native/agent-chat\",\n tags: {\n source: \"builder-engine\",\n phase: context.phase,\n model: context.model,\n timedOut: context.timedOut ? \"true\" : \"false\",\n errorCode: context.timedOut\n ? \"builder_gateway_timeout\"\n : BUILDER_GATEWAY_NETWORK_ERROR_CODE,\n },\n extra: {\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n timeoutMs: context.timeoutMs,\n elapsedMs: context.elapsedMs,\n },\n contexts: {\n builderGateway: {\n phase: context.phase,\n model: context.model,\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n timeoutMs: context.timeoutMs,\n timedOut: context.timedOut,\n elapsedMs: context.elapsedMs,\n },\n },\n });\n}\n\n/**\n * Capture a Builder-gateway no-detail stop event to Sentry with the request\n * context the run-manager doesn't have. The gateway emits\n * `{type:\"stop\",reason:\"error\",requestId:\"...\"}` with no diagnostic — the\n * only way to debug it is from the gateway side, so we surface model,\n * gatewayOrigin, and requestId as searchable tags.\n */\nfunction captureBuilderGatewayNoDetailError(context: {\n requestId?: string;\n model: string;\n gatewayUrl?: URL;\n rawEvent: unknown;\n}): void {\n const err = new Error(\n context.requestId\n ? `Builder gateway stop reason=error with no detail (requestId=${context.requestId})`\n : \"Builder gateway stop reason=error with no detail\",\n );\n err.name = \"BuilderGatewayNoDetailError\";\n captureError(err, {\n route: \"/_agent-native/agent-chat\",\n tags: {\n source: \"builder-engine\",\n phase: \"stream\",\n model: context.model,\n errorCode: \"builder_gateway_error\",\n ...(context.requestId ? { gatewayRequestId: context.requestId } : {}),\n },\n extra: {\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n rawEvent: context.rawEvent,\n },\n contexts: {\n builderGateway: {\n phase: \"stream\",\n model: context.model,\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n requestId: context.requestId,\n errorCode: \"builder_gateway_error\",\n },\n },\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"builder-engine.js","sourceRoot":"","sources":["../../../src/agent/engine/builder-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * BuilderEngine — HTTP client for the Builder.io managed LLM gateway.\n *\n * The gateway accepts an Anthropic-shaped request body and streams events as\n * JSONL. This engine translates the framework's EngineStreamOptions into the\n * gateway request, parses the streamed events into EngineEvent items, and\n * maps gateway error responses (402 quota, 403 disabled, 401 auth, 429\n * concurrency) into structured stop events that carry an upgrade URL when\n * the chat UI needs to prompt the user to upgrade.\n *\n * Credentials come from BUILDER_PRIVATE_KEY + BUILDER_PUBLIC_KEY (set via the\n * Builder CLI-auth onboarding flow). Base URL is overridable via\n * BUILDER_GATEWAY_BASE_URL.\n */\n\nimport { captureError } from \"../../server/capture-error.js\";\nimport {\n clearBuilderCredentialAuthFailure,\n resolveBuilderCredentials,\n getBuilderGatewayBaseUrl,\n recordBuilderCredentialAuthFailure,\n} from \"../../server/credential-provider.js\";\nimport {\n normalizeReasoningEffortForModel,\n type ReasoningEffort,\n} from \"../../shared/reasoning-effort.js\";\nimport { isInBackgroundFunctionRuntime } from \"../durable-background.js\";\nimport { BUILDER_MODEL_CONFIG } from \"../model-config.js\";\nimport { getBuilderGatewayRequestHeaders } from \"./builder-gateway-headers.js\";\nimport {\n LLM_MISSING_CREDENTIALS_ERROR_CODE,\n LLM_MISSING_CREDENTIALS_MESSAGE,\n} from \"./credential-errors.js\";\nimport { FIRST_STREAM_EVENT_TIMEOUT_MS } from \"./first-event-timeout.js\";\nimport { resolveMaxOutputTokensForEngine } from \"./output-tokens.js\";\nimport {\n engineMessagesToBuilderGatewayAnthropic,\n engineToolsToAnthropic,\n} from \"./translate-anthropic.js\";\nimport type {\n AgentEngine,\n EngineCapabilities,\n EngineContentPart,\n EngineEvent,\n EngineStreamOptions,\n} from \"./types.js\";\n\nexport const BUILDER_CAPABILITIES: EngineCapabilities = {\n thinking: true,\n promptCaching: true,\n vision: true,\n computerUse: false,\n parallelToolCalls: true,\n};\n\nexport const BUILDER_SUPPORTED_MODELS = BUILDER_MODEL_CONFIG.supportedModels;\n\n// Keep the foreground hosted gateway timeout below the synchronous serverless\n// wall so the agent loop can append a continuation and persist terminal state\n// before the host hard-kills the invocation.\nconst DEFAULT_BUILDER_GATEWAY_TIMEOUT_MS = 45_000;\nconst MAX_HOSTED_FOREGROUND_BUILDER_GATEWAY_TIMEOUT_MS = 45_000;\n/**\n * Netlify background functions have a 15-minute wall. Keep the Builder gateway\n * ceiling below that, but above the run-manager's 13-minute soft-timeout so\n * durable background runs checkpoint before this timer wins.\n */\nconst MAX_BACKGROUND_BUILDER_GATEWAY_TIMEOUT_MS = 14 * 60_000;\n/** Local and non-hosted runtimes have no synchronous serverless wall. */\nconst MAX_LOCAL_BUILDER_GATEWAY_TIMEOUT_MS =\n MAX_BACKGROUND_BUILDER_GATEWAY_TIMEOUT_MS;\nconst BUILDER_GATEWAY_NETWORK_ERROR_CODE = \"builder_gateway_network_error\";\n\nexport const BUILDER_DEFAULT_MODEL = BUILDER_MODEL_CONFIG.defaultModel;\n\n/**\n * Bucket an Anthropic `thinking.budgetTokens` value into the gateway's\n * legacy three-level `reasoning_effort` enum.\n *\n * The thresholds are chosen to align with typical Anthropic extended-thinking\n * budgets we see in the wild:\n * • < 2000 → short one-step reasoning (\"low\")\n * • 2000–8000 → multi-step thinking (\"medium\")\n * • ≥ 8000 → deep planning / long chains (\"high\")\n *\n * 8000 is Anthropic's documented default in our framework (see\n * engine/types.ts:195), so callers that don't explicitly set\n * `budgetTokens` map to \"high\" via the default. If the gateway later\n * exposes more granular knobs or different thresholds, revisit this map.\n */\nfunction mapReasoningEffort(budgetTokens: number): ReasoningEffort {\n if (budgetTokens < 2000) return \"low\";\n if (budgetTokens < 8000) return \"medium\";\n return \"high\";\n}\n\n/**\n * Build the URL the chat UI should link to when a user hits a quota error.\n *\n * We can't deep-link to a per-org billing page from `BUILDER_ORG_NAME` because\n * that field is the org's display name (e.g. \"Nicholas kipchumba Space\"), not\n * a URL-safe slug or id. URL-encoding the display name produces segments like\n * `/app/organizations/Nicholas%20kipchumba%20Space/billing` which Builder's\n * router treats as unknown and silently bounces to `/app/projects`. The\n * Builder CLI-auth callback doesn't expose the org slug/id today, so we route\n * to the org-agnostic subscription page. Agent Native attribution lets Builder\n * skip generic onboarding for new users who land there from an upgrade CTA.\n */\nasync function buildUpgradeUrl(): Promise<string> {\n const url = new URL(\"https://builder.io/account/subscription\");\n url.searchParams.set(\"signupSource\", \"agent-native\");\n url.searchParams.set(\"agentNativeConnectSource\", \"gateway_quota_upgrade\");\n url.searchParams.set(\"agentNativeFlow\", \"connect_llm\");\n url.searchParams.set(\"framework\", \"agent-native\");\n return url.toString();\n}\n\ninterface GatewayErrorBody {\n code?: string;\n message?: string;\n usageInfo?: {\n plan?: string;\n limitExceeded?: string;\n isEnterprise?: boolean;\n };\n}\n\nclass BuilderEngine implements AgentEngine {\n readonly name = \"builder\";\n readonly label = \"Builder.io Gateway\";\n readonly defaultModel = BUILDER_DEFAULT_MODEL;\n readonly supportedModels = BUILDER_SUPPORTED_MODELS;\n readonly capabilities = BUILDER_CAPABILITIES;\n\n async *stream(opts: EngineStreamOptions): AsyncIterable<EngineEvent> {\n const creds = await resolveBuilderCredentials();\n const authHeader = creds.privateKey ? `Bearer ${creds.privateKey}` : null;\n const spaceId = creds.publicKey;\n const builderUserId = creds.userId;\n if (!authHeader || !spaceId) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: LLM_MISSING_CREDENTIALS_MESSAGE,\n errorCode: LLM_MISSING_CREDENTIALS_ERROR_CODE,\n };\n return;\n }\n\n const messages = engineMessagesToBuilderGatewayAnthropic(opts.messages);\n const tools = engineToolsToAnthropic(opts.tools);\n const thinkingBudget =\n opts.providerOptions?.anthropic?.thinking?.budgetTokens;\n const reasoningEffort = normalizeReasoningEffortForModel(\n opts.model,\n opts.reasoningEffort ??\n (typeof thinkingBudget === \"number\"\n ? mapReasoningEffort(thinkingBudget)\n : undefined),\n );\n\n // Apply prompt caching to system + tools (stable prefix) and to the last\n // user message (moving cache breakpoint so growing history gets cached\n // across tool-loop iterations at ~90% off input cost).\n // Templates can opt out by setting providerOptions.anthropic.cacheControl=false.\n const cacheEnabled =\n opts.providerOptions?.anthropic?.cacheControl !== false;\n\n // System: wrap in array with cache_control when caching is on.\n const systemValue: unknown = opts.systemPrompt\n ? cacheEnabled\n ? [\n {\n type: \"text\",\n text: opts.systemPrompt,\n cache_control: { type: \"ephemeral\" },\n },\n ]\n : opts.systemPrompt\n : undefined;\n\n // Tools: add cache_control to the last tool definition.\n let cachedTools = tools;\n if (cacheEnabled && tools.length > 0) {\n cachedTools = [...tools];\n const last = { ...cachedTools[cachedTools.length - 1] } as any;\n last.cache_control = { type: \"ephemeral\" };\n cachedTools[cachedTools.length - 1] = last;\n }\n\n // Messages: add a moving cache breakpoint on the last user message's last\n // content block so the entire conversation prefix is cached.\n let cachedMessages = messages;\n if (cacheEnabled && messages.length > 0) {\n let lastUserIdx = -1;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if ((messages[i] as any).role === \"user\") {\n lastUserIdx = i;\n break;\n }\n }\n if (lastUserIdx >= 0) {\n cachedMessages = [...messages];\n const lastMsg = { ...cachedMessages[lastUserIdx] } as any;\n if (Array.isArray(lastMsg.content) && lastMsg.content.length > 0) {\n const content = [...lastMsg.content];\n const lastBlock = { ...content[content.length - 1] } as any;\n lastBlock.cache_control = { type: \"ephemeral\" };\n content[content.length - 1] = lastBlock;\n lastMsg.content = content;\n cachedMessages[lastUserIdx] = lastMsg;\n }\n }\n }\n\n const body: Record<string, unknown> = {\n model: opts.model,\n messages: cachedMessages,\n ...(systemValue !== undefined ? { system: systemValue } : {}),\n ...(cachedTools.length > 0 ? { tools: cachedTools } : {}),\n max_tokens: resolveMaxOutputTokensForEngine(\n this.name,\n opts.maxOutputTokens,\n opts.model,\n ),\n ...(typeof opts.temperature === \"number\"\n ? { temperature: opts.temperature }\n : {}),\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n };\n\n const gatewayBaseUrl = getBuilderGatewayBaseUrl();\n const gatewayUrl = new URL(\n \"messages\",\n gatewayBaseUrl.endsWith(\"/\") ? gatewayBaseUrl : `${gatewayBaseUrl}/`,\n );\n gatewayUrl.searchParams.set(\"apiKey\", spaceId);\n const orgLabel = creds.orgName || \"unknown-org\";\n const tStart = Date.now();\n console.log(\n `[builder-engine] → POST ${gatewayUrl.origin}${gatewayUrl.pathname} model=${opts.model} tools=${tools.length} org=${orgLabel}`,\n );\n\n const gatewayTimeoutMs = getBuilderGatewayTimeoutMs();\n const gatewayAbort = createGatewayAbortSignal(\n opts.abortSignal,\n gatewayTimeoutMs,\n );\n try {\n let response: Response;\n try {\n response = await fetch(gatewayUrl.toString(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: authHeader,\n \"x-builder-api-key\": spaceId,\n ...getBuilderGatewayRequestHeaders(),\n ...(builderUserId ? { \"x-builder-user-id\": builderUserId } : {}),\n },\n body: JSON.stringify(body),\n signal: gatewayAbort.signal,\n });\n } catch (err) {\n const timedOut = gatewayAbort.didTimeout();\n if (gatewayAbort.didTimeout()) {\n console.warn(\n `[builder-engine] gateway timed out after ${Date.now() - tStart}ms`,\n );\n }\n if (timedOut || isBuilderGatewayNetworkError(err)) {\n captureBuilderGatewayTransportError(err, {\n phase: \"request\",\n model: opts.model,\n gatewayUrl,\n timeoutMs: gatewayAbort.effectiveTimeoutMs(),\n timedOut,\n elapsedMs: Date.now() - tStart,\n });\n }\n yield createBuilderGatewayTimeoutStop(\n err,\n timedOut,\n gatewayAbort.effectiveTimeoutMs(),\n );\n return;\n }\n\n console.log(\n `[builder-engine] ← ${response.status} ${response.statusText} in ${Date.now() - tStart}ms`,\n );\n\n if (!response.ok) {\n yield* emitHttpError(response);\n return;\n }\n\n // A successful gateway call proves the connected credentials are valid\n // again. Clear any prior auth-failure marker so status / chat-card\n // surfaces stop flagging the connection as broken. This is the only\n // self-healing path for workspace/env-managed credentials, which never\n // flow through writeBuilderCredentials.\n try {\n const creds = await resolveBuilderCredentials();\n await clearBuilderCredentialAuthFailure({\n privateKey: creds.privateKey,\n publicKey: creds.publicKey,\n });\n } catch {\n // Marker clearing is best-effort; a stale marker just means the user\n // sees \"reconnect Builder\" until the next successful call clears it.\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/html\")) {\n const rawText = await response.text().catch(() => \"\");\n yield {\n type: \"stop\",\n reason: \"error\",\n error: normalizeGatewayErrorText(rawText, response.status || 502),\n errorCode: `http_${response.status || 502}`,\n };\n return;\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder gateway response has no body\",\n };\n return;\n }\n\n yield* parseJsonlStream(reader, opts.model, {\n abortSignal: gatewayAbort.signal,\n didGatewayTimeout: gatewayAbort.didTimeout,\n getGatewayTimeoutMs: gatewayAbort.effectiveTimeoutMs,\n onFirstEvent: gatewayAbort.markFirstEvent,\n gatewayUrl,\n requestStartedAt: tStart,\n });\n } finally {\n gatewayAbort.cleanup();\n }\n }\n}\n\nasync function* emitHttpError(response: Response): AsyncIterable<EngineEvent> {\n const status = response.status;\n // Read the body once as text and then try to parse — calling `.json()`\n // and then `.text()` as a fallback fails because the body stream is\n // already consumed (TypeError: Body has already been read), so we'd\n // silently lose non-JSON error payloads like HTML proxy 502s.\n let errBody: GatewayErrorBody = {};\n const rawText = await response.text().catch(() => \"\");\n if (rawText) {\n try {\n errBody = JSON.parse(rawText) as GatewayErrorBody;\n } catch {\n errBody.message = normalizeGatewayErrorText(rawText, status);\n }\n }\n const code = errBody.code ?? `http_${status}`;\n const message = errBody.message ?? `Builder gateway returned ${status}`;\n\n // Belt-and-suspenders: 402 without a structured `credits-limit` code\n // (e.g. bare proxy response) still means quota → show upgrade CTA.\n if (code.startsWith(\"credits-limit\") || status === 402) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n upgradeUrl: await buildUpgradeUrl(),\n };\n return;\n }\n if (code === \"gateway_not_enabled\") {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n return;\n }\n if (status === 401 || code === \"unauthorized\") {\n await recordBuilderCredentialAuthFailure({ status, code, message });\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder authentication failed. Reconnect Builder via Settings.\",\n errorCode: \"builder_auth_error\",\n };\n return;\n }\n if (status === 403 && isBuilderCredentialAuthError(message)) {\n await recordBuilderCredentialAuthFailure({ status, code, message });\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder authentication failed. Reconnect Builder via Settings.\",\n errorCode: \"builder_auth_error\",\n };\n return;\n }\n if (status === 403) {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n return;\n }\n if (code === \"rate_limit_exceeded\") {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n return;\n }\n if (status === 429 || code === \"too_many_concurrent_requests\") {\n // Include \"too many requests\" in the message so production-agent's\n // isRetryableError picks up transient concurrency throttles and retries\n // the turn. Daily gateway caps use `rate_limit_exceeded` above and must\n // not loop.\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `${message} (too many requests)`,\n errorCode: code,\n };\n return;\n }\n yield {\n type: \"stop\",\n reason: \"error\",\n error: message,\n errorCode: code,\n };\n}\n\n// Yields one non-empty JSONL line at a time. Flushes any trailing content\n// after the stream ends so a final event without a newline terminator\n// isn't silently dropped — some gateway proxies close the connection on\n// a complete line and the client must still process it.\nasync function* readJsonlLines(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n abortSignal?: AbortSignal,\n): AsyncIterable<string> {\n const decoder = new TextDecoder();\n let buffer = \"\";\n while (true) {\n const { done, value } = await readStreamChunk(reader, abortSignal);\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let newlineIdx = buffer.indexOf(\"\\n\");\n while (newlineIdx !== -1) {\n const line = buffer.slice(0, newlineIdx).trim();\n buffer = buffer.slice(newlineIdx + 1);\n newlineIdx = buffer.indexOf(\"\\n\");\n if (line) yield line;\n }\n }\n // Flush any bytes the streaming decoder buffered for an incomplete multibyte\n // sequence at the end of the stream; otherwise a trailing multibyte char in\n // the final chunk is silently dropped from the last line.\n buffer += decoder.decode();\n const tail = buffer.trim();\n if (tail) yield tail;\n}\n\nasync function* parseJsonlStream(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n model: string,\n captureContext: {\n abortSignal?: AbortSignal;\n didGatewayTimeout?: () => boolean;\n getGatewayTimeoutMs?: () => number;\n onFirstEvent?: () => void;\n gatewayUrl?: URL;\n requestStartedAt?: number;\n } = {},\n): AsyncIterable<EngineEvent> {\n const parts: EngineContentPart[] = [];\n let pendingText = \"\";\n let pendingThinking: { text: string; signature?: string } | null = null;\n\n const flushPendingText = () => {\n if (pendingText) {\n parts.push({ type: \"text\", text: pendingText });\n pendingText = \"\";\n }\n };\n\n const flushPendingThinking = () => {\n if (pendingThinking) {\n parts.push({\n type: \"thinking\",\n text: pendingThinking.text,\n ...(pendingThinking.signature !== undefined\n ? { signature: pendingThinking.signature }\n : {}),\n });\n pendingThinking = null;\n }\n };\n\n const flushPending = () => {\n flushPendingText();\n flushPendingThinking();\n };\n\n try {\n for await (const line of readJsonlLines(\n reader,\n captureContext.abortSignal,\n )) {\n let event: any;\n try {\n event = JSON.parse(line);\n } catch {\n const normalized = normalizeGatewayErrorText(line, 502);\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `Builder gateway returned invalid JSONL: ${normalized.slice(\n 0,\n 240,\n )}`,\n errorCode: \"http_502\",\n };\n return;\n }\n\n // Heartbeats are transport-level keepalives, not proof the model is\n // producing output — every other parsed event counts as first progress.\n if (event?.type !== \"heartbeat\") {\n captureContext.onFirstEvent?.();\n }\n\n switch (event.type) {\n case \"text-delta\": {\n const text = event.text ?? \"\";\n flushPendingThinking();\n pendingText += text;\n yield { type: \"text-delta\", text };\n break;\n }\n\n case \"thinking-delta\":\n case \"reasoning-delta\": {\n const text = event.text ?? \"\";\n flushPendingText();\n if (!pendingThinking) pendingThinking = { text: \"\" };\n pendingThinking.text += text;\n if (event.signature) pendingThinking.signature = event.signature;\n yield {\n type: \"thinking-delta\",\n text,\n ...(event.signature ? { signature: event.signature } : {}),\n };\n break;\n }\n\n case \"tool-call-delta\":\n yield {\n type: \"tool-input-delta\",\n id: event.id,\n name: event.name,\n text:\n typeof event.argsTextDelta === \"string\"\n ? event.argsTextDelta\n : typeof event.delta === \"string\"\n ? event.delta\n : \"\",\n };\n break;\n\n case \"heartbeat\":\n yield { type: \"gateway-heartbeat\" };\n break;\n\n case \"tool-call\": {\n flushPending();\n parts.push({\n type: \"tool-call\",\n id: event.id,\n name: event.name,\n input: event.input,\n });\n yield {\n type: \"tool-call\",\n id: event.id,\n name: event.name,\n input: event.input,\n };\n break;\n }\n\n case \"usage\": {\n const cacheWrite =\n (event.cacheCreatedTokens ?? 0) + (event.cacheCreated1hTokens ?? 0);\n yield {\n type: \"usage\",\n inputTokens: event.inputTokens ?? 0,\n outputTokens: event.outputTokens ?? 0,\n ...(event.cacheInputTokens !== undefined\n ? { cacheReadTokens: event.cacheInputTokens }\n : {}),\n ...(cacheWrite > 0 ? { cacheWriteTokens: cacheWrite } : {}),\n };\n break;\n }\n\n case \"stop\": {\n flushPending();\n yield { type: \"assistant-content\", parts };\n\n const reason = event.reason ?? \"end_turn\";\n if (reason === \"rate_limited\") {\n // Include \"rate_limit\" in the message so production-agent's\n // isRetryableError picks it up and retries.\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `rate_limit exceeded: ${event.error ?? \"upstream provider rate limited\"}`,\n errorCode: \"rate_limited\",\n };\n } else if (reason === \"invalid_request\") {\n // errorCode has no retry-trigger keywords, so isRetryableError\n // won't loop on broken history.\n const errMsg =\n event.error ||\n event.message ||\n \"Builder gateway rejected the request as malformed.\";\n const errCode =\n typeof event.errorCode === \"string\"\n ? event.errorCode\n : typeof event.code === \"string\"\n ? event.code\n : \"invalid_request\";\n console.warn(\n `[builder-engine] stop reason=invalid_request model=${model} code=${errCode} error=${errMsg}`,\n );\n yield {\n type: \"stop\",\n reason: \"error\",\n error: errMsg,\n errorCode: errCode,\n };\n } else if (reason === \"error\") {\n // Surface every diagnostic the gateway gave us so the user (and\n // our logs) get more than a bare \"Gateway error\". The gateway\n // sometimes emits an error stop event with no message — most\n // commonly when the upstream provider rejects the model for\n // this account (Opus quotas have hit this in practice).\n const explicitErrMsg = event.error || event.message || event.detail;\n const errMsg =\n explicitErrMsg ??\n `Gateway error (no detail; raw event: ${JSON.stringify(event)})`;\n const gatewayErrCode = event.errorCode ?? event.code;\n const isCredentialAuthError =\n Boolean(explicitErrMsg) &&\n isBuilderCredentialAuthError(String(errMsg));\n // Anthropic's bare \"Connection error.\" often arrives here with no\n // gateway code. Tag it as a network error so in-run retries and\n // run-level resume treat it as transient instead of terminal.\n const isProviderConnectionError =\n typeof explicitErrMsg === \"string\" &&\n isProviderConnectionErrorMessage(String(explicitErrMsg));\n const errCode = isCredentialAuthError\n ? \"builder_auth_error\"\n : isProviderConnectionError\n ? BUILDER_GATEWAY_NETWORK_ERROR_CODE\n : (gatewayErrCode ??\n (!explicitErrMsg ? \"builder_gateway_error\" : undefined));\n console.error(\n `[builder-engine] stop reason=error model=${model} code=${errCode ?? \"(none)\"} error=${errMsg}`,\n );\n if (isCredentialAuthError) {\n await recordBuilderCredentialAuthFailure({\n code:\n typeof gatewayErrCode === \"string\" ? gatewayErrCode : errCode,\n message: String(errMsg),\n });\n }\n // No-detail gateway errors are opaque to the chat client — the\n // only way to debug them is from the gateway side. Capture rich\n // tags here (model, gatewayOrigin, requestId) so the gateway\n // team can search Sentry by requestId or filter by model. The\n // downstream run-manager will also capture the EngineError once\n // it's thrown, but without these tags.\n if (!explicitErrMsg) {\n captureBuilderGatewayNoDetailError({\n requestId:\n typeof event.requestId === \"string\"\n ? event.requestId\n : undefined,\n model,\n gatewayUrl: captureContext.gatewayUrl,\n rawEvent: event,\n });\n }\n yield {\n type: \"stop\",\n reason: \"error\",\n error: errMsg,\n ...(errCode ? { errorCode: errCode } : {}),\n };\n } else if (\n reason === \"end_turn\" ||\n reason === \"tool_use\" ||\n reason === \"max_tokens\" ||\n reason === \"stop_sequence\"\n ) {\n yield { type: \"stop\", reason };\n } else {\n yield {\n type: \"stop\",\n reason: \"error\",\n error: `Unknown stop reason: ${reason}`,\n };\n }\n return;\n }\n\n default:\n // Unknown event type — ignore for forward compat.\n break;\n }\n }\n\n // Stream ended without a stop event — synthesize one so callers don't hang.\n flushPending();\n yield { type: \"assistant-content\", parts };\n yield {\n type: \"stop\",\n reason: \"error\",\n error: \"Builder gateway stream ended without a stop event\",\n };\n } catch (err) {\n const timedOut = captureContext.didGatewayTimeout?.() ?? false;\n const gatewayTimeoutMs =\n captureContext.getGatewayTimeoutMs?.() ??\n DEFAULT_BUILDER_GATEWAY_TIMEOUT_MS;\n if (timedOut || isBuilderGatewayNetworkError(err)) {\n captureBuilderGatewayTransportError(err, {\n phase: \"stream\",\n model,\n gatewayUrl: captureContext.gatewayUrl,\n timeoutMs: gatewayTimeoutMs,\n timedOut,\n elapsedMs:\n typeof captureContext.requestStartedAt === \"number\"\n ? Date.now() - captureContext.requestStartedAt\n : undefined,\n });\n }\n yield createBuilderGatewayTimeoutStop(err, timedOut, gatewayTimeoutMs);\n } finally {\n // Release the reader on every exit path — early returns (invalid JSONL,\n // stop event) and generator abandonment both leave the underlying\n // Response body locked otherwise. cancel() also closes the socket.\n try {\n await reader.cancel();\n } catch {\n // Already cancelled or closed\n }\n }\n}\n\nfunction readStreamChunk(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n abortSignal?: AbortSignal,\n): Promise<ReadableStreamReadResult<Uint8Array>> {\n if (!abortSignal) return reader.read();\n if (abortSignal.aborted) {\n return Promise.reject(abortSignal.reason ?? new Error(\"Stream aborted\"));\n }\n return new Promise((resolve, reject) => {\n const onAbort = () => {\n reject(abortSignal.reason ?? new Error(\"Stream aborted\"));\n };\n abortSignal.addEventListener(\"abort\", onAbort, { once: true });\n reader.read().then(\n (value) => {\n abortSignal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (err) => {\n abortSignal.removeEventListener(\"abort\", onAbort);\n reject(err);\n },\n );\n });\n}\n\nfunction normalizeGatewayErrorText(raw: string, status: number): string {\n const text = raw.trim();\n const looksHtml = /<html[\\s>]|<body[\\s>]|<head[\\s>]/i.test(text);\n const readable = looksHtml ? htmlToText(text) : text;\n if (/inactivity timeout/i.test(readable)) {\n return `Builder gateway returned ${status}: Inactivity Timeout. The upstream connection was idle too long before sending data.`;\n }\n if (looksHtml) {\n return `Builder gateway returned ${status}: ${readable.slice(0, 240)}`;\n }\n return readable;\n}\n\nfunction htmlToText(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/(p|div|h1|h2|h3|li|tr)>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \" \")\n .replace(/ /gi, \" \")\n .replace(/</gi, \"<\")\n .replace(/>/gi, \">\")\n .replace(/&/gi, \"&\")\n .replace(/"/gi, '\"')\n .replace(/'/gi, \"'\")\n .replace(/[ \\t]+/g, \" \")\n .replace(/\\n\\s+/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nexport function createBuilderEngine(\n _config: Record<string, unknown> = {},\n): AgentEngine {\n return new BuilderEngine();\n}\n\nfunction resolveMaxBuilderGatewayTimeoutMs(): number {\n if (isInBackgroundFunctionRuntime()) {\n return MAX_BACKGROUND_BUILDER_GATEWAY_TIMEOUT_MS;\n }\n\n if (!isHostedBuilderRuntime()) {\n return MAX_LOCAL_BUILDER_GATEWAY_TIMEOUT_MS;\n }\n\n try {\n const base = getBuilderGatewayBaseUrl();\n if (/^https?:\\/\\/(localhost|127\\.0\\.0\\.1)([:/]|$)/i.test(base)) {\n return MAX_LOCAL_BUILDER_GATEWAY_TIMEOUT_MS;\n }\n } catch {\n // ignore malformed override\n }\n return MAX_HOSTED_FOREGROUND_BUILDER_GATEWAY_TIMEOUT_MS;\n}\n\nfunction isHostedBuilderRuntime(): boolean {\n if (\n process.env.NETLIFY &&\n process.env.NETLIFY !== \"false\" &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n if (\n process.env.AWS_LAMBDA_FUNCTION_NAME &&\n process.env.NETLIFY_LOCAL !== \"true\"\n ) {\n return true;\n }\n return Boolean(\n process.env.CF_PAGES ||\n process.env.VERCEL ||\n process.env.VERCEL_ENV ||\n process.env.RENDER ||\n process.env.FLY_APP_NAME ||\n process.env.K_SERVICE,\n );\n}\n\nfunction getBuilderGatewayTimeoutMs(): number {\n const raw = process.env.AGENT_NATIVE_BUILDER_GATEWAY_TIMEOUT_MS;\n const maxMs = resolveMaxBuilderGatewayTimeoutMs();\n if (!raw) return maxMs;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n return maxMs;\n }\n return Math.min(parsed, maxMs);\n}\n\n/**\n * Two-stage abort deadline: until the first real stream event arrives, the\n * effective deadline is min(totalTimeoutMs, FIRST_STREAM_EVENT_TIMEOUT_MS) —\n * a wedged gateway that never streams anything gets cut off in ~2 minutes\n * instead of riding the full flat timeout. Once `markFirstEvent()` fires, the\n * timer reschedules for whatever remains of the original total deadline, so\n * a request that starts streaming still gets the full budget it always did.\n */\nfunction createGatewayAbortSignal(\n parentSignal: AbortSignal,\n totalTimeoutMs: number,\n): {\n signal: AbortSignal;\n didTimeout: () => boolean;\n effectiveTimeoutMs: () => number;\n markFirstEvent: () => void;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n let timedOut = false;\n let firstEventSeen = false;\n const startedAt = Date.now();\n\n const abortFromParent = () => {\n if (!controller.signal.aborted) {\n controller.abort(parentSignal.reason);\n }\n };\n\n const fireTimeout = () => {\n timedOut = true;\n if (!controller.signal.aborted) {\n controller.abort(new Error(\"Builder gateway request timed out\"));\n }\n };\n\n const firstEventDeadlineMs = Math.min(\n totalTimeoutMs,\n FIRST_STREAM_EVENT_TIMEOUT_MS,\n );\n let timeout = setTimeout(fireTimeout, firstEventDeadlineMs);\n\n if (parentSignal.aborted) abortFromParent();\n parentSignal.addEventListener(\"abort\", abortFromParent, { once: true });\n\n return {\n signal: controller.signal,\n didTimeout: () => timedOut,\n effectiveTimeoutMs: () =>\n firstEventSeen ? totalTimeoutMs : firstEventDeadlineMs,\n markFirstEvent: () => {\n if (firstEventSeen || timedOut) return;\n firstEventSeen = true;\n // The first-event window was already the binding constraint (total\n // timeout <= it) — nothing to reschedule.\n if (firstEventDeadlineMs >= totalTimeoutMs) return;\n clearTimeout(timeout);\n const remainingMs = Math.max(\n 0,\n totalTimeoutMs - (Date.now() - startedAt),\n );\n timeout = setTimeout(fireTimeout, remainingMs);\n },\n cleanup: () => {\n clearTimeout(timeout);\n parentSignal.removeEventListener(\"abort\", abortFromParent);\n },\n };\n}\n\nfunction isBuilderCredentialAuthError(message: string): boolean {\n const lowerMessage = message.toLowerCase();\n const referencesAccessToken =\n lowerMessage.includes(\"personal access token\") ||\n lowerMessage.includes(\"access token\");\n const rejectedToken =\n lowerMessage.includes(\"invalid\") ||\n lowerMessage.includes(\"inactive\") ||\n lowerMessage.includes(\"expired\") ||\n lowerMessage.includes(\"revoked\");\n return (\n lowerMessage.includes(\"unauthorized\") ||\n lowerMessage.includes(\"private key\") ||\n lowerMessage.includes(\"invalid token\") ||\n lowerMessage.includes(\"invalid_token\") ||\n lowerMessage.includes(\"token invalid\") ||\n (referencesAccessToken && rejectedToken)\n );\n}\n\nfunction normalizeBuilderGatewayFetchError(\n err: unknown,\n timedOut: boolean,\n timeoutMs: number,\n): string {\n if (timedOut) {\n return `Builder gateway timed out after ${formatTimeoutMs(\n timeoutMs,\n )} before the hosting function limit. Please retry; if this keeps happening, reduce the prompt size or try again when the gateway is less busy.`;\n }\n const message = errorMessage(err);\n if (isBuilderGatewayNetworkError(err)) {\n return `Builder gateway network error: ${message}`;\n }\n return message;\n}\n\nfunction createBuilderGatewayTimeoutStop(\n err: unknown,\n timedOut: boolean,\n timeoutMs: number,\n): EngineEvent {\n const networkError = !timedOut && isBuilderGatewayNetworkError(err);\n return {\n type: \"stop\",\n reason: \"error\",\n error: normalizeBuilderGatewayFetchError(err, timedOut, timeoutMs),\n ...(timedOut\n ? { errorCode: \"builder_gateway_timeout\" }\n : networkError\n ? { errorCode: BUILDER_GATEWAY_NETWORK_ERROR_CODE }\n : {}),\n };\n}\n\nfunction formatTimeoutMs(timeoutMs: number): string {\n if (timeoutMs < 1000) return `${timeoutMs}ms`;\n return `${Math.round(timeoutMs / 1000)}s`;\n}\n\nfunction errorMessage(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\nfunction errorSearchText(err: unknown): string {\n const parts: string[] = [];\n if (err instanceof Error) {\n parts.push(err.name, err.message);\n const maybe = err as Error & {\n code?: unknown;\n cause?: unknown;\n };\n if (typeof maybe.code === \"string\") parts.push(maybe.code);\n if (maybe.cause) parts.push(errorSearchText(maybe.cause));\n } else {\n parts.push(String(err));\n }\n return parts.join(\" \").toLowerCase();\n}\n\nfunction isBuilderGatewayNetworkError(err: unknown): boolean {\n const text = errorSearchText(err);\n return (\n text.includes(\"socket hang up\") ||\n text.includes(\"econnreset\") ||\n text.includes(\"enetreset\") ||\n text.includes(\"econnaborted\") ||\n text.includes(\"fetch failed\") ||\n text.includes(\"network error\") ||\n // Anthropic SDK's APIConnectionError default (\"Connection error.\") is\n // often forwarded by the Builder gateway as a stop event with no code.\n text.includes(\"connection error\") ||\n text.includes(\"connection reset\") ||\n text.includes(\"connection closed\") ||\n text.includes(\"stream closed\") ||\n text.includes(\"terminated\")\n );\n}\n\nfunction isProviderConnectionErrorMessage(message: string): boolean {\n return message.trim().toLowerCase() === \"connection error.\";\n}\n\nfunction captureBuilderGatewayTransportError(\n err: unknown,\n context: {\n phase: \"request\" | \"stream\";\n model: string;\n gatewayUrl?: URL;\n timeoutMs: number;\n timedOut: boolean;\n elapsedMs?: number;\n },\n): void {\n captureError(err, {\n route: \"/_agent-native/agent-chat\",\n tags: {\n source: \"builder-engine\",\n phase: context.phase,\n model: context.model,\n timedOut: context.timedOut ? \"true\" : \"false\",\n errorCode: context.timedOut\n ? \"builder_gateway_timeout\"\n : BUILDER_GATEWAY_NETWORK_ERROR_CODE,\n },\n extra: {\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n timeoutMs: context.timeoutMs,\n elapsedMs: context.elapsedMs,\n },\n contexts: {\n builderGateway: {\n phase: context.phase,\n model: context.model,\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n timeoutMs: context.timeoutMs,\n timedOut: context.timedOut,\n elapsedMs: context.elapsedMs,\n },\n },\n });\n}\n\n/**\n * Capture a Builder-gateway no-detail stop event to Sentry with the request\n * context the run-manager doesn't have. The gateway emits\n * `{type:\"stop\",reason:\"error\",requestId:\"...\"}` with no diagnostic — the\n * only way to debug it is from the gateway side, so we surface model,\n * gatewayOrigin, and requestId as searchable tags.\n */\nfunction captureBuilderGatewayNoDetailError(context: {\n requestId?: string;\n model: string;\n gatewayUrl?: URL;\n rawEvent: unknown;\n}): void {\n const err = new Error(\n context.requestId\n ? `Builder gateway stop reason=error with no detail (requestId=${context.requestId})`\n : \"Builder gateway stop reason=error with no detail\",\n );\n err.name = \"BuilderGatewayNoDetailError\";\n captureError(err, {\n route: \"/_agent-native/agent-chat\",\n tags: {\n source: \"builder-engine\",\n phase: \"stream\",\n model: context.model,\n errorCode: \"builder_gateway_error\",\n ...(context.requestId ? { gatewayRequestId: context.requestId } : {}),\n },\n extra: {\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n rawEvent: context.rawEvent,\n },\n contexts: {\n builderGateway: {\n phase: \"stream\",\n model: context.model,\n gatewayOrigin: context.gatewayUrl?.origin,\n gatewayPath: context.gatewayUrl?.pathname,\n requestId: context.requestId,\n errorCode: \"builder_gateway_error\",\n },\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared "first stream event" deadline for model-request engines.
|
|
3
|
+
*
|
|
4
|
+
* A request that connects successfully but then streams zero events means the
|
|
5
|
+
* transport or gateway is wedged, not slow — real models (including deep
|
|
6
|
+
* thinking ones) emit their first event within seconds. Bounding this window
|
|
7
|
+
* separately from any total-request deadline turns a silent multi-minute hang
|
|
8
|
+
* into a fast abort-and-retry.
|
|
9
|
+
*/
|
|
10
|
+
export declare const FIRST_STREAM_EVENT_TIMEOUT_MS = 120000;
|
|
11
|
+
export interface FirstEventAbortController {
|
|
12
|
+
readonly signal: AbortSignal;
|
|
13
|
+
/** Idempotent. Call once the first real (non-keepalive) stream event arrives. */
|
|
14
|
+
markFirstEvent: () => void;
|
|
15
|
+
didTimeout: () => boolean;
|
|
16
|
+
cleanup: () => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Layer a first-event deadline on top of a caller's AbortSignal. Aborts if
|
|
20
|
+
* `markFirstEvent()` is not called within `FIRST_STREAM_EVENT_TIMEOUT_MS`.
|
|
21
|
+
* Has no opinion on a total-request deadline — callers that need one (e.g.
|
|
22
|
+
* builder-engine's flat gateway timeout) compose their own on top.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createFirstEventAbortController(parentSignal: AbortSignal): FirstEventAbortController;
|
|
25
|
+
//# sourceMappingURL=first-event-timeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-event-timeout.d.ts","sourceRoot":"","sources":["../../../src/agent/engine/first-event-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,iFAAiF;IACjF,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,YAAY,EAAE,WAAW,GACxB,yBAAyB,CAoC3B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared "first stream event" deadline for model-request engines.
|
|
3
|
+
*
|
|
4
|
+
* A request that connects successfully but then streams zero events means the
|
|
5
|
+
* transport or gateway is wedged, not slow — real models (including deep
|
|
6
|
+
* thinking ones) emit their first event within seconds. Bounding this window
|
|
7
|
+
* separately from any total-request deadline turns a silent multi-minute hang
|
|
8
|
+
* into a fast abort-and-retry.
|
|
9
|
+
*/
|
|
10
|
+
export const FIRST_STREAM_EVENT_TIMEOUT_MS = 120_000;
|
|
11
|
+
/**
|
|
12
|
+
* Layer a first-event deadline on top of a caller's AbortSignal. Aborts if
|
|
13
|
+
* `markFirstEvent()` is not called within `FIRST_STREAM_EVENT_TIMEOUT_MS`.
|
|
14
|
+
* Has no opinion on a total-request deadline — callers that need one (e.g.
|
|
15
|
+
* builder-engine's flat gateway timeout) compose their own on top.
|
|
16
|
+
*/
|
|
17
|
+
export function createFirstEventAbortController(parentSignal) {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
let timedOut = false;
|
|
20
|
+
let firstEventSeen = false;
|
|
21
|
+
const abortFromParent = () => {
|
|
22
|
+
if (!controller.signal.aborted)
|
|
23
|
+
controller.abort(parentSignal.reason);
|
|
24
|
+
};
|
|
25
|
+
const timeout = setTimeout(() => {
|
|
26
|
+
timedOut = true;
|
|
27
|
+
if (!controller.signal.aborted) {
|
|
28
|
+
controller.abort(new Error(`Model request produced no stream events within ${FIRST_STREAM_EVENT_TIMEOUT_MS / 1000}s`));
|
|
29
|
+
}
|
|
30
|
+
}, FIRST_STREAM_EVENT_TIMEOUT_MS);
|
|
31
|
+
if (parentSignal.aborted)
|
|
32
|
+
abortFromParent();
|
|
33
|
+
parentSignal.addEventListener("abort", abortFromParent, { once: true });
|
|
34
|
+
return {
|
|
35
|
+
signal: controller.signal,
|
|
36
|
+
markFirstEvent: () => {
|
|
37
|
+
if (firstEventSeen)
|
|
38
|
+
return;
|
|
39
|
+
firstEventSeen = true;
|
|
40
|
+
clearTimeout(timeout);
|
|
41
|
+
},
|
|
42
|
+
didTimeout: () => timedOut,
|
|
43
|
+
cleanup: () => {
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
parentSignal.removeEventListener("abort", abortFromParent);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=first-event-timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-event-timeout.js","sourceRoot":"","sources":["../../../src/agent/engine/first-event-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,OAAO,CAAC;AAUrD;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAC7C,YAAyB;IAEzB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,MAAM,eAAe,GAAG,GAAG,EAAE;QAC3B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO;YAAE,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACxE,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,UAAU,CAAC,KAAK,CACd,IAAI,KAAK,CACP,kDAAkD,6BAA6B,GAAG,IAAI,GAAG,CAC1F,CACF,CAAC;QACJ,CAAC;IACH,CAAC,EAAE,6BAA6B,CAAC,CAAC;IAElC,IAAI,YAAY,CAAC,OAAO;QAAE,eAAe,EAAE,CAAC;IAC5C,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAExE,OAAO;QACL,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,cAAc,EAAE,GAAG,EAAE;YACnB,IAAI,cAAc;gBAAE,OAAO;YAC3B,cAAc,GAAG,IAAI,CAAC;YACtB,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QACD,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ;QAC1B,OAAO,EAAE,GAAG,EAAE;YACZ,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,YAAY,CAAC,mBAAmB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Shared \"first stream event\" deadline for model-request engines.\n *\n * A request that connects successfully but then streams zero events means the\n * transport or gateway is wedged, not slow — real models (including deep\n * thinking ones) emit their first event within seconds. Bounding this window\n * separately from any total-request deadline turns a silent multi-minute hang\n * into a fast abort-and-retry.\n */\nexport const FIRST_STREAM_EVENT_TIMEOUT_MS = 120_000;\n\nexport interface FirstEventAbortController {\n readonly signal: AbortSignal;\n /** Idempotent. Call once the first real (non-keepalive) stream event arrives. */\n markFirstEvent: () => void;\n didTimeout: () => boolean;\n cleanup: () => void;\n}\n\n/**\n * Layer a first-event deadline on top of a caller's AbortSignal. Aborts if\n * `markFirstEvent()` is not called within `FIRST_STREAM_EVENT_TIMEOUT_MS`.\n * Has no opinion on a total-request deadline — callers that need one (e.g.\n * builder-engine's flat gateway timeout) compose their own on top.\n */\nexport function createFirstEventAbortController(\n parentSignal: AbortSignal,\n): FirstEventAbortController {\n const controller = new AbortController();\n let timedOut = false;\n let firstEventSeen = false;\n\n const abortFromParent = () => {\n if (!controller.signal.aborted) controller.abort(parentSignal.reason);\n };\n\n const timeout = setTimeout(() => {\n timedOut = true;\n if (!controller.signal.aborted) {\n controller.abort(\n new Error(\n `Model request produced no stream events within ${FIRST_STREAM_EVENT_TIMEOUT_MS / 1000}s`,\n ),\n );\n }\n }, FIRST_STREAM_EVENT_TIMEOUT_MS);\n\n if (parentSignal.aborted) abortFromParent();\n parentSignal.addEventListener(\"abort\", abortFromParent, { once: true });\n\n return {\n signal: controller.signal,\n markFirstEvent: () => {\n if (firstEventSeen) return;\n firstEventSeen = true;\n clearTimeout(timeout);\n },\n didTimeout: () => timedOut,\n cleanup: () => {\n clearTimeout(timeout);\n parentSignal.removeEventListener(\"abort\", abortFromParent);\n },\n };\n}\n"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
export declare const PR_VISUAL_RECAP_WORKFLOW_YML = "name: PR Visual Recap\n\n# Visual code review: a coding agent runs the repo's visual-recap skill over the\n# PR diff, publishes a plan, and upserts one sticky comment with a screenshot.\n# Plain `pull_request` (NOT `pull_request_target`) so fork code never sees secrets.\n\non:\n pull_request:\n types: [opened, synchronize, reopened, ready_for_review, closed]\n\npermissions:\n contents: read\n\nconcurrency:\n group: pr-visual-recap-${{ github.event.pull_request.number }}\n cancel-in-progress: true\n\nenv:\n VISUAL_RECAP_AGENT: ${{ vars.VISUAL_RECAP_AGENT || 'claude' }}\n VISUAL_RECAP_BASE_URL: ${{ vars.VISUAL_RECAP_BASE_URL || '' }}\n VISUAL_RECAP_SKILL_SOURCE: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}\n VISUAL_RECAP_SECRET_SCAN: ${{ vars.VISUAL_RECAP_SECRET_SCAN || 'high-confidence' }}\n\njobs:\n gate:\n name: Gate\n # A custom plain-label runner is allowed only for trusted same-repo authors.\n # Fork and untrusted PRs are forced onto GitHub-hosted ubuntu-latest before\n # any step starts. The only fromJSON input is this static association list.\n runs-on: ${{ github.event.pull_request.head.repo.full_name == github.repository && contains(fromJSON('[\"OWNER\",\"MEMBER\",\"COLLABORATOR\"]'), github.event.pull_request.author_association) && (vars.VISUAL_RECAP_GATE_RUNS_ON || 'ubuntu-latest') || 'ubuntu-latest' }}\n timeout-minutes: 10\n permissions:\n contents: read\n issues: write\n pull-requests: write\n outputs:\n run: ${{ steps.decide.outputs.run }}\n agent: ${{ steps.decide.outputs.agent }}\n runs_on: ${{ steps.decide.outputs.runs_on }}\n steps:\n - id: decide\n uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0\n env:\n # Presence-only signals \u2014 never expose secret VALUES to the gate.\n HAS_PLAN: ${{ secrets.PLAN_RECAP_TOKEN != '' }}\n HAS_ANTHROPIC: ${{ secrets.ANTHROPIC_API_KEY != '' }}\n HAS_OPENAI: ${{ secrets.OPENAI_API_KEY != '' }}\n HAS_COMPATIBLE: ${{ secrets.VISUAL_RECAP_API_KEY != '' }}\n AGENT: ${{ env.VISUAL_RECAP_AGENT }}\n VISUAL_RECAP_BASE_URL: ${{ env.VISUAL_RECAP_BASE_URL }}\n VISUAL_RECAP_MODEL: ${{ vars.VISUAL_RECAP_MODEL }}\n VISUAL_RECAP_RUNS_ON: ${{ vars.VISUAL_RECAP_RUNS_ON || '\"ubuntu-latest\"' }}\n VISUAL_RECAP_SKILL_SOURCE: ${{ env.VISUAL_RECAP_SKILL_SOURCE }}\n HEAD_SHA: ${{ github.event.pull_request.head.sha }}\n with:\n script: |\n const pr = context.payload.pull_request;\n const reasons = [];\n\n if (!pr) reasons.push('no pull_request payload');\n if (pr && pr.draft) reasons.push('draft PR');\n if (pr && context.payload.action === 'closed' && !pr.merged) {\n reasons.push('closed without merge');\n }\n\n // Fork PRs only receive repo secrets when the org/repo opts into\n // GitHub's \"Send secrets to workflows from pull requests\" setting\n // (common in private orgs that use forks heavily). Gate on secret\n // availability, not fork-ness: run on forks that have the token,\n // and skip \u2014 with an actionable hint \u2014 those that don't.\n const headRepo = pr && pr.head && pr.head.repo && pr.head.repo.full_name;\n const isFork = !!(pr && headRepo && headRepo !== process.env.GITHUB_REPOSITORY);\n const isPrivate = !!(context.payload.repository && context.payload.repository.private);\n const association = (pr && pr.author_association || '').toUpperCase();\n const trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR'];\n const isTrustedAuthor = trustedAssociations.includes(association);\n let configuredRunner = 'ubuntu-latest';\n let usesSelfHostedRunner = false;\n try {\n const candidate = JSON.parse(process.env.VISUAL_RECAP_RUNS_ON || '\"ubuntu-latest\"');\n const hosted = typeof candidate === 'string' && /^(?:ubuntu|windows|macos)-[A-Za-z0-9.-]+$/.test(candidate);\n const selfHosted = Array.isArray(candidate) && candidate.length >= 1 && candidate.length <= 20 && candidate.includes('self-hosted') && candidate.every((label) => typeof label === 'string' && label.length >= 1 && label.length <= 100 && !/[\\u0000-\\u001f\\u007f]/.test(label)) && new Set(candidate).size === candidate.length;\n if (!hosted && !selfHosted) throw new Error('unsupported runner value');\n configuredRunner = candidate;\n usesSelfHostedRunner = selfHosted;\n } catch {\n reasons.push('invalid VISUAL_RECAP_RUNS_ON JSON');\n }\n if (usesSelfHostedRunner && (isFork || !isTrustedAuthor)) {\n reasons.push('self-hosted runner mode requires a trusted same-repository PR author');\n }\n if (isFork && process.env.HAS_PLAN !== 'true') {\n reasons.push(`fork PR (${headRepo}) without secret access \u2014 enable \"Send secrets to workflows from pull requests\" (and write tokens) in the repo/org Actions settings to run recaps on forks`);\n }\n\n const login = (pr && pr.user && pr.user.login || '').toLowerCase();\n const botAuthors = ['dependabot[bot]', 'dependabot', 'renovate[bot]', 'renovate'];\n if (botAuthors.includes(login)) reasons.push(`bot author (${login})`);\n if (pr && pr.user && pr.user.type === 'Bot') reasons.push('bot author (type=Bot)');\n\n if (!isFork && process.env.HAS_PLAN !== 'true') reasons.push('PLAN_RECAP_TOKEN not configured');\n\n // Normalize + validate the agent so a mis-cased value can't pass the\n // gate and then match neither agent step below.\n const rawAgent = (process.env.AGENT || 'claude').toLowerCase();\n const agent = ['deepseek', 'kimi', 'moonshot', 'custom'].includes(rawAgent) ? 'openai-compatible' : rawAgent;\n if (!['claude', 'codex', 'openai-compatible'].includes(agent)) {\n reasons.push(`unsupported VISUAL_RECAP_AGENT \"${process.env.AGENT}\" (expected \"claude\", \"codex\", or \"openai-compatible\")`);\n } else if (agent === 'codex') {\n if (process.env.HAS_OPENAI !== 'true') reasons.push('OPENAI_API_KEY not configured (codex backend)');\n } else if (agent === 'claude') {\n if (process.env.HAS_ANTHROPIC !== 'true') reasons.push('ANTHROPIC_API_KEY not configured (claude backend)');\n } else {\n if (process.env.HAS_COMPATIBLE !== 'true') reasons.push('VISUAL_RECAP_API_KEY not configured (openai-compatible backend)');\n if (!(process.env.VISUAL_RECAP_MODEL || '').trim()) reasons.push('VISUAL_RECAP_MODEL is required (openai-compatible backend)');\n const baseUrl = process.env.VISUAL_RECAP_BASE_URL || '';\n try {\n const parsed = new URL(baseUrl);\n if (!['http:', 'https:'].includes(parsed.protocol) || parsed.username || parsed.password) {\n reasons.push('VISUAL_RECAP_BASE_URL must be an http(s) URL without credentials');\n }\n } catch {\n reasons.push('VISUAL_RECAP_BASE_URL must be a valid http(s) URL');\n }\n }\n\n // Validate the model before it reaches the agent CLI.\n const model = process.env.VISUAL_RECAP_MODEL || '';\n if (model && !/^[a-zA-Z0-9._-]{1,80}$/.test(model)) {\n reasons.push(`invalid VISUAL_RECAP_MODEL value (must match [a-zA-Z0-9._-]{1,80})`);\n }\n\n const skillSource = (process.env.VISUAL_RECAP_SKILL_SOURCE || 'auto').toLowerCase();\n if (!['auto', 'latest', 'repo'].includes(skillSource)) {\n reasons.push('invalid VISUAL_RECAP_SKILL_SOURCE value (expected \"auto\", \"latest\", or \"repo\")');\n }\n const usesRepoSkill = skillSource === 'repo';\n\n // Self-modifying guard, evaluated in the trusted gate (runs NO\n // PR-checked-out code): skip the ENTIRE job if the PR touches the\n // repo-pinned skill instructions or any agent config the runner\n // loads, so a PR can't rewrite what the agent loads and exfiltrate\n // secrets. With the default bundled skill source, visual skill and\n // recap workflow files are reviewed content, not instructions loaded\n // by the runner.\n // Keep this guard for untrusted forks and untrusted public-repo PRs.\n // Trusted write actors may edit recap-control files as normal\n // reviewable content; running the recap is useful signal for those\n // changes.\n if (pr && !isTrustedAuthor && (isFork || !isPrivate)) {\n try {\n const files = await github.paginate(github.rest.pulls.listFiles, {\n owner: context.repo.owner,\n repo: context.repo.repo,\n pull_number: pr.number,\n per_page: 100,\n });\n const isSensitive = (p) =>\n (usesRepoSkill && /(^|\\/)skills\\/visual-(recap|plan|plans)\\//.test(p)) ||\n p.startsWith('.claude/') ||\n p === 'CLAUDE.md' ||\n p === 'AGENTS.md' ||\n p === '.mcp.json';\n const hits = files.map((f) => f.filename).filter(isSensitive);\n if (hits.length) {\n reasons.push(`PR modifies recap-control files (${hits.slice(0, 3).join(', ')}${hits.length > 3 ? ', \u2026' : ''}) \u2014 skipping so untrusted PR code never runs with secrets`);\n }\n } catch (e) {\n // Fail closed: if the file list can't be read, skip.\n reasons.push(`could not list PR files for the self-modifying guard (${e.message}); skipping to be safe`);\n }\n }\n\n const run = reasons.length === 0;\n core.setOutput('run', run ? 'true' : 'false');\n core.setOutput('agent', agent);\n core.setOutput('runs_on', JSON.stringify(configuredRunner));\n if (run) {\n core.info(`Visual recap will run (${agent}).`);\n } else {\n // Surface the skip reason as a run-summary annotation, not just a\n // buried info log, so it's clear in the Actions UI why we skipped.\n core.notice(`Visual recap skipped: ${reasons.join('; ')}`);\n }\n\n // When skipping, upsert a sticky recap comment with a short skip\n // line so the PR always explains why the recap job did not run.\n if (!run && pr) {\n try {\n const MARKER = '<!-- pr-visual-recap -->';\n const { data: comments } = await github.rest.issues.listComments({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: pr.number,\n per_page: 100,\n });\n const existing = comments.find(\n (c) => c.user && c.user.type === 'Bot' && c.body && c.body.includes(MARKER)\n );\n const headShort = (process.env.HEAD_SHA || '').slice(0, 7);\n const shaRef = headShort ? `\\`${headShort}\\`` : 'latest push';\n const primaryReason = reasons.filter(\n (r) => !r.startsWith('could not list PR files for the self-modifying guard')\n )[0] || reasons[0] || 'skipped';\n const skipLine = `_Recap skipped for ${shaRef}: ${primaryReason}._`;\n const baseBody = `${MARKER}\\n### Visual recap \u2014 skipped\\n\\nThe visual recap job did not run for this pull request. This is informational only and does **not** block the PR.`;\n const planIdMatch = (existing && existing.body ? existing.body : '').match(/<!--\\s*plan-id:\\s*([A-Za-z0-9_-]{1,64})\\s*-->/);\n const planIdMarker = planIdMatch ? `\\n\\n<!-- plan-id: ${planIdMatch[1]} -->` : '';\n const updatedBody = `${baseBody}${planIdMarker}\\n\\n${skipLine}`;\n if (existing) {\n await github.rest.issues.updateComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n comment_id: existing.id,\n body: updatedBody,\n });\n } else {\n await github.rest.issues.createComment({\n owner: context.repo.owner,\n repo: context.repo.repo,\n issue_number: pr.number,\n body: updatedBody,\n });\n }\n } catch (e) {\n core.warning(`Could not update recap skip comment: ${e.message}`);\n }\n }\n\n recap:\n name: Generate visual recap\n needs: gate\n if: needs.gate.outputs.run == 'true'\n runs-on: ${{ fromJSON(needs.gate.outputs.runs_on) }}\n timeout-minutes: 30\n defaults:\n run:\n shell: bash\n permissions:\n actions: write\n checks: write\n contents: read\n issues: write\n pull-requests: write\n env:\n PLAN_RECAP_APP_URL: ${{ secrets.PLAN_RECAP_APP_URL || 'https://plan.agent-native.com' }}\n PLAN_RECAP_TOKEN: ${{ secrets.PLAN_RECAP_TOKEN }}\n GH_TOKEN: ${{ github.token }}\n PR_NUMBER: ${{ github.event.pull_request.number }}\n PR_STATE: ${{ github.event.pull_request.state }}\n PR_MERGED: ${{ github.event.pull_request.merged }}\n PR_MERGED_AT: ${{ github.event.pull_request.merged_at }}\n HEAD_SHA: ${{ github.event.pull_request.head.sha }}\n VISUAL_RECAP_MODEL: ${{ vars.VISUAL_RECAP_MODEL }}\n VISUAL_RECAP_BASE_URL: ${{ vars.VISUAL_RECAP_BASE_URL || '' }}\n VISUAL_RECAP_REASONING: ${{ vars.VISUAL_RECAP_REASONING }}\n VISUAL_RECAP_SKILL_SOURCE: ${{ vars.VISUAL_RECAP_SKILL_SOURCE || 'auto' }}\n VISUAL_RECAP_SECRET_SCAN: ${{ vars.VISUAL_RECAP_SECRET_SCAN || 'high-confidence' }}\n steps:\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3\n with:\n fetch-depth: 0\n # This job runs an agent over untrusted PR diff; don't leave the token\n # in .git/config (it uses GH_TOKEN for gh API calls, never git push).\n persist-credentials: false\n\n # Dogfood trusted base-branch source inside this monorepo, else install the\n # published package once. Never execute PR-head recap CLI code.\n - name: Resolve recap CLI\n id: cli\n env:\n # Optional: pin the consumer CLI version (e.g. \"1.2.3\"). Defaults to\n # \"latest\" when unset. Set via repository variable RECAP_CLI_VERSION.\n RECAP_CLI_VERSION: ${{ vars.RECAP_CLI_VERSION || 'latest' }}\n run: |\n if [ \"$GITHUB_REPOSITORY\" = \"BuilderIO/agent-native\" ] && [ -f packages/core/src/cli/index.ts ]; then\n echo \"local=true\" >> \"$GITHUB_OUTPUT\"\n else\n echo \"local=false\" >> \"$GITHUB_OUTPUT\"\n fi\n\n - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3\n if: steps.cli.outputs.local == 'true'\n with:\n ref: ${{ github.event.pull_request.base.sha }}\n path: .recap-cli-source\n fetch-depth: 1\n persist-credentials: false\n\n - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8\n if: steps.cli.outputs.local == 'true'\n\n - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0\n with:\n node-version: \"22\"\n cache: ${{ steps.cli.outputs.local == 'true' && 'pnpm' || '' }}\n\n - name: Install trusted workspace recap CLI\n if: steps.cli.outputs.local == 'true'\n working-directory: .recap-cli-source\n run: |\n set -euo pipefail\n pnpm install --frozen-lockfile --ignore-scripts\n pnpm --filter @agent-native/recap-cli build\n echo \"RECAP_CLI=$PWD/node_modules/.bin/tsx $PWD/packages/core/src/cli/index.ts\" >> \"$GITHUB_ENV\"\n echo \"CODE_CLI=$PWD/node_modules/.bin/tsx $PWD/packages/core/src/cli/index.ts\" >> \"$GITHUB_ENV\"\n echo \"RECAP_PLAYWRIGHT=$PWD/node_modules/.bin/playwright\" >> \"$GITHUB_ENV\"\n\n - name: Install published recap CLI\n if: steps.cli.outputs.local != 'true'\n env:\n RECAP_CLI_VERSION: ${{ vars.RECAP_CLI_VERSION || 'latest' }}\n run: |\n set -euo pipefail\n VERSION=\"$RECAP_CLI_VERSION\"\n if [ \"$VERSION\" = \"latest\" ]; then\n VERSION=\"$(npm view @agent-native/recap-cli@latest version)\"\n fi\n for attempt in 1 2 3; do\n if npm install --prefix \"$RUNNER_TEMP/recap-cli\" --no-audit --no-fund --ignore-scripts \"@agent-native/recap-cli@$VERSION\"; then\n break\n fi\n if [ \"$attempt\" = \"3\" ]; then exit 1; fi\n sleep $((attempt * 10))\n done\n echo \"RECAP_CLI_VERSION=$VERSION\" >> \"$GITHUB_ENV\"\n echo \"RECAP_CLI=$RUNNER_TEMP/recap-cli/node_modules/.bin/agent-native\" >> \"$GITHUB_ENV\"\n echo \"RECAP_PLAYWRIGHT=$RUNNER_TEMP/recap-cli/node_modules/.bin/playwright\" >> \"$GITHUB_ENV\"\n\n - name: Install OpenAI-compatible provider runtime\n if: needs.gate.outputs.agent == 'openai-compatible' && steps.cli.outputs.local != 'true'\n env:\n CORE_CLI_VERSION: ${{ vars.CORE_CLI_VERSION || 'latest' }}\n run: |\n set -euo pipefail\n CORE_VERSION=\"$CORE_CLI_VERSION\"\n if [ \"$CORE_VERSION\" = \"latest\" ]; then\n CORE_VERSION=\"$(npm view @agent-native/core@latest version)\"\n fi\n npm install --prefix \"$RUNNER_TEMP/recap-code\" --no-audit --no-fund --ignore-scripts ai @ai-sdk/openai \"@agent-native/core@$CORE_VERSION\"\n echo \"CORE_CLI_VERSION=$CORE_VERSION\" >> \"$GITHUB_ENV\"\n echo \"CODE_CLI=$RUNNER_TEMP/recap-code/node_modules/.bin/agent-native\" >> \"$GITHUB_ENV\"\n\n - name: Start visual recap check\n id: recap_check\n continue-on-error: true\n run: |\n set -uo pipefail\n $RECAP_CLI recap check start --sha \"$HEAD_SHA\" --workflow-url \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\"\n\n - name: Fetch pull request head\n env:\n PR_NUMBER_ENV: ${{ github.event.pull_request.number }}\n run: |\n set -euo pipefail\n if git cat-file -e \"${HEAD_SHA}^{commit}\" 2>/dev/null; then\n git update-ref refs/recap/pr-head \"$HEAD_SHA\"\n else\n AUTH_B64=\"$(printf 'x-access-token:%s' \"$GH_TOKEN\" | base64 | tr -d '\\n')\"\n git -c \"http.https://github.com/.extraheader=AUTHORIZATION: basic $AUTH_B64\" fetch origin \"pull/${PR_NUMBER_ENV}/head:refs/recap/pr-head\"\n fi\n FETCHED_SHA=\"$(git rev-parse refs/recap/pr-head)\"\n if [ \"$FETCHED_SHA\" != \"$HEAD_SHA\" ]; then\n echo \"FATAL: fetched PR head $FETCHED_SHA != event HEAD_SHA $HEAD_SHA \u2014 aborting to avoid recapping the wrong commit\"\n exit 1\n fi\n\n - name: Collect bounded diff\n id: diff\n env:\n BASE_SHA: ${{ github.event.pull_request.base.sha }}\n run: |\n set -euo pipefail\n $RECAP_CLI recap collect-diff --base \"$BASE_SHA\" --head refs/recap/pr-head --out recap.diff --stat recap.stat\n\n - name: Probe plan-app auth\n id: auth_probe\n if: steps.diff.outputs.tiny != 'true'\n continue-on-error: true\n run: |\n set -uo pipefail\n # Hit the plan app's action surface with the publish token. A 401 means\n # the token is expired/revoked; surface it in the sticky comment so the\n # repo owner knows to re-mint it instead of seeing a generic failure.\n HTTP_STATUS=$(node -e '\n const https = require(\"https\");\n const url = new URL(\"/_agent-native/actions/record-recap-usage\", process.env.PLAN_RECAP_APP_URL || \"https://plan.agent-native.com\");\n const req = https.request(url, { method: \"POST\", headers: { \"authorization\": \"Bearer \" + process.env.PLAN_RECAP_TOKEN, \"content-type\": \"application/json\" }, timeout: 8000 }, (res) => { process.stdout.write(String(res.statusCode)); req.destroy(); });\n req.on(\"error\", () => process.stdout.write(\"0\"));\n req.end(JSON.stringify({ planId: \"__probe__\" }));\n ' 2>/dev/null || echo \"0\")\n if [ \"$HTTP_STATUS\" = \"401\" ]; then\n echo \"auth_failed=true\" >> \"$GITHUB_OUTPUT\"\n else\n echo \"auth_failed=false\" >> \"$GITHUB_OUTPUT\"\n fi\n\n - name: Probe plan-app route health\n id: route_health\n if: steps.diff.outputs.tiny != 'true'\n continue-on-error: true\n run: |\n set -uo pipefail\n # Pre-publish health gate: confirm the plan app's recap action routes\n # are actually deployed BEFORE the agent runs. A 404 from\n # create-visual-recap (POST) or get-plan-blocks (GET) means the\n # plan-app deploy has not propagated yet (the client is ahead of the\n # deployed server). Say that plainly here instead of letting the agent\n # run and then fail confusingly at publish time. A 401 or 200 is\n # healthy \u2014 the route exists, it just rejected/accepted the probe.\n probe_status() {\n ROUTE=\"$1\" METHOD=\"$2\" node -e '\n const https = require(\"https\");\n const base = process.env.PLAN_RECAP_APP_URL || \"https://plan.agent-native.com\";\n const url = new URL(process.env.ROUTE, base);\n if (process.env.METHOD === \"GET\") url.searchParams.set(\"format\", \"reference\");\n const req = https.request(url, { method: process.env.METHOD, headers: { \"authorization\": \"Bearer \" + (process.env.PLAN_RECAP_TOKEN || \"\"), \"content-type\": \"application/json\" }, timeout: 8000 }, (res) => { process.stdout.write(String(res.statusCode)); req.destroy(); });\n req.on(\"error\", () => process.stdout.write(\"0\"));\n req.on(\"timeout\", () => { process.stdout.write(\"0\"); req.destroy(); });\n if (process.env.METHOD === \"POST\") { req.end(JSON.stringify({ __probe__: true })); } else { req.end(); }\n ' 2>/dev/null || echo \"0\"\n }\n CREATE_STATUS=\"$(probe_status /_agent-native/actions/create-visual-recap POST)\"\n BLOCKS_STATUS=\"$(probe_status /_agent-native/actions/get-plan-blocks GET)\"\n REASON=\"\"\n if [ \"$CREATE_STATUS\" = \"404\" ] || [ \"$BLOCKS_STATUS\" = \"404\" ]; then\n REASON=\"Plan app routes return 404 \u2014 deploy not yet propagated (create-visual-recap: $CREATE_STATUS, get-plan-blocks: $BLOCKS_STATUS). The plan-app client is ahead of the deployed server; re-run once the deploy finishes propagating.\"\n echo \"::error::$REASON\"\n echo \"unhealthy=true\" >> \"$GITHUB_OUTPUT\"\n else\n echo \"unhealthy=false\" >> \"$GITHUB_OUTPUT\"\n fi\n {\n echo 'reason<<__RECAP_ROUTE_HEALTH_EOF__'\n echo \"$REASON\"\n echo '__RECAP_ROUTE_HEALTH_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n\n - name: Secret scan\n id: scan\n if: steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true'\n run: |\n set -uo pipefail\n # Fail CLOSED: a scanner error or invalid JSON suppresses the diff so a\n # credential-bearing diff is never handed to the agent / plan service.\n if ! SCAN_JSON=\"$($RECAP_CLI recap scan --diff recap.diff --mode \"$VISUAL_RECAP_SECRET_SCAN\")\"; then\n SCAN_JSON='{\"suppressed\":true,\"reason\":\"secret scan failed to run; failing closed\"}'\n fi\n {\n echo 'json<<__RECAP_SCAN_EOF__'\n echo \"$SCAN_JSON\"\n echo '__RECAP_SCAN_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n SUPPRESSED=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).suppressed?\"true\":\"false\")}catch{process.stdout.write(\"true\")}' \"$SCAN_JSON\")\n echo \"suppressed=$SUPPRESSED\" >> \"$GITHUB_OUTPUT\"\n\n - name: Read previous plan id\n id: prev\n if: steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true'\n continue-on-error: true\n run: |\n set -euo pipefail\n PLAN_ID=\"$($RECAP_CLI recap comment find-plan-id --repo \"$GITHUB_REPOSITORY\" --issue \"$PR_NUMBER\" --token \"$GH_TOKEN\")\"\n echo \"plan_id=$PLAN_ID\" >> \"$GITHUB_OUTPUT\"\n\n - name: Fetch plan block reference\n id: block_reference\n if: steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n continue-on-error: true\n run: |\n set -uo pipefail\n if $RECAP_CLI recap block-reference --app-url \"$PLAN_RECAP_APP_URL\" --out recap-blocks.md; then\n echo \"ok=true\" >> \"$GITHUB_OUTPUT\"\n else\n echo \"ok=false\" >> \"$GITHUB_OUTPUT\"\n {\n echo 'summary<<__RECAP_BLOCK_REFERENCE_EOF__'\n echo \"Could not fetch the live plan block reference; the agent will fall back to bundled visual-recap instructions and the hosted Plan action will validate the final MDX.\"\n echo '__RECAP_BLOCK_REFERENCE_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n cat > recap-blocks.md <<'EOF'\n Live plan block reference unavailable. Follow the bundled visual-recap skill and author conservative MDX; the deterministic publisher will validate the source before posting.\n EOF\n fi\n\n - name: Build recap prompt\n id: prompt\n if: steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n env:\n # Pass step outputs via env, NOT ${{ }} interpolation into the run body:\n # the prev plan id is parsed from a PR comment and could inject shell.\n PREV_PLAN_ID: ${{ steps.prev.outputs.plan_id }}\n DIFF_HUGE: ${{ steps.diff.outputs.huge }}\n IS_FORK: ${{ github.event.pull_request.head.repo.full_name != github.repository }}\n run: |\n set -euo pipefail\n ARGS=(--diff recap.diff --stat recap.stat --block-reference recap-blocks.md --pr \"$PR_NUMBER\" --repo \"$GITHUB_REPOSITORY\" --head \"$HEAD_SHA\" --app-url \"$PLAN_RECAP_APP_URL\" --skill-source \"$VISUAL_RECAP_SKILL_SOURCE\" --out recap-prompt.md)\n if [ \"${DIFF_HUGE:-}\" = \"true\" ]; then ARGS+=(--huge); fi\n if [ \"${IS_FORK:-}\" = \"true\" ]; then ARGS+=(--fork-pr true); fi\n if [ -n \"${PREV_PLAN_ID:-}\" ]; then ARGS+=(--prev-plan-id \"$PREV_PLAN_ID\"); fi\n $RECAP_CLI recap build-prompt \"${ARGS[@]}\"\n\n - name: Run agent (Claude Code)\n id: claude\n if: needs.gate.outputs.agent == 'claude' && steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n continue-on-error: true\n env:\n ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n run: |\n set -uo pipefail\n CLAUDE_ALLOWED_TOOLS=\"Read,Write,Bash(git diff:*)\"\n CLAUDE_ARGS=(-p \"$(cat recap-prompt.md)\" --allowedTools \"$CLAUDE_ALLOWED_TOOLS\" --permission-mode dontAsk --output-format json)\n CLAUDE_ARGS+=(--model \"${VISUAL_RECAP_MODEL:-claude-sonnet-5}\")\n rm -f recap-source.json recap-url.txt recap-url-reason.txt claude-result.json claude-stderr.log\n run_claude() {\n set +e\n npx -y @anthropic-ai/claude-code@2 \"${CLAUDE_ARGS[@]}\" > claude-result.json 2> claude-stderr.log\n CLAUDE_STATUS=\"$?\"\n set -e\n echo \"$CLAUDE_STATUS\" > claude-exit-code.txt\n }\n run_claude\n # A clean agent exit WITHOUT recap-source.json is the strongest\n # \"retry me\" signal \u2014 the deterministic publisher needs that file, and\n # the agent occasionally finishes a turn without writing it. Retry once.\n if [ ! -s recap-source.json ]; then\n if grep -Eiq -- 'quota exceeded|billing details|insufficient (credits|quota)|rate[-_ ]limit|invalid (api )?key|authentication (failed|error)|unauthorized|forbidden' claude-result.json claude-stderr.log 2>/dev/null; then\n echo \"::error::Visual recap agent failed with a non-retryable provider error; skipping the duplicate retry.\"\n else\n echo \"::warning::recap-source.json missing after the agent run; retrying the agent once.\"\n sleep 5\n run_claude\n fi\n fi\n\n - name: Run agent (Codex)\n id: codex\n if: needs.gate.outputs.agent == 'codex' && steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n continue-on-error: true\n env:\n OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n run: |\n set -uo pipefail\n # `codex login` writes ~/.codex/auth.json (the bare env var is dropped on\n # the gpt-5.5 wss transport); stdin keeps the key out of process args.\n printenv OPENAI_API_KEY | npx -y @openai/codex@0 login --with-api-key || true\n # The runner is itself an ephemeral sandbox; bypass Codex's own sandbox\n # (bubblewrap can't init here) and approval gate (cancels the MCP write).\n CODEX_ARGS=(exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check)\n if [ -n \"${VISUAL_RECAP_MODEL:-}\" ]; then CODEX_ARGS+=(--model \"$VISUAL_RECAP_MODEL\"); fi\n # Validate reasoning against the enum before embedding it in the TOML override.\n case \"${VISUAL_RECAP_REASONING:-}\" in\n none|minimal|low|medium|high|xhigh)\n CODEX_ARGS+=(-c \"model_reasoning_effort=\\\"$VISUAL_RECAP_REASONING\\\"\") ;;\n \"\") ;;\n *) echo \"Ignoring invalid VISUAL_RECAP_REASONING: $VISUAL_RECAP_REASONING\" ;;\n esac\n rm -f recap-source.json recap-url.txt recap-url-reason.txt codex-events.jsonl codex-stderr.log\n run_codex() {\n set +e\n npx -y @openai/codex@0 \"${CODEX_ARGS[@]}\" --json \"$(cat recap-prompt.md)\" 2> codex-stderr.log | tee codex-events.jsonl\n CODEX_STATUS=\"${PIPESTATUS[0]}\"\n set -e\n echo \"$CODEX_STATUS\" > codex-exit-code.txt\n }\n run_codex\n # Retry once if the agent exited without writing recap-source.json\n # (see the Claude step) \u2014 the publisher needs that file.\n if [ ! -s recap-source.json ]; then\n if grep -Eiq -- 'quota exceeded|billing details|insufficient (credits|quota)|rate[-_ ]limit|invalid (api )?key|authentication (failed|error)|unauthorized|forbidden' codex-events.jsonl codex-stderr.log 2>/dev/null; then\n echo \"::error::Visual recap agent failed with a non-retryable provider error; skipping the duplicate retry.\"\n else\n echo \"::warning::recap-source.json missing after the agent run; retrying the agent once.\"\n sleep 5\n run_codex\n fi\n fi\n\n - name: Run agent (OpenAI-compatible)\n id: openai_compatible\n if: needs.gate.outputs.agent == 'openai-compatible' && steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n continue-on-error: true\n env:\n OPENAI_API_KEY: ${{ secrets.VISUAL_RECAP_API_KEY }}\n OPENAI_BASE_URL: ${{ vars.VISUAL_RECAP_BASE_URL }}\n AGENT_ENGINE: ai-sdk:openai\n AGENT_MODEL: ${{ vars.VISUAL_RECAP_MODEL }}\n AGENT_NATIVE_CODE_USAGE_FILE: openai-compatible-usage.json\n AGENT_NATIVE_CODE_TOOL_PROFILE: recap-source\n run: |\n set -uo pipefail\n rm -f recap-source.json recap-url.txt recap-url-reason.txt openai-compatible-result.txt openai-compatible-usage.json openai-compatible-stderr.log\n run_openai_compatible() {\n set +e\n $CODE_CLI code exec --permission-mode auto-edit \"$(cat recap-prompt.md)\" > openai-compatible-result.txt 2> openai-compatible-stderr.log\n OPENAI_COMPATIBLE_STATUS=\"$?\"\n set -e\n echo \"$OPENAI_COMPATIBLE_STATUS\" > openai-compatible-exit-code.txt\n }\n run_openai_compatible\n if [ ! -s recap-source.json ]; then\n if grep -Eiq -- 'quota exceeded|billing details|insufficient (credits|quota)|rate[-_ ]limit|invalid (api )?key|authentication (failed|error)|unauthorized|forbidden' openai-compatible-result.txt openai-compatible-stderr.log 2>/dev/null; then\n echo \"::error::Visual recap agent failed with a non-retryable provider error; skipping the duplicate retry.\"\n else\n echo \"::warning::recap-source.json missing after the agent run; retrying the agent once.\"\n sleep 5\n run_openai_compatible\n fi\n fi\n\n - name: Publish recap source\n id: publish\n if: steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n continue-on-error: true\n env:\n PREV_PLAN_ID: ${{ steps.prev.outputs.plan_id }}\n run: |\n set -uo pipefail\n ARGS=(--source recap-source.json --out recap-url.txt --repo \"$GITHUB_REPOSITORY\" --pr \"$PR_NUMBER\" --app-url \"$PLAN_RECAP_APP_URL\" --token \"$PLAN_RECAP_TOKEN\")\n if [ -n \"${PREV_PLAN_ID:-}\" ]; then ARGS+=(--prev-plan-id \"$PREV_PLAN_ID\"); fi\n ARGS+=(--source-type pull-request --source-repo \"$GITHUB_REPOSITORY\" --source-pr-number \"$PR_NUMBER\")\n if [ \"${PR_MERGED:-false}\" = \"true\" ] || [ -n \"${PR_MERGED_AT:-}\" ]; then\n ARGS+=(--source-pr-state merged)\n elif [ -n \"${PR_STATE:-}\" ]; then\n ARGS+=(--source-pr-state \"$PR_STATE\")\n fi\n if [ -n \"${PR_MERGED_AT:-}\" ]; then ARGS+=(--source-pr-merged-at \"$PR_MERGED_AT\"); fi\n $RECAP_CLI recap publish \"${ARGS[@]}\"\n\n - name: Build one-shot recap repair prompt\n id: repair_prompt\n if: steps.publish.outputs.repairable == 'true'\n run: |\n set -euo pipefail\n cp recap-source.json recap-source.initial.json\n $RECAP_CLI recap repair-prompt --source recap-source.json --reason-file recap-url-reason.txt --out recap-repair-prompt.md\n\n - name: Repair recap source (Claude Code)\n id: claude_repair\n if: steps.publish.outputs.repairable == 'true' && needs.gate.outputs.agent == 'claude'\n continue-on-error: true\n env:\n ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n run: |\n set -uo pipefail\n CLAUDE_ALLOWED_TOOLS=\"Read,Write\"\n CLAUDE_ARGS=(-p \"$(cat recap-repair-prompt.md)\" --allowedTools \"$CLAUDE_ALLOWED_TOOLS\" --permission-mode dontAsk --output-format json)\n CLAUDE_ARGS+=(--model \"${VISUAL_RECAP_MODEL:-claude-sonnet-5}\")\n rm -f claude-repair-result.json claude-repair-stderr.log\n set +e\n npx -y @anthropic-ai/claude-code@2 \"${CLAUDE_ARGS[@]}\" > claude-repair-result.json 2> claude-repair-stderr.log\n CLAUDE_REPAIR_STATUS=\"$?\"\n set -e\n echo \"$CLAUDE_REPAIR_STATUS\" > claude-repair-exit-code.txt\n if [ \"$CLAUDE_REPAIR_STATUS\" -eq 0 ]; then echo \"ok=true\" >> \"$GITHUB_OUTPUT\"; else echo \"ok=false\" >> \"$GITHUB_OUTPUT\"; fi\n\n - name: Repair recap source (Codex)\n id: codex_repair\n if: steps.publish.outputs.repairable == 'true' && needs.gate.outputs.agent == 'codex'\n continue-on-error: true\n env:\n OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n run: |\n set -uo pipefail\n printenv OPENAI_API_KEY | npx -y @openai/codex@0 login --with-api-key || true\n CODEX_ARGS=(exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check)\n if [ -n \"${VISUAL_RECAP_MODEL:-}\" ]; then CODEX_ARGS+=(--model \"$VISUAL_RECAP_MODEL\"); fi\n case \"${VISUAL_RECAP_REASONING:-}\" in\n none|minimal|low|medium|high|xhigh)\n CODEX_ARGS+=(-c \"model_reasoning_effort=\\\"$VISUAL_RECAP_REASONING\\\"\") ;;\n \"\") ;;\n *) echo \"Ignoring invalid VISUAL_RECAP_REASONING: $VISUAL_RECAP_REASONING\" ;;\n esac\n rm -f codex-repair-events.jsonl codex-repair-stderr.log\n set +e\n npx -y @openai/codex@0 \"${CODEX_ARGS[@]}\" --json \"$(cat recap-repair-prompt.md)\" 2> codex-repair-stderr.log | tee codex-repair-events.jsonl\n CODEX_REPAIR_STATUS=\"${PIPESTATUS[0]}\"\n set -e\n echo \"$CODEX_REPAIR_STATUS\" > codex-repair-exit-code.txt\n if [ \"$CODEX_REPAIR_STATUS\" -eq 0 ]; then echo \"ok=true\" >> \"$GITHUB_OUTPUT\"; else echo \"ok=false\" >> \"$GITHUB_OUTPUT\"; fi\n\n - name: Repair recap source (OpenAI-compatible)\n id: openai_compatible_repair\n if: steps.publish.outputs.repairable == 'true' && needs.gate.outputs.agent == 'openai-compatible'\n continue-on-error: true\n env:\n OPENAI_API_KEY: ${{ secrets.VISUAL_RECAP_API_KEY }}\n OPENAI_BASE_URL: ${{ vars.VISUAL_RECAP_BASE_URL }}\n AGENT_ENGINE: ai-sdk:openai\n AGENT_MODEL: ${{ vars.VISUAL_RECAP_MODEL }}\n AGENT_NATIVE_CODE_USAGE_FILE: openai-compatible-repair-usage.json\n AGENT_NATIVE_CODE_TOOL_PROFILE: recap-source\n run: |\n set -uo pipefail\n rm -f openai-compatible-repair-result.txt openai-compatible-repair-usage.json openai-compatible-repair-stderr.log\n set +e\n $CODE_CLI code exec --permission-mode auto-edit \"$(cat recap-repair-prompt.md)\" > openai-compatible-repair-result.txt 2> openai-compatible-repair-stderr.log\n OPENAI_COMPATIBLE_REPAIR_STATUS=\"$?\"\n set -e\n echo \"$OPENAI_COMPATIBLE_REPAIR_STATUS\" > openai-compatible-repair-exit-code.txt\n if [ \"$OPENAI_COMPATIBLE_REPAIR_STATUS\" -eq 0 ]; then echo \"ok=true\" >> \"$GITHUB_OUTPUT\"; else echo \"ok=false\" >> \"$GITHUB_OUTPUT\"; fi\n\n - name: Validate repaired recap source\n id: repaired_source\n if: steps.publish.outputs.repairable == 'true'\n env:\n REPAIR_AGENT_OK: ${{ steps.claude_repair.outputs.ok || steps.codex_repair.outputs.ok || steps.openai_compatible_repair.outputs.ok }}\n run: |\n set -uo pipefail\n REPAIR_REASON=\"\"\n if [ \"${REPAIR_AGENT_OK:-false}\" != \"true\" ]; then\n echo \"ok=false\" >> \"$GITHUB_OUTPUT\"\n REPAIR_REASON=\"Repair agent exited unsuccessfully; repaired source was not published.\"\n else\n VALIDATION_JSON=\"$(GITHUB_OUTPUT=/dev/null $RECAP_CLI recap validate-repair --original recap-source.initial.json --source recap-source.json --reason-file recap-url-reason.txt || true)\"\n REPAIR_OK=\"$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).ok===true?\"true\":\"false\")}catch{process.stdout.write(\"false\")}' \"$VALIDATION_JSON\")\"\n REPAIR_REASON=\"$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).reason||\"\")}catch{process.stdout.write(\"Repair validation returned invalid output.\")}' \"$VALIDATION_JSON\")\"\n echo \"ok=$REPAIR_OK\" >> \"$GITHUB_OUTPUT\"\n fi\n if [ -n \"$REPAIR_REASON\" ]; then\n echo \"$REPAIR_REASON\" > recap-url-reason.txt\n fi\n {\n echo 'reason<<__RECAP_REPAIR_REASON_EOF__'\n echo \"$REPAIR_REASON\"\n echo '__RECAP_REPAIR_REASON_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n\n - name: Publish repaired recap source\n id: publish_repair\n if: steps.repaired_source.outputs.ok == 'true'\n continue-on-error: true\n env:\n PREV_PLAN_ID: ${{ steps.prev.outputs.plan_id }}\n run: |\n set -uo pipefail\n ARGS=(--source recap-source.json --out recap-url.txt --repo \"$GITHUB_REPOSITORY\" --pr \"$PR_NUMBER\" --app-url \"$PLAN_RECAP_APP_URL\" --token \"$PLAN_RECAP_TOKEN\")\n if [ -n \"${PREV_PLAN_ID:-}\" ]; then ARGS+=(--prev-plan-id \"$PREV_PLAN_ID\"); fi\n ARGS+=(--source-type pull-request --source-repo \"$GITHUB_REPOSITORY\" --source-pr-number \"$PR_NUMBER\")\n if [ \"${PR_MERGED:-false}\" = \"true\" ] || [ -n \"${PR_MERGED_AT:-}\" ]; then\n ARGS+=(--source-pr-state merged)\n elif [ -n \"${PR_STATE:-}\" ]; then\n ARGS+=(--source-pr-state \"$PR_STATE\")\n fi\n if [ -n \"${PR_MERGED_AT:-}\" ]; then ARGS+=(--source-pr-merged-at \"$PR_MERGED_AT\"); fi\n $RECAP_CLI recap publish \"${ARGS[@]}\"\n\n - name: Read plan URL\n id: url\n if: steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n run: |\n set -uo pipefail\n PLAN_URL=\"\"\n URL_REASON=\"\"\n if [ -f recap-url.txt ]; then\n PLAN_URL=\"$(tr -d '\\r\\n' < recap-url.txt | tr -d ' ')\"\n elif [ -f recap-url-reason.txt ]; then\n URL_REASON=\"$(cat recap-url-reason.txt)\"\n else\n URL_REASON=\"recap-url.txt was not created.\"\n fi\n # recap-url.txt is agent-written -> untrusted. Rebuild a canonical\n # recap URL from the trusted app base and a strictly validated plan id,\n # preserving path-prefixed self-hosted mounts.\n if [ -z \"$URL_REASON\" ]; then\n URL_RESULT=$(PLAN_URL=\"$PLAN_URL\" node <<'NODE'\n const emit = (value) => process.stdout.write(JSON.stringify(value));\n try {\n const raw = process.env.PLAN_URL || \"\";\n if (!raw) {\n emit({ url: \"\", reason: \"recap-url.txt was empty\" });\n process.exit(0);\n }\n const trusted = new URL(process.env.PLAN_RECAP_APP_URL || \"https://plan.agent-native.com\");\n const parsed = /^https?:\\/\\//i.test(raw)\n ? new URL(raw)\n : new URL(raw, trusted);\n if (parsed.origin !== trusted.origin) {\n emit({ url: \"\", reason: `recap-url.txt points at ${parsed.origin}, expected ${trusted.origin}` });\n process.exit(0);\n }\n\n const base = trusted.pathname.replace(/\\/$/, \"\");\n const paths = [parsed.pathname];\n if (base && parsed.pathname.startsWith(`${base}/`)) {\n paths.push(parsed.pathname.slice(base.length) || \"/\");\n }\n\n for (const path of paths) {\n const match = path.match(/^\\/(?:plans|recaps)\\/([A-Za-z0-9_-]+)\\/?$/);\n if (match) {\n emit({ url: `${trusted.origin}${base}/recaps/${match[1]}`, reason: \"\" });\n process.exit(0);\n }\n }\n emit({ url: \"\", reason: \"recap-url.txt did not contain a valid /plans/<id> or /recaps/<id> URL for the configured plan app\" });\n } catch {\n emit({ url: \"\", reason: \"recap-url.txt was not a valid URL or recap path\" });\n }\n NODE\n )\n CANONICAL_URL=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).url||\"\")}catch{process.stdout.write(\"\")}' \"$URL_RESULT\")\n URL_REASON=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).reason||\"\")}catch{process.stdout.write(\"recap-url.txt URL validation failed\")}' \"$URL_RESULT\")\n else\n CANONICAL_URL=\"\"\n fi\n if [ -n \"$CANONICAL_URL\" ]; then\n echo \"plan_url=$CANONICAL_URL\" >> \"$GITHUB_OUTPUT\"; echo \"ok=true\" >> \"$GITHUB_OUTPUT\"\n else\n echo \"plan_url=\" >> \"$GITHUB_OUTPUT\"; echo \"ok=false\" >> \"$GITHUB_OUTPUT\"\n fi\n {\n echo 'reason<<__RECAP_URL_REASON_EOF__'\n echo \"$URL_REASON\"\n echo '__RECAP_URL_REASON_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n\n - name: Summarize agent failure\n id: agent_summary\n if: steps.url.outputs.ok != 'true' && steps.diff.outputs.tiny != 'true' && steps.route_health.outputs.unhealthy != 'true' && steps.scan.outputs.suppressed != 'true'\n continue-on-error: true\n env:\n RECAP_AGENT: ${{ needs.gate.outputs.agent }}\n RECAP_REPAIR_ATTEMPTED: ${{ steps.repair_prompt.outcome == 'success' }}\n RECAP_BLOCK_REFERENCE_SUMMARY: ${{ steps.block_reference.outputs.summary }}\n RECAP_PUBLISH_REASON: ${{ steps.repaired_source.outputs.reason || steps.publish_repair.outputs.reason || steps.publish.outputs.reason }}\n run: |\n set -uo pipefail\n RESULT=claude-result.json\n STDERR=claude-stderr.log\n EXIT_CODE=claude-exit-code.txt\n if [ \"$RECAP_AGENT\" = \"codex\" ]; then\n RESULT=codex-events.jsonl\n STDERR=codex-stderr.log\n EXIT_CODE=codex-exit-code.txt\n elif [ \"$RECAP_AGENT\" = \"openai-compatible\" ]; then\n RESULT=openai-compatible-result.txt\n STDERR=openai-compatible-stderr.log\n EXIT_CODE=openai-compatible-exit-code.txt\n fi\n if [ \"$RECAP_REPAIR_ATTEMPTED\" = \"true\" ]; then\n RESULT=claude-repair-result.json\n STDERR=claude-repair-stderr.log\n EXIT_CODE=claude-repair-exit-code.txt\n if [ \"$RECAP_AGENT\" = \"codex\" ]; then\n RESULT=codex-repair-events.jsonl\n STDERR=codex-repair-stderr.log\n EXIT_CODE=codex-repair-exit-code.txt\n elif [ \"$RECAP_AGENT\" = \"openai-compatible\" ]; then\n RESULT=openai-compatible-repair-result.txt\n STDERR=openai-compatible-repair-stderr.log\n EXIT_CODE=openai-compatible-repair-exit-code.txt\n fi\n fi\n SUMMARY_JSON=\"$(GITHUB_OUTPUT=/dev/null $RECAP_CLI recap agent-summary --agent \"$RECAP_AGENT\" --result-file \"$RESULT\" --stderr-file \"$STDERR\" --exit-code-file \"$EXIT_CODE\" || echo '{}')\"\n SUMMARY=\"$(node -e 'try { const value = JSON.parse(process.argv[1]).summary; process.stdout.write(typeof value === \"string\" ? value : \"\"); } catch {}' \"$SUMMARY_JSON\")\"\n if [ -n \"$SUMMARY\" ]; then\n {\n echo 'summary<<__RECAP_AGENT_SUMMARY_EOF__'\n echo \"$SUMMARY\"\n echo '__RECAP_AGENT_SUMMARY_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n elif [ -n \"${RECAP_BLOCK_REFERENCE_SUMMARY:-}\" ]; then\n {\n echo 'summary<<__RECAP_BLOCK_REFERENCE_SUMMARY_EOF__'\n echo \"$RECAP_BLOCK_REFERENCE_SUMMARY\"\n echo '__RECAP_BLOCK_REFERENCE_SUMMARY_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n elif [ -n \"${RECAP_PUBLISH_REASON:-}\" ]; then\n {\n echo 'summary<<__RECAP_PUBLISH_SUMMARY_EOF__'\n echo \"$RECAP_PUBLISH_REASON\"\n echo '__RECAP_PUBLISH_SUMMARY_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n fi\n\n - name: Attach usage\n if: steps.url.outputs.ok == 'true'\n continue-on-error: true\n env:\n PLAN_URL: ${{ steps.url.outputs.plan_url }}\n # Use the gate-normalized agent so \"Codex\" still selects the right file.\n RECAP_AGENT: ${{ needs.gate.outputs.agent }}\n RECAP_REPAIR_SUCCEEDED: ${{ steps.publish_repair.outcome == 'success' }}\n run: |\n set -uo pipefail\n RESULT=claude-result.json\n if [ \"$RECAP_AGENT\" = \"codex\" ]; then RESULT=codex-events.jsonl; fi\n if [ \"$RECAP_AGENT\" = \"openai-compatible\" ]; then RESULT=openai-compatible-usage.json; fi\n if [ \"$RECAP_REPAIR_SUCCEEDED\" = \"true\" ]; then\n RESULT=claude-repair-result.json\n if [ \"$RECAP_AGENT\" = \"codex\" ]; then RESULT=codex-repair-events.jsonl; fi\n if [ \"$RECAP_AGENT\" = \"openai-compatible\" ]; then RESULT=openai-compatible-repair-usage.json; fi\n fi\n if [ -f \"$RESULT\" ]; then $RECAP_CLI recap usage --plan-url \"$PLAN_URL\" --agent \"$RECAP_AGENT\" --result-file \"$RESULT\" --model \"${VISUAL_RECAP_MODEL:-}\" --app-url \"$PLAN_RECAP_APP_URL\" --token \"$PLAN_RECAP_TOKEN\" || true; fi\n\n - name: Cache Playwright browsers\n if: steps.url.outputs.ok == 'true'\n uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3\n with:\n path: ~/.cache/ms-playwright\n key: playwright-1-${{ runner.os }}\n\n - name: Screenshot + upload\n id: shot\n if: steps.url.outputs.ok == 'true'\n continue-on-error: true\n env:\n # recap-url.txt is untrusted agent output; pass via env, never ${{ }}.\n PLAN_URL: ${{ steps.url.outputs.plan_url }}\n run: |\n set -uo pipefail\n if [ -n \"${RECAP_PLAYWRIGHT:-}\" ] && [ -x \"$RECAP_PLAYWRIGHT\" ]; then\n \"$RECAP_PLAYWRIGHT\" install --with-deps chromium || true\n elif command -v pnpm >/dev/null 2>&1; then\n pnpm exec playwright install --with-deps chromium 2>/dev/null || npx -y playwright@1 install --with-deps chromium || true\n else\n npx -y playwright@1 install --with-deps chromium || true\n fi\n IMAGE_CACHE_KEY=\"$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT\"\n LIGHT_SHOT_JSON=\"$($RECAP_CLI recap shot --url \"$PLAN_URL\" --token \"$PLAN_RECAP_TOKEN\" --app-url \"$PLAN_RECAP_APP_URL\" --out recap.png --theme light --image-cache-key \"$IMAGE_CACHE_KEY\" || echo '{}')\"\n DARK_SHOT_JSON=\"$($RECAP_CLI recap shot --url \"$PLAN_URL\" --token \"$PLAN_RECAP_TOKEN\" --app-url \"$PLAN_RECAP_APP_URL\" --out recap-dark.png --theme dark --image-cache-key \"$IMAGE_CACHE_KEY\" || echo '{}')\"\n for SHOT_LABEL in light dark; do\n if [ \"$SHOT_LABEL\" = \"light\" ]; then SHOT_JSON=\"$LIGHT_SHOT_JSON\"; else SHOT_JSON=\"$DARK_SHOT_JSON\"; fi\n SHOT_LABEL=\"$SHOT_LABEL\" SHOT_JSON=\"$SHOT_JSON\" node -e 'const label = process.env.SHOT_LABEL || \"shot\"; let parsed = {}; try { parsed = JSON.parse(process.env.SHOT_JSON || \"{}\"); } catch { parsed = { ok: false, reason: \"invalid shot JSON\" }; } const summary = { ok: parsed.ok === true, imageUrl: parsed.imageUrl ? \"[present]\" : \"\", out: typeof parsed.out === \"string\" ? parsed.out : \"\", reason: typeof parsed.reason === \"string\" ? parsed.reason.slice(0, 500) : \"\" }; console.log(`[recap shot] ${label}: ${JSON.stringify(summary)}`);'\n done\n IMAGE_URL=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).imageUrl||\"\")}catch{process.stdout.write(\"\")}' \"$LIGHT_SHOT_JSON\")\n DARK_IMAGE_URL=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).imageUrl||\"\")}catch{process.stdout.write(\"\")}' \"$DARK_SHOT_JSON\")\n SHOT_STATUS=$(LIGHT_SHOT_JSON=\"$LIGHT_SHOT_JSON\" DARK_SHOT_JSON=\"$DARK_SHOT_JSON\" node <<'NODE'\n const parse = (raw) => { try { return JSON.parse(raw || \"{}\"); } catch { return { ok: false, reason: \"invalid shot JSON\" }; } };\n const shots = [[\"light\", parse(process.env.LIGHT_SHOT_JSON)], [\"dark\", parse(process.env.DARK_SHOT_JSON)]];\n const hasImage = shots.some(([, shot]) => typeof shot.imageUrl === \"string\" && shot.imageUrl.trim());\n const reasons = shots.flatMap(([label, shot]) => {\n if (typeof shot.reason === \"string\" && shot.reason.trim()) return [`${label}: ${shot.reason.trim()}`];\n if (!(typeof shot.imageUrl === \"string\" && shot.imageUrl.trim())) return [`${label}: no imageUrl returned`];\n return [];\n });\n process.stdout.write(JSON.stringify({ ok: hasImage, reason: hasImage ? \"\" : reasons.join(\"; \").slice(0, 1000) }));\n NODE\n )\n SHOT_OK=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).ok===true?\"true\":\"false\")}catch{process.stdout.write(\"false\")}' \"$SHOT_STATUS\")\n SHOT_REASON=$(node -e 'try{process.stdout.write(JSON.parse(process.argv[1]).reason||\"\")}catch{process.stdout.write(\"invalid shot status JSON\")}' \"$SHOT_STATUS\")\n if [ \"$SHOT_OK\" != \"true\" ]; then\n echo \"::warning::Visual recap screenshot unavailable; posting screenshot-failed recap comment. $SHOT_REASON\"\n fi\n echo \"image_url=$IMAGE_URL\" >> \"$GITHUB_OUTPUT\"\n echo \"light_image_url=$IMAGE_URL\" >> \"$GITHUB_OUTPUT\"\n echo \"dark_image_url=$DARK_IMAGE_URL\" >> \"$GITHUB_OUTPUT\"\n echo \"shot_ok=$SHOT_OK\" >> \"$GITHUB_OUTPUT\"\n {\n echo 'shot_reason<<__RECAP_SHOT_REASON_EOF__'\n echo \"$SHOT_REASON\"\n echo '__RECAP_SHOT_REASON_EOF__'\n } >> \"$GITHUB_OUTPUT\"\n if [ -f recap.png ] || [ -f recap-dark.png ]; then echo \"captured=true\" >> \"$GITHUB_OUTPUT\"; else echo \"captured=false\" >> \"$GITHUB_OUTPUT\"; fi\n\n - name: Upload recap screenshot artifact\n if: steps.shot.outputs.captured == 'true'\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n with:\n name: pr-visual-recap-${{ github.event.pull_request.number }}\n path: |\n recap.png\n recap-dark.png\n if-no-files-found: ignore\n retention-days: 14\n\n - name: Upload recap source artifact\n if: always() && !cancelled()\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n with:\n # recap-source.json + the agent transcript (claude-result.json /\n # codex-events.jsonl + stderr) are the only window into WHAT the agent\n # did when a publish fails (no plan URL) \u2014 INCLUDING the case where it\n # finished without writing recap-source.json at all. The sticky comment\n # only shows the screenshot, so without these a failed recap is\n # undebuggable. Uploaded on success + failure; tolerant when absent.\n name: pr-visual-recap-source-${{ github.event.pull_request.number }}\n path: |\n recap-source.json\n recap-source.initial.json\n recap-url-reason.txt\n recap-repair-prompt.md\n claude-result.json\n claude-stderr.log\n claude-repair-result.json\n claude-repair-stderr.log\n claude-repair-exit-code.txt\n codex-events.jsonl\n codex-stderr.log\n codex-repair-events.jsonl\n codex-repair-stderr.log\n codex-repair-exit-code.txt\n openai-compatible-result.txt\n openai-compatible-usage.json\n openai-compatible-stderr.log\n openai-compatible-repair-result.txt\n openai-compatible-repair-usage.json\n openai-compatible-repair-stderr.log\n openai-compatible-repair-exit-code.txt\n if-no-files-found: ignore\n retention-days: 14\n\n - name: Upsert sticky comment\n if: always() && !cancelled()\n continue-on-error: true\n env:\n PLAN_URL: ${{ steps.url.outputs.plan_url }}\n RECAP_IMAGE_URL: ${{ steps.shot.outputs.image_url }}\n RECAP_LIGHT_IMAGE_URL: ${{ steps.shot.outputs.light_image_url }}\n RECAP_DARK_IMAGE_URL: ${{ steps.shot.outputs.dark_image_url }}\n RECAP_SHOT_OK: ${{ steps.shot.outputs.shot_ok }}\n RECAP_SHOT_REASON: ${{ steps.shot.outputs.shot_reason }}\n SUPPRESSED: ${{ steps.scan.outputs.suppressed }}\n SUPPRESSED_JSON: ${{ steps.scan.outputs.json }}\n DIFF_HUGE: ${{ steps.diff.outputs.huge }}\n DIFF_TINY: ${{ steps.diff.outputs.tiny }}\n PREV_PLAN_ID: ${{ steps.prev.outputs.plan_id }}\n RECAP_AUTH_FAILED: ${{ steps.auth_probe.outputs.auth_failed }}\n RECAP_AGENT_SUMMARY: ${{ steps.agent_summary.outputs.summary }}\n # Prefer the route-health diagnostic when the plan app routes are not\n # yet deployed so the comment explains the 404 instead of a generic\n # \"recap-url.txt was not created\" message.\n RECAP_URL_REASON: ${{ steps.route_health.outputs.reason || steps.url.outputs.reason }}\n run: |\n set -euo pipefail\n $RECAP_CLI recap comment upsert --repo \"$GITHUB_REPOSITORY\" --issue \"$PR_NUMBER\" --token \"$GH_TOKEN\" --head-sha \"$HEAD_SHA\"\n\n - name: Complete visual recap check\n if: always() && !cancelled() && steps.recap_check.outputs.check_run_id != ''\n continue-on-error: true\n env:\n # Untrusted/step values via env (NOT ${{ }}-interpolated into the run\n # body): the agent-written plan URL and the scan JSON could inject shell.\n CHECK_RUN_ID: ${{ steps.recap_check.outputs.check_run_id }}\n PLAN_OK: ${{ steps.url.outputs.ok }}\n PLAN_URL: ${{ steps.url.outputs.plan_url }}\n SUPPRESSED: ${{ steps.scan.outputs.suppressed }}\n SUPPRESSED_JSON: ${{ steps.scan.outputs.json }}\n DIFF_HUGE: ${{ steps.diff.outputs.huge }}\n DIFF_TINY: ${{ steps.diff.outputs.tiny }}\n RECAP_AGENT_SUMMARY: ${{ steps.agent_summary.outputs.summary }}\n RECAP_URL_REASON: ${{ steps.route_health.outputs.reason || steps.url.outputs.reason }}\n run: |\n set -uo pipefail\n $RECAP_CLI recap check complete \\\n --check-run-id \"$CHECK_RUN_ID\" \\\n --plan-ok \"$PLAN_OK\" \\\n --plan-url \"$PLAN_URL\" \\\n --suppressed \"$SUPPRESSED\" \\\n --suppressed-json \"$SUPPRESSED_JSON\" \\\n --huge \"$DIFF_HUGE\" \\\n --tiny \"$DIFF_TINY\" \\\n --failure-summary \"$RECAP_AGENT_SUMMARY\" \\\n --url-reason \"$RECAP_URL_REASON\" \\\n --workflow-url \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\"\n";
|
|
1
|
+
/** Compatibility re-export for the workflow bundled by the recap CLI package. */
|
|
2
|
+
export { PR_VISUAL_RECAP_WORKFLOW_YML } from "@agent-native/recap-cli";
|
|
3
3
|
//# sourceMappingURL=pr-visual-recap-workflow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-visual-recap-workflow.d.ts","sourceRoot":"","sources":["../../src/cli/pr-visual-recap-workflow.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"pr-visual-recap-workflow.d.ts","sourceRoot":"","sources":["../../src/cli/pr-visual-recap-workflow.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC"}
|