Skip to content

Add typed Agent request context and pluggable context providers #95

Description

@ScriptedAlchemy

Summary

Give every generated event route, tool, CLI command, rendered script, Server
Function, and browser-backed render request one typed, request-scoped Agent context. Let
framework and application providers contribute capabilities to that context so
authors can build APIs such as useWorktree(), useAgentTopology(), or
useTraceDecay() without modifying compiler core.

This issue provides the composition boundary. It does not provide durable
state, infer agent relationships, or require a daemon.

Problem

The current createRscRequestContext() is a thin AsyncLocalStorage wrapper.
The full RSC example hand-builds useEdit() and useRuntimeSnapshot() around
it. That proves request scoping, but every application must still invent:

  • the canonical request identity;
  • host, session, thread, actor, workspace, and worktree availability semantics;
  • service and storage injection;
  • provider ordering and failure behavior;
  • generated TypeScript augmentation;
  • test fixtures and request-lifetime validation.

React Context is not available to Server Components, and client state hooks do
not provide server request scope. A framework-owned async context is required.

Public model

interface AgentRequestContext {
  invocation: AgentInvocation;
  host: Observed<AgentHostIdentity>;
  session: Observed<AgentSessionIdentity>;
  actor: Observed<AgentActorIdentity>;
  workspace: Observed<AgentWorkspaceIdentity>;
  capabilities: AgentRequestCapabilities;
  progress: AgentProgressReporter;
  signal: AbortSignal;
  services: AgentServiceRegistry;
  providers: AgentProviderValues;
}

type Observed<T> =
  | { state: 'available'; value: T; source: 'native' | 'receipt' | 'derived' }
  | { state: 'unavailable'; reason: AgentContextUnavailableReason };

Unknown identity is never represented by a fabricated string or an ambiguous
optional field.

The capability set includes explicit server-side filesystem, command, network,
and project-root authorities where the invocation grants them. An RSC route may
therefore read files or run commands directly through those capabilities; it
does not need an MCP tool call merely because it executes on the server.

Async Server Components and ordinary server utilities use:

const context = await agent();

The RSC renderer issue adds a synchronous useAgent() convenience by unwrapping
one stable request promise through React use(). The core request store remains
React-independent and available to ordinary server utilities.

Context-provider extension

interface AgentContextProvider<Name extends string, Value> {
  readonly name: Name;
  readonly requirements?: AgentProviderRequirements;
  resolve(request: AgentRequest): Promise<Value>;
}

Providers may be enabled project-wide in agent-bundle.config.ts or discovered
through a conventional src/providers/ root. The compiler:

  • validates unique provider names and dependency order;
  • generates the augmented context type;
  • records provider requirements in the semantic manifest;
  • rejects provider cycles;
  • prevents request-scoped values from entering persistent caches;
  • fails closed when a required host event or capability is unavailable;
  • gives Rstest a provider fixture boundary.

Application code can define an async provider accessor without framework
changes:

export async function worktree(): Promise<WorktreeContext> {
  return (await agent()).providers.gitWorktree;
}

After the renderer's React bridge exists, a synchronous custom useWorktree()
may delegate to useAgent(). Async components should still prefer
await worktree() or await agent().

Providers resolve request-scoped capabilities. They do not implicitly observe
events or mutate durable state. An application that needs those behaviors uses
an explicit semantic event route and state transaction, keeping provider
composition independent from the optional state kernel.

Request lifecycle

The framework installs versioned, realm-singleton async stores at every real
entrypoint. The context is read-only during render, explicitly mutation
capable during action, and reduced to captured values during after.
Access outside a real invocation throws a typed framework error.

Artifact epoch, source revision, host contract revision, and protocol revision
travel with the invocation so stale Server Function or Flight references are
rejected.

Non-goals

  • A built-in thread-topology algorithm.
  • A mandatory local server or daemon.
  • React Context as server state.
  • useSyncExternalStore in Server Components.
  • Inferring parent/subagent relationships absent from a host contract.

Delivery steps

  1. Promote createRscRequestContext into a framework-owned request store.
  2. Define the canonical request and Observed<T> identity contracts.
  3. Add agent() and synchronous useAgent().
  4. Add provider registration, ordering, requirement validation, and typegen.
  5. Bind event-route, MCP, CLI, script, and Server Function entrypoints.
  6. Add test provider fixtures and cross-request isolation tests.

Acceptance criteria

  • The same typed context is available across every generated server entrypoint.
  • Request context survives await and is absent after invocation completion.
  • A project-defined provider adds a typed context property without compiler
    modification.
  • Two simultaneous requests cannot observe each other's principal, event,
    capabilities, or provider values.
  • Unavailable host identity is typed and provenance-bearing.
  • Framework-owned persistent caches never retain request context, and access
    through a captured handle after request completion throws.
  • The API works without a daemon or durable state provider.

Design references

Stack position

Full meta-framework stack

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmeta-frameworkAgent Bundle compiler-coupled meta-frameworkruntimeRuntime context, state, rendering, or execution

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions