@minzicat/pi-team 0.1.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/Dockerfile +82 -0
- package/LICENSE +21 -0
- package/README.md +114 -0
- package/bin/pi-team.js +2 -0
- package/dist/agent.js +252 -0
- package/dist/agent.js.map +1 -0
- package/dist/cli.js +371 -0
- package/dist/cli.js.map +1 -0
- package/dist/http-inject.js +136 -0
- package/dist/http-inject.js.map +1 -0
- package/dist/inject-server.js +101 -0
- package/dist/inject-server.js.map +1 -0
- package/dist/observer.js +151 -0
- package/dist/observer.js.map +1 -0
- package/dist/orchestra.js +192 -0
- package/dist/orchestra.js.map +1 -0
- package/dist/tmux.js +54 -0
- package/dist/tmux.js.map +1 -0
- package/dist/transcript.js +71 -0
- package/dist/transcript.js.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/usage/plans.js +214 -0
- package/dist/usage/plans.js.map +1 -0
- package/dist/usage/reporter.js +69 -0
- package/dist/usage/reporter.js.map +1 -0
- package/dist/usage/tracker.js +200 -0
- package/dist/usage/tracker.js.map +1 -0
- package/dist/usage/types.js +18 -0
- package/dist/usage/types.js.map +1 -0
- package/docker/entrypoint.sh +94 -0
- package/docker-compose.yml +28 -0
- package/examples/emotion-debate-topic.md +20 -0
- package/examples/emotion-debate.sh +20 -0
- package/package.json +60 -0
package/Dockerfile
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1.7
|
|
2
|
+
|
|
3
|
+
# pi-team container image
|
|
4
|
+
# - Node 20 base
|
|
5
|
+
# - pi coding agent (global install)
|
|
6
|
+
# - tmux for session layout
|
|
7
|
+
# - ttyd for web-based tmux observation
|
|
8
|
+
# - pi-team (from this repo)
|
|
9
|
+
#
|
|
10
|
+
# Runtime:
|
|
11
|
+
# docker run --rm -it \
|
|
12
|
+
# -e ANTHROPIC_API_KEY=... \
|
|
13
|
+
# -e OPENAI_API_KEY=... \
|
|
14
|
+
# -e PITEAM_NAME=emotions \
|
|
15
|
+
# -e PITEAM_AGENTS='claude:anthropic/claude-sonnet-4-5,codex:openai-codex/gpt-5.4:xhigh' \
|
|
16
|
+
# -e PITEAM_TOPIC_FILE=/topics/debate.md \
|
|
17
|
+
# -v $(pwd)/topics:/topics:ro \
|
|
18
|
+
# -p 7681:7681 -p 7682:7682 \
|
|
19
|
+
# ghcr.io/minzique/pi-team:latest
|
|
20
|
+
#
|
|
21
|
+
# Then:
|
|
22
|
+
# open http://localhost:7681/ (watch tmux in the browser)
|
|
23
|
+
# curl -X POST http://localhost:7682/inject -d 'human message' (inject)
|
|
24
|
+
|
|
25
|
+
FROM node:20-slim AS build
|
|
26
|
+
WORKDIR /app
|
|
27
|
+
|
|
28
|
+
# Install build deps first for layer caching
|
|
29
|
+
COPY package.json pnpm-lock.yaml* ./
|
|
30
|
+
RUN corepack enable && corepack prepare pnpm@10.18.2 --activate \
|
|
31
|
+
&& pnpm install --frozen-lockfile=false
|
|
32
|
+
|
|
33
|
+
COPY tsconfig.json ./
|
|
34
|
+
COPY src ./src
|
|
35
|
+
COPY bin ./bin
|
|
36
|
+
RUN pnpm build
|
|
37
|
+
|
|
38
|
+
# ---- runtime image ----
|
|
39
|
+
FROM node:20-slim AS runtime
|
|
40
|
+
WORKDIR /app
|
|
41
|
+
|
|
42
|
+
# System deps: tmux, ttyd (for web observation), netcat (socket inject), tini (PID 1)
|
|
43
|
+
RUN apt-get update \
|
|
44
|
+
&& apt-get install -y --no-install-recommends \
|
|
45
|
+
tmux \
|
|
46
|
+
netcat-openbsd \
|
|
47
|
+
tini \
|
|
48
|
+
ca-certificates \
|
|
49
|
+
curl \
|
|
50
|
+
bash \
|
|
51
|
+
&& curl -fsSL https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.$(uname -m) -o /usr/local/bin/ttyd \
|
|
52
|
+
&& chmod +x /usr/local/bin/ttyd \
|
|
53
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
54
|
+
|
|
55
|
+
# Install pi globally
|
|
56
|
+
RUN npm install -g @mariozechner/pi-coding-agent@latest
|
|
57
|
+
|
|
58
|
+
# Copy app artifacts
|
|
59
|
+
COPY --from=build /app/node_modules ./node_modules
|
|
60
|
+
COPY --from=build /app/dist ./dist
|
|
61
|
+
COPY --from=build /app/bin ./bin
|
|
62
|
+
COPY --from=build /app/package.json ./package.json
|
|
63
|
+
|
|
64
|
+
# Symlink the CLI onto PATH
|
|
65
|
+
RUN ln -sf /app/bin/pi-team.js /usr/local/bin/pi-team \
|
|
66
|
+
&& chmod +x /app/bin/pi-team.js
|
|
67
|
+
|
|
68
|
+
# Minimal tmux config for clean rendering
|
|
69
|
+
RUN printf 'set -g extended-keys on\nset -g extended-keys-format csi-u\nset -g mouse on\nset -g history-limit 50000\nset -g default-terminal "tmux-256color"\n' > /root/.tmux.conf
|
|
70
|
+
|
|
71
|
+
ENV PITEAM_HTTP_PORT=7682 \
|
|
72
|
+
PITEAM_TTYD_PORT=7681 \
|
|
73
|
+
PITEAM_SESSIONS_DIR=/data/sessions \
|
|
74
|
+
PATH=/usr/local/bin:/app/bin:$PATH
|
|
75
|
+
|
|
76
|
+
EXPOSE 7681 7682
|
|
77
|
+
VOLUME ["/data"]
|
|
78
|
+
|
|
79
|
+
COPY docker/entrypoint.sh /entrypoint.sh
|
|
80
|
+
RUN chmod +x /entrypoint.sh
|
|
81
|
+
|
|
82
|
+
ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"]
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 minzique
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# pi-team
|
|
2
|
+
|
|
3
|
+
Two or more LLMs in the same conversation. You can watch, and you can hop in.
|
|
4
|
+
|
|
5
|
+
Built on [pi](https://github.com/badlogic/pi-mono) RPC mode. Each agent is a real pi subprocess with its own model, tools, and session — the orchestrator just routes messages between them.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add -g @minzicat/pi-team
|
|
11
|
+
# or
|
|
12
|
+
npm i -g @minzicat/pi-team
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Requires: Node 20+, `pi` on PATH, `tmux` 3.2+.
|
|
16
|
+
|
|
17
|
+
## Use
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pi-team start \
|
|
21
|
+
--name emotions \
|
|
22
|
+
--agent claude:anthropic/claude-sonnet-4-5 \
|
|
23
|
+
--agent codex:openai-codex/gpt-5.4:xhigh \
|
|
24
|
+
--topic-file debate.md \
|
|
25
|
+
--max-turns 10
|
|
26
|
+
|
|
27
|
+
tmux attach -t piteam-emotions
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Three panes: stream, inject, log tail. Type in the inject pane to hop in — all agents see it at the next turn boundary. Detach with `Ctrl+b d`.
|
|
31
|
+
|
|
32
|
+
Agent spec: `name:provider/model[:thinking][@plan-id]`. The name is used as attribution and persona (`skeptic:anthropic/...`, `optimist:openai-codex/...`).
|
|
33
|
+
|
|
34
|
+
## Usage tracking
|
|
35
|
+
|
|
36
|
+
Pi's per-token dollar display is wrong if you're on a subscription — the real constraint is 5-hour and weekly usage limits. Declare your plan per agent to get window-based tracking:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pi-team start --name x \
|
|
40
|
+
--agent claude:anthropic/claude-sonnet-4-5@anthropic-max-20x \
|
|
41
|
+
--agent codex:openai-codex/gpt-5.4:xhigh@openai-plus \
|
|
42
|
+
--topic-file debate.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After every turn you get a per-agent status line:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
claude │ sonnet-4-5 │ 5h: 12/900–4500 msg (1%) · wk: 0.4/800 h anthropic-max-20x
|
|
49
|
+
codex │ gpt-5.4 │ 5h: 5/33–168 msg (15%) openai-plus
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Plans: `openai-plus`, `openai-pro`, `openai-business`, `anthropic-pro`, `anthropic-max-5x`, `anthropic-max-20x`, `api`. Run `pi-team plans` to list. Without a plan, pi-team falls back to `api` mode and shows raw token counts + pay-per-token dollar cost. Fetch snapshots programmatically at `GET /usage`.
|
|
53
|
+
|
|
54
|
+
## Commands
|
|
55
|
+
|
|
56
|
+
| | |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `pi-team start` | launch session in tmux (observable + injectable) |
|
|
59
|
+
| `pi-team run` | foreground, no tmux |
|
|
60
|
+
| `pi-team inject` | interactive stdin → running session |
|
|
61
|
+
| `pi-team stop` | kill session |
|
|
62
|
+
| `pi-team list` | active and archived sessions |
|
|
63
|
+
|
|
64
|
+
## Inject from anywhere
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# interactive
|
|
68
|
+
pi-team inject --name emotions
|
|
69
|
+
|
|
70
|
+
# unix socket
|
|
71
|
+
echo "your message" | nc -U ~/.pi/team/sessions/emotions/inject.sock
|
|
72
|
+
|
|
73
|
+
# HTTP (when --http-port is set)
|
|
74
|
+
curl -X POST http://localhost:7682/inject -d "push back on that last point"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
All three land the same way: queued, delivered at the next turn boundary, visible to every agent.
|
|
78
|
+
|
|
79
|
+
## Container
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
docker compose up --build
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `:7681` — ttyd web terminal on the tmux session
|
|
86
|
+
- `:7682` — HTTP API (`POST /inject`, `GET /state`, `GET /transcript`, `POST /stop`)
|
|
87
|
+
- `/data` — persistent session storage
|
|
88
|
+
|
|
89
|
+
Env: `PITEAM_NAME`, `PITEAM_AGENTS` (comma-separated specs), `PITEAM_TOPIC_FILE` or `PITEAM_TOPIC`, `PITEAM_MAX_TURNS`, `PITEAM_TTYD_CREDS` (basic auth), `PITEAM_HTTP_TOKEN` (bearer), `PITEAM_HTTP_HOST` (defaults to `127.0.0.1`; set to `0.0.0.0` only when token is also set).
|
|
90
|
+
|
|
91
|
+
## How it works
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
┌─ Orchestra ─────────────────────────────┐
|
|
95
|
+
│ Transcript (jsonl, single source) │
|
|
96
|
+
│ │ │
|
|
97
|
+
│ ├─► Agent A (pi --mode rpc) │
|
|
98
|
+
│ ├─► Agent B (pi --mode rpc) │
|
|
99
|
+
│ └─► Agent N ... │
|
|
100
|
+
│ ▲ │
|
|
101
|
+
│ │ │
|
|
102
|
+
│ ├─ Unix socket ─┐ │
|
|
103
|
+
│ ├─ HTTP POST ───┼── human inject │
|
|
104
|
+
│ └─ tmux pane ───┘ │
|
|
105
|
+
└─────────────────────────────────────────┘
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Round-robin by default. Each agent's pi session holds its own side; the orchestrator renders everything-since-last-turn with attribution (`[claude]: ...`, `[human]: ...`) as the next prompt. Injections drain at turn boundaries.
|
|
109
|
+
|
|
110
|
+
Every agent gets pi's full stack: tools, skills, extensions, thinking levels. The orchestrator is ~400 lines of TypeScript because pi does the hard work.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
package/bin/pi-team.js
ADDED
package/dist/agent.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent: a thin wrapper around a `pi --mode rpc` subprocess.
|
|
3
|
+
*
|
|
4
|
+
* Each agent runs its own pi instance with its own model and session file.
|
|
5
|
+
* The orchestrator calls `prompt(text)` and awaits the assistant's full reply.
|
|
6
|
+
*
|
|
7
|
+
* Wire format: JSONL. Every line to stdin is a command, every line from stdout
|
|
8
|
+
* is either a response (to a command) or an event (streamed during execution).
|
|
9
|
+
* We wait for `agent_end` to know a prompt turn is fully complete, then fetch
|
|
10
|
+
* the last assistant text via `get_last_assistant_text`.
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { EventEmitter } from "node:events";
|
|
14
|
+
import { mkdirSync } from "node:fs";
|
|
15
|
+
import { dirname } from "node:path";
|
|
16
|
+
/**
|
|
17
|
+
* Events emitted:
|
|
18
|
+
* - "delta" (agentName, text): streaming token from the assistant
|
|
19
|
+
* - "tool_start" (agentName, toolName, args)
|
|
20
|
+
* - "tool_end" (agentName, toolName, isError)
|
|
21
|
+
* - "error" (agentName, message)
|
|
22
|
+
* - "exit" (agentName, code)
|
|
23
|
+
*/
|
|
24
|
+
export class Agent extends EventEmitter {
|
|
25
|
+
opts;
|
|
26
|
+
name;
|
|
27
|
+
spec;
|
|
28
|
+
proc;
|
|
29
|
+
buffer = "";
|
|
30
|
+
nextReqId = 1;
|
|
31
|
+
pending = new Map();
|
|
32
|
+
streaming = false;
|
|
33
|
+
currentTurnText = "";
|
|
34
|
+
turnResolver = null;
|
|
35
|
+
turnRejector = null;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
super();
|
|
38
|
+
this.opts = opts;
|
|
39
|
+
this.name = opts.spec.name;
|
|
40
|
+
this.spec = opts.spec;
|
|
41
|
+
}
|
|
42
|
+
async start() {
|
|
43
|
+
mkdirSync(dirname(this.opts.sessionPath), { recursive: true });
|
|
44
|
+
const args = [
|
|
45
|
+
"--mode",
|
|
46
|
+
"rpc",
|
|
47
|
+
"--provider",
|
|
48
|
+
this.spec.provider,
|
|
49
|
+
"--model",
|
|
50
|
+
this.spec.model,
|
|
51
|
+
"--session",
|
|
52
|
+
this.opts.sessionPath,
|
|
53
|
+
];
|
|
54
|
+
if (this.spec.thinking) {
|
|
55
|
+
args.push("--thinking", this.spec.thinking);
|
|
56
|
+
}
|
|
57
|
+
if (this.opts.systemPromptFile) {
|
|
58
|
+
args.push("--append-system-prompt", this.opts.systemPromptFile);
|
|
59
|
+
}
|
|
60
|
+
this.proc = spawn("pi", args, {
|
|
61
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
62
|
+
env: { ...process.env, ...(this.opts.env ?? {}) },
|
|
63
|
+
});
|
|
64
|
+
this.proc.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
65
|
+
this.proc.stderr.on("data", (chunk) => {
|
|
66
|
+
const text = chunk.toString("utf8");
|
|
67
|
+
// pi can be chatty to stderr during startup; only emit as error if prefixed
|
|
68
|
+
if (/error|Error|ERROR/.test(text)) {
|
|
69
|
+
this.emit("stderr", this.name, text);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
this.proc.on("exit", (code) => {
|
|
73
|
+
this.emit("exit", this.name, code);
|
|
74
|
+
for (const pending of this.pending.values()) {
|
|
75
|
+
pending.reject(new Error(`pi process for "${this.name}" exited with code ${code}`));
|
|
76
|
+
}
|
|
77
|
+
this.pending.clear();
|
|
78
|
+
if (this.turnRejector) {
|
|
79
|
+
this.turnRejector(new Error(`agent "${this.name}" exited mid-turn`));
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Wait for the process to be ready. We send a cheap get_state ping.
|
|
83
|
+
await this.waitForReady();
|
|
84
|
+
}
|
|
85
|
+
async waitForReady() {
|
|
86
|
+
// pi RPC mode is ready as soon as it reads stdin. Send get_state and wait
|
|
87
|
+
// up to 30s for a response. If it fails, start() rejects.
|
|
88
|
+
const deadline = Date.now() + 30_000;
|
|
89
|
+
while (Date.now() < deadline) {
|
|
90
|
+
try {
|
|
91
|
+
await this.sendCommand("get_state", {}, 5_000);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
throw new Error(`agent "${this.name}" did not become ready within 30s`);
|
|
99
|
+
}
|
|
100
|
+
onStdout(chunk) {
|
|
101
|
+
this.buffer += chunk.toString("utf8");
|
|
102
|
+
while (true) {
|
|
103
|
+
const nl = this.buffer.indexOf("\n");
|
|
104
|
+
if (nl === -1)
|
|
105
|
+
break;
|
|
106
|
+
let line = this.buffer.slice(0, nl);
|
|
107
|
+
this.buffer = this.buffer.slice(nl + 1);
|
|
108
|
+
if (line.endsWith("\r"))
|
|
109
|
+
line = line.slice(0, -1);
|
|
110
|
+
if (!line.trim())
|
|
111
|
+
continue;
|
|
112
|
+
try {
|
|
113
|
+
const msg = JSON.parse(line);
|
|
114
|
+
this.handleRpcMessage(msg);
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
// Not JSON — pi sometimes prints warnings to stdout. Ignore.
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
handleRpcMessage(msg) {
|
|
122
|
+
const type = msg.type;
|
|
123
|
+
// Response to a command
|
|
124
|
+
if (type === "response") {
|
|
125
|
+
const id = msg.id;
|
|
126
|
+
if (id && this.pending.has(id)) {
|
|
127
|
+
const p = this.pending.get(id);
|
|
128
|
+
this.pending.delete(id);
|
|
129
|
+
if (msg.success) {
|
|
130
|
+
p.resolve(msg.data);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
p.reject(new Error(msg.error ?? "rpc error"));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Streaming events — we care about text deltas and turn boundaries
|
|
139
|
+
if (type === "agent_start") {
|
|
140
|
+
this.streaming = true;
|
|
141
|
+
this.currentTurnText = "";
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (type === "message_update") {
|
|
145
|
+
const evt = msg.assistantMessageEvent;
|
|
146
|
+
if (evt?.type === "text_delta" && evt.delta) {
|
|
147
|
+
this.currentTurnText += evt.delta;
|
|
148
|
+
this.emit("delta", this.name, evt.delta);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (type === "tool_execution_start") {
|
|
153
|
+
this.emit("tool_start", this.name, msg.toolName, msg.args);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (type === "tool_execution_end") {
|
|
157
|
+
this.emit("tool_end", this.name, msg.toolName, msg.isError);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (type === "agent_end") {
|
|
161
|
+
this.streaming = false;
|
|
162
|
+
const text = this.currentTurnText;
|
|
163
|
+
this.currentTurnText = "";
|
|
164
|
+
if (this.turnResolver) {
|
|
165
|
+
this.turnResolver(text);
|
|
166
|
+
this.turnResolver = null;
|
|
167
|
+
this.turnRejector = null;
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
sendCommand(type, payload, timeoutMs = 120_000) {
|
|
173
|
+
const id = `req-${this.nextReqId++}`;
|
|
174
|
+
const cmd = { id, type, ...payload };
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
const timer = setTimeout(() => {
|
|
177
|
+
if (this.pending.has(id)) {
|
|
178
|
+
this.pending.delete(id);
|
|
179
|
+
reject(new Error(`rpc timeout on ${type}`));
|
|
180
|
+
}
|
|
181
|
+
}, timeoutMs);
|
|
182
|
+
this.pending.set(id, {
|
|
183
|
+
resolve: (data) => {
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
resolve(data);
|
|
186
|
+
},
|
|
187
|
+
reject: (err) => {
|
|
188
|
+
clearTimeout(timer);
|
|
189
|
+
reject(err);
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
this.proc.stdin.write(`${JSON.stringify(cmd)}\n`);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Send a user message and await the full assistant response text.
|
|
197
|
+
* Returns the concatenated assistant text for this turn (excluding tools).
|
|
198
|
+
*/
|
|
199
|
+
async prompt(message, timeoutMs = 20 * 60 * 1000) {
|
|
200
|
+
if (this.streaming) {
|
|
201
|
+
throw new Error(`agent "${this.name}" is already streaming`);
|
|
202
|
+
}
|
|
203
|
+
const textPromise = new Promise((resolve, reject) => {
|
|
204
|
+
this.turnResolver = resolve;
|
|
205
|
+
this.turnRejector = reject;
|
|
206
|
+
});
|
|
207
|
+
const timer = setTimeout(() => {
|
|
208
|
+
if (this.turnRejector) {
|
|
209
|
+
const rej = this.turnRejector;
|
|
210
|
+
this.turnResolver = null;
|
|
211
|
+
this.turnRejector = null;
|
|
212
|
+
rej(new Error(`turn timeout for "${this.name}"`));
|
|
213
|
+
}
|
|
214
|
+
}, timeoutMs);
|
|
215
|
+
try {
|
|
216
|
+
await this.sendCommand("prompt", { message });
|
|
217
|
+
const text = await textPromise;
|
|
218
|
+
return text;
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
clearTimeout(timer);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async abort() {
|
|
225
|
+
try {
|
|
226
|
+
await this.sendCommand("abort", {}, 5_000);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
/* ignore */
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async getSessionStats() {
|
|
233
|
+
return this.sendCommand("get_session_stats", {});
|
|
234
|
+
}
|
|
235
|
+
stop() {
|
|
236
|
+
try {
|
|
237
|
+
this.proc.stdin.end();
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
/* ignore */
|
|
241
|
+
}
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
try {
|
|
244
|
+
this.proc.kill("SIGTERM");
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
/* ignore */
|
|
248
|
+
}
|
|
249
|
+
}, 2000);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|