import type { AgentActionScope } from "../agent/types.js"; import type { TrackingEventScope } from "../observability/tracing.js"; import type { ContextStatus } from "../shared/context-status.js"; import type { FirstRunBuilderCreditsV2RequestAssignment } from "../shared/first-run-builder-credits-experiment.js"; import type { ReasoningEffort } from "../shared/reasoning-effort.js"; import type { SignupAttributionContext } from "./attribution.js"; export interface RequestRunContext { waitUntil?: (promise: Promise) => void; requestOrigin?: string; browserTabId?: string; chatScope?: { type: string; id: string; label?: string; } | null; owner?: string; userApiKey?: string; userApiKeyEnvVar?: string; threadId?: string; runId?: string; systemPrompt?: string; engine?: import("../agent/engine/types.js").AgentEngine; model?: string; /** The run's resolved thinking effort; unset when the model takes none. */ reasoningEffort?: ReasoningEffort; allowedActionNames?: readonly string[]; actionScope?: Readonly; appAuthorization?: { appId: string; roles: string[]; permissions: Record; } | null; hostedHarnessRuntime?: "claude-code" | "codex" | "pi" | "opencode"; isBackgroundWorker?: boolean; analyticsJevPrefetch?: { preloadedReferenceCount: number; }; /** Whether the pre-model reference prefetch and screen grounding reached the model. */ contextStatus?: { prefetch?: ContextStatus; screen?: ContextStatus; }; /** Current user text used to rank reachable workspace apps for this turn. */ appDiscoveryQuery?: string; /** Privacy-safe app discovery result diagnostics for the current run. */ appDiscoverySelection?: { status: "selected" | "no-match" | "unavailable" | "failed" | "timed_out"; directoryStatus: "available" | "unavailable" | "forbidden" | "setup-required"; selectedIds: string[]; latencyMs: number; }; toolCalls?: Array<{ name: string; input: unknown; }>; toolResults?: Array<{ name: string; content: string; isError: boolean; }>; extensionContentReads?: Record; extensionExcerptReads?: Record; toolSearchReads?: Record; /** Signup-time question-intake assignment loaded for this authenticated run. */ questionIntakeExperimentAssignment?: { authUserId: string; experimentId: string; variantId: "control" | "no_questions"; }; /** Tools unavailable to the current agent run and its tool-search surface. */ excludedActionNames?: readonly string[]; } export interface RequestContext { /** * The id the server stamps on this request's response, so a failure captured * anywhere in the request names the id the person sees on screen. */ requestId?: string; isSyntheticTraffic?: boolean; mcpRequestId?: string; userEmail?: string; /** Provenance for a cross-app identity; org-member grants only member-level org role. */ a2aIdentityAssurance?: "user" | "organization" | "org-member"; /** Keep data-source credentials within the selected org, not the user. */ credentialScope?: "org"; /** Storage-only org selection; null prevents an active-org fallback. */ builderStorageCredentialOrgId?: string | null; /** Provenance set only after a stored org service token is verified. */ verifiedServiceIdentity?: { userEmail: string; orgId: string; }; identityAuthenticatedAtMs?: number; identitySessionToken?: string; /** Signed MCP credential issue time, used to revoke derived widget grants. */ mcpCredentialIssuedAtMs?: number | null; authUserId?: string; agentRunAnonymous?: boolean; userName?: string; orgId?: string; orgScope?: "personal"; /** Explicitly selects deployment-wide agent defaults for shared no-org jobs. */ defaultAgentEngineScope?: "deployment"; /** * Narrow authorization capability verified from an embed session. This is * deliberately separate from user identity: capability-only sessions must * not satisfy account-backed auth or inherit the ticket owner's privileges. */ authCapability?: string; timezone?: string; /** * The caller's browser analytics session id, when the request came from a * page. Emitted as PostHog's `$session_id` so agent traces join to session * replay; never used for authorization. */ browserSessionId?: string; trackingScope?: TrackingEventScope; /** * Browser attribution captured before a Better Auth signup crosses into its * async user-create hook. Analytics-only; never used for authorization. */ signupAttribution?: SignupAttributionContext; signupOrigin?: import("./attribution.js").SignupOrigin; clientPlatform?: import("../shared/analytics-platform.js").AnalyticsClientPlatform; /** * Set only after the authenticated first-run route confirms the v2 flag is * enabled; tracking uses it to tag the four durable experiment events. */ firstRunBuilderCreditsV2Assignment?: FirstRunBuilderCreditsV2RequestAssignment; authContextAccessed?: boolean; requestOrigin?: string; federationMembershipValidated?: boolean; /** Resolves embed authority independently of the origin used for MCP links. */ resolveEmbedRequestOrigin?: () => string; /** * True when the request's real socket peer is loopback, captured by the * action-route handler while the h3 event is still in scope (nothing below * that layer can see the event). Derived from `getRequestIP()` WITHOUT * `x-forwarded-for`, so a remote client cannot set it via headers. * * A local-dev gate only. A tunnel or reverse proxy that reaches the dev * server over loopback also presents as loopback, so this is necessary but * not sufficient on its own — pair it with something that scopes the blast * radius (a resource that is itself local-only, NODE_ENV, etc.). */ isLoopbackRequest?: boolean; /** True only when this server received the request directly on 127.0.0.1. */ isDirectLoopbackRequest?: boolean; isIntegrationCaller?: boolean; integration?: { taskId: string; attempts?: number; incoming: import("../integrations/types.js").IncomingMessage; placeholderRef?: string; progressRef?: import("../integrations/types.js").PlatformRunProgressRef; installationId?: string; scopeId?: string; principalType?: "user" | "service"; lineage?: { runId?: string; parentTaskId?: string; source?: { kind: string; platform?: string; id: string; url?: string; }; network?: { protocol: "a2a" | "mcp" | "provider-api"; id: string; peer?: string; }; }; }; run?: RequestRunContext; } type RequestContextEvent = { context?: Record; }; export declare function markVerifiedServiceIdentityForEvent(event: RequestContextEvent, identity: { userEmail: string; orgId: string; }): void; export declare function getVerifiedServiceIdentityFromEvent(event: RequestContextEvent): { userEmail: string; orgId: string; } | undefined; /** * The request authenticated with an MCP credential this app verified, so an * action route records the call as MCP rather than as a person's HTTP call. */ export declare function markVerifiedMcpCredentialForEvent(event: RequestContextEvent, credential: { userEmail: string; oauthClientId?: string; }): void; export declare function getVerifiedMcpCredentialFromEvent(event: RequestContextEvent): { userEmail: string; oauthClientId?: string; } | undefined; export declare function markExplicitPersonalOrgScope(event: { context?: Record; }): void; export declare function hasExplicitPersonalOrgScope(event: { context?: Record; }): boolean; export declare function markRequestIdentityAuthenticatedAtMs(event: { context?: Record; }, email: string, authenticatedAtMs: number, sessionToken?: string): void; export declare function getRequestIdentityAuthenticatedAtMs(event: { context?: Record; }, email: string): number | undefined; export declare function getRequestIdentitySessionToken(event: { context?: Record; }, email: string): string | undefined; type RequestContextObserver = (ctx: RequestContext) => void; /** * Authorization state must never use the shared-stack compatibility fallback: * overlapping async requests are only isolated by native AsyncLocalStorage. */ export declare function assertRequestActionSurfaceIsolation(): void; export declare function hasContinuationLocalRequestContext(): boolean; /** * Register a callback fired every time `runWithRequestContext` enters a new * scope. The hook runs INSIDE the AsyncLocalStorage scope, so observability * helpers that read the current isolation scope (e.g. Sentry) attach to the * right per-request context. * * Returned function unregisters the observer. Observers must never throw — * any error is swallowed so a misbehaving observer can't break the request * path. */ export declare function addRequestContextObserver(observer: RequestContextObserver): () => void; export declare function runWithRequestContext(ctx: RequestContext, fn: () => T | Promise): T | Promise; export declare function getRequestContext(): RequestContext | undefined; /** * Call only after the Clips v2 feature flag evaluates on for this request. * The arm is derived from the verified auth id already in the request context. */ export declare function hasRequestContext(): boolean; export declare function markRequestBoundaryInstalled(): void; export declare function hasRequestBoundary(): boolean; export declare function getAmbientUserEmail(): string | undefined; export declare function getAmbientOrgId(): string | undefined; export declare function getRequestUserEmail(): string | undefined; export declare function getRequestUserName(): string | undefined; export declare function getRequestOrgId(): string | undefined; export declare function getRequestBuilderStorageCredentialOrgId(): string | null | undefined; export declare function getRequestAuthCapability(): string | undefined; export declare function getRequestIsLoopback(): boolean; export declare function hasAuthContextAccess(ctx: RequestContext | undefined): boolean; export declare function getRequestTimezone(): string | undefined; export declare function isIntegrationCallerRequest(): boolean; export declare function getIntegrationRequestContext(): NonNullable | undefined; export declare function getCredentialContext(): { userEmail: string; orgId: string | null; credentialScope?: "org"; } | null; export declare function getRequestRunContext(): RequestRunContext | undefined; export declare function ensureRequestRunContext(): RequestRunContext | undefined; export {};