Conversation
- replace `cron` demo with new `schedules` ex - remove Explorer-only `evals` - restore `webrtc` and `websocket` demos - align ref code with current SDK usage - tighten sandbox run scripts and output - regenerate nav, routes, and script manifests
- fix `model-arena` with heartbeat `stream()` - route `google` and `groq` through AI Gateway - clean stale docs links and Explorer refs - tighten `websocket` demo behavior and copy
…e-demos # Conflicts: # bun.lock
|
The latest Agentuity deployment details.
|
📝 WalkthroughWalkthroughRemoved the eval demo and related APIs; added managed Schedules, WebRTC, and WebSocket demos and routes; introduced ai-gateway provider factories and refactored model usage; switched Model Arena streaming to newline-delimited JSON; migrated KV examples to a namespaced KV API and bumped model IDs to gpt-5.4-nano. Changes
|
📦 Canary Packages Publishedversion: PackagesInstallAdd to your {
"dependencies": {
"@agentuity/runtime": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-runtime-2.0.9-e111c2c.tgz",
"@agentuity/keyvalue": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-keyvalue-2.0.9-e111c2c.tgz",
"@agentuity/db": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-db-2.0.9-e111c2c.tgz",
"@agentuity/migrate": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-migrate-2.0.9-e111c2c.tgz",
"@agentuity/workbench": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-workbench-2.0.9-e111c2c.tgz",
"@agentuity/drizzle": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-drizzle-2.0.9-e111c2c.tgz",
"@agentuity/opencode": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-opencode-2.0.9-e111c2c.tgz",
"@agentuity/vector": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-vector-2.0.9-e111c2c.tgz",
"@agentuity/core": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-core-2.0.9-e111c2c.tgz",
"@agentuity/evals": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-evals-2.0.9-e111c2c.tgz",
"@agentuity/schema": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-schema-2.0.9-e111c2c.tgz",
"@agentuity/cli": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-cli-2.0.9-e111c2c.tgz",
"@agentuity/webhook": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-webhook-2.0.9-e111c2c.tgz",
"@agentuity/coder-tui": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-coder-tui-2.0.9-e111c2c.tgz",
"@agentuity/email": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-email-2.0.9-e111c2c.tgz",
"@agentuity/coder": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-coder-2.0.9-e111c2c.tgz",
"@agentuity/sandbox": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-sandbox-2.0.9-e111c2c.tgz",
"@agentuity/frontend": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-frontend-2.0.9-e111c2c.tgz",
"@agentuity/claude-code": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-claude-code-2.0.9-e111c2c.tgz",
"@agentuity/postgres": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-postgres-2.0.9-e111c2c.tgz",
"@agentuity/server": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-server-2.0.9-e111c2c.tgz",
"@agentuity/queue": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-queue-2.0.9-e111c2c.tgz",
"@agentuity/react": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-react-2.0.9-e111c2c.tgz",
"@agentuity/schedule": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-schedule-2.0.9-e111c2c.tgz",
"@agentuity/task": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-task-2.0.9-e111c2c.tgz",
"@agentuity/auth": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-auth-2.0.9-e111c2c.tgz"
}
}Or install directly: bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-runtime-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-keyvalue-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-db-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-migrate-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-workbench-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-drizzle-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-opencode-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-vector-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-core-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-evals-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-schema-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-cli-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-webhook-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-coder-tui-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-email-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-coder-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-sandbox-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-frontend-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-claude-code-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-postgres-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-server-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-queue-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-react-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-schedule-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-task-2.0.9-e111c2c.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/2.0.9-e111c2c/agentuity-auth-2.0.9-e111c2c.tgz |
- add OIDC provider setup with Console and CLI paths - split OIDC guidance from app-owned `@agentuity/auth` - update auth links, services nav, and route metadata - normalize `Next Steps` links
…e-demos # Conflicts: # apps/docs/src/web/content/cookbook/tutorials/rag-agent.mdx # apps/docs/src/web/demo-config.tsx # apps/docs/src/web/routes/explorer/webrtc.tsx
There was a problem hiding this comment.
Actionable comments posted: 16
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/docs/src/api/queue/route.ts (1)
138-154:⚠️ Potential issue | 🟡 MinorUse
pending.totalinstead ofpending.messages.lengthfor accurate pending message count.
listMessagesreturns atotalfield (just aslistDeadLetterMessagesdoes), but the code currently ignores it and relies only onpending.messages.length, which is capped at 100 due to thelimitparameter. This causes undercounting when more than 100 messages are pending. Update to match the pattern already used fordlq_count:Suggested fix
return c.json({ success: true, data: { - message_count: pending.messages.length, + message_count: pending.total ?? pending.messages.length, dlq_count: dlq.total ?? dlq.messages.length,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/api/queue/route.ts` around lines 138 - 154, The pending message count uses the paged result's messages array length (pending.messages.length) which is capped by the limit; change it to use the paginated total field (pending.total) like dlq_count does — update the response construction that references pending to set message_count to pending.total (with an optional fallback to pending.messages.length if total is undefined) and adjust the block around getQueue / listMessages / listDeadLetterMessages accordingly.apps/docs/src/run/agent-calls.ts (1)
16-22:⚠️ Potential issue | 🟡 Minor
JSON.parseon CLI input is outside thetry/catch.Malformed JSON passed as
process.argv[2]will throw before the try block, bypassing the new---OUTPUT---error framing. Consider either moving the parse insidetry, or using theparseJSON<T>(text, fallback)helper pattern already used inai-gateway.tsfor consistency and resilience.♻️ Proposed fix
-const input: Input = JSON.parse(process.argv[2] ?? '{}'); -const name = input.name ?? 'Explorer'; - -const standaloneCtx = createAgentContext(); -standaloneCtx.logger.info('Agent calls demo'); - try { + const input: Input = JSON.parse(process.argv[2] ?? '{}'); + const name = input.name ?? 'Explorer'; + + const standaloneCtx = createAgentContext(); + standaloneCtx.logger.info('Agent calls demo'); + // Must use invoke() to get proper execution context for waitUntil await standaloneCtx.invoke(async () => {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/run/agent-calls.ts` around lines 16 - 22, The CLI JSON parsing is done outside the try/catch so malformed input will throw before your error framing; update the code that creates the Input (currently using JSON.parse(process.argv[2] ?? '{}')) to either move the parse into the existing try block or, preferably, use the parseJSON helper used elsewhere (e.g. parseJSON<Input>(process.argv[2] ?? '{}', {})) so parsing errors are handled and logged via the same ---OUTPUT--- error flow; adjust references around Input and keep createAgentContext()/standaloneCtx usage unchanged.apps/docs/src/web/test-outputs.ts (1)
87-93:⚠️ Potential issue | 🟡 MinorStale terminology in
sse-streamfixture.The live script now emits
[Buffered N text chunks in the sandbox]plus an "In a real route, each chunk would be wrapped in named SSE events" line (seeapps/docs/src/run/sse-stream.tslines 46–47), but this fixture still reads[Streamed 47 tokens]. Users previewing the UI from this fixture will see output that no longer matches what the sandbox produces.Suggested fix
-[Streamed 47 tokens]`, +[Buffered 47 text chunks in the sandbox] +In a real route, each chunk would be wrapped in named SSE events`,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/test-outputs.ts` around lines 87 - 93, Update the 'sse-stream' fixture string in test-outputs.ts so its final lines match the current runtime output from run/sse-stream.ts (replace the stale "[Streamed 47 tokens]" tail with the new buffered/chunk text and explanatory line emitted by the live script); locate the 'sse-stream' entry in apps/docs/src/web/test-outputs.ts and change its ending to include the "[Buffered N text chunks in the sandbox]" text plus the "In a real route, each chunk would be wrapped in named SSE events" line (use the same wording and a matching chunk count as produced by run/sse-stream.ts).apps/docs/src/web/demo-config.tsx (1)
313-525:⚠️ Potential issue | 🟡 MinorCategory inconsistency: WebSocket in
io-patterns, WebRTC inexamples.
websocketis filed underio-patterns(Line 344) whilewebrtcis filed underexamples(Line 519), even though both are introduced in the same PR as real-time communication patterns and are cross-linked in each other's explanations. If the intent is to group both as I/O / real-time patterns, consider movingwebrtctoio-patternsfor consistency. If not, a short comment clarifying the distinction would help.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/demo-config.tsx` around lines 313 - 525, The PR shows an inconsistency: the object with id 'websocket' uses category 'io-patterns' while the object with id 'webrtc' uses category 'examples'; update the 'webrtc' demo entry (the object where id === 'webrtc' and component is WebRTCDemo) to use category 'io-patterns' to match WebSocket (or, if intentional, add a short inline comment next to the 'webrtc' object's category explaining why it differs), ensuring the cross-linked explorerHref references remain unchanged.
🧹 Nitpick comments (12)
apps/docs/src/api/vector-storage/route.ts (1)
29-33: Nit: redundantmessageandnotefields.Both keys convey the same thing ("sample products loaded"). Consider keeping just one to keep the API response tidy.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/api/vector-storage/route.ts` around lines 29 - 33, The JSON response in the seed handler currently returns both "message" and "note" with the same content; simplify the API by removing one of them (e.g., drop "note") in the c.json(...) return inside the route handler so only a single descriptive field remains (update the return in the seeding route where c.json is called), and adjust any related tests, type definitions, or docs that expect the removed field to use the remaining key.apps/docs/src/api/sse-stream/route.ts (1)
43-58: Nit: terminology inconsistency between comments and event payload.The header/description now describe streaming "chunks" (Line 2, Line 5, Line 20), but the SSE event name is still
'token'(Line 45) and the completion payload exposestotalTokens(Line 52, Line 56). Consider either renaming the event to'chunk'or keeping the "token" wording in the docs — mixing the two may confuse client implementers. Note that renaming the event is a breaking change for any existing consumers.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/api/sse-stream/route.ts` around lines 43 - 58, The SSE event name is inconsistent with the surrounding "chunk" terminology; update the event sent in the streaming loop by replacing the literal 'token' with 'chunk' in the stream.writeSSE calls inside the for-await loop (the call that currently passes event: 'token', data: chunk, id: String(chunkCount++)), and keep the completion event as-is (event: 'done') while retaining the usage-derived totalTokens in the done payload; ensure any code that references the old 'token' event is updated to listen for 'chunk' instead.apps/docs/src/lib/ai-gateway.ts (1)
23-39: Memoize providers instead of rebuilding them on every call.Callers invoke
createGoogleProvider()/createGroqProvider()at everygenerateText/getModelcall site (e.g.,models.ts,chat/agent.ts,text-processor/agent.ts), which re-reads env vars and constructs a fresh provider for each request. A simple module-scoped singleton keeps behavior identical but avoids redundant allocations on hot paths.♻️ Suggested refactor
-export function createGoogleProvider() { - const { apiKey, baseUrl } = requireGatewayConfig(); - - return createGoogleGenerativeAI({ - apiKey, - baseURL: `${baseUrl}/gateway/google-ai-studio`, - }); -} - -export function createGroqProvider() { - const { apiKey, baseUrl } = requireGatewayConfig(); - - return createGroq({ - apiKey, - baseURL: `${baseUrl}/gateway/groq`, - }); -} +let googleProvider: ReturnType<typeof createGoogleGenerativeAI> | undefined; +let groqProvider: ReturnType<typeof createGroq> | undefined; + +export function createGoogleProvider() { + if (!googleProvider) { + const { apiKey, baseUrl } = requireGatewayConfig(); + googleProvider = createGoogleGenerativeAI({ + apiKey, + baseURL: `${baseUrl}/gateway/google-ai-studio`, + }); + } + return googleProvider; +} + +export function createGroqProvider() { + if (!groqProvider) { + const { apiKey, baseUrl } = requireGatewayConfig(); + groqProvider = createGroq({ + apiKey, + baseURL: `${baseUrl}/gateway/groq`, + }); + } + return groqProvider; +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/lib/ai-gateway.ts` around lines 23 - 39, The current createGoogleProvider and createGroqProvider recreate provider instances and re-read env config on every call; change them to return memoized module-scoped singletons: add private module-level variables (e.g., googleProvider, groqProvider), lazily initialize them inside createGoogleProvider/createGroqProvider by calling requireGatewayConfig and constructing the provider only if the corresponding variable is undefined, then return the cached instance on subsequent calls; ensure the initialization is idempotent and uses the same unique symbols createGoogleGenerativeAI and createGroq to build the instances.apps/docs/src/api/index.ts (1)
19-27: Nit: alphabetical ordering —schedulesshould come aftersandbox.The file otherwise keeps imports and
.route(...)calls sorted alphabetically, butschedules(line 19 / line 45) is placed beforesandbox(lines 20 / 46). Alphabetically,sandboxprecedesschedules(sa<sc). Consider movingschedulesaftersandboxin both the import block and the router chain for consistency.Also applies to: 45-53
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/api/index.ts` around lines 19 - 27, Imports and router registrations are out of alphabetical order: move the schedules import and its router registration so "sandbox" comes before "schedules". Edit the import block to place "sandbox from './sandbox/route';" before "schedules from './schedules/route';" and update the router chain to call sandbox.route(...) before schedules.route(...), targeting the symbols "schedules" and "sandbox" in apps/docs/src/api/index.ts.apps/docs/src/run/handler-context.ts (1)
43-47: Minor: wording nit — "Bun s3" looks out of place next toctx.*items.The other bullets in this section describe context-bound services (
ctx.kv,ctx.vector,ctx.stream). TheBun s3entry breaks that pattern and may confuse readers as to how it's reached from the handler. Consider aligning the phrasing, e.g.Bun.s3 - S3-compatible object storage (Bun built-in), or dropping it if it isn't part of the handler context surface you want to showcase here.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/run/handler-context.ts` around lines 43 - 47, The "Bun s3" bullet breaks the ctx.* pattern; update the console output so it consistently describes context-bound services — either rename the line to "Bun.s3 - S3-compatible object storage (Bun built-in)" or remove it if it's not part of the handler context; modify the console.log that prints "Bun s3 - S3-compatible object storage" near the other ctx lines (referencing ctx.kv, ctx.vector, ctx.stream) so the phrasing matches the others and clarifies access (e.g., "Bun.s3 - S3-compatible object storage (Bun built-in)").apps/docs/src/web/content/services/index.mdx (1)
6-6: Nit: longlucide-reactimport exceeds 100-col line width.This single-line import is ~190 columns. MDX isn't formatted by Biome, but for readability (and consistency with the repo's 100-col convention) consider wrapping the named imports across multiple lines.
♻️ Proposed refactor
-import { Database, Search, HardDrive, Server, Activity, Eye, FileText, Route, Bug, Box, Camera, Mail, Webhook, ListTodo, Clock, MessageSquare, BrainCircuit, KeyRound, ShieldCheck } from 'lucide-react'; +import { + Database, Search, HardDrive, Server, Activity, Eye, FileText, Route, Bug, + Box, Camera, Mail, Webhook, ListTodo, Clock, MessageSquare, BrainCircuit, + KeyRound, ShieldCheck, +} from 'lucide-react';As per coding guidelines: "Use Biome as code formatter with tabs (width 3), single quotes, semicolons, lineWidth 100, and trailingCommas es5".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/content/services/index.mdx` at line 6, The single-line named import from 'lucide-react' (Database, Search, HardDrive, Server, Activity, Eye, FileText, Route, Bug, Box, Camera, Mail, Webhook, ListTodo, Clock, MessageSquare, BrainCircuit, KeyRound, ShieldCheck) exceeds the 100-column line width; split the import across multiple lines so each line stays under 100 columns (one per symbol or grouped) and reformat with the repo Biome settings (tabs width 3, single quotes, semicolons, lineWidth 100, trailing commas es5) to keep the MDX readable and consistent.apps/docs/src/run/agent-calls.ts (1)
49-49: Minor: unnecessary template literal.
console.log(Scheduled async work after main execution);has no interpolation — a plain string literal would do. Same for line 50 if the trailing text doesn't need backticks (though line 50 does interpolate, so it's fine there). Trivial nit, feel free to ignore.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/run/agent-calls.ts` at line 49, Replace the unnecessary template literal in the console.log call in agent-calls.ts by using a plain string literal; locate the console.log(` Scheduled async work after main execution`) and change it to use regular quotes (e.g., " Scheduled async work after main execution") since there is no interpolation.apps/docs/src/run/streaming.ts (1)
48-52: Consider settingprocess.exitCode = 1in the error path for consistency.
ai-gateway.tssetsprocess.exitCode = 1on error (line 64), but this script does not. For parity across run scripts and so sandbox/pipeline consumers can detect failures via exit code, consider matching that behavior.♻️ Proposed change
} catch (error) { console.log('---OUTPUT---'); console.log(`Error: ${error instanceof Error ? error.message : String(error)}`); console.log('---OUTPUT---'); + process.exitCode = 1; }The same observation applies to
durable-stream.tsandagent-calls.ts, which also omit the exit code.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/run/streaming.ts` around lines 48 - 52, The catch block in apps/docs/src/run/streaming.ts currently logs the error but doesn't set a non-zero exit code; update the catch handler (the catch(error) block that logs '---OUTPUT---' and the error message) to set process.exitCode = 1 before or after logging so callers can detect failure; apply the same change to the equivalent catch blocks in durable-stream.ts and agent-calls.ts for parity with ai-gateway.ts's error handling.apps/docs/src/api/websocket/route.ts (1)
59-72: Minor:String(event.data)silently mangles binary frames.If a client ever sends a
Blob/ArrayBuffer,String(event.data)yields"[object Blob]"/"[object ArrayBuffer]"rather than an error. For an echo demo this is acceptable, but consider explicitly rejecting non-string frames to avoid confusing echoed output:Optional hardening
- const message = String(event.data).trim(); + if (typeof event.data !== 'string') { + ws.send(JSON.stringify({ + type: 'error', + message: 'Only text frames are supported', + timestamp: new Date().toISOString(), + })); + return; + } + const message = event.data.trim();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/api/websocket/route.ts` around lines 59 - 72, The WebSocket onMessage handler (ws.onMessage) currently coerces event.data via String(event.data), which mangles binary frames (Blob/ArrayBuffer); update the ws.onMessage callback to explicitly check the type of event.data and only proceed when it's a string (e.g., typeof event.data === 'string'), and for non-string frames return or send a clear error/ignore response instead of echoing "[object Blob]"/"[object ArrayBuffer]" so the echo logic that builds message/timestamp operates only on real text frames.apps/docs/src/run/schedule.ts (1)
39-65: Remove redundantschedules.get()call.
schedules.create()andschedules.get()return the same structure ({schedule, destinations}). Since all needed fields (id,name,expression,due_date) are already available on thescheduleobject fromcreate(), the subsequentawait schedules.get(schedule.id)is an unnecessary round trip. Reusescheduledirectly:♻️ Proposed refactor
- const current = await schedules.get(schedule.id); const { deliveries } = await schedules.listDeliveries(schedule.id, { limit: 5 }); - output.push(`Created schedule: ${current.schedule.id}`); - output.push(`Name: ${current.schedule.name}`); - output.push(`Expression: ${current.schedule.expression}`); - output.push(`Next run: ${current.schedule.due_date}`); + output.push(`Created schedule: ${schedule.id}`); + output.push(`Name: ${schedule.name}`); + output.push(`Expression: ${schedule.expression}`); + output.push(`Next run: ${schedule.due_date}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/run/schedule.ts` around lines 39 - 65, Remove the redundant await schedules.get(schedule.id) call: use the schedule object returned from schedules.create() (the variable schedule) for all fields instead of calling schedules.get; update any references that used current.schedule (e.g., current.schedule.id, current.schedule.name, current.schedule.expression, current.schedule.due_date) to use schedule.id, schedule.name, schedule.expression, schedule.due_date, keep scheduleId = schedule.id and retain the subsequent schedules.listDeliveries call unchanged.apps/docs/src/web/components/WebRTCDemo.tsx (2)
1192-1194: ReuseorderedRemotePeerIdsinstead of re-sorting inline.
orderedRemotePeerIds(line 969) already holds the sorted list. PassingremotePeerIds.slice().sort()here creates a fresh array every render, preventing referential-equality checks insideConnectionStatsPanelfrom short-circuiting work.♻️ Suggested change
- <ConnectionStatsPanel quality={quality} remotePeerIds={remotePeerIds.slice().sort()} /> + <ConnectionStatsPanel quality={quality} remotePeerIds={orderedRemotePeerIds} />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/components/WebRTCDemo.tsx` around lines 1192 - 1194, Replace the inline re-sorting that creates a new array every render by passing the already-sorted array `orderedRemotePeerIds` to `ConnectionStatsPanel` instead of `remotePeerIds.slice().sort()`; update the JSX where `ConnectionStatsPanel quality={quality} remotePeerIds={...}` is used so it references `orderedRemotePeerIds` to allow referential-equality checks to short-circuit renders.
915-915: MovesendStringRef.currentassignment into auseEffectto avoid render-phase ref mutations.
sendStringRef.current = sendString;executes at the top level ofVideoCallTabon every render. In React 19 with Concurrent mode, render functions can run multiple times before commit, so ref mutations during render are discouraged. UseuseEffectto keep the ref in sync post-commit, matching the existing pattern in the same component forstateRef,isAudioMutedRef, andisVideoMutedRef.♻️ Suggested change
- sendStringRef.current = sendString; + useEffect(() => { + sendStringRef.current = sendString; + }, [sendString]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/components/WebRTCDemo.tsx` at line 915, Move the assignment sendStringRef.current = sendString out of the render body of the VideoCallTab component and sync it inside a useEffect so ref mutations occur post-commit; specifically, add a useEffect that depends on sendString and sets sendStringRef.current = sendString (mirroring the existing useEffect patterns used for stateRef, isAudioMutedRef, and isVideoMutedRef) to avoid render-phase ref mutations in concurrent rendering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs/src/api/ai-gateway/route.ts`:
- Around line 38-50: Replace the non-streaming generateText usage for Gemini by
calling the provider's streamText API so responses are token-streamed: in the
branch that checks model.startsWith('gemini-'), call streamText({ model:
getModel(model), prompt: FIXED_PROMPT }) (instead of generateText) and return
the resulting ReadableStream directly so tokens arrive incrementally; if you
cannot switch, add a clear code comment next to the model.startsWith('gemini-')
check explaining the specific limitation why streamText cannot be used.
In `@apps/docs/src/api/model-arena/route.ts`:
- Around line 71-156: The stream's start handler never observes the incoming
request abort signal so generateStory and judgeStories keep running after the
client cancels; modify the start(controller) logic in stream/ReadableStream to
watch c.req.raw.signal (e.g., add an abort listener or attach the signal to a
local AbortController) and propagate that signal into calls to
deps.generateStory and deps.judgeStories (or pass the signal as an extra arg) so
those functions can cancel early; ensure the abort listener clears the heartbeat
interval, stops enqueuing, and causes the start handler to return/throw to
terminate the stream promptly.
In `@apps/docs/src/api/queue/route.ts`:
- Around line 169-174: The handler currently treats any ValidationOutputError as
an empty-queue result; update the catch for ValidationOutputError in route.ts to
inspect the error.issues (from the thrown ValidationOutputError) and only
convert to a success/no-messages response when the issues indicate an empty
response (e.g., a single issue about the top-level value being null/undefined or
a missing "messages" array), otherwise re-throw the error so malformations
surface; keep the existing c.var.logger?.warn and the c.json(...) path for the
empty-case but call throw err for real schema failures so they are not silently
swallowed.
In `@apps/docs/src/api/schedules/route.ts`:
- Around line 135-145: The code currently swallows malformed JSON by using
c.req.json().catch(() => ({})) which lets invalid payloads reach
CreateScheduleRequestSchema.safeParse and create schedules; change this so that
malformed JSON returns a 400 response instead of defaulting to {}: remove the
catch fallback and wrap the JSON parse in a try/catch (or handle the rejected
promise) so that when c.req.json() throws, the handler returns c.json({ success:
false, message: 'Invalid JSON payload.' }, 400) (refer to c.req.json,
CreateScheduleRequestSchema.safeParse, and parsed.success to locate the logic).
In `@apps/docs/src/api/vector-storage/route.ts`:
- Line 27: The /seed handler calls c.var.vector.upsert(...) directly which can
throw if c.var.vector is undefined (inconsistent with /status which checks
c.var.vector?.search); update the /seed flow to guard against missing vector
storage by checking c.var.vector before calling upsert (e.g. use
c.var.vector?.upsert(...) or an explicit if (!c.var.vector) return new
Response(JSON.stringify({ error: 'Vector store not available' }), { status: 503
})), ensuring you reference the same symbols (c.var.vector, upsert,
getVectorSeedDocuments, VECTOR_NAMESPACE) and return the intended 503 JSON
response instead of allowing a TypeError.
In `@apps/docs/src/lib/ai-gateway.ts`:
- Line 8: The baseUrl assignment can include a trailing slash from
AGENTUITY_TRANSPORT_URL or AGENTUITY_CATALYST_URL causing a double slash later;
normalize by trimming any trailing slashes when computing baseUrl (the variable
named baseUrl in ai-gateway.ts) — e.g., when selecting
process.env.AGENTUITY_TRANSPORT_URL || process.env.AGENTUITY_CATALYST_URL, strip
trailing '/' characters (use a replace or trim logic) so subsequent construction
of baseURL (e.g., baseUrl + '/gateway/google-ai-studio') never produces a double
slash.
- Around line 10-18: Replace raw Error throws in the AI Gateway config checks
with StructuredError from '@agentuity/core': add an import for StructuredError
and where apiKey or baseUrl are missing (the checks referencing apiKey and
baseUrl in ai-gateway.ts) throw a StructuredError that includes a clear code
(e.g. 'MISSING_CONFIG' or 'AGENTUITY_SDK_KEY_MISSING'), a descriptive message,
and optional context/meta (e.g. {envVar: 'AGENTUITY_SDK_KEY'} or {config:
'baseUrl'}) so failures surface with consistent structured metadata across the
codebase.
In `@apps/docs/src/run/schedule.ts`:
- Around line 56-65: The report is showing deliveries.length immediately after
creating the schedule so it will almost always be 0; change the logic in
run/schedule.ts around the schedules.get and schedules.listDeliveries calls to
poll for deliveries instead of reading them once: after creating the schedule
(current = await schedules.get(...)) loop calling
schedules.listDeliveries(schedule.id, { limit: 5 }) at a short interval (e.g.,
2–5s) until deliveries.length > 0 or a reasonable timeout (e.g., 60s) elapses,
then push the final "Deliveries" output (and optionally note timeout if none
found); alternatively remove the `Deliveries so far: ${deliveries.length}` line
if you prefer not to poll.
In `@apps/docs/src/run/websocket.ts`:
- Around line 46-68: The client can miss the server's initial system frame
because ws.onmessage is assigned after awaiting the open Promise; move or assign
ws.onmessage before creating/awaiting the Promise (i.e., attach the message
handler on the ws object before setting up the open/error handlers and before
resolving in the Promise) so incoming frames sent immediately on upgrade are
handled; keep the existing JSON/parsing logic and the Promise's
timeout/clearTimeout and onopen/onerror behavior unchanged.
In `@apps/docs/src/web/code-examples.ts`:
- Around line 287-298: The schedules.create example hardcodes the docs host in
the destinations config (the url field), which will send deliveries to the
public docs deployment when copied; update the example in the schedules.create
call to use a placeholder or environment-derived base URL (e.g.,
process.env.APP_BASE_URL or '<YOUR_APP_URL>') for the
destinations[...].config.url so readers replace it with their own app/webhook
instead of pointing at agentuity.dev.
In `@apps/docs/src/web/components/SchedulesDemo.tsx`:
- Around line 295-315: The current useEffect (empty deps) always deletes any
persisted schedule on mount via deleteSchedule and resets demoState, which wipes
active runs; change the logic in the effect that references demoState,
deleteSchedule, setDemoState, INITIAL_STATE and cleanedUp so it only treats a
schedule as stale by verifying an age or terminal-state: e.g., check
demoState.schedule.createdAt/lastUpdated against a TTL threshold OR confirm
demoState.status is in a terminal set (completed/failed/canceled) before calling
deleteSchedule and resetting state, and otherwise resume polling/state
restoration instead of deleting on mount; also ensure the effect depends on the
minimal needed demoState fields or runs a one-time resume-and-check flow rather
than unconditionally cleaning up.
In `@apps/docs/src/web/components/WebRTCDemo.tsx`:
- Around line 482-496: Handle clipboard errors and cancel the timeout on
unmount: update the copyLink implementation (the navigator.clipboard.writeText
call inside copyLink and the setTimeout that clears setCopied) to use try/catch
so any rejection is swallowed and you can set an error/fallback state or show
feedback; store the timeout id in a ref (e.g., copyTimeoutRef) and clear it in a
useEffect cleanup to avoid state updates after unmount; also ensure setCopied is
only set when mounted (or guard with the same ref) and remove usage of void
onClick by keeping copyLink as a self-contained async that handles its own
errors.
- Around line 245-304: The effect that creates the AudioContext/analyser (the
useEffect that reads stream, audioTrack and sets level via setLevel) aborts
early when audioTrack.enabled is false and only depends on stream, so unmuting
later doesn't restart the analyser; either include the track's enabled state in
the dependency array or (preferred) remove the early-return guard that checks
audioTrack.enabled and always start the analyser (keep the existing audio-muted
override elsewhere), i.e., locate the useEffect, remove the `!audioTrack ||
!audioTrack.enabled` short-circuit and ensure the effect deps include any track
reference if you choose the alternative approach so the analyser is recreated
when enabled toggles.
In `@apps/docs/src/web/content/services/oidc-provider.mdx`:
- Around line 79-84: The oauthConfig example uses process.env.OAUTH_ISSUER,
process.env.OAUTH_CLIENT_ID and process.env.OAUTH_CLIENT_SECRET which are typed
as string | undefined under TS strict mode and will cause type errors when
passed to functions like buildAuthorizeUrl, exchangeToken and fetchUserInfo; fix
by validating/normalizing these env values before constructing oauthConfig
(e.g., add a small helper like assertEnv(name) that throws if missing or supply
explicit non-null defaults) and use that helper when assigning
issuer/clientId/clientSecret so oauthConfig fields are guaranteed strings at
compile time.
- Around line 168-183: The snippet uses c.var.kv at top-level so c is undefined;
move this logic into a request handler (e.g., the existing /oauth/callback
handler) or refactor into a factory that accepts the kv store. Specifically,
create or reuse a handler function (where parameter c is available) and
instantiate KeyValueTokenStorage with c.var.kv, call tokenStore.set(user.sub,
token) and tokenStore.get(user.sub) inside that handler, and perform the
isTokenExpired check and redirect there; alternatively expose a helper function
that takes kv (or c) and returns the tokenStore so callers inside handlers can
safely use KeyValueTokenStorage, tokenStore, and isTokenExpired without
referencing undefined c.
In `@apps/docs/src/web/test-outputs.ts`:
- Around line 121-131: The schedules test-output entry currently contains two
---OUTPUT--- markers and places "Deleted schedule: sch_abc123xyz" after the
second marker, which will be dropped by the parser; update the schedules value
so it matches the single-marker style used elsewhere by removing the second
`---OUTPUT---` marker and keeping the “Deleted schedule: sch_abc123xyz” line
inside the single output block (ensure the `schedules` string contains exactly
one `---OUTPUT---` followed by the full body including the Deleted line).
---
Outside diff comments:
In `@apps/docs/src/api/queue/route.ts`:
- Around line 138-154: The pending message count uses the paged result's
messages array length (pending.messages.length) which is capped by the limit;
change it to use the paginated total field (pending.total) like dlq_count does —
update the response construction that references pending to set message_count to
pending.total (with an optional fallback to pending.messages.length if total is
undefined) and adjust the block around getQueue / listMessages /
listDeadLetterMessages accordingly.
In `@apps/docs/src/run/agent-calls.ts`:
- Around line 16-22: The CLI JSON parsing is done outside the try/catch so
malformed input will throw before your error framing; update the code that
creates the Input (currently using JSON.parse(process.argv[2] ?? '{}')) to
either move the parse into the existing try block or, preferably, use the
parseJSON helper used elsewhere (e.g. parseJSON<Input>(process.argv[2] ?? '{}',
{})) so parsing errors are handled and logged via the same ---OUTPUT--- error
flow; adjust references around Input and keep createAgentContext()/standaloneCtx
usage unchanged.
In `@apps/docs/src/web/demo-config.tsx`:
- Around line 313-525: The PR shows an inconsistency: the object with id
'websocket' uses category 'io-patterns' while the object with id 'webrtc' uses
category 'examples'; update the 'webrtc' demo entry (the object where id ===
'webrtc' and component is WebRTCDemo) to use category 'io-patterns' to match
WebSocket (or, if intentional, add a short inline comment next to the 'webrtc'
object's category explaining why it differs), ensuring the cross-linked
explorerHref references remain unchanged.
In `@apps/docs/src/web/test-outputs.ts`:
- Around line 87-93: Update the 'sse-stream' fixture string in test-outputs.ts
so its final lines match the current runtime output from run/sse-stream.ts
(replace the stale "[Streamed 47 tokens]" tail with the new buffered/chunk text
and explanatory line emitted by the live script); locate the 'sse-stream' entry
in apps/docs/src/web/test-outputs.ts and change its ending to include the
"[Buffered N text chunks in the sandbox]" text plus the "In a real route, each
chunk would be wrapped in named SSE events" line (use the same wording and a
matching chunk count as produced by run/sse-stream.ts).
---
Nitpick comments:
In `@apps/docs/src/api/index.ts`:
- Around line 19-27: Imports and router registrations are out of alphabetical
order: move the schedules import and its router registration so "sandbox" comes
before "schedules". Edit the import block to place "sandbox from
'./sandbox/route';" before "schedules from './schedules/route';" and update the
router chain to call sandbox.route(...) before schedules.route(...), targeting
the symbols "schedules" and "sandbox" in apps/docs/src/api/index.ts.
In `@apps/docs/src/api/sse-stream/route.ts`:
- Around line 43-58: The SSE event name is inconsistent with the surrounding
"chunk" terminology; update the event sent in the streaming loop by replacing
the literal 'token' with 'chunk' in the stream.writeSSE calls inside the
for-await loop (the call that currently passes event: 'token', data: chunk, id:
String(chunkCount++)), and keep the completion event as-is (event: 'done') while
retaining the usage-derived totalTokens in the done payload; ensure any code
that references the old 'token' event is updated to listen for 'chunk' instead.
In `@apps/docs/src/api/vector-storage/route.ts`:
- Around line 29-33: The JSON response in the seed handler currently returns
both "message" and "note" with the same content; simplify the API by removing
one of them (e.g., drop "note") in the c.json(...) return inside the route
handler so only a single descriptive field remains (update the return in the
seeding route where c.json is called), and adjust any related tests, type
definitions, or docs that expect the removed field to use the remaining key.
In `@apps/docs/src/api/websocket/route.ts`:
- Around line 59-72: The WebSocket onMessage handler (ws.onMessage) currently
coerces event.data via String(event.data), which mangles binary frames
(Blob/ArrayBuffer); update the ws.onMessage callback to explicitly check the
type of event.data and only proceed when it's a string (e.g., typeof event.data
=== 'string'), and for non-string frames return or send a clear error/ignore
response instead of echoing "[object Blob]"/"[object ArrayBuffer]" so the echo
logic that builds message/timestamp operates only on real text frames.
In `@apps/docs/src/lib/ai-gateway.ts`:
- Around line 23-39: The current createGoogleProvider and createGroqProvider
recreate provider instances and re-read env config on every call; change them to
return memoized module-scoped singletons: add private module-level variables
(e.g., googleProvider, groqProvider), lazily initialize them inside
createGoogleProvider/createGroqProvider by calling requireGatewayConfig and
constructing the provider only if the corresponding variable is undefined, then
return the cached instance on subsequent calls; ensure the initialization is
idempotent and uses the same unique symbols createGoogleGenerativeAI and
createGroq to build the instances.
In `@apps/docs/src/run/agent-calls.ts`:
- Line 49: Replace the unnecessary template literal in the console.log call in
agent-calls.ts by using a plain string literal; locate the console.log(`
Scheduled async work after main execution`) and change it to use regular quotes
(e.g., " Scheduled async work after main execution") since there is no
interpolation.
In `@apps/docs/src/run/handler-context.ts`:
- Around line 43-47: The "Bun s3" bullet breaks the ctx.* pattern; update the
console output so it consistently describes context-bound services — either
rename the line to "Bun.s3 - S3-compatible object storage (Bun built-in)" or
remove it if it's not part of the handler context; modify the console.log that
prints "Bun s3 - S3-compatible object storage" near the other ctx lines
(referencing ctx.kv, ctx.vector, ctx.stream) so the phrasing matches the others
and clarifies access (e.g., "Bun.s3 - S3-compatible object storage (Bun
built-in)").
In `@apps/docs/src/run/schedule.ts`:
- Around line 39-65: Remove the redundant await schedules.get(schedule.id) call:
use the schedule object returned from schedules.create() (the variable schedule)
for all fields instead of calling schedules.get; update any references that used
current.schedule (e.g., current.schedule.id, current.schedule.name,
current.schedule.expression, current.schedule.due_date) to use schedule.id,
schedule.name, schedule.expression, schedule.due_date, keep scheduleId =
schedule.id and retain the subsequent schedules.listDeliveries call unchanged.
In `@apps/docs/src/run/streaming.ts`:
- Around line 48-52: The catch block in apps/docs/src/run/streaming.ts currently
logs the error but doesn't set a non-zero exit code; update the catch handler
(the catch(error) block that logs '---OUTPUT---' and the error message) to set
process.exitCode = 1 before or after logging so callers can detect failure;
apply the same change to the equivalent catch blocks in durable-stream.ts and
agent-calls.ts for parity with ai-gateway.ts's error handling.
In `@apps/docs/src/web/components/WebRTCDemo.tsx`:
- Around line 1192-1194: Replace the inline re-sorting that creates a new array
every render by passing the already-sorted array `orderedRemotePeerIds` to
`ConnectionStatsPanel` instead of `remotePeerIds.slice().sort()`; update the JSX
where `ConnectionStatsPanel quality={quality} remotePeerIds={...}` is used so it
references `orderedRemotePeerIds` to allow referential-equality checks to
short-circuit renders.
- Line 915: Move the assignment sendStringRef.current = sendString out of the
render body of the VideoCallTab component and sync it inside a useEffect so ref
mutations occur post-commit; specifically, add a useEffect that depends on
sendString and sets sendStringRef.current = sendString (mirroring the existing
useEffect patterns used for stateRef, isAudioMutedRef, and isVideoMutedRef) to
avoid render-phase ref mutations in concurrent rendering.
In `@apps/docs/src/web/content/services/index.mdx`:
- Line 6: The single-line named import from 'lucide-react' (Database, Search,
HardDrive, Server, Activity, Eye, FileText, Route, Bug, Box, Camera, Mail,
Webhook, ListTodo, Clock, MessageSquare, BrainCircuit, KeyRound, ShieldCheck)
exceeds the 100-column line width; split the import across multiple lines so
each line stays under 100 columns (one per symbol or grouped) and reformat with
the repo Biome settings (tabs width 3, single quotes, semicolons, lineWidth 100,
trailing commas es5) to keep the MDX readable and consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 28a1aec9-6f36-4390-b30c-e2c3a8c65be7
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (79)
apps/docs/.agents/agentuity/sdk/agent/AGENTS.mdapps/docs/AGENTS.mdapps/docs/package.jsonapps/docs/scripts/generate-nav-data.tsapps/docs/src/agent/AGENTS.mdapps/docs/src/agent/chat/agent.tsapps/docs/src/agent/context/agent.tsapps/docs/src/agent/evals/agent.tsapps/docs/src/agent/evals/eval.tsapps/docs/src/agent/hello/agent.tsapps/docs/src/agent/index.tsapps/docs/src/agent/kv/agent.tsapps/docs/src/agent/model-arena/agent.tsapps/docs/src/agent/model-arena/lib.tsapps/docs/src/agent/model-arena/prompts.tsapps/docs/src/agent/model-arena/types.tsapps/docs/src/agent/objectstore/agent.tsapps/docs/src/agent/queue/agent.tsapps/docs/src/agent/sse-stream/agent.tsapps/docs/src/agent/text-processor/agent.tsapps/docs/src/agent/vector/agent.tsapps/docs/src/agent/websocket/agent.tsapps/docs/src/api/AGENTS.mdapps/docs/src/api/ai-gateway/route.tsapps/docs/src/api/evals/route.tsapps/docs/src/api/index.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/queue/route.tsapps/docs/src/api/sandbox/scripts.tsapps/docs/src/api/schedules/route.tsapps/docs/src/api/sse-stream/route.tsapps/docs/src/api/vector-storage/route.tsapps/docs/src/api/webrtc/route.tsapps/docs/src/api/websocket/route.tsapps/docs/src/lib/ai-gateway.tsapps/docs/src/lib/models.tsapps/docs/src/run/AGENTS.mdapps/docs/src/run/agent-calls.tsapps/docs/src/run/ai-gateway.tsapps/docs/src/run/chat.tsapps/docs/src/run/cron.tsapps/docs/src/run/durable-stream.tsapps/docs/src/run/evals.tsapps/docs/src/run/handler-context.tsapps/docs/src/run/hello.tsapps/docs/src/run/kv.tsapps/docs/src/run/model-arena.tsapps/docs/src/run/objectstore.tsapps/docs/src/run/queue.tsapps/docs/src/run/schedule.tsapps/docs/src/run/sse-stream.tsapps/docs/src/run/streaming.tsapps/docs/src/run/vector.tsapps/docs/src/run/webrtc.tsapps/docs/src/run/websocket.tsapps/docs/src/web/code-examples.tsapps/docs/src/web/components/CronDemo.tsxapps/docs/src/web/components/EvalsDemo.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/SchedulesDemo.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/WebSocketDemo.tsxapps/docs/src/web/components/docs/nav-data.tsapps/docs/src/web/content/cookbook/tutorials/rag-agent.mdxapps/docs/src/web/content/frontend/authentication.mdxapps/docs/src/web/content/reference/cli/oauth.mdxapps/docs/src/web/content/routes/http.mdxapps/docs/src/web/content/services/authentication.mdxapps/docs/src/web/content/services/index.mdxapps/docs/src/web/content/services/meta.jsonapps/docs/src/web/content/services/oidc-provider.mdxapps/docs/src/web/demo-config.tsxapps/docs/src/web/routeTree.gen.tsapps/docs/src/web/routes/_docs/services/oidc-provider.tsxapps/docs/src/web/routes/explorer/cron.tsxapps/docs/src/web/routes/explorer/schedules.tsxapps/docs/src/web/routes/explorer/webrtc.tsxapps/docs/src/web/routes/explorer/websocket.tsxapps/docs/src/web/test-outputs.ts
💤 Files with no reviewable changes (9)
- apps/docs/AGENTS.md
- apps/docs/src/agent/index.ts
- apps/docs/src/run/cron.ts
- apps/docs/src/agent/evals/agent.ts
- apps/docs/src/run/evals.ts
- apps/docs/src/web/components/CronDemo.tsx
- apps/docs/src/agent/evals/eval.ts
- apps/docs/src/web/components/EvalsDemo.tsx
- apps/docs/src/api/evals/route.ts
| useEffect(() => { | ||
| const audioTrack = stream?.getAudioTracks()[0]; | ||
| if (!stream || !audioTrack || !audioTrack.enabled) { | ||
| setLevel(0); | ||
| return; | ||
| } | ||
|
|
||
| let active = true; | ||
| let audioContext: AudioContext | undefined; | ||
| let source: MediaStreamAudioSourceNode | undefined; | ||
| let animationFrame = 0; | ||
|
|
||
| try { | ||
| audioContext = new AudioContext(); | ||
| const analyser = audioContext.createAnalyser(); | ||
| analyser.fftSize = 256; | ||
| analyser.smoothingTimeConstant = 0.3; | ||
|
|
||
| source = audioContext.createMediaStreamSource(stream); | ||
| source.connect(analyser); | ||
|
|
||
| const data = new Uint8Array(analyser.fftSize); | ||
|
|
||
| const tick = (): void => { | ||
| if (!active) { | ||
| return; | ||
| } | ||
|
|
||
| analyser.getByteTimeDomainData(data); | ||
| let peak = 0; | ||
| for (const value of data) { | ||
| const amplitude = Math.abs(value - 128) / 128; | ||
| if (amplitude > peak) { | ||
| peak = amplitude; | ||
| } | ||
| } | ||
|
|
||
| setLevel((previousLevel) => { | ||
| const boostedPeak = Math.min(1, peak * 1.15); | ||
| return Math.max(boostedPeak, previousLevel * 0.6); | ||
| }); | ||
| animationFrame = window.requestAnimationFrame(tick); | ||
| }; | ||
|
|
||
| animationFrame = window.requestAnimationFrame(tick); | ||
| } catch { | ||
| setLevel(0); | ||
| void audioContext?.close().catch(() => {}); | ||
| return; | ||
| } | ||
|
|
||
| return () => { | ||
| active = false; | ||
| window.cancelAnimationFrame(animationFrame); | ||
| try { | ||
| source?.disconnect(); | ||
| } catch {} | ||
| void audioContext?.close().catch(() => {}); | ||
| }; | ||
| }, [stream]); |
There was a problem hiding this comment.
Audio visualizer won't react to post-mount mute/unmute toggles.
The effect's deps only include stream, but the early-return guard checks audioTrack.enabled. If the component mounts with the track disabled (e.g., user joins muted), the analyzer is never started, and later unmuting won't re-run the effect — bars stay flat. Consider either tracking audioMuted/enabled in the dep array, or unconditionally starting the analyzer and letting the disabled track naturally emit silence (then only use audioMuted for the visual override you already have at line 326).
🛠️ Suggested adjustment
useEffect(() => {
- const audioTrack = stream?.getAudioTracks()[0];
- if (!stream || !audioTrack || !audioTrack.enabled) {
+ const audioTrack = stream?.getAudioTracks()[0];
+ if (!stream || !audioTrack) {
setLevel(0);
return;
}
- // ...
- }, [stream]);
+ // ...
+ }, [stream, audioMuted]);A disabled MediaStreamTrack produces silence through MediaStreamAudioSourceNode, so the analyzer can safely run regardless of enabled.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| const audioTrack = stream?.getAudioTracks()[0]; | |
| if (!stream || !audioTrack || !audioTrack.enabled) { | |
| setLevel(0); | |
| return; | |
| } | |
| let active = true; | |
| let audioContext: AudioContext | undefined; | |
| let source: MediaStreamAudioSourceNode | undefined; | |
| let animationFrame = 0; | |
| try { | |
| audioContext = new AudioContext(); | |
| const analyser = audioContext.createAnalyser(); | |
| analyser.fftSize = 256; | |
| analyser.smoothingTimeConstant = 0.3; | |
| source = audioContext.createMediaStreamSource(stream); | |
| source.connect(analyser); | |
| const data = new Uint8Array(analyser.fftSize); | |
| const tick = (): void => { | |
| if (!active) { | |
| return; | |
| } | |
| analyser.getByteTimeDomainData(data); | |
| let peak = 0; | |
| for (const value of data) { | |
| const amplitude = Math.abs(value - 128) / 128; | |
| if (amplitude > peak) { | |
| peak = amplitude; | |
| } | |
| } | |
| setLevel((previousLevel) => { | |
| const boostedPeak = Math.min(1, peak * 1.15); | |
| return Math.max(boostedPeak, previousLevel * 0.6); | |
| }); | |
| animationFrame = window.requestAnimationFrame(tick); | |
| }; | |
| animationFrame = window.requestAnimationFrame(tick); | |
| } catch { | |
| setLevel(0); | |
| void audioContext?.close().catch(() => {}); | |
| return; | |
| } | |
| return () => { | |
| active = false; | |
| window.cancelAnimationFrame(animationFrame); | |
| try { | |
| source?.disconnect(); | |
| } catch {} | |
| void audioContext?.close().catch(() => {}); | |
| }; | |
| }, [stream]); | |
| useEffect(() => { | |
| const audioTrack = stream?.getAudioTracks()[0]; | |
| if (!stream || !audioTrack) { | |
| setLevel(0); | |
| return; | |
| } | |
| let active = true; | |
| let audioContext: AudioContext | undefined; | |
| let source: MediaStreamAudioSourceNode | undefined; | |
| let animationFrame = 0; | |
| try { | |
| audioContext = new AudioContext(); | |
| const analyser = audioContext.createAnalyser(); | |
| analyser.fftSize = 256; | |
| analyser.smoothingTimeConstant = 0.3; | |
| source = audioContext.createMediaStreamSource(stream); | |
| source.connect(analyser); | |
| const data = new Uint8Array(analyser.fftSize); | |
| const tick = (): void => { | |
| if (!active) { | |
| return; | |
| } | |
| analyser.getByteTimeDomainData(data); | |
| let peak = 0; | |
| for (const value of data) { | |
| const amplitude = Math.abs(value - 128) / 128; | |
| if (amplitude > peak) { | |
| peak = amplitude; | |
| } | |
| } | |
| setLevel((previousLevel) => { | |
| const boostedPeak = Math.min(1, peak * 1.15); | |
| return Math.max(boostedPeak, previousLevel * 0.6); | |
| }); | |
| animationFrame = window.requestAnimationFrame(tick); | |
| }; | |
| animationFrame = window.requestAnimationFrame(tick); | |
| } catch { | |
| setLevel(0); | |
| void audioContext?.close().catch(() => {}); | |
| return; | |
| } | |
| return () => { | |
| active = false; | |
| window.cancelAnimationFrame(animationFrame); | |
| try { | |
| source?.disconnect(); | |
| } catch {} | |
| void audioContext?.close().catch(() => {}); | |
| }; | |
| }, [stream, audioMuted]); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/src/web/components/WebRTCDemo.tsx` around lines 245 - 304, The
effect that creates the AudioContext/analyser (the useEffect that reads stream,
audioTrack and sets level via setLevel) aborts early when audioTrack.enabled is
false and only depends on stream, so unmuting later doesn't restart the
analyser; either include the track's enabled state in the dependency array or
(preferred) remove the early-return guard that checks audioTrack.enabled and
always start the analyser (keep the existing audio-muted override elsewhere),
i.e., locate the useEffect, remove the `!audioTrack || !audioTrack.enabled`
short-circuit and ensure the effect deps include any track reference if you
choose the alternative approach so the analyser is recreated when enabled
toggles.
- tighten `stream`, `queue`, `schedule`, and `vector` - clean up sandbox scripts and Explorer output fixtures - clarify AI Gateway provider setup and Gemini fallback - refresh Explorer model defaults to `gpt-5.4-nano` - align Coder docs with `enabledAgents` - polish OIDC docs and LLM text surfaces
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/docs/src/web/content/cookbook/patterns/using-workspaces-to-reuse-repos-skills-and-agent-selection.mdx (1)
46-72:⚠️ Potential issue | 🟡 MinorShow
enabledAgentsin the read-back confirmation.Line 46 stores the workspace roster, but the confirmation output does not include
session.enabledAgents, so the example cannot prove that agent selection flowed throughworkspaceId.📝 Proposed docs update
workspaceId: workspace.id, sessionId: session.sessionId, defaultAgent: session.defaultAgent, + enabledAgents: session.enabledAgents, skills: session.skills.map((skill) => ({ repo: skill.repo, skillId: skill.skillId, name: skill.name,"workspaceId": "ws_956cc248e682", "sessionId": "codesess_2f3af05751fb", "defaultAgent": "builder", + "enabledAgents": ["builder", "reviewer"], "skills": [- the workspace stored the reusable selections - `workspaceId` carried those selections into the session +- `enabledAgents` confirms the workspace agent roster was applied - you can still set a default agent like `builder` when you create the session🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/content/cookbook/patterns/using-workspaces-to-reuse-repos-skills-and-agent-selection.mdx` around lines 46 - 72, The example reads back the session but omits showing the inherited enabledAgents, so update the read-back/console output after client.getSession(created.sessionId) to include session.enabledAgents; locate the session object usage in the snippet (after client.createSession and const session = await client.getSession(...)) and add enabledAgents to the JSON being logged alongside workspaceId, sessionId, defaultAgent, and skills to demonstrate the workspace roster propagated correctly.apps/docs/src/run/chat.ts (1)
24-32:⚠️ Potential issue | 🟡 MinorValidate parsed input before using
message.
JSON.parsereturns untrusted runtime data;{"message":123}currently bypasses theInputtype and sends a non-string message through the demo path.Proposed fix
-interface Input { - message?: string; -} - const standaloneCtx = createAgentContext(); try { - const input: Input = JSON.parse(process.argv[2] ?? '{}'); - const message = input.message ?? 'What is Agentuity?'; + const input: unknown = JSON.parse(process.argv[2] ?? '{}'); + const message = + typeof input === 'object' && + input !== null && + 'message' in input && + typeof input.message === 'string' + ? input.message + : 'What is Agentuity?';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/run/chat.ts` around lines 24 - 32, The parsed runtime Input may contain non-string values (e.g. {"message":123}) so validate before using; after JSON.parse(process.argv[2] ?? '{}') assign to a local variable (e.g. const parsed = JSON.parse(...)) and ensure the message is a string: const message = typeof parsed.message === 'string' ? parsed.message : 'What is Agentuity?'; update any code paths that use message (the demo path that uses standaloneCtx and message) to rely on this validated string so non-string inputs are rejected/coerced to the default.apps/docs/src/web/components/SSEStreamDemo.tsx (1)
93-101:⚠️ Potential issue | 🟡 Minor
isEstimate: falseis inaccurate during streaming — chunks ≠ tokens.The comment claims the count is accurate because we receive individual stream chunks, but a
chunkSSE event corresponds to atextStreamdelta (often multi-token), not a single token. IncrementingtokenCountper chunk and flippingisEstimatetofalsewill display a count that's almost always lower than the real token count until thedoneevent arrives withtotalTokens. KeepisEstimate: trueduring streaming so the UI shows"N tokens (est.)"until the real count lands.🛠️ Suggested adjustment
- // Handle chunk events - count is accurate since we receive individual stream chunks + // Handle chunk events - chunk count is a rough proxy; real token count arrives on 'done'. eventSource.addEventListener('chunk', (event) => { setState((prev) => ({ ...prev, content: prev.content + event.data, tokenCount: prev.tokenCount + 1, - isEstimate: false, + isEstimate: true, })); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/components/SSEStreamDemo.tsx` around lines 93 - 101, The chunk SSE handler in SSEStreamDemo incorrectly treats each 'chunk' event as a single token and flips isEstimate to false; update the eventSource.addEventListener('chunk', ...) handler so it appends event.data to content but does NOT increment tokenCount by 1 or set isEstimate to false (keep isEstimate true while streaming), and ensure the final 'done' handler remains responsible for setting the authoritative tokenCount and flipping isEstimate to false once totalTokens is received.
🧹 Nitpick comments (2)
apps/docs/src/api/vector-storage/route.ts (1)
37-41: Consider500instead of503for unexpected seed failures.
503is appropriate whenc.var.vectoris absent (service unavailable), but the catch-all block returns503for any error thrown byupsert— including validation/data issues that aren't availability-related. A generic failure is more accurately a500, reserving503for the service-missing branch on line 28.Proposed tweak
- return c.json({ success: false, error: message }, 503); + return c.json({ success: false, error: message }, 500);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/api/vector-storage/route.ts` around lines 37 - 41, The catch-all error handler currently returns HTTP 503 for any failure in the upsert/seed path; update the response status to 500 instead of 503 in the catch block (the one that logs via c.var.logger?.error('Vector seed failed', { error }) and builds message = error instanceof Error ? error.message : 'Vector seed failed') so that unexpected internal errors return 500 while preserving the existing 503 use for the earlier service-missing branch when c.var.vector is absent.apps/docs/src/web/components/SchedulesDemo.tsx (1)
245-268: Minor: transient'waiting'status while finalizing.
updateFromPayload(payload, 'waiting', false)runs before the delivery-status check, so when a poll returns asuccess/faileddelivery the UI flips towaitingand then awaitsdeleteScheduleinsidefinalizeRunbefore reaching the terminal state. That can briefly show the countdown/"Waiting" badge for a delivered run. Consider branching onlatestDelivery?.statusbefore the generic update, or passing the next status intoupdateFromPayload.♻️ Suggested refactor
const latestDelivery = getPrimaryDelivery(payload.deliveries); - updateFromPayload(payload, 'waiting', false); - - if (latestDelivery?.status === 'success') { - await finalizeRun(scheduleId, 'delivered'); - return; - } - - if (latestDelivery?.status === 'failed') { - await finalizeRun(scheduleId, 'failed'); - return; - } + if (latestDelivery?.status === 'success') { + updateFromPayload(payload, 'delivered', false); + await finalizeRun(scheduleId, 'delivered'); + return; + } + if (latestDelivery?.status === 'failed') { + updateFromPayload(payload, 'failed', false); + await finalizeRun(scheduleId, 'failed'); + return; + } + updateFromPayload(payload, 'waiting', false);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/web/components/SchedulesDemo.tsx` around lines 245 - 268, The UI briefly shows 'waiting' because updateFromPayload(payload, 'waiting', false) runs before checking latestDelivery status; change the logic in the poll block (around getPrimaryDelivery, updateFromPayload, finalizeRun) to first inspect latestDelivery?.status and, if it is 'success' or 'failed', call finalizeRun(scheduleId, 'delivered'|'failed') immediately (and skip the generic update), otherwise call updateFromPayload with the 'waiting' state; alternatively, compute the correct next status from getPrimaryDelivery and pass that status into updateFromPayload so the UI never transiently flips to 'waiting' before finalizeRun runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs/src/api/schedules/route.ts`:
- Around line 133-183: Add authentication and per-caller limits to the POST /
handler: apply the same middleware pattern used by the `sessions`/`process-docs`
routes (e.g., `cookieAuth` or `bearerTokenAuth`) to this `.post('/', ...)`
route, extract the caller identity (use `chat_user_id` from the cookie/session
on `c.req`), and scope schedule ownership by injecting that ID into the schedule
creation params (the object built by `createScheduleParams` / passed to
`c.var.schedule.create`). Before calling `c.var.schedule.create`, query the
store for how many active schedules exist for that caller and enforce a hard
per-caller limit (reject with 429 or 400 if exceeded); also consider
rejecting/limiting requests from unauthenticated callers with a 401. Keep the
rest of the validation (e.g., `CreateScheduleRequestSchema`,
`buildDestinationUrl`, `DEFAULT_EXPRESSION`) intact.
- Around line 75-82: Replace the string-based message parsing in
isMissingScheduleError with a typed check against ServiceException: change the
function to return error instanceof ServiceException && error.statusCode ===
404; ensure the ServiceException symbol is imported/available in the file so the
instanceof check compiles and remove the toLowerCase/message.includes logic.
In `@apps/docs/src/run/chat.ts`:
- Around line 77-81: The catch block in apps/docs/src/run/chat.ts currently logs
the error but doesn't signal failure; update the catch to return a failing exit
code by calling process.exit(1) (or rethrow the error) after logging so the
process exits non‑zero on failure, mirroring the behavior used in
agent-calls.ts; locate the catch block around the main async run in chat.ts and
append process.exit(1) after the existing console.error/console.log error
output.
In `@apps/docs/src/run/handler-context.ts`:
- Around line 68-72: The catch block in apps/docs/src/run/handler-context.ts
currently logs the error but leaves the process exit code at 0; set a non-zero
exit code so callers can detect failure by adding either process.exitCode = 1
(preferred) or process.exit(1) after the existing console.log statements in that
catch block to mark the run as failed.
In `@apps/docs/src/web/components/ModelArena.tsx`:
- Around line 294-302: The stop() callback currently treats a user-initiated
cancel as an error by setting state.status to 'error' and globalError to 'Run
stopped before completion'; change stop() (which calls
abortControllerRef.current?.abort()) to set a non-error terminal state instead —
e.g., setState(prev => ({ ...prev, status: 'stopped', globalError: 'Run stopped
by user' })) or set status to 'idle' and set a separate informational
flag/message so the UI doesn't render the red error banner; update any UI logic
that treats only 'error' as the red banner to ignore the new 'stopped' state (or
respect the informational flag) so user cancels are not styled as errors.
- Around line 247-266: The read-loop should not let a single malformed JSON line
throw the whole stream: inside the for (const line of lines) loop (the code that
currently does const event = JSON.parse(line) as StreamEvent; and calls
applyEvent), wrap JSON.parse in a try/catch and skip any unparseable lines
(optionally log them) so only successfully parsed events are passed to
applyEvent and used to set sawTerminalEvent; keep the outer try/catch for real
connection errors and retain the existing abortController/sawTerminalEvent logic
so the run is only failed by a server-sent event.event === 'error' or an actual
connection failure, not by a bad line.
In `@apps/docs/src/web/components/WebRTCDemo.tsx`:
- Around line 586-597: The onDataChannelMessage handler currently falls back to
JSON.stringify and yields "{}" for binary payloads; update the
onDataChannelMessage callback in WebRTCDemo.tsx (the function named
onDataChannelMessage that calls appendMessage) to detect binary types
(ArrayBuffer, TypedArray, Blob) and handle them explicitly: use TextDecoder to
decode ArrayBuffer/TypedArray to UTF-8 text before calling appendMessage, await
blob.text() for Blob if the handler can be made async (or convert Blob to
ArrayBuffer and decode), and if decoding fails or the payload is unknown, pass a
clear placeholder like "[binary payload]" to appendMessage instead of
JSON.stringify(data). Ensure appendMessage is called with a string in all
branches.
---
Outside diff comments:
In `@apps/docs/src/run/chat.ts`:
- Around line 24-32: The parsed runtime Input may contain non-string values
(e.g. {"message":123}) so validate before using; after
JSON.parse(process.argv[2] ?? '{}') assign to a local variable (e.g. const
parsed = JSON.parse(...)) and ensure the message is a string: const message =
typeof parsed.message === 'string' ? parsed.message : 'What is Agentuity?';
update any code paths that use message (the demo path that uses standaloneCtx
and message) to rely on this validated string so non-string inputs are
rejected/coerced to the default.
In `@apps/docs/src/web/components/SSEStreamDemo.tsx`:
- Around line 93-101: The chunk SSE handler in SSEStreamDemo incorrectly treats
each 'chunk' event as a single token and flips isEstimate to false; update the
eventSource.addEventListener('chunk', ...) handler so it appends event.data to
content but does NOT increment tokenCount by 1 or set isEstimate to false (keep
isEstimate true while streaming), and ensure the final 'done' handler remains
responsible for setting the authoritative tokenCount and flipping isEstimate to
false once totalTokens is received.
In
`@apps/docs/src/web/content/cookbook/patterns/using-workspaces-to-reuse-repos-skills-and-agent-selection.mdx`:
- Around line 46-72: The example reads back the session but omits showing the
inherited enabledAgents, so update the read-back/console output after
client.getSession(created.sessionId) to include session.enabledAgents; locate
the session object usage in the snippet (after client.createSession and const
session = await client.getSession(...)) and add enabledAgents to the JSON being
logged alongside workspaceId, sessionId, defaultAgent, and skills to demonstrate
the workspace roster propagated correctly.
---
Nitpick comments:
In `@apps/docs/src/api/vector-storage/route.ts`:
- Around line 37-41: The catch-all error handler currently returns HTTP 503 for
any failure in the upsert/seed path; update the response status to 500 instead
of 503 in the catch block (the one that logs via c.var.logger?.error('Vector
seed failed', { error }) and builds message = error instanceof Error ?
error.message : 'Vector seed failed') so that unexpected internal errors return
500 while preserving the existing 503 use for the earlier service-missing branch
when c.var.vector is absent.
In `@apps/docs/src/web/components/SchedulesDemo.tsx`:
- Around line 245-268: The UI briefly shows 'waiting' because
updateFromPayload(payload, 'waiting', false) runs before checking latestDelivery
status; change the logic in the poll block (around getPrimaryDelivery,
updateFromPayload, finalizeRun) to first inspect latestDelivery?.status and, if
it is 'success' or 'failed', call finalizeRun(scheduleId, 'delivered'|'failed')
immediately (and skip the generic update), otherwise call updateFromPayload with
the 'waiting' state; alternatively, compute the correct next status from
getPrimaryDelivery and pass that status into updateFromPayload so the UI never
transiently flips to 'waiting' before finalizeRun runs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 478b5d8d-2044-4a20-9fa2-5fa248223189
📒 Files selected for processing (47)
apps/docs/scripts/generate-markdown-files.tsapps/docs/src/agent/model-arena/lib.tsapps/docs/src/api/AGENTS.mdapps/docs/src/api/ai-gateway/route.tsapps/docs/src/api/index.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/queue/route.tsapps/docs/src/api/schedules/route.tsapps/docs/src/api/sse-stream/route.tsapps/docs/src/api/streaming/route.tsapps/docs/src/api/vector-storage/route.tsapps/docs/src/api/websocket/route.tsapps/docs/src/lib/ai-gateway.tsapps/docs/src/run/agent-calls.tsapps/docs/src/run/ai-gateway.tsapps/docs/src/run/chat.tsapps/docs/src/run/durable-stream.tsapps/docs/src/run/handler-context.tsapps/docs/src/run/model-arena.tsapps/docs/src/run/schedule.tsapps/docs/src/run/sse-stream.tsapps/docs/src/run/streaming.tsapps/docs/src/run/websocket.tsapps/docs/src/web/code-examples.tsapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/SSEStreamDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsxapps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/docs/nav-data.tsapps/docs/src/web/content/agents/ai-gateway.mdxapps/docs/src/web/content/cookbook/patterns/choosing-built-in-agents-for-a-coder-session.mdxapps/docs/src/web/content/cookbook/patterns/llm-as-a-judge.mdxapps/docs/src/web/content/cookbook/patterns/using-workspaces-to-reuse-repos-skills-and-agent-selection.mdxapps/docs/src/web/content/cookbook/patterns/web-exploration.mdxapps/docs/src/web/content/cookbook/tutorials/rag-agent.mdxapps/docs/src/web/content/reference/cli/debugging.mdxapps/docs/src/web/content/routes/http.mdxapps/docs/src/web/content/services/coder.mdxapps/docs/src/web/content/services/index.mdxapps/docs/src/web/content/services/oidc-provider.mdxapps/docs/src/web/demo-config.tsxapps/docs/src/web/routeTree.gen.tsapps/docs/src/web/test-outputs.tstemplates/default/src/agent/translate/index.tstemplates/default/src/web/App.tsx
💤 Files with no reviewable changes (2)
- apps/docs/src/web/content/reference/cli/debugging.mdx
- apps/docs/scripts/generate-markdown-files.ts
✅ Files skipped from review due to trivial changes (13)
- apps/docs/src/api/AGENTS.md
- apps/docs/src/api/streaming/route.ts
- apps/docs/src/web/content/agents/ai-gateway.mdx
- apps/docs/src/web/content/services/index.mdx
- apps/docs/src/web/components/StreamingDemo.tsx
- apps/docs/src/web/content/routes/http.mdx
- apps/docs/src/web/content/cookbook/patterns/llm-as-a-judge.mdx
- apps/docs/src/web/content/cookbook/tutorials/rag-agent.mdx
- apps/docs/src/web/components/docs/nav-data.ts
- apps/docs/src/web/content/cookbook/patterns/web-exploration.mdx
- apps/docs/src/run/websocket.ts
- apps/docs/src/web/content/services/oidc-provider.mdx
- apps/docs/src/web/routeTree.gen.ts
🚧 Files skipped from review as they are similar to previous changes (10)
- apps/docs/src/api/index.ts
- apps/docs/src/api/sse-stream/route.ts
- apps/docs/src/run/ai-gateway.ts
- apps/docs/src/run/sse-stream.ts
- apps/docs/src/api/ai-gateway/route.ts
- apps/docs/src/lib/ai-gateway.ts
- apps/docs/src/run/durable-stream.ts
- apps/docs/src/api/queue/route.ts
- apps/docs/src/run/schedule.ts
- apps/docs/src/web/demo-config.tsx
📜 Review details
⏰ 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). (13)
- GitHub Check: Framework Integration Tests (TanStack & Next.js)
- GitHub Check: Sandbox CLI Tests
- GitHub Check: Queue CLI Tests
- GitHub Check: Queue SDK Tests
- GitHub Check: SDK Integration Test Suite
- GitHub Check: Playwright E2E Smoke Test
- GitHub Check: Postgres SSL Integration Test
- GitHub Check: Package Installation & Usage Test
- GitHub Check: Cloud Deployment Tests
- GitHub Check: Template Integration Tests
- GitHub Check: Build
- GitHub Check: Windows WSL CLI Smoke Test
- GitHub Check: Agentuity Deployment
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome as code formatter with tabs (width 3), single quotes, semicolons, lineWidth 100, and trailingCommas es5
Files:
apps/docs/src/run/model-arena.tsapps/docs/src/web/components/SSEStreamDemo.tsxtemplates/default/src/agent/translate/index.tsapps/docs/src/run/streaming.tstemplates/default/src/web/App.tsxapps/docs/src/run/handler-context.tsapps/docs/src/run/agent-calls.tsapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/api/vector-storage/route.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/run/chat.tsapps/docs/src/api/websocket/route.tsapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/test-outputs.tsapps/docs/src/web/code-examples.tsapps/docs/src/api/schedules/route.tsapps/docs/src/web/components/SchedulesDemo.tsxapps/docs/src/agent/model-arena/lib.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript Strict mode with ESNext target and bundler moduleResolution
UseStructuredErrorfrom@agentuity/corefor error handling
Files:
apps/docs/src/run/model-arena.tsapps/docs/src/web/components/SSEStreamDemo.tsxtemplates/default/src/agent/translate/index.tsapps/docs/src/run/streaming.tstemplates/default/src/web/App.tsxapps/docs/src/run/handler-context.tsapps/docs/src/run/agent-calls.tsapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/api/vector-storage/route.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/run/chat.tsapps/docs/src/api/websocket/route.tsapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/test-outputs.tsapps/docs/src/web/code-examples.tsapps/docs/src/api/schedules/route.tsapps/docs/src/web/components/SchedulesDemo.tsxapps/docs/src/agent/model-arena/lib.ts
apps/docs/src/run/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Standalone demo scripts should be created in
src/run/directory with individual files for each demo (e.g.,hello.ts,chat.ts,kv.ts). After creating new scripts, runbun run generate:scriptsto regenerate script metadata.
Files:
apps/docs/src/run/model-arena.tsapps/docs/src/run/streaming.tsapps/docs/src/run/handler-context.tsapps/docs/src/run/agent-calls.tsapps/docs/src/run/chat.ts
apps/docs/src/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
React frontend components should be organized in
src/web/with hooks insrc/web/hooks/and reusable components insrc/web/components/. The entry point must befrontend.tsxwhich renders to#root, andApp.tsxmust contain the main React component.
Files:
apps/docs/src/web/components/SSEStreamDemo.tsxapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/test-outputs.tsapps/docs/src/web/code-examples.tsapps/docs/src/web/components/SchedulesDemo.tsx
apps/docs/src/web/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
SSE terminal output should be displayed using the
TerminalOutputcomponent located insrc/web/components/TerminalOutput.tsx
Files:
apps/docs/src/web/components/SSEStreamDemo.tsxapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
apps/docs/src/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
React components should use TypeScript/TSX syntax. The build system automatically handles all compilation, bundling, and hot module reloading—no need for external Babel or bundlers.
Files:
apps/docs/src/web/components/SSEStreamDemo.tsxapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/test-outputs.tsapps/docs/src/web/code-examples.tsapps/docs/src/web/components/SchedulesDemo.tsx
**/index.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use named exports from package
index.tsfiles
Files:
templates/default/src/agent/translate/index.ts
apps/docs/src/api/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
API routes should be organized in the
src/api/directory with subdirectories for each endpoint type (e.g.,hello/,chat/,streaming/,sse-stream/,sandbox/)
Files:
apps/docs/src/api/vector-storage/route.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/websocket/route.tsapps/docs/src/api/schedules/route.ts
apps/docs/src/agent/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Agent implementations should be organized in the
src/agent/directory with subdirectories for each agent type (e.g.,hello/,chat/,context/,kv/,vector/,objectstore/,model-arena/)
Files:
apps/docs/src/agent/model-arena/lib.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: Build should be executed with `bun run build` to compile the application
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: Development should be started with `bun run dev` to start the development server
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: TypeScript type checking should be performed with `bun run typecheck`
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: Deployment should be executed with `bun run deploy` to deploy the app to the Agentuity cloud
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: The app serves as a reference implementation demonstrating multiple agent implementations, API routes (REST, streaming, SSE, WebSocket), cloud sandbox execution for live code demos, React 19 frontend with interactive demo components, Tailwind CSS styling, and AI SDK integration with multiple providers (OpenAI, Anthropic, Google, Groq)
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: Cloud sandbox execution uses a session reuse architecture where the thread ID from `atid` cookie identifies the user session, and a KV bucket `explorer-sessions` stores `threadId → sandboxId` mapping. Sandboxes are created without initial commands and stay in idle state, with 10-minute idle timeout for automatic cleanup and KV TTL refreshed on each use.
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:43.138Z
Learning: When adding a new demo script, create the script in `src/run/`, run `bun run generate:scripts` to regenerate script metadata, rebuild the sandbox snapshot to include the new script, and add demo config to the `DEMOS` array in `src/web/App.tsx`
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:52.346Z
Learning: HTTP routes for agents must be placed in src/api/, not in agent folders
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:12:52.346Z
Learning: Optional supporting files for agents include lib.ts, types.ts, prompts.ts, sample-data.json, and context.txt
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:13:04.238Z
Learning: Each API folder name becomes the route name (e.g., status/ folder → /api/status endpoint)
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:13:04.238Z
Learning: Return appropriate HTTP status codes (200, 400, 404, 500, etc.) from route handlers
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-17T21:13:11.209Z
Learning: Scripts should be self-contained demonstrations of specific SDK capabilities
📚 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:
apps/docs/src/run/model-arena.tstemplates/default/src/agent/translate/index.tsapps/docs/src/run/streaming.tsapps/docs/src/run/handler-context.tsapps/docs/src/run/agent-calls.tsapps/docs/src/api/vector-storage/route.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/run/chat.tsapps/docs/src/api/websocket/route.tsapps/docs/src/web/test-outputs.tsapps/docs/src/web/code-examples.tsapps/docs/src/api/schedules/route.tsapps/docs/src/agent/model-arena/lib.ts
📚 Learning: 2026-01-09T16:26:51.893Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 523
File: templates/_base/src/web/frontend.tsx:13-35
Timestamp: 2026-01-09T16:26:51.893Z
Learning: In web frontend code, prefer using the built-in Error class for runtime errors. Do not throw or re-export StructuredError from agentuity/core in web app code. Replace instances of StructuredError with new Error or custom error types that extend Error; ensure error handling logic remains intact and that error messages are descriptive. This guideline applies to all web UI TypeScript/TSX files that run in the browser and import StructuredError from agentuity/core.
Applied to files:
apps/docs/src/web/components/SSEStreamDemo.tsxtemplates/default/src/web/App.tsxapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
📚 Learning: 2026-01-06T03:11:55.300Z
Learnt from: mcongrove
Repo: agentuity/sdk PR: 396
File: templates/default/src/web/App.tsx:111-111
Timestamp: 2026-01-06T03:11:55.300Z
Learning: In this repository's default template (Tailwind CSS v4 via tailwindcss/vite), gradient utilities such as bg-linear-to-*, bg-radial, and bg-conic are valid. Do not flag or replace these with bg-gradient-to-* in template files under templates/, including templates/default/src/web/App.tsx. Use bg-* utilities appropriate to Tailwind v4.
Applied to files:
templates/default/src/web/App.tsx
📚 Learning: 2026-01-06T03:11:55.300Z
Learnt from: mcongrove
Repo: agentuity/sdk PR: 396
File: templates/default/src/web/App.tsx:111-111
Timestamp: 2026-01-06T03:11:55.300Z
Learning: In templates/default/src/web/App.tsx, keep using the Tailwind v4 class bg-linear-to-r for the background gradient. Do not suggest changing it to bg-gradient-to-r. This is a file-specific convention based on the project’s Tailwind version; for other files, verify the Tailwind version before proposing class changes.
Applied to files:
templates/default/src/web/App.tsx
📚 Learning: 2025-12-19T14:19:33.765Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 259
File: packages/cli/src/cmd/build/vite/registry-generator.ts:306-312
Timestamp: 2025-12-19T14:19:33.765Z
Learning: Route files under src/api should use the .ts extension only (no .tsx) and regex patterns for such paths should anchor to \.ts$ (e.g., /\/.ts$/). Agent files may support both .ts and .tsx, but route files in the Agentuity SDK codebase are restricted to .ts. This guideline applies to all similar route files under src/api across the repository.
Applied to files:
apps/docs/src/api/vector-storage/route.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/websocket/route.tsapps/docs/src/api/schedules/route.ts
📚 Learning: 2026-02-25T22:13:01.823Z
Learnt from: Huijiro
Repo: agentuity/sdk PR: 1063
File: apps/testing/vite-rsc-app/agentuity/src/api/index.ts:26-26
Timestamp: 2026-02-25T22:13:01.823Z
Learning: Agentuity SDK requires default exports for API route files (e.g., src/api/**/index.ts and src/api/**/route.ts) because the CLI's generateRouteRegistry relies on default exports to discover routes. Using named exports will skip route generation and lead to runtime 500 errors. This overrides typical guidance about named exports in index.ts files; ensure a default export is present in all relevant API route files under src/api/**/.
Applied to files:
apps/docs/src/api/vector-storage/route.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/websocket/route.tsapps/docs/src/api/schedules/route.ts
🔇 Additional comments (23)
apps/docs/src/run/streaming.ts (1)
5-52: LGTM!Terminology rename (
tokenCount→chunkCount), doc pointer update toAGENTS.md, matching---OUTPUT---framing, andprocess.exitCode = 1on the error path are all consistent and correct. Behavior is unchanged aside from the intended model bump and clearer output framing.templates/default/src/agent/translate/index.ts (1)
19-19: LGTM — model identifier bump is consistent.
MODELSand the handler default are updated in lockstep, and thes.enum(MODELS)validation stays aligned with the UI options inApp.tsx.Also applies to: 63-63
templates/default/src/web/App.tsx (1)
9-9: LGTM — UI model list matches the agent schema.
MODELS, initialmodelstate, and the<option>value/label all consistently usegpt-5.4-nano, matching the updatedAgentInputenum intemplates/default/src/agent/translate/index.ts.Also applies to: 18-18, 123-123
apps/docs/src/api/vector-storage/route.ts (1)
13-13: No namespace alignment issue detected.Both
/seedand/searchendpoints use the sameVECTOR_NAMESPACE = 'sdk-explorer', andvectorAgentalso uses the identical namespace value. Seeded documents will be accessible to search operations.apps/docs/src/web/content/cookbook/patterns/using-workspaces-to-reuse-repos-skills-and-agent-selection.mdx (1)
115-116: LGTM — workspace roster field is aligned.This
enabledAgentsexample matches the workspace API terminology used by the current Coder schema.apps/docs/src/web/content/services/coder.mdx (2)
57-57: LGTM — clear distinction between roster and routing.The
enabledAgents/defaultAgentwording is concise and matches the Coder API model.
185-185: LGTM — workspace example uses the current field.
enabledAgentsis supported byCoderCreateWorkspaceRequestSchemainpackages/core/src/services/coder/types.ts:339-356.apps/docs/src/web/content/cookbook/patterns/choosing-built-in-agents-for-a-coder-session.mdx (1)
4-10: LGTM —enabledAgentsmigration is consistent.The example payload, read-back output, and explanatory text now consistently use
enabledAgents, matchingCoderCreateSessionRequestSchemainpackages/core/src/services/coder/types.ts:471-521.Also applies to: 22-53, 79-104
apps/docs/src/run/model-arena.ts (1)
91-93: Remove the incorrect comparison to sibling scripts — the dual-marker pattern is consistent withqueue.tsandschedule.ts.The
---OUTPUT---markers at lines 91 and 93 match the same pattern used inqueue.ts(lines 91–93) andschedule.ts(lines 76–78), which also accumulate output in an array before printing. The original review incorrectly claimed thatchat.ts,streaming.ts, andsse-stream.tsuse a single-marker convention; these scripts actually use scatteredconsole.logcalls instead. The dual-marker pattern is intentional for scripts that buffer output and is consistent across at least three files in the codebase.apps/docs/src/run/handler-context.ts (1)
6-6: LGTM — updated docs and capability output are consistent.The
AGENTS.mdreference, stream-oriented storage/service list, and closing success delimiter all fit the standalone demo output format.Also applies to: 43-47, 67-67
apps/docs/src/run/agent-calls.ts (1)
14-61: LGTM — safer input handling and proper failure signaling.Using
unknownfor parsed input, running the agent insidestandaloneCtx.invoke, and settingprocess.exitCode = 1on failure are solid improvements for the demo runner.apps/docs/src/run/chat.ts (1)
34-76: LGTM — invoking with the active standalone context is the right pattern.Moving session/thread state, logging, model generation, and output emission inside
standaloneCtx.invokecorrectly ensuresgetAgentContext()resolves the per-run context.apps/docs/src/web/components/WebRTCDemo.tsx (2)
245-304: Previously flagged audio visualizer gating is resolved.The early-return guard now only checks for
streamandaudioTrackpresence, dropping theaudioTrack.enabledcheck. Mute/unmute toggles won't flatline the analyser anymore since disabled tracks emit silence through the analyser naturally.
471-508: Previously flaggedcopyLinkissues are resolved.
navigator.clipboard.writeTextrejections are caught (falling back tosetCopied(false)), the 1.5s timer is tracked viacopyTimeoutRefand cleared before re-scheduling, and the unmount effect cancels any pending timer. Good.apps/docs/src/web/test-outputs.ts (2)
122-130: Previously flagged double-marker on schedules is resolved.The entry now uses a single
---OUTPUT---fence, andDeleted schedule: sch_abc123xyzsits inside the body with the rest of the lifecycle output, matching the style used by the other fixtures.
93-94: LGTM!SSE-stream fixture rewording aligns with the route emitting buffered
chunkevents, and the Model Arena fixture's OpenAI id bump togpt-5.4-nanotracks the MODELS config inapps/docs/src/agent/model-arena/lib.ts.Also applies to: 137-137
apps/docs/src/web/components/AIGatewayDemo.tsx (1)
34-49: LGTM!Model id/label rename is consistent across
AVAILABLE_MODELSand the persisted default.gpt-5.4-nanois a real OpenAI model id (released March 17, 2026), so the defaults align with the backend changes.apps/docs/src/api/websocket/route.ts (1)
23-82: LGTM!Typing
heartbeatIntervalwithReturnType<typeof setInterval>is more portable thanTimer, the non-string guard onevent.datais a reasonable contract for the demo, and reusing a singletimestampfor both the echo body and thetimestampfield keeps the response internally consistent (and matches the client/run-script format inapps/docs/src/web/components/WebSocketDemo.tsxandapps/docs/src/run/websocket.ts). One stylistic note:event.data.trim()silently alters the user's input before echoing — fine for a demo, but worth noting if anyone expects the echo to be byte-for-byte.apps/docs/src/agent/model-arena/lib.ts (2)
19-46: LGTM!
JUDGE_PROMPT_SUFFIXES+repairJudgmentTextgive two recovery angles (extra instruction + JSON substring extraction) for model output that drifts from pure JSON, andgetJudgeModelas a factory defersrequireGatewayConfig()to call time so missing env vars don't crash module load.experimental_repairTextis async-compatible, so the async signature here is fine even though the body is synchronous.
83-113: LGTM!Retrying across
JUDGE_PROMPT_SUFFIXES, threadingabortSignalthroughgenerateObject, and rethrowinglastErrorafter exhausting suffixes is clean. Note: if the caller aborts,AbortErrors from every suffix will be caught and retried once before throwing — harmless here (each retry is a no-op under an aborted signal), but worth keeping in mind if suffix count grows.apps/docs/src/api/model-arena/route.ts (1)
38-150: LGTM — abort propagation is solid.
abortSignalis captured fromc.req.raw.signaland threaded throughgenerateStoryandjudgeStories; the heartbeat is torn down via aonce-listener on abort and again infinally;writeis a no-op after abort;controller.close()is guarded. The per-provider catch that returnsnull+ filters before judging cleanly avoids judging a partial set. Past concern about client aborts is addressed.Minor nit: the caught-error path emits
\Judge failed: ${message}`even when the failure originated before judging (e.g., an error thrown insidewrite('start', …)or the Promise.all block). Consider dropping theJudge failed:prefix or moving it closer to thejudgeStories` call so the surfaced message accurately reflects what failed.apps/docs/src/web/components/SchedulesDemo.tsx (1)
302-329: Mount reconciliation now resumes in-flight runs — LGTM.The previously flagged unconditional cleanup is gone: non-terminal persisted schedules resume polling, terminal-but-not-cleaned schedules get a best-effort DELETE, and already-cleaned state is left alone. Nice fix.
apps/docs/src/web/code-examples.ts (1)
278-328: Schedules example addresses prior placeholder-URL feedback — LGTM.Using
<YOUR_APP_URL>/api/hellowith an explanatory comment prevents readers from accidentally pointing deliveries at the docs host. Thetry/finallycleanup with.catch(() => undefined)is a sensible pattern for a copy-pasteable example.
- simplify `model-arena` stream and judge handling - make sandbox scripts fail on caught errors - use typed `schedule` 404 handling - make `model-arena` stop and parse states safer - improve WebRTC chat accessibility and payload display
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/docs/src/agent/model-arena/lib.ts (1)
19-33: Drop unnecessaryasynconrepairJudgmentText.There's no
awaitinside and the AI SDK'sexperimental_repairTextaccepts either sync or promise-returning callbacks, soasyncjust adds a wrapper Promise. Also, the localerror: unknownis slightly loose compared to the SDK'sJSONParseError | TypeValidationError, but since it's unused here, that's fine.♻️ Optional simplification
-async function repairJudgmentText({ - text, -}: { - text: string; - error: unknown; -}): Promise<string | null> { +function repairJudgmentText({ text }: { text: string; error: unknown }): string | null { const start = text.indexOf('{'); const end = text.lastIndexOf('}'); if (start === -1 || end === -1 || end <= start) { return null; } return text.slice(start, end + 1); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/docs/src/agent/model-arena/lib.ts` around lines 19 - 33, The function repairJudgmentText is unnecessarily marked async and returns a Promise wrapper; change it to a synchronous function so it returns string | null directly (remove async and the Promise return type) and simplify the parameter to { text: string } (drop the unused error: unknown), keeping the same logic; this makes it compatible with the AI SDK's experimental_repairText which accepts sync callbacks and avoids the extra Promise overhead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs/src/api/model-arena/route.ts`:
- Around line 128-140: The outer catch currently logs all errors as "Model Arena
stream failed" and writes "Judge failed: …", which treats user-initiated aborts
as errors; update the catch to detect cancellation (check abortSignal.aborted or
error.name === 'AbortError') and either skip or log at a lower level (e.g.,
debug/trace) when cancelled, while still calling write appropriately (or omit
writing an error for aborts); also change the written message prefix from "Judge
failed: ..." to a more neutral "Model Arena failed: ..." (update references in
this catch block around abortSignal, stopHeartbeat, controller.close, write and
the surrounding catch handler).
In `@apps/docs/src/web/content/reference/api/coder.mdx`:
- Around line 511-516: The docs expose an unsupported field "targetAgentSlug";
either remove it from the generated docs or wire it up in the API: update the
Zod schema CoderCreateAgentBuilderSessionRequestSchema to include
targetAgentSlug (matching type string and optional) and update the request
handling in sessions.ts (the code that validates/reads request payloads and any
downstream use of targetAgentId) to accept and resolve targetAgentSlug to the
corresponding agent ID, then regenerate the docs; alternatively remove the
targetAgentSlug entry from the generated docs so it matches the existing
schema/validation.
---
Nitpick comments:
In `@apps/docs/src/agent/model-arena/lib.ts`:
- Around line 19-33: The function repairJudgmentText is unnecessarily marked
async and returns a Promise wrapper; change it to a synchronous function so it
returns string | null directly (remove async and the Promise return type) and
simplify the parameter to { text: string } (drop the unused error: unknown),
keeping the same logic; this makes it compatible with the AI SDK's
experimental_repairText which accepts sync callbacks and avoids the extra
Promise overhead.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 48bb73cd-5bc7-493a-aad0-8e28ebc27a3a
📒 Files selected for processing (12)
apps/docs/scripts/generate-nav-data.tsapps/docs/src/agent/model-arena/lib.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/schedules/route.tsapps/docs/src/run/chat.tsapps/docs/src/run/handler-context.tsapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/WebSocketDemo.tsxapps/docs/src/web/components/docs/nav-data.tsapps/docs/src/web/content/frontend/authentication.mdxapps/docs/src/web/content/reference/api/coder.mdx
✅ Files skipped from review due to trivial changes (2)
- apps/docs/src/web/content/frontend/authentication.mdx
- apps/docs/src/web/components/WebSocketDemo.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/docs/scripts/generate-nav-data.ts
- apps/docs/src/run/handler-context.ts
- apps/docs/src/web/components/WebRTCDemo.tsx
- apps/docs/src/api/schedules/route.ts
- apps/docs/src/web/components/ModelArena.tsx
📜 Review details
⏰ 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). (1)
- GitHub Check: Agentuity Deployment
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome as code formatter with tabs (width 3), single quotes, semicolons, lineWidth 100, and trailingCommas es5
Files:
apps/docs/src/web/components/docs/nav-data.tsapps/docs/src/run/chat.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/agent/model-arena/lib.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript Strict mode with ESNext target and bundler moduleResolution
UseStructuredErrorfrom@agentuity/corefor error handling
Files:
apps/docs/src/web/components/docs/nav-data.tsapps/docs/src/run/chat.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/agent/model-arena/lib.ts
apps/docs/src/web/**/*.{ts,tsx,html,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
React frontend files should be organized in
src/web/directory with proper structure:index.htmlas main HTML file,frontend.tsxas React entry point,App.tsxas main React component,hooks/for custom hooks, andcomponents/for React components
Files:
apps/docs/src/web/components/docs/nav-data.ts
apps/docs/src/web/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Use the
useSandboxRunnercustom hook fromsrc/web/hooks/useSandboxRunner.tsfor React components that need to execute sandbox scriptsStyle React components using Tailwind CSS
Files:
apps/docs/src/web/components/docs/nav-data.ts
apps/docs/src/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Use React 19 features and all modern React patterns including hooks, functional components, and TypeScript
Support hot module reloading (HMR) in dev mode using
import.meta.hot
Files:
apps/docs/src/web/components/docs/nav-data.ts
apps/docs/src/run/**/*.ts
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Standalone demo scripts should be placed in
src/run/directory following the naming convention of{scriptname}.tsScripts should use the local CLI directly:
bun ../../packages/cli/bin/cli.tswhen invoking CLI commands
Files:
apps/docs/src/run/chat.ts
apps/docs/src/api/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
API routes should be organized in
src/api/directory with subdirectories for each endpoint type (hello, chat, streaming, sse-stream, sandbox, etc.)
Files:
apps/docs/src/api/model-arena/route.ts
apps/docs/src/agent/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Agent implementations should be organized in
src/agent/directory with subdirectories for each agent type (hello, chat, context, kv, vector, objectstore, model-arena, etc.)
Files:
apps/docs/src/agent/model-arena/lib.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:37.864Z
Learning: Build the application using `bun run build` command
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:37.864Z
Learning: Start development server using `bun run dev` command
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:37.864Z
Learning: Run TypeScript type checking with `bun run typecheck` command
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:37.864Z
Learning: Deploy the application to Agentuity cloud using `bun run deploy` command
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:37.864Z
Learning: When adding a new demo script: create it in `src/run/newscript.ts`, run `bun run generate:scripts` to regenerate script metadata, rebuild the sandbox snapshot, and add demo config to the `DEMOS` array in `src/web/App.tsx`
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:37.864Z
Learning: Agent implementations should demonstrate SDK patterns including multiple agent implementations, API routes (REST, streaming, SSE, WebSocket), cloud sandbox execution, and AI SDK integration with multiple providers (OpenAI, Anthropic, Google, Groq)
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:50.252Z
Learning: HTTP routes for agents must be located in `src/api/` directory, not in agent folders
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:50.252Z
Learning: Subagents must be organized one level deep only (e.g., team/members/, not team/members/subagent/)
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:50.252Z
Learning: Supporting modules (lib.ts, types.ts, prompts.ts) are optional files that help organize agent code
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:50.252Z
Learning: Sample data files (sample-data.json, sample-products.json) should be placed in the agent folder for reference and testing
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:39:50.252Z
Learning: Context documents for LLM (context.txt, agentuity-context.txt) should be placed in the agent folder
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:40:02.221Z
Learning: Each API folder name becomes the route name (e.g., status/ → /api/status) and APIs run at /api/{folderName} by default
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:40:07.899Z
Learning: When updating a script, run 'bun run generate:scripts' and rebuild the snapshot to update script metadata
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T19:40:07.899Z
Learning: Scripts should be self-contained demonstrations of SDK features
📚 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:
apps/docs/src/web/components/docs/nav-data.tsapps/docs/src/run/chat.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/agent/model-arena/lib.ts
📚 Learning: 2025-12-19T14:19:33.765Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 259
File: packages/cli/src/cmd/build/vite/registry-generator.ts:306-312
Timestamp: 2025-12-19T14:19:33.765Z
Learning: Route files under src/api should use the .ts extension only (no .tsx) and regex patterns for such paths should anchor to \.ts$ (e.g., /\/.ts$/). Agent files may support both .ts and .tsx, but route files in the Agentuity SDK codebase are restricted to .ts. This guideline applies to all similar route files under src/api across the repository.
Applied to files:
apps/docs/src/api/model-arena/route.ts
📚 Learning: 2026-02-25T22:13:01.823Z
Learnt from: Huijiro
Repo: agentuity/sdk PR: 1063
File: apps/testing/vite-rsc-app/agentuity/src/api/index.ts:26-26
Timestamp: 2026-02-25T22:13:01.823Z
Learning: Agentuity SDK requires default exports for API route files (e.g., src/api/**/index.ts and src/api/**/route.ts) because the CLI's generateRouteRegistry relies on default exports to discover routes. Using named exports will skip route generation and lead to runtime 500 errors. This overrides typical guidance about named exports in index.ts files; ensure a default export is present in all relevant API route files under src/api/**/.
Applied to files:
apps/docs/src/api/model-arena/route.ts
🔇 Additional comments (2)
apps/docs/src/agent/model-arena/lib.ts (1)
36-36:gpt-5.4-nanomodel id is valid and supported. This model was released by OpenAI on March 17, 2026, and is fully supported by@ai-sdk/openaiv2.0.88 (the version in use in apps/docs). No runtime 404 error will occur.apps/docs/src/run/chat.ts (1)
37-38: No changes required; code is correct.
ctx.session.stateis the documented, intended API for session-scoped request-local state. TheSessioninterface definesstate: Map<string, unknown>, initialized withnew Map()in the runtime constructor. Bothctx.stateandctx.session.stateare valid context properties serving distinct purposes:
ctx.state: Temporary calculations within handler executionctx.session.state: Request-scoped data needed in session lifecycle listenersThis pattern is used throughout the codebase (tests, integration suites, examples, and documentation) and requires no correction.
| { | ||
| "name": "targetAgentSlug", | ||
| "type": "string", | ||
| "description": "Target custom-agent slug for edit launches", | ||
| "required": false | ||
| } |
There was a problem hiding this comment.
Remove or wire up targetAgentSlug before documenting it.
The generated docs list targetAgentSlug, but CoderCreateAgentBuilderSessionRequestSchema in packages/core/src/services/coder/types.ts:535-574 only accepts targetAgentId; packages/core/src/services/coder/sessions.ts:159-169 validates requests with that schema. Clients following this reference may send a field the SDK/API schema does not accept.
🛠️ Suggested generated-doc output if slug launches are not supported yet
- },
- {
- "name": "targetAgentSlug",
- "type": "string",
- "description": "Target custom-agent slug for edit launches",
- "required": false
}Alternatively, add targetAgentSlug to the source Zod schema and endpoint handling, then regenerate this file.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/src/web/content/reference/api/coder.mdx` around lines 511 - 516,
The docs expose an unsupported field "targetAgentSlug"; either remove it from
the generated docs or wire it up in the API: update the Zod schema
CoderCreateAgentBuilderSessionRequestSchema to include targetAgentSlug (matching
type string and optional) and update the request handling in sessions.ts (the
code that validates/reads request payloads and any downstream use of
targetAgentId) to accept and resolve targetAgentSlug to the corresponding agent
ID, then regenerate the docs; alternatively remove the targetAgentSlug entry
from the generated docs so it matches the existing schema/validation.
…lorer-realtime-demos # Conflicts: # bun.lock
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs/src/api/schedules/route.ts`:
- Around line 25-27: The module-level Map createAttemptsByUser used with
CREATE_RATE_LIMIT_WINDOW_MS and MAX_CREATES_PER_WINDOW implements a per-process
in-memory rate limiter that is bypassable in multi-worker deployments and can
grow unbounded; replace it with a shared store (e.g., Redis or platform KV) to
count and prune attempts atomically (or add TTL-backed keys) and remove the
per-process Map usage, or if keeping in-memory, document the single-instance
assumption and implement periodic eviction of stale user keys and size caps for
createAttemptsByUser to prevent unbounded growth.
- Around line 202-245: Add the cookieAuth middleware to the GET '/:id' and
DELETE '/:id' routes and enforce ownership: require authentication via
cookieAuth for both handlers, then after loading the schedule via
readScheduleState (or c.var.schedule.read), compare the schedule's
creator/userId field to the authenticated user's id from the cookie/session
(from c.req or c.var.session) and return 403 if they differ; keep the existing
isMissingScheduleError handling and error logging around readScheduleState and
c.var.schedule.delete.
In `@apps/docs/src/web/components/SchedulesDemo.tsx`:
- Around line 302-309: In the useEffect mount handler, detect when there is no
persistedScheduleId (demoState.schedule?.id is falsy) and the demoState is not
idle (e.g., demoState.status !== 'idle' or demoState.error is set) and reset the
UI by calling setDemoState(INITIAL_STATE). Update the existing block in
SchedulesDemo.tsx (the useEffect referencing demoState, setDemoState, and
INITIAL_STATE) to clear any stale non-idle/no-schedule transient states such as
'creating' or error states so the demo isn't left stuck without a start/reset
action.
- Around line 453-471: When isCreating is true the visual label is hidden and
the loading span is empty causing the button to lose its accessible name; in the
SchedulesDemo component update the Button (the element using
onClick={handleStart}, disabled={isBusy || !demoState.cleanedUp}) so that when
isCreating is true it still exposes an accessible label (e.g., add aria-label or
include a visually-hidden text node inside the loading span describing the
action like "Creating schedule" or "Running schedule"), ensuring screen readers
receive a meaningful name even while the visual label is invisible.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: abda5275-f239-40cc-9acd-6cd90b8a45c2
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (35)
apps/docs/src/agent/model-arena/lib.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/schedules/route.tsapps/docs/src/lib/ai-gateway.tsapps/docs/src/web/components/AIGatewayDemo.tsxapps/docs/src/web/components/AgentCallsDemo.tsxapps/docs/src/web/components/ChatDemo.tsxapps/docs/src/web/components/DatabaseDemo.tsxapps/docs/src/web/components/HandlerContextDemo.tsxapps/docs/src/web/components/HelloDemo.tsxapps/docs/src/web/components/JsonDisplay.tsxapps/docs/src/web/components/KVExplorer.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/QueueDemo.tsxapps/docs/src/web/components/SSEStreamDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsxapps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/TerminalOutput.tsxapps/docs/src/web/components/VectorSearch.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/demo-view.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/web/components/docs/cards.tsxapps/docs/src/web/components/docs/cli-command.tsxapps/docs/src/web/components/docs/copy-migration-prompt.tsxapps/docs/src/web/components/docs/mdx-components.tsxapps/docs/src/web/components/docs/steps.tsxapps/docs/src/web/components/docs/toc.tsxapps/docs/src/web/components/ui/alert.tsxapps/docs/src/web/components/ui/button.tsxapps/docs/src/web/content/get-started/what-is-agentuity.mdxapps/docs/src/web/content/reference/gravity-network.mdxapps/docs/src/web/demo-config.tsxapps/docs/src/web/routes/__root.tsxapps/docs/src/web/routes/index.tsx
✅ Files skipped from review due to trivial changes (23)
- apps/docs/src/web/content/get-started/what-is-agentuity.mdx
- apps/docs/src/web/components/docs/toc.tsx
- apps/docs/src/web/components/ChatDemo.tsx
- apps/docs/src/web/components/AgentCallsDemo.tsx
- apps/docs/src/web/components/JsonDisplay.tsx
- apps/docs/src/web/components/HelloDemo.tsx
- apps/docs/src/web/components/docs/copy-migration-prompt.tsx
- apps/docs/src/web/components/KVExplorer.tsx
- apps/docs/src/web/components/HandlerContextDemo.tsx
- apps/docs/src/web/content/reference/gravity-network.mdx
- apps/docs/src/web/components/ui/button.tsx
- apps/docs/src/web/routes/index.tsx
- apps/docs/src/web/components/VectorSearch.tsx
- apps/docs/src/web/components/QueueDemo.tsx
- apps/docs/src/web/components/DatabaseDemo.tsx
- apps/docs/src/web/components/docs/mdx-components.tsx
- apps/docs/src/web/components/docs/steps.tsx
- apps/docs/src/web/components/docs/cards.tsx
- apps/docs/src/web/components/demo-view.tsx
- apps/docs/src/web/routes/__root.tsx
- apps/docs/src/web/components/TerminalOutput.tsx
- apps/docs/src/web/components/ui/alert.tsx
- apps/docs/src/web/components/docs/cli-command.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/docs/src/web/components/SSEStreamDemo.tsx
- apps/docs/src/lib/ai-gateway.ts
- apps/docs/src/web/components/AIGatewayDemo.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome as code formatter with tabs (width 3), single quotes, semicolons, lineWidth 100, and trailingCommas es5
Files:
apps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/agent/model-arena/lib.tsapps/docs/src/web/components/ModelArena.tsxapps/docs/src/api/model-arena/route.tsapps/docs/src/web/demo-config.tsxapps/docs/src/api/schedules/route.tsapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript Strict mode with ESNext target and bundler moduleResolution
UseStructuredErrorfrom@agentuity/corefor error handling
Files:
apps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/agent/model-arena/lib.tsapps/docs/src/web/components/ModelArena.tsxapps/docs/src/api/model-arena/route.tsapps/docs/src/web/demo-config.tsxapps/docs/src/api/schedules/route.tsapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
apps/docs/src/web/**/*.tsx
📄 CodeRabbit inference engine (apps/docs/src/web/AGENTS.md)
apps/docs/src/web/**/*.tsx: Wrap your app with AgentuityProvider for React hooks (useAgent, useAPI, useAgentWebsocket, useAgentEventStream) to work correctly
Use useAgent hook for one-off agent calls and useAgentWebsocket for bidirectional real-time communication
Use useAgentEventStream for server-to-client streaming operations in React components
Place reusable components in separate files rather than inline
Handle loading and error states in UI when using Agentuity hooks
Use TypeScript for type safety in React components
For static assets referenced from JS/TSX, useimport url from './path.svg'instead of string literals like/public/foo.svgThe
src/web/hooks/useSandboxRunner.tshook should be used to handle sandbox execution in React componentsReact components can use all modern React features and TypeScript without external Babel or bundler configuration
Use Tailwind CSS for styling in React frontend components
Files:
apps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/demo-config.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
apps/docs/src/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
React frontend components and utilities must be organized in the
src/web/directory with proper subdirectory structure (hooks/, components/, etc.)The Agentuity build system automatically bundles
frontend.tsxand compiles TypeScript/TSX - no external bundler configuration is neededUse
import.meta.hotfor implementing hot module reloading in development mode within React components
Files:
apps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/demo-config.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
apps/docs/src/web/components/**/*.tsx
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
The
src/web/components/TerminalOutput.tsxcomponent should be used to display streaming output from sandbox executions
Files:
apps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
apps/docs/src/agent/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
Agent implementations must be organized in the
src/agent/directory with subdirectories for each agent type (hello, chat, context, kv, vector, objectstore, model-arena, etc.)
Files:
apps/docs/src/agent/model-arena/lib.ts
apps/docs/src/agent/**/*.ts
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
AI SDK integration should support multiple LLM providers (OpenAI, Anthropic, Google, Groq)
Files:
apps/docs/src/agent/model-arena/lib.ts
apps/docs/src/api/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/docs/AGENTS.md)
HTTP routes must be organized in the
src/api/directory with subdirectories for each endpoint type (hello, chat, streaming, sse-stream, sandbox, etc.)API routes should implement SSE (Server-Sent Events) for streaming responses from sandbox executions
Use Hono framework for defining HTTP routes and API endpoints
Files:
apps/docs/src/api/model-arena/route.tsapps/docs/src/api/schedules/route.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:26:30.480Z
Learning: The SDK Explorer app demonstrates multiple agent implementations that serve as reference implementations for SDK patterns
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:26:30.480Z
Learning: The SDK Explorer serves as live documentation with working demos, a reference implementation for SDK patterns, a testing ground for new features, and a cloud sandbox execution environment
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:26:30.480Z
Learning: Use Bun as the package manager and task runner for this project (build, dev, typecheck, deploy commands)
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:26:41.738Z
Learning: HTTP routes for agents must be placed in src/api/ directory, not in agent folders
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:27:08.106Z
Learning: Each API folder name becomes the route name (e.g., `status/` → `/api/status`), mounting at `/api/{folderName}` by default
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:27:16.719Z
Learning: When updating a script, regenerate script metadata by running 'bun run generate:scripts' and rebuild the sandbox snapshot
Learnt from: CR
Repo: agentuity/sdk
Timestamp: 2026-04-21T21:27:16.719Z
Learning: When adding a new script, update src/api/sandbox/scripts.ts with the new script name and default input, and add demo configuration to src/web/demo-config.tsx with category, title, description, and sandbox settings
📚 Learning: 2026-01-09T16:26:51.893Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 523
File: templates/_base/src/web/frontend.tsx:13-35
Timestamp: 2026-01-09T16:26:51.893Z
Learning: In web frontend code, prefer using the built-in Error class for runtime errors. Do not throw or re-export StructuredError from agentuity/core in web app code. Replace instances of StructuredError with new Error or custom error types that extend Error; ensure error handling logic remains intact and that error messages are descriptive. This guideline applies to all web UI TypeScript/TSX files that run in the browser and import StructuredError from agentuity/core.
Applied to files:
apps/docs/src/web/components/StreamingDemo.tsxapps/docs/src/web/components/docs/app-sidebar.tsxapps/docs/src/web/components/ModelArena.tsxapps/docs/src/web/demo-config.tsxapps/docs/src/web/components/WebRTCDemo.tsxapps/docs/src/web/components/SchedulesDemo.tsx
📚 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:
apps/docs/src/agent/model-arena/lib.tsapps/docs/src/api/model-arena/route.tsapps/docs/src/api/schedules/route.ts
📚 Learning: 2025-12-19T14:19:33.765Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 259
File: packages/cli/src/cmd/build/vite/registry-generator.ts:306-312
Timestamp: 2025-12-19T14:19:33.765Z
Learning: Route files under src/api should use the .ts extension only (no .tsx) and regex patterns for such paths should anchor to \.ts$ (e.g., /\/.ts$/). Agent files may support both .ts and .tsx, but route files in the Agentuity SDK codebase are restricted to .ts. This guideline applies to all similar route files under src/api across the repository.
Applied to files:
apps/docs/src/api/model-arena/route.tsapps/docs/src/api/schedules/route.ts
📚 Learning: 2026-02-25T22:13:01.823Z
Learnt from: Huijiro
Repo: agentuity/sdk PR: 1063
File: apps/testing/vite-rsc-app/agentuity/src/api/index.ts:26-26
Timestamp: 2026-02-25T22:13:01.823Z
Learning: Agentuity SDK requires default exports for API route files (e.g., src/api/**/index.ts and src/api/**/route.ts) because the CLI's generateRouteRegistry relies on default exports to discover routes. Using named exports will skip route generation and lead to runtime 500 errors. This overrides typical guidance about named exports in index.ts files; ensure a default export is present in all relevant API route files under src/api/**/.
Applied to files:
apps/docs/src/api/model-arena/route.tsapps/docs/src/api/schedules/route.ts
🔇 Additional comments (1)
apps/docs/src/web/components/StreamingDemo.tsx (1)
30-36: The model IDgpt-5.4-nanois valid. It is a supported OpenAI model available via the Chat Completions API, so no changes are needed. The repeated usage across StreamingDemo, AIGatewayDemo, SSEStreamDemo, and related files is correct.
| const CREATE_RATE_LIMIT_WINDOW_MS = 60_000; | ||
| const MAX_CREATES_PER_WINDOW = 1; | ||
| const createAttemptsByUser = new Map<string, number[]>(); |
There was a problem hiding this comment.
In-memory rate limiter is per-instance and grows unbounded.
createAttemptsByUser is a module-level Map that (a) is bypassable if the docs app runs in more than one process/worker (each instance keeps its own counter, so concurrent requests routed to different replicas each get 1/min), and (b) never evicts keys for users that stop calling — the per-user array is pruned on each call, but the map entry itself persists for the process lifetime.
For a demo this is probably fine, but worth either documenting the single-instance assumption or moving to a shared store (KV/Redis) + periodic key eviction if this endpoint is ever exposed in a load-balanced deployment.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/src/api/schedules/route.ts` around lines 25 - 27, The module-level
Map createAttemptsByUser used with CREATE_RATE_LIMIT_WINDOW_MS and
MAX_CREATES_PER_WINDOW implements a per-process in-memory rate limiter that is
bypassable in multi-worker deployments and can grow unbounded; replace it with a
shared store (e.g., Redis or platform KV) to count and prune attempts atomically
(or add TTL-backed keys) and remove the per-process Map usage, or if keeping
in-memory, document the single-instance assumption and implement periodic
eviction of stale user keys and size caps for createAttemptsByUser to prevent
unbounded growth.
| .get('/:id', async (c) => { | ||
| try { | ||
| const scheduleId = c.req.param('id'); | ||
| const destinationUrl = buildDestinationUrl(c.req.url) ?? HELLO_DESTINATION_PATH; | ||
| const state = await readScheduleState(c.var.schedule, scheduleId); | ||
|
|
||
| return c.json({ | ||
| success: true, | ||
| data: { | ||
| ...state, | ||
| destinationUrl, | ||
| }, | ||
| }); | ||
| } catch (error) { | ||
| if (isMissingScheduleError(error)) { | ||
| return c.json({ success: false, message: 'Schedule not found.' }, 404); | ||
| } | ||
|
|
||
| const message = getErrorMessage(error); | ||
| c.var.logger?.error('Schedules demo get failed', { | ||
| scheduleId: c.req.param('id'), | ||
| message, | ||
| }); | ||
| return c.json({ success: false, message }, 500); | ||
| } | ||
| }) | ||
| .delete('/:id', async (c) => { | ||
| try { | ||
| const scheduleId = c.req.param('id'); | ||
| await c.var.schedule.delete(scheduleId); | ||
| return c.json({ success: true, message: 'Schedule deleted.' }); | ||
| } catch (error) { | ||
| if (isMissingScheduleError(error)) { | ||
| return c.json({ success: true, message: 'Schedule already deleted.' }); | ||
| } | ||
|
|
||
| const message = getErrorMessage(error); | ||
| c.var.logger?.error('Schedules demo delete failed', { | ||
| scheduleId: c.req.param('id'), | ||
| message, | ||
| }); | ||
| return c.json({ success: false, message }, 500); | ||
| } | ||
| }); |
There was a problem hiding this comment.
GET /:id and DELETE /:id are unauthenticated and not scoped to the creator.
Only POST / is behind cookieAuth; the read and delete handlers have no middleware and don't verify that the caller owns the schedule. Any anonymous client that obtains (or guesses, if IDs aren't sufficiently opaque) a schedule ID can:
- Enumerate delivery history for someone else's Explorer schedule via
GET /:id. - Delete another user's schedule via
DELETE /:id.
For a demo app this may be acceptable, but it's inconsistent with the POST path and with the sessions/process-docs patterns referenced elsewhere in this repo. At minimum, apply cookieAuth on both routes; ideally, record the creating userId on the schedule (e.g., via name/description or a side index) and reject requests where the cookie's user doesn't match.
🛡️ Minimum auth gate (add cookieAuth to both routes)
- .get('/:id', async (c) => {
+ .get('/:id', cookieAuth, async (c) => {
try {
const scheduleId = c.req.param('id');
...
- .delete('/:id', async (c) => {
+ .delete('/:id', cookieAuth, async (c) => {
try {
const scheduleId = c.req.param('id');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/src/api/schedules/route.ts` around lines 202 - 245, Add the
cookieAuth middleware to the GET '/:id' and DELETE '/:id' routes and enforce
ownership: require authentication via cookieAuth for both handlers, then after
loading the schedule via readScheduleState (or c.var.schedule.read), compare the
schedule's creator/userId field to the authenticated user's id from the
cookie/session (from c.req or c.var.session) and return 403 if they differ; keep
the existing isMissingScheduleError handling and error logging around
readScheduleState and c.var.schedule.delete.
| // biome-ignore lint/correctness/useExhaustiveDependencies: only run once per mount | ||
| useEffect(() => { | ||
| const persistedScheduleId = demoState.schedule?.id; | ||
| if (!persistedScheduleId) { | ||
| if (demoState.status === 'error' || demoState.error) { | ||
| setDemoState(INITIAL_STATE); | ||
| } | ||
| return; |
There was a problem hiding this comment.
Reset stale no-schedule transient states on mount.
If the page remounts after Line 333 persists status: 'creating' but before a schedule id is stored, this effect leaves the demo stuck busy with no enabled reset/start action. Reset any no-schedule non-idle state.
Proposed fix
const persistedScheduleId = demoState.schedule?.id;
if (!persistedScheduleId) {
- if (demoState.status === 'error' || demoState.error) {
+ if (demoState.status !== 'idle' || demoState.error) {
setDemoState(INITIAL_STATE);
}
return;
}Also applies to: 331-334
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/src/web/components/SchedulesDemo.tsx` around lines 302 - 309, In
the useEffect mount handler, detect when there is no persistedScheduleId
(demoState.schedule?.id is falsy) and the demoState is not idle (e.g.,
demoState.status !== 'idle' or demoState.error is set) and reset the UI by
calling setDemoState(INITIAL_STATE). Update the existing block in
SchedulesDemo.tsx (the useEffect referencing demoState, setDemoState, and
INITIAL_STATE) to clear any stale non-idle/no-schedule transient states such as
'creating' or error states so the demo isn't left stuck without a start/reset
action.
| <Button | ||
| onClick={handleStart} | ||
| disabled={isBusy || !demoState.cleanedUp} | ||
| variant="outline" | ||
| size="sm" | ||
| className="min-h-11 sm:min-h-9" | ||
| > | ||
| <span className="relative"> | ||
| <span className={isCreating ? 'invisible' : ''}> | ||
| {demoState.schedule ? 'Run again' : 'Create schedule'} | ||
| </span> | ||
| {isCreating && ( | ||
| <span | ||
| className="absolute inset-0 flex items-center justify-center" | ||
| data-loading="true" | ||
| /> | ||
| )} | ||
| </span> | ||
| </Button> |
There was a problem hiding this comment.
Keep the loading button accessible.
When isCreating is true, the only text label is hidden and the replacement loading span is empty, so the disabled button can become unlabeled for assistive tech.
Proposed fix
<Button
onClick={handleStart}
disabled={isBusy || !demoState.cleanedUp}
+ aria-label={isCreating ? 'Creating schedule' : undefined}
variant="outline"
size="sm"
className="min-h-11 sm:min-h-9"
>
@@
{isCreating && (
<span
+ aria-hidden="true"
className="absolute inset-0 flex items-center justify-center"
data-loading="true"
/>
)}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Button | |
| onClick={handleStart} | |
| disabled={isBusy || !demoState.cleanedUp} | |
| variant="outline" | |
| size="sm" | |
| className="min-h-11 sm:min-h-9" | |
| > | |
| <span className="relative"> | |
| <span className={isCreating ? 'invisible' : ''}> | |
| {demoState.schedule ? 'Run again' : 'Create schedule'} | |
| </span> | |
| {isCreating && ( | |
| <span | |
| className="absolute inset-0 flex items-center justify-center" | |
| data-loading="true" | |
| /> | |
| )} | |
| </span> | |
| </Button> | |
| <Button | |
| onClick={handleStart} | |
| disabled={isBusy || !demoState.cleanedUp} | |
| aria-label={isCreating ? 'Creating schedule' : undefined} | |
| variant="outline" | |
| size="sm" | |
| className="min-h-11 sm:min-h-9" | |
| > | |
| <span className="relative"> | |
| <span className={isCreating ? 'invisible' : ''}> | |
| {demoState.schedule ? 'Run again' : 'Create schedule'} | |
| </span> | |
| {isCreating && ( | |
| <span | |
| aria-hidden="true" | |
| className="absolute inset-0 flex items-center justify-center" | |
| data-loading="true" | |
| /> | |
| )} | |
| </span> | |
| </Button> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs/src/web/components/SchedulesDemo.tsx` around lines 453 - 471, When
isCreating is true the visual label is hidden and the loading span is empty
causing the button to lose its accessible name; in the SchedulesDemo component
update the Button (the element using onClick={handleStart}, disabled={isBusy ||
!demoState.cleanedUp}) so that when isCreating is true it still exposes an
accessible label (e.g., add aria-label or include a visually-hidden text node
inside the loading span describing the action like "Creating schedule" or
"Running schedule"), ensuring screen readers receive a meaningful name even
while the visual label is invisible.
Summary by CodeRabbit
New Features
Documentation
Removals