@agentproto/harness 0.1.0 → 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/dist/index.d.ts +18 -12
- package/dist/index.mjs +22 -14
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +23 -15
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -30,18 +30,24 @@ declare class HarnessClient {
|
|
|
30
30
|
* Connect an MCP client over HTTP to the daemon's `/mcp` endpoint.
|
|
31
31
|
*/
|
|
32
32
|
static connect(opts?: ConnectHarnessOptions): Promise<HarnessClient>;
|
|
33
|
-
/** Spawn a session via `
|
|
33
|
+
/** Spawn a session via `agent_start`. */
|
|
34
34
|
start(args: StartAgentArgs): Promise<SessionDescriptor>;
|
|
35
|
-
/** Send a follow-up turn via `
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
/** Send a follow-up turn via `agent_prompt` (fire-and-forget). `opts.interrupt`
|
|
36
|
+
* cancels an in-flight turn and redirects the session onto this prompt instead
|
|
37
|
+
* of rejecting (see `agent_prompt`'s `interrupt` field). */
|
|
38
|
+
prompt(sessionId: string, prompt: string, opts?: {
|
|
39
|
+
interrupt?: boolean;
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
/** Tail the ring buffer via `agent_output`. */
|
|
38
42
|
output(sessionId: string, lastN?: number): Promise<string>;
|
|
39
|
-
/** SIGTERM via `
|
|
43
|
+
/** SIGTERM via `agent_kill`. */
|
|
40
44
|
kill(sessionId: string): Promise<void>;
|
|
41
45
|
/**
|
|
42
|
-
* Multiplexed long-poll via `
|
|
46
|
+
* Multiplexed long-poll via `session_monitor`. `timeoutMs` is clamped to the
|
|
43
47
|
* tool's 1 000–49 000 window; a clean timeout surfaces as
|
|
44
|
-
* `{
|
|
48
|
+
* `{ timedOut: true, sessionIds }` with no `event` field at all — `event`
|
|
49
|
+
* is only ever set (to `"turn-end"|"awaiting-input"|"exited"`) on a real
|
|
50
|
+
* match. Callers must check `timedOut`, not `event`, to detect a timeout.
|
|
45
51
|
*/
|
|
46
52
|
waitForAny(sessionIds: string[], opts?: {
|
|
47
53
|
timeoutMs?: number;
|
|
@@ -73,7 +79,7 @@ interface MakeHandleMeta {
|
|
|
73
79
|
*
|
|
74
80
|
* WP2: implement `send` (→ client.prompt), `waitForTurn` (→ client.waitForAny
|
|
75
81
|
* with `event: "any"` to catch `turn-end`, `awaiting-input`, and `exited`),
|
|
76
|
-
* timeout → `{
|
|
82
|
+
* timeout → `{ timedOut: true }`), `ask` (send + waitForTurn + output),
|
|
77
83
|
* `output` (→ client.output), `kill` (→ client.kill).
|
|
78
84
|
*/
|
|
79
85
|
declare function makeHandle(client: HarnessClient, meta: MakeHandleMeta): AgentHandle;
|
|
@@ -119,7 +125,7 @@ interface CoderHarnessOptions {
|
|
|
119
125
|
mcpServers?: McpServerMount[];
|
|
120
126
|
}
|
|
121
127
|
/**
|
|
122
|
-
* Build the `
|
|
128
|
+
* Build the `agent_start` args for the coder preset. Exported so WP3's
|
|
123
129
|
* unit test can snapshot the args for both engines without a live daemon.
|
|
124
130
|
*
|
|
125
131
|
* For hermes: `model` and `effort` are NOT included — hermes does not declare
|
|
@@ -167,7 +173,7 @@ declare const DEFAULT_RESEARCH_SCHEMA: {
|
|
|
167
173
|
*/
|
|
168
174
|
declare function renderResearcherPrompt(opts: ResearcherHarnessOptions): string;
|
|
169
175
|
/**
|
|
170
|
-
* Build the `
|
|
176
|
+
* Build the `agent_start` args for the researcher preset.
|
|
171
177
|
* Exported so WP4's unit test can assert `mcpServers` + schema are present.
|
|
172
178
|
*
|
|
173
179
|
* `model`, `effort`, and the system `prompt` are NOT included here —
|
|
@@ -224,13 +230,13 @@ interface SupervisorHarnessOptions {
|
|
|
224
230
|
interface SupervisorHandle extends AgentHandle {
|
|
225
231
|
/** Snapshot this session's child subtree (→ `session_tree`). */
|
|
226
232
|
subtree(): Promise<unknown>;
|
|
227
|
-
/** Block until ANY child session ends a turn (→ `
|
|
233
|
+
/** Block until ANY child session ends a turn (→ `session_monitor`). */
|
|
228
234
|
waitForAnyChild(opts?: {
|
|
229
235
|
timeoutMs?: number;
|
|
230
236
|
}): Promise<TurnResult>;
|
|
231
237
|
}
|
|
232
238
|
/**
|
|
233
|
-
* Build the `
|
|
239
|
+
* Build the `agent_start` args for the supervisor preset. Exported so
|
|
234
240
|
* WP5's unit test can assert `orchestrator` + the rendered WP brief.
|
|
235
241
|
*/
|
|
236
242
|
declare function buildSupervisorArgs(opts: SupervisorHarnessOptions): StartAgentArgs;
|
package/dist/index.mjs
CHANGED
|
@@ -30,33 +30,41 @@ var HarnessClient = class _HarnessClient {
|
|
|
30
30
|
await client.connect(transport);
|
|
31
31
|
return new _HarnessClient(url, client);
|
|
32
32
|
}
|
|
33
|
-
/** Spawn a session via `
|
|
33
|
+
/** Spawn a session via `agent_start`. */
|
|
34
34
|
async start(args) {
|
|
35
|
-
return this.#call("
|
|
35
|
+
return this.#call("agent_start", args);
|
|
36
36
|
}
|
|
37
|
-
/** Send a follow-up turn via `
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
/** Send a follow-up turn via `agent_prompt` (fire-and-forget). `opts.interrupt`
|
|
38
|
+
* cancels an in-flight turn and redirects the session onto this prompt instead
|
|
39
|
+
* of rejecting (see `agent_prompt`'s `interrupt` field). */
|
|
40
|
+
async prompt(sessionId, prompt, opts) {
|
|
41
|
+
await this.#call("agent_prompt", {
|
|
42
|
+
sessionId,
|
|
43
|
+
prompt,
|
|
44
|
+
...opts?.interrupt !== void 0 ? { interrupt: opts.interrupt } : {}
|
|
45
|
+
});
|
|
40
46
|
}
|
|
41
|
-
/** Tail the ring buffer via `
|
|
47
|
+
/** Tail the ring buffer via `agent_output`. */
|
|
42
48
|
async output(sessionId, lastN) {
|
|
43
49
|
const res = await this.#call(
|
|
44
|
-
"
|
|
50
|
+
"agent_output",
|
|
45
51
|
{ sessionId, lastN }
|
|
46
52
|
);
|
|
47
53
|
return (res.lines ?? []).join("\n");
|
|
48
54
|
}
|
|
49
|
-
/** SIGTERM via `
|
|
55
|
+
/** SIGTERM via `agent_kill`. */
|
|
50
56
|
async kill(sessionId) {
|
|
51
|
-
await this.#call("
|
|
57
|
+
await this.#call("agent_kill", { sessionId });
|
|
52
58
|
}
|
|
53
59
|
/**
|
|
54
|
-
* Multiplexed long-poll via `
|
|
60
|
+
* Multiplexed long-poll via `session_monitor`. `timeoutMs` is clamped to the
|
|
55
61
|
* tool's 1 000–49 000 window; a clean timeout surfaces as
|
|
56
|
-
* `{
|
|
62
|
+
* `{ timedOut: true, sessionIds }` with no `event` field at all — `event`
|
|
63
|
+
* is only ever set (to `"turn-end"|"awaiting-input"|"exited"`) on a real
|
|
64
|
+
* match. Callers must check `timedOut`, not `event`, to detect a timeout.
|
|
57
65
|
*/
|
|
58
66
|
async waitForAny(sessionIds, opts) {
|
|
59
|
-
return this.#call("
|
|
67
|
+
return this.#call("session_monitor", {
|
|
60
68
|
sessionIds,
|
|
61
69
|
...opts?.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
62
70
|
...opts?.event !== void 0 ? { event: opts.event } : {}
|
|
@@ -113,7 +121,7 @@ function makeHandle(client, meta) {
|
|
|
113
121
|
});
|
|
114
122
|
await client.prompt(meta.sessionId, prompt);
|
|
115
123
|
const result = await waitPromise;
|
|
116
|
-
if (result.
|
|
124
|
+
if (result.timedOut) return "[timeout]";
|
|
117
125
|
return client.output(meta.sessionId);
|
|
118
126
|
},
|
|
119
127
|
async output(opts) {
|
|
@@ -286,7 +294,7 @@ async function createSupervisorHarness(client, opts = {}) {
|
|
|
286
294
|
if (childIds.length === 0) {
|
|
287
295
|
return {
|
|
288
296
|
sessionId: desc.id,
|
|
289
|
-
|
|
297
|
+
timedOut: true
|
|
290
298
|
};
|
|
291
299
|
}
|
|
292
300
|
const CHUNK = 20;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/handle.ts","../src/context.ts","../src/harnesses/coder.ts","../src/harnesses/researcher.ts","../src/wp.ts","../src/harnesses/supervisor.ts","../src/index.ts"],"names":["DEFAULTS","opts"],"mappings":";;;;;;;;AAuBO,IAAM,eAAA,GAAkB;AAKxB,SAAS,cAAc,IAAA,EAAsC;AAClE,EAAA,OACE,IAAA,EAAM,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,kBAAA,IAAsB,eAAA;AAEnD;AAMO,IAAM,aAAA,GAAN,MAAM,cAAA,CAAc;AAAA,EAChB,GAAA;AAAA,EACT,OAAA;AAAA,EAEQ,WAAA,CAAY,KAAa,MAAA,EAAgB;AAC/C,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AACX,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,QAAQ,IAAA,EAAsD;AACzE,IAAA,MAAM,GAAA,GAAM,cAAc,IAAI,CAAA;AAC9B,IAAA,MAAM,SAAS,IAAI,MAAA;AAAA,MACjB,EAAE,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,OAAA,EAAQ;AAAA,MACpC,EAAE,YAAA,EAAc,EAAC;AAAE,KACrB;AACA,IAAA,MAAM,YAAY,IAAI,6BAAA,CAA8B,IAAI,GAAA,CAAI,GAAG,CAAC,CAAA;AAChE,IAAA,MAAM,MAAA,CAAO,QAAQ,SAAS,CAAA;AAC9B,IAAA,OAAO,IAAI,cAAA,CAAc,GAAA,EAAK,MAAM,CAAA;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,MAAM,IAAA,EAAkD;AAC5D,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,qBAAA,EAAuB,IAA0C,CAAA;AAAA,EACrF;AAAA;AAAA,EAGA,MAAM,MAAA,CAAO,SAAA,EAAmB,MAAA,EAA+B;AAC7D,IAAA,MAAM,KAAK,KAAA,CAAM,sBAAA,EAAwB,EAAE,SAAA,EAAW,QAAQ,CAAA;AAAA,EAChE;AAAA;AAAA,EAGA,MAAM,MAAA,CAAO,SAAA,EAAmB,KAAA,EAAiC;AAC/D,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA;AAAA,MACrB,0BAAA;AAAA,MACA,EAAE,WAAW,KAAA;AAAM,KACrB;AACA,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,IAAS,EAAC,EAAG,KAAK,IAAI,CAAA;AAAA,EACpC;AAAA;AAAA,EAGA,MAAM,KAAK,SAAA,EAAkC;AAC3C,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,oBAAA,EAAsB,EAAE,WAAW,CAAA;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAA,CACJ,UAAA,EACA,IAAA,EACqB;AACrB,IAAA,OAAO,IAAA,CAAK,MAAM,cAAA,EAAgB;AAAA,MAChC,UAAA;AAAA,MACA,GAAI,MAAM,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,IAAA,CAAK,SAAA,EAAU,GAAI,EAAC;AAAA,MACrE,GAAI,MAAM,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,IAAA,CAAK,KAAA,EAAM,GAAI;AAAC,KAC1D,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAA,CAAY,SAAA,EAAmB,SAAA,EAAuC;AAC1E,IAAA,OAAO,IAAA,CAAK,MAAM,cAAA,EAAgB;AAAA,MAChC,SAAA;AAAA,MACA,GAAI,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,KAAc;AAAC,KAChD,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,IAAA,CAAK,QAAQ,KAAA,EAAM;AAAA,EAC3B;AAAA;AAAA;AAAA,EAKA,MAAM,KAAA,CACJ,IAAA,EACA,IAAA,EACY;AACZ,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA,CAAQ,SAAS,EAAE,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,CAAA;AACjE,IAAA,MAAM,IAAA,GACJ,GAAA,CAAI,OAAA,CACJ,CAAC,CAAA,EAAG,IAAA;AACN,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,IAAI,CAAA,EAAA,CAAI,CAAA;AAAA,IACpD;AAGA,IAAA,IAAK,IAA8B,OAAA,EAAS;AAC1C,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,IAAI,CAAA,mBAAA,EAAsB,IAAI,CAAA,CAAE,CAAA;AAAA,IAC5D;AACA,IAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB;AACF;;;AChHO,SAAS,UAAA,CACd,QACA,IAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,OAAO,IAAA,CAAK,KAAA;AAAA,IAEZ,MAAM,KAAK,MAAA,EAA+B;AACxC,MAAA,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,MAAM,CAAA;AAAA,IAC5C,CAAA;AAAA,IAEA,MAAM,YAAY,IAAA,EAAoD;AACpE,MAAA,OAAO,MAAA,CAAO,UAAA,CAAW,CAAC,IAAA,CAAK,SAAS,CAAA,EAAG;AAAA,QACzC,KAAA,EAAO,KAAA;AAAA,QACP,GAAI,MAAM,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,IAAA,CAAK,SAAA,EAAU,GAAI;AAAC,OACtE,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,MAAM,GAAA,CAAI,MAAA,EAAgB,IAAA,EAAgD;AAIxE,MAAA,MAAM,cAAc,MAAA,CAAO,UAAA,CAAW,CAAC,IAAA,CAAK,SAAS,CAAA,EAAG;AAAA,QACtD,KAAA,EAAO,KAAA;AAAA,QACP,SAAA,EAAW,IAAA,EAAM,SAAA,KAAc,MAAA,GAAY,KAAK,SAAA,GAAY;AAAA,OAC7D,CAAA;AACD,MAAA,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,MAAM,CAAA;AAC1C,MAAA,MAAM,SAAS,MAAM,WAAA;AACrB,MAAA,IAAI,MAAA,CAAO,KAAA,KAAU,SAAA,EAAW,OAAO,WAAA;AACvC,MAAA,OAAO,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA;AAAA,IACrC,CAAA;AAAA,IAEA,MAAM,OAAO,IAAA,EAA4C;AACvD,MAAA,OAAO,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,MAAM,KAAK,CAAA;AAAA,IAClD,CAAA;AAAA,IAEA,MAAM,IAAA,GAAsB;AAC1B,MAAA,MAAM,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA;AAAA,IAClC;AAAA,GACF;AACF;;;AClDO,SAAS,kBAAkB,GAAA,EAA2B;AAC3D,EAAA,MAAM,KAAA,GAAkB,CAAC,mBAAmB,CAAA;AAC5C,EAAA,IAAI,IAAI,KAAA,EAAO,KAAA,CAAM,KAAK,CAAA,WAAA,EAAc,GAAA,CAAI,KAAK,CAAA,CAAE,CAAA;AACnD,EAAA,IAAI,IAAI,WAAA,EAAa,KAAA,CAAM,KAAK,CAAA,iBAAA,EAAoB,GAAA,CAAI,WAAW,CAAA,CAAE,CAAA;AACrE,EAAA,IAAI,GAAA,CAAI,UAAU,MAAA,EAAQ;AACxB,IAAA,KAAA,CAAM,IAAA;AAAA,MACJ,CAAA,UAAA,EAAa,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAA,EAAK,CAAC,CAAA,EAAA,CAAI,CAAA,CAAE,IAAA,CAAK,QAAK,CAAC,CAAA;AAAA,KAC9D;AAAA,EACF;AACA,EAAA,IAAI,GAAA,CAAI,KAAA,EAAO,KAAA,CAAM,IAAA,CAAK,IAAI,KAAK,CAAA;AACnC,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;;;ACOA,IAAM,QAAA,GAAW;AAAA,EACf,eAAA,EAAiB,iBAAA;AAAA,EACjB,WAAA,EAAa,0BAAA;AAAA,EACb,MAAA,EAAQ;AACV,CAAA;AAUO,SAAS,eAAe,IAAA,EAA2C;AACxE,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,aAAA;AAC9B,EAAA,MAAM,WAAW,MAAA,KAAW,QAAA;AAC5B,EAAA,MAAM,QACJ,IAAA,CAAK,KAAA,KACJ,QAAA,GAAW,QAAA,CAAS,cAAc,QAAA,CAAS,eAAA,CAAA;AAC9C,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,MAAA;AAAA,IACT,GAAI,QAAA,GAAW,EAAC,GAAI,EAAE,OAAO,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,QAAA,CAAS,MAAA,EAAO;AAAA,IACpE,GAAI,KAAK,SAAA,GAAY,EAAE,KAAK,IAAA,CAAK,SAAA,KAAc,EAAC;AAAA,IAChD,GAAI,KAAK,aAAA,GAAgB,EAAE,eAAe,IAAA,CAAK,aAAA,KAAkB,EAAC;AAAA,IAClE,GAAI,IAAA,CAAK,OAAA,GAAU,EAAE,MAAA,EAAQ,kBAAkB,IAAA,CAAK,OAAO,CAAA,EAAE,GAAI,EAAC;AAAA,IAClE,GAAI,KAAK,KAAA,GAAQ,EAAE,OAAO,IAAA,CAAK,KAAA,KAAU,EAAC;AAAA,IAC1C,GAAI,KAAK,UAAA,GAAa,EAAE,YAAY,IAAA,CAAK,UAAA,KAAe;AAAC,GAC3D;AACF;AAGA,eAAsB,kBAAA,CACpB,MAAA,EACA,IAAA,GAA4B,EAAC,EACP;AACtB,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,aAAA;AAC9B,EAAA,MAAM,WAAW,MAAA,KAAW,QAAA;AAC5B,EAAA,MAAM,SAAA,GAAY,WACb,IAAA,CAAK,KAAA,IAAS,SAAS,WAAA,GACvB,IAAA,CAAK,SAAS,QAAA,CAAS,eAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,eAAe,IAAI,CAAA;AAChC,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AACpC,EAAA,IAAI,YAAY,SAAA,EAAW;AACzB,IAAA,MAAM,OAAO,MAAA,CAAO,IAAA,CAAK,EAAA,EAAI,CAAA,OAAA,EAAU,SAAS,CAAA,CAAE,CAAA;AAGlD,IAAA,MAAM,MAAA,CAAO,UAAA,CAAW,CAAC,IAAA,CAAK,EAAE,CAAA,EAAG,EAAE,KAAA,EAAO,UAAA,EAAY,SAAA,EAAW,IAAA,EAAQ,CAAA;AAAA,EAC7E;AACA,EAAA,OAAO,WAAW,MAAA,EAAQ;AAAA,IACxB,WAAW,IAAA,CAAK,EAAA;AAAA,IAChB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,KAAA,EAAO;AAAA,GACR,CAAA;AACH;;;AC5DA,IAAMA,SAAAA,GAAW;AAAA,EACf,KAAA,EAAO;AACT,CAAA;AAGO,IAAM,uBAAA,GAA0B;AAAA,EACrC,QAAA,EAAU,UAAA;AAAA,EACV,OAAA,EAAS,UAAA;AAAA,EACT,UAAA,EAAY;AACd;AAUO,SAAS,uBACd,IAAA,EACQ;AACR,EAAA,MAAM,MAAA,GAAS,KAAK,YAAA,IAAgB,uBAAA;AACpC,EAAA,OAAO;AAAA,IACL,0EAAA;AAAA,IACA,mCAAA;AAAA,IACA,2DAAA;AAAA,IACA,EAAA;AAAA,IACA,oEAAA;AAAA,IACA,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAA;AAAA,IAC9B,EAAA;AAAA,IACA,cAAA;AAAA,IACA,KAAA;AAAA,IACA,0DAAA;AAAA,IACA,0CAAA;AAAA,IACA,yCAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AACb;AAcO,SAAS,oBACd,IAAA,EACgB;AAEhB,EAAA,MAAM,UAAA,GAA+B;AAAA,IACnC,GAAI,IAAA,CAAK,UAAA,IAAc,EAAC;AAAA,IACxB,GAAI,IAAA,CAAK,SAAA,GAAY,CAAC,IAAA,CAAK,SAAS,IAAI;AAAC,GAC3C;AACA,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,QAAA;AAAA,IACT,GAAI,KAAK,GAAA,GAAM,EAAE,KAAK,IAAA,CAAK,GAAA,KAAQ,EAAC;AAAA,IACpC,GAAI,KAAK,aAAA,GAAgB,EAAE,eAAe,IAAA,CAAK,aAAA,KAAkB,EAAC;AAAA,IAClE,GAAI,UAAA,CAAW,MAAA,GAAS,EAAE,UAAA,KAAe,EAAC;AAAA,IAC1C,GAAI,KAAK,KAAA,GAAQ,EAAE,OAAO,IAAA,CAAK,KAAA,KAAU;AAAC,GAC5C;AACF;AAGA,eAAsB,uBAAA,CACpB,MAAA,EACA,IAAA,GAAiC,EAAC,EACZ;AACtB,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,IAASA,SAAAA,CAAS,KAAA;AACzC,EAAA,MAAM,IAAA,GAAO,oBAAoB,IAAI,CAAA;AACrC,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AACpC,EAAA,IAAI,SAAA,EAAW;AAEb,IAAA,MAAM,OAAO,MAAA,CAAO,IAAA,CAAK,EAAA,EAAI,CAAA,OAAA,EAAU,SAAS,CAAA,CAAE,CAAA;AAClD,IAAA,MAAM,MAAA,CAAO,UAAA,CAAW,CAAC,IAAA,CAAK,EAAE,CAAA,EAAG,EAAE,KAAA,EAAO,UAAA,EAAY,SAAA,EAAW,IAAA,EAAQ,CAAA;AAAA,EAC7E;AAEA,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA,CAAK,EAAA,EAAI,sBAAA,CAAuB,IAAI,CAAC,CAAA;AACzD,EAAA,MAAM,MAAA,CAAO,UAAA,CAAW,CAAC,IAAA,CAAK,EAAE,CAAA,EAAG,EAAE,KAAA,EAAO,UAAA,EAAY,SAAA,EAAW,GAAA,EAAQ,CAAA;AAC3E,EAAA,OAAO,WAAW,MAAA,EAAQ;AAAA,IACxB,WAAW,IAAA,CAAK,EAAA;AAAA,IAChB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,KAAA,EAAO;AAAA,GACR,CAAA;AACH;;;ACvGO,SAAS,uBAAuB,YAAA,EAAqC;AAC1E,EAAA,MAAM,MAAA,GACJ,sJAAA;AAGF,EAAA,MAAM,IAAA,GAAO,YAAA,CACV,GAAA,CAAI,CAAA,EAAA,KAAM;AACT,IAAA,IAAI,IAAI,CAAA,GAAA,EAAM,EAAA,CAAG,EAAE,CAAA,QAAA,EAAM,GAAG,KAAK;AAAA,EAAK,GAAG,WAAW,CAAA,CAAA;AACpD,IAAA,IAAI,EAAA,CAAG,KAAA,EAAO,MAAA,EAAQ,CAAA,IAAK;AAAA,OAAA,EAAY,EAAA,CAAG,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAC1D,IAAA,IAAI,EAAA,CAAG,MAAM,CAAA,IAAK;AAAA,MAAA,EAAW,GAAG,IAAI,CAAA,CAAA;AACpC,IAAA,OAAO,CAAA;AAAA,EACT,CAAC,CAAA,CACA,IAAA,CAAK,MAAM,CAAA;AAEd,EAAA,OAAO,GAAG,MAAM;;AAAA,EAAO,IAAI,CAAA,CAAA;AAC7B;;;ACUA,IAAMA,SAAAA,GAAW;AAAA,EACf,KAAA,EAAO,iBAAA;AAAA,EACP,MAAA,EAAQ;AACV,CAAA;AAMO,SAAS,oBACd,IAAA,EACgB;AAChB,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,aAAA;AAAA,IACT,KAAA,EAAO,IAAA,CAAK,KAAA,IAASA,SAAAA,CAAS,KAAA;AAAA,IAC9B,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAUA,SAAAA,CAAS,MAAA;AAAA,IAChC,YAAA,EAAc,KAAK,YAAA,IAAgB,IAAA;AAAA,IACnC,GAAI,KAAK,SAAA,GAAY,EAAE,KAAK,IAAA,CAAK,SAAA,KAAc,EAAC;AAAA,IAChD,GAAI,KAAK,aAAA,GAAgB,EAAE,eAAe,IAAA,CAAK,aAAA,KAAkB,EAAC;AAAA,IAClE,GAAI,IAAA,CAAK,YAAA,EAAc,MAAA,GACnB,EAAE,MAAA,EAAQ,sBAAA,CAAuB,IAAA,CAAK,YAAa,CAAA,EAAE,GACrD,EAAC;AAAA,IACL,GAAI,KAAK,KAAA,GAAQ,EAAE,OAAO,IAAA,CAAK,KAAA,KAAU;AAAC,GAC5C;AACF;AAGA,eAAsB,uBAAA,CACpB,MAAA,EACA,IAAA,GAAiC,EAAC,EACP;AAC3B,EAAA,MAAM,IAAA,GAAO,oBAAoB,IAAI,CAAA;AACrC,EAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,WAAW,MAAA,EAAQ;AAAA,IAC9B,WAAW,IAAA,CAAK,EAAA;AAAA,IAChB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,GAAI,KAAK,KAAA,GAAQ,EAAE,OAAO,IAAA,CAAK,KAAA,KAAU;AAAC,GAC3C,CAAA;AACD,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,MAAM,OAAA,GAA4B;AAChC,MAAA,OAAO,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,EAAE,CAAA;AAAA,IACnC,CAAA;AAAA,IACA,MAAM,gBAAgBC,KAAAA,EAAoD;AACxE,MAAA,MAAM,IAAA,GAAQ,MAAM,MAAA,CAAO,WAAA,CAAY,KAAK,EAAE,CAAA;AAG9C,MAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,IAAA,CAAK,IAAA,IAAQ,EAAE,CAAA;AAChD,MAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,QAAA,OAAO;AAAA,UACL,WAAW,IAAA,CAAK,EAAA;AAAA,UAChB,KAAA,EAAO;AAAA,SACT;AAAA,MACF;AAEA,MAAA,MAAM,KAAA,GAAQ,EAAA;AACd,MAAA,IAAI,QAAA,CAAS,UAAU,KAAA,EAAO;AAC5B,QAAA,OAAO,MAAA,CAAO,UAAA,CAAW,QAAA,EAAUA,KAAI,CAAA;AAAA,MACzC;AACA,MAAA,MAAM,SAAqB,EAAC;AAC5B,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,MAAA,EAAQ,KAAK,KAAA,EAAO;AAC/C,QAAA,MAAA,CAAO,KAAK,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,KAAK,CAAC,CAAA;AAAA,MAC1C;AAIA,MAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU,MAAA,CAAO,UAAA,CAAW,KAAA,EAAOA,KAAI,CAAC,CAAC,CAAA;AAAA,IAC3E;AAAA,GACF;AACF;AAGA,SAAS,gBAAgB,KAAA,EAAsC;AAC7D,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,GAAA,CAAI,IAAA,CAAK,KAAK,EAAE,CAAA;AAChB,IAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAQ;AACzB,MAAA,GAAA,CAAI,IAAA,CAAK,GAAG,eAAA,CAAgB,IAAA,CAAK,QAAsB,CAAC,CAAA;AAAA,IAC1D;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;;;ACvGA,eAAsB,eACpB,IAAA,EACwB;AACxB,EAAA,OAAO,aAAA,CAAc,QAAQ,IAAI,CAAA;AACnC","file":"index.mjs","sourcesContent":["/**\n * @agentproto/harness — transport client (WP1).\n *\n * The single place that touches the MCP SDK + JSON-payload parsing. Connects to\n * the daemon's `/mcp` endpoint over `StreamableHTTPClientTransport` and exposes\n * typed wrappers over the session tools. Mirrors the proven pattern in\n * `packages/cli/src/commands/mcp-bridge.ts:30-58`.\n *\n * Tool results come back as `content: [{ type: \"text\", text: <JSON> }]`; the\n * `#call` helper unwraps + parses that text payload.\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\"\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\"\nimport type {\n ConnectHarnessOptions,\n SessionDescriptor,\n StartAgentArgs,\n TurnEvent,\n TurnResult,\n} from \"./types.js\"\n\n/** Default daemon MCP endpoint (port 18790; `serve.ts:186,865`). */\nexport const DEFAULT_MCP_URL = \"http://127.0.0.1:18790/mcp\"\n\n/**\n * Resolve the daemon URL: explicit option → `AGENTPROTO_MCP_URL` → default.\n */\nexport function resolveMcpUrl(opts?: ConnectHarnessOptions): string {\n return (\n opts?.url ?? process.env.AGENTPROTO_MCP_URL ?? DEFAULT_MCP_URL\n )\n}\n\n/**\n * Thin typed facade over the daemon's session MCP tools. One instance is shared\n * by all harnesses created against the same daemon.\n */\nexport class HarnessClient {\n readonly url: string\n #client: Client\n\n private constructor(url: string, client: Client) {\n this.url = url\n this.#client = client\n }\n\n /**\n * Connect an MCP client over HTTP to the daemon's `/mcp` endpoint.\n */\n static async connect(opts?: ConnectHarnessOptions): Promise<HarnessClient> {\n const url = resolveMcpUrl(opts)\n const client = new Client(\n { name: \"harness\", version: \"0.1.0\" },\n { capabilities: {} },\n )\n const transport = new StreamableHTTPClientTransport(new URL(url))\n await client.connect(transport)\n return new HarnessClient(url, client)\n }\n\n /** Spawn a session via `start_agent_session`. */\n async start(args: StartAgentArgs): Promise<SessionDescriptor> {\n return this.#call(\"start_agent_session\", args as unknown as Record<string, unknown>)\n }\n\n /** Send a follow-up turn via `prompt_agent_session` (fire-and-forget). */\n async prompt(sessionId: string, prompt: string): Promise<void> {\n await this.#call(\"prompt_agent_session\", { sessionId, prompt })\n }\n\n /** Tail the ring buffer via `get_agent_session_output`. */\n async output(sessionId: string, lastN?: number): Promise<string> {\n const res = await this.#call<{ lines?: string[] }>(\n \"get_agent_session_output\",\n { sessionId, lastN },\n )\n return (res.lines ?? []).join(\"\\n\")\n }\n\n /** SIGTERM via `kill_agent_session`. */\n async kill(sessionId: string): Promise<void> {\n await this.#call(\"kill_agent_session\", { sessionId })\n }\n\n /**\n * Multiplexed long-poll via `wait_for_any`. `timeoutMs` is clamped to the\n * tool's 1 000–49 000 window; a clean timeout surfaces as\n * `{ event: \"timeout\" }`.\n */\n async waitForAny(\n sessionIds: string[],\n opts?: { timeoutMs?: number; event?: TurnEvent },\n ): Promise<TurnResult> {\n return this.#call(\"wait_for_any\", {\n sessionIds,\n ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),\n ...(opts?.event !== undefined ? { event: opts.event } : {}),\n })\n }\n\n /**\n * Snapshot the session hierarchy via `session_tree`. When called from a\n * scoped orchestrator token only the caller's subtree is returned.\n */\n async sessionTree(sessionId: string, onlyAlive?: boolean): Promise<unknown> {\n return this.#call(\"session_tree\", {\n sessionId,\n ...(onlyAlive !== undefined ? { onlyAlive } : {}),\n })\n }\n\n /** Disconnect the underlying transport. */\n async close(): Promise<void> {\n await this.#client.close()\n }\n\n // ── private helpers ────────────────────────────────────────────────\n\n /** Call a daemon MCP tool and unwrap its JSON response. */\n async #call<T = unknown>(\n name: string,\n args: Record<string, unknown>,\n ): Promise<T> {\n const res = await this.#client.callTool({ name, arguments: args })\n const text = (\n res.content as Array<{ type: string; text?: string }>\n )[0]?.text\n if (!text) {\n throw new Error(`No content from tool \\`${name}\\``)\n }\n // TODO: remove cast once SDK types are stable — CallToolResult already\n // carries isError?: boolean in newer SDK versions.\n if ((res as { isError?: boolean }).isError) {\n throw new Error(`Tool \\`${name}\\` returned error: ${text}`)\n }\n return JSON.parse(text) as T\n }\n}\n","/**\n * @agentproto/harness — AgentHandle factory (WP2, STUB).\n *\n * `makeHandle` adapts a `HarnessClient` + a live session into the uniform\n * `AgentHandle` contract that every preset returns.\n */\n\nimport type { HarnessClient } from \"./client.js\"\nimport type { AgentHandle, TurnResult } from \"./types.js\"\n\nexport type { AgentHandle } from \"./types.js\"\n\nexport interface MakeHandleMeta {\n sessionId: string\n adapter: string\n model?: string\n}\n\n/**\n * Build an `AgentHandle` over a started session.\n *\n * WP2: implement `send` (→ client.prompt), `waitForTurn` (→ client.waitForAny\n * with `event: \"any\"` to catch `turn-end`, `awaiting-input`, and `exited`),\n * timeout → `{ event: \"timeout\" }`), `ask` (send + waitForTurn + output),\n * `output` (→ client.output), `kill` (→ client.kill).\n */\nexport function makeHandle(\n client: HarnessClient,\n meta: MakeHandleMeta,\n): AgentHandle {\n return {\n sessionId: meta.sessionId,\n adapter: meta.adapter,\n model: meta.model,\n\n async send(prompt: string): Promise<void> {\n await client.prompt(meta.sessionId, prompt)\n },\n\n async waitForTurn(opts?: { timeoutMs?: number }): Promise<TurnResult> {\n return client.waitForAny([meta.sessionId], {\n event: \"any\",\n ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),\n })\n },\n\n async ask(prompt: string, opts?: { timeoutMs?: number }): Promise<string> {\n // Start the wait BEFORE sending to avoid a race window: if the agent\n // turns around extremely fast the prompt could produce a turn-end before\n // waitForAny subscribes.\n const waitPromise = client.waitForAny([meta.sessionId], {\n event: \"any\",\n timeoutMs: opts?.timeoutMs !== undefined ? opts.timeoutMs : 45000,\n })\n await client.prompt(meta.sessionId, prompt)\n const result = await waitPromise\n if (result.event === \"timeout\") return \"[timeout]\"\n return client.output(meta.sessionId)\n },\n\n async output(opts?: { lastN?: number }): Promise<string> {\n return client.output(meta.sessionId, opts?.lastN)\n },\n\n async kill(): Promise<void> {\n await client.kill(meta.sessionId)\n },\n }\n}\n","/**\n * @agentproto/harness — coding context types + rendering.\n *\n * Extract of the coder preset's `CoderContext` shape and its prompt renderer,\n * so both the harness and the supervisor can reference them without a circular\n * import through the harness file.\n */\n\nimport type { CoderContext } from \"./types.js\"\n\nexport type { CoderContext }\n\n/**\n * Renders a `CoderContext` into an agent-facing instruction block.\n *\n * Produces a short markdown block with stack, conventions, and gate commands\n * the agent should verify before declaring a task done.\n */\nexport function renderCoderPrompt(ctx: CoderContext): string {\n const parts: string[] = [\"## Coding context\"]\n if (ctx.stack) parts.push(`**Stack:** ${ctx.stack}`)\n if (ctx.conventions) parts.push(`**Conventions:** ${ctx.conventions}`)\n if (ctx.gateCmds?.length) {\n parts.push(\n `**Gate:** ${ctx.gateCmds.map((c) => `\\`${c}\\``).join(\" · \")}`,\n )\n }\n if (ctx.extra) parts.push(ctx.extra)\n return parts.join(\"\\n\")\n}","/**\n * @agentproto/harness — coder preset (WP3, STUB).\n *\n * Spawns a coding agent: `claude-code` (default) or `hermes` routed to a coding\n * model via OpenRouter. Sets cwd to the workspace and injects a coding context\n * (stack, conventions, gate commands) as the initial prompt.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { renderCoderPrompt } from \"../context.js\"\nexport { renderCoderPrompt }\nimport type { CoderContext } from \"../context.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n McpServerMount,\n StartAgentArgs,\n} from \"../types.js\"\n\nexport interface CoderHarnessOptions {\n /** Absolute workspace path (wins over `workspaceSlug`). */\n workspace?: string\n workspaceSlug?: string\n /** Engine selector. Default `claude-code`. */\n engine?: \"claude-code\" | \"hermes\"\n /** Model override. Defaults: claude-code → `claude-opus-4-8`;\n * hermes → `deepseek/deepseek-v4-pro` (confirmed live, WP6). */\n model?: string\n /** Reasoning effort. Default `high`. */\n effort?: string\n /** Coding context rendered into the spawn prompt. */\n context?: CoderContext\n label?: string\n mcpServers?: McpServerMount[]\n}\n\nconst DEFAULTS = {\n claudeCodeModel: \"claude-opus-4-8\",\n hermesModel: \"deepseek/deepseek-v4-pro\",\n effort: \"high\",\n} as const\n\n/**\n * Build the `start_agent_session` args for the coder preset. Exported so WP3's\n * unit test can snapshot the args for both engines without a live daemon.\n *\n * For hermes: `model` and `effort` are NOT included — hermes does not declare\n * them as manifest options so the daemon rejects them at compose time. Instead,\n * `createCoderHarness` sends `/model <slug>` as a first prompt turn after spawn.\n */\nexport function buildCoderArgs(opts: CoderHarnessOptions): StartAgentArgs {\n const engine = opts.engine ?? \"claude-code\"\n const isHermes = engine === \"hermes\"\n const model =\n opts.model ??\n (isHermes ? DEFAULTS.hermesModel : DEFAULTS.claudeCodeModel)\n return {\n adapter: engine,\n ...(isHermes ? {} : { model, effort: opts.effort ?? DEFAULTS.effort }),\n ...(opts.workspace ? { cwd: opts.workspace } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(opts.context ? { prompt: renderCoderPrompt(opts.context) } : {}),\n ...(opts.label ? { label: opts.label } : {}),\n ...(opts.mcpServers ? { mcpServers: opts.mcpServers } : {}),\n }\n}\n\n/** Create a coder session and return its handle. */\nexport async function createCoderHarness(\n client: HarnessClient,\n opts: CoderHarnessOptions = {},\n): Promise<AgentHandle> {\n const engine = opts.engine ?? \"claude-code\"\n const isHermes = engine === \"hermes\"\n const modelSlug = isHermes\n ? (opts.model ?? DEFAULTS.hermesModel)\n : (opts.model ?? DEFAULTS.claudeCodeModel)\n const args = buildCoderArgs(opts)\n const desc = await client.start(args)\n if (isHermes && modelSlug) {\n await client.prompt(desc.id, `/model ${modelSlug}`)\n // wait for the model-switch turn to complete before caller uses the handle,\n // otherwise waitForTurn() on the first ask() triggers on this event instead\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 15_000 })\n }\n return makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n model: modelSlug,\n })\n}\n","/**\n * @agentproto/harness — researcher preset (WP4).\n *\n * Spawns a big-context research agent: `hermes` routed to GLM-5.2 via\n * OpenRouter. Mounts a web-search MCP server and injects a structured-output\n * instruction so replies are parseable.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n McpServerMount,\n StartAgentArgs,\n} from \"../types.js\"\n\nexport interface ResearcherHarnessOptions {\n /** Model override. Default `z-ai/glm-5.2` (big context, WP6). */\n model?: string\n cwd?: string\n workspaceSlug?: string\n /** MCP server to mount for web search (e.g. a bureau/search MCP ref). */\n searchMcp?: McpServerMount\n /** JSON schema hint injected into the spawn prompt for structured output. */\n outputSchema?: Record<string, unknown>\n effort?: string\n label?: string\n mcpServers?: McpServerMount[]\n}\n\nconst DEFAULTS = {\n model: \"z-ai/glm-5.2\",\n} as const\n\n/** Default output-schema hint the researcher is asked to return. */\nexport const DEFAULT_RESEARCH_SCHEMA = {\n findings: \"string[]\",\n sources: \"string[]\",\n confidence: \"low | medium | high\",\n} as const\n\n/**\n * Render the researcher spawn prompt — an instruction block telling the agent:\n * 1. It is a researcher agent.\n * 2. It MUST structure its final answer as JSON matching the outputSchema.\n * 3. Brief format hint: { findings: [...], sources: [...], confidence: \"...\" }\n *\n * Exported for unit tests.\n */\nexport function renderResearcherPrompt(\n opts: ResearcherHarnessOptions,\n): string {\n const schema = opts.outputSchema ?? DEFAULT_RESEARCH_SCHEMA\n return [\n \"You are a researcher agent. Use the available web-search tools to gather\",\n \"evidence and synthesize findings.\",\n \"Always reply in English regardless of the query language.\",\n \"\",\n \"You MUST structure your final answer as JSON matching this schema:\",\n JSON.stringify(schema, null, 2),\n \"\",\n \"Format hint:\",\n \" {\",\n ' \"findings\": [\"key finding 1\", \"key finding 2\", ...],',\n ' \"sources\": [\"url or citation\", ...],',\n ' \"confidence\": \"low | medium | high\"',\n \" }\",\n ].join(\"\\n\")\n}\n\n/**\n * Build the `start_agent_session` args for the researcher preset.\n * Exported so WP4's unit test can assert `mcpServers` + schema are present.\n *\n * `model`, `effort`, and the system `prompt` are NOT included here —\n * `createResearcherHarness` delivers them as controlled turns after spawn\n * so each step has exactly one turn-end to drain:\n * 1. `/model <slug>` → model switch turn-end (fast)\n * 2. system prompt turn → LLM response turn-end (may be slow)\n * This avoids the race where a spawn-time prompt fires a turn-end that\n * interferes with the caller's first `ask()`.\n */\nexport function buildResearcherArgs(\n opts: ResearcherHarnessOptions,\n): StartAgentArgs {\n // effort is not supported for hermes engine (not declared as a manifest option)\n const mcpServers: McpServerMount[] = [\n ...(opts.mcpServers ?? []),\n ...(opts.searchMcp ? [opts.searchMcp] : []),\n ]\n return {\n adapter: \"hermes\",\n ...(opts.cwd ? { cwd: opts.cwd } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(mcpServers.length ? { mcpServers } : {}),\n ...(opts.label ? { label: opts.label } : {}),\n }\n}\n\n/** Create a researcher session and return its handle. */\nexport async function createResearcherHarness(\n client: HarnessClient,\n opts: ResearcherHarnessOptions = {},\n): Promise<AgentHandle> {\n const modelSlug = opts.model ?? DEFAULTS.model\n const args = buildResearcherArgs(opts)\n const desc = await client.start(args)\n if (modelSlug) {\n // Step 1: switch model, drain its fast turn-end\n await client.prompt(desc.id, `/model ${modelSlug}`)\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 15_000 })\n }\n // Step 2: inject system prompt as an explicit turn, drain LLM response\n await client.prompt(desc.id, renderResearcherPrompt(opts))\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 30_000 })\n return makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n model: modelSlug,\n })\n}","/**\n * @agentproto/harness — WorkPackage type + supervisor prompt renderer (WP5).\n *\n * A WorkPackage describes a unit of work the supervisor assigns to a sub-agent.\n * `renderSupervisorPrompt` turns a list into a markdown orchestration brief.\n */\n\n/** A unit of work the supervisor harness assigns to a sub-agent. */\nexport interface WorkPackage {\n id: string // e.g. \"WP1\"\n title: string\n description: string\n files?: string[] // file scope\n gate?: string // gate command\n}\n\n/** Renders a WP list into a supervisor orchestration brief. */\nexport function renderSupervisorPrompt(workPackages: WorkPackage[]): string {\n const header =\n \"You are a supervisor agent. Execute the following work packages in order, \" +\n \"assigning each to a sub-agent. Gate each WP before proceeding to the next.\"\n\n const body = workPackages\n .map(wp => {\n let s = `## ${wp.id} — ${wp.title}\\n${wp.description}`\n if (wp.files?.length) s += `\\nFiles: ${wp.files.join(\", \")}`\n if (wp.gate) s += `\\nGate: ${wp.gate}`\n return s\n })\n .join(\"\\n\\n\")\n\n return `${header}\\n\\n${body}`\n}","/**\n * @agentproto/harness — supervisor preset (WP5).\n *\n * Spawns a `claude-code` opus orchestrator with `orchestrator: true` so it can\n * spawn + supervise its OWN sub-agents via the daemon's scoped sub-gateway.\n * Accepts a Work-Package list and renders it into an orchestration brief, and\n * adds fan-in helpers (`subtree`, `waitForAnyChild`) on top of `AgentHandle`.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n OrchestratorOption,\n StartAgentArgs,\n TurnResult,\n} from \"../types.js\"\nimport type { WorkPackage } from \"../wp.js\"\nimport { renderSupervisorPrompt } from \"../wp.js\"\nexport { renderSupervisorPrompt }\n\nexport interface SupervisorHarnessOptions {\n workspace?: string\n workspaceSlug?: string\n /** Model override. Default `claude-opus-4-8`. */\n model?: string\n effort?: string\n /** Scoped-orchestrator config. Default `true` (curated subset). */\n orchestrator?: OrchestratorOption\n /** Work packages to render into the orchestration brief. */\n workPackages?: WorkPackage[]\n label?: string\n}\n\n/** Supervisor handle adds fan-in helpers over the base contract. */\nexport interface SupervisorHandle extends AgentHandle {\n /** Snapshot this session's child subtree (→ `session_tree`). */\n subtree(): Promise<unknown>\n /** Block until ANY child session ends a turn (→ `wait_for_any`). */\n waitForAnyChild(opts?: { timeoutMs?: number }): Promise<TurnResult>\n}\n\nconst DEFAULTS = {\n model: \"claude-opus-4-8\",\n effort: \"high\",\n} as const\n\n/**\n * Build the `start_agent_session` args for the supervisor preset. Exported so\n * WP5's unit test can assert `orchestrator` + the rendered WP brief.\n */\nexport function buildSupervisorArgs(\n opts: SupervisorHarnessOptions,\n): StartAgentArgs {\n return {\n adapter: \"claude-code\",\n model: opts.model ?? DEFAULTS.model,\n effort: opts.effort ?? DEFAULTS.effort,\n orchestrator: opts.orchestrator ?? true,\n ...(opts.workspace ? { cwd: opts.workspace } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(opts.workPackages?.length\n ? { prompt: renderSupervisorPrompt(opts.workPackages!) }\n : {}),\n ...(opts.label ? { label: opts.label } : {}),\n }\n}\n\n/** Create a supervisor session and return its (extended) handle. */\nexport async function createSupervisorHarness(\n client: HarnessClient,\n opts: SupervisorHarnessOptions = {},\n): Promise<SupervisorHandle> {\n const args = buildSupervisorArgs(opts)\n const desc = await client.start(args)\n const base = makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n ...(args.model ? { model: args.model } : {}),\n })\n return {\n ...base,\n async subtree(): Promise<unknown> {\n return client.sessionTree(desc.id)\n },\n async waitForAnyChild(opts?: { timeoutMs?: number }): Promise<TurnResult> {\n const data = (await client.sessionTree(desc.id)) as {\n tree?: TreeNode[]\n }\n const childIds = collectChildIds(data.tree ?? [])\n if (childIds.length === 0) {\n return {\n sessionId: desc.id,\n event: \"timeout\",\n }\n }\n // wait_for_any accepts max 20 session IDs — chunk & race\n const CHUNK = 20\n if (childIds.length <= CHUNK) {\n return client.waitForAny(childIds, opts)\n }\n const chunks: string[][] = []\n for (let i = 0; i < childIds.length; i += CHUNK) {\n chunks.push(childIds.slice(i, i + CHUNK))\n }\n // NOTE: losing chunks are not cancellable — they poll until their own timeoutMs\n // expires. This is a known limitation of the wait_for_any tool (no cancel API).\n // Impact: at most (Math.ceil(n/20) - 1) extra open long-polls until timeout.\n return Promise.race(chunks.map((chunk) => client.waitForAny(chunk, opts)))\n },\n }\n}\n\n/** Recursively collect all child session ids from a session_tree result. */\nfunction collectChildIds(nodes: readonly TreeNode[]): string[] {\n const ids: string[] = []\n for (const node of nodes) {\n ids.push(node.id)\n if (node.children?.length) {\n ids.push(...collectChildIds(node.children as TreeNode[]))\n }\n }\n return ids\n}\n\ninterface TreeNode {\n id: string\n children?: unknown[]\n}","/**\n * @agentproto/harness — public barrel.\n *\n * Typed, one-call agent-session presets over the agentproto daemon's session\n * tools. Connect once, then spin up `coder` / `researcher` / `supervisor`\n * sessions that all resolve to the uniform `AgentHandle` contract.\n *\n * import { connectHarness, createCoderHarness } from \"@agentproto/harness\"\n * const dx = await connectHarness()\n * const coder = await createCoderHarness(dx, { workspace: process.cwd() })\n * const reply = await coder.ask(\"Add a health-check route\")\n */\n\nimport { HarnessClient } from \"./client.js\"\nimport type { ConnectHarnessOptions } from \"./types.js\"\n\n/**\n * Connect the shared transport to the daemon's `/mcp` endpoint. Returns a\n * `HarnessClient` to hand to the `create*Harness` factories.\n */\nexport async function connectHarness(\n opts?: ConnectHarnessOptions,\n): Promise<HarnessClient> {\n return HarnessClient.connect(opts)\n}\n\nexport { HarnessClient, DEFAULT_MCP_URL, resolveMcpUrl } from \"./client.js\"\nexport { makeHandle } from \"./handle.js\"\n\nexport {\n createCoderHarness,\n buildCoderArgs,\n renderCoderPrompt,\n type CoderHarnessOptions,\n} from \"./harnesses/coder.js\"\nexport {\n createResearcherHarness,\n buildResearcherArgs,\n renderResearcherPrompt,\n DEFAULT_RESEARCH_SCHEMA,\n type ResearcherHarnessOptions,\n} from \"./harnesses/researcher.js\"\nexport {\n createSupervisorHarness,\n buildSupervisorArgs,\n renderSupervisorPrompt,\n type SupervisorHarnessOptions,\n type SupervisorHandle,\n} from \"./harnesses/supervisor.js\"\n\nexport type {\n AgentHandle,\n TurnResult,\n TurnEvent,\n McpServerMount,\n OrchestratorOption,\n StartAgentArgs,\n SessionDescriptor,\n ConnectHarnessOptions,\n CoderContext,\n} from \"./types.js\"\nexport type { WorkPackage } from \"./wp.js\"\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/handle.ts","../src/context.ts","../src/harnesses/coder.ts","../src/harnesses/researcher.ts","../src/wp.ts","../src/harnesses/supervisor.ts","../src/index.ts"],"names":["DEFAULTS","opts"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @agentproto/harness — transport client (WP1).\n *\n * The single place that touches the MCP SDK + JSON-payload parsing. Connects to\n * the daemon's `/mcp` endpoint over `StreamableHTTPClientTransport` and exposes\n * typed wrappers over the session tools. Mirrors the proven pattern in\n * `packages/cli/src/commands/mcp-bridge.ts:30-58`.\n *\n * Tool results come back as `content: [{ type: \"text\", text: <JSON> }]`; the\n * `#call` helper unwraps + parses that text payload.\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\"\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\"\nimport type {\n ConnectHarnessOptions,\n SessionDescriptor,\n StartAgentArgs,\n TurnEvent,\n TurnResult,\n} from \"./types.js\"\n\n/** Default daemon MCP endpoint (port 18790; `serve.ts:186,865`). */\nexport const DEFAULT_MCP_URL = \"http://127.0.0.1:18790/mcp\"\n\n/**\n * Resolve the daemon URL: explicit option → `AGENTPROTO_MCP_URL` → default.\n */\nexport function resolveMcpUrl(opts?: ConnectHarnessOptions): string {\n return (\n opts?.url ?? process.env.AGENTPROTO_MCP_URL ?? DEFAULT_MCP_URL\n )\n}\n\n/**\n * Thin typed facade over the daemon's session MCP tools. One instance is shared\n * by all harnesses created against the same daemon.\n */\nexport class HarnessClient {\n readonly url: string\n #client: Client\n\n private constructor(url: string, client: Client) {\n this.url = url\n this.#client = client\n }\n\n /**\n * Connect an MCP client over HTTP to the daemon's `/mcp` endpoint.\n */\n static async connect(opts?: ConnectHarnessOptions): Promise<HarnessClient> {\n const url = resolveMcpUrl(opts)\n const client = new Client(\n { name: \"harness\", version: \"0.1.0\" },\n { capabilities: {} },\n )\n const transport = new StreamableHTTPClientTransport(new URL(url))\n await client.connect(transport)\n return new HarnessClient(url, client)\n }\n\n /** Spawn a session via `agent_start`. */\n async start(args: StartAgentArgs): Promise<SessionDescriptor> {\n return this.#call(\"agent_start\", args as unknown as Record<string, unknown>)\n }\n\n /** Send a follow-up turn via `agent_prompt` (fire-and-forget). `opts.interrupt`\n * cancels an in-flight turn and redirects the session onto this prompt instead\n * of rejecting (see `agent_prompt`'s `interrupt` field). */\n async prompt(sessionId: string, prompt: string, opts?: { interrupt?: boolean }): Promise<void> {\n await this.#call(\"agent_prompt\", {\n sessionId,\n prompt,\n ...(opts?.interrupt !== undefined ? { interrupt: opts.interrupt } : {}),\n })\n }\n\n /** Tail the ring buffer via `agent_output`. */\n async output(sessionId: string, lastN?: number): Promise<string> {\n const res = await this.#call<{ lines?: string[] }>(\n \"agent_output\",\n { sessionId, lastN },\n )\n return (res.lines ?? []).join(\"\\n\")\n }\n\n /** SIGTERM via `agent_kill`. */\n async kill(sessionId: string): Promise<void> {\n await this.#call(\"agent_kill\", { sessionId })\n }\n\n /**\n * Multiplexed long-poll via `session_monitor`. `timeoutMs` is clamped to the\n * tool's 1 000–49 000 window; a clean timeout surfaces as\n * `{ timedOut: true, sessionIds }` with no `event` field at all — `event`\n * is only ever set (to `\"turn-end\"|\"awaiting-input\"|\"exited\"`) on a real\n * match. Callers must check `timedOut`, not `event`, to detect a timeout.\n */\n async waitForAny(\n sessionIds: string[],\n opts?: { timeoutMs?: number; event?: TurnEvent },\n ): Promise<TurnResult> {\n return this.#call(\"session_monitor\", {\n sessionIds,\n ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),\n ...(opts?.event !== undefined ? { event: opts.event } : {}),\n })\n }\n\n /**\n * Snapshot the session hierarchy via `session_tree`. When called from a\n * scoped orchestrator token only the caller's subtree is returned.\n */\n async sessionTree(sessionId: string, onlyAlive?: boolean): Promise<unknown> {\n return this.#call(\"session_tree\", {\n sessionId,\n ...(onlyAlive !== undefined ? { onlyAlive } : {}),\n })\n }\n\n /** Disconnect the underlying transport. */\n async close(): Promise<void> {\n await this.#client.close()\n }\n\n // ── private helpers ────────────────────────────────────────────────\n\n /** Call a daemon MCP tool and unwrap its JSON response. */\n async #call<T = unknown>(\n name: string,\n args: Record<string, unknown>,\n ): Promise<T> {\n const res = await this.#client.callTool({ name, arguments: args })\n const text = (\n res.content as Array<{ type: string; text?: string }>\n )[0]?.text\n if (!text) {\n throw new Error(`No content from tool \\`${name}\\``)\n }\n // TODO: remove cast once SDK types are stable — CallToolResult already\n // carries isError?: boolean in newer SDK versions.\n if ((res as { isError?: boolean }).isError) {\n throw new Error(`Tool \\`${name}\\` returned error: ${text}`)\n }\n return JSON.parse(text) as T\n }\n}\n","/**\n * @agentproto/harness — AgentHandle factory (WP2, STUB).\n *\n * `makeHandle` adapts a `HarnessClient` + a live session into the uniform\n * `AgentHandle` contract that every preset returns.\n */\n\nimport type { HarnessClient } from \"./client.js\"\nimport type { AgentHandle, TurnResult } from \"./types.js\"\n\nexport type { AgentHandle } from \"./types.js\"\n\nexport interface MakeHandleMeta {\n sessionId: string\n adapter: string\n model?: string\n}\n\n/**\n * Build an `AgentHandle` over a started session.\n *\n * WP2: implement `send` (→ client.prompt), `waitForTurn` (→ client.waitForAny\n * with `event: \"any\"` to catch `turn-end`, `awaiting-input`, and `exited`),\n * timeout → `{ timedOut: true }`), `ask` (send + waitForTurn + output),\n * `output` (→ client.output), `kill` (→ client.kill).\n */\nexport function makeHandle(\n client: HarnessClient,\n meta: MakeHandleMeta,\n): AgentHandle {\n return {\n sessionId: meta.sessionId,\n adapter: meta.adapter,\n model: meta.model,\n\n async send(prompt: string): Promise<void> {\n await client.prompt(meta.sessionId, prompt)\n },\n\n async waitForTurn(opts?: { timeoutMs?: number }): Promise<TurnResult> {\n return client.waitForAny([meta.sessionId], {\n event: \"any\",\n ...(opts?.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),\n })\n },\n\n async ask(prompt: string, opts?: { timeoutMs?: number }): Promise<string> {\n // Start the wait BEFORE sending to avoid a race window: if the agent\n // turns around extremely fast the prompt could produce a turn-end before\n // waitForAny subscribes.\n const waitPromise = client.waitForAny([meta.sessionId], {\n event: \"any\",\n timeoutMs: opts?.timeoutMs !== undefined ? opts.timeoutMs : 45000,\n })\n await client.prompt(meta.sessionId, prompt)\n const result = await waitPromise\n if (result.timedOut) return \"[timeout]\"\n return client.output(meta.sessionId)\n },\n\n async output(opts?: { lastN?: number }): Promise<string> {\n return client.output(meta.sessionId, opts?.lastN)\n },\n\n async kill(): Promise<void> {\n await client.kill(meta.sessionId)\n },\n }\n}\n","/**\n * @agentproto/harness — coding context types + rendering.\n *\n * Extract of the coder preset's `CoderContext` shape and its prompt renderer,\n * so both the harness and the supervisor can reference them without a circular\n * import through the harness file.\n */\n\nimport type { CoderContext } from \"./types.js\"\n\nexport type { CoderContext }\n\n/**\n * Renders a `CoderContext` into an agent-facing instruction block.\n *\n * Produces a short markdown block with stack, conventions, and gate commands\n * the agent should verify before declaring a task done.\n */\nexport function renderCoderPrompt(ctx: CoderContext): string {\n const parts: string[] = [\"## Coding context\"]\n if (ctx.stack) parts.push(`**Stack:** ${ctx.stack}`)\n if (ctx.conventions) parts.push(`**Conventions:** ${ctx.conventions}`)\n if (ctx.gateCmds?.length) {\n parts.push(\n `**Gate:** ${ctx.gateCmds.map((c) => `\\`${c}\\``).join(\" · \")}`,\n )\n }\n if (ctx.extra) parts.push(ctx.extra)\n return parts.join(\"\\n\")\n}","/**\n * @agentproto/harness — coder preset (WP3, STUB).\n *\n * Spawns a coding agent: `claude-code` (default) or `hermes` routed to a coding\n * model via OpenRouter. Sets cwd to the workspace and injects a coding context\n * (stack, conventions, gate commands) as the initial prompt.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { renderCoderPrompt } from \"../context.js\"\nexport { renderCoderPrompt }\nimport type { CoderContext } from \"../context.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n McpServerMount,\n StartAgentArgs,\n} from \"../types.js\"\n\nexport interface CoderHarnessOptions {\n /** Absolute workspace path (wins over `workspaceSlug`). */\n workspace?: string\n workspaceSlug?: string\n /** Engine selector. Default `claude-code`. */\n engine?: \"claude-code\" | \"hermes\"\n /** Model override. Defaults: claude-code → `claude-opus-4-8`;\n * hermes → `deepseek/deepseek-v4-pro` (confirmed live, WP6). */\n model?: string\n /** Reasoning effort. Default `high`. */\n effort?: string\n /** Coding context rendered into the spawn prompt. */\n context?: CoderContext\n label?: string\n mcpServers?: McpServerMount[]\n}\n\nconst DEFAULTS = {\n claudeCodeModel: \"claude-opus-4-8\",\n hermesModel: \"deepseek/deepseek-v4-pro\",\n effort: \"high\",\n} as const\n\n/**\n * Build the `agent_start` args for the coder preset. Exported so WP3's\n * unit test can snapshot the args for both engines without a live daemon.\n *\n * For hermes: `model` and `effort` are NOT included — hermes does not declare\n * them as manifest options so the daemon rejects them at compose time. Instead,\n * `createCoderHarness` sends `/model <slug>` as a first prompt turn after spawn.\n */\nexport function buildCoderArgs(opts: CoderHarnessOptions): StartAgentArgs {\n const engine = opts.engine ?? \"claude-code\"\n const isHermes = engine === \"hermes\"\n const model =\n opts.model ??\n (isHermes ? DEFAULTS.hermesModel : DEFAULTS.claudeCodeModel)\n return {\n adapter: engine,\n ...(isHermes ? {} : { model, effort: opts.effort ?? DEFAULTS.effort }),\n ...(opts.workspace ? { cwd: opts.workspace } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(opts.context ? { prompt: renderCoderPrompt(opts.context) } : {}),\n ...(opts.label ? { label: opts.label } : {}),\n ...(opts.mcpServers ? { mcpServers: opts.mcpServers } : {}),\n }\n}\n\n/** Create a coder session and return its handle. */\nexport async function createCoderHarness(\n client: HarnessClient,\n opts: CoderHarnessOptions = {},\n): Promise<AgentHandle> {\n const engine = opts.engine ?? \"claude-code\"\n const isHermes = engine === \"hermes\"\n const modelSlug = isHermes\n ? (opts.model ?? DEFAULTS.hermesModel)\n : (opts.model ?? DEFAULTS.claudeCodeModel)\n const args = buildCoderArgs(opts)\n const desc = await client.start(args)\n if (isHermes && modelSlug) {\n await client.prompt(desc.id, `/model ${modelSlug}`)\n // wait for the model-switch turn to complete before caller uses the handle,\n // otherwise waitForTurn() on the first ask() triggers on this event instead\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 15_000 })\n }\n return makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n model: modelSlug,\n })\n}\n","/**\n * @agentproto/harness — researcher preset (WP4).\n *\n * Spawns a big-context research agent: `hermes` routed to GLM-5.2 via\n * OpenRouter. Mounts a web-search MCP server and injects a structured-output\n * instruction so replies are parseable.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n McpServerMount,\n StartAgentArgs,\n} from \"../types.js\"\n\nexport interface ResearcherHarnessOptions {\n /** Model override. Default `z-ai/glm-5.2` (big context, WP6). */\n model?: string\n cwd?: string\n workspaceSlug?: string\n /** MCP server to mount for web search (e.g. a bureau/search MCP ref). */\n searchMcp?: McpServerMount\n /** JSON schema hint injected into the spawn prompt for structured output. */\n outputSchema?: Record<string, unknown>\n effort?: string\n label?: string\n mcpServers?: McpServerMount[]\n}\n\nconst DEFAULTS = {\n model: \"z-ai/glm-5.2\",\n} as const\n\n/** Default output-schema hint the researcher is asked to return. */\nexport const DEFAULT_RESEARCH_SCHEMA = {\n findings: \"string[]\",\n sources: \"string[]\",\n confidence: \"low | medium | high\",\n} as const\n\n/**\n * Render the researcher spawn prompt — an instruction block telling the agent:\n * 1. It is a researcher agent.\n * 2. It MUST structure its final answer as JSON matching the outputSchema.\n * 3. Brief format hint: { findings: [...], sources: [...], confidence: \"...\" }\n *\n * Exported for unit tests.\n */\nexport function renderResearcherPrompt(\n opts: ResearcherHarnessOptions,\n): string {\n const schema = opts.outputSchema ?? DEFAULT_RESEARCH_SCHEMA\n return [\n \"You are a researcher agent. Use the available web-search tools to gather\",\n \"evidence and synthesize findings.\",\n \"Always reply in English regardless of the query language.\",\n \"\",\n \"You MUST structure your final answer as JSON matching this schema:\",\n JSON.stringify(schema, null, 2),\n \"\",\n \"Format hint:\",\n \" {\",\n ' \"findings\": [\"key finding 1\", \"key finding 2\", ...],',\n ' \"sources\": [\"url or citation\", ...],',\n ' \"confidence\": \"low | medium | high\"',\n \" }\",\n ].join(\"\\n\")\n}\n\n/**\n * Build the `agent_start` args for the researcher preset.\n * Exported so WP4's unit test can assert `mcpServers` + schema are present.\n *\n * `model`, `effort`, and the system `prompt` are NOT included here —\n * `createResearcherHarness` delivers them as controlled turns after spawn\n * so each step has exactly one turn-end to drain:\n * 1. `/model <slug>` → model switch turn-end (fast)\n * 2. system prompt turn → LLM response turn-end (may be slow)\n * This avoids the race where a spawn-time prompt fires a turn-end that\n * interferes with the caller's first `ask()`.\n */\nexport function buildResearcherArgs(\n opts: ResearcherHarnessOptions,\n): StartAgentArgs {\n // effort is not supported for hermes engine (not declared as a manifest option)\n const mcpServers: McpServerMount[] = [\n ...(opts.mcpServers ?? []),\n ...(opts.searchMcp ? [opts.searchMcp] : []),\n ]\n return {\n adapter: \"hermes\",\n ...(opts.cwd ? { cwd: opts.cwd } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(mcpServers.length ? { mcpServers } : {}),\n ...(opts.label ? { label: opts.label } : {}),\n }\n}\n\n/** Create a researcher session and return its handle. */\nexport async function createResearcherHarness(\n client: HarnessClient,\n opts: ResearcherHarnessOptions = {},\n): Promise<AgentHandle> {\n const modelSlug = opts.model ?? DEFAULTS.model\n const args = buildResearcherArgs(opts)\n const desc = await client.start(args)\n if (modelSlug) {\n // Step 1: switch model, drain its fast turn-end\n await client.prompt(desc.id, `/model ${modelSlug}`)\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 15_000 })\n }\n // Step 2: inject system prompt as an explicit turn, drain LLM response\n await client.prompt(desc.id, renderResearcherPrompt(opts))\n await client.waitForAny([desc.id], { event: \"turn-end\", timeoutMs: 30_000 })\n return makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n model: modelSlug,\n })\n}","/**\n * @agentproto/harness — WorkPackage type + supervisor prompt renderer (WP5).\n *\n * A WorkPackage describes a unit of work the supervisor assigns to a sub-agent.\n * `renderSupervisorPrompt` turns a list into a markdown orchestration brief.\n */\n\n/** A unit of work the supervisor harness assigns to a sub-agent. */\nexport interface WorkPackage {\n id: string // e.g. \"WP1\"\n title: string\n description: string\n files?: string[] // file scope\n gate?: string // gate command\n}\n\n/** Renders a WP list into a supervisor orchestration brief. */\nexport function renderSupervisorPrompt(workPackages: WorkPackage[]): string {\n const header =\n \"You are a supervisor agent. Execute the following work packages in order, \" +\n \"assigning each to a sub-agent. Gate each WP before proceeding to the next.\"\n\n const body = workPackages\n .map(wp => {\n let s = `## ${wp.id} — ${wp.title}\\n${wp.description}`\n if (wp.files?.length) s += `\\nFiles: ${wp.files.join(\", \")}`\n if (wp.gate) s += `\\nGate: ${wp.gate}`\n return s\n })\n .join(\"\\n\\n\")\n\n return `${header}\\n\\n${body}`\n}","/**\n * @agentproto/harness — supervisor preset (WP5).\n *\n * Spawns a `claude-code` opus orchestrator with `orchestrator: true` so it can\n * spawn + supervise its OWN sub-agents via the daemon's scoped sub-gateway.\n * Accepts a Work-Package list and renders it into an orchestration brief, and\n * adds fan-in helpers (`subtree`, `waitForAnyChild`) on top of `AgentHandle`.\n */\n\nimport type { HarnessClient } from \"../client.js\"\nimport { makeHandle } from \"../handle.js\"\nimport type {\n AgentHandle,\n OrchestratorOption,\n StartAgentArgs,\n TurnResult,\n} from \"../types.js\"\nimport type { WorkPackage } from \"../wp.js\"\nimport { renderSupervisorPrompt } from \"../wp.js\"\nexport { renderSupervisorPrompt }\n\nexport interface SupervisorHarnessOptions {\n workspace?: string\n workspaceSlug?: string\n /** Model override. Default `claude-opus-4-8`. */\n model?: string\n effort?: string\n /** Scoped-orchestrator config. Default `true` (curated subset). */\n orchestrator?: OrchestratorOption\n /** Work packages to render into the orchestration brief. */\n workPackages?: WorkPackage[]\n label?: string\n}\n\n/** Supervisor handle adds fan-in helpers over the base contract. */\nexport interface SupervisorHandle extends AgentHandle {\n /** Snapshot this session's child subtree (→ `session_tree`). */\n subtree(): Promise<unknown>\n /** Block until ANY child session ends a turn (→ `session_monitor`). */\n waitForAnyChild(opts?: { timeoutMs?: number }): Promise<TurnResult>\n}\n\nconst DEFAULTS = {\n model: \"claude-opus-4-8\",\n effort: \"high\",\n} as const\n\n/**\n * Build the `agent_start` args for the supervisor preset. Exported so\n * WP5's unit test can assert `orchestrator` + the rendered WP brief.\n */\nexport function buildSupervisorArgs(\n opts: SupervisorHarnessOptions,\n): StartAgentArgs {\n return {\n adapter: \"claude-code\",\n model: opts.model ?? DEFAULTS.model,\n effort: opts.effort ?? DEFAULTS.effort,\n orchestrator: opts.orchestrator ?? true,\n ...(opts.workspace ? { cwd: opts.workspace } : {}),\n ...(opts.workspaceSlug ? { workspaceSlug: opts.workspaceSlug } : {}),\n ...(opts.workPackages?.length\n ? { prompt: renderSupervisorPrompt(opts.workPackages!) }\n : {}),\n ...(opts.label ? { label: opts.label } : {}),\n }\n}\n\n/** Create a supervisor session and return its (extended) handle. */\nexport async function createSupervisorHarness(\n client: HarnessClient,\n opts: SupervisorHarnessOptions = {},\n): Promise<SupervisorHandle> {\n const args = buildSupervisorArgs(opts)\n const desc = await client.start(args)\n const base = makeHandle(client, {\n sessionId: desc.id,\n adapter: args.adapter,\n ...(args.model ? { model: args.model } : {}),\n })\n return {\n ...base,\n async subtree(): Promise<unknown> {\n return client.sessionTree(desc.id)\n },\n async waitForAnyChild(opts?: { timeoutMs?: number }): Promise<TurnResult> {\n const data = (await client.sessionTree(desc.id)) as {\n tree?: TreeNode[]\n }\n const childIds = collectChildIds(data.tree ?? [])\n if (childIds.length === 0) {\n return {\n sessionId: desc.id,\n timedOut: true,\n }\n }\n // session_monitor accepts max 20 session IDs — chunk & race\n const CHUNK = 20\n if (childIds.length <= CHUNK) {\n return client.waitForAny(childIds, opts)\n }\n const chunks: string[][] = []\n for (let i = 0; i < childIds.length; i += CHUNK) {\n chunks.push(childIds.slice(i, i + CHUNK))\n }\n // NOTE: losing chunks are not cancellable — they poll until their own timeoutMs\n // expires. This is a known limitation of the session_monitor tool (no cancel API).\n // Impact: at most (Math.ceil(n/20) - 1) extra open long-polls until timeout.\n return Promise.race(chunks.map((chunk) => client.waitForAny(chunk, opts)))\n },\n }\n}\n\n/** Recursively collect all child session ids from a session_tree result. */\nfunction collectChildIds(nodes: readonly TreeNode[]): string[] {\n const ids: string[] = []\n for (const node of nodes) {\n ids.push(node.id)\n if (node.children?.length) {\n ids.push(...collectChildIds(node.children as TreeNode[]))\n }\n }\n return ids\n}\n\ninterface TreeNode {\n id: string\n children?: unknown[]\n}","/**\n * @agentproto/harness — public barrel.\n *\n * Typed, one-call agent-session presets over the agentproto daemon's session\n * tools. Connect once, then spin up `coder` / `researcher` / `supervisor`\n * sessions that all resolve to the uniform `AgentHandle` contract.\n *\n * import { connectHarness, createCoderHarness } from \"@agentproto/harness\"\n * const dx = await connectHarness()\n * const coder = await createCoderHarness(dx, { workspace: process.cwd() })\n * const reply = await coder.ask(\"Add a health-check route\")\n */\n\nimport { HarnessClient } from \"./client.js\"\nimport type { ConnectHarnessOptions } from \"./types.js\"\n\n/**\n * Connect the shared transport to the daemon's `/mcp` endpoint. Returns a\n * `HarnessClient` to hand to the `create*Harness` factories.\n */\nexport async function connectHarness(\n opts?: ConnectHarnessOptions,\n): Promise<HarnessClient> {\n return HarnessClient.connect(opts)\n}\n\nexport { HarnessClient, DEFAULT_MCP_URL, resolveMcpUrl } from \"./client.js\"\nexport { makeHandle } from \"./handle.js\"\n\nexport {\n createCoderHarness,\n buildCoderArgs,\n renderCoderPrompt,\n type CoderHarnessOptions,\n} from \"./harnesses/coder.js\"\nexport {\n createResearcherHarness,\n buildResearcherArgs,\n renderResearcherPrompt,\n DEFAULT_RESEARCH_SCHEMA,\n type ResearcherHarnessOptions,\n} from \"./harnesses/researcher.js\"\nexport {\n createSupervisorHarness,\n buildSupervisorArgs,\n renderSupervisorPrompt,\n type SupervisorHarnessOptions,\n type SupervisorHandle,\n} from \"./harnesses/supervisor.js\"\n\nexport type {\n AgentHandle,\n TurnResult,\n TurnEvent,\n McpServerMount,\n OrchestratorOption,\n StartAgentArgs,\n SessionDescriptor,\n ConnectHarnessOptions,\n CoderContext,\n} from \"./types.js\"\nexport type { WorkPackage } from \"./wp.js\"\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @agentproto/harness — shared types.
|
|
3
3
|
*
|
|
4
|
-
* The harness wraps the daemon's session tools (`
|
|
5
|
-
* `
|
|
6
|
-
* `
|
|
4
|
+
* The harness wraps the daemon's session tools (`agent_start`,
|
|
5
|
+
* `agent_prompt`, `agent_output`, `agent_kill`,
|
|
6
|
+
* `session_monitor`) exposed over the `/mcp` endpoint. These types describe the
|
|
7
7
|
* client-side contract; the wire shapes mirror the tool schemas in
|
|
8
8
|
* `@agentproto/runtime` (`session-tools.ts`, `orchestration-tools.ts`).
|
|
9
9
|
*/
|
|
10
|
-
/** Lifecycle event a turn can settle on.
|
|
11
|
-
type TurnEvent = "turn-end" | "awaiting-input" | "exited" | "any"
|
|
12
|
-
/**
|
|
10
|
+
/** Lifecycle event a turn can settle on. */
|
|
11
|
+
type TurnEvent = "turn-end" | "awaiting-input" | "exited" | "any";
|
|
12
|
+
/**
|
|
13
|
+
* Result of `AgentHandle.waitForTurn` / `session_monitor`. On a real match,
|
|
14
|
+
* `event` is one of `"turn-end"|"awaiting-input"|"exited"` and `timedOut` is
|
|
15
|
+
* absent/falsy. On a clean timeout, the daemon returns `{ timedOut: true,
|
|
16
|
+
* sessionIds }` with no `event` field at all — there is no `"timeout"`
|
|
17
|
+
* literal on the wire.
|
|
18
|
+
*/
|
|
13
19
|
interface TurnResult {
|
|
14
|
-
sessionId
|
|
15
|
-
event
|
|
20
|
+
sessionId?: string;
|
|
21
|
+
event?: TurnEvent;
|
|
16
22
|
status?: string;
|
|
17
23
|
awaitingInput?: boolean;
|
|
24
|
+
timedOut?: boolean;
|
|
25
|
+
sessionIds?: string[];
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
20
|
-
* MCP-server mount forwarded verbatim to `
|
|
28
|
+
* MCP-server mount forwarded verbatim to `agent_start.mcpServers`
|
|
21
29
|
* (→ `session/new.mcpServers` on the ACP arm).
|
|
22
30
|
*/
|
|
23
31
|
interface McpServerMount {
|
|
@@ -27,7 +35,7 @@ interface McpServerMount {
|
|
|
27
35
|
[k: string]: unknown;
|
|
28
36
|
}
|
|
29
37
|
/**
|
|
30
|
-
* Scoped-orchestrator request — forwarded to `
|
|
38
|
+
* Scoped-orchestrator request — forwarded to `agent_start.orchestrator`.
|
|
31
39
|
* `true` = the default curated subset; the object form narrows it.
|
|
32
40
|
*/
|
|
33
41
|
type OrchestratorOption = boolean | {
|
|
@@ -36,7 +44,7 @@ type OrchestratorOption = boolean | {
|
|
|
36
44
|
maxChildren?: number;
|
|
37
45
|
};
|
|
38
46
|
/**
|
|
39
|
-
* Args handed to `
|
|
47
|
+
* Args handed to `agent_start`. 1:1 with the tool schema
|
|
40
48
|
* (`session-tools.ts:241-374`).
|
|
41
49
|
*/
|
|
42
50
|
interface StartAgentArgs {
|
|
@@ -51,7 +59,7 @@ interface StartAgentArgs {
|
|
|
51
59
|
orchestrator?: OrchestratorOption;
|
|
52
60
|
notifyUrl?: string;
|
|
53
61
|
}
|
|
54
|
-
/** Session descriptor as returned by `
|
|
62
|
+
/** Session descriptor as returned by `agent_start` (subset). */
|
|
55
63
|
interface SessionDescriptor {
|
|
56
64
|
id: string;
|
|
57
65
|
label?: string;
|
|
@@ -78,7 +86,7 @@ interface AgentHandle {
|
|
|
78
86
|
readonly model?: string;
|
|
79
87
|
/** Send a follow-up turn (fire-and-forget at the daemon). */
|
|
80
88
|
send(prompt: string): Promise<void>;
|
|
81
|
-
/** Block until this session ends its current turn (`
|
|
89
|
+
/** Block until this session ends its current turn (`session_monitor`). */
|
|
82
90
|
waitForTurn(opts?: {
|
|
83
91
|
timeoutMs?: number;
|
|
84
92
|
}): Promise<TurnResult>;
|
|
@@ -86,11 +94,11 @@ interface AgentHandle {
|
|
|
86
94
|
ask(prompt: string, opts?: {
|
|
87
95
|
timeoutMs?: number;
|
|
88
96
|
}): Promise<string>;
|
|
89
|
-
/** Tail the ring buffer (`
|
|
97
|
+
/** Tail the ring buffer (`agent_output`). */
|
|
90
98
|
output(opts?: {
|
|
91
99
|
lastN?: number;
|
|
92
100
|
}): Promise<string>;
|
|
93
|
-
/** SIGTERM the session (`
|
|
101
|
+
/** SIGTERM the session (`agent_kill`). */
|
|
94
102
|
kill(): Promise<void>;
|
|
95
103
|
}
|
|
96
104
|
/** Coding context injected by the coder harness into its spawn prompt. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "@agentproto/harness — typed, one-call agent-session presets (coder, researcher, supervisor) over the agentproto daemon's start/prompt/output session tools. A client-side recipe layer; adds no new daemon surface.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentproto",
|