@agentproto/harness 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -21
- package/dist/index.d.ts +10 -4
- package/dist/index.mjs +14 -6
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +13 -5
- package/package.json +2 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,202 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/dist/index.d.ts
CHANGED
|
@@ -32,8 +32,12 @@ declare class HarnessClient {
|
|
|
32
32
|
static connect(opts?: ConnectHarnessOptions): Promise<HarnessClient>;
|
|
33
33
|
/** Spawn a session via `agent_start`. */
|
|
34
34
|
start(args: StartAgentArgs): Promise<SessionDescriptor>;
|
|
35
|
-
/** Send a follow-up turn via `agent_prompt` (fire-and-forget).
|
|
36
|
-
|
|
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>;
|
|
37
41
|
/** Tail the ring buffer via `agent_output`. */
|
|
38
42
|
output(sessionId: string, lastN?: number): Promise<string>;
|
|
39
43
|
/** SIGTERM via `agent_kill`. */
|
|
@@ -41,7 +45,9 @@ declare class HarnessClient {
|
|
|
41
45
|
/**
|
|
42
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;
|
package/dist/index.mjs
CHANGED
|
@@ -34,9 +34,15 @@ var HarnessClient = class _HarnessClient {
|
|
|
34
34
|
async start(args) {
|
|
35
35
|
return this.#call("agent_start", args);
|
|
36
36
|
}
|
|
37
|
-
/** Send a follow-up turn via `agent_prompt` (fire-and-forget).
|
|
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
47
|
/** Tail the ring buffer via `agent_output`. */
|
|
42
48
|
async output(sessionId, lastN) {
|
|
@@ -53,7 +59,9 @@ var HarnessClient = class _HarnessClient {
|
|
|
53
59
|
/**
|
|
54
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
67
|
return this.#call("session_monitor", {
|
|
@@ -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":"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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). */\n async prompt(sessionId: string, prompt: string): Promise<void> {\n await this.#call(\"agent_prompt\", { sessionId, prompt })\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 * `{ event: \"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 → `{ 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 `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 event: \"timeout\",\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"]}
|
|
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
|
@@ -7,14 +7,22 @@
|
|
|
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
28
|
* MCP-server mount forwarded verbatim to `agent_start.mcpServers`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"bugs": {
|
|
21
21
|
"url": "https://github.com/agentproto/ts/issues"
|
|
22
22
|
},
|
|
23
|
-
"license": "
|
|
23
|
+
"license": "Apache-2.0",
|
|
24
24
|
"type": "module",
|
|
25
25
|
"main": "dist/index.mjs",
|
|
26
26
|
"module": "dist/index.mjs",
|