@agentproto/adapter-pi 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/MCP-BRIDGE.md +132 -0
- package/PI-RPC.md +158 -0
- package/PI.md +103 -0
- package/README.md +87 -0
- package/SANDBOX.md +63 -0
- package/SECRETS.md +48 -0
- package/dist/index.d.ts +209 -0
- package/dist/index.mjs +18885 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mcp-bridge-extension.mjs +18333 -0
- package/dist/mcp-bridge-extension.mjs.map +1 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# @agentproto/adapter-pi
|
|
2
|
+
|
|
3
|
+
AIP-45 AGENT-CLI adapter for **[earendil-works/pi](https://github.com/earendil-works/pi)**
|
|
4
|
+
(`@earendil-works/pi-coding-agent`) — an MIT, headless TypeScript coding
|
|
5
|
+
agent. This adapter drives pi over its **persistent JSON-over-stdio RPC mode**
|
|
6
|
+
(`pi --mode rpc`), spawned as a real child process.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { pi, piRuntime } from "@agentproto/adapter-pi"
|
|
10
|
+
|
|
11
|
+
const session = await piRuntime().start()
|
|
12
|
+
for await (const evt of session.send({ role: "user", content: "list the files" })) {
|
|
13
|
+
console.log(evt.kind)
|
|
14
|
+
}
|
|
15
|
+
await session.close()
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## MCP support — bridged into pi tools
|
|
19
|
+
|
|
20
|
+
Pi ships **no native MCP client** — but this adapter closes that gap. When the
|
|
21
|
+
host injects `mcpServers` into `connect()` (the daemon's orchestration gateway,
|
|
22
|
+
or any scoped toolset), the adapter **bridges** them into pi by exploiting pi's
|
|
23
|
+
own TypeScript **extension** system:
|
|
24
|
+
|
|
25
|
+
1. At `connect()`, it enumerates each server's tools (`tools/list`), writes a
|
|
26
|
+
per-session config JSON, and spawns pi with `-e <mcp-bridge-extension.mjs>`
|
|
27
|
+
plus `PI_MCP_BRIDGE_CONFIG`.
|
|
28
|
+
2. The bundled extension registers **one pi tool per MCP tool** (namespaced
|
|
29
|
+
`mcp__<server>__<tool>`); each tool's `execute` proxies the call to the MCP
|
|
30
|
+
server over `@modelcontextprotocol/sdk`.
|
|
31
|
+
|
|
32
|
+
Net result: pi gains agentproto's full injected toolset, **including
|
|
33
|
+
`agent_start`** when the daemon injects its gateway (`--orchestrator` flag),
|
|
34
|
+
enabling sub-agent orchestration (`capabilities.sub_agents: true`). When no
|
|
35
|
+
MCP servers are injected, behavior is unchanged (pi runs only its own
|
|
36
|
+
built-in file/shell tools). Full mechanism, limitations, and caveats
|
|
37
|
+
(image/binary-content, cancellation): [`MCP-BRIDGE.md`](./MCP-BRIDGE.md).
|
|
38
|
+
|
|
39
|
+
## What it is
|
|
40
|
+
|
|
41
|
+
Because pi has no native ACP/MCP protocol surface, this is a
|
|
42
|
+
`protocol: "proprietary"` manifest:
|
|
43
|
+
`createAgentCliRuntime` skips the built-in ACP/print subprocess plumbing and
|
|
44
|
+
instead dynamic-imports this package's `createAgentCliClient(definition)`
|
|
45
|
+
factory (see `createProprietaryProtocolArm` in `@agentproto/driver-agent-cli`).
|
|
46
|
+
Unlike `@agentproto/adapter-mastracode-inprocess` (the in-process proprietary
|
|
47
|
+
arm), **this arm spawns a real child** (`pi --mode rpc`) and translates pi's
|
|
48
|
+
RPC event stream into the canonical `StreamEvent` taxonomy.
|
|
49
|
+
|
|
50
|
+
- **Multi-provider** — Anthropic, OpenAI, Google (Gemini). One provider key
|
|
51
|
+
minimum. See [`SECRETS.md`](./SECRETS.md).
|
|
52
|
+
- **Streaming** — text + thinking deltas, tool-call/result lifecycle.
|
|
53
|
+
- **Live duplex** — pi's RPC mode supports `steer` / `follow_up` / `abort`
|
|
54
|
+
mid-turn (`capabilities.bidirectional: true`).
|
|
55
|
+
- **Resumable** — pi persists sessions; the client captures pi's session id
|
|
56
|
+
from `get_state` and reattaches via `--session <id>`
|
|
57
|
+
(`continuation.default: "native-resume"`).
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
| Option | Type | Notes |
|
|
62
|
+
| -------- | ------ | ----- |
|
|
63
|
+
| `model` | string | Passed to pi's `--model` (accepts `provider/id`, e.g. `anthropic/claude-sonnet-4-5`). |
|
|
64
|
+
| `effort` | enum | Thinking level, mapped 1:1 to pi's `set_thinking_level`: `off \| minimal \| low \| medium \| high \| xhigh`. |
|
|
65
|
+
|
|
66
|
+
The pi binary is resolved from `definition.bin` (`pi`), overridable via the
|
|
67
|
+
`AGENTPROTO_PI_BIN` env var (used by the gated smoke test to point at a local
|
|
68
|
+
install without a global `pi` on PATH).
|
|
69
|
+
|
|
70
|
+
## Safety
|
|
71
|
+
|
|
72
|
+
Pi has **no built-in permission system** — file, process, network and
|
|
73
|
+
credential access run with the launching user's permissions, and non-interactive
|
|
74
|
+
modes (including `--mode rpc`) show no trust prompt. Treat a pi session as
|
|
75
|
+
arbitrary code execution. See [`SANDBOX.md`](./SANDBOX.md).
|
|
76
|
+
|
|
77
|
+
## Docs in this package
|
|
78
|
+
|
|
79
|
+
- [`PI.md`](./PI.md) — AIP-45 manifest overview.
|
|
80
|
+
- [`PI-RPC.md`](./PI-RPC.md) — the reverse-engineered RPC wire profile + the
|
|
81
|
+
pi-event → `StreamEvent` mapping table.
|
|
82
|
+
- [`SECRETS.md`](./SECRETS.md) — provider env slots.
|
|
83
|
+
- [`SANDBOX.md`](./SANDBOX.md) — no built-in permissions; containerization.
|
|
84
|
+
|
|
85
|
+
Built against pi **0.80.3**. The event/command wire profile was
|
|
86
|
+
reverse-engineered from pi source (`packages/coding-agent/src/modes/rpc/*` +
|
|
87
|
+
`core/agent-session.ts`); see `PI-RPC.md`.
|
package/SANDBOX.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Pi — sandbox & safety profile
|
|
2
|
+
|
|
3
|
+
## Pi has NO built-in permission system
|
|
4
|
+
|
|
5
|
+
This is not an opinion — it is pi's own documented position. From pi's
|
|
6
|
+
README (`## Permissions & Containerization`):
|
|
7
|
+
|
|
8
|
+
> Pi does not include a built-in permission system for restricting filesystem,
|
|
9
|
+
> process, network, or credential access. By default, it runs with the
|
|
10
|
+
> permissions of the user and process that launched it.
|
|
11
|
+
|
|
12
|
+
And, critically for this adapter, from pi's coding-agent README:
|
|
13
|
+
|
|
14
|
+
> Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a
|
|
15
|
+
> trust prompt.
|
|
16
|
+
|
|
17
|
+
> **No permission popups.** Run in a container, or build your own confirmation
|
|
18
|
+
> flow with extensions inline with your environment and security requirements.
|
|
19
|
+
|
|
20
|
+
> **Security:** Pi packages run with full system access. Extensions execute
|
|
21
|
+
> arbitrary code, and skills can instruct the model to perform any action
|
|
22
|
+
> including running executables.
|
|
23
|
+
|
|
24
|
+
Because this adapter drives pi via `--mode rpc` — a **non-interactive** mode —
|
|
25
|
+
there is **no trust prompt and no approval gate**. Every `bash`, `write`,
|
|
26
|
+
`edit` the model decides to run executes immediately with the launching
|
|
27
|
+
process's full OS permissions.
|
|
28
|
+
|
|
29
|
+
**Treat a pi session as arbitrary code execution on the host.**
|
|
30
|
+
|
|
31
|
+
## Recommendation: containerize
|
|
32
|
+
|
|
33
|
+
Pi's own guidance is to sandbox the whole process. Do not run this adapter
|
|
34
|
+
against untrusted repos or prompts on a host you care about. Pi documents three
|
|
35
|
+
patterns in `packages/coding-agent/docs/containerization.md`:
|
|
36
|
+
|
|
37
|
+
- run pi inside a Docker/OCI container scoped to the target workspace;
|
|
38
|
+
- restrict network egress at the container/VM boundary;
|
|
39
|
+
- **OpenShell** — run the whole `pi` process in a policy-controlled sandbox.
|
|
40
|
+
|
|
41
|
+
Prefer running the agentproto daemon (and therefore the spawned `pi --mode rpc`
|
|
42
|
+
child) inside such a boundary, with only the target working directory mounted
|
|
43
|
+
and only the provider API egress it needs.
|
|
44
|
+
|
|
45
|
+
## MCP substrate is unavailable (defense-in-depth note)
|
|
46
|
+
|
|
47
|
+
Pi has no MCP, so the daemon **cannot** narrow pi's tool surface by mounting a
|
|
48
|
+
curated MCP toolset — pi always exposes its own built-in file/shell tools, and
|
|
49
|
+
`connect({ mcpServers })` is ignored (with a one-time warning). There is no
|
|
50
|
+
"allowed tools" lever at the protocol layer here: the only enforcement boundary
|
|
51
|
+
is the OS/container sandbox you place pi in. This is a meaningful difference
|
|
52
|
+
from the ACP adapters, where the host chooses the mounted toolset.
|
|
53
|
+
|
|
54
|
+
## What the adapter does / doesn't isolate
|
|
55
|
+
|
|
56
|
+
- **Working directory** — the runner spawns `pi --mode rpc` with the
|
|
57
|
+
host-chosen `cwd`; pi's file tools operate relative to it. This is scoping,
|
|
58
|
+
not a security boundary.
|
|
59
|
+
- **Env / secrets** — only the runner-injected env (provider keys + host env)
|
|
60
|
+
reaches the child. Keys are never logged.
|
|
61
|
+
- **Process** — the adapter owns the child and kills it (`SIGTERM`, after
|
|
62
|
+
`stdin.end()`) on `close()` / abort. It does **not** confine what the child
|
|
63
|
+
does while alive. That is the sandbox's job.
|
package/SECRETS.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-secrets
|
|
3
|
+
id: pi-secrets
|
|
4
|
+
description: Secret slots pi reads at boot. At minimum ONE model-provider key MUST be present — pi routes each turn to whichever provider the selected model belongs to (Anthropic / OpenAI / Google).
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
slots:
|
|
7
|
+
- name: ANTHROPIC_API_KEY
|
|
8
|
+
description: Anthropic API key — enables `anthropic/claude-*` models (adapter default provider).
|
|
9
|
+
required: false
|
|
10
|
+
sensitivity: high
|
|
11
|
+
- name: OPENAI_API_KEY
|
|
12
|
+
description: OpenAI API key — enables `openai/gpt-*` models.
|
|
13
|
+
required: false
|
|
14
|
+
sensitivity: high
|
|
15
|
+
- name: GOOGLE_GENERATIVE_AI_API_KEY
|
|
16
|
+
description: Google Generative AI (Gemini) key — enables `google/gemini-*` models.
|
|
17
|
+
required: false
|
|
18
|
+
sensitivity: high
|
|
19
|
+
constraints:
|
|
20
|
+
- kind: at-least-one-of
|
|
21
|
+
of:
|
|
22
|
+
- ANTHROPIC_API_KEY
|
|
23
|
+
- OPENAI_API_KEY
|
|
24
|
+
- GOOGLE_GENERATIVE_AI_API_KEY
|
|
25
|
+
tags: [pi, secrets, model-providers]
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Pi — secrets inventory
|
|
29
|
+
|
|
30
|
+
Pi routes each turn to the provider that owns the selected model. The adapter
|
|
31
|
+
declares the three provider key slots pi's supported providers read from the
|
|
32
|
+
process environment:
|
|
33
|
+
|
|
34
|
+
| Env var | Provider | Unlocks |
|
|
35
|
+
| ------- | -------- | ------- |
|
|
36
|
+
| `ANTHROPIC_API_KEY` | Anthropic | `anthropic/claude-*` (adapter default) |
|
|
37
|
+
| `OPENAI_API_KEY` | OpenAI | `openai/gpt-*` |
|
|
38
|
+
| `GOOGLE_GENERATIVE_AI_API_KEY` | Google | `google/gemini-*` |
|
|
39
|
+
|
|
40
|
+
**At least one** must be present, and it must match the provider of the model
|
|
41
|
+
you route to (`models.default` is `anthropic/claude-sonnet-4-5`, so
|
|
42
|
+
`ANTHROPIC_API_KEY` is the natural minimum). Keys are injected into the spawned
|
|
43
|
+
`pi --mode rpc` child's environment by the runner (from the workspace secrets
|
|
44
|
+
store) and are never logged.
|
|
45
|
+
|
|
46
|
+
Pi also accepts a per-invocation `--api-key`, but this adapter relies on the
|
|
47
|
+
env slots above so key material flows through the runner's secrets pipeline
|
|
48
|
+
rather than argv.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { AgentCliHandle, AgentCliClient, StreamEvent, AgentCliRuntime } from '@agentproto/driver-agent-cli';
|
|
2
|
+
export { AgentCliHandle, AgentCliRuntime } from '@agentproto/driver-agent-cli';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `AgentCliClient` for pi (`@earendil-works/pi-coding-agent`), driven over
|
|
6
|
+
* its persistent JSON-over-stdio RPC mode.
|
|
7
|
+
*
|
|
8
|
+
* Unlike `@agentproto/adapter-mastracode-inprocess` (the other
|
|
9
|
+
* `protocol: "proprietary"` arm, which runs in-process), this arm spawns a
|
|
10
|
+
* real child: `pi --mode rpc`. It writes RPC commands (LF-delimited JSON) to
|
|
11
|
+
* the child's stdin and reads pi's response + `AgentSessionEvent` stream from
|
|
12
|
+
* stdout, translating the events into agentproto `StreamEvent`s.
|
|
13
|
+
*
|
|
14
|
+
* ## MCP support — bridged via a generated pi extension
|
|
15
|
+
*
|
|
16
|
+
* Pi ships neither ACP nor MCP. The proprietary arm's `connect()` receives
|
|
17
|
+
* `mcpServers` (the host may inject the daemon's own orchestration gateway or
|
|
18
|
+
* any scoped toolset). Pi cannot mount MCP natively, so this arm bridges them:
|
|
19
|
+
* it enumerates each server's tools up-front, writes a per-session config JSON,
|
|
20
|
+
* and spawns pi with `-e <mcp-bridge-extension.mjs>` + `PI_MCP_BRIDGE_CONFIG`.
|
|
21
|
+
* The extension registers one pi tool per MCP tool and proxies calls over
|
|
22
|
+
* `@modelcontextprotocol/sdk`. See ../MCP-BRIDGE.md. When no MCP servers are
|
|
23
|
+
* injected, behavior is unchanged (pi runs only its own file/shell tools).
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
declare function createAgentCliClient(definition: AgentCliHandle): AgentCliClient;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Pi RPC wire types + the pure pi-event → {@link StreamEvent} mapper.
|
|
30
|
+
*
|
|
31
|
+
* Pi (`@earendil-works/pi-coding-agent`) exposes a persistent
|
|
32
|
+
* JSON-over-stdio RPC mode (`pi --mode rpc`). Its stdout carries two
|
|
33
|
+
* kinds of LF-delimited JSON records:
|
|
34
|
+
*
|
|
35
|
+
* 1. **Responses** — `{ type: "response", command, success, id?, data?, error? }`,
|
|
36
|
+
* correlated to a command by the `id` echoed back. Handled by the
|
|
37
|
+
* client's request/response layer.
|
|
38
|
+
* 2. **Session events** — the `AgentSessionEvent` union emitted by pi's
|
|
39
|
+
* `session.subscribe(...)` (assistant text/thinking deltas, tool
|
|
40
|
+
* execution lifecycle, turn/agent lifecycle). These are what this
|
|
41
|
+
* module narrows and maps onto agentproto's canonical taxonomy.
|
|
42
|
+
*
|
|
43
|
+
* Everything here is pure and synchronous so it can be unit-tested
|
|
44
|
+
* against hand-built pi records without spawning a real `pi`.
|
|
45
|
+
*
|
|
46
|
+
* Wire profile documented in ../PI-RPC.md.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/** Pi `StopReason` (packages/ai/src/types.ts). */
|
|
50
|
+
type PiStopReason = "stop" | "length" | "toolUse" | "error" | "aborted";
|
|
51
|
+
/** Pi `Usage` (packages/ai/src/types.ts) — token + cost accounting on an
|
|
52
|
+
* assistant message. Only the fields this adapter surfaces are modelled. */
|
|
53
|
+
interface PiUsage {
|
|
54
|
+
input: number;
|
|
55
|
+
output: number;
|
|
56
|
+
totalTokens: number;
|
|
57
|
+
cost: {
|
|
58
|
+
total: number;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Minimal shape of an assistant `AgentMessage` carried on `turn_end`. */
|
|
62
|
+
interface PiTurnMessage {
|
|
63
|
+
role: string;
|
|
64
|
+
stopReason?: PiStopReason;
|
|
65
|
+
usage?: PiUsage;
|
|
66
|
+
errorMessage?: string;
|
|
67
|
+
}
|
|
68
|
+
/** Assistant-message-event types this adapter does NOT translate but must
|
|
69
|
+
* still discriminate cleanly (keeps `PiAssistantMessageEvent` exhaustive). */
|
|
70
|
+
type PiIgnoredAssistantEventType = "start" | "text_start" | "text_end" | "thinking_start" | "thinking_end" | "toolcall_start" | "toolcall_delta" | "toolcall_end";
|
|
71
|
+
/** Pi `AssistantMessageEvent` (packages/ai/src/types.ts), narrowed to the
|
|
72
|
+
* fields this adapter reads. Streaming deltas + the terminal done/error. */
|
|
73
|
+
type PiAssistantMessageEvent = {
|
|
74
|
+
type: "text_delta";
|
|
75
|
+
delta: string;
|
|
76
|
+
} | {
|
|
77
|
+
type: "thinking_delta";
|
|
78
|
+
delta: string;
|
|
79
|
+
} | {
|
|
80
|
+
type: "done";
|
|
81
|
+
reason: "stop" | "length" | "toolUse";
|
|
82
|
+
} | {
|
|
83
|
+
type: "error";
|
|
84
|
+
reason: "error" | "aborted";
|
|
85
|
+
errorMessage?: string;
|
|
86
|
+
} | {
|
|
87
|
+
type: PiIgnoredAssistantEventType;
|
|
88
|
+
};
|
|
89
|
+
/** Pi `AgentSessionEvent` (packages/coding-agent/src/core/agent-session.ts +
|
|
90
|
+
* packages/agent/src/types.ts `AgentEvent`), narrowed to the events this
|
|
91
|
+
* adapter acts on. Any other pi event is dropped before it reaches here. */
|
|
92
|
+
type PiSessionEvent = {
|
|
93
|
+
type: "agent_start";
|
|
94
|
+
} | {
|
|
95
|
+
type: "agent_end";
|
|
96
|
+
willRetry?: boolean;
|
|
97
|
+
} | {
|
|
98
|
+
type: "turn_start";
|
|
99
|
+
} | {
|
|
100
|
+
type: "turn_end";
|
|
101
|
+
message?: PiTurnMessage;
|
|
102
|
+
} | {
|
|
103
|
+
type: "message_update";
|
|
104
|
+
assistantMessageEvent: PiAssistantMessageEvent;
|
|
105
|
+
} | {
|
|
106
|
+
type: "tool_execution_start";
|
|
107
|
+
toolCallId: string;
|
|
108
|
+
toolName: string;
|
|
109
|
+
args: unknown;
|
|
110
|
+
} | {
|
|
111
|
+
type: "tool_execution_end";
|
|
112
|
+
toolCallId: string;
|
|
113
|
+
toolName: string;
|
|
114
|
+
result: unknown;
|
|
115
|
+
isError: boolean;
|
|
116
|
+
} | {
|
|
117
|
+
type: "agent_settled";
|
|
118
|
+
};
|
|
119
|
+
/** A pi RPC response line (`type: "response"`). */
|
|
120
|
+
interface PiResponse {
|
|
121
|
+
type: "response";
|
|
122
|
+
id?: string;
|
|
123
|
+
command: string;
|
|
124
|
+
success: boolean;
|
|
125
|
+
error?: string;
|
|
126
|
+
data?: unknown;
|
|
127
|
+
}
|
|
128
|
+
/** Classified pi stdout line. `other` covers extension-UI requests, the
|
|
129
|
+
* json-mode session header, and anything this adapter ignores. */
|
|
130
|
+
type PiOutbound = {
|
|
131
|
+
kind: "response";
|
|
132
|
+
response: PiResponse;
|
|
133
|
+
} | {
|
|
134
|
+
kind: "event";
|
|
135
|
+
event: PiSessionEvent;
|
|
136
|
+
} | {
|
|
137
|
+
kind: "other";
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Parse + classify one pi stdout JSON line. Returns `{ kind: "other" }` for
|
|
141
|
+
* malformed lines and any record this adapter does not act on, so the caller
|
|
142
|
+
* can uniformly ignore them.
|
|
143
|
+
*/
|
|
144
|
+
declare function classifyPiLine(line: string): PiOutbound;
|
|
145
|
+
/** Carried across a turn's events — pi reports the stop reason mid-stream
|
|
146
|
+
* (`message_update` done/error, `turn_end.message.stopReason`) but the
|
|
147
|
+
* turn only truly closes on `agent_settled`, so it must be remembered. */
|
|
148
|
+
interface PiMapperState {
|
|
149
|
+
lastStopReason: PiStopReason | undefined;
|
|
150
|
+
}
|
|
151
|
+
declare function createPiMapperState(): PiMapperState;
|
|
152
|
+
/** Reset for a fresh turn (call in the client's `send`). */
|
|
153
|
+
declare function resetPiMapperState(state: PiMapperState): void;
|
|
154
|
+
/** Map a pi `StopReason` onto the canonical `turn-end` reason.
|
|
155
|
+
* `length` (token/context cap) has no exact equivalent; `max_turns` is the
|
|
156
|
+
* closest "hit a budget limit" reason. `toolUse` is never the settled
|
|
157
|
+
* reason (the loop keeps going) but falls back to `completed` defensively. */
|
|
158
|
+
declare function mapStopReason(reason: PiStopReason | undefined): "completed" | "cancelled" | "max_turns" | "error";
|
|
159
|
+
/**
|
|
160
|
+
* Translate one pi session event into zero or more {@link StreamEvent}s,
|
|
161
|
+
* updating `state` in place. Pure aside from the state mutation.
|
|
162
|
+
*
|
|
163
|
+
* `agent_end` (with `willRetry` false) is the turn terminator: it flushes a
|
|
164
|
+
* `turn-end` whose reason reflects the stop reason accumulated over the turn.
|
|
165
|
+
* An `agent_end` with `willRetry: true` (auto-retry) does NOT close the turn —
|
|
166
|
+
* pi will run again and emit a final `agent_end`. NOTE: pi's `agent_settled`
|
|
167
|
+
* event is emitted to in-process extension listeners but is NOT written to the
|
|
168
|
+
* RPC stdout stream (verified empirically against pi 0.80.3), so it cannot be
|
|
169
|
+
* relied on as the terminator — see PI-RPC.md.
|
|
170
|
+
*/
|
|
171
|
+
declare function mapPiEvent(event: PiSessionEvent, sessionId: string, state: PiMapperState): StreamEvent[];
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @agentproto/adapter-pi — AIP-45 adapter for **earendil-works/pi**
|
|
175
|
+
* (`@earendil-works/pi-coding-agent`), an MIT TypeScript headless coding
|
|
176
|
+
* agent.
|
|
177
|
+
*
|
|
178
|
+
* Pi ships **no ACP and no MCP** — but it does ship a persistent
|
|
179
|
+
* JSON-over-stdio RPC mode (`pi --mode rpc`). So this is a
|
|
180
|
+
* `protocol: "proprietary"` manifest: `createAgentCliRuntime` skips the
|
|
181
|
+
* built-in ACP/print subprocess plumbing and instead dynamic-imports this
|
|
182
|
+
* package's `createAgentCliClient(definition)` factory (see
|
|
183
|
+
* `createProprietaryProtocolArm` in `@agentproto/driver-agent-cli`). Unlike
|
|
184
|
+
* the in-process mastracode arm, THIS arm spawns a real child (`pi --mode
|
|
185
|
+
* rpc`) and translates pi's RPC event stream — see `./client.ts`.
|
|
186
|
+
*
|
|
187
|
+
* import { pi, piRuntime } from "@agentproto/adapter-pi"
|
|
188
|
+
* const session = await piRuntime().start()
|
|
189
|
+
* for await (const evt of session.send({ role: "user", content: "..." })) {
|
|
190
|
+
* console.log(evt)
|
|
191
|
+
* }
|
|
192
|
+
* await session.close()
|
|
193
|
+
*
|
|
194
|
+
* ## MCP support — bridged via a generated pi extension
|
|
195
|
+
*
|
|
196
|
+
* Pi has no native MCP client, but the proprietary arm's `connect()` receives
|
|
197
|
+
* `mcpServers` and now bridges them: it enumerates each server's tools, writes a
|
|
198
|
+
* per-session config, and spawns pi with `-e <mcp-bridge-extension.mjs>` so the
|
|
199
|
+
* extension registers one pi tool per MCP tool (proxying calls over
|
|
200
|
+
* `@modelcontextprotocol/sdk`). Injected toolsets — including the daemon's
|
|
201
|
+
* `agent_start` orchestration gateway — become callable from pi. When no MCP
|
|
202
|
+
* servers are injected, pi runs only its own built-in file/shell tools. See
|
|
203
|
+
* MCP-BRIDGE.md, README.md, and SANDBOX.md.
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
declare const pi: AgentCliHandle;
|
|
207
|
+
declare function piRuntime(): AgentCliRuntime;
|
|
208
|
+
|
|
209
|
+
export { type PiAssistantMessageEvent, type PiMapperState, type PiOutbound, type PiResponse, type PiSessionEvent, type PiStopReason, type PiTurnMessage, type PiUsage, classifyPiLine, createAgentCliClient, createPiMapperState, mapPiEvent, mapStopReason, pi, piRuntime, resetPiMapperState };
|