@astrosheep/keiyaku 4.6.7 → 4.6.9
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 +46 -16
- package/build/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/build/plugins/claude/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/claude/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/build/plugins/codex/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/codex/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/opencode/index.js +1 -1
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/opencode/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/pi/keiyaku.ts +0 -5
- package/build/skills/keiyaku/SKILL.md +5 -6
- package/build/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/src/akuma/akuma-call.d.ts +2 -0
- package/build/src/akuma/akuma-call.js +8 -2
- package/build/src/akuma/akuma-instance.d.ts +14 -1
- package/build/src/akuma/akuma-instance.js +37 -7
- package/build/src/akuma/akuma-observe.d.ts +33 -8
- package/build/src/akuma/akuma-observe.js +89 -63
- package/build/src/akuma/akuma-owner.d.ts +14 -2
- package/build/src/akuma/akuma-owner.js +49 -35
- package/build/src/akuma/akuma-selection-execution.js +9 -1
- package/build/src/akuma/akuma-stream.d.ts +22 -0
- package/build/src/akuma/akuma-stream.js +116 -0
- package/build/src/akuma/akuma-wait.d.ts +1 -40
- package/build/src/akuma/akuma-wait.js +23 -84
- package/build/src/akuma/akuma.d.ts +52 -16
- package/build/src/akuma/akuma.js +10 -10
- package/build/src/akuma/allowed.d.ts +7 -12
- package/build/src/akuma/allowed.js +13 -4
- package/build/src/akuma/archetype.d.ts +7 -15
- package/build/src/akuma/archetype.js +36 -35
- package/build/src/akuma/body-supervisor.d.ts +5 -5
- package/build/src/akuma/body-supervisor.js +22 -20
- package/build/src/akuma/body.d.ts +5 -3
- package/build/src/akuma/body.js +57 -8
- package/build/src/akuma/call-request.d.ts +30 -32
- package/build/src/akuma/call-request.js +10 -3
- package/build/src/akuma/caller.d.ts +39 -0
- package/build/src/akuma/caller.js +36 -0
- package/build/src/akuma/dispatch-association.d.ts +0 -1
- package/build/src/akuma/dispatch-association.js +0 -3
- package/build/src/akuma/heart/activity-schema.d.ts +12 -0
- package/build/src/akuma/heart/activity-schema.js +6 -0
- package/build/src/akuma/heart/facts.d.ts +16 -12
- package/build/src/akuma/heart/facts.js +8 -0
- package/build/src/akuma/heart/index.d.ts +61 -9
- package/build/src/akuma/heart/index.js +89 -24
- package/build/src/akuma/heart/rows.d.ts +3 -3
- package/build/src/akuma/heart/rows.js +5 -3
- package/build/src/akuma/heart/soul.d.ts +10 -1
- package/build/src/akuma/heart/soul.js +34 -24
- package/build/src/akuma/heart/storage.d.ts +20 -0
- package/build/src/akuma/heart/storage.js +62 -3
- package/build/src/akuma/heart/timeline.d.ts +7 -0
- package/build/src/akuma/heart/timeline.js +10 -0
- package/build/src/akuma/identity.d.ts +0 -1
- package/build/src/akuma/identity.js +2 -5
- package/build/src/akuma/index.d.ts +6 -2
- package/build/src/akuma/index.js +1 -0
- package/build/src/akuma/nuke.js +6 -28
- package/build/src/akuma/projection.d.ts +25 -11
- package/build/src/akuma/projection.js +24 -7
- package/build/src/akuma/provider-recipe.d.ts +18 -6
- package/build/src/akuma/provider-recipe.js +24 -1
- package/build/src/akuma/provider.d.ts +31 -10
- package/build/src/akuma/provider.js +105 -14
- package/build/src/akuma/providers/acp/events.js +29 -19
- package/build/src/akuma/providers/acp/index.js +2 -3
- package/build/src/akuma/providers/claude/events.js +110 -69
- package/build/src/akuma/providers/claude/index.d.ts +2 -2
- package/build/src/akuma/providers/claude/index.js +4 -8
- package/build/src/akuma/providers/codex-app-server/events.js +17 -2
- package/build/src/akuma/providers/codex-app-server/index.js +17 -11
- package/build/src/akuma/providers/decode.d.ts +33 -0
- package/build/src/akuma/providers/decode.js +65 -0
- package/build/src/akuma/providers/execution-environment.d.ts +2 -1
- package/build/src/akuma/providers/execution-environment.js +3 -0
- package/build/src/akuma/providers/grok-build/index.js +16 -48
- package/build/src/akuma/providers/index.js +2 -0
- package/build/src/akuma/providers/lifecycle.d.ts +9 -0
- package/build/src/akuma/providers/lifecycle.js +10 -0
- package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
- package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
- package/build/src/akuma/providers/opencode-sdk/events.js +146 -296
- package/build/src/akuma/providers/opencode-sdk/index.js +270 -431
- package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
- package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
- package/build/src/akuma/providers/opencode-sdk/session.js +75 -84
- package/build/src/akuma/providers/paseo/events.d.ts +33 -0
- package/build/src/akuma/providers/paseo/events.js +204 -0
- package/build/src/akuma/providers/paseo/index.d.ts +9 -0
- package/build/src/akuma/providers/paseo/index.js +357 -0
- package/build/src/akuma/providers/pi/events.d.ts +2 -0
- package/build/src/akuma/providers/pi/events.js +36 -38
- package/build/src/akuma/providers/pi/index.js +21 -35
- package/build/src/akuma/publication.d.ts +2 -0
- package/build/src/akuma/publication.js +5 -0
- package/build/src/akuma/request-lifecycle.d.ts +4 -2
- package/build/src/akuma/request-lifecycle.js +27 -12
- package/build/src/akuma/request-rendezvous.js +38 -55
- package/build/src/akuma/request-serve.d.ts +1 -1
- package/build/src/akuma/request-serve.js +77 -113
- package/build/src/akuma/requests.d.ts +3 -1
- package/build/src/akuma/requests.js +32 -0
- package/build/src/akuma/selection-observation.d.ts +129 -53
- package/build/src/akuma/selection-observation.js +3 -9
- package/build/src/akuma/turn-drive.d.ts +3 -0
- package/build/src/akuma/turn-drive.js +28 -10
- package/build/src/akuma-body.js +12 -22
- package/build/src/cli/akuma-caller.d.ts +3 -0
- package/build/src/cli/akuma-caller.js +31 -0
- package/build/src/cli/commands/akuma-grammar.js +10 -16
- package/build/src/cli/commands/akuma.js +25 -55
- package/build/src/cli/commands/contract-grammar.d.ts +9 -7
- package/build/src/cli/commands/contract-grammar.js +40 -47
- package/build/src/cli/commands/contract-help.d.ts +17 -7
- package/build/src/cli/commands/contract-help.js +50 -11
- package/build/src/cli/commands/contract.js +34 -63
- package/build/src/cli/commands/debt-grammar.d.ts +19 -0
- package/build/src/cli/commands/debt-grammar.js +323 -0
- package/build/src/cli/commands/debt-query.d.ts +5 -0
- package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
- package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
- package/build/src/cli/commands/{task.js → debt.js} +87 -164
- package/build/src/cli/coordinates.d.ts +1 -1
- package/build/src/cli/coordinates.js +1 -1
- package/build/src/cli/parse.d.ts +5 -5
- package/build/src/cli/parse.js +17 -16
- package/build/src/cli/render/akuma-activity.d.ts +11 -83
- package/build/src/cli/render/akuma-activity.js +20 -382
- package/build/src/cli/render/catalog.d.ts +4 -7
- package/build/src/cli/render/catalog.js +5 -5
- package/build/src/cli/render/contract-history.js +3 -6
- package/build/src/cli/render/contract.js +17 -52
- package/build/src/cli/render/debt.d.ts +28 -0
- package/build/src/cli/render/{task.js → debt.js} +55 -133
- package/build/src/cli/render/kanshi.js +28 -28
- package/build/src/cli/render/marks.d.ts +5 -5
- package/build/src/cli/render/marks.js +4 -10
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/render/receipt.js +3 -10
- package/build/src/cli/runtime.d.ts +1 -1
- package/build/src/cli/runtime.js +14 -20
- package/build/src/cli/scan.d.ts +1 -1
- package/build/src/cli/selectors.d.ts +3 -6
- package/build/src/cli/selectors.js +22 -53
- package/build/src/cli/usage.d.ts +1 -1
- package/build/src/cli/usage.js +4 -4
- package/build/src/contract-worktree.js +3 -3
- package/build/src/debt/board.d.ts +160 -0
- package/build/src/{task → debt}/board.js +89 -89
- package/build/src/debt/catalog.d.ts +11 -0
- package/build/src/debt/catalog.js +59 -0
- package/build/src/{task → debt}/context.d.ts +1 -1
- package/build/src/{task → debt}/context.js +1 -1
- package/build/src/{task → debt}/created-observation.d.ts +6 -10
- package/build/src/{task → debt}/created-observation.js +7 -7
- package/build/src/debt/document.d.ts +37 -0
- package/build/src/{task → debt}/document.js +37 -37
- package/build/src/debt/identity.d.ts +21 -0
- package/build/src/{task → debt}/identity.js +35 -35
- package/build/src/debt/index.d.ts +111 -0
- package/build/src/debt/index.js +203 -0
- package/build/src/{task → debt}/input.d.ts +8 -8
- package/build/src/{task → debt}/input.js +21 -21
- package/build/src/debt/lifecycle-operations.d.ts +6 -0
- package/build/src/{task → debt}/lifecycle-operations.js +27 -31
- package/build/src/debt/mutation-result.d.ts +981 -0
- package/build/src/debt/mutation-result.js +109 -0
- package/build/src/debt/mutation.d.ts +424 -0
- package/build/src/debt/mutation.js +223 -0
- package/build/src/debt/operation-types.d.ts +71 -0
- package/build/src/debt/operations.d.ts +28 -0
- package/build/src/{task → debt}/operations.js +59 -60
- package/build/src/debt/query.d.ts +76 -0
- package/build/src/{task → debt}/query.js +55 -55
- package/build/src/{task → debt}/store.d.ts +13 -13
- package/build/src/{task → debt}/store.js +58 -49
- package/build/src/debt/view.d.ts +4 -0
- package/build/src/debt/view.js +7 -0
- package/build/src/dispatch/index.d.ts +3 -3
- package/build/src/dispatch/index.js +1 -2
- package/build/src/git/observe.d.ts +6 -2
- package/build/src/git/observe.js +6 -2
- package/build/src/identity/coordinates.d.ts +1 -1
- package/build/src/index.d.ts +17 -17
- package/build/src/index.js +11 -11
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/read.js +54 -39
- package/build/src/kanshi/report.d.ts +7 -7
- package/build/src/kanshi/select.js +4 -4
- package/build/src/library/address.js +2 -4
- package/build/src/library/akuma-creation.d.ts +5 -1
- package/build/src/library/akuma-creation.js +27 -47
- package/build/src/library/akumas.d.ts +7 -7
- package/build/src/library/akumas.js +13 -9
- package/build/src/library/bind.d.ts +17 -17
- package/build/src/library/bind.js +16 -12
- package/build/src/library/contract-address.d.ts +9 -0
- package/build/src/library/contract-address.js +71 -0
- package/build/src/library/contract-composition.d.ts +4 -7
- package/build/src/library/contract-composition.js +6 -18
- package/build/src/library/contract-creation.d.ts +3 -5
- package/build/src/library/contract-creation.js +24 -22
- package/build/src/library/contract-execution.js +21 -26
- package/build/src/library/contract-outcomes.d.ts +2 -14
- package/build/src/library/contract-outcomes.js +2 -13
- package/build/src/library/contract-types.d.ts +38 -4
- package/build/src/library/delivery.d.ts +0 -2
- package/build/src/library/delivery.js +2 -5
- package/build/src/library/input.d.ts +2 -2
- package/build/src/library/input.js +5 -5
- package/build/src/library/invocation.js +2 -2
- package/build/src/library/keiyaku.d.ts +0 -5
- package/build/src/library/keiyaku.js +6 -12
- package/build/src/library/nuke.js +3 -3
- package/build/src/library/outcome.d.ts +626 -625
- package/build/src/library/outcome.js +13 -3
- package/build/src/library/reconcile.js +8 -16
- package/build/src/library/refusal.d.ts +2 -2
- package/build/src/library/repo.d.ts +3 -2
- package/build/src/library/repo.js +10 -5
- package/build/src/library/selection.d.ts +5 -8
- package/build/src/library/selection.js +22 -73
- package/build/src/plugin/akuma-signals.d.ts +2 -0
- package/build/src/plugin/akuma-signals.js +4 -0
- package/build/src/plugin/public.d.ts +32 -2
- package/build/src/plugin/runtime.js +5 -3
- package/build/src/protocol/amend.js +3 -2
- package/build/src/protocol/attempt.js +3 -8
- package/build/src/protocol/bind.d.ts +2 -2
- package/build/src/protocol/bind.js +1 -1
- package/build/src/protocol/deliver.js +3 -3
- package/build/src/protocol/operations.d.ts +1 -3
- package/build/src/protocol/operations.js +0 -8
- package/build/src/protocol/outcome.d.ts +1 -2
- package/build/src/protocol/outcome.js +1 -13
- package/build/src/protocol/placement.js +3 -10
- package/build/src/protocol/read/status.js +31 -70
- package/build/src/protocol/reintegrate.js +3 -10
- package/build/src/protocol/review.js +3 -3
- package/build/src/protocol/run.d.ts +5 -1
- package/build/src/protocol/run.js +3 -3
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/fence.d.ts +3 -3
- package/build/src/settlement/fence.js +4 -4
- package/build/src/settlement/holder.d.ts +16 -16
- package/build/src/settlement/holder.js +69 -63
- package/build/src/settlement/settle.d.ts +5 -5
- package/build/src/settlement/settle.js +53 -53
- package/package.json +19 -9
- package/plugins/paseo/plugin/index.server.ts +17 -0
- package/plugins/paseo/plugin/paseo-plugin.json +4 -0
- package/plugins/paseo/plugin/server/attach.ts +52 -0
- package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
- package/plugins/paseo/plugin/server/message.ts +60 -0
- package/plugins/paseo/plugin/server/mirror.ts +193 -0
- package/plugins/paseo/plugin/server/model.ts +14 -0
- package/plugins/paseo/plugin/server/provider.ts +276 -0
- package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
- package/plugins/paseo/plugin/server/sdk.ts +289 -0
- package/plugins/paseo/plugin/server/stop.ts +26 -0
- package/plugins/paseo/plugin/server/transport.ts +35 -0
- package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
- package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
- package/plugins/paseo/plugin/tsconfig.json +6 -0
- package/plugins/pi/keiyaku.ts +57 -0
- package/skills/keiyaku/SKILL.md +43 -0
- package/skills/keiyaku-akuma/SKILL.md +130 -0
- package/skills/keiyaku-akuma/references/automation.md +269 -0
- package/skills/keiyaku-babysit/SKILL.md +65 -0
- package/skills/keiyaku-bind/SKILL.md +216 -0
- package/skills/keiyaku-bind/agents/openai.yaml +4 -0
- package/skills/keiyaku-debt/SKILL.md +91 -0
- package/skills/keiyaku-workflow/SKILL.md +129 -0
- package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
- package/build/skills/keiyaku-task/SKILL.md +0 -104
- package/build/src/cli/commands/amend.d.ts +0 -12
- package/build/src/cli/commands/amend.js +0 -10
- package/build/src/cli/commands/bind.d.ts +0 -11
- package/build/src/cli/commands/bind.js +0 -23
- package/build/src/cli/commands/task-grammar.d.ts +0 -19
- package/build/src/cli/commands/task-grammar.js +0 -384
- package/build/src/cli/commands/task-query.d.ts +0 -5
- package/build/src/cli/render/task.d.ts +0 -41
- package/build/src/dispatch/association.d.ts +0 -1
- package/build/src/dispatch/association.js +0 -1
- package/build/src/task/board.d.ts +0 -168
- package/build/src/task/catalog.d.ts +0 -11
- package/build/src/task/catalog.js +0 -59
- package/build/src/task/compose-language.d.ts +0 -57
- package/build/src/task/compose-language.js +0 -364
- package/build/src/task/compose-parser.d.ts +0 -32
- package/build/src/task/compose-parser.js +0 -180
- package/build/src/task/compose.d.ts +0 -16
- package/build/src/task/compose.js +0 -189
- package/build/src/task/document.d.ts +0 -39
- package/build/src/task/identity.d.ts +0 -21
- package/build/src/task/index.d.ts +0 -138
- package/build/src/task/index.js +0 -269
- package/build/src/task/lifecycle-operations.d.ts +0 -6
- package/build/src/task/mutation-result.d.ts +0 -1726
- package/build/src/task/mutation-result.js +0 -198
- package/build/src/task/mutation.d.ts +0 -590
- package/build/src/task/mutation.js +0 -262
- package/build/src/task/operation-types.d.ts +0 -71
- package/build/src/task/operations.d.ts +0 -28
- package/build/src/task/query.d.ts +0 -76
- package/build/src/task/view.d.ts +0 -4
- package/build/src/task/view.js +0 -7
- /package/build/src/{task → debt}/operation-types.js +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type OpenCodeClient } from "@opencode/client";
|
|
2
|
+
/** The matching native SDK owns the dialect; this attempt owns its HTTP connections. */
|
|
3
|
+
export declare function createNativeClient(baseUrl: string, password: string): Readonly<{
|
|
4
|
+
sdk: OpenCodeClient;
|
|
5
|
+
subscribe(signal: AbortSignal): Promise<Readonly<{
|
|
6
|
+
stream: AsyncIterable<unknown>;
|
|
7
|
+
}>>;
|
|
8
|
+
close(): Promise<void>;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { OpenCode } from "@opencode/client";
|
|
2
|
+
import { Agent } from "undici";
|
|
3
|
+
import { object } from "../decode.js";
|
|
4
|
+
/** The matching native SDK owns the dialect; this attempt owns its HTTP connections. */
|
|
5
|
+
export function createNativeClient(baseUrl, password) {
|
|
6
|
+
const dispatcher = new Agent();
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
// Node's fetch accepts an Undici dispatcher in addition to standard RequestInit.
|
|
9
|
+
// Keep that native extension at this one SDK seam.
|
|
10
|
+
const ownedFetch = (input, init) => {
|
|
11
|
+
controller.signal.throwIfAborted();
|
|
12
|
+
const options = {
|
|
13
|
+
...init,
|
|
14
|
+
dispatcher,
|
|
15
|
+
signal: init?.signal == null ? controller.signal : AbortSignal.any([controller.signal, init.signal]),
|
|
16
|
+
};
|
|
17
|
+
return globalThis.fetch(input, options);
|
|
18
|
+
};
|
|
19
|
+
const sdk = OpenCode.make({
|
|
20
|
+
baseUrl,
|
|
21
|
+
fetch: ownedFetch,
|
|
22
|
+
headers: { authorization: `Basic ${Buffer.from(`opencode:${password}`).toString("base64")}` },
|
|
23
|
+
});
|
|
24
|
+
const subscribe = async (signal) => {
|
|
25
|
+
const iterator = sdk.event.subscribe({ signal })[Symbol.asyncIterator]();
|
|
26
|
+
try {
|
|
27
|
+
// The producer subscribes before emitting this frame. Headers alone are
|
|
28
|
+
// not a barrier against losing the opening native admission broadcast.
|
|
29
|
+
const connected = await iterator.next();
|
|
30
|
+
if (connected.done || object(connected.value)?.type !== "server.connected") {
|
|
31
|
+
throw new Error("OpenCode event feed did not confirm subscription");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
await iterator.return?.();
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
stream: {
|
|
40
|
+
[Symbol.asyncIterator]: () => ({
|
|
41
|
+
next: async () => {
|
|
42
|
+
const next = await iterator.next();
|
|
43
|
+
// Effect stream-failure frames are not native events. The generated
|
|
44
|
+
// SDK parser can yield their payload; never drop that into narration.
|
|
45
|
+
if (!next.done && typeof object(next.value)?.type !== "string") {
|
|
46
|
+
throw new Error("OpenCode native event feed failed");
|
|
47
|
+
}
|
|
48
|
+
return next;
|
|
49
|
+
},
|
|
50
|
+
return: () => iterator.return?.() ?? Promise.resolve({ done: true, value: undefined }),
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
let closing;
|
|
56
|
+
return {
|
|
57
|
+
sdk,
|
|
58
|
+
subscribe,
|
|
59
|
+
close: () => {
|
|
60
|
+
closing ??= (async () => {
|
|
61
|
+
controller.abort();
|
|
62
|
+
// SDK iterator retirement is logical. Dispatcher destruction separately
|
|
63
|
+
// awaits closure of every socket, including requests aborted during setup.
|
|
64
|
+
await dispatcher.destroy();
|
|
65
|
+
})();
|
|
66
|
+
return closing;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -1,24 +1,49 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SessionCreateInput, SessionSwitchModelInput } from "@opencode/client";
|
|
2
2
|
import type { ResumeCoordinate } from "../../heart/index.js";
|
|
3
3
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
4
|
-
export type OpencodeSdkSession =
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
export type OpencodeSdkSession = Readonly<{
|
|
5
|
+
create(input: {
|
|
6
|
+
body: SessionCreateInput;
|
|
7
|
+
}): Promise<unknown>;
|
|
8
|
+
get(input: {
|
|
9
|
+
id: string;
|
|
10
|
+
}): Promise<unknown>;
|
|
11
|
+
switchModel(input: {
|
|
12
|
+
id: string;
|
|
13
|
+
model: SessionSwitchModelInput["model"];
|
|
14
|
+
}): Promise<unknown>;
|
|
15
|
+
instructions(input: {
|
|
16
|
+
id: string;
|
|
17
|
+
text: string;
|
|
18
|
+
}): Promise<unknown>;
|
|
19
|
+
active(): Promise<unknown>;
|
|
20
|
+
fork(input: {
|
|
21
|
+
id: string;
|
|
22
|
+
before: string;
|
|
23
|
+
}): Promise<unknown>;
|
|
24
|
+
interrupt(input: {
|
|
25
|
+
id: string;
|
|
26
|
+
}): Promise<unknown>;
|
|
27
|
+
prompt(input: {
|
|
28
|
+
id: string;
|
|
29
|
+
body: {
|
|
30
|
+
id: string;
|
|
31
|
+
text: string;
|
|
32
|
+
};
|
|
33
|
+
}): Promise<unknown>;
|
|
34
|
+
message(input: {
|
|
35
|
+
id: string;
|
|
36
|
+
messageID: string;
|
|
37
|
+
}): Promise<unknown>;
|
|
38
|
+
}>;
|
|
10
39
|
export type OpencodeEventSubscriptionRequest = Readonly<{
|
|
11
40
|
directory: string;
|
|
12
|
-
/** Cancels the subscription's fetch, reader, and retry waiting. */
|
|
13
41
|
signal: AbortSignal;
|
|
14
|
-
/** Resolves without rejecting when `signal` aborts, and always clears its timer. */
|
|
15
|
-
sleep(milliseconds: number): Promise<void>;
|
|
16
|
-
}>;
|
|
17
|
-
type OpencodeEventSubscription = Readonly<{
|
|
18
|
-
stream: AsyncIterable<unknown>;
|
|
19
42
|
}>;
|
|
20
43
|
export type OpencodeSdkEvent = Readonly<{
|
|
21
|
-
subscribe(request: OpencodeEventSubscriptionRequest): Promise<
|
|
44
|
+
subscribe(request: OpencodeEventSubscriptionRequest): Promise<Readonly<{
|
|
45
|
+
stream: AsyncIterable<unknown>;
|
|
46
|
+
}>>;
|
|
22
47
|
}>;
|
|
23
48
|
export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution, signal: AbortSignal) => Promise<Readonly<{
|
|
24
49
|
client: {
|
|
@@ -29,31 +54,11 @@ export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution, sign
|
|
|
29
54
|
ready?: Promise<void>;
|
|
30
55
|
}>>;
|
|
31
56
|
export declare const OPENCODE_SDK_PROVIDER: "opencode-sdk";
|
|
32
|
-
/**
|
|
33
|
-
* Adapt the installed client's generated event endpoint to the adapter's
|
|
34
|
-
* subscription port.
|
|
35
|
-
*
|
|
36
|
-
* The generated per-endpoint `Options` type omits the SDK's runtime
|
|
37
|
-
* `sseSleepFn` option even though the client forwards every per-request key
|
|
38
|
-
* into `createSseClient`, so a caller cannot express a cancellable backoff
|
|
39
|
-
* through the published type. Declaring the port here keeps that one typing gap
|
|
40
|
-
* and its single adaptation at the SDK seam: no other module repeats a cast,
|
|
41
|
-
* the SDK's own parser and retry policy stay untouched, and an injected loader
|
|
42
|
-
* supplies the same port shape.
|
|
43
|
-
*/
|
|
44
|
-
export declare function opencodeEventPort(event: OpencodeClient["event"]): OpencodeSdkEvent;
|
|
45
57
|
export declare function messageId(sequence?: number): string;
|
|
46
58
|
export declare function parseModel(model: string): Readonly<{
|
|
47
59
|
providerID: string;
|
|
48
|
-
|
|
60
|
+
id: string;
|
|
49
61
|
}>;
|
|
50
|
-
/**
|
|
51
|
-
* Compose the config handed to a headless opencode server. The permission base
|
|
52
|
-
* layer fills only the classes the caller leaves unspecified: an explicit caller
|
|
53
|
-
* permission key wins per key and every non-permission key passes through
|
|
54
|
-
* untouched. A caller that supplies a non-object `permission` shorthand states
|
|
55
|
-
* the whole policy and keeps it.
|
|
56
|
-
*/
|
|
57
62
|
export declare function composeHeadlessPermissionConfig(config?: Readonly<Record<string, unknown>>): Record<string, unknown>;
|
|
58
63
|
export type OpencodeRuntime = Readonly<{
|
|
59
64
|
client: {
|
|
@@ -62,6 +67,8 @@ export type OpencodeRuntime = Readonly<{
|
|
|
62
67
|
};
|
|
63
68
|
close: () => Promise<void>;
|
|
64
69
|
}>;
|
|
70
|
+
/** A successful HTML fallback, or a JSON response from another API, is not readiness. */
|
|
71
|
+
export declare function waitReady(json: (path: string) => Promise<unknown>, signal: AbortSignal): Promise<void>;
|
|
65
72
|
export declare function loadOpencode(input: Readonly<{
|
|
66
73
|
execution: ProviderExecution;
|
|
67
74
|
cwd: string;
|
|
@@ -71,4 +78,3 @@ export declare function loadOpencode(input: Readonly<{
|
|
|
71
78
|
requests?: string;
|
|
72
79
|
}>): Promise<OpencodeRuntime>;
|
|
73
80
|
export declare function coordinate(sessionId: string): ResumeCoordinate;
|
|
74
|
-
export {};
|
|
@@ -3,92 +3,59 @@ import { randomBytes } from "node:crypto";
|
|
|
3
3
|
import { abortable } from "../../abort.js";
|
|
4
4
|
import { akumaExecutionEnvironment } from "../execution-environment.js";
|
|
5
5
|
import { spawnDetachedProcess } from "../../../runtime/proc/run.js";
|
|
6
|
+
import { object } from "../decode.js";
|
|
7
|
+
import { createNativeClient } from "./native-http.js";
|
|
6
8
|
export const OPENCODE_SDK_PROVIDER = "opencode-sdk";
|
|
7
|
-
/**
|
|
8
|
-
* Adapt the installed client's generated event endpoint to the adapter's
|
|
9
|
-
* subscription port.
|
|
10
|
-
*
|
|
11
|
-
* The generated per-endpoint `Options` type omits the SDK's runtime
|
|
12
|
-
* `sseSleepFn` option even though the client forwards every per-request key
|
|
13
|
-
* into `createSseClient`, so a caller cannot express a cancellable backoff
|
|
14
|
-
* through the published type. Declaring the port here keeps that one typing gap
|
|
15
|
-
* and its single adaptation at the SDK seam: no other module repeats a cast,
|
|
16
|
-
* the SDK's own parser and retry policy stay untouched, and an injected loader
|
|
17
|
-
* supplies the same port shape.
|
|
18
|
-
*/
|
|
19
|
-
export function opencodeEventPort(event) {
|
|
20
|
-
return {
|
|
21
|
-
subscribe: (request) => {
|
|
22
|
-
const adapted = {
|
|
23
|
-
query: { directory: request.directory },
|
|
24
|
-
signal: request.signal,
|
|
25
|
-
};
|
|
26
|
-
// Runtime-only key omitted from the generated Options type; the installed
|
|
27
|
-
// client forwards it to createSseClient unchanged.
|
|
28
|
-
adapted.sseSleepFn = request.sleep;
|
|
29
|
-
return event.subscribe(adapted);
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
9
|
export function messageId(sequence = 0) {
|
|
34
|
-
const timestamp = BigInt(
|
|
35
|
-
|
|
36
|
-
bytes.writeUIntBE(Number(timestamp & 0xffffffffffffn), 0, 6);
|
|
37
|
-
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
38
|
-
const suffix = [...randomBytes(14)].map((byte) => alphabet[byte % alphabet.length]).join("");
|
|
39
|
-
return `msg_${bytes.toString("hex")}${suffix}`;
|
|
10
|
+
const timestamp = BigInt(Date.now()) * 0x1000n + BigInt(sequence);
|
|
11
|
+
return `msg_${timestamp.toString(16)}${randomBytes(14).toString("hex")}`;
|
|
40
12
|
}
|
|
41
13
|
export function parseModel(model) {
|
|
42
14
|
const slash = model.indexOf("/");
|
|
43
15
|
if (slash <= 0 || slash === model.length - 1)
|
|
44
16
|
throw new Error("OpenCode model must be <provider>/<model>");
|
|
45
|
-
return { providerID: model.slice(0, slash),
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Permission classes whose upstream defaults can await a human reply. A headless
|
|
49
|
-
* server has no reply channel, so such a pending ask never settles.
|
|
50
|
-
*
|
|
51
|
-
* Verified against the installed opencode 1.18.33 agent permission ruleset: the
|
|
52
|
-
* primary agents start from `{"*":"allow"}` with `external_directory` and
|
|
53
|
-
* `doom_loop` set to ask, `read` set to ask for `.env` files, and `question`
|
|
54
|
-
* allowed (the question tool awaits an answer by semantics). Every other class
|
|
55
|
-
* matches the allow-all rule and cannot await.
|
|
56
|
-
*/
|
|
57
|
-
const HEADLESS_PERMISSION_BASE = Object.freeze({
|
|
58
|
-
external_directory: "allow",
|
|
59
|
-
doom_loop: "allow",
|
|
60
|
-
read: "allow",
|
|
61
|
-
question: "deny",
|
|
62
|
-
});
|
|
63
|
-
function isRecord(value) {
|
|
64
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
17
|
+
return { providerID: model.slice(0, slash), id: model.slice(slash + 1) };
|
|
65
18
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
19
|
+
// v2.0.20 Agent.Info.default asks only for external_directory and env reads;
|
|
20
|
+
// question separately requests permission before awaiting its form reply.
|
|
21
|
+
const HEADLESS_PERMISSION_BASE = [
|
|
22
|
+
{ action: "external_directory", resource: "*", effect: "allow" },
|
|
23
|
+
{ action: "read", resource: "*", effect: "allow" },
|
|
24
|
+
{ action: "question", resource: "*", effect: "deny" },
|
|
25
|
+
];
|
|
73
26
|
export function composeHeadlessPermissionConfig(config) {
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
27
|
+
const permissions = config?.permissions;
|
|
28
|
+
if (permissions !== undefined && !Array.isArray(permissions))
|
|
29
|
+
throw new Error("OpenCode v2 permissions must be a ruleset");
|
|
30
|
+
const actions = new Set((permissions ?? []).map((rule) => object(rule)?.action));
|
|
31
|
+
return {
|
|
32
|
+
...config,
|
|
33
|
+
permissions: [...HEADLESS_PERMISSION_BASE.filter((rule) => !actions.has(rule.action)), ...(permissions ?? [])],
|
|
34
|
+
};
|
|
78
35
|
}
|
|
79
|
-
|
|
36
|
+
/** A successful HTML fallback, or a JSON response from another API, is not readiness. */
|
|
37
|
+
export async function waitReady(json, signal) {
|
|
38
|
+
let last;
|
|
80
39
|
for (let attempt = 0; attempt < 100; attempt += 1) {
|
|
81
|
-
|
|
82
|
-
throw new Error("OpenCode startup aborted");
|
|
40
|
+
signal.throwIfAborted();
|
|
83
41
|
try {
|
|
84
|
-
await abortable(
|
|
42
|
+
const info = object(await abortable(json("/api/info"), signal));
|
|
43
|
+
if (typeof info?.version !== "string" ||
|
|
44
|
+
!info.version.startsWith("2.") ||
|
|
45
|
+
typeof info.pid !== "number" ||
|
|
46
|
+
!Array.isArray(info.urls) ||
|
|
47
|
+
typeof object(info.paths)?.tmp !== "string") {
|
|
48
|
+
throw new Error("OpenCode readiness requires native v2 server identity");
|
|
49
|
+
}
|
|
85
50
|
return;
|
|
86
51
|
}
|
|
87
|
-
catch {
|
|
52
|
+
catch (error) {
|
|
53
|
+
last = error;
|
|
54
|
+
signal.throwIfAborted();
|
|
88
55
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
89
56
|
}
|
|
90
57
|
}
|
|
91
|
-
throw new Error(
|
|
58
|
+
throw new Error(`OpenCode server did not become ready within 10000ms: ${String(last)}`);
|
|
92
59
|
}
|
|
93
60
|
async function availablePort() {
|
|
94
61
|
return await new Promise((resolve, reject) => {
|
|
@@ -107,15 +74,17 @@ async function availablePort() {
|
|
|
107
74
|
}
|
|
108
75
|
export async function loadOpencode(input) {
|
|
109
76
|
const { execution, cwd, signal, loader, onRuntime, requests } = input;
|
|
110
|
-
if (loader) {
|
|
111
|
-
const loaded = await abortable(loader(cwd, {
|
|
77
|
+
if (loader !== undefined) {
|
|
78
|
+
const loaded = await abortable(loader(cwd, {
|
|
79
|
+
...execution,
|
|
80
|
+
env: akumaExecutionEnvironment(process.env, execution.env, requests),
|
|
81
|
+
}, signal), signal);
|
|
112
82
|
let closing;
|
|
113
83
|
const runtime = {
|
|
114
84
|
client: loaded.client,
|
|
115
|
-
close:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
},
|
|
85
|
+
close: () => (closing ??= Promise.resolve()
|
|
86
|
+
.then(() => loaded.close?.())
|
|
87
|
+
.then(() => undefined)),
|
|
119
88
|
};
|
|
120
89
|
onRuntime?.(runtime);
|
|
121
90
|
try {
|
|
@@ -130,34 +99,56 @@ export async function loadOpencode(input) {
|
|
|
130
99
|
}
|
|
131
100
|
}
|
|
132
101
|
const port = await availablePort();
|
|
102
|
+
signal.throwIfAborted();
|
|
103
|
+
const password = execution.env?.OPENCODE_PASSWORD ??
|
|
104
|
+
execution.env?.OPENCODE_SERVER_PASSWORD ??
|
|
105
|
+
randomBytes(32).toString("base64url");
|
|
106
|
+
const config = composeHeadlessPermissionConfig(execution.config);
|
|
133
107
|
const owned = await spawnDetachedProcess({
|
|
134
108
|
argv: [execution.executable ?? "opencode", "serve", "--hostname", "127.0.0.1", "--port", String(port)],
|
|
135
109
|
cwd,
|
|
136
110
|
env: akumaExecutionEnvironment(process.env, {
|
|
137
|
-
OPENCODE_CONFIG_CONTENT: JSON.stringify(
|
|
111
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify(config),
|
|
138
112
|
...execution.env,
|
|
113
|
+
OPENCODE_PASSWORD: password,
|
|
114
|
+
OPENCODE_SERVER_PASSWORD: password,
|
|
139
115
|
}, requests),
|
|
140
116
|
log: `${cwd}/.opencode.log`,
|
|
141
117
|
});
|
|
142
|
-
const
|
|
143
|
-
const client = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}`, directory: cwd });
|
|
118
|
+
const native = createNativeClient(`http://127.0.0.1:${port}`, password);
|
|
144
119
|
let closing;
|
|
120
|
+
const options = { signal };
|
|
145
121
|
const runtime = {
|
|
146
|
-
client: {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
122
|
+
client: {
|
|
123
|
+
session: {
|
|
124
|
+
create: async ({ body }) => ({ data: await native.sdk.session.create(body, options) }),
|
|
125
|
+
get: async ({ id }) => ({ data: await native.sdk.session.get({ sessionID: id }, options) }),
|
|
126
|
+
switchModel: ({ id, model }) => native.sdk.session.switchModel({ sessionID: id, model }, options),
|
|
127
|
+
instructions: ({ id, text }) => native.sdk.session.instructions.entry.put({ sessionID: id, key: "keiyaku.system", value: text }, options),
|
|
128
|
+
active: async () => ({ data: await native.sdk.session.active(options) }),
|
|
129
|
+
fork: async ({ id, before }) => ({ data: await native.sdk.session.fork({ sessionID: id, before }, options) }),
|
|
130
|
+
interrupt: ({ id }) => native.sdk.session.interrupt({ sessionID: id, resume: false }),
|
|
131
|
+
prompt: async ({ id, body }) => ({
|
|
132
|
+
data: await native.sdk.session.prompt({ sessionID: id, ...body }, options),
|
|
133
|
+
}),
|
|
134
|
+
message: async ({ id, messageID }) => ({
|
|
135
|
+
data: await native.sdk.session.message.get({ sessionID: id, messageID }, options),
|
|
136
|
+
}),
|
|
137
|
+
},
|
|
138
|
+
event: { subscribe: ({ signal }) => native.subscribe(signal) },
|
|
150
139
|
},
|
|
140
|
+
close: () => (closing ??= Promise.all([native.close(), owned.terminate()]).then(() => undefined)),
|
|
151
141
|
};
|
|
152
142
|
onRuntime?.(runtime);
|
|
153
143
|
try {
|
|
154
|
-
await waitReady(
|
|
144
|
+
await waitReady(() => native.sdk.server.info({ signal }), signal);
|
|
145
|
+
signal.throwIfAborted();
|
|
146
|
+
return runtime;
|
|
155
147
|
}
|
|
156
148
|
catch (error) {
|
|
157
149
|
await runtime.close();
|
|
158
150
|
throw error;
|
|
159
151
|
}
|
|
160
|
-
return runtime;
|
|
161
152
|
}
|
|
162
153
|
export function coordinate(sessionId) {
|
|
163
154
|
return { sessionId };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentStreamEventPayload } from "@getpaseo/protocol/messages";
|
|
2
|
+
import type { AgentRuntimeInfo } from "@getpaseo/protocol/agent-types";
|
|
3
|
+
import { AgentEventChannel, type TurnResult } from "../../provider.js";
|
|
4
|
+
/**
|
|
5
|
+
* The runtime's own confirmation at establishment, reported as a native
|
|
6
|
+
* provider model id. The installed Paseo wire carries no mid-attempt model
|
|
7
|
+
* change on this timeline subscription, so a later re-selection is not
|
|
8
|
+
* observable here and is never invented.
|
|
9
|
+
*/
|
|
10
|
+
export declare function paseoRuntimeModel(info: AgentRuntimeInfo | undefined): string | undefined;
|
|
11
|
+
/** Live fragments belong to a canonical admitted turn, not agent-wide status. */
|
|
12
|
+
export declare class PaseoTurn {
|
|
13
|
+
readonly messageId: string;
|
|
14
|
+
readonly events: AgentEventChannel;
|
|
15
|
+
readonly admission: Promise<string>;
|
|
16
|
+
readonly completion: Promise<TurnResult>;
|
|
17
|
+
private admit;
|
|
18
|
+
private rejectAdmission;
|
|
19
|
+
private finish;
|
|
20
|
+
private rejectCompletion;
|
|
21
|
+
private turnId;
|
|
22
|
+
private readonly messages;
|
|
23
|
+
private readonly messagesById;
|
|
24
|
+
private readonly calls;
|
|
25
|
+
private answer;
|
|
26
|
+
private assistantContiguous;
|
|
27
|
+
settled: boolean;
|
|
28
|
+
terminal: boolean;
|
|
29
|
+
constructor(messageId: string);
|
|
30
|
+
receive(event: AgentStreamEventPayload): void;
|
|
31
|
+
private appendAssistant;
|
|
32
|
+
fail(error: unknown): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { AgentEventChannel, otherToolCall } from "../../provider.js";
|
|
2
|
+
import { stringValue } from "../decode.js";
|
|
3
|
+
/**
|
|
4
|
+
* The runtime's own confirmation at establishment, reported as a native
|
|
5
|
+
* provider model id. The installed Paseo wire carries no mid-attempt model
|
|
6
|
+
* change on this timeline subscription, so a later re-selection is not
|
|
7
|
+
* observable here and is never invented.
|
|
8
|
+
*/
|
|
9
|
+
export function paseoRuntimeModel(info) {
|
|
10
|
+
const model = info?.model;
|
|
11
|
+
return typeof model === "string" && model.trim().length > 0 ? model : undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The observed result text one native detail carries. A detail that observes no
|
|
15
|
+
* text stays absent; a present empty string remains observed and empty.
|
|
16
|
+
*/
|
|
17
|
+
function detailOutput(detail) {
|
|
18
|
+
switch (detail.type) {
|
|
19
|
+
case "shell":
|
|
20
|
+
return stringValue(detail.output);
|
|
21
|
+
case "read":
|
|
22
|
+
case "search":
|
|
23
|
+
return stringValue(detail.content);
|
|
24
|
+
case "fetch":
|
|
25
|
+
return stringValue(detail.result);
|
|
26
|
+
default:
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** The verified unified patch a completed edit detail observed, when it supplied one. */
|
|
31
|
+
function detailPatch(detail) {
|
|
32
|
+
return detail.type === "edit" ? stringValue(detail.unifiedDiff) : undefined;
|
|
33
|
+
}
|
|
34
|
+
/** Attach the observed patch to the one change its correlated path already named. */
|
|
35
|
+
function withObservedPatch(call, patch) {
|
|
36
|
+
if (call.kind !== "fileChange")
|
|
37
|
+
return call;
|
|
38
|
+
const change = call.changes[0];
|
|
39
|
+
if (patch === undefined || change === undefined || call.changes.length !== 1)
|
|
40
|
+
return call;
|
|
41
|
+
return { kind: "fileChange", changes: [{ ...change, patch }] };
|
|
42
|
+
}
|
|
43
|
+
function toolCall(item) {
|
|
44
|
+
const detail = item.detail;
|
|
45
|
+
switch (detail.type) {
|
|
46
|
+
case "shell":
|
|
47
|
+
return { kind: "run", command: detail.command };
|
|
48
|
+
case "read":
|
|
49
|
+
return {
|
|
50
|
+
kind: "read",
|
|
51
|
+
path: detail.filePath,
|
|
52
|
+
...(detail.offset === undefined ? {} : { offset: detail.offset }),
|
|
53
|
+
...(detail.limit === undefined ? {} : { limit: detail.limit }),
|
|
54
|
+
};
|
|
55
|
+
case "edit":
|
|
56
|
+
case "write":
|
|
57
|
+
return { kind: "fileChange", changes: [{ op: "unspecified", path: detail.filePath }] };
|
|
58
|
+
case "search":
|
|
59
|
+
return { kind: "search", query: detail.query, scope: detail.toolName === "web_search" ? "web" : "content" };
|
|
60
|
+
case "unknown":
|
|
61
|
+
return otherToolCall(item.name, detail.input);
|
|
62
|
+
default:
|
|
63
|
+
return otherToolCall(item.name);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function timelineNarration(item, calls) {
|
|
67
|
+
switch (item.type) {
|
|
68
|
+
case "tool_call": {
|
|
69
|
+
const base = calls.get(item.callId) ?? (item.status === "running" ? toolCall(item) : otherToolCall(item.name));
|
|
70
|
+
const call = item.status === "running" ? base : withObservedPatch(base, detailPatch(item.detail));
|
|
71
|
+
calls.set(item.callId, call);
|
|
72
|
+
if (item.status === "running") {
|
|
73
|
+
return { type: "tool", phase: "started", id: item.callId, name: item.name, call };
|
|
74
|
+
}
|
|
75
|
+
const output = detailOutput(item.detail);
|
|
76
|
+
return {
|
|
77
|
+
type: "tool",
|
|
78
|
+
phase: "completed",
|
|
79
|
+
id: item.callId,
|
|
80
|
+
name: item.name,
|
|
81
|
+
call,
|
|
82
|
+
result: {
|
|
83
|
+
status: item.status === "completed" ? "ok" : "error",
|
|
84
|
+
...(output === undefined ? {} : { output }),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
case "error":
|
|
89
|
+
case "notification":
|
|
90
|
+
return { type: "note", text: item.message };
|
|
91
|
+
case "compaction":
|
|
92
|
+
return { type: "note", text: `Context compaction ${item.status}` };
|
|
93
|
+
case "reasoning":
|
|
94
|
+
case "user_message":
|
|
95
|
+
case "assistant_message":
|
|
96
|
+
return undefined;
|
|
97
|
+
default:
|
|
98
|
+
return { type: "unknown", kind: item.type };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Live fragments belong to a canonical admitted turn, not agent-wide status. */
|
|
102
|
+
export class PaseoTurn {
|
|
103
|
+
messageId;
|
|
104
|
+
events = new AgentEventChannel();
|
|
105
|
+
admission;
|
|
106
|
+
completion;
|
|
107
|
+
admit;
|
|
108
|
+
rejectAdmission;
|
|
109
|
+
finish;
|
|
110
|
+
rejectCompletion;
|
|
111
|
+
turnId;
|
|
112
|
+
messages = [];
|
|
113
|
+
messagesById = new Map();
|
|
114
|
+
calls = new Map();
|
|
115
|
+
answer = "";
|
|
116
|
+
assistantContiguous = false;
|
|
117
|
+
settled = false;
|
|
118
|
+
terminal = false;
|
|
119
|
+
constructor(messageId) {
|
|
120
|
+
this.messageId = messageId;
|
|
121
|
+
this.admission = new Promise((resolve, reject) => {
|
|
122
|
+
this.admit = resolve;
|
|
123
|
+
this.rejectAdmission = reject;
|
|
124
|
+
});
|
|
125
|
+
this.completion = new Promise((resolve, reject) => {
|
|
126
|
+
this.finish = resolve;
|
|
127
|
+
this.rejectCompletion = reject;
|
|
128
|
+
});
|
|
129
|
+
void this.admission.catch(() => undefined);
|
|
130
|
+
void this.completion.catch(() => undefined);
|
|
131
|
+
}
|
|
132
|
+
receive(event) {
|
|
133
|
+
if (this.settled)
|
|
134
|
+
return;
|
|
135
|
+
if (event.type === "timeline" &&
|
|
136
|
+
event.item.type === "user_message" &&
|
|
137
|
+
event.item.clientMessageId === this.messageId) {
|
|
138
|
+
if (event.turnId === undefined)
|
|
139
|
+
return this.fail(new Error("Paseo native admission omitted turnId"));
|
|
140
|
+
if (this.turnId !== undefined) {
|
|
141
|
+
if (this.turnId !== event.turnId)
|
|
142
|
+
this.fail(new Error("Paseo canonical admission changed native turn"));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this.turnId = event.turnId;
|
|
146
|
+
this.admit(event.turnId);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!("turnId" in event) || this.turnId === undefined || event.turnId !== this.turnId)
|
|
150
|
+
return;
|
|
151
|
+
if (event.type === "timeline") {
|
|
152
|
+
if (event.item.type === "assistant_message")
|
|
153
|
+
this.appendAssistant(event.item);
|
|
154
|
+
else {
|
|
155
|
+
this.assistantContiguous = false;
|
|
156
|
+
const narration = timelineNarration(event.item, this.calls);
|
|
157
|
+
if (narration !== undefined)
|
|
158
|
+
this.events.emit(narration);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (event.type === "turn_completed") {
|
|
162
|
+
this.settled = true;
|
|
163
|
+
this.finish({
|
|
164
|
+
kind: "answered",
|
|
165
|
+
answer: this.answer,
|
|
166
|
+
historyId: this.turnId,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
else if (event.type === "turn_failed" || event.type === "turn_canceled") {
|
|
170
|
+
this.settled = true;
|
|
171
|
+
this.finish({ kind: "failed", diagnostic: event.type === "turn_failed" ? event.error : event.reason });
|
|
172
|
+
}
|
|
173
|
+
if (this.settled) {
|
|
174
|
+
this.terminal = true;
|
|
175
|
+
for (const message of this.messages)
|
|
176
|
+
this.events.emit({ type: "assistant", text: message.text });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
appendAssistant(item) {
|
|
180
|
+
// Native final text is the last contiguous assistant segment; narration keeps all messages.
|
|
181
|
+
this.answer = this.assistantContiguous ? this.answer + item.text : item.text;
|
|
182
|
+
const previous = item.messageId === undefined
|
|
183
|
+
? this.assistantContiguous
|
|
184
|
+
? this.messages.at(-1)
|
|
185
|
+
: undefined
|
|
186
|
+
: this.messagesById.get(item.messageId);
|
|
187
|
+
this.assistantContiguous = true;
|
|
188
|
+
if (previous !== undefined)
|
|
189
|
+
previous.text += item.text;
|
|
190
|
+
else {
|
|
191
|
+
const message = { ...(item.messageId === undefined ? {} : { id: item.messageId }), text: item.text };
|
|
192
|
+
this.messages.push(message);
|
|
193
|
+
if (item.messageId !== undefined)
|
|
194
|
+
this.messagesById.set(item.messageId, message);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
fail(error) {
|
|
198
|
+
if (this.settled)
|
|
199
|
+
return;
|
|
200
|
+
this.settled = true;
|
|
201
|
+
this.rejectAdmission(error);
|
|
202
|
+
this.rejectCompletion(error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DaemonClient, type DaemonClientConfig } from "@getpaseo/client/internal/daemon-client";
|
|
2
|
+
import { type ProviderAdapter } from "../../provider.js";
|
|
3
|
+
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
4
|
+
type PaseoClient = Pick<DaemonClient, "connect" | "close" | "createAgent" | "fetchAgent" | "setAgentModel" | "listProviderModels" | "setAgentThinkingOption" | "sendMessage" | "cancelAgent" | "subscribeAgentTimeline" | "subscribeConnectionStatus">;
|
|
5
|
+
export type PaseoDependencies = Readonly<{
|
|
6
|
+
createClient?(config: DaemonClientConfig): PaseoClient;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function createPaseoProvider(execution: ProviderExecution, dependencies?: PaseoDependencies): ProviderAdapter;
|
|
9
|
+
export {};
|