Skip to content

feat(console): custom function-call views, session export, markdown directory bodies#201

Merged
andersonleal merged 4 commits into
mainfrom
feat/console-custom-function-views
May 29, 2026
Merged

feat(console): custom function-call views, session export, markdown directory bodies#201
andersonleal merged 4 commits into
mainfrom
feat/console-custom-function-views

Conversation

@andersonleal
Copy link
Copy Markdown
Collaborator

@andersonleal andersonleal commented May 29, 2026

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

FunctionCallMessage now 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:

  • directoryskills (.md body rendered as markdown), prompts, registry, download
  • enginefunctions, triggers, registered-triggers, workers (list/info) + workers::register
  • webfetch
  • worker — list / op

Each family is self-contained: parsers.ts (pure, schema-tolerant parsing) + index.tsx (the *ToolView dispatcher + *FunctionIdLabel) + view components + shared primitives.

Markdown rendering for directory bodies

MarkdownPane (used by directory::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-session lib download a conversation transcript; wired into ChatView.

Lock sync

console/Cargo.lock: console crate 0.1.4 → 0.1.5 (syncs the lock with the already-merged chore(console): bump to v0.1.5).

Test plan

  • tsc --noEmit clean
  • vitest run408/408 pass (24 files), including new parser unit tests for every view family (directory/engine/web/worker) and export-session
  • biome check on changed files — no errors/warnings (5 info-level noUselessFragments suggestions only)
  • Examples page fixtures added for directory/engine/web/worker so each view renders in the component gallery
  • Manual: reload console, confirm directory::skills::get renders markdown and each family's tool call shows its custom preview/terminal

Notes

  • Behavior is additive/presentational; unmatched function ids keep the prior JSON panes.
  • Docs: console/web/docs/custom-function-components.md describes how to add a new view family.

Summary by CodeRabbit

  • New Features

    • Download chat sessions as Markdown files with full conversation history
    • Enhanced UI rendering for directory operations (skills, prompts, registry workers)
    • Improved visualization for engine operations (functions, workers, triggers, registrations)
    • Better display for web fetch operations with response formatting and error details
    • Enhanced worker operation UIs (list, start, stop, add, remove, update, clear)
    • Clearer function-id labels and namespace identification across tool types
  • Documentation

    • Added guide for implementing custom function component renderers

Review Change Stack

…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.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment May 29, 2026 12:31pm

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2026

skill-check — worker

0 verified, 13 skipped (no docs/).

Layer Result
structure
vale
ai
render

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.

  • shell/README.md
  • shell/skill.md
  • shell/skills/chmod.md
  • shell/skills/exec.md
  • shell/skills/exec_bg.md
  • shell/skills/grep.md
  • shell/skills/kill.md
  • shell/skills/list.md
  • shell/skills/ls.md
  • shell/skills/mkdir.md
  • shell/skills/mv.md
  • shell/skills/read.md
  • …and 5 more (see the workflow logs)

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Warning

Review limit reached

@andersonleal, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 65827668-26cb-48bd-92e4-7eb00770c32d

📥 Commits

Reviewing files that changed from the base of the PR and between d2d14c1 and 7fc119d.

📒 Files selected for processing (5)
  • console/web/package.json
  • console/web/src/lib/export-session.test.ts
  • console/web/src/lib/export-session.ts
  • console/web/src/pages/Examples/index.tsx
  • console/web/src/pages/Examples/sections/custom-function-views.tsx
📝 Walkthrough

Walkthrough

This 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 FunctionCallMessage to route rendering through a generic FunctionIdLabel and tryRender pipeline, adds comprehensive UI views and tests for each family, provides chat session markdown export with an ExportSessionButton component, and includes extensive documentation and demo fixtures.

Changes

Multi-family function-call rendering with chat export

Layer / File(s) Summary
Architecture documentation and core dispatcher refactoring
console/web/docs/custom-function-components.md, console/web/src/components/chat/FunctionCallMessage.tsx
Documents the multi-family pattern and refactors the main message component from sandbox-specific to a generic dispatcher that routes via FunctionIdLabel and prioritized customPreview/customTerminal renderers.
Directory tool family (skills, prompts, registry)
console/web/src/components/chat/directory/parsers.ts, console/web/src/components/chat/directory/shared.tsx, console/web/src/components/chat/directory/{SkillsViews,PromptsViews,RegistryViews,DownloadView}.tsx, console/web/src/components/chat/directory/index.tsx, console/web/src/components/chat/directory/__tests__/parsers.test.ts, console/web/src/pages/Examples/sections/directory-fixtures.ts
Implements full directory family with schemas for skills/prompts/registry endpoints, views for list/get/index/download operations, shared UI helpers (KvChip, MarkdownPane, time/byte formatters), dispatcher routing, tests, and fixtures.
Engine tool family (functions, triggers, workers)
console/web/src/components/chat/engine/parsers.ts, console/web/src/components/chat/engine/shared.tsx, console/web/src/components/chat/engine/{FunctionsListView,FunctionInfoView,TriggersListView,RegisteredTriggersListView,WorkersListView,WorkerInfoView,WorkersRegisterView}.tsx, console/web/src/components/chat/engine/index.tsx, console/web/src/components/chat/engine/__tests__/parsers.test.ts, console/web/src/pages/Examples/sections/engine-fixtures.ts
Implements full engine family with schemas for functions/triggers/workers endpoints, views for list/info/register operations, shared list header and filter chip components, dispatcher routing, tests, and fixtures covering success/error/edge cases.
Web tool family (web::fetch)
console/web/src/components/chat/web/parsers.ts, console/web/src/components/chat/web/FetchView.tsx, console/web/src/components/chat/web/index.tsx, console/web/src/components/chat/web/__tests__/parsers.test.ts, console/web/src/pages/Examples/sections/web-fixtures.ts
Implements web family with schemas for fetch request/response/error shapes, views for running/success/error UI, error categorization and URI validation, dispatcher routing, tests, and fixtures.
Worker tool family (worker lifecycle operations)
console/web/src/components/chat/worker/parsers.ts, console/web/src/components/chat/worker/{WorkerListView,WorkerOpView}.tsx, console/web/src/components/chat/worker/index.tsx, console/web/src/components/chat/worker/__tests__/parsers.test.ts, console/web/src/pages/Examples/sections/worker-fixtures.ts
Implements worker family with schemas for lifecycle operations, views for list/start/stop/add/remove/update/clear UI with state transitions, dispatcher routing, tests, and fixtures.
Chat session markdown export and ChatView integration
console/web/src/lib/export-session.ts, console/web/src/lib/export-session.test.ts, console/web/src/components/chat/ExportSessionButton.tsx, console/web/src/components/chat/ChatView.tsx
Adds markdown export utilities for conversations, an ExportSessionButton component with success state feedback, ChatView wiring to announce exports, and comprehensive tests for message rendering and filename generation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • iii-hq/workers#151: Both PRs modify console/web/src/components/chat/FunctionCallMessage.tsx to refactor function-call rendering logic and dispatcher handling.
  • iii-hq/workers#141: Both PRs extend the existing console chat UI with new rendering capabilities by modifying FunctionCallMessage.tsx and ChatView.tsx.
  • iii-hq/workers#190: Both PRs modify console/web/src/components/chat/FunctionCallMessage.tsx to change how sandbox/tool call UI is rendered, with this PR building on the sandbox view patterns.

Suggested reviewers

  • sergiofilhowz

Poem

🐰 A dozen renderers dance in the dispatcher's light,
From directory to engine, each family claims its right,
With Zod schemas validating every parse,
And web::fetch soaring through digital space,
Sessions export to markdown, no more left behind!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/console-custom-function-views

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.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
console/web/src/components/chat/engine/WorkersListView.tsx (2)

154-157: ⚡ Quick win

Extract shortenId to a shared utility.

This function is duplicated in WorkersRegisterView.tsx (lines 92-95). Consider moving it to console/web/src/components/chat/engine/shared.tsx to 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.tsx and WorkersRegisterView.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 formatConnectedFor helper calls Date.now() on every invocation. Because WorkerRow is 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 now parameter (computed once at the top of WorkersListView) 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 now once in WorkersListView:

 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 WorkerRow signature:

-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

📥 Commits

Reviewing files that changed from the base of the PR and between 0c497ac and d2d14c1.

⛔ Files ignored due to path filters (1)
  • console/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (38)
  • console/web/docs/custom-function-components.md
  • console/web/src/components/chat/ChatView.tsx
  • console/web/src/components/chat/ExportSessionButton.tsx
  • console/web/src/components/chat/FunctionCallMessage.tsx
  • console/web/src/components/chat/directory/DownloadView.tsx
  • console/web/src/components/chat/directory/PromptsViews.tsx
  • console/web/src/components/chat/directory/RegistryViews.tsx
  • console/web/src/components/chat/directory/SkillsViews.tsx
  • console/web/src/components/chat/directory/__tests__/parsers.test.ts
  • console/web/src/components/chat/directory/index.tsx
  • console/web/src/components/chat/directory/parsers.ts
  • console/web/src/components/chat/directory/shared.tsx
  • console/web/src/components/chat/engine/FunctionInfoView.tsx
  • console/web/src/components/chat/engine/FunctionsListView.tsx
  • console/web/src/components/chat/engine/RegisteredTriggersListView.tsx
  • console/web/src/components/chat/engine/TriggersListView.tsx
  • console/web/src/components/chat/engine/WorkerInfoView.tsx
  • console/web/src/components/chat/engine/WorkersListView.tsx
  • console/web/src/components/chat/engine/WorkersRegisterView.tsx
  • console/web/src/components/chat/engine/__tests__/parsers.test.ts
  • console/web/src/components/chat/engine/index.tsx
  • console/web/src/components/chat/engine/parsers.ts
  • console/web/src/components/chat/engine/shared.tsx
  • console/web/src/components/chat/web/FetchView.tsx
  • console/web/src/components/chat/web/__tests__/parsers.test.ts
  • console/web/src/components/chat/web/index.tsx
  • console/web/src/components/chat/web/parsers.ts
  • console/web/src/components/chat/worker/WorkerListView.tsx
  • console/web/src/components/chat/worker/WorkerOpView.tsx
  • console/web/src/components/chat/worker/__tests__/parsers.test.ts
  • console/web/src/components/chat/worker/index.tsx
  • console/web/src/components/chat/worker/parsers.ts
  • console/web/src/lib/export-session.test.ts
  • console/web/src/lib/export-session.ts
  • console/web/src/pages/Examples/sections/directory-fixtures.ts
  • console/web/src/pages/Examples/sections/engine-fixtures.ts
  • console/web/src/pages/Examples/sections/web-fixtures.ts
  • console/web/src/pages/Examples/sections/worker-fixtures.ts

Comment thread console/web/docs/custom-function-components.md
Comment thread console/web/docs/custom-function-components.md
Comment thread console/web/src/components/chat/engine/shared.tsx
Comment thread console/web/src/lib/export-session.ts Outdated
…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.
@andersonleal andersonleal merged commit 187a56a into main May 29, 2026
11 checks passed
@andersonleal andersonleal deleted the feat/console-custom-function-views branch May 29, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants