Skip to content

feat(runtime,cli,react): add typed SSE output schema support#875

Merged
jhaynie merged 4 commits intomainfrom
task/fix-sse-route-855
Feb 5, 2026
Merged

feat(runtime,cli,react): add typed SSE output schema support#875
jhaynie merged 4 commits intomainfrom
task/fix-sse-route-855

Conversation

@jhaynie
Copy link
Member

@jhaynie jhaynie commented Feb 5, 2026

Summary

  • Add sse({ output: schema }, handler) overload to support typed SSE routes
  • Extract output schema from SSE options during CLI route discovery
  • Add generic type override TOutput to useEventStream hook for escape hatch

Closes #855

Changes

Runtime Package (@agentuity/runtime)

  • Added SSEOptions<TOutput> interface for typed SSE configuration
  • Added function overloads to support both patterns:
    • sse(handler) - Original pattern (backward compatible)
    • sse({ output: schema }, handler) - New typed pattern

CLI Package (@agentuity/cli)

  • Added extractSSEOutputSchema() function to parse sse({ output: schema }, handler)
  • Integrated schema extraction into route parsing
  • Tracks import paths for schemas from other files

React Package (@agentuity/react)

  • Added optional TOutput generic to useEventStream:
    useEventStream<TRoute, TOutput = SSERouteOutput<TRoute>>(route, options)

Usage

Option A: Typed SSE Route (Full Flow)

// src/api/search/route.ts
import { createRouter, sse } from '@agentuity/runtime';
import { s } from '@agentuity/schema';

export const outputSchema = s.object({
  type: s.enum(['token', 'complete', 'error']),
  content: s.optional(s.string()),
});

router.get('/search', sse({ output: outputSchema }, async (c, stream) => {
  await stream.writeSSE({ data: JSON.stringify({ type: 'token', content: 'Hello' }) });
  stream.close();
}));

Frontend (auto-typed from registry)

const { data } = useEventStream('/api/search');
// data is typed as { type: 'token' | 'complete' | 'error', content?: string }

Option B: Type Override (escape hatch)

interface StreamMessage {
  type: 'token' | 'complete';
  content?: string;
}

const { data } = useEventStream<'/api/search', StreamMessage>('/api/search');
// data is typed as StreamMessage | undefined

Testing

  • Added 5 tests for SSE output schema extraction in ast.test.ts
  • Added 4 tests for SSE registry generation in registry-generator.test.ts
  • All existing tests pass
  • Full verification suite passes (format, lint, typecheck, build, test)

Summary by CodeRabbit

  • New Features

    • SSE handlers can declare typed output via SSEOptions and be invoked with options+handler.
    • useEventStream gains a generic to override emitted data types per route.
    • Build tooling now extracts SSE output schemas for improved typing and registry generation.
  • Bug Fixes / Validation

    • Runtime now errors when SSE options are provided without a handler.
  • Tests

    • Added extensive tests for SSE output schema extraction and typing.

Add support for typed SSE routes with proper output schema inference:

- runtime: Add SSEOptions<TOutput> interface and sse({ output }, handler) overload
- cli: Extract output schema from sse({ output: schema }) during route discovery
- react: Add TOutput generic override to useEventStream hook
- tests: Add comprehensive tests for SSE schema extraction and registry generation

This enables full type flow from SSE route definition to useEventStream:
- sse({ output: MySchema }, handler) -> routes.ts -> useEventStream typed data

Also supports type override escape hatch:
- useEventStream<'/path', MyType>('/path') when registry has outputSchema: never

Closes #855
@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

CLI now extracts SSE route output schemas from sse({ output }) calls and tracks imports; runtime adds SSEOptions and overloads for sse(...); React hook useEventStream gains a generic TOutput; tests added for extraction, import-tracking, registry typing, and related behaviors.

Changes

