feat(FN-2706): merge fusion/fn-2706 (auto-resolved)
- feat(FN-2706): complete Step 6 — document Paperclip REST runtime behavior - test(FN-2706): cover getAgentIdentity success and request payload assertions - fix(FN-2706): align promptWithFallback signature with runtime contract - fix(FN-2706): add session dispose compatibility for engine callers - fix(FN-2706): refine Paperclip API client error and config handling - test(FN-2706): complete Step 4 — cover paperclip api client and adapter flow - feat(FN-2706): complete Step 3 — wire plugin settings and remove engine guard - feat(FN-2706): complete Step 2 — rewrite paperclip runtime adapter - fix(FN-2706): restore compatibility exports during runtime migration - feat(FN-2706): complete Step 1 — add Paperclip REST client
This commit is contained in:
@@ -1,252 +1,75 @@
|
||||
# Paperclip Runtime Plugin
|
||||
|
||||
A Fusion plugin that provides the **Paperclip runtime** for AI agents, using the existing pi backend for session management.
|
||||
`fusion-plugin-paperclip-runtime` provides the `paperclip` runtime for Fusion agents by calling a running **Paperclip REST API** instance.
|
||||
|
||||
## Overview
|
||||
> This plugin no longer delegates to Fusion's internal `@fusion/engine` pi runtime.
|
||||
|
||||
This plugin provides a runtime adapter that wraps the existing `createFnAgent` and `promptWithFallback` functions from `@fusion/engine`, making the pi-based agent session available through Fusion's plugin runtime system.
|
||||
## Runtime Identity
|
||||
|
||||
## Runtime ID
|
||||
- **Plugin ID:** `fusion-plugin-paperclip-runtime`
|
||||
- **Runtime ID:** `paperclip`
|
||||
- **Runtime Name:** `Paperclip Runtime`
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Runtime ID** | `paperclip` |
|
||||
| **Name** | `Paperclip Runtime` |
|
||||
| **Version** | `1.0.0` |
|
||||
## Prerequisites
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Install pi globally:
|
||||
|
||||
```bash
|
||||
npm i -g @mariozechner/pi-coding-agent
|
||||
```
|
||||
|
||||
2. Authenticate pi with your AI provider:
|
||||
|
||||
```bash
|
||||
pi
|
||||
# Follow the login flow for your provider
|
||||
```
|
||||
|
||||
### Install the Plugin
|
||||
|
||||
Install the plugin as a local plugin:
|
||||
1. Paperclip is installed and running (default URL: `http://localhost:3100`)
|
||||
2. Fusion plugin installed:
|
||||
|
||||
```bash
|
||||
fn plugin install ./plugins/fusion-plugin-paperclip-runtime
|
||||
```
|
||||
|
||||
Verify installation:
|
||||
|
||||
```bash
|
||||
fn plugin list
|
||||
# Should show fusion-plugin-paperclip-runtime
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Plugin Discovery
|
||||
The runtime resolves configuration in this priority order:
|
||||
|
||||
After installation, the Paperclip runtime is automatically discovered by Fusion's plugin system when the plugin is loaded. No additional configuration is required to make the runtime available.
|
||||
1. Plugin settings (`ctx.settings`)
|
||||
2. Environment variables
|
||||
3. Defaults
|
||||
|
||||
### Selecting the Paperclip Runtime
|
||||
| Setting | Env Var | Required | Default |
|
||||
|---|---|---:|---|
|
||||
| `apiUrl` | `PAPERCLIP_API_URL` | No | `http://localhost:3100` |
|
||||
| `apiKey` | `PAPERCLIP_API_KEY` | No | `undefined` |
|
||||
| `agentId` | `PAPERCLIP_AGENT_ID` | Yes (for session create) | `undefined` |
|
||||
| `companyId` | `PAPERCLIP_COMPANY_ID` | Yes (for session create) | `undefined` |
|
||||
|
||||
Once the plugin is installed, you can select the Paperclip runtime for agents by setting `runtimeHint` in the agent's `runtimeConfig`.
|
||||
### Authentication Modes
|
||||
|
||||
#### Via Agent Configuration
|
||||
- **Bearer token mode:** set `apiKey` / `PAPERCLIP_API_KEY` and requests include `Authorization: Bearer <token>`
|
||||
- **Local trusted mode:** leave `apiKey` unset; plugin probes `/api/health` without auth and proceeds when allowed by Paperclip deployment mode
|
||||
|
||||
Set the runtime hint in an agent's `runtimeConfig`:
|
||||
## How Runtime Execution Works
|
||||
|
||||
For each prompt, the runtime adapter performs:
|
||||
|
||||
1. `POST /api/companies/{companyId}/issues` (creates issue in `backlog`, assigned to `agentId`)
|
||||
2. `POST /api/issues/{issueId}/checkout` (atomic claim; 409 conflicts are logged and execution continues)
|
||||
3. `POST /api/agents/{agentId}/heartbeat/invoke` (async agent execution)
|
||||
4. Polls `GET /api/issues/{issueId}` with exponential backoff (2s → 4s → 8s → 10s cap, 120s timeout)
|
||||
5. Reads output from `GET /api/issues/{issueId}/comments`
|
||||
6. Emits text/thinking/tool callbacks back to Fusion runtime consumers
|
||||
|
||||
The runtime uses Paperclip as the orchestration engine; Fusion receives summarized output via issue comments.
|
||||
|
||||
## Runtime Selection in Fusion
|
||||
|
||||
Configure an agent with runtime hint `paperclip`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Paperclip Executor",
|
||||
"role": "executor",
|
||||
"runtimeConfig": {
|
||||
"runtimeHint": "paperclip"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When an agent with `runtimeHint: "paperclip"` is assigned to a task, the task's executor session will use the Paperclip Runtime Adapter.
|
||||
|
||||
#### How Runtime Selection Works
|
||||
|
||||
1. When an agent session is created, Fusion checks the agent's `runtimeConfig.runtimeHint`
|
||||
2. If `runtimeHint` is set to `"paperclip"`, Fusion resolves the Paperclip Runtime from the plugin
|
||||
3. If the plugin is not installed or unavailable, Fusion falls back to the default `pi` runtime
|
||||
4. If `runtimeHint` is not set, Fusion uses the default `pi` runtime
|
||||
|
||||
### Fallback Behavior
|
||||
|
||||
If the Paperclip runtime is unavailable (plugin not installed, not enabled, or factory error), Fusion automatically falls back to the default `pi` runtime with a warning log:
|
||||
|
||||
```
|
||||
[runtime-resolver] Runtime "paperclip" unavailable (not_found), falling back to default pi runtime
|
||||
```
|
||||
|
||||
The fallback behavior ensures tasks continue executing even if the plugin is misconfigured.
|
||||
|
||||
## Runtime Resolution Order
|
||||
|
||||
When resolving a runtime, Fusion follows this order:
|
||||
|
||||
1. **No runtime hint** → Use default `pi` runtime
|
||||
2. **Hint is `"pi"` or `"default"`** → Use default `pi` runtime
|
||||
3. **Hint is a plugin runtime ID** (e.g., `"paperclip"`) → Look up and instantiate the plugin runtime
|
||||
4. **Plugin runtime unavailable** → Fall back to default `pi` runtime
|
||||
|
||||
## Supported Session Purposes
|
||||
|
||||
The Paperclip runtime supports all Fusion agent session purposes:
|
||||
|
||||
- `executor` — Task implementation
|
||||
- `triage` — Task specification
|
||||
- `reviewer` — Code/plan review
|
||||
- `merger` — Merge operations
|
||||
- `heartbeat` — Health monitoring
|
||||
- `validation` — Workflow step validation
|
||||
|
||||
## Interface Implementation
|
||||
|
||||
The Paperclip Runtime Adapter implements the `AgentRuntime` interface:
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `id` | Returns `"paperclip"` |
|
||||
| `name` | Returns `"Paperclip Runtime"` |
|
||||
| `createSession(options)` | Creates a session using `createFnAgent` from `@fusion/engine` |
|
||||
| `promptWithFallback(session, prompt, options?)` | Delegates to pi's `promptWithFallback` with automatic retry and compaction |
|
||||
| `describeModel(session)` | Returns `"<provider>/<modelId>"` or `"unknown model"` |
|
||||
| `dispose(session)` | Calls `session.dispose()` if available |
|
||||
|
||||
## Credentials
|
||||
|
||||
The Paperclip runtime uses the user's existing pi configuration:
|
||||
|
||||
- **No additional credentials required** — Reuses pi's authenticated provider
|
||||
- **Provider/model** — Sourced from pi's configured default
|
||||
- **Fallback provider/model** — Uses pi's configured fallback if set
|
||||
|
||||
If pi is not authenticated, session creation will fail and fall back to the default `pi` runtime.
|
||||
|
||||
## Constraints
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- `pi` must be installed globally (`npm i -g @mariozechner/pi-coding-agent`)
|
||||
- `pi` must be authenticated with at least one AI provider
|
||||
- The plugin must be installed and enabled in Fusion
|
||||
- The agent must have `runtimeConfig.runtimeHint` set to `"paperclip"` to use this runtime
|
||||
|
||||
### Limitations
|
||||
|
||||
- **No task-level runtime selection**: Runtime selection is configured at the agent level via `runtimeConfig.runtimeHint`, not at the task level. Tasks inherit the runtime from their assigned agent.
|
||||
- **Session persistence**: The Paperclip runtime uses pi's session management. Sessions are persisted to disk according to pi's configuration.
|
||||
- **Tool selection**: Tool availability is controlled by the `skills` parameter passed to `createSession`, not by the runtime itself.
|
||||
- **Model selection**: Model selection is determined by pi's configuration, not by the runtime adapter.
|
||||
|
||||
### Compatibility
|
||||
|
||||
The Paperclip runtime is compatible with all Fusion session purposes. It wraps the same underlying implementation used by the default `pi` runtime, ensuring feature parity.
|
||||
|
||||
## Verification
|
||||
|
||||
### Check Plugin Status
|
||||
|
||||
```bash
|
||||
fn plugin list
|
||||
```
|
||||
|
||||
### Verify Agent Configuration
|
||||
|
||||
Check that the agent has the correct `runtimeConfig`:
|
||||
|
||||
```bash
|
||||
fn agent list
|
||||
# Look for agents with runtimeHint: "paperclip" in their runtimeConfig
|
||||
```
|
||||
|
||||
### Verify Runtime Resolution
|
||||
|
||||
Enable debug logging and look for runtime resolution messages:
|
||||
|
||||
```
|
||||
[runtime-resolver] [executor] Using configured plugin runtime "paperclip" from "fusion-plugin-paperclip-runtime"
|
||||
```
|
||||
|
||||
Or fallback warnings (when plugin is unavailable):
|
||||
|
||||
```
|
||||
[runtime-resolver] [executor] Runtime "paperclip" unavailable (not_found), falling back to default pi runtime
|
||||
```
|
||||
Fusion runtime resolution still falls back to default `pi` runtime if plugin runtime resolution fails.
|
||||
|
||||
## Development
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
cd plugins/fusion-plugin-paperclip-runtime
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
```bash
|
||||
cd plugins/fusion-plugin-paperclip-runtime
|
||||
pnpm test
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
fusion-plugin-paperclip-runtime/
|
||||
├── manifest.json # Plugin metadata with runtime declaration
|
||||
├── src/
|
||||
│ ├── index.ts # Plugin entry point with runtime registration
|
||||
│ ├── runtime-adapter.ts # PaperclipRuntimeAdapter implementation
|
||||
│ └── types.ts # Type re-exports
|
||||
├── README.md
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
This plugin follows the Fusion plugin runtime contract defined in [FN-2256](https://github.com/gsxdsm/fusion/issues/FN-2256).
|
||||
|
||||
### Runtime Registration
|
||||
|
||||
Runtimes are registered via the plugin's `runtime` field:
|
||||
|
||||
```typescript
|
||||
const plugin = definePlugin({
|
||||
manifest: { /* ... */ },
|
||||
runtime: {
|
||||
metadata: {
|
||||
runtimeId: "paperclip",
|
||||
name: "Paperclip Runtime",
|
||||
description: "Paperclip-backed AI session using the user's configured pi provider and model",
|
||||
version: "1.0.0",
|
||||
},
|
||||
factory: paperclipRuntimeFactory,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Runtime Factory
|
||||
|
||||
The factory function creates a new `PaperclipRuntimeAdapter` instance when the runtime is resolved:
|
||||
|
||||
```typescript
|
||||
async function paperclipRuntimeFactory(): Promise<PaperclipRuntimeAdapter> {
|
||||
return new PaperclipRuntimeAdapter();
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [FN-2256](https://github.com/gsxdsm/fusion/issues/FN-2256) — Runtime contract definition
|
||||
- [FN-2260](https://github.com/gsxdsm/fusion/issues/FN-2260) — Plugin scaffold
|
||||
- [Runtime Resolution](../packages/engine/src/runtime-resolution.ts) — Engine runtime resolution implementation
|
||||
|
||||
Reference in New Issue
Block a user