@nklisch/pi-enhanced 0.1.2 → 0.1.4
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 +7 -0
- package/README.md +3 -2
- package/node_modules/@nklisch/pi-clearance/README.md +10 -5
- package/node_modules/@nklisch/pi-clearance/docs/ARCHITECTURE.md +12 -7
- package/node_modules/@nklisch/pi-clearance/docs/CONFIGURATION.md +25 -35
- package/node_modules/@nklisch/pi-clearance/docs/DEVELOPER_GUIDE.md +30 -30
- package/node_modules/@nklisch/pi-clearance/docs/PACK_AUTHORING.md +5 -4
- package/node_modules/@nklisch/pi-clearance/docs/PRINCIPLES.md +14 -10
- package/node_modules/@nklisch/pi-clearance/docs/REFERENCE_PATTERNS.md +1 -1
- package/node_modules/@nklisch/pi-clearance/docs/REVIEWER_PROMPTS.md +12 -8
- package/node_modules/@nklisch/pi-clearance/docs/RULE_PACKS.md +1 -1
- package/node_modules/@nklisch/pi-clearance/docs/SPEC.md +7 -6
- package/node_modules/@nklisch/pi-clearance/docs/TUNE.md +2 -2
- package/node_modules/@nklisch/pi-clearance/docs/USER_GUIDE.md +7 -3
- package/node_modules/@nklisch/pi-clearance/docs/VISION.md +3 -3
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.darwin-arm64.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.darwin-x64.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.linux-arm64-gnu.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.linux-x64-gnu.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-arm64-msvc.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
- package/node_modules/@nklisch/pi-clearance/package.json +9 -5
- package/node_modules/@nklisch/pi-clearance/src/config/config-command-plans.ts +79 -3
- package/node_modules/@nklisch/pi-clearance/src/config/config-command-writer.ts +7 -1
- package/node_modules/@nklisch/pi-clearance/src/config/defaults.ts +42 -0
- package/node_modules/@nklisch/pi-clearance/src/config/gated-tools.ts +7 -0
- package/node_modules/@nklisch/pi-clearance/src/config/loader.ts +7 -1
- package/node_modules/@nklisch/pi-clearance/src/config/pack-enablement-writer.ts +1 -0
- package/node_modules/@nklisch/pi-clearance/src/config/paths.ts +14 -3
- package/node_modules/@nklisch/pi-clearance/src/config/persistence.ts +135 -0
- package/node_modules/@nklisch/pi-clearance/src/config/schema.ts +74 -26
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCase.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseCategory.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseExpectation.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseResult.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseResultOutcome.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialCaseSource.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialValidationReport.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/AdversarialValidationStatus.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashBlock.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashCommandShape.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashConditionalArm.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashControlConstruct.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashFlag.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashForLoopKeywordSpans.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashIteratorEntry.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashIteratorEntryKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashListOperator.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashLoopVariableReference.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFact.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFactContext.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFactProvenance.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFactProvenanceEntry.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashPathFacts.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashPipeline.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashStage.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BashStageProgram.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/BlockOperator.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CapturedOutcome.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CommandFamilyKey.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CommandFamilySummary.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CompileError.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CompositionOperator.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundBodyReason.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundFeatureReason.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundForm.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CompoundIteratorReason.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusEntry.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusExpectedLabel.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusFidelity.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusQueryModel.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusQuerySummary.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusQuerySummarySnapshot.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusRecord.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CorpusSource.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/CountByLabel.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/Decision.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/DecisionEffect.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/DecisionProvenance.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/DecisionSource.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/DiagnosticSeverity.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/EffectivePolicy.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/EmbeddedShellProjection.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/EnvironmentAssignment.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/IteratorSourceKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/LoopQuoteKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/LoopVariableUnknownReason.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/MatcherExpr.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/MutationShapeKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/MutationTrustBoundaryClassification.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/MutationTrustBoundaryKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PackCompileResult.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PackWarningLevel.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ParsedEvidence.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ParsedShapeSummary.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathAccess.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathFactProjectScope.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathFactsRequirement.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathFactsResolvedConfig.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathNormalization.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathScope.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathScopeMatcherExpr.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathScopeMatcherMode.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathUnknownReason.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PathUsageKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolOperation.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolPathInput.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolShape.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PiBuiltinToolSpec.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PiFileMutationToolName.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PiToolMutationFacts.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPack.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackDocLink.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackExample.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackMetadata.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyPackWarning.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/PolicyRule.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ProposalNotRunReason.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ProposalNotRunSeverity.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/QuoteKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/Redirect.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/RedirectStream.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/RedirectTargetKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayCorpus.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDelta.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaBlockedSummary.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaChangedRecord.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaFamily.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaImprovement.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaRegression.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaStatus.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayDeltaTransitionCount.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayPathFacts.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayReviewerMode.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayReviewerOutcome.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayStatus.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ReplayedDecision.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ShapeDiagnostic.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/SourceFidelity.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/SourceSpan.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/Substitution.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/SubstitutionKind.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolCallIdentity.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathAccess.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathFact.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathFactContext.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathFacts.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolPathUsage.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/ToolShape.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/UnknownPathBehavior.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/UnknownToolShape.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/contracts/index.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/index.ts +33 -2
- package/node_modules/@nklisch/pi-clearance/src/native/loader.ts +29 -42
- package/node_modules/@nklisch/pi-clearance/src/replay/reviewer-config-proposals.ts +7 -4
- package/node_modules/@nklisch/pi-clearance/src/runtime/allow-request-message.ts +21 -0
- package/node_modules/@nklisch/pi-clearance/src/runtime/auto-reviewer-read-models.ts +165 -8
- package/node_modules/@nklisch/pi-clearance/src/runtime/command-registry.ts +1 -1
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/allow.ts +26 -2
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/packs.ts +6 -6
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/scope.ts +5 -5
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/actions.ts +11 -0
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/dispatcher.ts +274 -1
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/model-options.ts +52 -0
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/native-ui.ts +54 -67
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/panels/reviewer.ts +19 -3
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/panels/scope.ts +2 -11
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/panels.ts +10 -1
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings/read-model.ts +47 -13
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/settings.ts +32 -37
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/status.ts +3 -0
- package/node_modules/@nklisch/pi-clearance/src/runtime/config-commands/types.ts +14 -5
- package/node_modules/@nklisch/pi-clearance/src/runtime/handler.ts +36 -0
- package/node_modules/@nklisch/pi-clearance/src/runtime/mode-prompt.ts +0 -1
- package/node_modules/@nklisch/pi-clearance/src/runtime/model-adapter.ts +5 -1
- package/node_modules/@nklisch/pi-clearance/src/runtime/reviewer-context.ts +73 -10
- package/node_modules/@nklisch/pi-clearance/src/runtime/reviewer-prompts.ts +186 -175
- package/node_modules/@nklisch/pi-clearance/src/runtime/reviewer.ts +26 -6
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/state/local-lock-filesystem.d.ts +23 -1
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/state/local-lock-filesystem.js +46 -50
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/state/local-lock-filesystem.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-package.js +2 -2
- package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-runtime.js +2 -2
- package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-lifecycle.js +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-package.js +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/README.md +41 -31
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/public.d.ts +2 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md +17 -11
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/VISION.md +14 -7
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/architecture.md +11 -19
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/comparison-with-upstream.md +58 -53
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/agent-type-resolution.ts +43 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/agent-types.ts +11 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/custom-agents.ts +13 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/default-agents.ts +0 -52
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/thinking-levels.ts +12 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/handlers/interrupt.ts +5 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/handlers/lifecycle.ts +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/index.ts +7 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +7 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/parent-snapshot.ts +11 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +26 -56
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +48 -9
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-state.ts +32 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +105 -17
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/composite-subagent-observer.ts +4 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/notification.ts +50 -46
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/renderer.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/subagent-events-observer.ts +15 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/runtime.ts +2 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service-adapter.ts +35 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service.ts +1 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/model-label.ts +19 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/prompts.ts +24 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/session-config.ts +11 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/settings.ts +70 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/agent-tool.ts +27 -10
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/background-spawner.ts +6 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +12 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-report.ts +17 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-tool.ts +13 -20
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/result-renderer.ts +6 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/spawn-config.ts +16 -16
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/steer-tool.ts +12 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/types.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +24 -11
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/display.ts +10 -7
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/glyphs.ts +7 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigation.ts +34 -25
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +30 -10
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/subagents-settings.ts +58 -13
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/widget-renderer.ts +32 -19
- package/node_modules/@nklisch/pi-plugins/package.json +3 -3
- package/package.json +1 -1
- package/test/verify-bundle.mjs +28 -1
|
@@ -6,6 +6,7 @@ import type { Subagent } from "#src/types";
|
|
|
6
6
|
export interface NotificationDetails {
|
|
7
7
|
id: string;
|
|
8
8
|
description: string;
|
|
9
|
+
modelLabel: string;
|
|
9
10
|
status: string;
|
|
10
11
|
toolUses: number;
|
|
11
12
|
turnCount: number;
|
|
@@ -19,9 +20,14 @@ export interface NotificationDetails {
|
|
|
19
20
|
|
|
20
21
|
// ---- Pure helpers (exported for unit testing) ----
|
|
21
22
|
|
|
22
|
-
/** Escape XML
|
|
23
|
+
/** Escape XML text and attribute delimiters in structured notifications. */
|
|
23
24
|
export function escapeXml(s: string): string {
|
|
24
|
-
return s
|
|
25
|
+
return s
|
|
26
|
+
.replace(/&/g, "&")
|
|
27
|
+
.replace(/</g, "<")
|
|
28
|
+
.replace(/>/g, ">")
|
|
29
|
+
.replace(/"/g, """)
|
|
30
|
+
.replace(/'/g, "'");
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
/** Human-readable status label for agent completion. */
|
|
@@ -49,7 +55,9 @@ export function formatTaskNotification(record: Subagent, resultMaxLen: number):
|
|
|
49
55
|
const ctxXml = contextPercent !== null ? `<context_percent>${Math.round(contextPercent)}</context_percent>` : "";
|
|
50
56
|
const compactXml = record.compactionCount ? `<compactions>${record.compactionCount}</compactions>` : "";
|
|
51
57
|
|
|
52
|
-
const resultPreview = record.
|
|
58
|
+
const resultPreview = record.stoppedWhileQueued
|
|
59
|
+
? "Agent was stopped while queued and never started. No work was performed."
|
|
60
|
+
: record.result
|
|
53
61
|
? record.result.length > resultMaxLen
|
|
54
62
|
? record.result.slice(0, resultMaxLen) + "\n...(truncated, use get_subagent_result for full output)"
|
|
55
63
|
: record.result
|
|
@@ -63,6 +71,7 @@ export function formatTaskNotification(record: Subagent, resultMaxLen: number):
|
|
|
63
71
|
toolCallId ? `<tool-use-id>${escapeXml(toolCallId)}</tool-use-id>` : null,
|
|
64
72
|
outputFile ? `<output-file>${escapeXml(outputFile)}</output-file>` : null,
|
|
65
73
|
`<status>${escapeXml(status)}</status>`,
|
|
74
|
+
`<model>${escapeXml(record.modelLabel)}</model>`,
|
|
66
75
|
`<summary>Subagent "${escapeXml(record.description)}" ${record.status}</summary>`,
|
|
67
76
|
`<result>${escapeXml(resultPreview)}</result>`,
|
|
68
77
|
`<usage><total_tokens>${totalTokens}</total_tokens><tool_uses>${record.toolUses}</tool_uses>${ctxXml}${compactXml}<duration_ms>${durationMs}</duration_ms></usage>`,
|
|
@@ -82,6 +91,7 @@ export function buildNotificationDetails(
|
|
|
82
91
|
return {
|
|
83
92
|
id: record.id,
|
|
84
93
|
description: record.description,
|
|
94
|
+
modelLabel: record.modelLabel,
|
|
85
95
|
status: record.status,
|
|
86
96
|
toolUses: record.toolUses,
|
|
87
97
|
turnCount: record.turnCount,
|
|
@@ -90,7 +100,9 @@ export function buildNotificationDetails(
|
|
|
90
100
|
durationMs: record.completedAt ? record.completedAt - record.startedAt : 0,
|
|
91
101
|
outputFile: record.outputFile,
|
|
92
102
|
error: record.error,
|
|
93
|
-
resultPreview: record.
|
|
103
|
+
resultPreview: record.stoppedWhileQueued
|
|
104
|
+
? "Agent was stopped while queued and never started. No work was performed."
|
|
105
|
+
: record.result
|
|
94
106
|
? record.result.length > resultMaxLen
|
|
95
107
|
? record.result.slice(0, resultMaxLen) + "…"
|
|
96
108
|
: record.result
|
|
@@ -127,17 +139,12 @@ export interface NotificationSystem {
|
|
|
127
139
|
dispose: () => void;
|
|
128
140
|
}
|
|
129
141
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const NUDGE_HOLD_MS = 200;
|
|
137
|
-
|
|
138
|
-
export class NotificationManager implements NotificationSystem, ResultDelivery {
|
|
139
|
-
private pendingNudges = new Map<string, ReturnType<typeof setTimeout>>();
|
|
140
|
-
private consumed = new Set<string>();
|
|
142
|
+
export class NotificationManager implements NotificationSystem {
|
|
143
|
+
// Pi cannot recall a queued followUp. Hold records while the parent run is
|
|
144
|
+
// active so consumption can be rechecked at the actual delivery boundary.
|
|
145
|
+
private pendingNudges = new Map<string, Subagent>();
|
|
146
|
+
private parentRunActive = false;
|
|
147
|
+
private disposed = false;
|
|
141
148
|
|
|
142
149
|
constructor(
|
|
143
150
|
private sendMessage: (
|
|
@@ -146,51 +153,46 @@ export class NotificationManager implements NotificationSystem, ResultDelivery {
|
|
|
146
153
|
) => void,
|
|
147
154
|
) {}
|
|
148
155
|
|
|
149
|
-
consume(id: string): void {
|
|
150
|
-
this.consumed.add(id);
|
|
151
|
-
this.cancelNudge(id);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
156
|
sendCompletion(record: Subagent): void {
|
|
155
|
-
if (this.
|
|
156
|
-
|
|
157
|
+
if (this.disposed || record.consumed) return;
|
|
158
|
+
if (this.parentRunActive) {
|
|
159
|
+
this.pendingNudges.set(record.id, record);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.emitIndividualNudge(record);
|
|
157
163
|
}
|
|
158
164
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
this.pendingNudges.clear();
|
|
162
|
-
this.consumed.clear();
|
|
165
|
+
onParentAgentStart(): void {
|
|
166
|
+
if (!this.disposed) this.parentRunActive = true;
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
169
|
+
onParentAgentSettled(): void {
|
|
170
|
+
if (this.disposed) return;
|
|
171
|
+
this.parentRunActive = false;
|
|
172
|
+
const withheld = [...this.pendingNudges.values()];
|
|
173
|
+
this.pendingNudges.clear();
|
|
174
|
+
for (const record of withheld) {
|
|
175
|
+
try {
|
|
176
|
+
this.emitIndividualNudge(record);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
debugLog("notification render", err);
|
|
179
|
+
}
|
|
170
180
|
}
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
|
|
174
|
-
this.
|
|
175
|
-
this.pendingNudges.
|
|
176
|
-
key,
|
|
177
|
-
setTimeout(() => {
|
|
178
|
-
this.pendingNudges.delete(key);
|
|
179
|
-
try {
|
|
180
|
-
send();
|
|
181
|
-
} catch (err) {
|
|
182
|
-
debugLog("notification render", err);
|
|
183
|
-
}
|
|
184
|
-
}, delay),
|
|
185
|
-
);
|
|
183
|
+
dispose(): void {
|
|
184
|
+
this.disposed = true;
|
|
185
|
+
this.pendingNudges.clear();
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
private emitIndividualNudge(record: Subagent): void {
|
|
189
|
-
if (this.
|
|
189
|
+
if (this.disposed || record.consumed) return;
|
|
190
190
|
|
|
191
191
|
const notification = formatTaskNotification(record, 500);
|
|
192
192
|
const outputFile = record.outputFile;
|
|
193
|
-
const footer =
|
|
193
|
+
const footer = !record.stoppedWhileQueued && outputFile
|
|
194
|
+
? `\nFull transcript available at: ${outputFile}`
|
|
195
|
+
: "";
|
|
194
196
|
|
|
195
197
|
this.sendMessage(
|
|
196
198
|
{
|
|
@@ -201,5 +203,7 @@ export class NotificationManager implements NotificationSystem, ResultDelivery {
|
|
|
201
203
|
},
|
|
202
204
|
{ deliverAs: "followUp", triggerTurn: true },
|
|
203
205
|
);
|
|
206
|
+
// Push delivery collected the terminal outcome just as surely as a pull.
|
|
207
|
+
record.markConsumed();
|
|
204
208
|
}
|
|
205
209
|
}
|
|
@@ -39,7 +39,7 @@ export function createNotificationRenderer() {
|
|
|
39
39
|
let line = `${icon} ${theme.bold(d.description)} ${theme.fg("dim", statusText)}`;
|
|
40
40
|
|
|
41
41
|
// Line 2: stats
|
|
42
|
-
const parts: string[] = [];
|
|
42
|
+
const parts: string[] = [d.modelLabel];
|
|
43
43
|
if (d.turnCount > 0) parts.push(formatTurns(d.turnCount, d.maxTurns));
|
|
44
44
|
if (d.toolUses > 0) parts.push(`${d.toolUses} tool use${d.toolUses === 1 ? "" : "s"}`);
|
|
45
45
|
if (d.totalTokens > 0) parts.push(formatTokens(d.totalTokens));
|
|
@@ -68,6 +68,21 @@ export class SubagentEventsObserver implements SubagentManagerObserver {
|
|
|
68
68
|
this.notifications.sendCompletion(record);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
onSubagentResumed(record: Subagent): void {
|
|
72
|
+
const eventData = buildEventData(record);
|
|
73
|
+
this.emit("subagents:resumed", eventData);
|
|
74
|
+
this.appendEntry("subagents:record", {
|
|
75
|
+
id: record.id,
|
|
76
|
+
type: record.type,
|
|
77
|
+
description: record.description,
|
|
78
|
+
status: record.status,
|
|
79
|
+
result: record.result,
|
|
80
|
+
error: record.error,
|
|
81
|
+
startedAt: record.startedAt,
|
|
82
|
+
completedAt: record.completedAt,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
71
86
|
onSubagentCompacted(record: Subagent, info: CompactionInfo): void {
|
|
72
87
|
// Emit compacted event when agent's session compacts (preserves count on record).
|
|
73
88
|
this.emit("subagents:compacted", {
|
|
@@ -18,6 +18,8 @@ import type { SessionContext } from "#src/types";
|
|
|
18
18
|
export interface RunConfig {
|
|
19
19
|
readonly defaultMaxTurns: number | undefined;
|
|
20
20
|
readonly graceTurns: number;
|
|
21
|
+
readonly consumedSessionRetentionMinutes?: number;
|
|
22
|
+
readonly unconsumedSessionRetentionMinutes?: number;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Model } from "@earendil-works/pi-ai";
|
|
9
|
+
import { resolveDispatchAgentType } from "#src/config/agent-type-resolution";
|
|
10
|
+
import type { AgentTypeRegistry } from "#src/config/agent-types";
|
|
9
11
|
import type {
|
|
10
12
|
SubagentLifecycleInterceptor,
|
|
11
13
|
SubagentLifecycleRegistration,
|
|
@@ -13,8 +15,10 @@ import type {
|
|
|
13
15
|
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
14
16
|
import type { WorkspaceProvider } from "#src/lifecycle/workspace";
|
|
15
17
|
import type { SpawnOptions, SubagentRecord, SubagentsService } from "#src/service/service";
|
|
18
|
+
import { formatModelLabel } from "#src/session/model-label";
|
|
16
19
|
import type { ModelRegistry } from "#src/session/model-resolver";
|
|
17
|
-
import
|
|
20
|
+
import { resolveDefaultModel } from "#src/session/session-config";
|
|
21
|
+
import type { AgentInvocation, SessionContext, Subagent } from "#src/types";
|
|
18
22
|
|
|
19
23
|
/** Narrow interface for the SubagentManager — avoids coupling to the concrete class. */
|
|
20
24
|
export interface SubagentManagerLike {
|
|
@@ -46,6 +50,8 @@ export class SubagentsServiceAdapter implements SubagentsService {
|
|
|
46
50
|
private readonly manager: SubagentManagerLike,
|
|
47
51
|
private readonly resolveModel: (input: string, registry: ModelRegistry) => Model<any> | string,
|
|
48
52
|
private readonly runtime: ServiceRuntimeLike,
|
|
53
|
+
private readonly agentRegistry?: AgentTypeRegistry,
|
|
54
|
+
private readonly settings?: { readonly fallbackSubagent?: string | false },
|
|
49
55
|
) {}
|
|
50
56
|
|
|
51
57
|
spawn(type: string, prompt: string, options?: SpawnOptions): string {
|
|
@@ -53,13 +59,28 @@ export class SubagentsServiceAdapter implements SubagentsService {
|
|
|
53
59
|
throw new Error("No active session — cannot spawn agents outside a session.");
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
this.agentRegistry?.reload();
|
|
63
|
+
const resolution = this.agentRegistry
|
|
64
|
+
? resolveDispatchAgentType(type, this.agentRegistry, this.settings?.fallbackSubagent)
|
|
65
|
+
: { type, requestedType: type, fellBack: false };
|
|
66
|
+
if ("error" in resolution) throw new Error(resolution.error);
|
|
67
|
+
const resolvedType = resolution.type;
|
|
68
|
+
|
|
69
|
+
const model = options?.model
|
|
70
|
+
? this.resolveModelOption(options.model)
|
|
71
|
+
: this.resolveTypeDefaultModel(resolvedType);
|
|
57
72
|
const description = options?.description ?? prompt.slice(0, 80);
|
|
58
73
|
const isBackground = !(options?.foreground ?? false);
|
|
74
|
+
const invocation: AgentInvocation = {
|
|
75
|
+
modelName: formatModelLabel(model),
|
|
76
|
+
maxTurns: options?.maxTurns,
|
|
77
|
+
inheritContext: options?.inheritContext,
|
|
78
|
+
runInBackground: isBackground,
|
|
79
|
+
};
|
|
59
80
|
|
|
60
81
|
const snapshot = this.runtime.buildSnapshot(options?.inheritContext ?? false);
|
|
61
82
|
const parent = this.runtime.getSessionInfo();
|
|
62
|
-
return this.manager.spawn(snapshot,
|
|
83
|
+
return this.manager.spawn(snapshot, resolvedType, prompt, {
|
|
63
84
|
description,
|
|
64
85
|
model,
|
|
65
86
|
maxTurns: options?.maxTurns,
|
|
@@ -68,6 +89,7 @@ export class SubagentsServiceAdapter implements SubagentsService {
|
|
|
68
89
|
bypassQueue: options?.bypassQueue,
|
|
69
90
|
isBackground,
|
|
70
91
|
origin: "service",
|
|
92
|
+
invocation,
|
|
71
93
|
lifecycleParentSession: parent.parentSessionId
|
|
72
94
|
? {
|
|
73
95
|
parentSessionFile: parent.parentSessionFile || undefined,
|
|
@@ -117,9 +139,8 @@ export class SubagentsServiceAdapter implements SubagentsService {
|
|
|
117
139
|
return this.manager.registerLifecycleInterceptor(interceptor);
|
|
118
140
|
}
|
|
119
141
|
|
|
120
|
-
/** Resolve
|
|
121
|
-
private resolveModelOption(modelInput: string
|
|
122
|
-
if (!modelInput) return undefined;
|
|
142
|
+
/** Resolve a model-string override against the current session's registry. */
|
|
143
|
+
private resolveModelOption(modelInput: string): Model<any> {
|
|
123
144
|
const registry = this.runtime.currentCtx?.modelRegistry;
|
|
124
145
|
if (!registry) {
|
|
125
146
|
throw new Error("No model registry available.");
|
|
@@ -130,6 +151,14 @@ export class SubagentsServiceAdapter implements SubagentsService {
|
|
|
130
151
|
}
|
|
131
152
|
return resolved;
|
|
132
153
|
}
|
|
154
|
+
|
|
155
|
+
/** Resolve the agent type's configured model with the same fallback used by session assembly. */
|
|
156
|
+
private resolveTypeDefaultModel(type: string): Model<any> {
|
|
157
|
+
const ctx = this.runtime.currentCtx!;
|
|
158
|
+
const configured = this.agentRegistry?.resolveAgentConfig(type).model;
|
|
159
|
+
if (!ctx.modelRegistry) return ctx.model as Model<any>;
|
|
160
|
+
return resolveDefaultModel(ctx.model, ctx.modelRegistry, configured) as Model<any>;
|
|
161
|
+
}
|
|
133
162
|
}
|
|
134
163
|
|
|
135
164
|
/**
|
package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service.ts
CHANGED
|
@@ -125,6 +125,7 @@ export interface SubagentsService {
|
|
|
125
125
|
export const SUBAGENT_EVENTS = {
|
|
126
126
|
STARTED: "subagents:started",
|
|
127
127
|
COMPLETED: "subagents:completed",
|
|
128
|
+
RESUMED: "subagents:resumed",
|
|
128
129
|
FAILED: "subagents:failed",
|
|
129
130
|
COMPACTED: "subagents:compacted",
|
|
130
131
|
CREATED: "subagents:created",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Model } from "@earendil-works/pi-ai";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Return the exact display identity for a resolved model.
|
|
5
|
+
*
|
|
6
|
+
* Pi identifies models by provider and id. The human-readable `name` is not
|
|
7
|
+
* unique across providers, so operator status surfaces use `provider/id`.
|
|
8
|
+
*/
|
|
9
|
+
export function formatModelLabel(model: unknown): string {
|
|
10
|
+
if (isModelIdentity(model)) return `${model.provider}/${model.id}`;
|
|
11
|
+
return "unknown model";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isModelIdentity(value: unknown): value is Pick<Model<any>, "provider" | "id"> {
|
|
15
|
+
if (typeof value !== "object" || value === null) return false;
|
|
16
|
+
const candidate = value as { provider?: unknown; id?: unknown };
|
|
17
|
+
return typeof candidate.provider === "string" && candidate.provider.length > 0
|
|
18
|
+
&& typeof candidate.id === "string" && candidate.id.length > 0;
|
|
19
|
+
}
|
package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/prompts.ts
CHANGED
|
@@ -27,12 +27,14 @@ import type { AgentPromptConfig } from "#src/types";
|
|
|
27
27
|
* The tag follows the cacheable parent prefix in both modes.
|
|
28
28
|
*
|
|
29
29
|
* @param parentSystemPrompt The parent agent's effective system prompt.
|
|
30
|
+
* @param parentCwd Parent cwd used to remove a contradictory Pi footer.
|
|
30
31
|
*/
|
|
31
32
|
export function buildAgentPrompt(
|
|
32
33
|
config: AgentPromptConfig,
|
|
33
34
|
cwd: string,
|
|
34
35
|
env: EnvInfo,
|
|
35
36
|
parentSystemPrompt?: string,
|
|
37
|
+
parentCwd?: string,
|
|
36
38
|
): string {
|
|
37
39
|
const activeAgentTag = `<active_agent name="${config.name}"/>\n\n`;
|
|
38
40
|
|
|
@@ -41,7 +43,9 @@ Working directory: ${cwd}
|
|
|
41
43
|
${env.isGitRepo ? `Git repository: yes\nBranch: ${env.branch}` : "Not a git repository"}
|
|
42
44
|
Platform: ${env.platform}`;
|
|
43
45
|
|
|
44
|
-
const identity = parentSystemPrompt
|
|
46
|
+
const identity = parentSystemPrompt
|
|
47
|
+
? withoutContradictoryCwdFooter(parentSystemPrompt, parentCwd, cwd)
|
|
48
|
+
: genericBase;
|
|
45
49
|
|
|
46
50
|
if (config.promptMode === "append") {
|
|
47
51
|
|
|
@@ -85,6 +89,25 @@ You are operating as a sub-agent invoked to handle a specific task.
|
|
|
85
89
|
return identity + "\n\n" + activeAgentTag + envBlock + "\n\n" + config.systemPrompt;
|
|
86
90
|
}
|
|
87
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Pi appends an authoritative cwd line to the parent prompt. A workspace-backed
|
|
94
|
+
* child appends its own environment block, so retain that footer only when both
|
|
95
|
+
* sessions actually share a directory.
|
|
96
|
+
*/
|
|
97
|
+
function withoutContradictoryCwdFooter(
|
|
98
|
+
prompt: string,
|
|
99
|
+
parentCwd: string | undefined,
|
|
100
|
+
childCwd: string,
|
|
101
|
+
): string {
|
|
102
|
+
if (!parentCwd || toPromptPath(parentCwd) === toPromptPath(childCwd)) return prompt;
|
|
103
|
+
const footerLine = `Current working directory: ${toPromptPath(parentCwd)}`;
|
|
104
|
+
return prompt.split("\n").filter((line) => line !== footerLine).join("\n");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function toPromptPath(cwd: string): string {
|
|
108
|
+
return cwd.replaceAll("\\", "/");
|
|
109
|
+
}
|
|
110
|
+
|
|
88
111
|
/** Fallback base prompt when parent system prompt is unavailable (both modes). */
|
|
89
112
|
const genericBase = `# Role
|
|
90
113
|
You are a general-purpose coding agent for complex, multi-step tasks.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* before invoking this function, keeping the assembler synchronous.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type
|
|
13
|
+
import { type AgentConfigLookup, BUILTIN_TOOL_NAMES } from "#src/config/agent-types";
|
|
14
14
|
import type { EnvInfo } from "#src/session/env";
|
|
15
15
|
import type { AgentPromptConfig, SubagentType, ThinkingLevel } from "#src/types";
|
|
16
16
|
|
|
@@ -30,6 +30,7 @@ export interface AssemblerIO {
|
|
|
30
30
|
cwd: string,
|
|
31
31
|
env: EnvInfo,
|
|
32
32
|
parentPrompt?: string,
|
|
33
|
+
parentCwd?: string,
|
|
33
34
|
) => string;
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -79,8 +80,8 @@ export interface SessionConfig {
|
|
|
79
80
|
effectiveCwd: string;
|
|
80
81
|
/** Fully-assembled system prompt string (ready for `systemPromptOverride`). */
|
|
81
82
|
systemPrompt: string;
|
|
82
|
-
/** Built-in
|
|
83
|
-
|
|
83
|
+
/** Built-in tools denied to this agent; extension tools remain inheritable. */
|
|
84
|
+
excludedBuiltinToolNames: string[];
|
|
84
85
|
/**
|
|
85
86
|
* Resolved model instance (undefined → use parent model as passed to SDK).
|
|
86
87
|
* Opaque handle — the assembler passes it through without inspection.
|
|
@@ -102,7 +103,7 @@ export interface SessionConfig {
|
|
|
102
103
|
* string that resolves against the registry AND is in the available set, return
|
|
103
104
|
* that model instead.
|
|
104
105
|
*/
|
|
105
|
-
function resolveDefaultModel(
|
|
106
|
+
export function resolveDefaultModel(
|
|
106
107
|
parentModel: unknown,
|
|
107
108
|
registry: AssemblerContext["modelRegistry"],
|
|
108
109
|
configModel?: string,
|
|
@@ -155,7 +156,10 @@ export function assembleSessionConfig(
|
|
|
155
156
|
|
|
156
157
|
const effectiveCwd = options.cwd ?? ctx.cwd;
|
|
157
158
|
|
|
158
|
-
const
|
|
159
|
+
const enabledBuiltinTools = new Set(registry.getToolNamesForType(type));
|
|
160
|
+
const excludedBuiltinToolNames = BUILTIN_TOOL_NAMES.filter(
|
|
161
|
+
(name) => !enabledBuiltinTools.has(name),
|
|
162
|
+
);
|
|
159
163
|
|
|
160
164
|
// Build system prompt from the resolved agent config
|
|
161
165
|
const systemPrompt = io.buildAgentPrompt(
|
|
@@ -163,6 +167,7 @@ export function assembleSessionConfig(
|
|
|
163
167
|
effectiveCwd,
|
|
164
168
|
env,
|
|
165
169
|
ctx.parentSystemPrompt,
|
|
170
|
+
ctx.cwd,
|
|
166
171
|
);
|
|
167
172
|
|
|
168
173
|
// Model resolution: explicit option > config model string > parent model
|
|
@@ -179,7 +184,7 @@ export function assembleSessionConfig(
|
|
|
179
184
|
return {
|
|
180
185
|
effectiveCwd,
|
|
181
186
|
systemPrompt,
|
|
182
|
-
|
|
187
|
+
excludedBuiltinToolNames,
|
|
183
188
|
model,
|
|
184
189
|
thinkingLevel,
|
|
185
190
|
agentMaxTurns,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Persistence for pi-subagents operational settings.
|
|
2
2
|
// - Global: ~/.pi/agent/subagents.json (agentDir injected at construction) — manual defaults, never written here
|
|
3
|
-
// - Project: <cwd>/.pi/subagents.json — written by /
|
|
3
|
+
// - Project: <cwd>/.pi/subagents.json — written by /subagents:settings; overrides global on load
|
|
4
4
|
|
|
5
5
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
@@ -14,6 +14,11 @@ export interface SubagentsSettings {
|
|
|
14
14
|
*/
|
|
15
15
|
defaultMaxTurns?: number;
|
|
16
16
|
graceTurns?: number;
|
|
17
|
+
consumedSessionRetentionMinutes?: number;
|
|
18
|
+
unconsumedSessionRetentionMinutes?: number;
|
|
19
|
+
abortAllOnInterrupt?: boolean;
|
|
20
|
+
/** false or "none" fails closed; an agent name selects an explicit fallback. */
|
|
21
|
+
fallbackSubagent?: string | false;
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
|
|
@@ -22,15 +27,21 @@ export type SettingsEmit = (event: string, payload: unknown) => void;
|
|
|
22
27
|
|
|
23
28
|
const DEFAULT_MAX_CONCURRENT = 4;
|
|
24
29
|
const DEFAULT_GRACE_TURNS = 5;
|
|
30
|
+
const DEFAULT_CONSUMED_RETENTION_MINUTES = 10;
|
|
31
|
+
const DEFAULT_UNCONSUMED_RETENTION_MINUTES = 720;
|
|
25
32
|
|
|
26
33
|
/**
|
|
27
|
-
* Owns
|
|
34
|
+
* Owns runtime settings and their load/save/persist cycle.
|
|
28
35
|
* Replaces the scattered free-function + SettingsAppliers callback pattern.
|
|
29
36
|
*/
|
|
30
37
|
export class SettingsManager {
|
|
31
38
|
private _defaultMaxTurns: number | undefined = undefined;
|
|
32
39
|
private _graceTurns: number = DEFAULT_GRACE_TURNS;
|
|
33
40
|
private _maxConcurrent: number = DEFAULT_MAX_CONCURRENT;
|
|
41
|
+
private _consumedSessionRetentionMinutes = DEFAULT_CONSUMED_RETENTION_MINUTES;
|
|
42
|
+
private _unconsumedSessionRetentionMinutes = DEFAULT_UNCONSUMED_RETENTION_MINUTES;
|
|
43
|
+
private _abortAllOnInterrupt = true;
|
|
44
|
+
private _fallbackSubagent: string | false | undefined;
|
|
34
45
|
|
|
35
46
|
private readonly emit: SettingsEmit;
|
|
36
47
|
private readonly cwd: string;
|
|
@@ -78,6 +89,22 @@ export class SettingsManager {
|
|
|
78
89
|
this._maxConcurrent = Math.max(1, n);
|
|
79
90
|
}
|
|
80
91
|
|
|
92
|
+
get consumedSessionRetentionMinutes(): number { return this._consumedSessionRetentionMinutes; }
|
|
93
|
+
set consumedSessionRetentionMinutes(n: number) { this._consumedSessionRetentionMinutes = Math.max(0, n); }
|
|
94
|
+
|
|
95
|
+
get unconsumedSessionRetentionMinutes(): number { return this._unconsumedSessionRetentionMinutes; }
|
|
96
|
+
set unconsumedSessionRetentionMinutes(n: number) { this._unconsumedSessionRetentionMinutes = Math.max(0, n); }
|
|
97
|
+
|
|
98
|
+
get abortAllOnInterrupt(): boolean { return this._abortAllOnInterrupt; }
|
|
99
|
+
set abortAllOnInterrupt(value: boolean) { this._abortAllOnInterrupt = value; }
|
|
100
|
+
|
|
101
|
+
get fallbackSubagent(): string | false | undefined { return this._fallbackSubagent; }
|
|
102
|
+
set fallbackSubagent(value: string | false | undefined) {
|
|
103
|
+
this._fallbackSubagent = value === false || value === "none"
|
|
104
|
+
? false
|
|
105
|
+
: typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
81
108
|
// ── Lifecycle methods ──
|
|
82
109
|
|
|
83
110
|
/**
|
|
@@ -90,6 +117,10 @@ export class SettingsManager {
|
|
|
90
117
|
if (typeof settings.maxConcurrent === "number") this.maxConcurrent = settings.maxConcurrent;
|
|
91
118
|
if (typeof settings.defaultMaxTurns === "number") this.defaultMaxTurns = settings.defaultMaxTurns;
|
|
92
119
|
if (typeof settings.graceTurns === "number") this.graceTurns = settings.graceTurns;
|
|
120
|
+
if (typeof settings.consumedSessionRetentionMinutes === "number") this.consumedSessionRetentionMinutes = settings.consumedSessionRetentionMinutes;
|
|
121
|
+
if (typeof settings.unconsumedSessionRetentionMinutes === "number") this.unconsumedSessionRetentionMinutes = settings.unconsumedSessionRetentionMinutes;
|
|
122
|
+
if (typeof settings.abortAllOnInterrupt === "boolean") this.abortAllOnInterrupt = settings.abortAllOnInterrupt;
|
|
123
|
+
if (settings.fallbackSubagent !== undefined) this.fallbackSubagent = settings.fallbackSubagent;
|
|
93
124
|
this.emit("subagents:settings_loaded", { settings });
|
|
94
125
|
return settings;
|
|
95
126
|
}
|
|
@@ -98,11 +129,15 @@ export class SettingsManager {
|
|
|
98
129
|
* Snapshot current in-memory values for persistence.
|
|
99
130
|
* `defaultMaxTurns` uses 0 as the on-disk marker for unlimited (undefined).
|
|
100
131
|
*/
|
|
101
|
-
snapshot():
|
|
132
|
+
snapshot(): Required<SubagentsSettings> {
|
|
102
133
|
return {
|
|
103
134
|
maxConcurrent: this._maxConcurrent,
|
|
104
135
|
defaultMaxTurns: this._defaultMaxTurns ?? 0,
|
|
105
136
|
graceTurns: this._graceTurns,
|
|
137
|
+
consumedSessionRetentionMinutes: this._consumedSessionRetentionMinutes,
|
|
138
|
+
unconsumedSessionRetentionMinutes: this._unconsumedSessionRetentionMinutes,
|
|
139
|
+
abortAllOnInterrupt: this._abortAllOnInterrupt,
|
|
140
|
+
fallbackSubagent: this._fallbackSubagent ?? "general-purpose",
|
|
106
141
|
};
|
|
107
142
|
}
|
|
108
143
|
|
|
@@ -134,6 +169,27 @@ export class SettingsManager {
|
|
|
134
169
|
return this.saveAndNotify(`Grace turns set to ${this.graceTurns}`);
|
|
135
170
|
}
|
|
136
171
|
|
|
172
|
+
applyConsumedSessionRetention(n: number): { message: string; level: "info" | "warning" } {
|
|
173
|
+
this.consumedSessionRetentionMinutes = n;
|
|
174
|
+
return this.saveAndNotify(`Consumed session retention set to ${this.consumedSessionRetentionMinutes} minutes`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
applyUnconsumedSessionRetention(n: number): { message: string; level: "info" | "warning" } {
|
|
178
|
+
this.unconsumedSessionRetentionMinutes = n;
|
|
179
|
+
return this.saveAndNotify(`Unconsumed session retention set to ${this.unconsumedSessionRetentionMinutes} minutes`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
applyAbortAllOnInterrupt(value: boolean): { message: string; level: "info" | "warning" } {
|
|
183
|
+
this.abortAllOnInterrupt = value;
|
|
184
|
+
return this.saveAndNotify(`Abort all subagents on ESC ${value ? "enabled" : "disabled"}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
applyFallbackSubagent(value: string | false | undefined): { message: string; level: "info" | "warning" } {
|
|
188
|
+
this.fallbackSubagent = value;
|
|
189
|
+
const label = this.fallbackSubagent === false ? "none (fail closed)" : this.fallbackSubagent ?? "general-purpose";
|
|
190
|
+
return this.saveAndNotify(`Unknown agent fallback set to ${label}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
137
193
|
/**
|
|
138
194
|
* Persist the current snapshot, emit `subagents:settings_changed`,
|
|
139
195
|
* and return the toast the UI should display.
|
|
@@ -152,6 +208,7 @@ export class SettingsManager {
|
|
|
152
208
|
const MAX_CONCURRENT_CEILING = 1024;
|
|
153
209
|
const MAX_TURNS_CEILING = 10_000;
|
|
154
210
|
const GRACE_TURNS_CEILING = 1_000;
|
|
211
|
+
const RETENTION_MINUTES_CEILING = 60 * 24 * 365;
|
|
155
212
|
|
|
156
213
|
/** Drop fields that don't match the expected shape. Silent — garbage becomes absent. */
|
|
157
214
|
function sanitize(raw: unknown): SubagentsSettings {
|
|
@@ -179,6 +236,16 @@ function sanitize(raw: unknown): SubagentsSettings {
|
|
|
179
236
|
) {
|
|
180
237
|
out.graceTurns = r.graceTurns as number;
|
|
181
238
|
}
|
|
239
|
+
for (const key of ["consumedSessionRetentionMinutes", "unconsumedSessionRetentionMinutes"] as const) {
|
|
240
|
+
if (Number.isInteger(r[key]) && (r[key] as number) >= 0 && (r[key] as number) <= RETENTION_MINUTES_CEILING) {
|
|
241
|
+
out[key] = r[key] as number;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (typeof r.abortAllOnInterrupt === "boolean") out.abortAllOnInterrupt = r.abortAllOnInterrupt;
|
|
245
|
+
if (r.fallbackSubagent === false || r.fallbackSubagent === "none") out.fallbackSubagent = false;
|
|
246
|
+
else if (typeof r.fallbackSubagent === "string" && r.fallbackSubagent.trim()) {
|
|
247
|
+
out.fallbackSubagent = r.fallbackSubagent.trim();
|
|
248
|
+
}
|
|
182
249
|
return out;
|
|
183
250
|
}
|
|
184
251
|
|