Cohort / File(s) Summary
Runtime API Extensions
packages/runtime/src/handlers/sse.ts, packages/runtime/src/handlers/index.ts, packages/runtime/src/index.ts
Added SSEOptions<TOutput> interface, new sse overloads (handler-only and options+handler), runtime SSEHandlerMissingError, and re-exported SSEOptions from handlers/index and runtime index.
CLI Schema Extraction
packages/cli/src/cmd/build/ast.ts
Added extractSSEOutputSchema helper and logic to track sse(...) call expressions during route parsing to populate routeConfig.outputSchemaVariable and resolve outputSchemaImportPath/outputSchemaImportedName, integrating with existing validator/import handling. (Diff shows the helper defined twice.)
React Hook Enhancement
packages/react/src/eventstream.ts
Introduced generic TOutput for useEventStream<TRoute, TOutput> (defaulting to SSERouteOutput<TRoute>); updated internal state/manager typing and query dependency handling.
Tests — CLI & Registry
packages/cli/test/ast.test.ts, packages/cli/test/cmd/build/vite/registry-generator.test.ts
Added tests covering SSE output schema extraction (inline and imported), precedence over exported schema, exported-fallback behavior, and registry/type generation for SSE routes (including import-tracking and export generation).
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR successfully implements both objectives from issue #855: SSE routes now support typed output schemas via sse({ output: schema }, handler), and useEventStream provides a generic TOutput override as an escape hatch.
Out of Scope Changes check ✅ Passed All changes directly address typed SSE output schema support across runtime, CLI, and React packages, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c7b94b and 70bf225.

📒 Files selected for processing (1)
  • packages/cli/src/cmd/build/ast.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/build/ast.ts
packages/cli/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/build/ast.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/build/ast.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Package Installation & Usage Test
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Build
🔇 Additional comments (4)
packages/cli/src/cmd/build/ast.ts (4)

1249-1301: SSE output schema extraction is robust.
Nice defensive handling of non-Property entries while keeping the AST scan focused on output.


1600-1602: Clear SSE call tracking.
The dedicated sseCallExpr holder makes the later extraction logic easy to follow.


1863-1866: SSE call capture in middleware scan looks correct.
This cleanly ties the middleware detection to schema extraction later.


2022-2057: SSE output schema precedence is applied correctly.
Overriding validator output and preserving import tracking/validation aligns with the intended SSE typing flow.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

📦 Canary Packages Published

version: 1.0.1-70bf225

Packages
Package Version URL
@agentuity/auth 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-auth-1.0.1-70bf225.tgz
@agentuity/cli 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-cli-1.0.1-70bf225.tgz
@agentuity/react 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-react-1.0.1-70bf225.tgz
@agentuity/core 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-core-1.0.1-70bf225.tgz
@agentuity/server 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-server-1.0.1-70bf225.tgz
@agentuity/schema 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-schema-1.0.1-70bf225.tgz
@agentuity/runtime 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-runtime-1.0.1-70bf225.tgz
@agentuity/drizzle 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-drizzle-1.0.1-70bf225.tgz
@agentuity/frontend 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-frontend-1.0.1-70bf225.tgz
@agentuity/postgres 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-postgres-1.0.1-70bf225.tgz
@agentuity/workbench 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-workbench-1.0.1-70bf225.tgz
@agentuity/opencode 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-opencode-1.0.1-70bf225.tgz
@agentuity/evals 1.0.1-70bf225 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-evals-1.0.1-70bf225.tgz
Install

Add to your package.json:

{
  "dependencies": {
    "@agentuity/auth": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-auth-1.0.1-70bf225.tgz",
    "@agentuity/cli": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-cli-1.0.1-70bf225.tgz",
    "@agentuity/react": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-react-1.0.1-70bf225.tgz",
    "@agentuity/core": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-core-1.0.1-70bf225.tgz",
    "@agentuity/server": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-server-1.0.1-70bf225.tgz",
    "@agentuity/schema": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-schema-1.0.1-70bf225.tgz",
    "@agentuity/runtime": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-runtime-1.0.1-70bf225.tgz",
    "@agentuity/drizzle": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-drizzle-1.0.1-70bf225.tgz",
    "@agentuity/frontend": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-frontend-1.0.1-70bf225.tgz",
    "@agentuity/postgres": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-postgres-1.0.1-70bf225.tgz",
    "@agentuity/workbench": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-workbench-1.0.1-70bf225.tgz",
    "@agentuity/opencode": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-opencode-1.0.1-70bf225.tgz",
    "@agentuity/evals": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-evals-1.0.1-70bf225.tgz"
  }
}

