mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-09 06:15:21 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The runner package already provides the production protocol and execution spine. > - Contributors still need stable SDK surfaces, deterministic test tools, and local inspection tools. > - Those surfaces share generated contracts and must change as one package boundary. > - This pull request adds the package-local SDK, labs, examples, and drift checks. > - The benefit is a reviewable developer platform that does not change application execution selection. ## Linked Issues or Issue Description **Subsystem affected** `packages/paperclip-runner` — runner SDK, conformance tools, and developer tooling. **Problem or motivation** The production runner spine is present, but package consumers cannot build deterministic integrations, inspect sessions, or verify provider-neutral behavior through supported surfaces. **Proposed solution** Add browser, React, standalone, live-session, scenario, conformance, and evaluation surfaces. Add generated contract inventories and package-local verification scripts. Keep production application routing unchanged. **Alternatives considered** We considered splitting each generated catalog, SDK surface, and demo into separate pull requests. Those changes share exports, fixtures, and drift gates. Splitting them would create intermediate package states that do not build. **Roadmap alignment** No overlapping item appears in `ROADMAP.md`. This work extends the runner package that is already on `master`. ## What Changed - Add browser, React, standalone, live-session, and issue-thread SDK surfaces. - Add deterministic mock control-plane, scenario, conformance, replay, and evaluation tools. - Add bounded Codex, OpenCode, and ACPX development transports and fixtures. - Keep deferred managed-provider execution fail-closed. Persisted compatibility data remains readable. - Add generated capability inventories with their source files and drift checks. - Add examples, package documentation, browser checks, and clean-consumer checks. - Preserve the reviewed protocol bounds, replay compatibility aliases, process environment isolation, and semantic redaction limits. - Update the ACPX package patch that the existing workspace patch registry already tracks. - Do not change `pnpm-lock.yaml`, repository workflows, server runtime selection, or the application UI. ## Verification GitHub Actions is the verification authority for this pull request. The repository CI, package TypeScript and Rust checks, package tests, generated-output drift checks, browser checks, security scans, and Greptile review must pass on the exact head. Local test suites were not run because this series uses parallel GitHub Actions for verification. ## Risks This is a large greenfield package change. The main risks are public export drift, generated-output drift, and optional React consumer compatibility. Package boundary checks, clean-consumer checks, and browser tests cover those risks. Production adapter selection and server execution are outside this pull request. ## Stack 1. **This PR:** runner SDK and developer tooling. 2. [Codex production server integration](https://github.com/paperclipai/paperclip/pull/12616). 3. [Provider-neutral task-thread UI](https://github.com/paperclipai/paperclip/pull/12617). ## Model Used OpenAI Codex, GPT-5, high-reasoning mode, with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have described the issue in-PR following the feature request template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal Paperclip ticket id - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge
172 lines
7.6 KiB
Markdown
172 lines
7.6 KiB
Markdown
# SDK Browser SDK and Reference Console
|
|
|
|
## Public package surface
|
|
|
|
SDK freezes the browser SDK as package version `0.1.2`.
|
|
|
|
Version `0.1.1` adds direct chat mode. The browser sends the operator message
|
|
as plain Codex input. The protocol inspector still shows the event stream,
|
|
reducer state, requests, and replay data. The Codex task fixtures remain
|
|
available from the session controls.
|
|
|
|
Version `0.1.2` adds the canonical events for each transcript item to the
|
|
optional `debugEvents` projection. `ToolItem` renders these events inside a
|
|
nested `Debug details` disclosure. Completed Terminal rows stay folded by
|
|
default, while operators can inspect command input, output, provider items,
|
|
delta updates, event ids, sequence numbers, and timestamps. Long chat and
|
|
command content wraps at mobile widths without horizontal page scrolling.
|
|
|
|
| Import | Purpose |
|
|
| --- | --- |
|
|
| `@paperclipai/paperclip-runner` | Protocol, reducer, and existing package contracts |
|
|
| `@paperclipai/paperclip-runner/browser` | Framework-free HTTP/SSE client, protocol types, transcript projection |
|
|
| `@paperclipai/paperclip-runner/react` | Hook, reference console, and reusable React components |
|
|
| `@paperclipai/paperclip-runner/styles.css` | Scoped light-theme token and component styles |
|
|
|
|
React and React DOM are peer dependencies. The extracted surface adds no
|
|
runtime dependency. It is client-only: it uses `window`, `sessionStorage`,
|
|
Fetch, and EventSource, so applications must mount it in the browser rather
|
|
than render it on the server.
|
|
|
|
## Framework-free client
|
|
|
|
```ts
|
|
import { createRunnerClient } from "@paperclipai/paperclip-runner/browser";
|
|
|
|
const client = createRunnerClient({ baseUrl: "/api/liveConsole" });
|
|
const manifests = await client.fetchManifests();
|
|
```
|
|
|
|
`RunnerClient` exposes manifest listing; session create/read/close; event
|
|
history and SSE streaming; turn start, steering, and interrupt; typed request
|
|
resolution; goal operations; and reconnect. `RunnerClientError` preserves the
|
|
HTTP status, stable error code, and redacted server message.
|
|
|
|
The protocol server remains authoritative. The browser client never creates a
|
|
second event model, invents capabilities, changes run/session/provider
|
|
identities, or removes duplicate events before the shared reducer sees them.
|
|
|
|
## React hook
|
|
|
|
```tsx
|
|
import { useRunnerConsole } from "@paperclipai/paperclip-runner/react";
|
|
|
|
function Console() {
|
|
const runner = useRunnerConsole({ baseUrl: "/api/liveConsole" });
|
|
return <p>{runner.connection}: {runner.replayParity ? "match" : "waiting"}</p>;
|
|
}
|
|
```
|
|
|
|
`useRunnerConsole` returns manifests and selection, canonical server state,
|
|
the exact event list, reducer snapshot, transcript projection, connection and
|
|
retry state, composer state, steering acknowledgements, a single polite
|
|
announcement channel, errors, busy state, lineage selection, replay controls,
|
|
and verbs for every supported mutation. Durable history is re-read before a
|
|
reconnected stream opens. Replay uses the same reducer as live state.
|
|
|
|
## Components
|
|
|
|
The `./react` export includes:
|
|
|
|
- primitives: `Button`, `Badge`, `Card`, `Textarea`, `Tabs`, `Menu`, `Dialog`,
|
|
`Tooltip`, and `Banner`;
|
|
- protocol views: `Conversation`, `Message`, `ReasoningItem`, `ToolItem`,
|
|
`RequestCard`, `SessionTimeline`, `Inspector`, `ReplayControls`, and
|
|
`ConnectionBanner`;
|
|
- composition: `Composer`, `RunnerConsoleApp`, and `useRunnerConsole`.
|
|
|
|
Components take reducer/protocol shapes. Every component owns a stable
|
|
`data-slot` and `pcr-` class. Terminal, file, tool, plan, request, failure,
|
|
lineage, goal, connection, and replay states come only from canonical events
|
|
or public session state.
|
|
|
|
The reference server has two driver modes behind the same HTTP/SSE contract.
|
|
Deterministic manifests use `LiveConsoleScriptedDriver`. Real chat mode uses
|
|
`CodexAppServerDriver`, which starts a real local `codex app-server` process.
|
|
The Node server owns provider authentication and the disposable working
|
|
directory; browser code receives only canonical runner events.
|
|
|
|
## Five extension points
|
|
|
|
These are the complete extension surface for `0.1.2`:
|
|
|
|
1. `Conversation`, `Message`, `ReasoningItem`, and `ToolItem` accept
|
|
`renderItemBody(item)` for markdown, highlighting, or another item body.
|
|
2. `RequestCard` accepts `renderRequestDetail(request)` for its detail region.
|
|
3. `Composer` accepts `leadingActions` and `trailingActions`.
|
|
4. Consumers may override `--pcr-*` properties under `.pcr-root`.
|
|
5. `createRunnerClient` and `useRunnerConsole` accept `baseUrl`, `fetchImpl`,
|
|
and `eventSourceFactory` transport injection.
|
|
|
|
There is no headless distribution, component registry, render-prop shell,
|
|
dark theme, toast layer, or virtualized transcript in this version.
|
|
|
|
## Transport and credential boundary
|
|
|
|
```tsx
|
|
const runner = useRunnerConsole({
|
|
baseUrl: "/runner",
|
|
fetchImpl: (input, init) => fetch(input, {
|
|
...init,
|
|
headers: { ...Object.fromEntries(new Headers(init?.headers)), "x-app-session": appSession },
|
|
}),
|
|
eventSourceFactory: (url) => new EventSource(url),
|
|
});
|
|
```
|
|
|
|
Transport injection is for browser-to-protocol-server authentication, proxies,
|
|
and test doubles. Provider credentials stay on that server. Do not place a
|
|
provider bearer token in component props, manifest text, events, diagnostics,
|
|
browser storage, or an EventSource query string. The package demo fixes and
|
|
validates its workspace server-side and redacts provider paths and credentials.
|
|
|
|
## Tokens and contrast
|
|
|
|
`styles.css` declares a light-only `color-scheme` and all visual values under
|
|
`.pcr-root`. The shipped foreground/surface pairs are:
|
|
|
|
| Foreground | Surface | Contrast |
|
|
| --- | --- | ---: |
|
|
| `--pcr-foreground` | `--pcr-background` | 16.4:1 |
|
|
| `--pcr-card-foreground` | `--pcr-card` | 17.6:1 |
|
|
| `--pcr-primary-foreground` | `--pcr-primary` | 15.6:1 |
|
|
| `--pcr-muted-foreground` | `--pcr-muted` | 5.0:1 |
|
|
| `--pcr-success` | `--pcr-success-surface` | 6.5:1 |
|
|
| `--pcr-warning` | `--pcr-warning-surface` | 5.4:1 |
|
|
| `--pcr-danger` | `--pcr-danger-surface` | 6.2:1 |
|
|
| `--pcr-accent` | `--pcr-accent-surface` | 5.5:1 |
|
|
|
|
When a consumer overrides either side of a pair, that consumer owns a new
|
|
contrast check. Keep normal text at 4.5:1 or better. Motion respects
|
|
`prefers-reduced-motion`. All mobile controls use the `--pcr-touch-target`
|
|
minimum.
|
|
|
|
Minimum supported widths are 320px for `Conversation`, `Composer`, and
|
|
`Inspector`, and 280px for `RequestCard`. `RunnerConsoleApp` renders one
|
|
responsive tree: three panes above 900px and one selected pane below it.
|
|
|
|
## Keyboard and accessibility contract
|
|
|
|
- The transcript is a labelled `role="log"`; consumers render the hook's
|
|
`announcement` once in an `aria-live="polite"` region.
|
|
- Composer Enter sends or steers; Shift+Enter adds a line. Stop remains a
|
|
separate button.
|
|
- Tabs use arrow-key roving focus plus Home/End.
|
|
- Menu supports Enter/Space/ArrowDown, arrows, Home/End, and Escape with focus
|
|
restoration.
|
|
- The native dialog traps focus, closes on Escape, and restores its trigger.
|
|
- Reasoning and tool disclosures use native summary keyboard behavior.
|
|
- Replay Left/Right steps; Space toggles play from the scrubber.
|
|
- Status is always named in text, not communicated by color alone.
|
|
- Informational banners do not steal focus. A blocking reconnect failure may.
|
|
|
|
## Reference applications
|
|
|
|
`examples/reference-console/` composes `RunnerConsoleApp` only from public
|
|
exports. `examples/mini-consumer/` imports only the three public SDK subpaths
|
|
and visibly exercises every extension point. Both run against the package fake
|
|
driver or the real Codex driver through the same server-only adapter.
|
|
|
|
See the [hand-run tutorial](tutorials/sdk-console.md) and the
|
|
[implementation decision record](design/sdk-component-decisions.md).
|