@astrosheep/keiyaku 4.5.7 → 4.5.8
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/README.md +10 -0
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +10 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +22 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
- package/build/src/akuma/abort.d.ts +2 -1
- package/build/src/akuma/abort.js +6 -23
- package/build/src/akuma/akuma-handle.js +4 -2
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-product.js +9 -7
- package/build/src/akuma/akuma.d.ts +372 -9
- package/build/src/akuma/akuma.js +31 -1
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +1 -0
- package/build/src/akuma/body.d.ts +6 -4
- package/build/src/akuma/body.js +5 -3
- package/build/src/akuma/call-request.d.ts +80 -0
- package/build/src/akuma/call-request.js +211 -0
- package/build/src/akuma/heart/facts.d.ts +6 -78
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/request-authority.d.ts +5 -4
- package/build/src/akuma/heart/request-authority.js +20 -34
- package/build/src/akuma/heart/request-rows.js +12 -23
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +5 -13
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/projection-read.d.ts +1 -0
- package/build/src/akuma/projection-read.js +8 -1
- package/build/src/akuma/projection.d.ts +856 -137
- package/build/src/akuma/projection.js +190 -0
- package/build/src/akuma/provider.d.ts +30 -3
- package/build/src/akuma/provider.js +104 -0
- package/build/src/akuma/providers/acp/core.d.ts +2 -2
- package/build/src/akuma/providers/acp/core.js +13 -6
- package/build/src/akuma/providers/acp/index.js +5 -4
- package/build/src/akuma/providers/claude/index.d.ts +3 -3
- package/build/src/akuma/providers/claude/index.js +16 -5
- package/build/src/akuma/providers/codex-app-server/events.js +1 -1
- package/build/src/akuma/providers/codex-app-server/index.js +18 -6
- package/build/src/akuma/providers/grok-build/index.js +5 -4
- package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
- package/build/src/akuma/providers/pi/index.js +42 -14
- package/build/src/akuma/request-lifecycle.d.ts +3 -9
- package/build/src/akuma/request-lifecycle.js +4 -4
- package/build/src/akuma/request-rendezvous.d.ts +26 -0
- package/build/src/akuma/request-rendezvous.js +100 -0
- package/build/src/akuma/request-serve.d.ts +5 -65
- package/build/src/akuma/request-serve.js +81 -208
- package/build/src/akuma/request-wire.d.ts +109 -115
- package/build/src/akuma/request-wire.js +63 -318
- package/build/src/akuma/requests.d.ts +19 -47
- package/build/src/akuma/requests.js +51 -107
- package/build/src/akuma/turn-drive.d.ts +5 -3
- package/build/src/akuma/turn-drive.js +32 -10
- package/build/src/akuma-body.d.ts +7 -2
- package/build/src/akuma-body.js +68 -46
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +2 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +17 -9
- package/build/src/cli/commands/akuma.js +7 -7
- package/build/src/cli/commands/contract-invoke.d.ts +3 -2
- package/build/src/cli/commands/contract-invoke.js +26 -19
- package/build/src/cli/commands/contract.d.ts +13 -13
- package/build/src/cli/commands/contract.js +32 -17
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +1 -1
- package/build/src/cli/commands/task-invoke.d.ts +3 -0
- package/build/src/cli/commands/task-invoke.js +23 -140
- package/build/src/cli/commands/task.js +54 -20
- package/build/src/cli/invoke.js +39 -25
- package/build/src/cli/main.js +2 -1
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +37 -22
- package/build/src/cli/render/akuma-activity.d.ts +4 -1
- package/build/src/cli/render/akuma-activity.js +45 -30
- package/build/src/cli/render/akuma-tool.d.ts +5 -1
- package/build/src/cli/render/akuma.js +5 -9
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/catalog.js +80 -21
- package/build/src/cli/render/contract-observation.d.ts +2 -0
- package/build/src/cli/render/contract-observation.js +11 -0
- package/build/src/cli/render/contract.js +25 -65
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
- package/build/src/cli/render/kanshi-akuma.js +111 -0
- package/build/src/cli/render/kanshi.js +108 -213
- package/build/src/cli/render/receipt.d.ts +1 -2
- package/build/src/cli/render/receipt.js +76 -26
- package/build/src/cli/render/refusal.js +2 -10
- package/build/src/cli/render/region.js +5 -2
- package/build/src/cli/render/settings.d.ts +1 -1
- package/build/src/cli/render/settings.js +27 -8
- package/build/src/cli/render/task.js +22 -5
- package/build/src/cli/render/terminal.d.ts +28 -0
- package/build/src/cli/render/terminal.js +65 -0
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.js +3 -1
- package/build/src/cli/selectors.d.ts +2 -1
- package/build/src/cli/selectors.js +4 -3
- package/build/src/cli/square-edge.js +120 -36
- package/build/src/cli/usage.js +2 -1
- package/build/src/contract-guidance.d.ts +5 -0
- package/build/src/contract-guidance.js +121 -0
- package/build/src/contract-worktree.d.ts +0 -1
- package/build/src/contract-worktree.js +32 -83
- package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
- package/build/src/coordination/sqlite-transaction-lock.js +5 -0
- package/build/src/core/facts/codec.d.ts +2 -0
- package/build/src/core/facts/codec.js +4 -0
- package/build/src/core/verbs/placement.d.ts +6 -1
- package/build/src/core/verbs/placement.js +5 -3
- package/build/src/dispatch/index.d.ts +0 -2
- package/build/src/dispatch/index.js +54 -55
- package/build/src/git/admission.js +2 -2
- package/build/src/git/hooks.d.ts +9 -15
- package/build/src/git/hooks.js +23 -317
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +36 -18
- package/build/src/git/private-state-seat.d.ts +12 -0
- package/build/src/git/private-state-seat.js +39 -0
- package/build/src/git/process.d.ts +6 -0
- package/build/src/git/process.js +19 -7
- package/build/src/git/read-observation.js +29 -20
- package/build/src/git/reconcile.d.ts +11 -0
- package/build/src/git/reconcile.js +64 -11
- package/build/src/git/repository.d.ts +6 -2
- package/build/src/git/repository.js +8 -0
- package/build/src/git/target-placement.d.ts +1 -0
- package/build/src/git/target-placement.js +5 -0
- package/build/src/git/tender.d.ts +1 -0
- package/build/src/git/terminal-reconcile.d.ts +1 -1
- package/build/src/git/terminal-reconcile.js +22 -20
- package/build/src/git/workspace.d.ts +14 -0
- package/build/src/git/workspace.js +44 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +16 -16
- package/build/src/kanshi/report.d.ts +2 -2
- package/build/src/library/address.d.ts +9 -3
- package/build/src/library/address.js +3 -2
- package/build/src/library/akuma-creation.d.ts +4 -3
- package/build/src/library/akuma-creation.js +19 -13
- package/build/src/library/audit.d.ts +1 -1
- package/build/src/library/audit.js +5 -3
- package/build/src/library/catalog.d.ts +3 -1
- package/build/src/library/catalog.js +20 -6
- package/build/src/library/composition.d.ts +371 -0
- package/build/src/library/composition.js +28 -0
- package/build/src/library/configuration.js +8 -2
- package/build/src/library/continuation.js +66 -30
- package/build/src/library/contract-bind.js +10 -2
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +96 -0
- package/build/src/library/contract-forwarding-reconciliation-result.js +83 -0
- package/build/src/library/contract-forwarding-result.d.ts +6723 -0
- package/build/src/library/contract-forwarding-result.js +521 -0
- package/build/src/library/contract-forwarding.d.ts +72 -0
- package/build/src/library/contract-forwarding.js +125 -0
- package/build/src/library/contract-handle.d.ts +36 -0
- package/build/src/library/contract-handle.js +313 -0
- package/build/src/library/contract-operations.d.ts +1044 -67
- package/build/src/library/contract-operations.js +190 -118
- package/build/src/library/contract.d.ts +11 -32
- package/build/src/library/contract.js +16 -289
- package/build/src/library/fleet-result.d.ts +1454 -0
- package/build/src/library/fleet-result.js +96 -0
- package/build/src/library/fleet.d.ts +112 -54
- package/build/src/library/fleet.js +211 -71
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +4 -0
- package/build/src/library/keiyaku.d.ts +371 -20
- package/build/src/library/keiyaku.js +8 -21
- package/build/src/library/mutation.d.ts +3 -3
- package/build/src/library/mutation.js +5 -9
- package/build/src/library/nuke.d.ts +1 -1
- package/build/src/library/nuke.js +4 -3
- package/build/src/library/reconcile.d.ts +4 -0
- package/build/src/library/reconcile.js +2 -0
- package/build/src/library/refusal.d.ts +0 -9
- package/build/src/library/refusal.js +0 -7
- package/build/src/protocol/amend.js +56 -50
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/attempt.js +8 -1
- package/build/src/protocol/completion.js +7 -0
- package/build/src/protocol/deliver.js +6 -2
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +5 -2
- package/build/src/protocol/placement.d.ts +1 -0
- package/build/src/protocol/placement.js +52 -38
- package/build/src/protocol/read/observation.d.ts +1 -4
- package/build/src/protocol/read/observation.js +2 -15
- package/build/src/protocol/reintegrate.js +62 -58
- package/build/src/protocol/review.js +5 -0
- package/build/src/protocol/run.js +17 -13
- package/build/src/runtime/proc/run.d.ts +8 -0
- package/build/src/runtime/proc/run.js +27 -0
- package/build/src/runtime/proc/termination.js +26 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -1
- package/build/src/settlement/holder.js +15 -4
- package/build/src/settlement/settle.js +99 -33
- package/build/src/task/board.d.ts +68 -27
- package/build/src/task/board.js +31 -1
- package/build/src/task/catalog.d.ts +4 -0
- package/build/src/task/catalog.js +23 -0
- package/build/src/task/compose-language.js +33 -7
- package/build/src/task/compose-parser.d.ts +1 -1
- package/build/src/task/compose-parser.js +1 -1
- package/build/src/task/compose.js +2 -0
- package/build/src/task/index.d.ts +12 -4
- package/build/src/task/index.js +97 -16
- package/build/src/task/mutation-result.d.ts +923 -0
- package/build/src/task/mutation-result.js +140 -0
- package/build/src/task/mutation.d.ts +552 -28
- package/build/src/task/mutation.js +304 -97
- package/build/src/task/operations.d.ts +1 -4
- package/build/src/task/operations.js +0 -6
- package/build/src/task/public.d.ts +2 -0
- package/build/src/task/public.js +1 -0
- package/build/src/workspace-place.d.ts +7 -2
- package/build/src/workspace-place.js +34 -24
- package/build/src/world.d.ts +1 -0
- package/build/src/world.js +11 -0
- package/package.json +8 -6
- package/build/src/akuma/request-execution.d.ts +0 -8
- package/build/src/akuma/request-execution.js +0 -98
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
2
|
+
import { AKUMA_REQUESTS_ENV, AgentEventChannel, createProviderAttempt, } from "../../provider.js";
|
|
4
3
|
import { createEventState, mapEvent } from "./events.js";
|
|
5
4
|
import { coordinate, loadOpencode, OPENCODE_SDK_PROVIDER, parseModel } from "./session.js";
|
|
6
5
|
function object(value) {
|
|
@@ -201,27 +200,51 @@ async function forceDisposeOpencode(abortController, close, finish) {
|
|
|
201
200
|
await close();
|
|
202
201
|
await finish({ kind: "failed", diagnostic: "OpenCode session force-disposed" });
|
|
203
202
|
}
|
|
204
|
-
async function loadDriveRuntime(execution, input, signal, loader) {
|
|
205
|
-
|
|
203
|
+
async function loadDriveRuntime(execution, input, signal, loader, onRuntime) {
|
|
204
|
+
const runtime = await loadOpencode({
|
|
206
205
|
...execution,
|
|
207
206
|
env: {
|
|
208
207
|
...execution.env,
|
|
209
208
|
...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
|
|
210
209
|
},
|
|
211
|
-
}, input.cwd, signal, loader
|
|
210
|
+
}, input.cwd, signal, loader, onRuntime);
|
|
211
|
+
if (signal.aborted) {
|
|
212
|
+
await runtime.close();
|
|
213
|
+
signal.throwIfAborted();
|
|
214
|
+
}
|
|
215
|
+
return runtime;
|
|
216
|
+
}
|
|
217
|
+
function ownRuntime(custody, runtime) {
|
|
218
|
+
let closing;
|
|
219
|
+
let settleRuntimeClosed;
|
|
220
|
+
let rejectRuntimeClosed;
|
|
221
|
+
const runtimeClosed = new Promise((resolve, reject) => {
|
|
222
|
+
settleRuntimeClosed = resolve;
|
|
223
|
+
rejectRuntimeClosed = reject;
|
|
224
|
+
});
|
|
225
|
+
const close = () => {
|
|
226
|
+
if (closing === undefined) {
|
|
227
|
+
closing = runtime.close();
|
|
228
|
+
void closing.then(settleRuntimeClosed, rejectRuntimeClosed);
|
|
229
|
+
}
|
|
230
|
+
return closing;
|
|
231
|
+
};
|
|
232
|
+
custody?.own({ closed: runtimeClosed, abort: close, forceDispose: close });
|
|
233
|
+
return close;
|
|
212
234
|
}
|
|
213
235
|
async function openDriveSession(runtime, input, resumeSessionId, signal) {
|
|
214
236
|
const session = runtime.client.session;
|
|
215
|
-
const response = await
|
|
237
|
+
const response = await (input.session.kind === "fresh"
|
|
216
238
|
? session.create({ query: { directory: input.cwd }, throwOnError: true })
|
|
217
|
-
: session.get({ path: { id: resumeSessionId }, query: { directory: input.cwd }, throwOnError: true })
|
|
239
|
+
: session.get({ path: { id: resumeSessionId }, query: { directory: input.cwd }, throwOnError: true }));
|
|
240
|
+
signal.throwIfAborted();
|
|
218
241
|
const info = object(object(response)?.data) ?? object(response);
|
|
219
242
|
const sessionId = text(info?.id) ?? resumeSessionId;
|
|
220
243
|
if (sessionId === undefined)
|
|
221
244
|
throw new Error("OpenCode did not return a session id");
|
|
222
245
|
return { session, sessionId };
|
|
223
246
|
}
|
|
224
|
-
async function drive(execution, input, loader) {
|
|
247
|
+
async function drive(execution, input, loader, custody) {
|
|
225
248
|
admit(input.options);
|
|
226
249
|
const signal = input.signal ?? new AbortController().signal;
|
|
227
250
|
const resumeSessionId = input.session.kind === "resume" ? opencodeSessionId(input.session.coordinate) : undefined;
|
|
@@ -229,13 +252,11 @@ async function drive(execution, input, loader) {
|
|
|
229
252
|
const abortSetup = () => abortController.abort(signal.reason);
|
|
230
253
|
signal.addEventListener("abort", abortSetup, { once: true });
|
|
231
254
|
signal.throwIfAborted();
|
|
232
|
-
|
|
233
|
-
|
|
255
|
+
let closeOnce;
|
|
256
|
+
const runtime = await loadDriveRuntime(execution, input, abortController.signal, loader, (ready) => {
|
|
257
|
+
closeOnce = ownRuntime(custody, ready);
|
|
258
|
+
});
|
|
234
259
|
let iterator;
|
|
235
|
-
const closeOnce = () => {
|
|
236
|
-
closing ??= runtime.close();
|
|
237
|
-
return closing;
|
|
238
|
-
};
|
|
239
260
|
try {
|
|
240
261
|
const { session, sessionId } = await openDriveSession(runtime, input, resumeSessionId, abortController.signal);
|
|
241
262
|
const events = new AgentEventChannel();
|
|
@@ -243,9 +264,11 @@ async function drive(execution, input, loader) {
|
|
|
243
264
|
const messageID = `msg_${randomUUID().replaceAll("-", "")}`;
|
|
244
265
|
const submissionState = { started: false };
|
|
245
266
|
events.emit({ type: "session", coordinate: coordinate(sessionId) });
|
|
246
|
-
const streamResult = await
|
|
247
|
-
|
|
248
|
-
|
|
267
|
+
const streamResult = await runtime.client.event.subscribe({ query: { directory: input.cwd } });
|
|
268
|
+
if (abortController.signal.aborted) {
|
|
269
|
+
await streamResult.stream[Symbol.asyncIterator]().return?.(undefined);
|
|
270
|
+
abortController.signal.throwIfAborted();
|
|
271
|
+
}
|
|
249
272
|
iterator = streamResult.stream[Symbol.asyncIterator]();
|
|
250
273
|
const { completion, finish } = terminalSettlement(events, closeOnce);
|
|
251
274
|
const observation = observeTurn({
|
|
@@ -259,12 +282,13 @@ async function drive(execution, input, loader) {
|
|
|
259
282
|
submissionState,
|
|
260
283
|
});
|
|
261
284
|
submissionState.started = true;
|
|
262
|
-
await
|
|
285
|
+
await session.promptAsync({
|
|
263
286
|
path: { id: sessionId },
|
|
264
287
|
query: { directory: input.cwd },
|
|
265
288
|
body: promptBody(input, messageID),
|
|
266
289
|
throwOnError: true,
|
|
267
|
-
})
|
|
290
|
+
});
|
|
291
|
+
abortController.signal.throwIfAborted();
|
|
268
292
|
void observation.then(finish);
|
|
269
293
|
signal.removeEventListener("abort", abortSetup);
|
|
270
294
|
return {
|
|
@@ -312,11 +336,28 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
|
|
|
312
336
|
}),
|
|
313
337
|
};
|
|
314
338
|
},
|
|
315
|
-
start: (input) => drive(execution, input, loader),
|
|
316
|
-
resume: (input) => drive(execution, input, loader),
|
|
317
|
-
fork: async (
|
|
339
|
+
start: (input) => createProviderAttempt(input.signal, async (custody) => await drive(execution, { ...input, signal: custody.signal }, loader, custody)),
|
|
340
|
+
resume: (input) => createProviderAttempt(input.signal, async (custody) => await drive(execution, { ...input, signal: custody.signal }, loader, custody)),
|
|
341
|
+
fork: (input) => createProviderAttempt(new AbortController().signal, async (custody) => {
|
|
318
342
|
const sessionId = opencodeSessionId(input.session);
|
|
319
|
-
|
|
343
|
+
let close;
|
|
344
|
+
const runtime = await loadOpencode(execution, input.cwd, custody.signal, loader, (ready) => {
|
|
345
|
+
let closing;
|
|
346
|
+
let settleRuntimeClosed;
|
|
347
|
+
let rejectRuntimeClosed;
|
|
348
|
+
const runtimeClosed = new Promise((resolve, reject) => {
|
|
349
|
+
settleRuntimeClosed = resolve;
|
|
350
|
+
rejectRuntimeClosed = reject;
|
|
351
|
+
});
|
|
352
|
+
close = () => {
|
|
353
|
+
if (closing === undefined) {
|
|
354
|
+
closing = ready.close();
|
|
355
|
+
void closing.then(settleRuntimeClosed, rejectRuntimeClosed);
|
|
356
|
+
}
|
|
357
|
+
return closing;
|
|
358
|
+
};
|
|
359
|
+
custody.own({ closed: runtimeClosed, abort: close, forceDispose: close });
|
|
360
|
+
});
|
|
320
361
|
try {
|
|
321
362
|
const result = await runtime.client.session.fork({
|
|
322
363
|
path: { id: sessionId },
|
|
@@ -330,8 +371,8 @@ export function createOpencodeProvider(input = { name: OPENCODE_SDK_PROVIDER, ki
|
|
|
330
371
|
return { session: coordinate(id) };
|
|
331
372
|
}
|
|
332
373
|
finally {
|
|
333
|
-
await
|
|
374
|
+
await close();
|
|
334
375
|
}
|
|
335
|
-
},
|
|
376
|
+
}),
|
|
336
377
|
};
|
|
337
378
|
}
|
|
@@ -3,12 +3,13 @@ import type { ResumeCoordinate } from "../../heart/index.js";
|
|
|
3
3
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
4
4
|
export type OpencodeSdkSession = Pick<OpencodeClient["session"], "create" | "get" | "fork" | "abort" | "promptAsync" | "messages">;
|
|
5
5
|
export type OpencodeSdkEvent = Pick<OpencodeClient["event"], "subscribe">;
|
|
6
|
-
export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution) => Promise<Readonly<{
|
|
6
|
+
export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution, signal: AbortSignal) => Promise<Readonly<{
|
|
7
7
|
client: {
|
|
8
8
|
session: OpencodeSdkSession;
|
|
9
9
|
event: OpencodeSdkEvent;
|
|
10
10
|
};
|
|
11
11
|
close?: () => Promise<void> | void;
|
|
12
|
+
ready?: Promise<void>;
|
|
12
13
|
}>>;
|
|
13
14
|
export declare const OPENCODE_SDK_PROVIDER: "opencode-sdk";
|
|
14
15
|
export declare function parseModel(model: string): Readonly<{
|
|
@@ -22,5 +23,5 @@ export type OpencodeRuntime = Readonly<{
|
|
|
22
23
|
};
|
|
23
24
|
close: () => Promise<void>;
|
|
24
25
|
}>;
|
|
25
|
-
export declare function loadOpencode(execution: ProviderExecution, cwd: string, signal: AbortSignal, loader?: OpencodeSdkLoader): Promise<OpencodeRuntime>;
|
|
26
|
+
export declare function loadOpencode(execution: ProviderExecution, cwd: string, signal: AbortSignal, loader?: OpencodeSdkLoader, onRuntime?: (runtime: OpencodeRuntime) => void): Promise<OpencodeRuntime>;
|
|
26
27
|
export declare function coordinate(sessionId: string): ResumeCoordinate;
|
|
@@ -37,15 +37,28 @@ async function availablePort() {
|
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
|
-
export async function loadOpencode(execution, cwd, signal, loader) {
|
|
40
|
+
export async function loadOpencode(execution, cwd, signal, loader, onRuntime) {
|
|
41
41
|
if (loader) {
|
|
42
|
-
const loaded = await loader(cwd, execution);
|
|
43
|
-
|
|
42
|
+
const loaded = await abortable(loader(cwd, execution, signal), signal);
|
|
43
|
+
let closing;
|
|
44
|
+
const runtime = {
|
|
44
45
|
client: loaded.client,
|
|
45
46
|
close: async () => {
|
|
46
|
-
|
|
47
|
+
closing ??= Promise.resolve(loaded.close?.()).then(() => undefined);
|
|
48
|
+
await closing;
|
|
47
49
|
},
|
|
48
50
|
};
|
|
51
|
+
onRuntime?.(runtime);
|
|
52
|
+
try {
|
|
53
|
+
if (loaded.ready !== undefined)
|
|
54
|
+
await abortable(loaded.ready, signal);
|
|
55
|
+
signal.throwIfAborted();
|
|
56
|
+
return runtime;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
await runtime.close();
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
49
62
|
}
|
|
50
63
|
const port = await availablePort();
|
|
51
64
|
const owned = await spawnDetachedProcess({
|
|
@@ -60,19 +73,23 @@ export async function loadOpencode(execution, cwd, signal, loader) {
|
|
|
60
73
|
});
|
|
61
74
|
const { createOpencodeClient } = await import("@opencode-ai/sdk");
|
|
62
75
|
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}`, directory: cwd });
|
|
76
|
+
let closing;
|
|
77
|
+
const runtime = {
|
|
78
|
+
client,
|
|
79
|
+
close: async () => {
|
|
80
|
+
closing ??= owned.terminate();
|
|
81
|
+
await closing;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
onRuntime?.(runtime);
|
|
63
85
|
try {
|
|
64
86
|
await waitReady(client, cwd, signal);
|
|
65
87
|
}
|
|
66
88
|
catch (error) {
|
|
67
|
-
await
|
|
89
|
+
await runtime.close();
|
|
68
90
|
throw error;
|
|
69
91
|
}
|
|
70
|
-
return
|
|
71
|
-
client,
|
|
72
|
-
close: async () => {
|
|
73
|
-
await owned.terminate();
|
|
74
|
-
},
|
|
75
|
-
};
|
|
92
|
+
return runtime;
|
|
76
93
|
}
|
|
77
94
|
export function coordinate(sessionId) {
|
|
78
95
|
return { sessionId };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { abortable } from "../../abort.js";
|
|
2
|
-
import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
2
|
+
import { AKUMA_REQUESTS_ENV, AgentEventChannel, createProviderAttempt, } from "../../provider.js";
|
|
3
3
|
import { piTerminalFailure, translatePiEvent } from "./events.js";
|
|
4
4
|
const PI_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
5
5
|
const MODEL_PATTERN = /^[^/\s]+\/[^\s]+$/u;
|
|
@@ -75,7 +75,12 @@ async function createPiSession(sdk, execution, input, signal) {
|
|
|
75
75
|
}
|
|
76
76
|
return await sdk.createAgentSession(options);
|
|
77
77
|
});
|
|
78
|
-
|
|
78
|
+
const created = await setup;
|
|
79
|
+
if (signal.aborted) {
|
|
80
|
+
await created.session.dispose();
|
|
81
|
+
signal.throwIfAborted();
|
|
82
|
+
}
|
|
83
|
+
return created;
|
|
79
84
|
}
|
|
80
85
|
function forceDisposePi(dispose, settle, setAborting) {
|
|
81
86
|
setAborting();
|
|
@@ -109,9 +114,27 @@ async function runPiPrompt(native, input, events, state, settle) {
|
|
|
109
114
|
: { kind: "failed", diagnostic: diagnostic(error) });
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
|
-
async function drivePi(sdk, execution, input, signal) {
|
|
117
|
+
async function drivePi(sdk, execution, input, signal, custody) {
|
|
113
118
|
const created = await createPiSession(sdk, execution, input, signal);
|
|
114
119
|
const native = created.session;
|
|
120
|
+
let retired = false;
|
|
121
|
+
let settleRetired;
|
|
122
|
+
const closed = new Promise((resolve) => {
|
|
123
|
+
settleRetired = resolve;
|
|
124
|
+
});
|
|
125
|
+
custody?.own({
|
|
126
|
+
closed,
|
|
127
|
+
abort: async () => {
|
|
128
|
+
native.dispose();
|
|
129
|
+
retired = true;
|
|
130
|
+
settleRetired();
|
|
131
|
+
},
|
|
132
|
+
forceDispose: async () => {
|
|
133
|
+
native.dispose();
|
|
134
|
+
retired = true;
|
|
135
|
+
settleRetired();
|
|
136
|
+
},
|
|
137
|
+
});
|
|
115
138
|
if (signal.aborted) {
|
|
116
139
|
native.dispose();
|
|
117
140
|
signal.throwIfAborted();
|
|
@@ -138,6 +161,10 @@ async function drivePi(sdk, execution, input, signal) {
|
|
|
138
161
|
finally {
|
|
139
162
|
try {
|
|
140
163
|
native.dispose();
|
|
164
|
+
if (!retired) {
|
|
165
|
+
retired = true;
|
|
166
|
+
settleRetired();
|
|
167
|
+
}
|
|
141
168
|
}
|
|
142
169
|
finally {
|
|
143
170
|
events.end();
|
|
@@ -216,21 +243,22 @@ export function createPiProvider(execution = { name: "pi", kind: "pi" }, load =
|
|
|
216
243
|
if (execution.env !== undefined && Object.keys(execution.env).length > 0) {
|
|
217
244
|
throw new TypeError("env injection not supported for provider pi");
|
|
218
245
|
}
|
|
219
|
-
const drive = async (input) => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
246
|
+
const drive = async (input, custody) => {
|
|
247
|
+
custody.signal.throwIfAborted();
|
|
248
|
+
const sdk = await abortable(load(), custody.signal);
|
|
249
|
+
custody.signal.throwIfAborted();
|
|
250
|
+
return await drivePi(sdk, execution, { ...input, signal: custody.signal }, custody.signal, custody);
|
|
223
251
|
};
|
|
224
252
|
return {
|
|
225
253
|
admitOptions: admitPiOptions,
|
|
226
|
-
start: drive,
|
|
227
|
-
resume: async (
|
|
254
|
+
start: (input) => createProviderAttempt(input.signal, async (custody) => await drive(input, custody)),
|
|
255
|
+
resume: (input) => createProviderAttempt(input.signal, async (custody) => {
|
|
228
256
|
piSessionFile(input.session.coordinate);
|
|
229
|
-
return drive(input);
|
|
230
|
-
},
|
|
231
|
-
fork: async (
|
|
257
|
+
return await drive(input, custody);
|
|
258
|
+
}),
|
|
259
|
+
fork: (input) => createProviderAttempt(new AbortController().signal, async () => {
|
|
232
260
|
piSessionFile(input.session);
|
|
233
|
-
return forkPi(await load(), input);
|
|
234
|
-
},
|
|
261
|
+
return await forkPi(await load(), input);
|
|
262
|
+
}),
|
|
235
263
|
};
|
|
236
264
|
}
|
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import { type Soul } from "./heart/index.js";
|
|
2
2
|
import { type AkumaPaths } from "./identity.js";
|
|
3
|
-
import { type
|
|
4
|
-
import type { OwnedProcess } from "../runtime/proc/run.js";
|
|
5
|
-
export type RequestChildLaunch = Readonly<{
|
|
6
|
-
paths: AkumaPaths;
|
|
7
|
-
seed: Omit<Soul, "createdAt">;
|
|
8
|
-
initialBody: string;
|
|
9
|
-
}>;
|
|
3
|
+
import { type RequestEnvelope } from "./request-wire.js";
|
|
10
4
|
export type PumpInput = Readonly<{
|
|
11
5
|
paths: AkumaPaths;
|
|
12
6
|
parent: Soul;
|
|
13
7
|
bodySequence: number;
|
|
14
8
|
now(): string;
|
|
15
|
-
spawn(launch:
|
|
9
|
+
spawn(launch: unknown): Promise<unknown>;
|
|
16
10
|
upstream?: unknown;
|
|
17
11
|
signal: AbortSignal;
|
|
18
12
|
}>;
|
|
19
13
|
type ServeClaim = (input: PumpInput & Readonly<{
|
|
20
14
|
directory: string;
|
|
21
15
|
transportId: string;
|
|
22
|
-
claim:
|
|
16
|
+
claim: RequestEnvelope;
|
|
23
17
|
signal: AbortSignal;
|
|
24
18
|
admissionOpen(): boolean;
|
|
25
19
|
}>) => Promise<void>;
|
|
@@ -2,9 +2,9 @@ import { access, mkdir, readFile, readdir, rm } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { abortableDelay } from "./abort.js";
|
|
4
4
|
import { HeldAkumaLeash, readNonterminalRequests, readSoul, serveRequest, voidRequest, } from "./heart/index.js";
|
|
5
|
-
import { pathsForAkuId } from "./identity.js";
|
|
5
|
+
import { pathsForAkuId, worldRootForAkumaPaths } from "./identity.js";
|
|
6
6
|
import { BIRTH_TIMEOUT_MS } from "./publication.js";
|
|
7
|
-
import {
|
|
7
|
+
import { decodeEnvelope } from "./request-wire.js";
|
|
8
8
|
const POLL_MS = 100;
|
|
9
9
|
export class BodyRequestPump {
|
|
10
10
|
input;
|
|
@@ -45,7 +45,7 @@ export class BodyRequestPump {
|
|
|
45
45
|
if (this.handled.has(transportId))
|
|
46
46
|
continue;
|
|
47
47
|
const path = join(this.directory, name);
|
|
48
|
-
const claim =
|
|
48
|
+
const claim = decodeEnvelope(await readFile(path, "utf8"), transportId);
|
|
49
49
|
if (claim === null) {
|
|
50
50
|
await rm(path, { force: true });
|
|
51
51
|
this.handled.add(transportId);
|
|
@@ -111,7 +111,7 @@ async function settleReservedSoul(paths, parent, request, soul) {
|
|
|
111
111
|
: voidRequest(paths, request.id, "reserved child origin does not match the request"));
|
|
112
112
|
}
|
|
113
113
|
async function settleReserved(paths, parent, request, now, signal) {
|
|
114
|
-
const childPaths = pathsForAkuId(
|
|
114
|
+
const childPaths = pathsForAkuId(worldRootForAkumaPaths(paths), request.child);
|
|
115
115
|
const deadline = performance.now() + BIRTH_TIMEOUT_MS;
|
|
116
116
|
for (;;) {
|
|
117
117
|
signal?.throwIfAborted();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RequestCommand } from "./request-wire.js";
|
|
2
|
+
export declare class AkumaBodyRequestError extends Error {
|
|
3
|
+
readonly action: string;
|
|
4
|
+
readonly outcome: "refused" | "voided";
|
|
5
|
+
readonly diagnostic: string;
|
|
6
|
+
readonly kind = "akuma-body-request";
|
|
7
|
+
constructor(action: string, outcome: "refused" | "voided", diagnostic: string);
|
|
8
|
+
}
|
|
9
|
+
/** Generic rendezvous only: operation owners supply their own request and result codecs. */
|
|
10
|
+
export declare function requestBodyCommand<Input, Output, Service, Reference = Service>(input: Readonly<{
|
|
11
|
+
directory: string;
|
|
12
|
+
id?: string;
|
|
13
|
+
command: RequestCommand<Input, Output, Service, Reference>;
|
|
14
|
+
value: Input;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}>): Promise<Readonly<{
|
|
17
|
+
kind: "returned";
|
|
18
|
+
result: Output;
|
|
19
|
+
requestId: string;
|
|
20
|
+
action: string;
|
|
21
|
+
}> | Readonly<{
|
|
22
|
+
kind: "reference";
|
|
23
|
+
reference: Reference;
|
|
24
|
+
requestId: string;
|
|
25
|
+
action: string;
|
|
26
|
+
}>>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
3
|
+
import { abortableDelay } from "./abort.js";
|
|
4
|
+
import { atomicJson, decodeReceiptEnvelope, receiptPath, requestPath } from "./request-wire.js";
|
|
5
|
+
const POLL_MS = 100;
|
|
6
|
+
export class AkumaBodyRequestError extends Error {
|
|
7
|
+
action;
|
|
8
|
+
outcome;
|
|
9
|
+
diagnostic;
|
|
10
|
+
kind = "akuma-body-request";
|
|
11
|
+
constructor(action, outcome, diagnostic) {
|
|
12
|
+
super(`${action} ${outcome === "voided" ? "failed" : "refused"}: ${diagnostic}`);
|
|
13
|
+
this.action = action;
|
|
14
|
+
this.outcome = outcome;
|
|
15
|
+
this.diagnostic = diagnostic;
|
|
16
|
+
this.name = "AkumaBodyRequestError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function throwVoidedRequestFailure(action, evidence, failure, decodeFailure) {
|
|
20
|
+
const ownerFailure = decodeVoidedOwnerFailure(failure, decodeFailure);
|
|
21
|
+
if (ownerFailure !== null)
|
|
22
|
+
throw ownerFailure;
|
|
23
|
+
throw new AkumaBodyRequestError(action, "voided", evidence);
|
|
24
|
+
}
|
|
25
|
+
function decodeVoidedOwnerFailure(failure, decodeFailure) {
|
|
26
|
+
if (failure === undefined || decodeFailure === undefined)
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
return decodeFailure(failure);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function withRequestMetadata(response, id, action) {
|
|
36
|
+
Object.defineProperties(response, {
|
|
37
|
+
requestId: { value: id, enumerable: false },
|
|
38
|
+
action: { value: action, enumerable: false },
|
|
39
|
+
});
|
|
40
|
+
return response;
|
|
41
|
+
}
|
|
42
|
+
/** Generic rendezvous only: operation owners supply their own request and result codecs. */
|
|
43
|
+
export async function requestBodyCommand(input) {
|
|
44
|
+
const id = input.id ?? randomUUID();
|
|
45
|
+
input.signal?.throwIfAborted();
|
|
46
|
+
const transportId = randomUUID();
|
|
47
|
+
await atomicJson(requestPath(input.directory, transportId), {
|
|
48
|
+
id,
|
|
49
|
+
action: input.command.action,
|
|
50
|
+
payload: input.command.encodeRequest(input.value),
|
|
51
|
+
});
|
|
52
|
+
const path = receiptPath(input.directory, transportId);
|
|
53
|
+
for (;;) {
|
|
54
|
+
try {
|
|
55
|
+
const receipt = decodeReceiptEnvelope(await readFile(path, "utf8"), id, input.command.action);
|
|
56
|
+
if (receipt === null)
|
|
57
|
+
throw new Error(`Akuma body request ${id} has an invalid receipt`);
|
|
58
|
+
if (receipt.state === "refused")
|
|
59
|
+
throw new AkumaBodyRequestError(receipt.action, "refused", receipt.diagnostic);
|
|
60
|
+
if (receipt.state === "voided") {
|
|
61
|
+
throwVoidedRequestFailure(receipt.action, receipt.evidence, receipt.failure, input.command.decodeFailure);
|
|
62
|
+
}
|
|
63
|
+
if ("reference" in receipt) {
|
|
64
|
+
let reference;
|
|
65
|
+
try {
|
|
66
|
+
reference = input.command.decodeReference(receipt.reference);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
70
|
+
throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid durable reference: ${diagnostic}`);
|
|
71
|
+
}
|
|
72
|
+
return withRequestMetadata({
|
|
73
|
+
kind: "reference",
|
|
74
|
+
reference,
|
|
75
|
+
}, id, input.command.action);
|
|
76
|
+
}
|
|
77
|
+
if (receipt.outcome.kind === "failed") {
|
|
78
|
+
const failure = receipt.outcome.failure;
|
|
79
|
+
throw new Error(failure.kind === "failed" ? failure.diagnostic : `Akuma ${failure.id} was not born`);
|
|
80
|
+
}
|
|
81
|
+
let result;
|
|
82
|
+
try {
|
|
83
|
+
result = input.command.decodeResult(receipt.outcome.result);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const diagnostic = error instanceof Error ? error.message : String(error);
|
|
87
|
+
throw new Error(`transport integrity: request ${id} action ${input.command.action} returned an invalid live result: ${diagnostic}`);
|
|
88
|
+
}
|
|
89
|
+
return withRequestMetadata({ kind: "returned", result }, id, input.command.action);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error.code !== "ENOENT")
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
if (!(await access(input.directory).then(() => true, () => false))) {
|
|
96
|
+
throw new AkumaBodyRequestError(input.command.action, "voided", "parent request channel closed before a receipt");
|
|
97
|
+
}
|
|
98
|
+
await abortableDelay(POLL_MS, input.signal);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,76 +1,16 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type
|
|
3
|
-
import { type StructuralRequestClaim } from "./request-wire.js";
|
|
4
|
-
import { type TaskMutationRequest } from "../task/mutation.js";
|
|
5
|
-
import { BodyRequestPump as LifecycleBodyRequestPump, type RequestChildLaunch as LifecycleRequestChildLaunch, type PumpInput as LifecyclePumpInput } from "./request-lifecycle.js";
|
|
1
|
+
import { type ErasedRequestCommand, type RequestEnvelope } from "./request-wire.js";
|
|
2
|
+
import { BodyRequestPump as LifecycleBodyRequestPump, type PumpInput as LifecyclePumpInput } from "./request-lifecycle.js";
|
|
6
3
|
export { clearBodyRequestTransport, settleBodyRequests } from "./request-lifecycle.js";
|
|
7
|
-
export type RequestChildLaunch = LifecycleRequestChildLaunch;
|
|
8
|
-
type UpstreamCall = Readonly<{
|
|
9
|
-
signal: AbortSignal;
|
|
10
|
-
}>;
|
|
11
|
-
type RequesterCall = UpstreamCall & Readonly<{
|
|
12
|
-
requester: AkuId;
|
|
13
|
-
}>;
|
|
14
|
-
type ContractCall = RequesterCall & Readonly<{
|
|
15
|
-
repoRoot: string;
|
|
16
|
-
contractId: string;
|
|
17
|
-
}>;
|
|
18
|
-
export type UpstreamExecutionPort = Readonly<{
|
|
19
|
-
wait(input: UpstreamCall & Readonly<{
|
|
20
|
-
targets: readonly AkuId[];
|
|
21
|
-
completion: "any" | "all";
|
|
22
|
-
timeoutMs?: number;
|
|
23
|
-
}>): Promise<unknown>;
|
|
24
|
-
tell(input: UpstreamCall & Readonly<{
|
|
25
|
-
target: AkuId;
|
|
26
|
-
body: string;
|
|
27
|
-
tellId: string;
|
|
28
|
-
recordedAt: string;
|
|
29
|
-
}>): Promise<unknown>;
|
|
30
|
-
kill(input: Readonly<{
|
|
31
|
-
targets: readonly AkuId[];
|
|
32
|
-
signal: AbortSignal;
|
|
33
|
-
}>): Promise<Readonly<{
|
|
34
|
-
result: unknown;
|
|
35
|
-
service: readonly Readonly<{
|
|
36
|
-
id: AkuId;
|
|
37
|
-
evidence: KillEvidence;
|
|
38
|
-
}>[];
|
|
39
|
-
}>>;
|
|
40
|
-
deliver(input: ContractCall & Readonly<{
|
|
41
|
-
message?: string;
|
|
42
|
-
includeDirty: boolean;
|
|
43
|
-
materializeConflict: boolean;
|
|
44
|
-
}>): Promise<Readonly<{
|
|
45
|
-
result: unknown;
|
|
46
|
-
deliveryFactId?: string;
|
|
47
|
-
}>>;
|
|
48
|
-
review(input: ContractCall & Readonly<{
|
|
49
|
-
verdict: "satisfied" | "unsatisfied";
|
|
50
|
-
summary?: string;
|
|
51
|
-
}>): Promise<Readonly<{
|
|
52
|
-
result: unknown;
|
|
53
|
-
reviewFactId?: string;
|
|
54
|
-
}>>;
|
|
55
|
-
task(input: RequesterCall & Readonly<{
|
|
56
|
-
world: string;
|
|
57
|
-
request: TaskMutationRequest;
|
|
58
|
-
}>): Promise<unknown>;
|
|
59
|
-
}>;
|
|
60
4
|
type PumpInput = Omit<LifecyclePumpInput, "upstream"> & Readonly<{
|
|
61
|
-
upstream?:
|
|
5
|
+
upstream?: unknown;
|
|
6
|
+
commands: Readonly<Record<string, ErasedRequestCommand>>;
|
|
62
7
|
}>;
|
|
63
8
|
export type ServeInput = Omit<PumpInput, "bodySequence"> & Readonly<{
|
|
64
9
|
directory: string;
|
|
65
10
|
transportId: string;
|
|
66
|
-
claim:
|
|
11
|
+
claim: RequestEnvelope;
|
|
67
12
|
admissionOpen(): boolean;
|
|
68
13
|
}>;
|
|
69
|
-
export type UpstreamFact = Exclude<Extract<RequestFact, {
|
|
70
|
-
state: "admitted";
|
|
71
|
-
}>, Extract<RequestFact, {
|
|
72
|
-
action: "akuma.call";
|
|
73
|
-
}>>;
|
|
74
14
|
export declare function serveRequest(input: ServeInput): Promise<void>;
|
|
75
15
|
export declare class BodyRequestPump extends LifecycleBodyRequestPump {
|
|
76
16
|
static open(input: PumpInput): Promise<BodyRequestPump>;
|