feat(console): custom function-call views, session export, markdown directory bodies#201
Conversation
…irectory bodies Render function calls in the chat transcript with namespace-specific views instead of raw JSON: - directory (skills/prompts/registry/download), engine (functions/triggers/ workers + register), web (fetch), worker (list/op). FunctionCallMessage now dispatches preview/terminal/id-label across all families via ??-chains; unknown function ids fall back to the default request/response JSON panes. - MarkdownPane renders directory bodies (skill .md, prompt body, worker README) as real markdown via the shared <Markdown> renderer, not raw monospace. - Add ExportSessionButton + export-session lib to download a conversation. - Each view family ships parsers + parser unit tests + Examples-page fixtures. - Sync console/Cargo.lock to console v0.1.5. Verified: tsc clean, 408/408 console-web tests pass.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
skill-check — worker0 verified, 13 skipped (no docs/).
Note 17 stale rendered artifact(s) detected on main, unrelated to this PR. This PR is fine; the drift was already there. A maintainer should open a chore PR to re-render these.
|
|
Warning Review limit reached
More reviews will be available in 23 minutes and 32 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThis PR implements a multi-family function-call renderer architecture for the console chat, introducing support for directory, engine, web, and worker tool families alongside the existing sandbox family. Each family defines Zod-based request/response parsers, React view components, and a dispatcher interface. The PR refactors ChangesMulti-family function-call rendering with chat export
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
PR #195 removed the per-conversation `autoAccept` boolean (permission mode is now backend-owned: manual/auto/full). The session exporter still referenced `conversation.autoAccept`, which broke the CI `tsc -b` build (TS2339/TS2353). Local `tsc --noEmit` did not surface it; `tsc -b` (the SPA build) does. Remove the stale `- Auto-accept:` header line and its test fixture/assertion.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
console/web/src/components/chat/engine/WorkersListView.tsx (2)
154-157: ⚡ Quick winExtract
shortenIdto a shared utility.This function is duplicated in
WorkersRegisterView.tsx(lines 92-95). Consider moving it toconsole/web/src/components/chat/engine/shared.tsxto eliminate duplication.♻️ Proposed extraction to shared.tsx
In
console/web/src/components/chat/engine/shared.tsx:+export function shortenId(id: string): string { + if (id.length <= 14) return id + return `${id.slice(0, 8)}…${id.slice(-4)}` +}Then in both
WorkersListView.tsxandWorkersRegisterView.tsx:-function shortenId(id: string): string { - if (id.length <= 14) return id - return `${id.slice(0, 8)}…${id.slice(-4)}` -}And update the imports:
-import { FilterChip, ListHeader } from './shared' +import { FilterChip, ListHeader, shortenId } from './shared'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/components/chat/engine/WorkersListView.tsx` around lines 154 - 157, The shortenId function is duplicated; extract it into a shared module (shared.tsx) as an exported utility (export function shortenId(id: string): string { ... }), remove the duplicate implementation from WorkersListView and WorkersRegisterView, and import shortenId from the shared module in both components; ensure the function signature and behavior remain unchanged and update any imports/usages to reference shortenId instead of the inline definitions.
159-166: ⚡ Quick win
Date.now()inside render path produces non-deterministic output.The
formatConnectedForhelper callsDate.now()on every invocation. BecauseWorkerRowis re-rendered whenever the parent updates, this produces a fresh timestamp each time, which can cause:
- Inconsistent duration strings across workers in the same list
- Stale "up" durations if the component doesn't re-render frequently
Consider accepting a stable
nowparameter (computed once at the top ofWorkersListView) or use a ref/timer to periodically update the display.♻️ Proposed refactor to accept a stable timestamp
-function formatConnectedFor(connectedAtMs: number): string { - const now = Date.now() +function formatConnectedFor(connectedAtMs: number, now: number): string { const ms = Math.max(0, now - connectedAtMs) if (ms < 60_000) return `${Math.floor(ms / 1000)}s up` if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m up` if (ms < 86_400_000) return `${Math.floor(ms / 3_600_000)}h up` return `${Math.floor(ms / 86_400_000)}d up` }Then compute
nowonce inWorkersListView:export function WorkersListView({ input, output, running }: WorkersListViewProps) { + const now = Date.now() const req = safeParseRequest(workersListRequestSchema, input) // ... <ul className="divide-y divide-rule-2"> {resp.workers.map((w) => ( - <WorkerRow key={w.id} worker={w} /> + <WorkerRow key={w.id} worker={w} now={now} /> ))} </ul>And update
WorkerRowsignature:-function WorkerRow({ worker }: { worker: WorkerSummary }) { +function WorkerRow({ worker, now }: { worker: WorkerSummary; now: number }) { // ... - <span>· {formatConnectedFor(worker.connected_at_ms)}</span> + <span>· {formatConnectedFor(worker.connected_at_ms, now)}</span>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@console/web/src/components/chat/engine/WorkersListView.tsx` around lines 159 - 166, formatConnectedFor currently calls Date.now() on each render causing non-deterministic durations; change formatConnectedFor to accept a stable now parameter, compute const now = Date.now() once at the top of WorkersListView (or maintain via a single interval/ref if live updates are needed) and pass that now into WorkerRow and into formatConnectedFor so all rows use the same reference time; update WorkerRow signature/props to accept the now value and replace internal Date.now() usage with the passed now.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@console/web/docs/custom-function-components.md`:
- Around line 45-46: The guidance claiming "Only `sandbox` is wired today" is
stale—update the prose and the example snippet to reflect that
FunctionCallMessage.tsx dispatches across directory/engine/worker/web/sandbox
and that contributors should use the `customPreview` / `customTerminal` hooks
rather than sandbox-specific wiring; replace references to SandboxToolView and
SandboxFunctionIdLabel in the example with the generic custom preview/terminal
flow and show how to register or dispatch multiple families (or mention using
the small registry approach) so contributors copy the current multi-family
wiring rather than sandbox-only code.
- Around line 149-159: The markdown has fenced code blocks without language tags
(the directory listing blocks shown in the snippet and the similar block around
lines ~404-409); update those triple-backtick fences to include an appropriate
language tag (e.g., ```text or ```bash or ```typescript as fits the content) so
markdownlint MD040 passes; ensure both instances (the directory tree block
containing src/components/chat/myfeature/ and the other block at ~404-409) are
updated to include the chosen language tag.
In `@console/web/src/components/chat/engine/shared.tsx`:
- Around line 22-27: The header shows a misleading empty-state when count === 0
because label and pillVariant ignore a loading state; update the ListHeader
(where label and pillVariant are computed) to accept a loading boolean and, when
loading is true, avoid forcing `label` to `no ${noun} match` and avoid forcing
`pillVariant` to `'warn'` (choose the original `tone` or a neutral/default
variant for loading); change the existing expressions around `label` and
`pillVariant` to short-circuit on `loading` first, and update the calling list
views to pass `loading` from their running branches so the header renders a
loading affordance instead of the empty-state pill.
In `@console/web/src/lib/export-session.ts`:
- Line 107: Remove the stale access to Conversation.autoAccept in export logic:
locate the template string that includes "`- Auto-accept:
${conversation.autoAccept ? 'yes' : 'no'}`" in export-session.ts (e.g., inside
the function that builds the export text for a conversation) and delete that
line or replace it by reading the actual approval setting from the current
approval model if you need to preserve the info (e.g., fetch from the approval
settings object used elsewhere). Ensure no other references to
conversation.autoAccept remain so TypeScript compiles cleanly.
---
Nitpick comments:
In `@console/web/src/components/chat/engine/WorkersListView.tsx`:
- Around line 154-157: The shortenId function is duplicated; extract it into a
shared module (shared.tsx) as an exported utility (export function shortenId(id:
string): string { ... }), remove the duplicate implementation from
WorkersListView and WorkersRegisterView, and import shortenId from the shared
module in both components; ensure the function signature and behavior remain
unchanged and update any imports/usages to reference shortenId instead of the
inline definitions.
- Around line 159-166: formatConnectedFor currently calls Date.now() on each
render causing non-deterministic durations; change formatConnectedFor to accept
a stable now parameter, compute const now = Date.now() once at the top of
WorkersListView (or maintain via a single interval/ref if live updates are
needed) and pass that now into WorkerRow and into formatConnectedFor so all rows
use the same reference time; update WorkerRow signature/props to accept the now
value and replace internal Date.now() usage with the passed now.
🪄 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: 7d6dab6c-19a7-4504-b208-df3a2e13e83e
⛔ Files ignored due to path filters (1)
console/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (38)
console/web/docs/custom-function-components.mdconsole/web/src/components/chat/ChatView.tsxconsole/web/src/components/chat/ExportSessionButton.tsxconsole/web/src/components/chat/FunctionCallMessage.tsxconsole/web/src/components/chat/directory/DownloadView.tsxconsole/web/src/components/chat/directory/PromptsViews.tsxconsole/web/src/components/chat/directory/RegistryViews.tsxconsole/web/src/components/chat/directory/SkillsViews.tsxconsole/web/src/components/chat/directory/__tests__/parsers.test.tsconsole/web/src/components/chat/directory/index.tsxconsole/web/src/components/chat/directory/parsers.tsconsole/web/src/components/chat/directory/shared.tsxconsole/web/src/components/chat/engine/FunctionInfoView.tsxconsole/web/src/components/chat/engine/FunctionsListView.tsxconsole/web/src/components/chat/engine/RegisteredTriggersListView.tsxconsole/web/src/components/chat/engine/TriggersListView.tsxconsole/web/src/components/chat/engine/WorkerInfoView.tsxconsole/web/src/components/chat/engine/WorkersListView.tsxconsole/web/src/components/chat/engine/WorkersRegisterView.tsxconsole/web/src/components/chat/engine/__tests__/parsers.test.tsconsole/web/src/components/chat/engine/index.tsxconsole/web/src/components/chat/engine/parsers.tsconsole/web/src/components/chat/engine/shared.tsxconsole/web/src/components/chat/web/FetchView.tsxconsole/web/src/components/chat/web/__tests__/parsers.test.tsconsole/web/src/components/chat/web/index.tsxconsole/web/src/components/chat/web/parsers.tsconsole/web/src/components/chat/worker/WorkerListView.tsxconsole/web/src/components/chat/worker/WorkerOpView.tsxconsole/web/src/components/chat/worker/__tests__/parsers.test.tsconsole/web/src/components/chat/worker/index.tsxconsole/web/src/components/chat/worker/parsers.tsconsole/web/src/lib/export-session.test.tsconsole/web/src/lib/export-session.tsconsole/web/src/pages/Examples/sections/directory-fixtures.tsconsole/web/src/pages/Examples/sections/engine-fixtures.tsconsole/web/src/pages/Examples/sections/web-fixtures.tsconsole/web/src/pages/Examples/sections/worker-fixtures.ts
…ground Wire the directory/engine/web/worker fixtures into the spec-sheet playground. A new CustomFunctionViewsSection renders every fixture (defaultOpen so the custom terminal/preview pane shows), grouped per family with a count heading, plus a 'function views' TOC entry. The fixtures existed but weren't rendered anywhere — now each namespace renderer is visible in the gallery.
`pnpm dev:playground` runs the dev server with VITE_PLAYGROUND=1, which enables the examples + playground views (reachable at #/examples and #/playground). Matches how CI sets the flag; no new dependency.
Summary
Replaces the raw-JSON rendering of agent function calls in the chat transcript with namespace-specific custom views, plus session export and markdown rendering for directory bodies. All changes are scoped to
console/— no harness/runtime changes.Custom function-call views
FunctionCallMessagenow dispatches preview / terminal / id-label across registered renderer families via??-chains; unknown function ids fall back to the existing request/response JSON panes (no regression for unmatched tools). New families:skills(.mdbody rendered as markdown),prompts,registry,downloadfunctions,triggers,registered-triggers,workers(list/info) +workers::registerfetchEach family is self-contained:
parsers.ts(pure, schema-tolerant parsing) +index.tsx(the*ToolViewdispatcher +*FunctionIdLabel) + view components + shared primitives.Markdown rendering for directory bodies
MarkdownPane(used bydirectory::skills::get/index,prompts::get, registry README) now renders through the shared<Markdown>component (react-markdown + remark-gfm +@fn()pills) instead of a raw<pre><code>monospace stub.Session export
ExportSessionButton+export-sessionlib download a conversation transcript; wired intoChatView.Lock sync
console/Cargo.lock:consolecrate0.1.4 → 0.1.5(syncs the lock with the already-mergedchore(console): bump to v0.1.5).Test plan
tsc --noEmitcleanvitest run— 408/408 pass (24 files), including new parser unit tests for every view family (directory/engine/web/worker) andexport-sessionbiome checkon changed files — no errors/warnings (5 info-levelnoUselessFragmentssuggestions only)directory::skills::getrenders markdown and each family's tool call shows its custom preview/terminalNotes
console/web/docs/custom-function-components.mddescribes how to add a new view family.Summary by CodeRabbit
New Features
Documentation