@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/dist/cli.js
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* pi-team: multi-agent debate/collaboration harness built on pi RPC mode.
|
|
4
|
+
*
|
|
5
|
+
* Subcommands:
|
|
6
|
+
* run Start a session in the foreground (orchestrator only)
|
|
7
|
+
* start Create a tmux session with a 3-pane layout (orchestrator, inject, log)
|
|
8
|
+
* inject Connect to a running session's injection socket and forward stdin
|
|
9
|
+
* stop Kill a tmux session and clean up
|
|
10
|
+
* list List sessions under the sessions dir
|
|
11
|
+
*
|
|
12
|
+
* Agent spec format (--agent): name:provider/model[:thinking]
|
|
13
|
+
* Examples:
|
|
14
|
+
* claude:anthropic/claude-sonnet-4-5
|
|
15
|
+
* codex:openai-codex/gpt-5.4:xhigh
|
|
16
|
+
* gem:google/gemini-3-pro-preview:high
|
|
17
|
+
*/
|
|
18
|
+
import { homedir } from "node:os";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { Orchestra } from "./orchestra.js";
|
|
22
|
+
import { Observer } from "./observer.js";
|
|
23
|
+
import { InjectServer, runInjectClient } from "./inject-server.js";
|
|
24
|
+
import { createLayout, killSession, sessionExists, tmuxInstalled } from "./tmux.js";
|
|
25
|
+
import { startHttpInject } from "./http-inject.js";
|
|
26
|
+
import { listPlans } from "./usage/plans.js";
|
|
27
|
+
const DEFAULT_SESSIONS_DIR = join(homedir(), ".pi", "team", "sessions");
|
|
28
|
+
function parseArgs(argv) {
|
|
29
|
+
const [command = "help", ...rest] = argv;
|
|
30
|
+
const flags = new Map();
|
|
31
|
+
const positional = [];
|
|
32
|
+
for (let i = 0; i < rest.length; i++) {
|
|
33
|
+
const a = rest[i];
|
|
34
|
+
if (a.startsWith("--")) {
|
|
35
|
+
const key = a.slice(2);
|
|
36
|
+
const next = rest[i + 1];
|
|
37
|
+
if (next !== undefined && !next.startsWith("--")) {
|
|
38
|
+
if (!flags.has(key))
|
|
39
|
+
flags.set(key, []);
|
|
40
|
+
flags.get(key).push(next);
|
|
41
|
+
i++;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
if (!flags.has(key))
|
|
45
|
+
flags.set(key, []);
|
|
46
|
+
flags.get(key).push("true");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
positional.push(a);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { command, flags, positional };
|
|
54
|
+
}
|
|
55
|
+
function parseAgentSpec(spec) {
|
|
56
|
+
// name:provider/model[:thinking][@plan]
|
|
57
|
+
// Examples:
|
|
58
|
+
// claude:anthropic/claude-sonnet-4-5
|
|
59
|
+
// codex:openai-codex/gpt-5.4:xhigh
|
|
60
|
+
// claude:anthropic/claude-sonnet-4-5@anthropic-max-20x
|
|
61
|
+
// codex:openai-codex/gpt-5.4:xhigh@openai-plus
|
|
62
|
+
let planId;
|
|
63
|
+
const atIdx = spec.lastIndexOf("@");
|
|
64
|
+
if (atIdx !== -1) {
|
|
65
|
+
planId = spec.slice(atIdx + 1);
|
|
66
|
+
spec = spec.slice(0, atIdx);
|
|
67
|
+
}
|
|
68
|
+
const firstColon = spec.indexOf(":");
|
|
69
|
+
if (firstColon === -1)
|
|
70
|
+
throw new Error(`bad agent spec: "${spec}"`);
|
|
71
|
+
const name = spec.slice(0, firstColon);
|
|
72
|
+
const rest = spec.slice(firstColon + 1);
|
|
73
|
+
// rest is provider/model[:thinking]
|
|
74
|
+
const slash = rest.indexOf("/");
|
|
75
|
+
if (slash === -1)
|
|
76
|
+
throw new Error(`bad agent spec: "${spec}" (expected name:provider/model)`);
|
|
77
|
+
const provider = rest.slice(0, slash);
|
|
78
|
+
const afterSlash = rest.slice(slash + 1);
|
|
79
|
+
const thinkingSplit = afterSlash.lastIndexOf(":");
|
|
80
|
+
const thinkingCandidates = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
81
|
+
let model = afterSlash;
|
|
82
|
+
let thinking;
|
|
83
|
+
if (thinkingSplit !== -1) {
|
|
84
|
+
const candidate = afterSlash.slice(thinkingSplit + 1);
|
|
85
|
+
if (thinkingCandidates.includes(candidate)) {
|
|
86
|
+
model = afterSlash.slice(0, thinkingSplit);
|
|
87
|
+
thinking = candidate;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return { name, provider, model, thinking, planId };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse --plan name=plan-id flag values into a map and fold them into agents
|
|
94
|
+
* that haven't already specified a plan via the @ suffix.
|
|
95
|
+
*/
|
|
96
|
+
function applyPlanFlags(agents, planFlags) {
|
|
97
|
+
if (!planFlags)
|
|
98
|
+
return agents;
|
|
99
|
+
const planMap = new Map();
|
|
100
|
+
for (const raw of planFlags) {
|
|
101
|
+
const eq = raw.indexOf("=");
|
|
102
|
+
if (eq === -1)
|
|
103
|
+
throw new Error(`bad --plan value: "${raw}" (expected name=plan-id)`);
|
|
104
|
+
planMap.set(raw.slice(0, eq), raw.slice(eq + 1));
|
|
105
|
+
}
|
|
106
|
+
return agents.map((a) => (a.planId ? a : { ...a, planId: planMap.get(a.name) ?? a.planId }));
|
|
107
|
+
}
|
|
108
|
+
function help() {
|
|
109
|
+
process.stdout.write(`pi-team — multi-agent debate/collaboration harness
|
|
110
|
+
|
|
111
|
+
USAGE
|
|
112
|
+
pi-team start --name <name> --agent <spec> --agent <spec> [--topic <text> | --topic-file <path>]
|
|
113
|
+
[--plan <name=plan-id>] [--max-turns N]
|
|
114
|
+
pi-team run (same flags as start, but foreground, no tmux)
|
|
115
|
+
pi-team inject --name <name>
|
|
116
|
+
pi-team stop --name <name>
|
|
117
|
+
pi-team list
|
|
118
|
+
pi-team plans
|
|
119
|
+
pi-team help
|
|
120
|
+
|
|
121
|
+
AGENT SPEC
|
|
122
|
+
name:provider/model[:thinking][@plan-id]
|
|
123
|
+
claude:anthropic/claude-sonnet-4-5
|
|
124
|
+
codex:openai-codex/gpt-5.4:xhigh
|
|
125
|
+
claude:anthropic/claude-sonnet-4-5@anthropic-max-20x
|
|
126
|
+
codex:openai-codex/gpt-5.4:xhigh@openai-plus
|
|
127
|
+
|
|
128
|
+
PLAN-AWARE COST TRACKING
|
|
129
|
+
Without --plan (or @plan suffix), pi-team shows dollar cost from pi’s
|
|
130
|
+
per-token pricing — which is wrong if you’re on a subscription. Declare
|
|
131
|
+
your plan per agent to get real 5-hour and weekly window usage instead:
|
|
132
|
+
|
|
133
|
+
pi-team start --name x \\
|
|
134
|
+
--agent claude:anthropic/claude-sonnet-4-5 \\
|
|
135
|
+
--agent codex:openai-codex/gpt-5.4:xhigh \\
|
|
136
|
+
--plan claude=anthropic-max-20x \\
|
|
137
|
+
--plan codex=openai-plus \\
|
|
138
|
+
--topic-file ./topic.md
|
|
139
|
+
|
|
140
|
+
Run 'pi-team plans' to list available plan ids.
|
|
141
|
+
|
|
142
|
+
EXAMPLES
|
|
143
|
+
# Start an emotion-concepts debate between Claude and Codex, observable via tmux
|
|
144
|
+
pi-team start \\
|
|
145
|
+
--name emotions \\
|
|
146
|
+
--agent claude:anthropic/claude-sonnet-4-5@anthropic-max-20x \\
|
|
147
|
+
--agent codex:openai-codex/gpt-5.4:xhigh@openai-plus \\
|
|
148
|
+
--max-turns 10 \\
|
|
149
|
+
--topic-file ./debate-prompt.md
|
|
150
|
+
|
|
151
|
+
tmux attach -t piteam-emotions
|
|
152
|
+
pi-team inject --name emotions
|
|
153
|
+
pi-team stop --name emotions
|
|
154
|
+
`);
|
|
155
|
+
}
|
|
156
|
+
function cmdPlans() {
|
|
157
|
+
for (const id of listPlans()) {
|
|
158
|
+
process.stdout.write(`${id}\n`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function resolveTopic(flags) {
|
|
162
|
+
const topicFile = flags.get("topic-file")?.[0];
|
|
163
|
+
if (topicFile)
|
|
164
|
+
return readFileSync(topicFile, "utf8");
|
|
165
|
+
const topic = flags.get("topic")?.[0];
|
|
166
|
+
if (topic)
|
|
167
|
+
return topic;
|
|
168
|
+
throw new Error("missing --topic or --topic-file");
|
|
169
|
+
}
|
|
170
|
+
function buildConfig(flags) {
|
|
171
|
+
const name = flags.get("name")?.[0];
|
|
172
|
+
if (!name)
|
|
173
|
+
throw new Error("missing --name");
|
|
174
|
+
const agentSpecs = flags.get("agent") ?? [];
|
|
175
|
+
if (agentSpecs.length < 2)
|
|
176
|
+
throw new Error("need at least two --agent specs");
|
|
177
|
+
const parsed = agentSpecs.map(parseAgentSpec);
|
|
178
|
+
const agents = applyPlanFlags(parsed, flags.get("plan"));
|
|
179
|
+
const topic = resolveTopic(flags);
|
|
180
|
+
const maxTurns = Number(flags.get("max-turns")?.[0] ?? "20");
|
|
181
|
+
const turnDelayMs = Number(flags.get("turn-delay-ms")?.[0] ?? "0");
|
|
182
|
+
const sessionsDir = flags.get("sessions-dir")?.[0] ?? DEFAULT_SESSIONS_DIR;
|
|
183
|
+
const mode = (flags.get("mode")?.[0] ?? "round-robin");
|
|
184
|
+
return { name, agents, topic, maxTurns, turnDelayMs, sessionsDir, mode };
|
|
185
|
+
}
|
|
186
|
+
async function cmdRun(flags) {
|
|
187
|
+
const config = buildConfig(flags);
|
|
188
|
+
await runFromConfig(config, flags);
|
|
189
|
+
}
|
|
190
|
+
async function cmdStart(flags) {
|
|
191
|
+
if (!tmuxInstalled()) {
|
|
192
|
+
throw new Error("tmux is required for 'start'; use 'run' for foreground");
|
|
193
|
+
}
|
|
194
|
+
const config = buildConfig(flags);
|
|
195
|
+
if (sessionExists(`piteam-${config.name}`)) {
|
|
196
|
+
throw new Error(`tmux session "piteam-${config.name}" already exists. Kill with: pi-team stop --name ${config.name}`);
|
|
197
|
+
}
|
|
198
|
+
// Write config so the background `run` process can read it
|
|
199
|
+
const sessionDir = join(config.sessionsDir, config.name);
|
|
200
|
+
const { mkdirSync } = await import("node:fs");
|
|
201
|
+
mkdirSync(sessionDir, { recursive: true });
|
|
202
|
+
const configPath = join(sessionDir, "config.json");
|
|
203
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
204
|
+
// Resolve the path to this script for the tmux pane commands
|
|
205
|
+
const scriptPath = process.argv[1];
|
|
206
|
+
const node = process.execPath;
|
|
207
|
+
const httpPortFlag = flags.get("http-port")?.[0];
|
|
208
|
+
const httpHostFlag = flags.get("http-host")?.[0];
|
|
209
|
+
const httpPortArgs = httpPortFlag ? ` --http-port ${httpPortFlag}` : "";
|
|
210
|
+
const httpHostArgs = httpHostFlag ? ` --http-host ${httpHostFlag}` : "";
|
|
211
|
+
const runCmd = `${node} ${scriptPath} run --config-file ${configPath}${httpPortArgs}${httpHostArgs}`;
|
|
212
|
+
const injectCmd = `${node} ${scriptPath} inject --name ${config.name}`;
|
|
213
|
+
const logPath = join(sessionDir, "events.log");
|
|
214
|
+
// Ensure log file exists so tail -f doesn't fail
|
|
215
|
+
writeFileSync(logPath, `# pi-team session ${config.name} — started ${new Date().toISOString()}\n`);
|
|
216
|
+
createLayout({
|
|
217
|
+
sessionName: `piteam-${config.name}`,
|
|
218
|
+
orchestratorCmd: runCmd,
|
|
219
|
+
injectCmd: `sleep 1 && ${injectCmd}`,
|
|
220
|
+
logPath,
|
|
221
|
+
});
|
|
222
|
+
process.stdout.write(`\n\x1b[1mpi-team session "${config.name}" started in tmux.\x1b[0m\n\n` +
|
|
223
|
+
` Watch: tmux attach -t piteam-${config.name}\n` +
|
|
224
|
+
` Inject: pi-team inject --name ${config.name} (from any shell)\n` +
|
|
225
|
+
` Stop: pi-team stop --name ${config.name}\n` +
|
|
226
|
+
` Log: ${logPath}\n` +
|
|
227
|
+
` Dir: ${sessionDir}\n\n`);
|
|
228
|
+
}
|
|
229
|
+
async function cmdInject(flags) {
|
|
230
|
+
const name = flags.get("name")?.[0];
|
|
231
|
+
if (!name)
|
|
232
|
+
throw new Error("missing --name");
|
|
233
|
+
const sessionsDir = flags.get("sessions-dir")?.[0] ?? DEFAULT_SESSIONS_DIR;
|
|
234
|
+
const socketPath = join(sessionsDir, name, "inject.sock");
|
|
235
|
+
// Wait briefly for socket if run just started
|
|
236
|
+
for (let i = 0; i < 20; i++) {
|
|
237
|
+
if (existsSync(socketPath))
|
|
238
|
+
break;
|
|
239
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
240
|
+
}
|
|
241
|
+
if (!existsSync(socketPath)) {
|
|
242
|
+
throw new Error(`no injection socket at ${socketPath} — is the session running?`);
|
|
243
|
+
}
|
|
244
|
+
process.stdout.write(`\x1b[2m[connected to ${name}. Type a message and press Enter. Ctrl+D to quit.]\x1b[0m\n`);
|
|
245
|
+
await runInjectClient(socketPath);
|
|
246
|
+
}
|
|
247
|
+
async function cmdStop(flags) {
|
|
248
|
+
const name = flags.get("name")?.[0];
|
|
249
|
+
if (!name)
|
|
250
|
+
throw new Error("missing --name");
|
|
251
|
+
killSession(`piteam-${name}`);
|
|
252
|
+
process.stdout.write(`stopped piteam-${name}\n`);
|
|
253
|
+
}
|
|
254
|
+
function cmdList(flags) {
|
|
255
|
+
const sessionsDir = flags.get("sessions-dir")?.[0] ?? DEFAULT_SESSIONS_DIR;
|
|
256
|
+
if (!existsSync(sessionsDir)) {
|
|
257
|
+
process.stdout.write(`(no sessions at ${sessionsDir})\n`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const entries = readdirSync(sessionsDir);
|
|
261
|
+
if (entries.length === 0) {
|
|
262
|
+
process.stdout.write(`(no sessions)\n`);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
for (const name of entries) {
|
|
266
|
+
const dir = join(sessionsDir, name);
|
|
267
|
+
if (!statSync(dir).isDirectory())
|
|
268
|
+
continue;
|
|
269
|
+
const active = sessionExists(`piteam-${name}`);
|
|
270
|
+
process.stdout.write(`${active ? "● " : " "}${name} ${dir}\n`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function cmdRunWithConfigFile(flags) {
|
|
274
|
+
const cf = flags.get("config-file")?.[0];
|
|
275
|
+
if (!cf) {
|
|
276
|
+
return cmdRun(flags);
|
|
277
|
+
}
|
|
278
|
+
const config = JSON.parse(readFileSync(cf, "utf8"));
|
|
279
|
+
// Use the loaded config directly — it already contains AgentSpec objects
|
|
280
|
+
// with planId preserved. Don't round-trip through string-based flags.
|
|
281
|
+
await runFromConfig(config, flags);
|
|
282
|
+
}
|
|
283
|
+
async function runFromConfig(config, flags) {
|
|
284
|
+
const orchestra = new Orchestra(config);
|
|
285
|
+
const sessionDir = join(config.sessionsDir, config.name);
|
|
286
|
+
const logPath = join(sessionDir, "events.log");
|
|
287
|
+
const socketPath = join(sessionDir, "inject.sock");
|
|
288
|
+
new Observer(orchestra, logPath);
|
|
289
|
+
const injectServer = new InjectServer(orchestra, socketPath);
|
|
290
|
+
injectServer.start();
|
|
291
|
+
const httpPort = Number(flags.get("http-port")?.[0] ?? process.env.PITEAM_HTTP_PORT ?? "0");
|
|
292
|
+
const httpHost = flags.get("http-host")?.[0] ?? process.env.PITEAM_HTTP_HOST ?? "127.0.0.1";
|
|
293
|
+
let httpHandle = null;
|
|
294
|
+
if (httpPort > 0) {
|
|
295
|
+
httpHandle = startHttpInject({
|
|
296
|
+
orchestra,
|
|
297
|
+
port: httpPort,
|
|
298
|
+
host: httpHost,
|
|
299
|
+
sessionDir,
|
|
300
|
+
token: process.env.PITEAM_HTTP_TOKEN,
|
|
301
|
+
onStop: async () => {
|
|
302
|
+
await orchestra.stop();
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
process.stdout.write(`\x1b[2m· http inject on ${httpHost}:${httpPort}\x1b[0m\n`);
|
|
306
|
+
}
|
|
307
|
+
const runfile = join(sessionDir, "runfile.json");
|
|
308
|
+
writeFileSync(runfile, JSON.stringify({ pid: process.pid, socket: socketPath, httpPort, started: Date.now(), config }, null, 2));
|
|
309
|
+
const shutdown = async () => {
|
|
310
|
+
process.stdout.write("\n\x1b[2m· shutting down\x1b[0m\n");
|
|
311
|
+
injectServer.stop();
|
|
312
|
+
httpHandle?.stop();
|
|
313
|
+
await orchestra.stop();
|
|
314
|
+
process.exit(0);
|
|
315
|
+
};
|
|
316
|
+
process.on("SIGINT", shutdown);
|
|
317
|
+
process.on("SIGTERM", shutdown);
|
|
318
|
+
try {
|
|
319
|
+
await orchestra.start();
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
process.stderr.write(`\n\x1b[31mfatal:\x1b[0m ${err.message}\n`);
|
|
323
|
+
injectServer.stop();
|
|
324
|
+
httpHandle?.stop();
|
|
325
|
+
await orchestra.stop();
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
injectServer.stop();
|
|
329
|
+
httpHandle?.stop();
|
|
330
|
+
await orchestra.stop();
|
|
331
|
+
process.exit(0);
|
|
332
|
+
}
|
|
333
|
+
async function main() {
|
|
334
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
335
|
+
try {
|
|
336
|
+
switch (parsed.command) {
|
|
337
|
+
case "run":
|
|
338
|
+
await cmdRunWithConfigFile(parsed.flags);
|
|
339
|
+
break;
|
|
340
|
+
case "start":
|
|
341
|
+
await cmdStart(parsed.flags);
|
|
342
|
+
break;
|
|
343
|
+
case "inject":
|
|
344
|
+
await cmdInject(parsed.flags);
|
|
345
|
+
break;
|
|
346
|
+
case "stop":
|
|
347
|
+
await cmdStop(parsed.flags);
|
|
348
|
+
break;
|
|
349
|
+
case "list":
|
|
350
|
+
cmdList(parsed.flags);
|
|
351
|
+
break;
|
|
352
|
+
case "plans":
|
|
353
|
+
cmdPlans();
|
|
354
|
+
break;
|
|
355
|
+
case "help":
|
|
356
|
+
case "--help":
|
|
357
|
+
case "-h":
|
|
358
|
+
help();
|
|
359
|
+
break;
|
|
360
|
+
default:
|
|
361
|
+
help();
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
catch (err) {
|
|
366
|
+
process.stderr.write(`\x1b[31merror:\x1b[0m ${err.message}\n`);
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
main();
|
|
371
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP inject endpoint: thin wrapper so external systems (ops-agent, curl,
|
|
3
|
+
* webhooks) can post human messages into a running team session without
|
|
4
|
+
* touching the Unix socket directly.
|
|
5
|
+
*
|
|
6
|
+
* Endpoints:
|
|
7
|
+
* POST /inject body = raw text or { "message": "..." }
|
|
8
|
+
* GET /state returns {agents, turn, lastMessages}
|
|
9
|
+
* GET /transcript returns JSONL of full transcript
|
|
10
|
+
* POST /stop gracefully stops the orchestra
|
|
11
|
+
*
|
|
12
|
+
* All responses JSON. Defaults to binding on 127.0.0.1 (localhost-only). Set
|
|
13
|
+
* host to "0.0.0.0" or another interface to expose over the network — when
|
|
14
|
+
* you do, you should also set PITEAM_HTTP_TOKEN so untrusted clients on the
|
|
15
|
+
* LAN can't POST /inject and feed arbitrary text into the agents.
|
|
16
|
+
*/
|
|
17
|
+
import { createServer } from "node:http";
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
/** Hard cap on POST /inject body to stop runaway streaming from eating memory. */
|
|
21
|
+
const MAX_BODY_BYTES = 1_000_000; // 1 MB
|
|
22
|
+
export function startHttpInject(opts) {
|
|
23
|
+
const server = createServer(async (req, res) => {
|
|
24
|
+
try {
|
|
25
|
+
if (opts.token) {
|
|
26
|
+
const auth = req.headers.authorization;
|
|
27
|
+
if (auth !== `Bearer ${opts.token}`) {
|
|
28
|
+
return json(res, 401, { error: "unauthorized" });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const url = req.url ?? "/";
|
|
32
|
+
if (req.method === "POST" && url === "/inject") {
|
|
33
|
+
const body = await readBody(req);
|
|
34
|
+
let message;
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(body);
|
|
37
|
+
message = typeof parsed === "string" ? parsed : parsed.message;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
message = body;
|
|
41
|
+
}
|
|
42
|
+
if (!message || !message.trim()) {
|
|
43
|
+
return json(res, 400, { error: "empty message" });
|
|
44
|
+
}
|
|
45
|
+
opts.orchestra.inject(message);
|
|
46
|
+
return json(res, 200, { ok: true, queued: message.length });
|
|
47
|
+
}
|
|
48
|
+
if (req.method === "GET" && url === "/state") {
|
|
49
|
+
return json(res, 200, {
|
|
50
|
+
session: opts.orchestra.config.name,
|
|
51
|
+
agents: opts.orchestra.config.agents.map((a) => ({
|
|
52
|
+
name: a.name,
|
|
53
|
+
provider: a.provider,
|
|
54
|
+
model: a.model,
|
|
55
|
+
planId: a.planId ?? "api",
|
|
56
|
+
})),
|
|
57
|
+
lastMessages: opts.orchestra.lastMessages(5),
|
|
58
|
+
usage: opts.orchestra.usageSnapshots(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (req.method === "GET" && url === "/usage") {
|
|
62
|
+
return json(res, 200, {
|
|
63
|
+
session: opts.orchestra.config.name,
|
|
64
|
+
snapshots: opts.orchestra.usageSnapshots(),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (req.method === "GET" && url === "/transcript") {
|
|
68
|
+
const path = join(opts.sessionDir, "transcript.jsonl");
|
|
69
|
+
try {
|
|
70
|
+
const raw = readFileSync(path, "utf8");
|
|
71
|
+
res.writeHead(200, { "content-type": "application/x-ndjson" });
|
|
72
|
+
res.end(raw);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
json(res, 500, { error: err.message });
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (req.method === "POST" && url === "/stop") {
|
|
80
|
+
if (opts.onStop)
|
|
81
|
+
await opts.onStop();
|
|
82
|
+
return json(res, 200, { ok: true });
|
|
83
|
+
}
|
|
84
|
+
if (req.method === "GET" && url === "/") {
|
|
85
|
+
return json(res, 200, {
|
|
86
|
+
service: "pi-team",
|
|
87
|
+
session: opts.orchestra.config.name,
|
|
88
|
+
endpoints: [
|
|
89
|
+
"POST /inject",
|
|
90
|
+
"GET /state",
|
|
91
|
+
"GET /usage",
|
|
92
|
+
"GET /transcript",
|
|
93
|
+
"POST /stop",
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
json(res, 404, { error: "not found" });
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
json(res, 500, { error: err.message });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const host = opts.host ?? "127.0.0.1";
|
|
104
|
+
server.on("error", (err) => {
|
|
105
|
+
if (err.code === "EADDRINUSE") {
|
|
106
|
+
console.error(`[http-inject] port ${opts.port} is already in use on ${host}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.error(`[http-inject] server error: ${err.message}`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
server.listen(opts.port, host);
|
|
113
|
+
return { stop: () => server.close() };
|
|
114
|
+
}
|
|
115
|
+
function readBody(req) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const chunks = [];
|
|
118
|
+
let total = 0;
|
|
119
|
+
req.on("data", (c) => {
|
|
120
|
+
total += c.length;
|
|
121
|
+
if (total > MAX_BODY_BYTES) {
|
|
122
|
+
req.destroy();
|
|
123
|
+
reject(new Error(`request body exceeds ${MAX_BODY_BYTES} bytes`));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
chunks.push(c);
|
|
127
|
+
});
|
|
128
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
129
|
+
req.on("error", reject);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function json(res, status, body) {
|
|
133
|
+
res.writeHead(status, { "content-type": "application/json" });
|
|
134
|
+
res.end(JSON.stringify(body));
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=http-inject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-inject.js","sourceRoot":"","sources":["../src/http-inject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection server: a Unix domain socket that accepts human messages and
|
|
3
|
+
* forwards them to the running Orchestra. Lets the user hop in live from a
|
|
4
|
+
* separate tmux pane (or remote shell) without disturbing the orchestrator's
|
|
5
|
+
* stdout stream.
|
|
6
|
+
*
|
|
7
|
+
* Protocol: newline-delimited text. Every line is one injection. Empty lines
|
|
8
|
+
* ignored. The socket file is created under the session dir.
|
|
9
|
+
*/
|
|
10
|
+
import { createServer } from "node:net";
|
|
11
|
+
import { unlinkSync, existsSync } from "node:fs";
|
|
12
|
+
export class InjectServer {
|
|
13
|
+
orchestra;
|
|
14
|
+
socketPath;
|
|
15
|
+
server = null;
|
|
16
|
+
constructor(orchestra, socketPath) {
|
|
17
|
+
this.orchestra = orchestra;
|
|
18
|
+
this.socketPath = socketPath;
|
|
19
|
+
}
|
|
20
|
+
start() {
|
|
21
|
+
if (existsSync(this.socketPath)) {
|
|
22
|
+
try {
|
|
23
|
+
unlinkSync(this.socketPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
/* ignore */
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
this.server = createServer((conn) => {
|
|
30
|
+
let buffer = "";
|
|
31
|
+
conn.on("data", (chunk) => {
|
|
32
|
+
buffer += chunk.toString("utf8");
|
|
33
|
+
let nl = buffer.indexOf("\n");
|
|
34
|
+
while (nl !== -1) {
|
|
35
|
+
const line = buffer.slice(0, nl).replace(/\r$/, "");
|
|
36
|
+
buffer = buffer.slice(nl + 1);
|
|
37
|
+
if (line.trim()) {
|
|
38
|
+
this.orchestra.inject(line);
|
|
39
|
+
conn.write("ok\n");
|
|
40
|
+
}
|
|
41
|
+
nl = buffer.indexOf("\n");
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
conn.on("end", () => {
|
|
45
|
+
if (buffer.trim())
|
|
46
|
+
this.orchestra.inject(buffer.trim());
|
|
47
|
+
});
|
|
48
|
+
conn.on("error", () => {
|
|
49
|
+
/* ignore */
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
this.server.listen(this.socketPath);
|
|
53
|
+
}
|
|
54
|
+
stop() {
|
|
55
|
+
if (this.server) {
|
|
56
|
+
this.server.close();
|
|
57
|
+
this.server = null;
|
|
58
|
+
}
|
|
59
|
+
if (existsSync(this.socketPath)) {
|
|
60
|
+
try {
|
|
61
|
+
unlinkSync(this.socketPath);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
/* ignore */
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Client-side: read lines from stdin (with a `team › ` prompt) and send them
|
|
71
|
+
* to the socket. Used by `pi-team inject <socket>`.
|
|
72
|
+
*/
|
|
73
|
+
export async function runInjectClient(socketPath) {
|
|
74
|
+
const { createConnection } = await import("node:net");
|
|
75
|
+
const readline = await import("node:readline");
|
|
76
|
+
const conn = createConnection(socketPath);
|
|
77
|
+
await new Promise((resolve, reject) => {
|
|
78
|
+
conn.once("connect", () => resolve());
|
|
79
|
+
conn.once("error", reject);
|
|
80
|
+
});
|
|
81
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
|
82
|
+
rl.setPrompt("team › ");
|
|
83
|
+
rl.prompt();
|
|
84
|
+
rl.on("line", (line) => {
|
|
85
|
+
if (line.trim()) {
|
|
86
|
+
conn.write(`${line}\n`);
|
|
87
|
+
}
|
|
88
|
+
rl.prompt();
|
|
89
|
+
});
|
|
90
|
+
rl.on("close", () => {
|
|
91
|
+
conn.end();
|
|
92
|
+
process.exit(0);
|
|
93
|
+
});
|
|
94
|
+
conn.on("data", () => {
|
|
95
|
+
// server ack; don't echo
|
|
96
|
+
});
|
|
97
|
+
conn.on("end", () => {
|
|
98
|
+
rl.close();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=inject-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inject-server.js","sourceRoot":"","sources":["../src/inject-server.ts"],"names":[],"mappings":"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"}
|