Or install directly:

bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-auth-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-cli-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-react-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-core-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-server-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-schema-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-runtime-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-drizzle-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-frontend-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-postgres-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-workbench-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-opencode-1.0.1-70bf225.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-70bf225/agentuity-evals-1.0.1-70bf225.tgz

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react/src/eventstream.ts (1)

85-151: ⚠️ Potential issue | 🟠 Major

Add an explicit SSR guard in the hook.

useEventStream runs EventStreamManager.connect() in a useEffect without checking if code is executing in the browser. Since EventStreamManager instantiates new EventSource() (a browser-only API) during initialization, this will throw a ReferenceError during server-side rendering. Add a browser check to prevent manager initialization on the server.

🛡️ Suggested SSR guard
 export function useEventStream<TRoute extends SSERouteKey, TOutput = SSERouteOutput<TRoute>>(
 	route: TRoute,
 	options?: EventStreamOptions
 ): {
@@
 	const context = useContext(AgentuityContext);
+	const isBrowser = typeof window !== 'undefined';
@@
-	const esUrl = useMemo(
-		() => buildUrl(context.baseUrl!, route as string, options?.subpath, options?.query),
-		[context.baseUrl, route, options?.subpath, options?.query]
-	);
+	const esUrl = useMemo(
+		() =>
+			isBrowser
+				? buildUrl(context.baseUrl!, route as string, options?.subpath, options?.query)
+				: '',
+		[isBrowser, context.baseUrl, route, options?.subpath, options?.query]
+	);
@@
 	useEffect(() => {
+		if (!isBrowser || !esUrl) return;
 		const manager = new EventStreamManager<TOutput>({
 			url: esUrl,
🤖 Fix all issues with AI agents
In `@packages/cli/src/cmd/build/ast.ts`:
- Around line 2017-2032: After extracting sseSchemaInfo via
extractSSEOutputSchema, run the same export validation used for validator
schemas (call validateSchemaExports with the extracted output schema variable
and current file/module context) before assigning
routeConfig.outputSchemaVariable; if validateSchemaExports reports the schema is
locally defined but not exported, surface that error (or skip assignment) so
registry generation won't try to import a non-exported local schema. Use the
same inputs you use for validator validation and keep using importInfoMap to
detect imported schemas (i.e., only skip validateSchemaExports when
importInfoMap already has an entry for sseSchemaInfo.outputSchemaVariable).

In `@packages/react/src/eventstream.ts`:
- Around line 112-115: The useMemo for esUrl (which calls buildUrl in
eventstream.ts) currently depends on the options.query object reference and can
miss in-place mutations; update the dependency array for the useMemo that
defines esUrl to include options?.query?.toString() (i.e., track the string
representation) instead of options?.query so the memo recomputes when
URLSearchParams are mutated, keeping other deps (context.baseUrl, route,
options?.subpath) the same.

In `@packages/runtime/src/handlers/sse.ts`:
- Around line 204-211: The sse helper currently uses a non-null assertion on
maybeHandler which lets calls like sse({ output }) produce a cryptic runtime
error; update the sse function to explicitly check whether handler is undefined
after deriving it from handlerOrOptions/maybeHandler and, if missing, throw a
clear StructuredError (or the project's standard error type) with a descriptive
message explaining that an SSE handler was not provided; reference the sse
function, the handlerOrOptions/maybeHandler variables, and the SSEHandler type
when locating where to add this guard and ensure the thrown error follows the
project's StructuredError shape.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a54abab and 7f3881b.

📒 Files selected for processing (7)
  • packages/cli/src/cmd/build/ast.ts
  • packages/cli/test/ast.test.ts
  • packages/cli/test/cmd/build/vite/registry-generator.test.ts
  • packages/react/src/eventstream.ts
  • packages/runtime/src/handlers/index.ts
  • packages/runtime/src/handlers/sse.ts
  • packages/runtime/src/index.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/runtime/src/handlers/index.ts
  • packages/runtime/src/index.ts
  • packages/cli/test/cmd/build/vite/registry-generator.test.ts
  • packages/cli/test/ast.test.ts
  • packages/react/src/eventstream.ts
  • packages/cli/src/cmd/build/ast.ts
  • packages/runtime/src/handlers/sse.ts
packages/runtime/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/runtime/AGENTS.md)

packages/runtime/**/*.{ts,tsx}: Every agent handler receives AgentContext with logger, tracer, storage (kv, vector, stream), and auth properties
Use ctx.logger instead of console.log for observability

Files:

  • packages/runtime/src/handlers/index.ts
  • packages/runtime/src/index.ts
  • packages/runtime/src/handlers/sse.ts
packages/*/src/index.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use named exports from package index.ts file as the public API

Files:

  • packages/runtime/src/index.ts
packages/*/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/*/test/**/*.{ts,tsx}: Place test files in test/ folder (never in src/ or __tests__/)
Import from ../src/ in test files to reference source code
Use @agentuity/test-utils for mocks and test helpers

Files:

  • packages/cli/test/cmd/build/vite/registry-generator.test.ts
  • packages/cli/test/ast.test.ts
packages/cli/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/test/cmd/build/vite/registry-generator.test.ts
  • packages/cli/test/ast.test.ts
  • packages/cli/src/cmd/build/ast.ts
packages/react/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/react/AGENTS.md)

packages/react/**/*.{ts,tsx}: All hooks must be used within AgentuityProvider
Use useAPI('GET /route') for GET requests which auto-execute and return refetch()
Use useAPI('POST/PUT/PATCH/DELETE /route') with manual invocation via invoke() for mutation requests
Types should be inferred from generated registries (RouteRegistry, etc.) rather than manually defined
Use useJsonMemo(value) for deep equality memoization of complex objects and arrays
Use withPageTracking(Component, pageName) HOC for automatic page tracking in components

Files:

  • packages/react/src/eventstream.ts
packages/react/src/**/*.ts?(x)

📄 CodeRabbit inference engine (packages/react/AGENTS.md)

packages/react/src/**/*.ts?(x): Include SSR guards in all hooks to ensure server-side rendering compatibility
Runtime environment is browser only - do not use Node.js APIs in hook implementations

Files:

  • packages/react/src/eventstream.ts
packages/react/src/eventstream.ts?(x)

📄 CodeRabbit inference engine (packages/react/AGENTS.md)

Configure useEventStream with auto-reconnection on connection loss and JSON memoization for data

Files:

  • packages/react/src/eventstream.ts
🧠 Learnings (2)
📚 Learning: 2025-12-13T14:15:18.261Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 168
File: packages/runtime/src/session.ts:536-546
Timestamp: 2025-12-13T14:15:18.261Z
Learning: The agentuity/runtime package is Bun-only; during code reviews, do not replace Bun-native APIs (e.g., Bun.CryptoHasher, Bun.serve, and other Bun namespace APIs) with Node.js alternatives. Review changes with the assumption that runtime runs on Bun, and ensure any edits preserve Bun compatibility and do not introduce Node.js-specific fallbacks. Apply this guidance broadly to files under packages/runtime (e.g., packages/runtime/src/...); if there are conditional environment checks, document why Bun is required and avoid dereferencing Bun-only APIs in non-Bun contexts.

Applied to files:

  • packages/runtime/src/handlers/index.ts
  • packages/runtime/src/index.ts
  • packages/runtime/src/handlers/sse.ts
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/runtime/src/handlers/index.ts
  • packages/runtime/src/index.ts
  • packages/cli/test/cmd/build/vite/registry-generator.test.ts
  • packages/cli/test/ast.test.ts
  • packages/react/src/eventstream.ts
  • packages/cli/src/cmd/build/ast.ts
  • packages/runtime/src/handlers/sse.ts
🧬 Code graph analysis (2)
packages/cli/test/cmd/build/vite/registry-generator.test.ts (2)
packages/cli/src/cmd/build/vite/route-discovery.ts (1)
  • RouteInfo (28-48)
packages/cli/src/cmd/build/vite/registry-generator.ts (1)
  • generateRouteRegistry (589-1218)
packages/cli/test/ast.test.ts (1)
packages/cli/src/cmd/build/ast.ts (1)
  • parseRoute (1406-2080)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Queue SDK Tests
  • GitHub Check: Template Integration Tests
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Queue CLI Tests
  • GitHub Check: Build
🔇 Additional comments (5)
packages/runtime/src/handlers/sse.ts (1)

64-185: Typed SSE options + docs are clear.

The new SSEOptions interface and examples make the typing intent easy to follow and align well with the new overloads.

packages/runtime/src/handlers/index.ts (1)

2-10: Re-export keeps the public API in sync.

Nice to see SSEOptions exposed alongside the existing SSE types.

packages/runtime/src/index.ts (1)

80-94: Public surface is consistent with handler exports.

SSEOptions is now correctly reachable from the main runtime index.

packages/cli/test/ast.test.ts (1)

471-642: Solid coverage for SSE output schema extraction.

The test matrix hits inline, imported, fallback, and precedence paths—nice coverage.

packages/cli/test/cmd/build/vite/registry-generator.test.ts (1)

2062-2189: Great end-to-end coverage for SSE registry typing.

These tests validate typed SSE outputs, never fallbacks, RPC registry wiring, and import tracking—exactly what #855 needed.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

- cli: Add validateSchemaExports for SSE output schemas (locally defined must be exported)
- react: Track query string representation to detect URLSearchParams mutations
- runtime: Add SSEHandlerMissingError guard when handler is undefined
- test: Add test for non-exported local schema error, fix existing test
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react/src/eventstream.ts (1)

122-156: ⚠️ Potential issue | 🟡 Minor

Add an explicit SSR guard for the hook.

The useEventStream hook instantiates EventStreamManager in a useEffect without an explicit SSR guard. While useEffect doesn't run on the server, the coding guidelines require explicit SSR guards in all hooks to ensure server-side rendering compatibility.

🛡️ Suggested SSR-safe guard
+	const isSSR = typeof window === 'undefined';
 	const esUrl = useMemo(
-		() => buildUrl(context.baseUrl!, route as string, options?.subpath, options?.query),
+		() =>
+			isSSR
+				? ''
+				: buildUrl(context.baseUrl!, route as string, options?.subpath, options?.query),
 		// biome-ignore lint/correctness/useExhaustiveDependencies: queryString tracks URLSearchParams mutations that options?.query reference wouldn't catch
-		[context.baseUrl, route, options?.subpath, options?.query, queryString]
+		[isSSR, context.baseUrl, route, options?.subpath, options?.query, queryString]
 	);
 
 	useEffect(() => {
+		if (isSSR || !esUrl) return;
 		const manager = new EventStreamManager<TOutput>({
 			url: esUrl,
 			callbacks: {
🤖 Fix all issues with AI agents
In `@packages/cli/src/cmd/build/ast.ts`:
- Around line 2017-2038: Update the comment above the SSE extraction block to
reflect that while SSE routes can accept schemas via sse({ output: schema },
handler) (see sseCallExpr and extractSSEOutputSchema), locally-defined schema
variables (sseSchemaInfo.outputSchemaVariable) must be exported and are
validated by validateSchemaExports; rephrase the line that currently says
"without requiring exported schemas" to indicate that imported schemas need not
be exported but locally-defined schemas are required to be exported and will be
validated.
- Around line 1249-1293: The loop in extractSSEOutputSchema assumes every entry
in objExpr.properties is a Property with key/value, which will throw for
SpreadElement entries; update the loop to skip any property whose node.type !==
'Property' before accessing prop.key/prop.value (i.e., guard prop.type ===
'Property'), then continue processing only Property nodes and perform the
existing key extraction and output check on those nodes.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f3881b and 3adcda3.

📒 Files selected for processing (4)
  • packages/cli/src/cmd/build/ast.ts
  • packages/cli/test/ast.test.ts
  • packages/react/src/eventstream.ts
  • packages/runtime/src/handlers/sse.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/test/ast.test.ts
  • packages/runtime/src/handlers/sse.ts
  • packages/cli/src/cmd/build/ast.ts
  • packages/react/src/eventstream.ts
packages/*/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/*/test/**/*.{ts,tsx}: Place test files in test/ folder (never in src/ or __tests__/)
Import from ../src/ in test files to reference source code
Use @agentuity/test-utils for mocks and test helpers

Files:

  • packages/cli/test/ast.test.ts
packages/cli/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/test/ast.test.ts
  • packages/cli/src/cmd/build/ast.ts
packages/runtime/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/runtime/AGENTS.md)

packages/runtime/**/*.{ts,tsx}: Every agent handler receives AgentContext with logger, tracer, storage (kv, vector, stream), and auth properties
Use ctx.logger instead of console.log for observability

Files:

  • packages/runtime/src/handlers/sse.ts
packages/react/**/*.{ts,tsx}

📄 CodeRabbit inference engine (packages/react/AGENTS.md)

packages/react/**/*.{ts,tsx}: All hooks must be used within AgentuityProvider
Use useAPI('GET /route') for GET requests which auto-execute and return refetch()
Use useAPI('POST/PUT/PATCH/DELETE /route') with manual invocation via invoke() for mutation requests
Types should be inferred from generated registries (RouteRegistry, etc.) rather than manually defined
Use useJsonMemo(value) for deep equality memoization of complex objects and arrays
Use withPageTracking(Component, pageName) HOC for automatic page tracking in components

Files:

  • packages/react/src/eventstream.ts
packages/react/src/**/*.ts?(x)

📄 CodeRabbit inference engine (packages/react/AGENTS.md)

packages/react/src/**/*.ts?(x): Include SSR guards in all hooks to ensure server-side rendering compatibility
Runtime environment is browser only - do not use Node.js APIs in hook implementations

Files:

  • packages/react/src/eventstream.ts
packages/react/src/eventstream.ts?(x)

📄 CodeRabbit inference engine (packages/react/AGENTS.md)

Configure useEventStream with auto-reconnection on connection loss and JSON memoization for data

Files:

  • packages/react/src/eventstream.ts
🧠 Learnings (2)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/test/ast.test.ts
  • packages/runtime/src/handlers/sse.ts
  • packages/cli/src/cmd/build/ast.ts
  • packages/react/src/eventstream.ts
📚 Learning: 2025-12-13T14:15:18.261Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 168
File: packages/runtime/src/session.ts:536-546
Timestamp: 2025-12-13T14:15:18.261Z
Learning: The agentuity/runtime package is Bun-only; during code reviews, do not replace Bun-native APIs (e.g., Bun.CryptoHasher, Bun.serve, and other Bun namespace APIs) with Node.js alternatives. Review changes with the assumption that runtime runs on Bun, and ensure any edits preserve Bun compatibility and do not introduce Node.js-specific fallbacks. Apply this guidance broadly to files under packages/runtime (e.g., packages/runtime/src/...); if there are conditional environment checks, document why Bun is required and avoid dereferencing Bun-only APIs in non-Bun contexts.

Applied to files:

  • packages/runtime/src/handlers/sse.ts
🧬 Code graph analysis (2)
packages/cli/test/ast.test.ts (1)
packages/cli/src/cmd/build/ast.ts (1)
  • parseRoute (1406-2093)
packages/react/src/eventstream.ts (2)
packages/frontend/src/eventstream-manager.ts (1)
  • EventStreamManager (59-203)
packages/frontend/src/url.ts (1)
  • buildUrl (3-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Build
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Template Integration Tests
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Pack & Upload
🔇 Additional comments (6)
packages/cli/test/ast.test.ts (1)

471-671: Solid SSE output schema extraction coverage.

The new suite hits the key extraction paths (inline, imported, fallback, precedence, and validation errors) and should protect the new behavior well.

packages/cli/src/cmd/build/ast.ts (1)

1595-1861: Good capture of the SSE call expression for downstream schema extraction.

The sse call tracking is straightforward and makes the later schema extraction logic much cleaner.

packages/react/src/eventstream.ts (2)

52-106: Typed output generic propagates cleanly through hook state and manager types.

The defaulted TOutput keeps inference intact while allowing overrides.


112-119: Query string mutation tracking looks good.

Using the string representation in dependencies closes the URLSearchParams mutation gap.

packages/runtime/src/handlers/sse.ts (2)

9-108: SSEOptions + StructuredError guard definition is clear and well-documented.

The documentation makes the type-only intent explicit, which should reduce runtime expectations.


201-227: Handler validation in sse() is a solid safety improvement.

Failing fast with a clear error message will save debugging time for misuses.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

- Update comment to clarify that locally-defined schemas must be exported
- Add guard for SpreadElement in extractSSEOutputSchema loop
- Skip non-Property nodes when iterating object expression properties
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/cli/src/cmd/build/ast.ts`:
- Around line 2022-2051: The current logic only sets
routeConfig.outputSchemaVariable from SSE when routeConfig.outputSchemaVariable
is falsy, so validator-provided output masks sse({ output }) for SSE routes;
change the block that handles sseCallExpr to always consider the sseSchemaInfo
when sseCallExpr is present: call extractSSEOutputSchema(sseCallExpr) and if
sseSchemaInfo.outputSchemaVariable is set, override
routeConfig.outputSchemaVariable (and set
routeConfig.outputSchemaImportPath/outputSchemaImportedName from importInfoMap
lookup) or, if you prefer surfacing conflicts, detect when an existing
routeConfig.outputSchemaVariable differs and raise/log a clear conflict instead
of silently keeping the validator value; keep the validateSchemaExports call for
locally-defined schemas (use importInfoMap.get to decide) and retain use of
validateSchemaExports, importInfoMap, sseCallExpr, extractSSEOutputSchema, and
routeConfig.* names to locate the changes.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3adcda3 and 5c7b94b.

📒 Files selected for processing (1)
  • packages/cli/src/cmd/build/ast.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/build/ast.ts
packages/cli/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/build/ast.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/build/ast.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Package Installation & Usage Test
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Pack & Upload
  • GitHub Check: Template Integration Tests
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Storage CLI Tests
  • GitHub Check: Standalone Agent Test
  • GitHub Check: Queue CLI Tests
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Build
🔇 Additional comments (3)
packages/cli/src/cmd/build/ast.ts (3)

1249-1301: Defensive SSE options parsing looks solid.
The guard against non-Property entries avoids crashes with spread elements in options objects.


1600-1601: Good setup for SSE schema extraction.
Keeping sseCallExpr scoped per route simplifies downstream handling.


1863-1866: Nice capture of sse() call context.
This cleanly enables schema extraction without affecting non-SSE routes.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

For SSE routes, the sse({ output }) pattern now overrides any validator-provided
schema. This ensures the explicit SSE output declaration is used for type
generation rather than being masked by validator middleware.
@jhaynie jhaynie merged commit 9c562a1 into main Feb 5, 2026
15 checks passed
@jhaynie jhaynie deleted the task/fix-sse-route-855 branch February 5, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSE routes have outputSchema: never in generated routes.ts, breaking useEventStream typing

1 participant