Files
fusion/plugins/fusion-plugin-paperclip-runtime
dependabot[bot] af3d78d2cd chore(deps-dev): bump vitest from 4.1.8 to 4.1.10 (#2446)
Bumps
[vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest)
from 4.1.8 to 4.1.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitest-dev/vitest/releases">vitest's
releases</a>.</em></p>
<blockquote>
<h2>v4.1.10</h2>
<h3>   🐞 Bug Fixes</h3>
<ul>
<li><strong>browser</strong>: Check fs access in builtin commands
[backport to v4]  -  by <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a>,
<strong>Hiroshi Ogawa</strong> and <strong>OpenCode
(claude-opus-4-8)</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10680">vitest-dev/vitest#10680</a>
<a href="https://github.com/vitest-dev/vitest/commit/5c18dd267"><!-- raw
HTML omitted -->(5c18d)<!-- raw HTML omitted --></a></li>
<li><strong>vm</strong>: Fix external module resolve error with deps
optimizer query for encoded URI [backport to v4]  -  by <a
href="https://github.com/SveLil"><code>@​SveLil</code></a> and <a
href="https://github.com/hi-ogawa"><code>@​hi-ogawa</code></a> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10661">vitest-dev/vitest#10661</a>
<a href="https://github.com/vitest-dev/vitest/commit/bae52b511"><!-- raw
HTML omitted -->(bae52)<!-- raw HTML omitted --></a></li>
</ul>
<h5>    <a
href="https://github.com/vitest-dev/vitest/compare/v4.1.9...v4.1.10">View
changes on GitHub</a></h5>
<h2>v4.1.9</h2>
<h3>🐞 Bug Fixes</h3>
<ul>
<li>Fix <code>importOriginal</code> with optimizer and query import
[backport to v4] - by <strong>Hiroshi Ogawa</strong>, <strong>David
Harris</strong>, <strong>Codex</strong>and <strong>Vladimir</strong> in
<a
href="https://redirect.github.com/vitest-dev/vitest/issues/10546">vitest-dev/vitest#10546</a>
<a href="https://github.com/vitest-dev/vitest/commit/a5180190c"><!-- raw
HTML omitted -->(a5180)<!-- raw HTML omitted --></a></li>
<li><strong>browser</strong>:
<ul>
<li>Wait for orchestrator readiness before resolving browser sessions
[backport to v4] - by <strong>Vladimir</strong> and <strong>Séamus
O'Connor</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10555">vitest-dev/vitest#10555</a>
<a href="https://github.com/vitest-dev/vitest/commit/7fb29651a"><!-- raw
HTML omitted -->(7fb29)<!-- raw HTML omitted --></a></li>
<li>Wait for iframe tester readiness before preparing [backport to v4] -
by <strong>Vladimir</strong> and <strong>Séamus O'Connor</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10497">vitest-dev/vitest#10497</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10556">vitest-dev/vitest#10556</a>
<a href="https://github.com/vitest-dev/vitest/commit/fbc626c40"><!-- raw
HTML omitted -->(fbc62)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>mocker</strong>:
<ul>
<li>Hoist vi.mock() for vite-plus/test imports [backport to v4] - by
<strong>Hiroshi Ogawa</strong>, <strong>LongYinan</strong>,
<strong>Claude Opus 4.8</strong> and <strong>Vladimir</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10548">vitest-dev/vitest#10548</a>
<a href="https://github.com/vitest-dev/vitest/commit/2c9559c02"><!-- raw
HTML omitted -->(2c955)<!-- raw HTML omitted --></a></li>
</ul>
</li>
<li><strong>pool</strong>:
<ul>
<li>Prevent test run hang on worker crash [backport to v4] - by
<strong>Ari Perkkiö</strong> and <strong>Jattioui Ismail</strong> in <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10543">vitest-dev/vitest#10543</a>
and <a
href="https://redirect.github.com/vitest-dev/vitest/issues/10564">vitest-dev/vitest#10564</a>
<a href="https://github.com/vitest-dev/vitest/commit/934b0f587"><!-- raw
HTML omitted -->(934b0)<!-- raw HTML omitted --></a></li>
</ul>
</li>
</ul>
<h5><a
href="https://github.com/vitest-dev/vitest/compare/v4.1.8...v4.1.9">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="db616d227b"><code>db616d2</code></a>
chore: release v4.1.10 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10718">#10718</a>)</li>
<li><a
href="bae52b5112"><code>bae52b5</code></a>
fix(vm): fix external module resolve error with deps optimizer query for
enco...</li>
<li><a
href="a7a61e78c7"><code>a7a61e7</code></a>
chore: release v4.1.9 (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10598">#10598</a>)</li>
<li><a
href="934b0f587c"><code>934b0f5</code></a>
fix(pool): prevent test run hang on worker crash (<a
href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/10543">#10543</a>)
[backport to v4] (#...</li>
<li><a
href="7fb29651af"><code>7fb2965</code></a>
fix(browser): wait for orchestrator readiness before resolving browser
sessio...</li>
<li><a
href="a5180190c1"><code>a518019</code></a>
fix: fix <code>importOriginal</code> with optimizer and query import
[backport to v4] (#...</li>
<li>See full diff in <a
href="https://github.com/vitest-dev/vitest/commits/v4.1.10/packages/vitest">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com>
2026-07-27 19:40:08 -07:00
..
2026-06-18 06:56:36 -07:00
2026-07-26 18:11:47 -07:00

Paperclip Runtime Plugin

Drives a Paperclip agent (an "employee" in a Paperclip company) via the wakeup + heartbeat-run API. Each Fusion prompt becomes a Paperclip task, not a chat completion.

Mental model — read this first

Paperclip is a control plane for AI labor. Agents are long-lived employees with budgets, chains of command, and approval gates; Paperclip itself does not run models — it dispatches work to adapters (claude_local, codex_local, openclaw, http, …) which run the actual LLM call inside their own heartbeat.

This plugin proxies a Fusion conversation through one of those Paperclip agents:

  1. (Optionally) creates a Paperclip issue with the prompt as its body, assigned to your chosen agent.
  2. Calls POST /api/agents/{id}/wakeup with payload: { prompt, fusionSessionId, issueId } and an idempotency key.
  3. Streams GET /api/heartbeat-runs/{runId}/events, forwarding heartbeat.run.log chunks to the chat UI.
  4. On terminal status (succeeded | failed | cancelled | timed_out), reads the issue's final state and the agent's closing comment.

Implications:

  • Latency is task-shaped (seconds to minutes), not chat-shaped.
  • Governance applies: budget caps, approval requirements, audit log all come from Paperclip.
  • A single Paperclip agent can be proxied from many Fusion sessions concurrently.

Prerequisites

A running Paperclip server you can reach. For local development:

npm install -g paperclipai
paperclipai onboard      # interactive setup
paperclipai run          # starts the server (default: http://localhost:3100)

Verify the server is up:

curl http://localhost:3100/api/health

Connection modes

The dashboard settings card lets you pick API or CLI mode:

API mode (default)

Paste an apiUrl and an agent apiKey. Get a key from the Paperclip UI's agent detail page → "Create API Key" (the full value is shown once). For local-trusted deployments, the key may be omitted.

CLI mode

Auto-derive the apiUrl from the local paperclipai install. The plugin reads ~/.paperclip/instances/default/config.json and uses that host:port as the apiUrl. No token needs to be pasted into Fusion. For non-local-trusted deployments, you can still set an override apiKey.

CLI key bootstrap

For authenticated Paperclip deployments (e.g. paperclip-dev or any non-local_trusted instance), a bearer token is required. The dashboard offers a one-click "✨ Mint API key via paperclipai" button that appears in CLI mode when:

  • A connection has been attempted but available === false (typically "API key rejected"), AND
  • The user has already selected an agent in the agent picker.

The button calls POST /api/providers/paperclip/cli-mint-key on the Fusion backend, which spawns:

paperclipai agent local-cli <agentRef> --json --no-install-skills --key-name fusion-runtime

On success the returned apiKey is written into the API key field and a save-prompt toast is shown. On failure (e.g. CLI not authenticated) the toast shows the error and instructs the user to run paperclipai onboard.

Requirement: The local paperclipai CLI must be authenticated (~/.paperclip/context.json must have a valid profile). Run paperclipai onboard to authenticate if the mint fails.

Conversation modes

Independent of transport, the mode setting controls how prompts map to Paperclip issues:

Mode Behavior
rolling-issue (default) Creates one Paperclip issue per Fusion session; subsequent prompts add comments. Closest to chat.
issue-per-prompt Each prompt creates a new top-level issue. Maximally explicit; clutters the board.
wakeup-only No issue side-effects; the prompt is delivered via the wakeup payload only. Requires the agent's prompt template to handle payload-driven wakes.

Settings

Key Env var Default Notes
transport PAPERCLIP_TRANSPORT api api or cli.
apiUrl PAPERCLIP_API_URL http://localhost:3100 API mode only.
apiKey PAPERCLIP_API_KEY (none) API mode (and as a CLI-mode override).
cliBinaryPath PAPERCLIPAI_BIN paperclipai CLI mode only.
cliConfigPath PAPERCLIP_CLI_CONFIG ~/.paperclip/instances/default/config.json CLI mode only.
agentId PAPERCLIP_AGENT_ID auto-derived from /api/agents/me The Paperclip agent this Fusion runtime proxies.
companyId PAPERCLIP_COMPANY_ID auto-derived from /api/agents/me The Paperclip company.
mode PAPERCLIP_RUNTIME_MODE rolling-issue One of the conversation modes above.
parentIssueId PAPERCLIP_PARENT_ISSUE_ID (none) Optional issue scoping.
projectId PAPERCLIP_PROJECT_ID (none) Optional.
goalId PAPERCLIP_GOAL_ID (none) Optional.
runTimeoutMs PAPERCLIP_RUN_TIMEOUT_MS 600000 Local cap before Fusion stops polling. The run continues server-side.
pollIntervalMs PAPERCLIP_POLL_INTERVAL_MS 500 Initial poll interval.
pollIntervalMaxMs PAPERCLIP_POLL_INTERVAL_MAX_MS 2000 Max poll interval after exponential backoff.

Settings precedence: plugin settings → env var → default.

Public API

import {
  PaperclipRuntimeAdapter,
  // REST helpers
  agentsMe,
  listCompanies,
  listCompanyAgents,
  // Probes
  probePaperclipConnection,
  discoverPaperclipCliConfig,
  // CLI key minting
  mintAgentApiKeyViaCli,
  // Types
  type PaperclipAgentSummary,
  type PaperclipCompanySummary,
  type PaperclipConnectionStatus,
  type PaperclipCliDiscoveryResult,
  type MintCliKeyOptions,
  type MintedApiKey,
} from "@fusion-plugin-examples/paperclip-runtime";
  • probePaperclipConnection({ apiUrl, apiKey?, timeoutMs? }) → { available, identity?, reason? }. Powers the dashboard's "✓ Connected as " badge.
  • listCompanyAgents(apiUrl, apiKey, companyId) → list of agents in a company. Drives the agent picker.
  • discoverPaperclipCliConfig({ configPath? }) → { ok, apiUrl, deploymentMode? } from the local paperclipai config. Drives CLI-mode auth discovery.
  • mintAgentApiKeyViaCli(opts: MintCliKeyOptions) → Promise<MintedApiKey>. Spawns paperclipai agent local-cli <agentRef> --json --no-install-skills to mint a fresh agent API key. Throws on ENOENT, non-zero exit, or malformed JSON; includes a hint to run paperclipai onboard on auth failures.

Endpoints used (Paperclip side)

Method Path Purpose
GET /api/agents/me Identity + auto-derive agentId/companyId.
GET /api/companies Company list (board access).
GET /api/companies/{companyId}/agents Agent list (agent-key sees its own company).
POST /api/companies/{companyId}/issues Issue creation (issue-per-prompt / rolling-issue modes).
POST /api/agents/{agentId}/wakeup Trigger a heartbeat run with the Fusion prompt as payload.
GET /api/heartbeat-runs/{runId}/events Streaming run log + status.
GET /api/issues/{issueId} Final issue state.
GET /api/issues/{issueId}/comments Final comment fallback.

The adapter does not call /api/issues/{id}/checkout — checkout is the agent's job during its own heartbeat. The adapter does not call the legacy /api/agents/{id}/heartbeat/invoke.

Limitations

  • Latency. Heartbeat runs can take minutes; not a chat-completion drop-in.
  • Single-agent identity per connection. A Paperclip agent API key is scoped to one agent in one company. To proxy several agents, configure several Fusion connections.
  • Run-events schema is partially inferred. The events endpoint payload shape is documented but not formally schema'd; the client accepts both bare-array and { events: [...] } envelopes defensively.

Metadata

  • Plugin ID: fusion-plugin-paperclip-runtime
  • Runtime ID: paperclip
  • Package: @fusion-plugin-examples/paperclip-runtime

Development

pnpm --filter @fusion-plugin-examples/paperclip-runtime test    # 46 tests
pnpm --filter @fusion-plugin-examples/paperclip-runtime build