Skip to content

chore(ts): add shared types/runtime.ts module#49

Merged
oxyc merged 1 commit into
mainfrom
chore/ts-shared-types
May 29, 2026
Merged

chore(ts): add shared types/runtime.ts module#49
oxyc merged 1 commit into
mainfrom
chore/ts-shared-types

Conversation

@oxyc

@oxyc oxyc commented May 29, 2026

Copy link
Copy Markdown
Member

PR 3 of 4 for #41. No behaviour change — types-only addition.

Defines the canonical TypeScript vocabulary the runtime adapter + chat components will share once PR 4 lands. Lives in resources/scripts/types/runtime.ts.

Wire / storage form

What the server emits and ConversationStore persists:

  • WireTextBlock, WireToolUseBlock, WireToolResultBlock, WireImageBlock
  • WireContentBlock discriminated union, keyed by type
  • WireMessage{ role, content: string | WireContentBlock[], ts? }

assistant-ui form

What the ExternalStoreRuntime renders. Same information, but tool_use + tool_result are coalesced into one tool-call part with result filled in on completion:

  • UiTextPart, UiToolCallPart, UiImagePart
  • UiContentPart union
  • UiMessage

SSE event union

The 10 event types the chat endpoint emits as a discriminated union keyed by type (text_delta, tool_use_start, tool_result, tool_approval_required, client_tool_call, ask_user, usage, error, conversation_start, message_stop). Each carries a typed data payload so the adapter's main switch will narrow on event.type in PR 4.

SessionUsageSnapshot

The token + cost shape onUsageUpdate callbacks already receive.

No consumers yet

This commit just lands the vocabulary so the next migration starts from a stable surface. PR 4 wires it through use-runtime-adapter.ts.

Verification

  • npm run typecheck — clean
  • npm run build — succeeds

🤖 Generated with Claude Code

PR 3 of 4 for #41. No behaviour change — types-only addition.

Defines the canonical TypeScript vocabulary the runtime adapter + chat
components will share once PR 4 lands:

## Wire / storage form

What the server emits and ConversationStore persists:

- `WireTextBlock`, `WireToolUseBlock`, `WireToolResultBlock`, `WireImageBlock`
- `WireContentBlock` discriminated union, keyed by `type`
- `WireMessage` — `{role, content: string | WireContentBlock[], ts?}`

## assistant-ui form

What the `ExternalStoreRuntime` renders. Same information, but
`tool_use` + `tool_result` are coalesced into one `tool-call` part with
`result` filled in on completion:

- `UiTextPart`, `UiToolCallPart`, `UiImagePart`
- `UiContentPart` union
- `UiMessage`

## SSE event union

The 10 event types the chat endpoint emits as a discriminated union
keyed by `type` (`text_delta`, `tool_use_start`, `tool_result`,
`tool_approval_required`, `client_tool_call`, `ask_user`, `usage`,
`error`, `conversation_start`, `message_stop`). Each carries a typed
`data` payload so the adapter's main switch will narrow on `event.type`
in PR 4.

## SessionUsageSnapshot

The token + cost shape `onUsageUpdate` callbacks already receive.

No consumers wired up yet — that's PR 4's job. This commit just lands
the vocabulary so the next migration starts from a stable surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@oxyc oxyc merged commit c24b34a into main May 29, 2026
3 checks passed
@oxyc oxyc deleted the chore/ts-shared-types branch May 29, 2026 22:11
oxyc added a commit that referenced this pull request May 29, 2026
PR 4 of 4 for #41 — the big one. No behaviour change; pure type
addition over the existing logic. Renames
`use-runtime-adapter.js` → `use-runtime-adapter.ts` and wires in the
shared `RuntimeEvent`, `UiMessage`, `WireMessage`, `UiContentPart`,
`WireContentBlock`, and `SessionUsageSnapshot` types from PR 3.

## Hook signature

`useAssistantRuntime()` now returns a typed `AssistantRuntimeHandle`:

```ts
interface AssistantRuntimeHandle {
  runtime: ReturnType<typeof useExternalStoreRuntime>;
  loadConversation: (uuid: string) => Promise<void>;
  approveToolCall: (options?: { trustHost?: boolean }) => void;
  denyToolCall: () => void;
  pendingApprovals: PendingApproval[];
  undoableActions: Record<string, UndoableActionState>;
  undoAction: (toolCallId: string, auditId: number) => Promise<void>;
  retryToolCall: (toolCallId: string) => Promise<void>;
  retryingIds: Set<string>;
}
```

## Globals

`window.gdsAssistant` is now declared via `declare global` with the
`GdsAssistantGlobal` interface: localised config (`restUrl`, `restBase`,
`nonce`, `modelPricing`) plus the two hooks we attach ourselves
(`sendChatMessage`, `openChat`). Eliminates the silent `as any` access
pattern.

## SSE event narrowing

The big `for await (const event of parseSSE(...))` switch now narrows
on `event.type` against the discriminated `RuntimeEvent` union, so each
case's `event.data` is the precise per-event shape (no more `event.data
.input_tokens` reads against `mixed`). `parseSSE` itself returns
`AsyncGenerator<RuntimeEvent>` rather than a loose object stream.

## Type interop boundary

assistant-ui's `ExternalStoreAdapter` types `onNew`/`onEdit` with its
own (narrower) `AppendMessage` shape. Our adapter accepts a superset
(control messages, client-tool-result resumes), so we cast at the
`useExternalStoreRuntime(adapter as …)` boundary rather than weakening
the internal `OnNewMessage` type. Comment explains why.

## Test helper

`restorePendingApprovalsFromHistory` keeps its existing signature
(`WireMessage[] | unknown`) and the Jest unit test continues to pass
unchanged.

## Consumers

`app.jsx`, `components/Composer.jsx`, `components/SidePanels.jsx`,
`components/Messages.jsx`, `components/Thread.jsx` all import without
an extension — webpack + TS resolve to the `.ts` file automatically. No
caller changes needed.

## Verification

- `npm run typecheck` — clean
- `npm run build` — bundle includes `useAssistantRuntime`,
  `loadConversation`, `approveToolCall`
- `npm run test:unit` — 17/17 pass
- `npm run lint:js` — only the pre-existing `no-nested-ternary` /
  `no-unused-vars-before-return` warnings carried over from the JS
  source; same in `editor-bridge.ts`

## Wraps up #41

PR 1 (#47): setup + UndoContext smoke
PR 2 (#48): editor-bridge.ts
PR 3 (#49): types/runtime.ts shared module
PR 4 (this): use-runtime-adapter.ts

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant