@botbotgo/agent-harness 0.0.308 → 0.0.310

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.
Files changed (195) hide show
  1. package/README.md +17 -1
  2. package/README.zh.md +17 -1
  3. package/dist/acp.d.ts +1 -116
  4. package/dist/acp.js +1 -310
  5. package/dist/api.d.ts +4 -2
  6. package/dist/api.js +4 -1
  7. package/dist/cli/chat-interactive.d.ts +24 -0
  8. package/dist/cli/chat-interactive.js +244 -0
  9. package/dist/cli/chat-rendering.d.ts +9 -0
  10. package/dist/cli/chat-rendering.js +102 -0
  11. package/dist/cli/chat-stream.d.ts +23 -0
  12. package/dist/cli/chat-stream.js +330 -0
  13. package/dist/cli/chat-ui.d.ts +20 -0
  14. package/dist/cli/chat-ui.js +198 -0
  15. package/dist/cli/chat-workspace.d.ts +15 -0
  16. package/dist/cli/chat-workspace.js +205 -0
  17. package/dist/cli/main.d.ts +52 -0
  18. package/dist/cli/main.js +323 -0
  19. package/dist/cli/managed-service-commands.d.ts +23 -0
  20. package/dist/cli/managed-service-commands.js +63 -0
  21. package/dist/cli/managed-service.d.ts +27 -0
  22. package/dist/cli/managed-service.js +61 -0
  23. package/dist/cli/options-init-chat.d.ts +16 -0
  24. package/dist/cli/options-init-chat.js +108 -0
  25. package/dist/cli/options-runtime.d.ts +27 -0
  26. package/dist/cli/options-runtime.js +158 -0
  27. package/dist/cli/options-serve.d.ts +24 -0
  28. package/dist/cli/options-serve.js +166 -0
  29. package/dist/cli/options.d.ts +5 -0
  30. package/dist/cli/options.js +47 -0
  31. package/dist/cli/process-guards.d.ts +14 -0
  32. package/dist/cli/process-guards.js +139 -0
  33. package/dist/cli/request-tree.d.ts +12 -0
  34. package/dist/cli/request-tree.js +296 -0
  35. package/dist/cli/runtime-commands.d.ts +15 -0
  36. package/dist/cli/runtime-commands.js +247 -0
  37. package/dist/cli/runtime-output.d.ts +5 -0
  38. package/dist/cli/runtime-output.js +124 -0
  39. package/dist/cli/server-commands.d.ts +36 -0
  40. package/dist/cli/server-commands.js +250 -0
  41. package/dist/cli/workspace.d.ts +6 -0
  42. package/dist/cli/workspace.js +71 -0
  43. package/dist/cli.d.ts +1 -67
  44. package/dist/cli.js +2 -2734
  45. package/dist/client/acp.d.ts +1 -50
  46. package/dist/client/acp.js +1 -219
  47. package/dist/client/in-process.d.ts +5 -5
  48. package/dist/client/index.d.ts +2 -2
  49. package/dist/client/index.js +1 -1
  50. package/dist/contracts/runtime-evaluation.d.ts +103 -0
  51. package/dist/contracts/runtime-evaluation.js +1 -0
  52. package/dist/contracts/runtime-memory.d.ts +162 -0
  53. package/dist/contracts/runtime-memory.js +1 -0
  54. package/dist/contracts/runtime-observability.d.ts +248 -0
  55. package/dist/contracts/runtime-observability.js +1 -0
  56. package/dist/contracts/runtime-requests.d.ts +342 -0
  57. package/dist/contracts/runtime-requests.js +1 -0
  58. package/dist/contracts/runtime-scheduling.d.ts +146 -0
  59. package/dist/contracts/runtime-scheduling.js +1 -0
  60. package/dist/contracts/runtime.d.ts +5 -1042
  61. package/dist/contracts/runtime.js +27 -1
  62. package/dist/flow/build-flow-graph.js +4 -875
  63. package/dist/flow/flow-graph-normalization.d.ts +56 -0
  64. package/dist/flow/flow-graph-normalization.js +214 -0
  65. package/dist/flow/flow-graph-runtime.d.ts +8 -0
  66. package/dist/flow/flow-graph-runtime.js +107 -0
  67. package/dist/flow/flow-graph-upstream.d.ts +18 -0
  68. package/dist/flow/flow-graph-upstream.js +498 -0
  69. package/dist/flow/types.d.ts +1 -1
  70. package/dist/index.d.ts +4 -4
  71. package/dist/index.js +2 -2
  72. package/dist/init-project.d.ts +1 -12
  73. package/dist/init-project.js +1 -651
  74. package/dist/{procedural → knowledge/procedural}/manager.d.ts +3 -3
  75. package/dist/{procedural → knowledge/procedural}/manager.js +6 -6
  76. package/dist/mcp.d.ts +2 -62
  77. package/dist/mcp.js +2 -253
  78. package/dist/package-version.d.ts +1 -1
  79. package/dist/package-version.js +1 -1
  80. package/dist/persistence/file-store.js +1 -1
  81. package/dist/persistence/sqlite-runtime.d.ts +19 -0
  82. package/dist/persistence/sqlite-runtime.js +86 -0
  83. package/dist/persistence/sqlite-store.js +11 -99
  84. package/dist/{request-events.d.ts → projections/request-events.d.ts} +1 -1
  85. package/dist/{upstream-events.js → projections/upstream-events.js} +1 -1
  86. package/dist/protocol/a2a/http-discovery.d.ts +39 -0
  87. package/dist/protocol/a2a/http-discovery.js +178 -0
  88. package/dist/protocol/a2a/http-rpc.d.ts +28 -0
  89. package/dist/protocol/a2a/http-rpc.js +623 -0
  90. package/dist/protocol/a2a/http.d.ts +72 -1
  91. package/dist/protocol/a2a/http.js +14 -1124
  92. package/dist/protocol/a2a/task-state.d.ts +29 -0
  93. package/dist/protocol/a2a/task-state.js +317 -0
  94. package/dist/protocol/acp/client.js +1 -1
  95. package/dist/protocol/acp/harness-client.d.ts +50 -0
  96. package/dist/protocol/acp/harness-client.js +219 -0
  97. package/dist/protocol/acp/server.d.ts +116 -0
  98. package/dist/protocol/acp/server.js +310 -0
  99. package/dist/protocol/ag-ui/http.js +1 -1
  100. package/dist/protocol/mcp/server.d.ts +76 -0
  101. package/dist/protocol/mcp/server.js +428 -0
  102. package/dist/resource/backend/workspace-scoped-backend.d.ts +40 -0
  103. package/dist/resource/backend/workspace-scoped-backend.js +296 -0
  104. package/dist/resource/mcp/tool-support.d.ts +35 -0
  105. package/dist/resource/mcp/tool-support.js +296 -0
  106. package/dist/resource/mcp-tool-support.d.ts +2 -35
  107. package/dist/resource/mcp-tool-support.js +2 -296
  108. package/dist/resource/providers/resource-provider.d.ts +22 -0
  109. package/dist/resource/providers/resource-provider.js +215 -0
  110. package/dist/resource/resource-impl.d.ts +3 -33
  111. package/dist/resource/resource-impl.js +2 -808
  112. package/dist/resource/resource-types.d.ts +33 -0
  113. package/dist/resource/resource-types.js +1 -0
  114. package/dist/resource/tools/function-tool-resolver.d.ts +2 -0
  115. package/dist/resource/tools/function-tool-resolver.js +306 -0
  116. package/dist/runtime/adapter/middleware-assembly.js +1 -1
  117. package/dist/runtime/adapter/model/invocation-request.js +2 -2
  118. package/dist/runtime/adapter/model/message-assembly.js +1 -1
  119. package/dist/runtime/agent-runtime-adapter.d.ts +3 -63
  120. package/dist/runtime/agent-runtime-adapter.js +5 -233
  121. package/dist/runtime/agent-runtime-assembly.d.ts +67 -0
  122. package/dist/runtime/agent-runtime-assembly.js +211 -0
  123. package/dist/runtime/harness/background-runtime.d.ts +1 -1
  124. package/dist/runtime/harness/events/event-sink.js +1 -1
  125. package/dist/runtime/harness/events/runtime-event-operations.d.ts +1 -1
  126. package/dist/runtime/harness/events/streaming.js +1 -1
  127. package/dist/runtime/harness/public-shapes.d.ts +43 -0
  128. package/dist/runtime/harness/public-shapes.js +186 -0
  129. package/dist/runtime/harness/run/inspection.js +2 -2
  130. package/dist/runtime/harness/run/resources.js +1 -1
  131. package/dist/runtime/harness/run/surface-semantics.js +1 -1
  132. package/dist/runtime/harness/system/inventory.d.ts +1 -1
  133. package/dist/runtime/harness/system/inventory.js +2 -2
  134. package/dist/runtime/harness/system/policy-engine.js +1 -1
  135. package/dist/runtime/harness/system/runtime-memory-manager.js +1 -1
  136. package/dist/runtime/harness/system/skill-requirements.d.ts +1 -1
  137. package/dist/runtime/harness/system/skill-requirements.js +1 -1
  138. package/dist/runtime/harness.d.ts +3 -2
  139. package/dist/runtime/harness.js +11 -191
  140. package/dist/runtime/maintenance/checkpoint-maintenance.js +1 -1
  141. package/dist/runtime/maintenance/runtime-record-maintenance.js +1 -1
  142. package/dist/runtime/parsing/output-content.d.ts +11 -0
  143. package/dist/runtime/parsing/output-content.js +442 -0
  144. package/dist/runtime/parsing/output-parsing.d.ts +3 -29
  145. package/dist/runtime/parsing/output-parsing.js +3 -806
  146. package/dist/runtime/parsing/output-recovery.d.ts +14 -0
  147. package/dist/runtime/parsing/output-recovery.js +288 -0
  148. package/dist/runtime/parsing/output-tool-args.d.ts +4 -0
  149. package/dist/runtime/parsing/output-tool-args.js +120 -0
  150. package/dist/runtime/support/runtime-factories.js +1 -1
  151. package/dist/scaffold/init-project.d.ts +12 -0
  152. package/dist/scaffold/init-project.js +651 -0
  153. package/dist/{extensions.d.ts → tooling/extensions.d.ts} +1 -1
  154. package/dist/{extensions.js → tooling/extensions.js} +3 -3
  155. package/dist/{tool-modules.d.ts → tooling/module-loader.d.ts} +1 -1
  156. package/dist/{tool-modules.js → tooling/module-loader.js} +2 -2
  157. package/dist/workspace/agent-binding-compiler.js +2 -2
  158. package/dist/workspace/compile.js +2 -2
  159. package/dist/workspace/object-loader-paths.d.ts +11 -0
  160. package/dist/workspace/object-loader-paths.js +75 -0
  161. package/dist/workspace/object-loader-readers.d.ts +21 -0
  162. package/dist/workspace/object-loader-readers.js +187 -0
  163. package/dist/workspace/object-loader.d.ts +0 -1
  164. package/dist/workspace/object-loader.js +6 -260
  165. package/dist/workspace/resource-compilers.js +1 -1
  166. package/dist/workspace/support/discovery.js +1 -1
  167. package/package.json +1 -1
  168. package/dist/runtime/adapter/index.d.ts +0 -13
  169. package/dist/runtime/adapter/index.js +0 -13
  170. package/dist/runtime/harness/index.d.ts +0 -19
  171. package/dist/runtime/harness/index.js +0 -19
  172. package/dist/runtime/maintenance/index.d.ts +0 -4
  173. package/dist/runtime/maintenance/index.js +0 -4
  174. package/dist/runtime/parsing/index.d.ts +0 -2
  175. package/dist/runtime/parsing/index.js +0 -2
  176. package/dist/runtime/support/index.d.ts +0 -4
  177. package/dist/runtime/support/index.js +0 -4
  178. package/dist/workspace/support/index.d.ts +0 -2
  179. package/dist/workspace/support/index.js +0 -2
  180. /package/dist/{procedural → knowledge/procedural}/config.d.ts +0 -0
  181. /package/dist/{procedural → knowledge/procedural}/config.js +0 -0
  182. /package/dist/{procedural → knowledge/procedural}/index.d.ts +0 -0
  183. /package/dist/{procedural → knowledge/procedural}/index.js +0 -0
  184. /package/dist/{presentation.d.ts → projections/presentation.d.ts} +0 -0
  185. /package/dist/{presentation.js → projections/presentation.js} +0 -0
  186. /package/dist/{request-events.js → projections/request-events.js} +0 -0
  187. /package/dist/{upstream-events.d.ts → projections/upstream-events.d.ts} +0 -0
  188. /package/dist/runtime/{support → env}/runtime-env.d.ts +0 -0
  189. /package/dist/runtime/{support → env}/runtime-env.js +0 -0
  190. /package/dist/runtime/{support → layout}/runtime-layout.d.ts +0 -0
  191. /package/dist/runtime/{support → layout}/runtime-layout.js +0 -0
  192. /package/dist/runtime/{support → prompts}/runtime-prompts.d.ts +0 -0
  193. /package/dist/runtime/{support → prompts}/runtime-prompts.js +0 -0
  194. /package/dist/runtime/{support → skills}/skill-metadata.d.ts +0 -0
  195. /package/dist/runtime/{support → skills}/skill-metadata.js +0 -0
@@ -0,0 +1,29 @@
1
+ import type { AgentHarnessRuntime } from "../../runtime/harness.js";
2
+ import type { ApprovalRecord, RequestRecord, RequestResult, SessionRecord } from "../../contracts/types.js";
3
+ import type { A2aSendMessageResponse, A2aTask, A2aTaskList, A2aTaskState, A2aStreamingResult, StoredA2aPushNotificationConfig, A2aPushNotificationConfig } from "./http.js";
4
+ export declare function mapRequestState(state: string): A2aTaskState;
5
+ export declare function mapTaskStatusToRequestState(state: string | undefined): RequestResult["state"] | undefined;
6
+ export declare function toTextParts(text: string | undefined): Array<{
7
+ text: string;
8
+ mediaType: "text/plain";
9
+ }>;
10
+ export declare function toSessionRecord(session: Awaited<ReturnType<AgentHarnessRuntime["getSessionRecord"]>>): SessionRecord | null;
11
+ export declare function toRequestRecord(request: Awaited<ReturnType<AgentHarnessRuntime["getRequest"]>>): RequestRecord | null;
12
+ export declare function buildTaskFromSessionAndRequest(session: SessionRecord | null, request: RequestRecord | null, approvals: ApprovalRecord[], output?: string, failureMessage?: string): A2aTask | null;
13
+ export declare function buildTaskFromRuntime(runtime: AgentHarnessRuntime, requestId: string): Promise<A2aTask | null>;
14
+ export declare function hydrateTaskStateFromEvents(runtime: AgentHarnessRuntime, task: A2aTask | null): Promise<A2aTask | null>;
15
+ export declare function listTasksFromRuntime(runtime: AgentHarnessRuntime, params: {
16
+ agentId?: string;
17
+ contextId?: string;
18
+ state?: string;
19
+ limit: number;
20
+ cursor?: string;
21
+ }): Promise<A2aTaskList>;
22
+ export declare function isV1Method(method: string): boolean;
23
+ export declare function toSendMessageResult(method: string, task: A2aTask | null): A2aTask | A2aSendMessageResponse | null;
24
+ export declare function toStreamingResult(method: string, task: A2aTask | null, mode: "task" | "status-update"): A2aStreamingResult;
25
+ export declare function withStreamingStatusText(task: A2aTask | null, text: string | undefined): A2aTask | null;
26
+ export declare function withRunResult(task: A2aTask | null, result: RequestResult, streamedText?: string): A2aTask | null;
27
+ export declare function isTerminalTaskState(state: A2aTaskState): boolean;
28
+ export declare function clonePushNotificationConfig(config: StoredA2aPushNotificationConfig): A2aPushNotificationConfig;
29
+ export declare function fingerprintTaskForPush(task: A2aTask): string;
@@ -0,0 +1,317 @@
1
+ export function mapRequestState(state) {
2
+ switch (state) {
3
+ case "queued":
4
+ return "TASK_STATE_SUBMITTED";
5
+ case "running":
6
+ return "TASK_STATE_WORKING";
7
+ case "waiting_for_approval":
8
+ return "TASK_STATE_INPUT_REQUIRED";
9
+ case "completed":
10
+ return "TASK_STATE_COMPLETED";
11
+ case "cancelled":
12
+ return "TASK_STATE_CANCELED";
13
+ case "failed":
14
+ default:
15
+ return "TASK_STATE_FAILED";
16
+ }
17
+ }
18
+ export function mapTaskStatusToRequestState(state) {
19
+ switch (state?.toLowerCase().replace(/^task_state_/, "").replace(/_/g, "-")) {
20
+ case "submitted":
21
+ return "queued";
22
+ case "working":
23
+ return "running";
24
+ case "input-required":
25
+ return "waiting_for_approval";
26
+ case "completed":
27
+ return "completed";
28
+ case "failed":
29
+ return "failed";
30
+ case "canceled":
31
+ case "cancelled":
32
+ return "cancelled";
33
+ default:
34
+ return undefined;
35
+ }
36
+ }
37
+ export function toTextParts(text) {
38
+ if (typeof text !== "string" || text.length === 0) {
39
+ return [];
40
+ }
41
+ return [{ text, mediaType: "text/plain" }];
42
+ }
43
+ function contentToText(content) {
44
+ if (typeof content === "string") {
45
+ return content;
46
+ }
47
+ if (!Array.isArray(content)) {
48
+ return undefined;
49
+ }
50
+ const text = content
51
+ .filter((part) => part.type === "text" && typeof part.text === "string")
52
+ .map((part) => part.text)
53
+ .join("\n\n")
54
+ .trim();
55
+ return text.length > 0 ? text : undefined;
56
+ }
57
+ export function toSessionRecord(session) {
58
+ return session ? toSessionRecordInternal(session) : null;
59
+ }
60
+ function toSessionRecordInternal(session) {
61
+ return {
62
+ sessionId: session.sessionId,
63
+ entryAgentId: session.entryAgentId,
64
+ currentAgentId: session.currentAgentId,
65
+ currentState: session.currentState,
66
+ latestRequestId: session.latestRequestId,
67
+ createdAt: session.createdAt,
68
+ updatedAt: session.updatedAt,
69
+ messages: session.messages,
70
+ requests: session.requests.map((request) => ({
71
+ requestId: request.requestId,
72
+ sessionId: request.sessionId,
73
+ agentId: request.agentId,
74
+ executionMode: request.executionMode,
75
+ adapterKind: request.adapterKind,
76
+ createdAt: request.createdAt,
77
+ updatedAt: request.updatedAt,
78
+ state: request.state,
79
+ checkpointRef: request.checkpointRef,
80
+ resumable: request.resumable,
81
+ startedAt: request.startedAt,
82
+ endedAt: request.endedAt,
83
+ lastActivityAt: request.lastActivityAt,
84
+ currentAgentId: request.currentAgentId,
85
+ delegationChain: request.delegationChain,
86
+ runtimeSnapshot: request.runtimeSnapshot,
87
+ traceItems: request.traceItems,
88
+ runtimeTimeline: request.runtimeTimeline,
89
+ })),
90
+ pendingDecision: session.pendingDecision,
91
+ };
92
+ }
93
+ export function toRequestRecord(request) {
94
+ if (!request) {
95
+ return null;
96
+ }
97
+ return {
98
+ requestId: request.requestId,
99
+ sessionId: request.sessionId,
100
+ agentId: request.agentId,
101
+ executionMode: request.executionMode,
102
+ adapterKind: request.adapterKind,
103
+ createdAt: request.createdAt,
104
+ updatedAt: request.updatedAt,
105
+ state: request.state,
106
+ checkpointRef: request.checkpointRef,
107
+ resumable: request.resumable,
108
+ startedAt: request.startedAt,
109
+ endedAt: request.endedAt,
110
+ lastActivityAt: request.lastActivityAt,
111
+ currentAgentId: request.currentAgentId,
112
+ delegationChain: request.delegationChain,
113
+ runtimeSnapshot: request.runtimeSnapshot,
114
+ traceItems: request.traceItems,
115
+ runtimeTimeline: request.runtimeTimeline,
116
+ };
117
+ }
118
+ export function buildTaskFromSessionAndRequest(session, request, approvals, output, failureMessage) {
119
+ if (!session || !request) {
120
+ return null;
121
+ }
122
+ const latestUserMessage = [...session.messages].reverse().find((message) => message.role === "user");
123
+ const latestAgentMessage = [...session.messages].reverse().find((message) => message.role === "assistant");
124
+ const approval = approvals.find((item) => item.status === "pending");
125
+ const latestAgentText = contentToText(latestAgentMessage?.content);
126
+ const latestUserText = contentToText(latestUserMessage?.content);
127
+ const statusText = request.state === "waiting_for_approval"
128
+ ? approval
129
+ ? `Approval required for tool ${approval.toolName}.`
130
+ : "Approval required."
131
+ : output ?? latestAgentText ?? failureMessage;
132
+ return {
133
+ id: request.requestId,
134
+ contextId: session.sessionId,
135
+ kind: "task",
136
+ status: {
137
+ state: mapRequestState(request.state),
138
+ timestamp: request.updatedAt,
139
+ ...(statusText ? {
140
+ message: {
141
+ role: "ROLE_AGENT",
142
+ messageId: `${request.requestId}:status`,
143
+ parts: toTextParts(statusText),
144
+ },
145
+ } : {}),
146
+ },
147
+ history: [
148
+ ...(latestUserText
149
+ ? [{
150
+ role: "ROLE_USER",
151
+ messageId: `${request.requestId}:user`,
152
+ parts: toTextParts(latestUserText),
153
+ }]
154
+ : []),
155
+ ...(latestAgentText
156
+ ? [{
157
+ role: "ROLE_AGENT",
158
+ messageId: `${request.requestId}:agent`,
159
+ parts: toTextParts(latestAgentText),
160
+ }]
161
+ : []),
162
+ ],
163
+ artifacts: [],
164
+ metadata: {
165
+ agentId: request.agentId,
166
+ sessionId: session.sessionId,
167
+ requestId: request.requestId,
168
+ state: request.state,
169
+ approvalIds: approvals.map((item) => item.approvalId),
170
+ },
171
+ };
172
+ }
173
+ export async function buildTaskFromRuntime(runtime, requestId) {
174
+ const request = await runtime.getRequest(requestId);
175
+ if (!request) {
176
+ return null;
177
+ }
178
+ const session = await runtime.getSessionRecord(request.sessionId);
179
+ const approvals = await runtime.listApprovals({ sessionId: request.sessionId, requestId: request.requestId });
180
+ return buildTaskFromSessionAndRequest(toSessionRecord(session), toRequestRecord(request), approvals);
181
+ }
182
+ export async function hydrateTaskStateFromEvents(runtime, task) {
183
+ if (!task) {
184
+ return null;
185
+ }
186
+ const events = await runtime.listRequestEvents(task.contextId, task.id);
187
+ const lastStateChange = [...events].reverse().find((event) => event.eventType === "request.state.changed");
188
+ const observedState = typeof lastStateChange?.payload?.state === "string" ? lastStateChange.payload.state : undefined;
189
+ if (!observedState) {
190
+ return task;
191
+ }
192
+ return {
193
+ ...task,
194
+ status: {
195
+ ...task.status,
196
+ state: mapRequestState(observedState),
197
+ },
198
+ metadata: {
199
+ ...task.metadata,
200
+ state: observedState,
201
+ },
202
+ };
203
+ }
204
+ export async function listTasksFromRuntime(runtime, params) {
205
+ const runState = mapTaskStatusToRequestState(params.state);
206
+ const requests = await runtime.listRequests({
207
+ ...(params.agentId ? { agentId: params.agentId } : {}),
208
+ ...(params.contextId ? { sessionId: params.contextId } : {}),
209
+ ...(runState ? { state: runState } : {}),
210
+ });
211
+ const startIndex = params.cursor ? Number.parseInt(Buffer.from(params.cursor, "base64url").toString("utf8"), 10) || 0 : 0;
212
+ const page = requests.slice(startIndex, startIndex + params.limit);
213
+ const tasks = (await Promise.all(page.map((request) => buildTaskFromRuntime(runtime, request.requestId)))).filter((task) => Boolean(task));
214
+ const nextIndex = startIndex + page.length;
215
+ const nextPageToken = nextIndex < requests.length ? Buffer.from(String(nextIndex), "utf8").toString("base64url") : "";
216
+ return {
217
+ tasks,
218
+ pageSize: params.limit,
219
+ totalSize: requests.length,
220
+ nextPageToken,
221
+ ...(nextPageToken ? { nextCursor: nextPageToken } : {}),
222
+ };
223
+ }
224
+ export function isV1Method(method) {
225
+ return /^[A-Z]/.test(method);
226
+ }
227
+ export function toSendMessageResult(method, task) {
228
+ if (!task || !isV1Method(method)) {
229
+ return task;
230
+ }
231
+ return { task };
232
+ }
233
+ function toStatusUpdate(task) {
234
+ return {
235
+ taskId: task.id,
236
+ contextId: task.contextId,
237
+ kind: "status-update",
238
+ status: task.status,
239
+ final: isTerminalTaskState(task.status.state),
240
+ metadata: task.metadata,
241
+ };
242
+ }
243
+ export function toStreamingResult(method, task, mode) {
244
+ if (!task) {
245
+ return null;
246
+ }
247
+ if (!isV1Method(method)) {
248
+ return task;
249
+ }
250
+ if (mode === "status-update") {
251
+ return {
252
+ statusUpdate: toStatusUpdate(task),
253
+ };
254
+ }
255
+ return { task };
256
+ }
257
+ export function withStreamingStatusText(task, text) {
258
+ if (!task || typeof text !== "string" || text.length === 0) {
259
+ return task;
260
+ }
261
+ return {
262
+ ...task,
263
+ status: {
264
+ ...task.status,
265
+ message: {
266
+ role: "ROLE_AGENT",
267
+ messageId: `${task.id}:status`,
268
+ parts: toTextParts(text),
269
+ },
270
+ },
271
+ };
272
+ }
273
+ export function withRunResult(task, result, streamedText) {
274
+ if (!task) {
275
+ return null;
276
+ }
277
+ const statusText = streamedText || result.output;
278
+ return {
279
+ ...task,
280
+ status: {
281
+ ...task.status,
282
+ state: mapRequestState(result.state),
283
+ ...(statusText
284
+ ? {
285
+ message: {
286
+ role: "ROLE_AGENT",
287
+ messageId: `${task.id}:status`,
288
+ parts: toTextParts(statusText),
289
+ },
290
+ }
291
+ : {}),
292
+ },
293
+ metadata: {
294
+ ...task.metadata,
295
+ state: result.state,
296
+ },
297
+ };
298
+ }
299
+ export function isTerminalTaskState(state) {
300
+ return state === "TASK_STATE_COMPLETED" || state === "TASK_STATE_FAILED" || state === "TASK_STATE_CANCELED";
301
+ }
302
+ export function clonePushNotificationConfig(config) {
303
+ return {
304
+ id: config.id,
305
+ taskId: config.taskId,
306
+ url: config.url,
307
+ ...(config.token ? { token: config.token } : {}),
308
+ ...(config.authentication ? { authentication: config.authentication } : {}),
309
+ };
310
+ }
311
+ export function fingerprintTaskForPush(task) {
312
+ return JSON.stringify({
313
+ state: task.status.state,
314
+ timestamp: task.status.timestamp,
315
+ message: task.status.message,
316
+ });
317
+ }
@@ -210,7 +210,7 @@ export function createAcpHttpClient(options) {
210
210
  listener(parsed);
211
211
  }
212
212
  catch {
213
- // Ignore listener failures so one subscriber cannot tear down the transport.
213
+ // Ignore malformed listener failures.
214
214
  }
215
215
  }
216
216
  }
@@ -0,0 +1,50 @@
1
+ import { type AcpHttpClientOptions, type AcpStdioClient, type AcpStdioClientOptions } from "./client.js";
2
+ import type { Approval, OperatorOverview, RequestEvent, RequestPlanState, RequestTraceItem } from "../../api.js";
3
+ import type { CancelOptions, RequestSummary, RuntimeHealthSnapshot, SessionListSummary, SessionRecord, SessionSummary } from "../../contracts/types.js";
4
+ import type { HarnessClient, HarnessClientApprovalFilter, HarnessClientRequestFilter, HarnessClientRequestOptions, HarnessClientRequestResult } from "../../client/types.js";
5
+ export type AcpHarnessTransport = Pick<AcpStdioClient, "request" | "subscribe" | "close">;
6
+ export declare class AcpHarnessClient implements HarnessClient {
7
+ private readonly transport;
8
+ private streamSequence;
9
+ constructor(transport: AcpHarnessTransport);
10
+ request(options: HarnessClientRequestOptions): Promise<HarnessClientRequestResult>;
11
+ private hasStreamingListeners;
12
+ private streamRequestInternal;
13
+ private requestWithStreamingListeners;
14
+ resolveApproval(options: Parameters<HarnessClient["resolveApproval"]>[0]): Promise<HarnessClientRequestResult>;
15
+ cancelRequest(options: CancelOptions): Promise<HarnessClientRequestResult>;
16
+ subscribe(listener: (event: RequestEvent) => void | Promise<void>): () => void;
17
+ listSessions(filter?: {
18
+ agentId?: string;
19
+ status?: RequestSummary["state"];
20
+ }): Promise<SessionSummary[]>;
21
+ listSessionSummaries(filter?: {
22
+ agentId?: string;
23
+ status?: RequestSummary["state"];
24
+ }): Promise<SessionListSummary[]>;
25
+ listRequests(filter?: HarnessClientRequestFilter): Promise<RequestSummary[]>;
26
+ getSession(sessionId: string): Promise<SessionRecord | null>;
27
+ getRequest(requestId: string): Promise<RequestSummary | null>;
28
+ listApprovals(filter?: HarnessClientApprovalFilter): Promise<Approval[]>;
29
+ getApproval(approvalId: string): Promise<Approval | null>;
30
+ getRequestPlanState(input: {
31
+ sessionId: string;
32
+ requestId: string;
33
+ }): Promise<RequestPlanState | null>;
34
+ listRequestEvents(input: {
35
+ sessionId: string;
36
+ requestId: string;
37
+ }): Promise<RequestEvent[]>;
38
+ listRequestTraceItems(input: {
39
+ sessionId: string;
40
+ requestId: string;
41
+ }): Promise<RequestTraceItem[]>;
42
+ getHealth(): Promise<RuntimeHealthSnapshot>;
43
+ getOperatorOverview(options?: {
44
+ limit?: number;
45
+ }): Promise<OperatorOverview>;
46
+ stop(): Promise<void>;
47
+ }
48
+ export declare function createAcpHarnessClient(transport: AcpHarnessTransport): HarnessClient;
49
+ export declare function createAcpStdioHarnessClient(options: AcpStdioClientOptions): HarnessClient;
50
+ export declare function createAcpHttpHarnessClient(options: AcpHttpClientOptions): HarnessClient;
@@ -0,0 +1,219 @@
1
+ import { createAcpHttpClient, createAcpStdioClient, } from "./client.js";
2
+ import { applyRequestStreamItemToSnapshot, createInitialRequestEventSnapshot, toRequestDataEvent, } from "../../projections/request-events.js";
3
+ function toEvent(notification) {
4
+ return notification.params.event;
5
+ }
6
+ function isRuntimeEventNotification(notification) {
7
+ return notification.method === "events.runtime";
8
+ }
9
+ function isStreamNotification(notification) {
10
+ return notification.method === "requests.stream";
11
+ }
12
+ export class AcpHarnessClient {
13
+ transport;
14
+ streamSequence = 0;
15
+ constructor(transport) {
16
+ this.transport = transport;
17
+ }
18
+ request(options) {
19
+ if (this.hasStreamingListeners(options)) {
20
+ return this.requestWithStreamingListeners(options);
21
+ }
22
+ return this.transport.request("requests.submit", options);
23
+ }
24
+ hasStreamingListeners(options) {
25
+ return Boolean(("eventListener" in options && options.eventListener)
26
+ || ("dataListener" in options && options.dataListener)
27
+ || options.listeners);
28
+ }
29
+ async *streamRequestInternal(options) {
30
+ const streamId = `harness-stream-${++this.streamSequence}`;
31
+ const queued = [];
32
+ let notify;
33
+ let settled = false;
34
+ let streamedResult = false;
35
+ let responseResolved = false;
36
+ let failure;
37
+ let fallbackTimer;
38
+ const waitForItem = () => new Promise((resolve) => {
39
+ notify = resolve;
40
+ });
41
+ const push = (item) => {
42
+ queued.push(item);
43
+ notify?.();
44
+ notify = undefined;
45
+ };
46
+ const settle = () => {
47
+ if (settled) {
48
+ return;
49
+ }
50
+ settled = true;
51
+ notify?.();
52
+ notify = undefined;
53
+ };
54
+ const unsubscribe = this.transport.subscribe((notification) => {
55
+ if (!isStreamNotification(notification) || notification.params.streamId !== streamId) {
56
+ return;
57
+ }
58
+ if (notification.params.item.type === "result") {
59
+ streamedResult = true;
60
+ if (fallbackTimer) {
61
+ clearTimeout(fallbackTimer);
62
+ fallbackTimer = undefined;
63
+ }
64
+ if (responseResolved) {
65
+ settle();
66
+ }
67
+ }
68
+ push(notification.params.item);
69
+ });
70
+ const resultPromise = this.transport.request("requests.submit", {
71
+ ...options,
72
+ streamId,
73
+ listeners: undefined,
74
+ eventListener: undefined,
75
+ dataListener: undefined,
76
+ });
77
+ resultPromise
78
+ .then((result) => {
79
+ responseResolved = true;
80
+ if (streamedResult) {
81
+ settle();
82
+ return;
83
+ }
84
+ fallbackTimer = setTimeout(() => {
85
+ push({
86
+ type: "result",
87
+ result,
88
+ });
89
+ settle();
90
+ }, 50);
91
+ })
92
+ .catch((error) => {
93
+ failure = error;
94
+ settle();
95
+ })
96
+ .finally(() => undefined);
97
+ try {
98
+ while (!settled || queued.length > 0) {
99
+ if (queued.length === 0) {
100
+ await waitForItem();
101
+ continue;
102
+ }
103
+ const item = queued.shift();
104
+ if (item) {
105
+ yield item;
106
+ }
107
+ }
108
+ if (failure) {
109
+ throw failure;
110
+ }
111
+ }
112
+ finally {
113
+ if (fallbackTimer) {
114
+ clearTimeout(fallbackTimer);
115
+ }
116
+ unsubscribe();
117
+ }
118
+ }
119
+ async requestWithStreamingListeners(options) {
120
+ const legacyListeners = options.listeners;
121
+ const eventListener = "eventListener" in options ? options.eventListener : undefined;
122
+ const dataListener = "dataListener" in options ? options.dataListener : undefined;
123
+ let snapshot = createInitialRequestEventSnapshot();
124
+ let finalResult;
125
+ for await (const item of this.streamRequestInternal(options)) {
126
+ snapshot = applyRequestStreamItemToSnapshot(snapshot, item);
127
+ if (item.type === "event") {
128
+ await legacyListeners?.onEvent?.(item.event);
129
+ }
130
+ else if (item.type === "upstream-event") {
131
+ await legacyListeners?.onUpstreamEvent?.(item.event);
132
+ if (item.surfaceItem) {
133
+ await legacyListeners?.onTraceItem?.({
134
+ sessionId: item.sessionId,
135
+ requestId: item.requestId,
136
+ surfaceItem: item.surfaceItem,
137
+ event: item.event,
138
+ });
139
+ }
140
+ }
141
+ else if (item.type === "plan-state") {
142
+ await legacyListeners?.onPlanState?.(item.planState);
143
+ }
144
+ else if (item.type === "result") {
145
+ finalResult = item.result;
146
+ }
147
+ const dataEvent = toRequestDataEvent(item);
148
+ if (dataEvent) {
149
+ await dataListener?.(dataEvent);
150
+ }
151
+ await eventListener?.(snapshot);
152
+ }
153
+ if (!finalResult) {
154
+ throw new Error("ACP streaming request completed without a terminal result.");
155
+ }
156
+ return finalResult;
157
+ }
158
+ resolveApproval(options) {
159
+ return this.transport.request("approvals.resolve", options);
160
+ }
161
+ cancelRequest(options) {
162
+ return this.transport.request("requests.cancel", options);
163
+ }
164
+ subscribe(listener) {
165
+ return this.transport.subscribe((notification) => {
166
+ if (isRuntimeEventNotification(notification)) {
167
+ void listener(toEvent(notification));
168
+ }
169
+ });
170
+ }
171
+ listSessions(filter) {
172
+ return this.transport.request("sessions.list", filter);
173
+ }
174
+ listSessionSummaries(filter) {
175
+ return this.transport.request("sessions.summaries", filter);
176
+ }
177
+ listRequests(filter) {
178
+ return this.transport.request("requests.list", filter);
179
+ }
180
+ getSession(sessionId) {
181
+ return this.transport.request("sessions.get", { sessionId });
182
+ }
183
+ getRequest(requestId) {
184
+ return this.transport.request("requests.get", { requestId });
185
+ }
186
+ listApprovals(filter) {
187
+ return this.transport.request("approvals.list", filter);
188
+ }
189
+ getApproval(approvalId) {
190
+ return this.transport.request("approvals.get", { approvalId });
191
+ }
192
+ getRequestPlanState(input) {
193
+ return this.transport.request("requests.plan.get", input);
194
+ }
195
+ listRequestEvents(input) {
196
+ return this.transport.request("events.list", input);
197
+ }
198
+ listRequestTraceItems(input) {
199
+ return this.transport.request("requests.trace.list", input);
200
+ }
201
+ getHealth() {
202
+ return this.transport.request("runtime.health");
203
+ }
204
+ getOperatorOverview(options) {
205
+ return this.transport.request("runtime.overview", options);
206
+ }
207
+ stop() {
208
+ return this.transport.close();
209
+ }
210
+ }
211
+ export function createAcpHarnessClient(transport) {
212
+ return new AcpHarnessClient(transport);
213
+ }
214
+ export function createAcpStdioHarnessClient(options) {
215
+ return new AcpHarnessClient(createAcpStdioClient(options));
216
+ }
217
+ export function createAcpHttpHarnessClient(options) {
218
+ return new AcpHarnessClient(createAcpHttpClient(options));
219
+ }