@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.
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Observer: consumes Orchestra events and renders them live to stdout.
3
+ *
4
+ * Colors per agent + dim timestamps + indent wrap. Designed to look decent
5
+ * inside a tmux pane. Also writes plain-text events to a log file for
6
+ * offline review (tmux scrollback is nice, files are persistent).
7
+ */
8
+ import { appendFileSync, mkdirSync } from "node:fs";
9
+ import { dirname } from "node:path";
10
+ import { formatSnapshot } from "./usage/reporter.js";
11
+ const AGENT_COLORS = [
12
+ "\x1b[38;5;39m", // cyan-blue
13
+ "\x1b[38;5;208m", // orange
14
+ "\x1b[38;5;141m", // purple
15
+ "\x1b[38;5;42m", // green
16
+ "\x1b[38;5;220m", // yellow
17
+ "\x1b[38;5;198m", // pink
18
+ ];
19
+ const HUMAN_COLOR = "\x1b[38;5;15m\x1b[1m"; // bold white
20
+ const DIM = "\x1b[2m";
21
+ const RESET = "\x1b[0m";
22
+ const BOLD = "\x1b[1m";
23
+ function timestamp() {
24
+ return new Date().toISOString().slice(11, 19);
25
+ }
26
+ export class Observer {
27
+ logPath;
28
+ colorByAgent = new Map();
29
+ streamingAgent = null;
30
+ constructor(orchestra, logPath) {
31
+ this.logPath = logPath;
32
+ if (this.logPath) {
33
+ mkdirSync(dirname(this.logPath), { recursive: true });
34
+ }
35
+ // Assign colors stably per agent based on config order
36
+ for (let i = 0; i < orchestra.config.agents.length; i++) {
37
+ const name = orchestra.config.agents[i].name;
38
+ this.colorByAgent.set(name, AGENT_COLORS[i % AGENT_COLORS.length]);
39
+ }
40
+ orchestra.on("event", (e) => this.onEvent(e));
41
+ orchestra.on("delta", (agentName, text) => this.onDelta(agentName, text));
42
+ orchestra.on("tool", (agentName, toolName, phase) => this.onTool(agentName, toolName, phase));
43
+ orchestra.on("usage", (snap) => this.onUsage(snap));
44
+ }
45
+ onUsage(snap) {
46
+ const line = formatSnapshot(snap, { color: true });
47
+ process.stdout.write(`${DIM} ⤷ ${RESET}${line}\n`);
48
+ this.writeLog(`usage: ${formatSnapshot(snap, { color: false })}`);
49
+ }
50
+ colorFor(from) {
51
+ if (from === "human")
52
+ return HUMAN_COLOR;
53
+ return this.colorByAgent.get(from) ?? "";
54
+ }
55
+ writeLog(line) {
56
+ if (!this.logPath)
57
+ return;
58
+ // Strip ANSI for log
59
+ const plain = line.replace(/\x1b\[[0-9;]*m/g, "");
60
+ try {
61
+ appendFileSync(this.logPath, `${plain}\n`);
62
+ }
63
+ catch {
64
+ /* ignore */
65
+ }
66
+ }
67
+ onEvent(e) {
68
+ switch (e.type) {
69
+ case "message": {
70
+ const m = e.message;
71
+ const color = this.colorFor(m.from);
72
+ const header = `${DIM}[${timestamp()}]${RESET} ${color}${BOLD}${m.from}${RESET}${color} ›${RESET}`;
73
+ // For agent messages where we just streamed deltas, content is already
74
+ // printed via onDelta. Only print full body for injections and seed topic.
75
+ if (m.from === "human" || m.role === "user") {
76
+ process.stdout.write(`\n${header} ${color}${m.content}${RESET}\n\n`);
77
+ this.writeLog(`[${timestamp()}] ${m.from}: ${m.content}`);
78
+ }
79
+ else {
80
+ // finalize the streaming line
81
+ if (this.streamingAgent === m.from) {
82
+ process.stdout.write(`${RESET}\n`);
83
+ this.streamingAgent = null;
84
+ }
85
+ // Full message log entry
86
+ this.writeLog(`[${timestamp()}] ${m.from}: ${m.content}`);
87
+ }
88
+ return;
89
+ }
90
+ case "turn_start": {
91
+ const color = this.colorFor(e.agent);
92
+ process.stdout.write(`\n${DIM}[${timestamp()}]${RESET} ${color}${BOLD}${e.agent}${RESET}${color} ›${RESET} `);
93
+ this.streamingAgent = e.agent;
94
+ return;
95
+ }
96
+ case "turn_end": {
97
+ if (this.streamingAgent === e.agent) {
98
+ process.stdout.write(`${RESET}\n`);
99
+ this.streamingAgent = null;
100
+ }
101
+ return;
102
+ }
103
+ case "agent_error": {
104
+ process.stdout.write(`\n\x1b[31m[error]\x1b[0m ${e.agent}: ${e.error}\n`);
105
+ this.writeLog(`[error] ${e.agent}: ${e.error}`);
106
+ return;
107
+ }
108
+ case "human_inject": {
109
+ const m = e.message;
110
+ process.stdout.write(`\n${HUMAN_COLOR}↘ human (injected)${RESET} ${m.content}${RESET}\n\n`);
111
+ this.writeLog(`[${timestamp()}] [INJECT] human: ${m.content}`);
112
+ return;
113
+ }
114
+ case "info": {
115
+ process.stdout.write(`${DIM}· ${e.info}${RESET}\n`);
116
+ this.writeLog(`[${timestamp()}] · ${e.info}`);
117
+ return;
118
+ }
119
+ case "stop": {
120
+ process.stdout.write(`\n${DIM}· session stopped${RESET}\n`);
121
+ return;
122
+ }
123
+ }
124
+ }
125
+ onDelta(agentName, text) {
126
+ if (this.streamingAgent !== agentName) {
127
+ // Different agent started streaming (shouldn't happen in round-robin but safe)
128
+ if (this.streamingAgent) {
129
+ process.stdout.write(`${RESET}\n`);
130
+ }
131
+ const color = this.colorFor(agentName);
132
+ process.stdout.write(`\n${DIM}[${timestamp()}]${RESET} ${color}${BOLD}${agentName}${RESET}${color} ›${RESET} `);
133
+ this.streamingAgent = agentName;
134
+ }
135
+ const color = this.colorFor(agentName);
136
+ // Indent continuation lines so attribution stays visible
137
+ const indented = text.replace(/\n/g, `\n${color}│${RESET} `);
138
+ process.stdout.write(`${color}${indented}${RESET}`);
139
+ }
140
+ onTool(agentName, toolName, phase) {
141
+ if (phase === "start") {
142
+ const color = this.colorFor(agentName);
143
+ process.stdout.write(`\n${color} ⚙ ${toolName}${RESET}`);
144
+ this.writeLog(`[${timestamp()}] ${agentName} tool_start: ${toolName}`);
145
+ }
146
+ else {
147
+ this.writeLog(`[${timestamp()}] ${agentName} tool_end: ${toolName}`);
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=observer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observer.js","sourceRoot":"","sources":["../src/observer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Orchestra: the central coordinator for a multi-agent team session.
3
+ *
4
+ * Responsibilities:
5
+ * - Spawn one Agent per AgentSpec
6
+ * - Route messages between them via the shared Transcript
7
+ * - Accept human injections at turn boundaries
8
+ * - Stream events to observers (stdout, log, etc.)
9
+ * - Handle graceful shutdown
10
+ */
11
+ import { EventEmitter } from "node:events";
12
+ import { mkdirSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { Agent } from "./agent.js";
15
+ import { Transcript } from "./transcript.js";
16
+ import { UsageTracker } from "./usage/tracker.js";
17
+ export class Orchestra extends EventEmitter {
18
+ config;
19
+ transcript;
20
+ agents = [];
21
+ usage;
22
+ agentLastSeen = new Map();
23
+ agentSessionPaths = new Map();
24
+ pendingInjections = [];
25
+ running = false;
26
+ turn = 0;
27
+ sessionDir;
28
+ constructor(config) {
29
+ super();
30
+ this.config = config;
31
+ this.sessionDir = join(config.sessionsDir, config.name);
32
+ mkdirSync(this.sessionDir, { recursive: true });
33
+ this.transcript = new Transcript(join(this.sessionDir, "transcript.jsonl"));
34
+ this.usage = new UsageTracker();
35
+ }
36
+ async start() {
37
+ if (this.running)
38
+ return;
39
+ this.running = true;
40
+ this.emitEvent({ type: "info", timestamp: Date.now(), info: `starting session "${this.config.name}"` });
41
+ // Spawn agents in parallel
42
+ for (const spec of this.config.agents) {
43
+ const agent = this.createAgent(spec);
44
+ this.agents.push(agent);
45
+ this.agentLastSeen.set(spec.name, 0);
46
+ }
47
+ await Promise.all(this.agents.map((a) => a.start()));
48
+ this.emitEvent({
49
+ type: "info",
50
+ timestamp: Date.now(),
51
+ info: `agents ready: ${this.agents.map((a) => a.name).join(", ")}`,
52
+ });
53
+ // Seed the transcript with the topic
54
+ const seeded = this.transcript.append({
55
+ from: "human",
56
+ role: "user",
57
+ content: this.config.topic,
58
+ });
59
+ this.emitEvent({ type: "message", timestamp: seeded.timestamp, message: seeded });
60
+ // Main loop
61
+ try {
62
+ await this.runLoop();
63
+ }
64
+ finally {
65
+ this.running = false;
66
+ this.emitEvent({ type: "stop", timestamp: Date.now() });
67
+ }
68
+ }
69
+ createAgent(spec) {
70
+ const sessionPath = join(this.sessionDir, `agent-${spec.name}.session.jsonl`);
71
+ this.agentSessionPaths.set(spec.name, sessionPath);
72
+ this.usage.register({
73
+ name: spec.name,
74
+ provider: spec.provider,
75
+ model: spec.model,
76
+ sessionPath,
77
+ planId: spec.planId ?? "api",
78
+ });
79
+ const agent = new Agent({ spec, sessionPath });
80
+ agent.on("delta", (name, text) => {
81
+ this.emit("delta", name, text);
82
+ });
83
+ agent.on("tool_start", (name, tool) => {
84
+ this.emit("tool", name, tool, "start");
85
+ });
86
+ agent.on("tool_end", (name, tool) => {
87
+ this.emit("tool", name, tool, "end");
88
+ });
89
+ agent.on("exit", (name, code) => {
90
+ this.emitEvent({
91
+ type: "agent_error",
92
+ timestamp: Date.now(),
93
+ agent: name,
94
+ error: `pi process exited with code ${code}`,
95
+ });
96
+ this.running = false;
97
+ });
98
+ return agent;
99
+ }
100
+ async runLoop() {
101
+ while (this.running) {
102
+ if (this.config.maxTurns > 0 && this.turn >= this.config.maxTurns) {
103
+ this.emitEvent({
104
+ type: "info",
105
+ timestamp: Date.now(),
106
+ info: `reached max turns (${this.config.maxTurns})`,
107
+ });
108
+ break;
109
+ }
110
+ // Drain any pending human injections into the transcript BEFORE this turn,
111
+ // so the active agent sees them.
112
+ this.drainInjections();
113
+ const agentIdx = this.turn % this.agents.length;
114
+ const agent = this.agents[agentIdx];
115
+ const lastSeen = this.agentLastSeen.get(agent.name) ?? 0;
116
+ const promptText = this.transcript.renderForAgent(agent.name, lastSeen);
117
+ if (!promptText.trim()) {
118
+ // Nothing new for this agent — skip its turn to avoid prompting with empty input
119
+ this.turn++;
120
+ continue;
121
+ }
122
+ this.emitEvent({ type: "turn_start", timestamp: Date.now(), agent: agent.name });
123
+ let replyText;
124
+ try {
125
+ replyText = await agent.prompt(promptText);
126
+ }
127
+ catch (err) {
128
+ this.emitEvent({
129
+ type: "agent_error",
130
+ timestamp: Date.now(),
131
+ agent: agent.name,
132
+ error: err.message,
133
+ });
134
+ break;
135
+ }
136
+ this.agentLastSeen.set(agent.name, this.transcript.lastSeq());
137
+ const msg = this.transcript.append({
138
+ from: agent.name,
139
+ role: "assistant",
140
+ content: replyText,
141
+ });
142
+ this.emitEvent({ type: "message", timestamp: msg.timestamp, message: msg });
143
+ // Refresh usage snapshot for this agent and emit it
144
+ const sessionPath = this.agentSessionPaths.get(agent.name);
145
+ if (sessionPath) {
146
+ this.usage.syncAgent(agent.name, sessionPath);
147
+ const snap = this.usage.snapshot(agent.name);
148
+ if (snap)
149
+ this.emit("usage", snap);
150
+ }
151
+ this.emitEvent({ type: "turn_end", timestamp: Date.now(), agent: agent.name });
152
+ this.turn++;
153
+ if (this.config.turnDelayMs > 0) {
154
+ await new Promise((r) => setTimeout(r, this.config.turnDelayMs));
155
+ }
156
+ }
157
+ }
158
+ drainInjections() {
159
+ while (this.pendingInjections.length > 0) {
160
+ const content = this.pendingInjections.shift();
161
+ const msg = this.transcript.append({ from: "human", role: "user", content });
162
+ this.emitEvent({ type: "human_inject", timestamp: msg.timestamp, message: msg });
163
+ }
164
+ }
165
+ /**
166
+ * Queue a human message. Will be delivered to the next agent at the next
167
+ * turn boundary. Every subsequent agent will see it because renderForAgent
168
+ * includes all messages since their last turn.
169
+ */
170
+ inject(content) {
171
+ this.pendingInjections.push(content);
172
+ // Don't emit an info event here — it would interleave with a streaming agent's
173
+ // output. The injection will appear as a human_inject event at the next turn boundary.
174
+ }
175
+ async stop() {
176
+ this.running = false;
177
+ await Promise.all(this.agents.map((a) => a.abort()));
178
+ for (const a of this.agents)
179
+ a.stop();
180
+ }
181
+ emitEvent(event) {
182
+ this.emit("event", event);
183
+ }
184
+ lastMessages(n) {
185
+ const all = this.transcript.all();
186
+ return all.slice(Math.max(0, all.length - n));
187
+ }
188
+ usageSnapshots() {
189
+ return this.usage.snapshotAll();
190
+ }
191
+ }
192
+ //# sourceMappingURL=orchestra.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestra.js","sourceRoot":"","sources":["../src/orchestra.ts"],"names":[],"mappings":"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"}
package/dist/tmux.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Tmux UI helper: creates a 3-pane layout for observing a team session.
3
+ *
4
+ * Layout:
5
+ * ┌──────────────────────────────────────────────┐
6
+ * │ │
7
+ * │ pane 0: orchestrator stream (main view) │
8
+ * │ ─ colored agent messages + deltas │
9
+ * │ │
10
+ * ├─────────────────────────┬────────────────────┤
11
+ * │ pane 1: inject prompt │ pane 2: meta/tail │
12
+ * │ (user types here) │ (log tail) │
13
+ * └─────────────────────────┴────────────────────┘
14
+ *
15
+ * Users attach with `tmux attach -t <name>` and detach with Ctrl+b d.
16
+ */
17
+ import { execSync, spawnSync } from "node:child_process";
18
+ export function tmuxInstalled() {
19
+ const r = spawnSync("tmux", ["-V"], { stdio: "ignore" });
20
+ return r.status === 0;
21
+ }
22
+ export function sessionExists(name) {
23
+ const r = spawnSync("tmux", ["has-session", "-t", name], { stdio: "ignore" });
24
+ return r.status === 0;
25
+ }
26
+ export function killSession(name) {
27
+ if (sessionExists(name)) {
28
+ spawnSync("tmux", ["kill-session", "-t", name], { stdio: "ignore" });
29
+ }
30
+ }
31
+ /**
32
+ * Create a new detached tmux session running the orchestrator in pane 0,
33
+ * the inject client in pane 1, and a log tail in pane 2.
34
+ */
35
+ export function createLayout(opts) {
36
+ if (sessionExists(opts.sessionName)) {
37
+ throw new Error(`tmux session "${opts.sessionName}" already exists`);
38
+ }
39
+ // Large default size so wrap looks OK even if first attach is small
40
+ execSync(`tmux new-session -d -s ${shell(opts.sessionName)} -x 220 -y 55 ${shell(opts.orchestratorCmd)}`, { stdio: "inherit" });
41
+ // Split horizontally (bottom pane)
42
+ execSync(`tmux split-window -v -p 25 -t ${shell(opts.sessionName)} ${shell(opts.injectCmd)}`, {
43
+ stdio: "inherit",
44
+ });
45
+ // Split the bottom pane vertically for a log tail
46
+ execSync(`tmux split-window -h -p 50 -t ${shell(opts.sessionName)} ${shell(`tail -f ${opts.logPath}`)}`, { stdio: "inherit" });
47
+ // Return focus to main orchestrator pane
48
+ execSync(`tmux select-pane -t ${shell(`${opts.sessionName}.0`)}`, { stdio: "inherit" });
49
+ }
50
+ function shell(s) {
51
+ // POSIX single-quote escape
52
+ return `'${s.replace(/'/g, "'\\''")}'`;
53
+ }
54
+ //# sourceMappingURL=tmux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.js","sourceRoot":"","sources":["../src/tmux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,UAAU,aAAa;IAC5B,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACzC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,SAAS,CAAC,MAAM,EAAE,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC;AACF,CAAC;AASD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAuB;IACnD,IAAI,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,CAAC,WAAW,kBAAkB,CAAC,CAAC;IACtE,CAAC;IACD,oEAAoE;IACpE,QAAQ,CACP,0BAA0B,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,EAC/F,EAAE,KAAK,EAAE,SAAS,EAAE,CACpB,CAAC;IACF,mCAAmC;IACnC,QAAQ,CAAC,iCAAiC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE;QAC7F,KAAK,EAAE,SAAS;KAChB,CAAC,CAAC;IACH,kDAAkD;IAClD,QAAQ,CACP,iCAAiC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,EAC9F,EAAE,KAAK,EAAE,SAAS,EAAE,CACpB,CAAC;IACF,yCAAyC;IACzC,QAAQ,CAAC,uBAAuB,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,SAAS,KAAK,CAAC,CAAS;IACvB,4BAA4B;IAC5B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACxC,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Shared transcript for a team session.
3
+ *
4
+ * Stores every message (human injection, agent reply, system event) in
5
+ * memory and appends to a JSONL file on disk for crash recovery.
6
+ */
7
+ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
8
+ import { dirname } from "node:path";
9
+ export class Transcript {
10
+ path;
11
+ messages = [];
12
+ nextSeq = 1;
13
+ constructor(path) {
14
+ this.path = path;
15
+ mkdirSync(dirname(path), { recursive: true });
16
+ if (existsSync(path)) {
17
+ const raw = readFileSync(path, "utf8");
18
+ for (const line of raw.split("\n")) {
19
+ if (!line.trim())
20
+ continue;
21
+ try {
22
+ const msg = JSON.parse(line);
23
+ this.messages.push(msg);
24
+ if (msg.seq >= this.nextSeq)
25
+ this.nextSeq = msg.seq + 1;
26
+ }
27
+ catch {
28
+ /* skip malformed */
29
+ }
30
+ }
31
+ }
32
+ }
33
+ append(msg) {
34
+ const full = {
35
+ seq: this.nextSeq++,
36
+ timestamp: Date.now(),
37
+ ...msg,
38
+ };
39
+ this.messages.push(full);
40
+ appendFileSync(this.path, `${JSON.stringify(full)}\n`);
41
+ return full;
42
+ }
43
+ all() {
44
+ return this.messages;
45
+ }
46
+ /** Messages since (exclusive) the given seq. If seq is 0, returns all. */
47
+ since(seq) {
48
+ return this.messages.filter((m) => m.seq > seq);
49
+ }
50
+ lastSeq() {
51
+ return this.messages.length > 0 ? this.messages[this.messages.length - 1].seq : 0;
52
+ }
53
+ /**
54
+ * Render messages for a specific agent's perspective: its own messages are
55
+ * already in its pi session, so we only send messages from others since its
56
+ * last turn, formatted with attribution.
57
+ */
58
+ renderForAgent(agentName, sinceSeq) {
59
+ const others = this.since(sinceSeq).filter((m) => m.from !== agentName);
60
+ if (others.length === 0)
61
+ return "";
62
+ return others
63
+ .map((m) => {
64
+ if (m.from === "human")
65
+ return `[human]: ${m.content}`;
66
+ return `[${m.from}]: ${m.content}`;
67
+ })
68
+ .join("\n\n---\n\n");
69
+ }
70
+ }
71
+ //# sourceMappingURL=transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../src/transcript.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared types for pi-team.
3
+ *
4
+ * The orchestrator maintains a single shared transcript. Each message has a
5
+ * `from` field identifying the speaker (agent name or "human"). Each agent has
6
+ * its own internal pi session; the orchestrator routes messages between them.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}