pi-crew 0.2.3 → 0.2.5
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/AGENTS.md +57 -32
- package/CHANGELOG.md +466 -448
- package/LICENSE +21 -21
- package/NOTICE.md +16 -16
- package/README.md +323 -323
- package/docs/FEATURE_INTAKE.md +126 -0
- package/docs/HARNESS.md +86 -0
- package/docs/HARNESS_BACKLOG.md +41 -0
- package/docs/TEST_MATRIX.md +49 -0
- package/docs/actions-reference.md +595 -595
- package/docs/architecture.md +180 -180
- package/docs/code-review-2026-05-11.md +592 -592
- package/docs/commands-reference.md +347 -347
- package/docs/comparison-pi-subagents-vs-pi-crew.md +303 -0
- package/docs/decisions/0001-durable-state.md +41 -0
- package/docs/decisions/0002-child-process-for-async.md +42 -0
- package/docs/decisions/0003-depth-guard.md +36 -0
- package/docs/decisions/0004-execfile-over-exec.md +34 -0
- package/docs/decisions/0005-no-parameter-properties.md +49 -0
- package/docs/decisions/0006-publish-bundled-esm.md +63 -0
- package/docs/decisions/0007-active-run-binary-index.md +54 -0
- package/docs/decisions/0008-child-pi-warm-pool.md +61 -0
- package/docs/decisions/README.md +23 -0
- package/docs/followup-review-round4-2026-05-13.md +107 -0
- package/docs/implementation-plan-top3.md +333 -0
- package/docs/live-mailbox-runtime.md +36 -36
- package/docs/next-upgrade-roadmap.md +808 -808
- package/docs/oh-my-pi-research.md +509 -0
- package/docs/perf/baseline-2026-05.md +113 -0
- package/docs/perf/final-report-2026-05.md +206 -0
- package/docs/perf/sprint-1-report.md +71 -0
- package/docs/perf/sprint-2-report.md +81 -0
- package/docs/perf/sprint-2.5-report.md +53 -0
- package/docs/perf/sprint-3-report.md +36 -0
- package/docs/perf/sprint-4-report.md +47 -0
- package/docs/perf/sprint-5-report.md +51 -0
- package/docs/perf/sprint-6-report.md +94 -0
- package/docs/perf/sprint-7-report.md +74 -0
- package/docs/perf/upgrade-plan-2026-05.md +147 -0
- package/docs/pi-subagents3-deep-analysis.md +508 -0
- package/docs/product/README.md +31 -0
- package/docs/product/platform.md +27 -0
- package/docs/product/runtime-safety.md +37 -0
- package/docs/product/team-run.md +39 -0
- package/docs/product/team-tool.md +37 -0
- package/docs/publishing.md +65 -65
- package/docs/resource-formats.md +134 -134
- package/docs/runtime-analysis-child-vs-live.md +171 -0
- package/docs/runtime-flow.md +148 -148
- package/docs/runtime-migration-in-process-analysis.md +250 -0
- package/docs/stories/README.md +30 -0
- package/docs/stories/backlog.md +36 -0
- package/docs/templates/decision.md +27 -0
- package/docs/templates/story.md +44 -0
- package/docs/templates/validation-report.md +32 -0
- package/docs/usage.md +238 -238
- package/index.ts +7 -6
- package/install.mjs +65 -65
- package/package.json +107 -100
- package/schema.json +222 -222
- package/skills/child-pi-spawning/SKILL.md +213 -0
- package/skills/context-artifact-hygiene/SKILL.md +32 -0
- package/skills/event-log-tracing/SKILL.md +299 -0
- package/skills/git-master/SKILL.md +225 -24
- package/skills/live-agent-lifecycle/SKILL.md +192 -0
- package/skills/mailbox-interactive/SKILL.md +300 -19
- package/skills/model-routing-context/SKILL.md +94 -0
- package/skills/multi-perspective-review/SKILL.md +88 -0
- package/skills/read-only-explorer/SKILL.md +250 -26
- package/skills/safe-bash/SKILL.md +307 -21
- package/skills/verification-before-done/SKILL.md +11 -2
- package/skills/widget-rendering/SKILL.md +258 -0
- package/skills/workspace-isolation/SKILL.md +202 -0
- package/skills/worktree-isolation/SKILL.md +202 -18
- package/src/adapters/claude-adapter.ts +25 -25
- package/src/adapters/codex-adapter.ts +21 -21
- package/src/adapters/cursor-adapter.ts +17 -17
- package/src/adapters/export-util.ts +137 -137
- package/src/adapters/index.ts +15 -15
- package/src/adapters/registry.ts +18 -18
- package/src/adapters/types.ts +23 -23
- package/src/agents/agent-config.ts +38 -38
- package/src/agents/agent-serializer.ts +38 -38
- package/src/agents/discover-agents.ts +121 -118
- package/src/config/config.ts +740 -858
- package/src/config/defaults.ts +96 -96
- package/src/config/drift-detector.ts +211 -211
- package/src/config/markers.ts +327 -327
- package/src/config/resilient-parser.ts +109 -108
- package/src/config/suggestions.ts +74 -74
- package/src/config/types.ts +199 -0
- package/src/extension/async-notifier.ts +123 -89
- package/src/extension/autonomous-policy.ts +169 -169
- package/src/extension/cross-extension-rpc.ts +104 -104
- package/src/extension/help.ts +47 -47
- package/src/extension/import-index.ts +69 -69
- package/src/extension/management.ts +395 -382
- package/src/extension/notification-router.ts +116 -116
- package/src/extension/notification-sink.ts +51 -51
- package/src/extension/project-init.ts +168 -168
- package/src/extension/register.ts +859 -668
- package/src/extension/registration/artifact-cleanup.ts +15 -15
- package/src/extension/registration/command-utils.ts +54 -54
- package/src/extension/registration/commands.ts +559 -452
- package/src/extension/registration/compaction-guard.ts +125 -125
- package/src/extension/registration/subagent-helpers.ts +102 -102
- package/src/extension/registration/subagent-tools.ts +220 -159
- package/src/extension/registration/team-tool.ts +159 -99
- package/src/extension/registration/viewers.ts +29 -0
- package/src/extension/result-watcher.ts +128 -128
- package/src/extension/run-bundle-schema.ts +89 -89
- package/src/extension/run-export.ts +73 -73
- package/src/extension/run-import.ts +84 -84
- package/src/extension/run-index.ts +94 -94
- package/src/extension/run-maintenance.ts +142 -142
- package/src/extension/session-summary.ts +8 -8
- package/src/extension/team-manager-command.ts +96 -96
- package/src/extension/team-recommendation.ts +188 -188
- package/src/extension/team-tool/api.ts +5 -2
- package/src/extension/team-tool/cancel.ts +224 -209
- package/src/extension/team-tool/config-patch.ts +36 -36
- package/src/extension/team-tool/context.ts +60 -60
- package/src/extension/team-tool/doctor.ts +242 -242
- package/src/extension/team-tool/handle-settings.ts +421 -195
- package/src/extension/team-tool/inspect.ts +41 -41
- package/src/extension/team-tool/lifecycle-actions.ts +139 -139
- package/src/extension/team-tool/parallel-dispatch.ts +156 -156
- package/src/extension/team-tool/plan.ts +19 -19
- package/src/extension/team-tool/respond.ts +112 -111
- package/src/extension/team-tool/run.ts +246 -229
- package/src/extension/team-tool/status.ts +110 -110
- package/src/extension/team-tool-types.ts +13 -13
- package/src/extension/team-tool.ts +344 -344
- package/src/extension/tool-result.ts +16 -16
- package/src/extension/validate-resources.ts +77 -77
- package/src/hooks/registry.ts +61 -61
- package/src/hooks/types.ts +40 -40
- package/src/i18n.ts +184 -184
- package/src/observability/correlation.ts +35 -35
- package/src/observability/event-to-metric.ts +68 -68
- package/src/observability/exporters/adapter.ts +30 -30
- package/src/observability/exporters/otlp-exporter.ts +106 -92
- package/src/observability/exporters/prometheus-exporter.ts +54 -54
- package/src/observability/metric-registry.ts +87 -87
- package/src/observability/metric-retention.ts +54 -54
- package/src/observability/metric-sink.ts +81 -56
- package/src/observability/metrics-primitives.ts +167 -167
- package/src/prompt/prompt-runtime.ts +72 -72
- package/src/runtime/adaptive-plan.ts +338 -0
- package/src/runtime/agent-control.ts +169 -169
- package/src/runtime/agent-memory.ts +72 -72
- package/src/runtime/agent-observability.ts +114 -114
- package/src/runtime/async-marker.ts +26 -26
- package/src/runtime/async-runner.ts +153 -153
- package/src/runtime/attention-events.ts +28 -28
- package/src/runtime/auto-resume.ts +100 -100
- package/src/runtime/background-runner.ts +122 -89
- package/src/runtime/cancellation.ts +61 -61
- package/src/runtime/capability-inventory.ts +116 -116
- package/src/runtime/child-pi-pool.ts +68 -0
- package/src/runtime/child-pi.ts +541 -461
- package/src/runtime/code-summary.ts +247 -247
- package/src/runtime/compaction-summary.ts +271 -271
- package/src/runtime/concurrency.ts +58 -58
- package/src/runtime/crash-recovery.ts +317 -301
- package/src/runtime/crew-agent-records.ts +379 -281
- package/src/runtime/crew-agent-runtime.ts +60 -60
- package/src/runtime/cross-extension-rpc.ts +72 -0
- package/src/runtime/custom-tools/irc-tool.ts +201 -201
- package/src/runtime/custom-tools/submit-result-tool.ts +90 -90
- package/src/runtime/deadletter.ts +47 -47
- package/src/runtime/delivery-coordinator.ts +176 -176
- package/src/runtime/delta-conflict.ts +360 -360
- package/src/runtime/diagnostic-export.ts +102 -102
- package/src/runtime/direct-run.ts +35 -35
- package/src/runtime/effectiveness.ts +82 -81
- package/src/runtime/errors/crew-errors.ts +166 -0
- package/src/runtime/event-stream-bridge.ts +92 -92
- package/src/runtime/foreground-control.ts +82 -82
- package/src/runtime/green-contract.ts +46 -46
- package/src/runtime/group-join.ts +234 -106
- package/src/runtime/heartbeat-watcher.ts +145 -124
- package/src/runtime/iteration-hooks.ts +267 -267
- package/src/runtime/live-agent-control.ts +88 -88
- package/src/runtime/live-agent-manager.ts +377 -179
- package/src/runtime/live-control-realtime.ts +36 -36
- package/src/runtime/live-session-runtime.ts +676 -600
- package/src/runtime/loop-gates.ts +129 -129
- package/src/runtime/manifest-cache.ts +263 -263
- package/src/runtime/mcp-proxy.ts +113 -113
- package/src/runtime/metric-parser.ts +40 -40
- package/src/runtime/model-fallback.ts +282 -274
- package/src/runtime/model-resolver.ts +118 -0
- package/src/runtime/output-validator.ts +187 -187
- package/src/runtime/overflow-recovery.ts +175 -175
- package/src/runtime/parallel-research.ts +44 -44
- package/src/runtime/parallel-utils.ts +156 -156
- package/src/runtime/parent-guard.ts +80 -80
- package/src/runtime/phase-progress.ts +217 -217
- package/src/runtime/pi-args.ts +165 -165
- package/src/runtime/pi-json-output.ts +111 -111
- package/src/runtime/pi-spawn.ts +167 -167
- package/src/runtime/policy-engine.ts +79 -79
- package/src/runtime/post-checks.ts +125 -125
- package/src/runtime/post-exit-stdio-guard.ts +86 -86
- package/src/runtime/process-status.ts +97 -73
- package/src/runtime/progress-event-coalescer.ts +43 -43
- package/src/runtime/recovery-recipes.ts +74 -74
- package/src/runtime/retry-executor.ts +81 -81
- package/src/runtime/role-permission.ts +39 -39
- package/src/runtime/run-tracker.ts +99 -0
- package/src/runtime/runtime-policy.ts +21 -0
- package/src/runtime/runtime-resolver.ts +94 -91
- package/src/runtime/scheduler.ts +294 -0
- package/src/runtime/semaphore.ts +131 -131
- package/src/runtime/sensitive-paths.ts +92 -92
- package/src/runtime/session-usage.ts +79 -79
- package/src/runtime/settings-store.ts +103 -0
- package/src/runtime/sidechain-output.ts +29 -29
- package/src/runtime/skill-instructions.ts +222 -222
- package/src/runtime/stale-reconciler.ts +198 -189
- package/src/runtime/streaming-output.ts +47 -0
- package/src/runtime/subagent-manager.ts +404 -400
- package/src/runtime/subprocess-tool-registry.ts +67 -67
- package/src/runtime/task-display.ts +38 -38
- package/src/runtime/task-graph-scheduler.ts +122 -122
- package/src/runtime/task-graph.ts +207 -207
- package/src/runtime/task-output-context.ts +177 -177
- package/src/runtime/task-packet.ts +93 -93
- package/src/runtime/task-quality.ts +207 -207
- package/src/runtime/task-runner/capabilities.ts +78 -78
- package/src/runtime/task-runner/live-executor.ts +131 -113
- package/src/runtime/task-runner/progress.ts +119 -119
- package/src/runtime/task-runner/prompt-builder.ts +139 -139
- package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
- package/src/runtime/task-runner/result-utils.ts +14 -14
- package/src/runtime/task-runner/run-projection.ts +103 -103
- package/src/runtime/task-runner/state-helpers.ts +22 -22
- package/src/runtime/task-runner.ts +469 -459
- package/src/runtime/team-runner.ts +693 -945
- package/src/runtime/usage-tracker.ts +71 -0
- package/src/runtime/worker-heartbeat.ts +21 -21
- package/src/runtime/worker-startup.ts +57 -57
- package/src/runtime/workflow-state.ts +187 -187
- package/src/runtime/yield-handler.ts +190 -190
- package/src/schema/config-schema.ts +172 -168
- package/src/schema/team-tool-schema.ts +126 -126
- package/src/schema/validation-types.ts +151 -148
- package/src/skills/discover-skills.ts +67 -67
- package/src/skills/skill-templates.ts +374 -374
- package/src/state/active-run-registry.ts +227 -191
- package/src/state/artifact-store.ts +130 -129
- package/src/state/atomic-write.ts +262 -195
- package/src/state/blob-store.ts +116 -116
- package/src/state/contracts.ts +111 -111
- package/src/state/event-log-rotation.ts +161 -158
- package/src/state/event-log.ts +383 -303
- package/src/state/event-reconstructor.ts +217 -217
- package/src/state/jsonl-writer.ts +82 -82
- package/src/state/locks.ts +146 -146
- package/src/state/mailbox.ts +446 -405
- package/src/state/state-store.ts +364 -351
- package/src/state/task-claims.ts +44 -44
- package/src/state/types.ts +285 -285
- package/src/state/usage.ts +29 -29
- package/src/subagents/async-entry.ts +1 -1
- package/src/subagents/index.ts +3 -3
- package/src/subagents/live/control.ts +1 -1
- package/src/subagents/live/manager.ts +1 -1
- package/src/subagents/live/realtime.ts +1 -1
- package/src/subagents/live/session-runtime.ts +1 -1
- package/src/subagents/manager.ts +1 -1
- package/src/subagents/spawn.ts +1 -1
- package/src/teams/discover-teams.ts +116 -116
- package/src/teams/team-config.ts +27 -27
- package/src/teams/team-serializer.ts +38 -38
- package/src/types/diff.d.ts +18 -18
- package/src/ui/agent-management-overlay.ts +144 -144
- package/src/ui/crew-widget.ts +487 -370
- package/src/ui/dashboard-panes/agents-pane.ts +109 -28
- package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
- package/src/ui/dashboard-panes/capability-pane.ts +59 -59
- package/src/ui/dashboard-panes/health-pane.ts +30 -30
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
- package/src/ui/dashboard-panes/progress-pane.ts +30 -30
- package/src/ui/dashboard-panes/transcript-pane.ts +10 -10
- package/src/ui/heartbeat-aggregator.ts +63 -63
- package/src/ui/keybinding-map.ts +97 -94
- package/src/ui/live-conversation-overlay.ts +152 -0
- package/src/ui/live-run-sidebar.ts +180 -180
- package/src/ui/mascot.ts +442 -442
- package/src/ui/overlays/agent-picker-overlay.ts +57 -57
- package/src/ui/overlays/confirm-overlay.ts +58 -58
- package/src/ui/overlays/mailbox-compose-overlay.ts +144 -144
- package/src/ui/overlays/mailbox-compose-preview.ts +63 -63
- package/src/ui/overlays/mailbox-detail-overlay.ts +122 -122
- package/src/ui/pi-ui-compat.ts +57 -57
- package/src/ui/powerbar-publisher.ts +221 -197
- package/src/ui/render-scheduler.ts +216 -143
- package/src/ui/run-action-dispatcher.ts +118 -118
- package/src/ui/run-dashboard.ts +526 -464
- package/src/ui/run-event-bus.ts +208 -208
- package/src/ui/run-snapshot-cache.ts +826 -777
- package/src/ui/settings-overlay.ts +721 -0
- package/src/ui/snapshot-types.ts +86 -70
- package/src/ui/theme-adapter.ts +190 -190
- package/src/ui/tool-progress-formatter.ts +89 -0
- package/src/ui/transcript-cache.ts +94 -94
- package/src/ui/transcript-viewer.ts +335 -335
- package/src/utils/conflict-detect.ts +662 -0
- package/src/utils/file-coalescer.ts +86 -86
- package/src/utils/frontmatter.ts +68 -68
- package/src/utils/fs-watch.ts +88 -31
- package/src/utils/gh-protocol.ts +479 -0
- package/src/utils/ids.ts +17 -17
- package/src/utils/incremental-reader.ts +104 -104
- package/src/utils/internal-error.ts +6 -6
- package/src/utils/names.ts +27 -27
- package/src/utils/paths.ts +102 -63
- package/src/utils/redaction.ts +44 -44
- package/src/utils/safe-paths.ts +47 -47
- package/src/utils/scan-cache.ts +136 -136
- package/src/utils/sse-parser.ts +134 -134
- package/src/utils/task-name-generator.ts +337 -337
- package/src/utils/timings.ts +33 -33
- package/src/utils/visual.ts +243 -198
- package/src/workflows/discover-workflows.ts +139 -139
- package/src/workflows/validate-workflow.ts +40 -40
- package/src/workflows/workflow-config.ts +26 -26
- package/src/workflows/workflow-serializer.ts +32 -32
- package/src/worktree/branch-freshness.ts +45 -45
- package/src/worktree/cleanup.ts +75 -75
- package/src/worktree/worktree-manager.ts +188 -188
- package/teams/default.team.md +12 -12
- package/teams/fast-fix.team.md +11 -11
- package/teams/implementation.team.md +18 -18
- package/teams/parallel-research.team.md +14 -14
- package/teams/research.team.md +11 -11
- package/teams/review.team.md +12 -12
- package/tsconfig.json +19 -19
- package/workflows/default.workflow.md +30 -30
- package/workflows/fast-fix.workflow.md +23 -23
- package/workflows/implementation.workflow.md +43 -43
- package/workflows/parallel-research.workflow.md +46 -46
- package/workflows/research.workflow.md +22 -22
- package/workflows/review.workflow.md +30 -30
- package/skills/task-packet/SKILL.md +0 -28
- package/skills/verify-evidence/SKILL.md +0 -27
|
@@ -1,274 +1,282 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as os from "node:os";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
seen.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (envDir
|
|
85
|
-
return envDir;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
...
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (model
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
/
|
|
165
|
-
/
|
|
166
|
-
|
|
167
|
-
/
|
|
168
|
-
/
|
|
169
|
-
/
|
|
170
|
-
/
|
|
171
|
-
/
|
|
172
|
-
/
|
|
173
|
-
/
|
|
174
|
-
/
|
|
175
|
-
/
|
|
176
|
-
/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
/
|
|
191
|
-
/
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { fuzzyResolveModelId } from "./model-resolver.ts";
|
|
5
|
+
|
|
6
|
+
export interface AvailableModelInfo {
|
|
7
|
+
provider: string;
|
|
8
|
+
id: string;
|
|
9
|
+
fullId: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ModelAttemptSummary {
|
|
13
|
+
model: string;
|
|
14
|
+
success: boolean;
|
|
15
|
+
exitCode?: number | null;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ModelLike {
|
|
20
|
+
provider?: unknown;
|
|
21
|
+
id?: unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ModelRegistryLike {
|
|
25
|
+
getAvailable?: () => unknown[];
|
|
26
|
+
getAll?: () => unknown[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface PiSettingsLike {
|
|
30
|
+
defaultProvider?: unknown;
|
|
31
|
+
defaultModel?: unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PiModelsJsonLike {
|
|
35
|
+
providers?: unknown;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface PiProviderConfigLike {
|
|
39
|
+
models?: unknown;
|
|
40
|
+
modelOverrides?: unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function modelInfoFromUnknown(value: unknown): AvailableModelInfo | undefined {
|
|
44
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
45
|
+
const record = value as ModelLike;
|
|
46
|
+
if (typeof record.provider !== "string" || typeof record.id !== "string") return undefined;
|
|
47
|
+
return { provider: record.provider, id: record.id, fullId: `${record.provider}/${record.id}` };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function availableModelInfosFromRegistry(registry: unknown): AvailableModelInfo[] | undefined {
|
|
51
|
+
if (!registry || typeof registry !== "object" || Array.isArray(registry)) return undefined;
|
|
52
|
+
const candidate = registry as ModelRegistryLike;
|
|
53
|
+
const raw = typeof candidate.getAvailable === "function" ? candidate.getAvailable() : typeof candidate.getAll === "function" ? candidate.getAll() : undefined;
|
|
54
|
+
if (!Array.isArray(raw)) return undefined;
|
|
55
|
+
return raw.map(modelInfoFromUnknown).filter((entry): entry is AvailableModelInfo => entry !== undefined);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function modelStringFromUnknown(model: unknown): string | undefined {
|
|
59
|
+
return modelInfoFromUnknown(model)?.fullId;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function uniqueModelInfos(models: AvailableModelInfo[]): AvailableModelInfo[] {
|
|
63
|
+
const seen = new Set<string>();
|
|
64
|
+
return models.filter((model) => {
|
|
65
|
+
if (seen.has(model.fullId)) return false;
|
|
66
|
+
seen.add(model.fullId);
|
|
67
|
+
return true;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function readJsonObject(filePath: string): Record<string, unknown> | undefined {
|
|
72
|
+
try {
|
|
73
|
+
if (!fs.existsSync(filePath)) return undefined;
|
|
74
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
75
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed as Record<string, unknown> : undefined;
|
|
76
|
+
} catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function piAgentDir(): string {
|
|
82
|
+
const envDir = process.env.PI_CODING_AGENT_DIR?.trim();
|
|
83
|
+
if (envDir) {
|
|
84
|
+
if (envDir === "~") return os.homedir();
|
|
85
|
+
if (envDir.startsWith("~/")) return path.join(os.homedir(), envDir.slice(2));
|
|
86
|
+
return envDir;
|
|
87
|
+
}
|
|
88
|
+
return path.join(os.homedir(), ".pi", "agent");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function settingsModelInfo(settings: PiSettingsLike | undefined): AvailableModelInfo | undefined {
|
|
92
|
+
if (typeof settings?.defaultProvider !== "string" || typeof settings.defaultModel !== "string") return undefined;
|
|
93
|
+
return { provider: settings.defaultProvider, id: settings.defaultModel, fullId: `${settings.defaultProvider}/${settings.defaultModel}` };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function modelsJsonInfos(modelsJson: PiModelsJsonLike | undefined): AvailableModelInfo[] {
|
|
97
|
+
if (!modelsJson?.providers || typeof modelsJson.providers !== "object" || Array.isArray(modelsJson.providers)) return [];
|
|
98
|
+
const infos: AvailableModelInfo[] = [];
|
|
99
|
+
for (const [provider, rawConfig] of Object.entries(modelsJson.providers as Record<string, unknown>)) {
|
|
100
|
+
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) continue;
|
|
101
|
+
const config = rawConfig as PiProviderConfigLike;
|
|
102
|
+
if (Array.isArray(config.models)) {
|
|
103
|
+
for (const rawModel of config.models) {
|
|
104
|
+
if (!rawModel || typeof rawModel !== "object" || Array.isArray(rawModel)) continue;
|
|
105
|
+
const id = (rawModel as { id?: unknown }).id;
|
|
106
|
+
if (typeof id === "string") infos.push({ provider, id, fullId: `${provider}/${id}` });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (config.modelOverrides && typeof config.modelOverrides === "object" && !Array.isArray(config.modelOverrides)) {
|
|
110
|
+
for (const id of Object.keys(config.modelOverrides)) infos.push({ provider, id, fullId: `${provider}/${id}` });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return infos;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function configuredModelInfosFromPiConfig(cwd?: string): AvailableModelInfo[] {
|
|
117
|
+
const agentDir = piAgentDir();
|
|
118
|
+
const globalSettings = readJsonObject(path.join(agentDir, "settings.json")) as PiSettingsLike | undefined;
|
|
119
|
+
const projectSettings = cwd ? readJsonObject(path.join(cwd, ".pi", "settings.json")) as PiSettingsLike | undefined : undefined;
|
|
120
|
+
const effectiveSettings = { ...(globalSettings ?? {}), ...(projectSettings ?? {}) };
|
|
121
|
+
const defaultModel = settingsModelInfo(effectiveSettings);
|
|
122
|
+
return uniqueModelInfos([
|
|
123
|
+
...(defaultModel ? [defaultModel] : []),
|
|
124
|
+
...modelsJsonInfos(readJsonObject(path.join(agentDir, "models.json")) as PiModelsJsonLike | undefined),
|
|
125
|
+
]);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function splitThinkingSuffix(model: string): { baseModel: string; thinkingSuffix: string } {
|
|
129
|
+
const colonIdx = model.lastIndexOf(":");
|
|
130
|
+
if (colonIdx === -1) return { baseModel: model, thinkingSuffix: "" };
|
|
131
|
+
return {
|
|
132
|
+
baseModel: model.substring(0, colonIdx),
|
|
133
|
+
thinkingSuffix: model.substring(colonIdx),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function resolveModelCandidate(
|
|
138
|
+
model: string | undefined,
|
|
139
|
+
availableModels: AvailableModelInfo[] | undefined,
|
|
140
|
+
preferredProvider?: string,
|
|
141
|
+
): string | undefined {
|
|
142
|
+
if (!model) return undefined;
|
|
143
|
+
if (model.includes("/")) return model;
|
|
144
|
+
if (!availableModels || availableModels.length === 0) return model;
|
|
145
|
+
|
|
146
|
+
const { baseModel, thinkingSuffix } = splitThinkingSuffix(model);
|
|
147
|
+
const matches = availableModels.filter((entry) => entry.id === baseModel);
|
|
148
|
+
if (preferredProvider) {
|
|
149
|
+
const preferredMatch = matches.find((entry) => entry.provider === preferredProvider);
|
|
150
|
+
if (preferredMatch) return `${preferredMatch.fullId}${thinkingSuffix}`;
|
|
151
|
+
}
|
|
152
|
+
// When multiple providers share the same model id, return the raw model string.
|
|
153
|
+
// Callers should use the preferredProvider hint via resolveModelCandidate.
|
|
154
|
+
if (matches.length !== 1) {
|
|
155
|
+
// Fuzzy fallback: try to resolve via partial name matching
|
|
156
|
+
const fuzzy = fuzzyResolveModelId(baseModel, availableModels);
|
|
157
|
+
if (fuzzy) return `${fuzzy}${thinkingSuffix}`;
|
|
158
|
+
return model;
|
|
159
|
+
}
|
|
160
|
+
return `${matches[0]!.fullId}${thinkingSuffix}`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
164
|
+
/rate\s*limit/i,
|
|
165
|
+
/too many requests/i,
|
|
166
|
+
/\b429\b/,
|
|
167
|
+
/quota/i,
|
|
168
|
+
/provider.*unavailable/i,
|
|
169
|
+
/model.*unavailable/i,
|
|
170
|
+
/model.*disabled/i,
|
|
171
|
+
/model.*not found/i,
|
|
172
|
+
/unknown model/i,
|
|
173
|
+
/overloaded/i,
|
|
174
|
+
/service unavailable/i,
|
|
175
|
+
/temporar(?:ily)? unavailable/i,
|
|
176
|
+
/connection refused/i,
|
|
177
|
+
/fetch failed/i,
|
|
178
|
+
/network error/i,
|
|
179
|
+
/socket hang up/i,
|
|
180
|
+
/upstream/i,
|
|
181
|
+
/timed? out/i,
|
|
182
|
+
/timeout/i,
|
|
183
|
+
/\b502\b/,
|
|
184
|
+
/\b503\b/,
|
|
185
|
+
/\b504\b/,
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
// These patterns indicate auth/key/billing issues that will never succeed on retry.
|
|
189
|
+
const NON_RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
190
|
+
/auth(?:entication)?/i,
|
|
191
|
+
/unauthori[sz]ed/i,
|
|
192
|
+
/forbidden/i,
|
|
193
|
+
/api key/i,
|
|
194
|
+
/token expired/i,
|
|
195
|
+
/invalid key/i,
|
|
196
|
+
/billing/i,
|
|
197
|
+
/credit/i,
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
export function isRetryableModelFailure(error: string | undefined): boolean {
|
|
201
|
+
if (!error) return false;
|
|
202
|
+
// Auth / billing / invalid-key failures will never succeed on retry.
|
|
203
|
+
if (NON_RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(error))) return false;
|
|
204
|
+
return RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(error));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function formatModelAttemptNote(attempt: ModelAttemptSummary, nextModel?: string): string {
|
|
208
|
+
const failure = attempt.error?.trim() || `exit ${attempt.exitCode ?? 1}`;
|
|
209
|
+
return nextModel ? `[fallback] ${attempt.model} failed: ${failure}. Retrying with ${nextModel}.` : `[fallback] ${attempt.model} failed: ${failure}.`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function buildModelCandidates(
|
|
213
|
+
primaryModel: string | undefined,
|
|
214
|
+
fallbackModels: string[] | undefined,
|
|
215
|
+
availableModels: AvailableModelInfo[] | undefined,
|
|
216
|
+
preferredProvider?: string,
|
|
217
|
+
): string[] {
|
|
218
|
+
const seen = new Set<string>();
|
|
219
|
+
const candidates: string[] = [];
|
|
220
|
+
for (const raw of [primaryModel, ...(fallbackModels ?? [])]) {
|
|
221
|
+
if (!raw) continue;
|
|
222
|
+
const normalized = resolveModelCandidate(raw.trim(), availableModels, preferredProvider);
|
|
223
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
224
|
+
seen.add(normalized);
|
|
225
|
+
candidates.push(normalized);
|
|
226
|
+
}
|
|
227
|
+
return candidates;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function isAvailableModel(model: string, availableModels: AvailableModelInfo[] | undefined): boolean {
|
|
231
|
+
if (!availableModels || availableModels.length === 0) return true;
|
|
232
|
+
const { baseModel } = splitThinkingSuffix(model);
|
|
233
|
+
if (baseModel.includes("/")) return availableModels.some((entry) => entry.fullId === baseModel);
|
|
234
|
+
if (availableModels.some((entry) => entry.id === baseModel)) return true;
|
|
235
|
+
const fuzzy = fuzzyResolveModelId(baseModel, availableModels);
|
|
236
|
+
return fuzzy !== undefined;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface ConfiguredModelRouting {
|
|
240
|
+
requested?: string;
|
|
241
|
+
candidates: string[];
|
|
242
|
+
reason?: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function buildConfiguredModelRouting(input: {
|
|
246
|
+
overrideModel?: string;
|
|
247
|
+
stepModel?: string;
|
|
248
|
+
teamRoleModel?: string;
|
|
249
|
+
agentModel?: string;
|
|
250
|
+
fallbackModels?: string[];
|
|
251
|
+
parentModel?: unknown;
|
|
252
|
+
modelRegistry?: unknown;
|
|
253
|
+
cwd?: string;
|
|
254
|
+
}): ConfiguredModelRouting {
|
|
255
|
+
const registryModels = availableModelInfosFromRegistry(input.modelRegistry);
|
|
256
|
+
const configModels = configuredModelInfosFromPiConfig(input.cwd);
|
|
257
|
+
const availableModels = registryModels && registryModels.length > 0 ? registryModels : configModels.length > 0 ? configModels : registryModels;
|
|
258
|
+
const parentModel = modelStringFromUnknown(input.parentModel);
|
|
259
|
+
const preferredProvider = parentModel?.split("/")[0] ?? availableModels?.[0]?.provider;
|
|
260
|
+
// B3: Parent model inheritance — when agent has no model specified,
|
|
261
|
+
// inherit from parent session model before falling back to defaults.
|
|
262
|
+
const effectiveAgentModel = input.agentModel?.trim() ? input.agentModel : parentModel;
|
|
263
|
+
const requested = [input.overrideModel, input.stepModel, input.teamRoleModel, effectiveAgentModel].find((model): model is string => Boolean(model?.trim()));
|
|
264
|
+
if (availableModels && availableModels.length === 0) return { requested, candidates: [], reason: "no configured Pi models available" };
|
|
265
|
+
const rawModels = availableModels
|
|
266
|
+
? [input.overrideModel, input.stepModel, input.teamRoleModel, effectiveAgentModel, ...(input.fallbackModels ?? []), ...availableModels.map((model) => model.fullId)]
|
|
267
|
+
: [input.overrideModel, input.stepModel, input.teamRoleModel, effectiveAgentModel, ...(input.fallbackModels ?? []), parentModel];
|
|
268
|
+
const configuredModels = rawModels
|
|
269
|
+
.filter((model): model is string => Boolean(model?.trim()))
|
|
270
|
+
.filter((model) => isAvailableModel(model.trim(), availableModels));
|
|
271
|
+
const candidates = buildModelCandidates(configuredModels[0], configuredModels.slice(1), availableModels, preferredProvider);
|
|
272
|
+
const reason = requested && candidates[0] && resolveModelCandidate(requested, availableModels, preferredProvider) !== candidates[0]
|
|
273
|
+
? "requested model unavailable; selected configured Pi fallback"
|
|
274
|
+
: candidates.length > 1
|
|
275
|
+
? "configured Pi fallback chain"
|
|
276
|
+
: undefined;
|
|
277
|
+
return { requested, candidates, reason };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function buildConfiguredModelCandidates(input: Parameters<typeof buildConfiguredModelRouting>[0]): string[] {
|
|
281
|
+
return buildConfiguredModelRouting(input).candidates;
|
|
282
|
+
}
|