@esso0428/pi-subagents 0.17.16 → 0.17.17
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/CHANGELOG.md +6 -0
- package/ROADMAP.md +87 -0
- package/docs/post-0.17.6-agents-roster-viewer-spec.md +42 -0
- package/docs/post-0.17.6-durable-history-spec.md +41 -0
- package/docs/post-0.17.6-feature-specs.md +50 -0
- package/docs/post-0.17.6-nested-agents-spec.md +38 -0
- package/docs/post-0.17.6-recovery-shutdown-spec.md +46 -0
- package/docs/post-0.17.6-ui-latency-baseline-spec.md +46 -0
- package/docs/post-0.17.6-workflow-rpc-lifecycle-spec.md +54 -0
- package/package.json +1 -1
- package/src/agent-history.ts +2 -54
- package/src/agent-manager.ts +406 -1288
- package/src/agent-runner.ts +27 -251
- package/src/agent-types.ts +32 -188
- package/src/cross-extension-rpc.ts +20 -96
- package/src/custom-agents.ts +13 -170
- package/src/index.ts +480 -1920
- package/src/invocation-config.ts +3 -118
- package/src/model-resolver.ts +0 -18
- package/src/output-file.ts +6 -61
- package/src/prompts.ts +2 -45
- package/src/schedule.ts +14 -35
- package/src/settings.ts +2 -301
- package/src/status-note.ts +1 -66
- package/src/types.ts +10 -177
- package/src/ui/agent-widget.ts +57 -278
- package/src/ui/conversation-blocks.ts +0 -6
- package/src/ui/conversation-timeline.ts +25 -139
- package/src/ui/conversation-viewer.ts +48 -212
- package/src/ui/schedule-menu.ts +8 -9
- package/src/usage.ts +2 -109
- package/src/worktree.ts +55 -69
- package/dist/abortable.d.ts +0 -13
- package/dist/abortable.d.ts.map +0 -1
- package/dist/abortable.js +0 -43
- package/dist/abortable.js.map +0 -1
- package/dist/agent-color.d.ts +0 -36
- package/dist/agent-color.d.ts.map +0 -1
- package/dist/agent-color.js +0 -124
- package/dist/agent-color.js.map +0 -1
- package/dist/agent-file-toggle.d.ts +0 -126
- package/dist/agent-file-toggle.d.ts.map +0 -1
- package/dist/agent-file-toggle.js +0 -259
- package/dist/agent-file-toggle.js.map +0 -1
- package/dist/agent-history-list.d.ts +0 -19
- package/dist/agent-history-list.d.ts.map +0 -1
- package/dist/agent-history-list.js +0 -69
- package/dist/agent-history-list.js.map +0 -1
- package/dist/agent-history.d.ts +0 -35
- package/dist/agent-history.d.ts.map +0 -1
- package/dist/agent-history.js +0 -188
- package/dist/agent-history.js.map +0 -1
- package/dist/agent-manager.d.ts +0 -503
- package/dist/agent-manager.d.ts.map +0 -1
- package/dist/agent-manager.js +0 -1572
- package/dist/agent-manager.js.map +0 -1
- package/dist/agent-recovery.d.ts +0 -37
- package/dist/agent-recovery.d.ts.map +0 -1
- package/dist/agent-recovery.js +0 -171
- package/dist/agent-recovery.js.map +0 -1
- package/dist/agent-runner.d.ts +0 -303
- package/dist/agent-runner.d.ts.map +0 -1
- package/dist/agent-runner.js +0 -1003
- package/dist/agent-runner.js.map +0 -1
- package/dist/agent-types.d.ts +0 -120
- package/dist/agent-types.d.ts.map +0 -1
- package/dist/agent-types.js +0 -301
- package/dist/agent-types.js.map +0 -1
- package/dist/child-context.d.ts +0 -3
- package/dist/child-context.d.ts.map +0 -1
- package/dist/child-context.js +0 -13
- package/dist/child-context.js.map +0 -1
- package/dist/context.d.ts +0 -13
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -57
- package/dist/context.js.map +0 -1
- package/dist/cross-extension-rpc.d.ts +0 -67
- package/dist/cross-extension-rpc.d.ts.map +0 -1
- package/dist/cross-extension-rpc.js +0 -139
- package/dist/cross-extension-rpc.js.map +0 -1
- package/dist/custom-agents.d.ts +0 -55
- package/dist/custom-agents.d.ts.map +0 -1
- package/dist/custom-agents.js +0 -309
- package/dist/custom-agents.js.map +0 -1
- package/dist/default-agents.d.ts +0 -8
- package/dist/default-agents.d.ts.map +0 -1
- package/dist/default-agents.js +0 -123
- package/dist/default-agents.js.map +0 -1
- package/dist/enabled-models.d.ts +0 -50
- package/dist/enabled-models.d.ts.map +0 -1
- package/dist/enabled-models.js +0 -146
- package/dist/enabled-models.js.map +0 -1
- package/dist/env.d.ts +0 -7
- package/dist/env.d.ts.map +0 -1
- package/dist/env.js +0 -29
- package/dist/env.js.map +0 -1
- package/dist/group-join.d.ts +0 -33
- package/dist/group-join.d.ts.map +0 -1
- package/dist/group-join.js +0 -117
- package/dist/group-join.js.map +0 -1
- package/dist/index.d.ts +0 -51
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -3687
- package/dist/index.js.map +0 -1
- package/dist/invocation-config.d.ts +0 -108
- package/dist/invocation-config.d.ts.map +0 -1
- package/dist/invocation-config.js +0 -84
- package/dist/invocation-config.js.map +0 -1
- package/dist/memory.d.ts +0 -54
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js +0 -166
- package/dist/memory.js.map +0 -1
- package/dist/mention-clone.d.ts +0 -88
- package/dist/mention-clone.d.ts.map +0 -1
- package/dist/mention-clone.js +0 -154
- package/dist/mention-clone.js.map +0 -1
- package/dist/mention.d.ts +0 -82
- package/dist/mention.d.ts.map +0 -1
- package/dist/mention.js +0 -132
- package/dist/mention.js.map +0 -1
- package/dist/model-resolver.d.ts +0 -37
- package/dist/model-resolver.d.ts.map +0 -1
- package/dist/model-resolver.js +0 -96
- package/dist/model-resolver.js.map +0 -1
- package/dist/model-scope.d.ts +0 -50
- package/dist/model-scope.d.ts.map +0 -1
- package/dist/model-scope.js +0 -49
- package/dist/model-scope.js.map +0 -1
- package/dist/nested-tools.d.ts +0 -57
- package/dist/nested-tools.d.ts.map +0 -1
- package/dist/nested-tools.js +0 -301
- package/dist/nested-tools.js.map +0 -1
- package/dist/nico-overrides.d.ts +0 -54
- package/dist/nico-overrides.d.ts.map +0 -1
- package/dist/nico-overrides.js +0 -170
- package/dist/nico-overrides.js.map +0 -1
- package/dist/output-file.d.ts +0 -44
- package/dist/output-file.d.ts.map +0 -1
- package/dist/output-file.js +0 -156
- package/dist/output-file.js.map +0 -1
- package/dist/prompts.d.ts +0 -56
- package/dist/prompts.d.ts.map +0 -1
- package/dist/prompts.js +0 -92
- package/dist/prompts.js.map +0 -1
- package/dist/schedule-store.d.ts +0 -39
- package/dist/schedule-store.d.ts.map +0 -1
- package/dist/schedule-store.js +0 -156
- package/dist/schedule-store.js.map +0 -1
- package/dist/schedule.d.ts +0 -110
- package/dist/schedule.d.ts.map +0 -1
- package/dist/schedule.js +0 -360
- package/dist/schedule.js.map +0 -1
- package/dist/settings.d.ts +0 -354
- package/dist/settings.d.ts.map +0 -1
- package/dist/settings.js +0 -247
- package/dist/settings.js.map +0 -1
- package/dist/skill-loader.d.ts +0 -25
- package/dist/skill-loader.d.ts.map +0 -1
- package/dist/skill-loader.js +0 -94
- package/dist/skill-loader.js.map +0 -1
- package/dist/status-note.d.ts +0 -62
- package/dist/status-note.d.ts.map +0 -1
- package/dist/status-note.js +0 -86
- package/dist/status-note.js.map +0 -1
- package/dist/structured-output.d.ts +0 -62
- package/dist/structured-output.d.ts.map +0 -1
- package/dist/structured-output.js +0 -113
- package/dist/structured-output.js.map +0 -1
- package/dist/types.d.ts +0 -372
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
- package/dist/ui/agent-mention.d.ts +0 -83
- package/dist/ui/agent-mention.d.ts.map +0 -1
- package/dist/ui/agent-mention.js +0 -188
- package/dist/ui/agent-mention.js.map +0 -1
- package/dist/ui/agent-widget.d.ts +0 -241
- package/dist/ui/agent-widget.d.ts.map +0 -1
- package/dist/ui/agent-widget.js +0 -992
- package/dist/ui/agent-widget.js.map +0 -1
- package/dist/ui/ccstyle/diff/ansi-utils.d.ts +0 -11
- package/dist/ui/ccstyle/diff/ansi-utils.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/ansi-utils.js +0 -145
- package/dist/ui/ccstyle/diff/ansi-utils.js.map +0 -1
- package/dist/ui/ccstyle/diff/diff-presentation.d.ts +0 -12
- package/dist/ui/ccstyle/diff/diff-presentation.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/diff-presentation.js +0 -48
- package/dist/ui/ccstyle/diff/diff-presentation.js.map +0 -1
- package/dist/ui/ccstyle/diff/diff-renderer.d.ts +0 -46
- package/dist/ui/ccstyle/diff/diff-renderer.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/diff-renderer.js +0 -2049
- package/dist/ui/ccstyle/diff/diff-renderer.js.map +0 -1
- package/dist/ui/ccstyle/diff/line-width-safety.d.ts +0 -12
- package/dist/ui/ccstyle/diff/line-width-safety.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/line-width-safety.js +0 -58
- package/dist/ui/ccstyle/diff/line-width-safety.js.map +0 -1
- package/dist/ui/ccstyle/diff/render-utils.d.ts +0 -6
- package/dist/ui/ccstyle/diff/render-utils.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/render-utils.js +0 -25
- package/dist/ui/ccstyle/diff/render-utils.js.map +0 -1
- package/dist/ui/ccstyle/diff/shiki-highlight.d.ts +0 -19
- package/dist/ui/ccstyle/diff/shiki-highlight.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/shiki-highlight.js +0 -85
- package/dist/ui/ccstyle/diff/shiki-highlight.js.map +0 -1
- package/dist/ui/ccstyle/diff/types.d.ts +0 -22
- package/dist/ui/ccstyle/diff/types.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/types.js +0 -10
- package/dist/ui/ccstyle/diff/types.js.map +0 -1
- package/dist/ui/ccstyle/diff/write-display-utils.d.ts +0 -2
- package/dist/ui/ccstyle/diff/write-display-utils.d.ts.map +0 -1
- package/dist/ui/ccstyle/diff/write-display-utils.js +0 -12
- package/dist/ui/ccstyle/diff/write-display-utils.js.map +0 -1
- package/dist/ui/ccstyle/tool-renderer.d.ts +0 -17
- package/dist/ui/ccstyle/tool-renderer.d.ts.map +0 -1
- package/dist/ui/ccstyle/tool-renderer.js +0 -74
- package/dist/ui/ccstyle/tool-renderer.js.map +0 -1
- package/dist/ui/ccstyle/tool-result.d.ts +0 -44
- package/dist/ui/ccstyle/tool-result.d.ts.map +0 -1
- package/dist/ui/ccstyle/tool-result.js +0 -423
- package/dist/ui/ccstyle/tool-result.js.map +0 -1
- package/dist/ui/conversation-blocks.d.ts +0 -46
- package/dist/ui/conversation-blocks.d.ts.map +0 -1
- package/dist/ui/conversation-blocks.js +0 -313
- package/dist/ui/conversation-blocks.js.map +0 -1
- package/dist/ui/conversation-nvim.d.ts +0 -8
- package/dist/ui/conversation-nvim.d.ts.map +0 -1
- package/dist/ui/conversation-nvim.js +0 -117
- package/dist/ui/conversation-nvim.js.map +0 -1
- package/dist/ui/conversation-role.d.ts +0 -13
- package/dist/ui/conversation-role.d.ts.map +0 -1
- package/dist/ui/conversation-role.js +0 -39
- package/dist/ui/conversation-role.js.map +0 -1
- package/dist/ui/conversation-search.d.ts +0 -39
- package/dist/ui/conversation-search.d.ts.map +0 -1
- package/dist/ui/conversation-search.js +0 -124
- package/dist/ui/conversation-search.js.map +0 -1
- package/dist/ui/conversation-timeline.d.ts +0 -102
- package/dist/ui/conversation-timeline.d.ts.map +0 -1
- package/dist/ui/conversation-timeline.js +0 -555
- package/dist/ui/conversation-timeline.js.map +0 -1
- package/dist/ui/conversation-viewer.d.ts +0 -138
- package/dist/ui/conversation-viewer.d.ts.map +0 -1
- package/dist/ui/conversation-viewer.js +0 -1175
- package/dist/ui/conversation-viewer.js.map +0 -1
- package/dist/ui/schedule-menu.d.ts +0 -17
- package/dist/ui/schedule-menu.d.ts.map +0 -1
- package/dist/ui/schedule-menu.js +0 -95
- package/dist/ui/schedule-menu.js.map +0 -1
- package/dist/ui/select-item.d.ts +0 -28
- package/dist/ui/select-item.d.ts.map +0 -1
- package/dist/ui/select-item.js +0 -35
- package/dist/ui/select-item.js.map +0 -1
- package/dist/ui/viewer-keys.d.ts +0 -21
- package/dist/ui/viewer-keys.d.ts.map +0 -1
- package/dist/ui/viewer-keys.js +0 -18
- package/dist/ui/viewer-keys.js.map +0 -1
- package/dist/ui/workflow-card.d.ts +0 -176
- package/dist/ui/workflow-card.d.ts.map +0 -1
- package/dist/ui/workflow-card.js +0 -333
- package/dist/ui/workflow-card.js.map +0 -1
- package/dist/ui/workflow-dialog.d.ts +0 -306
- package/dist/ui/workflow-dialog.d.ts.map +0 -1
- package/dist/ui/workflow-dialog.js +0 -844
- package/dist/ui/workflow-dialog.js.map +0 -1
- package/dist/ui/workflow-menu.d.ts +0 -42
- package/dist/ui/workflow-menu.d.ts.map +0 -1
- package/dist/ui/workflow-menu.js +0 -127
- package/dist/ui/workflow-menu.js.map +0 -1
- package/dist/usage.d.ts +0 -136
- package/dist/usage.d.ts.map +0 -1
- package/dist/usage.js +0 -121
- package/dist/usage.js.map +0 -1
- package/dist/workflow/collisions.d.ts +0 -96
- package/dist/workflow/collisions.d.ts.map +0 -1
- package/dist/workflow/collisions.js +0 -89
- package/dist/workflow/collisions.js.map +0 -1
- package/dist/workflow/entry.d.ts +0 -33
- package/dist/workflow/entry.d.ts.map +0 -1
- package/dist/workflow/entry.js +0 -30
- package/dist/workflow/entry.js.map +0 -1
- package/dist/workflow/host.d.ts +0 -63
- package/dist/workflow/host.d.ts.map +0 -1
- package/dist/workflow/host.js +0 -363
- package/dist/workflow/host.js.map +0 -1
- package/dist/workflow/journal.d.ts +0 -98
- package/dist/workflow/journal.d.ts.map +0 -1
- package/dist/workflow/journal.js +0 -121
- package/dist/workflow/journal.js.map +0 -1
- package/dist/workflow/json-schema.d.ts +0 -52
- package/dist/workflow/json-schema.d.ts.map +0 -1
- package/dist/workflow/json-schema.js +0 -112
- package/dist/workflow/json-schema.js.map +0 -1
- package/dist/workflow/meta.d.ts +0 -68
- package/dist/workflow/meta.d.ts.map +0 -1
- package/dist/workflow/meta.js +0 -318
- package/dist/workflow/meta.js.map +0 -1
- package/dist/workflow/progress.d.ts +0 -225
- package/dist/workflow/progress.d.ts.map +0 -1
- package/dist/workflow/progress.js +0 -362
- package/dist/workflow/progress.js.map +0 -1
- package/dist/workflow/runtime.d.ts +0 -335
- package/dist/workflow/runtime.d.ts.map +0 -1
- package/dist/workflow/runtime.js +0 -831
- package/dist/workflow/runtime.js.map +0 -1
- package/dist/workflow/saved.d.ts +0 -91
- package/dist/workflow/saved.d.ts.map +0 -1
- package/dist/workflow/saved.js +0 -204
- package/dist/workflow/saved.js.map +0 -1
- package/dist/workflow/task.d.ts +0 -137
- package/dist/workflow/task.d.ts.map +0 -1
- package/dist/workflow/task.js +0 -208
- package/dist/workflow/task.js.map +0 -1
- package/dist/workflow/tool-description.d.ts +0 -39
- package/dist/workflow/tool-description.d.ts.map +0 -1
- package/dist/workflow/tool-description.js +0 -200
- package/dist/workflow/tool-description.js.map +0 -1
- package/dist/workflow/worker-source.d.ts +0 -48
- package/dist/workflow/worker-source.d.ts.map +0 -1
- package/dist/workflow/worker-source.js +0 -779
- package/dist/workflow/worker-source.js.map +0 -1
- package/dist/worktree.d.ts +0 -53
- package/dist/worktree.d.ts.map +0 -1
- package/dist/worktree.js +0 -165
- package/dist/worktree.js.map +0 -1
- package/dist/write-execution.d.ts +0 -42
- package/dist/write-execution.d.ts.map +0 -1
- package/dist/write-execution.js +0 -138
- package/dist/write-execution.js.map +0 -1
- package/dist/xml.d.ts +0 -11
- package/dist/xml.d.ts.map +0 -1
- package/dist/xml.js +0 -13
- package/dist/xml.js.map +0 -1
- package/src/abortable.ts +0 -43
- package/src/agent-color.ts +0 -161
- package/src/agent-file-toggle.ts +0 -269
- package/src/child-context.ts +0 -15
- package/src/mention-clone.ts +0 -196
- package/src/mention.ts +0 -141
- package/src/model-scope.ts +0 -70
- package/src/nested-tools.ts +0 -424
- package/src/structured-output.ts +0 -130
- package/src/ui/agent-mention.ts +0 -216
- package/src/ui/select-item.ts +0 -45
- package/src/ui/workflow-card.ts +0 -470
- package/src/ui/workflow-dialog.ts +0 -1115
- package/src/ui/workflow-menu.ts +0 -166
- package/src/workflow/collisions.ts +0 -123
- package/src/workflow/entry.ts +0 -47
- package/src/workflow/host.ts +0 -403
- package/src/workflow/journal.ts +0 -164
- package/src/workflow/json-schema.ts +0 -128
- package/src/workflow/meta.ts +0 -325
- package/src/workflow/progress.ts +0 -550
- package/src/workflow/runtime.ts +0 -1219
- package/src/workflow/saved.ts +0 -217
- package/src/workflow/task.ts +0 -302
- package/src/workflow/tool-description.ts +0 -200
- package/src/workflow/worker-source.ts +0 -781
- package/src/xml.ts +0 -13
package/src/invocation-config.ts
CHANGED
|
@@ -1,59 +1,5 @@
|
|
|
1
|
-
import { Type } from "@sinclair/typebox";
|
|
2
1
|
import type { AgentConfig, IsolationMode, JoinMode, ThinkingLevel } from "./types.js";
|
|
3
2
|
|
|
4
|
-
/**
|
|
5
|
-
* The model-facing `isolation` parameter, shared by the `Agent` tool and the
|
|
6
|
-
* nested delegation tool so the two cannot drift.
|
|
7
|
-
*
|
|
8
|
-
* Shape matters more than wording here. As a single-value optional literal,
|
|
9
|
-
* models that fill every optional parameter — the transcript on #231 shows one
|
|
10
|
-
* emitting `resume: ""`, `schedule: ""` and `model: "default"` alongside it —
|
|
11
|
-
* had only `"worktree"` available to fill it with, and kept spawning worktrees
|
|
12
|
-
* across three turns while their own reasoning said to omit the field. Every
|
|
13
|
-
* other optional parameter has an inert filler; this one did not. `"off"` is
|
|
14
|
-
* listed first and described as the default so the harmless value is the
|
|
15
|
-
* obvious one to reach for.
|
|
16
|
-
*
|
|
17
|
-
* The wording tracks Claude Code's own `isolation` parameter, whose phrasing
|
|
18
|
-
* models have the most exposure to: one description on the union rather than
|
|
19
|
-
* per-value ones, opening "Isolation mode.", then a sentence per value in
|
|
20
|
-
* schema order, each with its caveats in a trailing parenthetical. Two clauses
|
|
21
|
-
* are ours, because our shape is not theirs — `"off"` has no counterpart there
|
|
22
|
-
* (their enum is `worktree | remote`, so both of their values do something),
|
|
23
|
-
* and neither does the uncommitted-work warning, which is the specific trap
|
|
24
|
-
* #231 fell into. Deliberately absent is any "only use a worktree when…"
|
|
25
|
-
* restriction: Claude Code's `Agent` tool states the capability and stops, and
|
|
26
|
-
* a second legal value is what lets a model decline one, not being told to.
|
|
27
|
-
*/
|
|
28
|
-
const isolationParamShape = {
|
|
29
|
-
isolation: Type.Optional(
|
|
30
|
-
Type.Union([Type.Literal("off"), Type.Literal("worktree")], {
|
|
31
|
-
description:
|
|
32
|
-
'Isolation mode. Default "off". "off" runs the agent in the current checkout, the same as omitting the field. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo (a copy cannot see uncommitted or staged changes in the main checkout).',
|
|
33
|
-
}),
|
|
34
|
-
),
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Build the `isolation` parameter for a tool schema, or nothing when the
|
|
39
|
-
* project disabled worktrees (`worktreeIsolation: false`).
|
|
40
|
-
*
|
|
41
|
-
* Dropping the field beats accepting it and quietly downgrading. The setting is
|
|
42
|
-
* for a project whose model passes `"worktree"` on *every* call, so a
|
|
43
|
-
* per-result "isolation was disabled" note would be noise on every result and
|
|
44
|
-
* would keep raising the salience of a capability that isn't there. With no
|
|
45
|
-
* field there is nothing to pass, nothing to drop, and nothing to explain — the
|
|
46
|
-
* same trade `scheduleParam` makes for disabled scheduling, at zero LLM-context
|
|
47
|
-
* cost. The resolver gate and the `agent-manager` check still cover the paths a
|
|
48
|
-
* schema can't reach: agent files, the scheduler, and cross-extension RPC.
|
|
49
|
-
*
|
|
50
|
-
* Like `scheduleParam`, this is read once at tool registration — flipping the
|
|
51
|
-
* setting needs a new pi session for the schema to change.
|
|
52
|
-
*/
|
|
53
|
-
export function isolationParam(enabled: boolean): Partial<typeof isolationParamShape> {
|
|
54
|
-
return enabled ? isolationParamShape : {};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
3
|
interface AgentInvocationParams {
|
|
58
4
|
model?: string;
|
|
59
5
|
thinking?: string;
|
|
@@ -61,42 +7,12 @@ interface AgentInvocationParams {
|
|
|
61
7
|
run_in_background?: boolean;
|
|
62
8
|
inherit_context?: boolean;
|
|
63
9
|
isolated?: boolean;
|
|
64
|
-
|
|
65
|
-
* Untyped on purpose. Both tool schemas now build this field conditionally
|
|
66
|
-
* and spread it, which erases TypeBox's literal inference to `unknown` (the
|
|
67
|
-
* `schedule` param has the same shape). The resolver below narrows by
|
|
68
|
-
* comparison rather than trusting the declaration, which also makes it safe
|
|
69
|
-
* for the cross-extension RPC path, where options arrive unvalidated.
|
|
70
|
-
*/
|
|
71
|
-
isolation?: unknown;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface ResolveOptions {
|
|
75
|
-
/**
|
|
76
|
-
* Whether worktree isolation is permitted at all. False when the project set
|
|
77
|
-
* `worktreeIsolation: false`, which drops a requested worktree rather than
|
|
78
|
-
* failing the call: the fail-loud precedent covers spawns that *cannot* work,
|
|
79
|
-
* while this one is the user opting out, and throwing would break exactly the
|
|
80
|
-
* calls the `"off"` value exists to tolerate. Defaults to allowed.
|
|
81
|
-
*/
|
|
82
|
-
worktreeAllowed?: boolean;
|
|
83
|
-
/**
|
|
84
|
-
* What an unqualified spawn means — neither the call nor the agent file said.
|
|
85
|
-
*
|
|
86
|
-
* Top-level callers pass the `backgroundByDefault` setting (default `true`,
|
|
87
|
-
* following Claude Code). Nested callers pass `false` unconditionally: a
|
|
88
|
-
* detached child is killed by `abortOwnedChildren` when its parent settles
|
|
89
|
-
* and has no notification path of its own, so backgrounding one loses its
|
|
90
|
-
* work. Both call sites pass it explicitly; the `false` fallback only covers
|
|
91
|
-
* a caller that supplies no options at all, which in-tree means tests.
|
|
92
|
-
*/
|
|
93
|
-
defaultRunInBackground?: boolean;
|
|
10
|
+
isolation?: IsolationMode;
|
|
94
11
|
}
|
|
95
12
|
|
|
96
13
|
export function resolveAgentInvocationConfig(
|
|
97
14
|
agentConfig: AgentConfig | undefined,
|
|
98
15
|
params: AgentInvocationParams,
|
|
99
|
-
opts?: ResolveOptions,
|
|
100
16
|
): {
|
|
101
17
|
modelInput?: string;
|
|
102
18
|
modelFromParams: boolean;
|
|
@@ -106,47 +22,16 @@ export function resolveAgentInvocationConfig(
|
|
|
106
22
|
runInBackground: boolean;
|
|
107
23
|
isolated: boolean;
|
|
108
24
|
isolation?: IsolationMode;
|
|
109
|
-
/**
|
|
110
|
-
* Caller parameters an agent file's frontmatter outranked, so the surfaces can
|
|
111
|
-
* say "(asked X)" instead of presenting the effective value as the requested
|
|
112
|
-
* one (#182). Populated only where both sides named something and they
|
|
113
|
-
* disagree — a caller who asked for what they got was still honored.
|
|
114
|
-
*
|
|
115
|
-
* `max_turns` is deliberately absent: no surface renders a requested-vs-
|
|
116
|
-
* effective turn limit, so recording one would be dead data.
|
|
117
|
-
*/
|
|
118
|
-
overridden?: { thinking?: ThinkingLevel; model?: string };
|
|
119
25
|
} {
|
|
120
|
-
// Precedence first, collapse second — reversing these loses the veto, since
|
|
121
|
-
// an agent file's "off" only outranks a caller's "worktree" while it is still
|
|
122
|
-
// a value. Everything downstream then sees "worktree" or nothing at all.
|
|
123
|
-
const requested = agentConfig?.isolation ?? params.isolation;
|
|
124
|
-
const isolation = requested === "worktree" && opts?.worktreeAllowed !== false ? "worktree" : undefined;
|
|
125
|
-
|
|
126
|
-
const overriddenThinking = agentConfig?.thinking != null && params.thinking != null
|
|
127
|
-
&& agentConfig.thinking !== params.thinking
|
|
128
|
-
? params.thinking as ThinkingLevel
|
|
129
|
-
: undefined;
|
|
130
|
-
const overriddenModel = agentConfig?.model != null && params.model != null
|
|
131
|
-
&& agentConfig.model !== params.model
|
|
132
|
-
? params.model
|
|
133
|
-
: undefined;
|
|
134
|
-
|
|
135
26
|
return {
|
|
136
27
|
modelInput: agentConfig?.model ?? params.model,
|
|
137
28
|
modelFromParams: agentConfig?.model == null && params.model != null,
|
|
138
29
|
thinking: (agentConfig?.thinking ?? params.thinking) as ThinkingLevel | undefined,
|
|
139
30
|
maxTurns: agentConfig?.maxTurns ?? params.max_turns,
|
|
140
31
|
inheritContext: agentConfig?.inheritContext ?? params.inherit_context ?? false,
|
|
141
|
-
runInBackground: agentConfig?.runInBackground ?? params.run_in_background ??
|
|
32
|
+
runInBackground: agentConfig?.runInBackground ?? params.run_in_background ?? false,
|
|
142
33
|
isolated: agentConfig?.isolated ?? params.isolated ?? false,
|
|
143
|
-
isolation,
|
|
144
|
-
// Undefined rather than an empty object when nothing was overridden: callers
|
|
145
|
-
// spread this into the invocation snapshot, and an always-present key would
|
|
146
|
-
// put `requestedThinking: undefined` on every record.
|
|
147
|
-
overridden: overriddenThinking || overriddenModel
|
|
148
|
-
? { thinking: overriddenThinking, model: overriddenModel }
|
|
149
|
-
: undefined,
|
|
34
|
+
isolation: agentConfig?.isolation ?? params.isolation,
|
|
150
35
|
};
|
|
151
36
|
}
|
|
152
37
|
|
package/src/model-resolver.ts
CHANGED
|
@@ -14,24 +14,6 @@ export interface ModelRegistry {
|
|
|
14
14
|
getAvailable?(): any[];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* Both display forms of a model. The short one goes on tight rows (the widget,
|
|
19
|
-
* the Agent tool result), the canonical one where there is room to disambiguate
|
|
20
|
-
* two providers serving a similarly-named model (the conversation viewer).
|
|
21
|
-
*
|
|
22
|
-
* One function, because `index.ts` labels the model it resolved before the run
|
|
23
|
-
* and `agent-manager.ts` relabels it from the live session afterwards — the two
|
|
24
|
-
* must agree or the label would visibly change the moment the session starts.
|
|
25
|
-
*/
|
|
26
|
-
export function describeModel(
|
|
27
|
-
model: { provider: string; id: string; name?: string },
|
|
28
|
-
): { modelName: string; modelId: string } {
|
|
29
|
-
return {
|
|
30
|
-
modelName: (model.name ?? model.id).replace(/^Claude\s+/i, "").toLowerCase(),
|
|
31
|
-
modelId: `${model.provider}/${model.id}`,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
17
|
/**
|
|
36
18
|
* Resolve a model string to a Model instance.
|
|
37
19
|
* Tries exact match first ("provider/modelId"), then fuzzy match against all available models.
|
package/src/output-file.ts
CHANGED
|
@@ -10,20 +10,6 @@ import { tmpdir } from "node:os";
|
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
import type { AgentSession, AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* Project/global default for writing a subagent's `.output` transcript; a custom
|
|
15
|
-
* agent's `output_transcript` overrides it per agent.
|
|
16
|
-
*
|
|
17
|
-
* State lives here rather than in an index.ts closure because both spawn paths
|
|
18
|
-
* need it — the top-level Agent tool and the nested delegation tools. Same
|
|
19
|
-
* reason `scopeModels` lives in model-scope.ts: a setting only one path can read
|
|
20
|
-
* is a setting the other path silently ignores.
|
|
21
|
-
*/
|
|
22
|
-
let outputTranscriptDefault = true;
|
|
23
|
-
|
|
24
|
-
export function getOutputTranscriptDefault(): boolean { return outputTranscriptDefault; }
|
|
25
|
-
export function setOutputTranscriptDefault(b: boolean): void { outputTranscriptDefault = b; }
|
|
26
|
-
|
|
27
13
|
/**
|
|
28
14
|
* Encode a cwd path as a filesystem-safe directory name. Handles:
|
|
29
15
|
* - POSIX: "/home/user/project" → "home-user-project"
|
|
@@ -37,14 +23,9 @@ export function encodeCwd(cwd: string): string {
|
|
|
37
23
|
.replace(/^-+/, ""); // strip leading dashes (POSIX root, UNC)
|
|
38
24
|
}
|
|
39
25
|
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
* Shared with the workflow tool, which persists each invocation's script here so
|
|
45
|
-
* iterating on one is edit-file-then-rerun — the same convention, one directory.
|
|
46
|
-
*/
|
|
47
|
-
export function sessionTaskDir(cwd: string, sessionId: string): string {
|
|
26
|
+
/** Create the output file path, ensuring the directory exists.
|
|
27
|
+
* Mirrors Claude Code's layout: /tmp/{prefix}-{uid}/{encoded-cwd}/{sessionId}/tasks/{agentId}.output */
|
|
28
|
+
export function createOutputFilePath(cwd: string, agentId: string, sessionId: string): string {
|
|
48
29
|
const encoded = encodeCwd(cwd);
|
|
49
30
|
const root = join(tmpdir(), `pi-subagents-${process.getuid?.() ?? 0}`);
|
|
50
31
|
mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
@@ -57,27 +38,7 @@ export function sessionTaskDir(cwd: string, sessionId: string): string {
|
|
|
57
38
|
}
|
|
58
39
|
const dir = join(root, encoded, sessionId, "tasks");
|
|
59
40
|
mkdirSync(dir, { recursive: true });
|
|
60
|
-
return dir;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Create the output file path, ensuring the directory exists. */
|
|
64
|
-
export function createOutputFilePath(cwd: string, agentId: string, sessionId: string): string {
|
|
65
|
-
return join(sessionTaskDir(cwd, sessionId), `${agentId}.output`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Ensure a transcript file exists without disturbing what is already in it.
|
|
70
|
-
*
|
|
71
|
-
* A resume reuses the agent's existing transcript (same deterministic path), so
|
|
72
|
-
* it must never call `writeInitialEntry` — that truncates, discarding turns the
|
|
73
|
-
* completion notification still points the user at, and any history the session
|
|
74
|
-
* has since compacted away is gone for good. Appending nothing creates the file
|
|
75
|
-
* when this is the agent's first transcript and is a no-op when it is not.
|
|
76
|
-
*/
|
|
77
|
-
export function ensureOutputFile(path: string): void {
|
|
78
|
-
try {
|
|
79
|
-
appendFileSync(path, "", "utf-8");
|
|
80
|
-
} catch { /* ignore — streaming writes are best-effort too */ }
|
|
41
|
+
return join(dir, `${agentId}.output`);
|
|
81
42
|
}
|
|
82
43
|
|
|
83
44
|
/** Write the initial user prompt entry. */
|
|
@@ -102,24 +63,9 @@ export function streamToOutputFile(
|
|
|
102
63
|
path: string,
|
|
103
64
|
agentId: string,
|
|
104
65
|
cwd: string,
|
|
105
|
-
startIndexOrHistoryPath?: number | string,
|
|
106
66
|
historyPath?: string,
|
|
107
67
|
): () => void {
|
|
108
|
-
|
|
109
|
-
// argument) while accepting upstream's six-argument resume form
|
|
110
|
-
// (startIndex, historyPath). This matters because scheduler/RPC/workflow
|
|
111
|
-
// callers use the ordinary spawn form, whereas resume starts after an
|
|
112
|
-
// existing in-memory message prefix.
|
|
113
|
-
const startIndex = typeof startIndexOrHistoryPath === "number" ? startIndexOrHistoryPath : undefined;
|
|
114
|
-
const durableHistoryPath = typeof startIndexOrHistoryPath === "string"
|
|
115
|
-
? startIndexOrHistoryPath
|
|
116
|
-
: historyPath;
|
|
117
|
-
// Index of the first message this stream is responsible for. A spawn writes
|
|
118
|
-
// messages[0] as the initial prompt entry, so it starts at 1. A resume hands
|
|
119
|
-
// in the session's length as of just before the run: the session already
|
|
120
|
-
// holds every prior turn, and re-emitting those would duplicate history that
|
|
121
|
-
// is already in the file.
|
|
122
|
-
let writtenCount = startIndex ?? 1;
|
|
68
|
+
let writtenCount = 1; // initial user prompt already written
|
|
123
69
|
|
|
124
70
|
const flush = () => {
|
|
125
71
|
const messages = session.messages;
|
|
@@ -134,8 +80,7 @@ export function streamToOutputFile(
|
|
|
134
80
|
cwd,
|
|
135
81
|
};
|
|
136
82
|
const entryJson = JSON.stringify(entry) + "\n";
|
|
137
|
-
const
|
|
138
|
-
for (const target of targets) {
|
|
83
|
+
for (const target of historyPath && historyPath !== path ? [path, historyPath] : [path]) {
|
|
139
84
|
try {
|
|
140
85
|
appendFileSync(target, entryJson, "utf-8");
|
|
141
86
|
} catch { /* ignore write errors */ }
|
package/src/prompts.ts
CHANGED
|
@@ -10,29 +10,6 @@ export interface PromptExtras {
|
|
|
10
10
|
memoryBlock?: string;
|
|
11
11
|
/** Preloaded skill contents to inject. */
|
|
12
12
|
skillBlocks?: { name: string; content: string }[];
|
|
13
|
-
/**
|
|
14
|
-
* Parent directory the worktree copy was created from. Set only for
|
|
15
|
-
* `isolation: "worktree"` spawns — triggers the block that tells the agent
|
|
16
|
-
* to stay in the copy.
|
|
17
|
-
*/
|
|
18
|
-
worktreeBase?: string;
|
|
19
|
-
/**
|
|
20
|
-
* Set only for a workflow's own children, and only when they have no
|
|
21
|
-
* `StructuredOutput` tool to answer through.
|
|
22
|
-
*
|
|
23
|
-
* A workflow child's final text is not read by a human — it is the value
|
|
24
|
-
* `agent()` resolves to, and the script interpolates it straight into the
|
|
25
|
-
* next stage's prompt. Without this, children answer the way every other
|
|
26
|
-
* subagent does (a report addressed to a reader), and the padding becomes
|
|
27
|
-
* input tokens for the stage downstream. Claude Code's `Workflow` tool
|
|
28
|
-
* documents this contract to the script-writing model; this is the end of it
|
|
29
|
-
* that makes the documentation true.
|
|
30
|
-
*
|
|
31
|
-
* Deliberately NOT applied to every subagent. In pi an ordinary agent's
|
|
32
|
-
* output IS read by a human — through the Agents widget, the conversation
|
|
33
|
-
* viewer and `get_subagent_result` — so terse raw data would be wrong there.
|
|
34
|
-
*/
|
|
35
|
-
workflowChild?: boolean;
|
|
36
13
|
}
|
|
37
14
|
|
|
38
15
|
/**
|
|
@@ -66,26 +43,6 @@ Working directory: ${cwd}
|
|
|
66
43
|
${env.isGitRepo ? `Git repository: yes\nBranch: ${env.branch}` : "Not a git repository"}
|
|
67
44
|
Platform: ${env.platform}`;
|
|
68
45
|
|
|
69
|
-
// A worktree agent is told its cwd twice: by the env block above (the copy)
|
|
70
|
-
// and by whatever names the main checkout — the inherited parent prompt in
|
|
71
|
-
// append mode, or the task prompt in either mode. It follows the latter and
|
|
72
|
-
// works in the shared tree (#187), so resolve the contradiction explicitly.
|
|
73
|
-
const worktreeBlock = extras?.worktreeBase
|
|
74
|
-
? `\n\n<worktree_isolation>
|
|
75
|
-
Your working directory is an isolated git worktree copy of ${extras.worktreeBase}.
|
|
76
|
-
Work only inside it — never in ${extras.worktreeBase}, even if other instructions name that path as your working directory.
|
|
77
|
-
</worktree_isolation>`
|
|
78
|
-
: "";
|
|
79
|
-
|
|
80
|
-
// The script, not a person, reads what this child returns — see
|
|
81
|
-
// `PromptExtras.workflowChild` for why only workflow children get this.
|
|
82
|
-
const workflowBlock = extras?.workflowChild
|
|
83
|
-
? `\n\n<workflow_child>
|
|
84
|
-
Your final message IS the return value of this task. A workflow script captures it and passes it to the next stage; no person reads it.
|
|
85
|
-
Return only the answer, in exactly the shape the prompt asks for — no preamble, no summary of what you did, no offer to continue.
|
|
86
|
-
</workflow_child>`
|
|
87
|
-
: "";
|
|
88
|
-
|
|
89
46
|
// Build optional extras suffix
|
|
90
47
|
const extraSections: string[] = [];
|
|
91
48
|
if (extras?.memoryBlock) {
|
|
@@ -123,7 +80,7 @@ You are operating as a sub-agent invoked to handle a specific task.
|
|
|
123
80
|
// placed verbatim (no wrapper tag) so it forms an identical byte prefix
|
|
124
81
|
// with the parent session, maximising KV cache hits. The <active_agent>
|
|
125
82
|
// tag and env block vary per call and are placed after the cached prefix.
|
|
126
|
-
return identity + "\n\n" + bridge + "\n\n" + activeAgentTag + envBlock +
|
|
83
|
+
return identity + "\n\n" + bridge + "\n\n" + activeAgentTag + envBlock + customSection + extrasSuffix;
|
|
127
84
|
}
|
|
128
85
|
|
|
129
86
|
// "replace" mode — env header + the config's full system prompt
|
|
@@ -132,7 +89,7 @@ You have been invoked to handle a specific task autonomously.
|
|
|
132
89
|
|
|
133
90
|
${envBlock}`;
|
|
134
91
|
|
|
135
|
-
return activeAgentTag + replaceHeader +
|
|
92
|
+
return activeAgentTag + replaceHeader + "\n\n" + config.systemPrompt + extrasSuffix;
|
|
136
93
|
}
|
|
137
94
|
|
|
138
95
|
/** Fallback base prompt when parent system prompt is unavailable in append mode. */
|
package/src/schedule.ts
CHANGED
|
@@ -19,8 +19,6 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
|
|
|
19
19
|
import { Cron } from "croner";
|
|
20
20
|
import { nanoid } from "nanoid";
|
|
21
21
|
import type { AgentManager } from "./agent-manager.js";
|
|
22
|
-
import { normalizeMaxTurns } from "./agent-runner.js";
|
|
23
|
-
import { resolveSpawnType } from "./agent-types.js";
|
|
24
22
|
import { resolveModel } from "./model-resolver.js";
|
|
25
23
|
import type { ScheduleStore } from "./schedule-store.js";
|
|
26
24
|
import type { IsolationMode, ScheduledSubagent, SubagentType, ThinkingLevel } from "./types.js";
|
|
@@ -240,15 +238,7 @@ export class SubagentScheduler {
|
|
|
240
238
|
|
|
241
239
|
let agentId: string;
|
|
242
240
|
try {
|
|
243
|
-
|
|
244
|
-
// reload from disk (the scheduler has no reason to rebuild process-global
|
|
245
|
-
// state from a timer), so it catches changes that went through /agents or
|
|
246
|
-
// an Agent call — not a file deleted directly from a shell. The catch below turns
|
|
247
|
-
// this into lastStatus: "error" plus an error event, like any other
|
|
248
|
-
// fire-time failure.
|
|
249
|
-
const dispatch = resolveSpawnType(job.subagent_type);
|
|
250
|
-
if (!dispatch.ok) throw new Error(dispatch.message);
|
|
251
|
-
agentId = manager.spawn(pi, ctx, dispatch.type, job.prompt, {
|
|
241
|
+
agentId = manager.spawn(pi, ctx, job.subagent_type, job.prompt, {
|
|
252
242
|
description: job.description,
|
|
253
243
|
isBackground: true,
|
|
254
244
|
bypassQueue: true,
|
|
@@ -257,20 +247,6 @@ export class SubagentScheduler {
|
|
|
257
247
|
isolated: job.isolated,
|
|
258
248
|
thinkingLevel: job.thinking,
|
|
259
249
|
isolation: job.isolation,
|
|
260
|
-
// A scheduled run has no tool call to build this, so without it the
|
|
261
|
-
// conversation viewer shows nothing about how the job was configured.
|
|
262
|
-
// The model is left out on purpose: agent-manager fills in the effective
|
|
263
|
-
// one when the session reports it, and naming the pre-session pick here
|
|
264
|
-
// would only be right until then.
|
|
265
|
-
invocation: {
|
|
266
|
-
thinking: job.thinking,
|
|
267
|
-
// Normalized like the Agent tool's own snapshot: `0` means unlimited,
|
|
268
|
-
// and rendering it as "max turns: 0" would read as a limit of none.
|
|
269
|
-
maxTurns: normalizeMaxTurns(job.max_turns),
|
|
270
|
-
isolated: job.isolated,
|
|
271
|
-
runInBackground: true,
|
|
272
|
-
isolation: job.isolation,
|
|
273
|
-
},
|
|
274
250
|
});
|
|
275
251
|
} catch (err) {
|
|
276
252
|
const error = err instanceof Error ? err.message : String(err);
|
|
@@ -281,6 +257,7 @@ export class SubagentScheduler {
|
|
|
281
257
|
|
|
282
258
|
this.emit({ type: "fired", jobId: id, agentId, name: job.name });
|
|
283
259
|
|
|
260
|
+
const record = manager.getRecord(agentId);
|
|
284
261
|
const finalize = (status: "success" | "error") => {
|
|
285
262
|
const next = this.getNextRun(id);
|
|
286
263
|
const current = store.get(id);
|
|
@@ -295,16 +272,18 @@ export class SubagentScheduler {
|
|
|
295
272
|
// AgentManager's promise resolves either way (its .catch returns ""), so we
|
|
296
273
|
// can't infer success/failure from the promise — read record.status instead.
|
|
297
274
|
// Terminal states: completed/steered = success; error/aborted/stopped = error.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
275
|
+
if (record?.promise) {
|
|
276
|
+
record.promise
|
|
277
|
+
.then(() => {
|
|
278
|
+
const r = manager.getRecord(agentId);
|
|
279
|
+
const failed = r?.status === "error" || r?.status === "aborted" || r?.status === "stopped";
|
|
280
|
+
finalize(failed ? "error" : "success");
|
|
281
|
+
})
|
|
282
|
+
.catch(() => finalize("error"));
|
|
283
|
+
} else {
|
|
284
|
+
// Spawn returned without a promise (defensive — bypassQueue path always sets one).
|
|
285
|
+
finalize("success");
|
|
286
|
+
}
|
|
308
287
|
}
|
|
309
288
|
|
|
310
289
|
private emit(event: ScheduleChangeEvent): void {
|