@piagent/platform 1.5.5 → 1.6.1
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 +166 -0
- package/README.md +25 -21
- package/README.vi.md +34 -5
- package/adapters/web-frontend/profile.json +2 -4
- package/architecture/layers.json +18 -3
- package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
- package/benchmarks/deep-logic-v1/grade.mjs +272 -10
- package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
- package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
- package/benchmarks/deep-logic-v1/project/package.json +1 -1
- package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
- package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
- package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
- package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
- package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
- package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
- package/benchmarks/deep-logic-v1/suite.json +51 -3
- package/benchmarks/deep-logic-v1/variant.mjs +22 -1
- package/benchmarks/production-v1/spend-control.v1.json +92 -0
- package/benchmarks/production-v1/suite.json +46 -3
- package/catalog/capabilities.json +18 -18
- package/docs/authority-manifest.md +1 -1
- package/docs/auto-delegation-policy.md +38 -73
- package/docs/command-reference-vietnamese.md +27 -35
- package/docs/context-engine.md +12 -4
- package/docs/context-window-policy.md +37 -1
- package/docs/distribution-standard.md +7 -7
- package/docs/en/architecture.md +27 -13
- package/docs/languages.json +4 -4
- package/docs/model-options.md +8 -5
- package/docs/operator-manual-vietnamese.md +27 -45
- package/docs/project-adapters.md +2 -2
- package/docs/publishing-for-teams.md +10 -0
- package/docs/quality-benchmark.md +427 -62
- package/docs/release-install-policy.md +10 -9
- package/docs/runtime-harness-standard.md +3 -3
- package/docs/runtime-policy-design.md +4 -4
- package/docs/runtime-quality-baseline.md +13 -6
- package/docs/security-threat-model.md +2 -2
- package/docs/subagent-orchestration-capabilities.md +19 -51
- package/docs/subagents-and-multiagent.md +21 -47
- package/docs/task-implementation-contract.md +3 -3
- package/docs/task-lifecycle-vietnamese.md +3 -3
- package/docs/team-onboarding.md +2 -2
- package/docs/usage-observability.md +7 -2
- package/docs/vi/architecture.md +27 -13
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +89 -95
- package/docs-site/commands.html +1 -1
- package/docs-site/content/benchmark.html +88 -94
- package/docs-site/content/en/benchmark.html +134 -90
- package/docs-site/content/en/index.html +19 -19
- package/docs-site/content/en/runtime.html +4 -4
- package/docs-site/content/en/whats-new.html +12 -1
- package/docs-site/content/en/workflows.html +2 -2
- package/docs-site/content/index.html +19 -19
- package/docs-site/content/runtime.html +4 -4
- package/docs-site/content/whats-new.html +12 -1
- package/docs-site/content/workflows.html +2 -2
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +135 -91
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +20 -20
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +5 -5
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +13 -2
- package/docs-site/en/workflows.html +3 -3
- package/docs-site/index.html +20 -20
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +5 -5
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +13 -2
- package/docs-site/workflows.html +3 -3
- package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
- package/evals/fixtures/codex-relative-efficiency-v1.invalid.json +4 -0
- package/evals/fixtures/codex-relative-efficiency-v1.valid.json +94 -0
- package/evals/fixtures/helper-request.invalid.json +1 -1
- package/evals/fixtures/helper-request.valid.json +1 -1
- package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
- package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
- package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +7 -0
- package/evals/fixtures/task-authority-snapshot.valid.json +4 -4
- package/evals/fs4-readiness-matrix.v1.json +2 -2
- package/evals/fs5-causal-arm.v1.json +3 -3
- package/evals/fs5-pilot-protocol.v1.json +3 -3
- package/evals/fs5-pilot-protocol.v2.json +8 -8
- package/evals/fs5-pilot-protocol.v3.json +8 -8
- package/evals/fs5-pilot-protocol.v4.json +7 -6
- package/evals/fs5-pilot-protocol.v5.json +9 -7
- package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
- package/evals/runtime-conformance-v1/README.md +43 -0
- package/evals/runtime-conformance-v1/evaluate-paid-canary.mjs +198 -0
- package/evals/runtime-conformance-v1/lane.json +57 -0
- package/evals/runtime-conformance-v1/paid-canary.json +31 -0
- package/evals/runtime-conformance-v1/runner.mjs +456 -0
- package/package.json +3 -1
- package/packages/piagent-core/README.md +13 -4
- package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
- package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
- package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
- package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +698 -0
- package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
- package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
- package/packages/piagent-core/benchmark/benchmark-core.js +736 -664
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
- package/packages/piagent-core/benchmark/benchmark-forensics.js +441 -4
- package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
- package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
- package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
- package/packages/piagent-core/benchmark/benchmark-preflight.js +5 -1
- package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
- package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +345 -0
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +252 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +130 -12
- package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
- package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
- package/packages/piagent-core/benchmark/benchmark-runtime-causal.js +244 -0
- package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +979 -0
- package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
- package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
- package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
- package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
- package/packages/piagent-core/benchmark/benchmark-suite.js +149 -2
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +380 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
- package/packages/piagent-core/benchmark/benchmark-usage.js +322 -0
- package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
- package/packages/piagent-core/capabilities/runtime-integrity.js +3 -0
- package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
- package/packages/piagent-core/extensions/acceptance-behavior-proof.js +806 -0
- package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
- package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
- package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
- package/packages/piagent-core/extensions/acceptance-receipt.js +123 -59
- package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
- package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
- package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
- package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
- package/packages/piagent-core/extensions/context-engine.js +149 -156
- package/packages/piagent-core/extensions/context-evidence.js +48 -0
- package/packages/piagent-core/extensions/context-import-links.js +296 -0
- package/packages/piagent-core/extensions/context-index-policy.js +4 -0
- package/packages/piagent-core/extensions/context-query-paths.js +57 -0
- package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
- package/packages/piagent-core/extensions/criterion-context-pack.js +435 -7
- package/packages/piagent-core/extensions/criterion-graph.js +82 -9
- package/packages/piagent-core/extensions/fallback-base-policy.ts +101 -0
- package/packages/piagent-core/extensions/guard-types.ts +6 -0
- package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +420 -260
- package/packages/piagent-core/extensions/task-contract-view.js +17 -3
- package/packages/piagent-core/extensions/task-lifecycle.js +39 -2
- package/packages/piagent-core/extensions/task-state.js +109 -142
- package/packages/piagent-core/extensions/verification-intelligence.js +52 -13
- package/packages/piagent-core/extensions/workspace-evidence-roots.js +193 -0
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/policies/base-policy.json +44 -2
- package/packages/piagent-core/policy/authority-manifest.v1.json +3 -3
- package/packages/piagent-core/prompts/be-to-fe.md +2 -8
- package/packages/piagent-core/prompts/plan.md +1 -1
- package/packages/piagent-core/prompts/platform-improve.md +2 -6
- package/packages/piagent-core/prompts/review.md +2 -7
- package/packages/piagent-core/prompts/scout.md +1 -1
- package/packages/piagent-core/prompts/task.md +4 -3
- package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
- package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
- package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
- package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
- package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
- package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
- package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
- package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
- package/packages/piagent-core/runtime/hooks/completion-hook.ts +12 -12
- package/packages/piagent-core/runtime/hooks/input-hook.ts +17 -1
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +107 -3
- package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +134 -166
- package/packages/piagent-core/runtime/hooks/tool-result-value-helpers.ts +66 -0
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
- package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
- package/packages/piagent-core/runtime/inspection/bounded-emission-guard.ts +286 -0
- package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +37 -7
- package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +27 -4
- package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +70 -0
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +73 -9
- package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
- package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
- package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
- package/packages/piagent-core/runtime/orchestration/helper-lifecycle.ts +16 -12
- package/packages/piagent-core/runtime/orchestration/minimal-delegation-policy.ts +71 -0
- package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +28 -20
- package/packages/piagent-core/runtime/orchestration/role-policy.ts +27 -9
- package/packages/piagent-core/runtime/orchestration/subagent-tool-policy.ts +329 -0
- package/packages/piagent-core/runtime/policy/block-remedy.ts +0 -4
- package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +7 -2
- package/packages/piagent-core/runtime/quality/edit-freshness-guard.ts +102 -0
- package/packages/piagent-core/runtime/quality/exact-output-contract.ts +22 -11
- package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
- package/packages/piagent-core/runtime/quality/performance-assurance.ts +9 -5
- package/packages/piagent-core/runtime/recovery/continuation-budget.ts +1 -1
- package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
- package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
- package/packages/piagent-core/runtime/recovery/handoff-projection.ts +4 -1
- package/packages/piagent-core/runtime/recovery/pristine-task-policy-refresh.ts +91 -0
- package/packages/piagent-core/runtime/recovery/recovery-policy.ts +7 -4
- package/packages/piagent-core/runtime/recovery/resume-state.ts +112 -14
- package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +60 -13
- package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
- package/packages/piagent-core/runtime/recovery/task-evidence-coverage-refresh.ts +217 -0
- package/packages/piagent-core/runtime/registration/context-commands.ts +82 -7
- package/packages/piagent-core/runtime/registration/knowledge-tools.ts +9 -5
- package/packages/piagent-core/runtime/registration/operator-request-intake.ts +49 -0
- package/packages/piagent-core/runtime/registration/policy-tools.ts +50 -15
- package/packages/piagent-core/runtime/registration/session-commands.ts +1 -1
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +61 -25
- package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +21 -12
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +169 -0
- package/packages/piagent-core/runtime/registration/task-start-manifest.ts +54 -0
- package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +108 -103
- package/packages/piagent-core/runtime/runtime-limits.ts +16 -2
- package/packages/piagent-core/runtime/session/adaptive-context-analysis.ts +461 -0
- package/packages/piagent-core/runtime/session/adaptive-context-governor.ts +464 -0
- package/packages/piagent-core/runtime/session/adaptive-context-ledger.ts +265 -0
- package/packages/piagent-core/runtime/session/message-signals.ts +7 -3
- package/packages/piagent-core/runtime/session/operator-request-carry.ts +44 -0
- package/packages/piagent-core/runtime/session/runtime-state.ts +161 -5
- package/packages/piagent-core/runtime/session/source-checkout-read-grants.ts +35 -0
- package/packages/piagent-core/runtime/session/system-prompt.ts +76 -14
- package/packages/piagent-core/runtime/session/task-contract-presentation.ts +39 -0
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
- package/packages/piagent-core/runtime/tools/phase-tools.ts +8 -8
- package/packages/piagent-core/runtime/tools/tool-groups.ts +12 -2
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
- package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +101 -0
- package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +164 -0
- package/packages/piagent-core/runtime/workflows/task-intake.ts +207 -38
- package/packages/piagent-core/security/sensitive-data.js +13 -218
- package/packages/piagent-core/security/sensitive-project-file.js +42 -0
- package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
- package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
- package/packages/piagent-core/security/sensitive-text.js +234 -0
- package/packages/piagent-core/subagents/piagent-oracle.md +5 -3
- package/packages/piagent-core/subagents/piagent-planner.md +6 -4
- package/packages/piagent-core/subagents/piagent-reviewer.md +5 -3
- package/packages/piagent-core/subagents/piagent-scout.md +4 -2
- package/packages/piagent-core/subagents/piagent-worker.md +7 -5
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-B4XehTCU.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/extension/piagent-webui.ts +3 -1
- package/packages/piagent-webui/extension/same-session-bridge.ts +1 -1
- package/packages/piagent-webui/extension/session-stream-adapter.ts +33 -10
- package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
- package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +122 -20
- package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
- package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
- package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
- package/packages/piagent-webui/gateway/session-operation-lifecycle.ts +237 -0
- package/packages/piagent-webui/gateway/session-operation-retry-control.ts +38 -0
- package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
- package/packages/piagent-webui/gateway/session-operation-watchdog.ts +165 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +141 -125
- package/packages/piagent-webui/ownership/session-lease-store.ts +5 -2
- package/packages/piagent-webui/server/core-inspection-provider.ts +2 -1
- package/packages/piagent-webui/server/loopback-server.ts +8 -0
- package/packages/piagent-webui/server/transcript-projection.ts +113 -9
- package/packages/piagent-webui/shared/text-visibility.ts +10 -0
- package/schemas/codex-relative-efficiency-v1.schema.json +155 -0
- package/schemas/piagent-webui/catalog-v1.json +9 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
- package/schemas/piagent-webui/runtime-event-v2.schema.json +15 -5
- package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
- package/schemas/piagent-webui/subagent-tree-v1.schema.json +11 -1
- package/schemas/project-profile.schema.json +1 -1
- package/schemas/task-contract.schema.json +27 -1
- package/scripts/benchmark-runner-core.mjs +367 -363
- package/scripts/benchmark-runner-finalization.mjs +313 -0
- package/scripts/benchmark-runner-host-readiness.mjs +94 -0
- package/scripts/benchmark-runner-support.mjs +200 -0
- package/scripts/benchmark-session.mjs +95 -41
- package/scripts/configure-model-scope.sh +4 -3
- package/scripts/configure-subagents.sh +42 -34
- package/scripts/helper-evaluation.mjs +2 -2
- package/scripts/install-global.sh +2 -2
- package/scripts/pi-usage-history.mjs +37 -10
- package/scripts/setup.sh +2 -2
- package/scripts/team-doctor.sh +1 -1
- package/scripts/verify-local.sh +10 -1
- package/templates/global/settings.json +2 -1
- package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { TaskContract } from "../../extensions/guard-types.ts";
|
|
5
|
+
import { readTaskJournal } from "../../extensions/task-journal.js";
|
|
6
|
+
import {
|
|
7
|
+
directChildGitEvidenceRoots,
|
|
8
|
+
normalizedGitPath
|
|
9
|
+
} from "../../extensions/workspace-evidence-roots.js";
|
|
10
|
+
import {
|
|
11
|
+
workingTreeSnapshot,
|
|
12
|
+
workingTreeSnapshotHasUnavailableEvidence
|
|
13
|
+
} from "../../extensions/task-state.js";
|
|
14
|
+
import { workingTreeEvidenceDigest } from "../../extensions/working-tree-digest.js";
|
|
15
|
+
import { readMutationProvenance } from "../inspection/mutation-provenance-store.ts";
|
|
16
|
+
import { readTaskBaselineManifest } from "../inspection/source-evidence-store.ts";
|
|
17
|
+
|
|
18
|
+
// Some filesystems expose timestamps at coarse granularity. Requiring a clear
|
|
19
|
+
// pre-task gap prevents a file created in the same timestamp bucket as task
|
|
20
|
+
// startup from being mistaken for legacy baseline state.
|
|
21
|
+
const LEGACY_EVIDENCE_TIMESTAMP_SAFETY_MS = 2_000;
|
|
22
|
+
|
|
23
|
+
export type TaskEvidenceCoverageRefresh = {
|
|
24
|
+
task: TaskContract;
|
|
25
|
+
refreshed: boolean;
|
|
26
|
+
reason: string;
|
|
27
|
+
addedPaths: string[];
|
|
28
|
+
retainedMutationPaths: string[];
|
|
29
|
+
ambiguousPaths: string[];
|
|
30
|
+
previousBaselineDigest: string;
|
|
31
|
+
nextBaselineDigest: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function strings(value: unknown): string[] {
|
|
35
|
+
return Array.isArray(value)
|
|
36
|
+
? [...new Set(value.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
|
|
37
|
+
.map((item) => normalizedGitPath(item).replace(/\/$/, "")))]
|
|
38
|
+
: [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function decodedMutationPath(value: unknown): string | undefined {
|
|
42
|
+
if (typeof value !== "string" || value.length > 8192 || !/^[A-Za-z0-9_-]*$/.test(value)) return undefined;
|
|
43
|
+
try {
|
|
44
|
+
const decoded = Buffer.from(value, "base64url").toString("utf8");
|
|
45
|
+
const normalized = normalizedGitPath(decoded);
|
|
46
|
+
return normalized && normalized !== "." && normalized !== ".." && !normalized.startsWith("../")
|
|
47
|
+
? normalized
|
|
48
|
+
: undefined;
|
|
49
|
+
} catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function journalMutationPaths(cwd: string, taskRunId: string): { paths: string[]; corruptions: string[] } {
|
|
55
|
+
const journal = readTaskJournal(cwd, { taskRunId });
|
|
56
|
+
const paths: string[] = [];
|
|
57
|
+
for (const event of journal.events) {
|
|
58
|
+
if (event.eventType !== "checkpoint" || event.taskRunId !== taskRunId) continue;
|
|
59
|
+
const evidence = event.data?.evidence;
|
|
60
|
+
if (!evidence || typeof evidence !== "object" || Array.isArray(evidence)) continue;
|
|
61
|
+
paths.push(...strings((evidence as Record<string, unknown>).files));
|
|
62
|
+
paths.push(...strings((evidence as Record<string, unknown>).targetPaths));
|
|
63
|
+
}
|
|
64
|
+
return { paths: [...new Set(paths)].sort(), corruptions: journal.corruptions };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function provenanceMutationPaths(cwd: string, taskRunId: string): { paths: string[]; corruptions: string[] } {
|
|
68
|
+
const provenance = readMutationProvenance(cwd, taskRunId);
|
|
69
|
+
const paths = provenance.records.flatMap((record) => record.changes
|
|
70
|
+
.map((change) => decodedMutationPath(change.repoPathBase64))
|
|
71
|
+
.filter((item): item is string => Boolean(item)));
|
|
72
|
+
return { paths: [...new Set(paths)].sort(), corruptions: provenance.corruptions };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isLegacyLooseHiddenPath(file: string, childGitPrefixes: string[]): boolean {
|
|
76
|
+
const normalized = normalizedGitPath(file);
|
|
77
|
+
if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../")) return false;
|
|
78
|
+
if (childGitPrefixes.some((prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`))) return false;
|
|
79
|
+
return normalized.split("/").some((segment) => segment.startsWith(".") && segment.length > 1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function fileStatePredatesTask(cwd: string, file: string, createdAt: string): boolean {
|
|
83
|
+
const taskStartedAt = Date.parse(createdAt);
|
|
84
|
+
if (!Number.isFinite(taskStartedAt)) return false;
|
|
85
|
+
const absolute = path.resolve(cwd, file);
|
|
86
|
+
const relative = path.relative(cwd, absolute);
|
|
87
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) return false;
|
|
88
|
+
|
|
89
|
+
// The legacy inventory has no content digest for this path. Metadata that is
|
|
90
|
+
// older than the task is the only local positive evidence that the exact file
|
|
91
|
+
// state existed before task execution. A symlink, unreadable component, zero
|
|
92
|
+
// timestamp, or any task-time ctime/mtime remains an ordinary task delta.
|
|
93
|
+
let current = cwd;
|
|
94
|
+
try {
|
|
95
|
+
for (const segment of relative.split(path.sep).filter(Boolean)) {
|
|
96
|
+
current = path.join(current, segment);
|
|
97
|
+
const component = fs.lstatSync(current);
|
|
98
|
+
if (component.isSymbolicLink()) return false;
|
|
99
|
+
}
|
|
100
|
+
const stat = fs.lstatSync(absolute);
|
|
101
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return false;
|
|
102
|
+
const timestamps = [stat.birthtimeMs, stat.ctimeMs, stat.mtimeMs];
|
|
103
|
+
const latestSafeTimestamp = taskStartedAt - LEGACY_EVIDENCE_TIMESTAMP_SAFETY_MS;
|
|
104
|
+
return timestamps.every((value) => Number.isFinite(value) && value > 0 && value <= latestSafeTimestamp);
|
|
105
|
+
} catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function manifestProvenBaselinePaths(
|
|
111
|
+
cwd: string,
|
|
112
|
+
task: TaskContract,
|
|
113
|
+
previousBaseline: Record<string, string>,
|
|
114
|
+
current: Record<string, string>,
|
|
115
|
+
candidates: string[]
|
|
116
|
+
): string[] {
|
|
117
|
+
if (candidates.length === 0) return [];
|
|
118
|
+
try {
|
|
119
|
+
const manifest = readTaskBaselineManifest(cwd, task.taskRunId);
|
|
120
|
+
if (!manifest || manifest.taskId !== task.taskId || manifest.taskRunId !== task.taskRunId) return [];
|
|
121
|
+
const expanded = { ...previousBaseline };
|
|
122
|
+
for (const file of candidates) expanded[file] = current[file];
|
|
123
|
+
return workingTreeEvidenceDigest(expanded) === manifest.baselineTreeDigest ? candidates : [];
|
|
124
|
+
} catch {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Reconcile the one coverage gap introduced when parent-workspace evidence
|
|
131
|
+
* began including hidden project source. Only paths the legacy collector could
|
|
132
|
+
* not see are adopted, and any path with durable mutation evidence remains a
|
|
133
|
+
* real task delta. Existing baseline entries are never rewritten.
|
|
134
|
+
*/
|
|
135
|
+
export function refreshLegacyHiddenWorkspaceEvidenceCoverage(
|
|
136
|
+
cwd: string,
|
|
137
|
+
task: TaskContract
|
|
138
|
+
): TaskEvidenceCoverageRefresh {
|
|
139
|
+
const previousBaseline = task.baselineFileDigests ?? {};
|
|
140
|
+
const previousBaselineDigest = workingTreeEvidenceDigest(previousBaseline);
|
|
141
|
+
const unchanged = (
|
|
142
|
+
reason: string,
|
|
143
|
+
retainedMutationPaths: string[] = [],
|
|
144
|
+
ambiguousPaths: string[] = []
|
|
145
|
+
): TaskEvidenceCoverageRefresh => ({
|
|
146
|
+
task,
|
|
147
|
+
refreshed: false,
|
|
148
|
+
reason,
|
|
149
|
+
addedPaths: [],
|
|
150
|
+
retainedMutationPaths,
|
|
151
|
+
ambiguousPaths,
|
|
152
|
+
previousBaselineDigest,
|
|
153
|
+
nextBaselineDigest: previousBaselineDigest
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
if (task.trace.outcome !== "pending" || task.changeMode !== "source-change") return unchanged("task-not-refreshable");
|
|
157
|
+
if (!previousBaseline || typeof previousBaseline !== "object" || Array.isArray(previousBaseline)) return unchanged("baseline-unavailable");
|
|
158
|
+
const childGitPrefixes = directChildGitEvidenceRoots(cwd).map((root) => normalizedGitPath(root.prefix)).filter(Boolean);
|
|
159
|
+
if (childGitPrefixes.length === 0) return unchanged("not-parent-multi-repo-workspace");
|
|
160
|
+
|
|
161
|
+
const current = workingTreeSnapshot(cwd) as Record<string, string>;
|
|
162
|
+
if (workingTreeSnapshotHasUnavailableEvidence(current)) return unchanged("current-evidence-unavailable");
|
|
163
|
+
const candidates = Object.keys(current)
|
|
164
|
+
.filter((file) => previousBaseline[file] === undefined && isLegacyLooseHiddenPath(file, childGitPrefixes))
|
|
165
|
+
.sort();
|
|
166
|
+
if (candidates.length === 0) return unchanged("coverage-current");
|
|
167
|
+
|
|
168
|
+
const journal = journalMutationPaths(cwd, task.taskRunId);
|
|
169
|
+
const provenance = provenanceMutationPaths(cwd, task.taskRunId);
|
|
170
|
+
if (journal.corruptions.length > 0 || provenance.corruptions.length > 0) {
|
|
171
|
+
return unchanged("mutation-evidence-unavailable");
|
|
172
|
+
}
|
|
173
|
+
const mutated = new Set([
|
|
174
|
+
...strings(task.observedChangedFiles),
|
|
175
|
+
...strings(task.changedFiles),
|
|
176
|
+
...journal.paths,
|
|
177
|
+
...provenance.paths
|
|
178
|
+
]);
|
|
179
|
+
const retainedMutationPaths = candidates.filter((file) => mutated.has(file));
|
|
180
|
+
const unclaimedCandidates = candidates.filter((file) => !mutated.has(file));
|
|
181
|
+
// A current, integrity-validated baseline manifest is stronger than file
|
|
182
|
+
// timestamps: if adding the currently observed missing paths reconstructs
|
|
183
|
+
// its exact task-start tree digest, none of those paths changed after start.
|
|
184
|
+
// Legacy manifests that did not cover the paths simply fail this equality
|
|
185
|
+
// and retain the conservative timestamp fallback.
|
|
186
|
+
const manifestProven = new Set(manifestProvenBaselinePaths(cwd, task, previousBaseline, current, unclaimedCandidates));
|
|
187
|
+
const addedPaths = unclaimedCandidates.filter((file) => manifestProven.has(file) || fileStatePredatesTask(cwd, file, task.createdAt));
|
|
188
|
+
const added = new Set(addedPaths);
|
|
189
|
+
const ambiguousPaths = unclaimedCandidates.filter((file) => !added.has(file));
|
|
190
|
+
if (addedPaths.length === 0) {
|
|
191
|
+
return unchanged(
|
|
192
|
+
ambiguousPaths.length > 0 ? "coverage-candidates-ambiguous" : "coverage-candidates-have-mutation-evidence",
|
|
193
|
+
retainedMutationPaths,
|
|
194
|
+
ambiguousPaths
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const baselineFileDigests = { ...previousBaseline };
|
|
199
|
+
for (const file of addedPaths) baselineFileDigests[file] = current[file];
|
|
200
|
+
const refreshed: TaskContract = {
|
|
201
|
+
...task,
|
|
202
|
+
baselineChangedFiles: Object.keys(baselineFileDigests).sort(),
|
|
203
|
+
baselineFileDigests
|
|
204
|
+
};
|
|
205
|
+
return {
|
|
206
|
+
task: refreshed,
|
|
207
|
+
refreshed: true,
|
|
208
|
+
reason: ambiguousPaths.length > 0
|
|
209
|
+
? "legacy-hidden-workspace-coverage-partially-expanded"
|
|
210
|
+
: "legacy-hidden-workspace-coverage-expanded",
|
|
211
|
+
addedPaths,
|
|
212
|
+
retainedMutationPaths,
|
|
213
|
+
ambiguousPaths,
|
|
214
|
+
previousBaselineDigest,
|
|
215
|
+
nextBaselineDigest: workingTreeEvidenceDigest(baselineFileDigests)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { stageContextDelivery } from "../context/context-delivery.ts";
|
|
3
|
+
import { semanticCompactionCancelled } from "../session/system-prompt.ts";
|
|
2
4
|
|
|
3
5
|
type ExtensionContext = any;
|
|
4
6
|
|
|
@@ -10,7 +12,7 @@ export function registerContextCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
10
12
|
contextIndexV2Status, crypto, emitRuntimeMessage, ensureContextIndexV2, estimateContextTokens,
|
|
11
13
|
formatContextPreflight,
|
|
12
14
|
formatCount, formatPercent, fs, helpersMode, loadProfileFromContext, memoryHandbookPath,
|
|
13
|
-
policy, projectFilePath, resolveMemorySettings, resolveOrchestrationPolicy, searchContextIndex,
|
|
15
|
+
policy, projectFilePath, resolveMemorySettings, resolveOrchestrationPolicy, retrievalKey, runtimeState, searchContextIndex,
|
|
14
16
|
searchContextIndexV2, selectRuntimeAction, semanticCompactionInstructions, telemetry
|
|
15
17
|
} = deps;
|
|
16
18
|
function emitContextIndexSearch(ctx: ExtensionContext, query: string): void {
|
|
@@ -123,6 +125,7 @@ export function registerContextCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
123
125
|
});
|
|
124
126
|
telemetry(ctx, {
|
|
125
127
|
event: "context_pack",
|
|
128
|
+
turnId: runtimeState.currentTurn(ctx)?.turnId,
|
|
126
129
|
queryHash: pack.queryHash,
|
|
127
130
|
confidence: pack.confidence,
|
|
128
131
|
candidates: pack.candidates,
|
|
@@ -131,12 +134,65 @@ export function registerContextCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
131
134
|
selectedPaths: pack.selected.map((item) => item.path),
|
|
132
135
|
source: "command"
|
|
133
136
|
});
|
|
137
|
+
const task = activeSessionTask(ctx.cwd, ctx.sessionManager.getSessionId());
|
|
138
|
+
const deliveryId = task?.trace?.outcome === "pending" && pack.selected.length > 0 ? crypto.randomUUID() : undefined;
|
|
139
|
+
if (deliveryId) {
|
|
140
|
+
stageContextDelivery(ctx, {
|
|
141
|
+
deliveryId,
|
|
142
|
+
taskRunId: task.taskRunId,
|
|
143
|
+
turnId: runtimeState.currentTurn(ctx)?.turnId,
|
|
144
|
+
entries: pack.selected.map((item) => ({
|
|
145
|
+
path: item.path,
|
|
146
|
+
reason: "Runtime confirmed delivery of a /context pack message."
|
|
147
|
+
})),
|
|
148
|
+
pack: {
|
|
149
|
+
retrievalKey: retrievalKey(ctx, query),
|
|
150
|
+
queryHash: pack.queryHash,
|
|
151
|
+
confidence: pack.confidence,
|
|
152
|
+
estimatedTokens: pack.estimatedTokens,
|
|
153
|
+
paths: pack.selected.map((item) => item.path)
|
|
154
|
+
},
|
|
155
|
+
injection: {
|
|
156
|
+
source: "context-command",
|
|
157
|
+
queryHash: pack.queryHash,
|
|
158
|
+
confidence: pack.confidence,
|
|
159
|
+
estimatedTokens: pack.estimatedTokens,
|
|
160
|
+
selectedItems: pack.selected.map((item) => ({
|
|
161
|
+
path: item.path,
|
|
162
|
+
estimatedTokens: item.estimatedTokens,
|
|
163
|
+
sources: item.sources,
|
|
164
|
+
links: item.links,
|
|
165
|
+
fileContentHash: item.fileContentHash,
|
|
166
|
+
...(item.sanitizedContentDigest ? { sanitizedContentDigest: item.sanitizedContentDigest } : {}),
|
|
167
|
+
payloadHash: item.payloadHash,
|
|
168
|
+
representation: item.representation,
|
|
169
|
+
ranges: item.ranges,
|
|
170
|
+
generation: item.generation,
|
|
171
|
+
sensitiveContentRedacted: item.sensitiveContentRedacted
|
|
172
|
+
}))
|
|
173
|
+
}
|
|
174
|
+
}, { state: runtimeState, telemetry });
|
|
175
|
+
}
|
|
134
176
|
emitRuntimeMessage(ctx, "piagent-context-pack-v2", pack.text, {
|
|
135
177
|
queryHash: pack.queryHash,
|
|
136
178
|
confidence: pack.confidence,
|
|
137
179
|
estimatedTokens: pack.estimatedTokens,
|
|
138
180
|
paths: pack.selected.map((item) => item.path),
|
|
139
|
-
|
|
181
|
+
selectedItems: pack.selected.map((item) => ({
|
|
182
|
+
path: item.path,
|
|
183
|
+
estimatedTokens: item.estimatedTokens,
|
|
184
|
+
sources: item.sources,
|
|
185
|
+
links: item.links,
|
|
186
|
+
fileContentHash: item.fileContentHash,
|
|
187
|
+
...(item.sanitizedContentDigest ? { sanitizedContentDigest: item.sanitizedContentDigest } : {}),
|
|
188
|
+
payloadHash: item.payloadHash,
|
|
189
|
+
representation: item.representation,
|
|
190
|
+
ranges: item.ranges,
|
|
191
|
+
generation: item.generation,
|
|
192
|
+
sensitiveContentRedacted: item.sensitiveContentRedacted
|
|
193
|
+
})),
|
|
194
|
+
finderRecommended: pack.finderRecommended,
|
|
195
|
+
contextDelivery: deliveryId ? { schemaVersion: 1, deliveryId } : undefined
|
|
140
196
|
});
|
|
141
197
|
}
|
|
142
198
|
|
|
@@ -156,13 +212,19 @@ export function registerContextCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
156
212
|
const report = buildContextEfficiencyReport(ctx.cwd);
|
|
157
213
|
const task = activeSessionTask(ctx);
|
|
158
214
|
const taskEfficiency = task ? buildTaskEfficiencyMetrics(ctx.cwd, task) : null;
|
|
215
|
+
const wasteScore = report.metrics.contextWasteScore === null
|
|
216
|
+
? `unavailable (diagnostic estimate ${report.metrics.contextWasteScoreEstimate}/100; evidence ${formatPercent(report.metrics.contextWasteScoreEvidenceCoverage)}, ${report.coverage.wasteScore.status})`
|
|
217
|
+
: `${report.metrics.contextWasteScore}/100 (lower is better; evidence ${formatPercent(report.metrics.contextWasteScoreEvidenceCoverage)}, ${report.coverage.wasteScore.status})`;
|
|
159
218
|
emitRuntimeMessage(ctx, "piagent-context-efficiency", [
|
|
160
|
-
`contextWasteScore: ${
|
|
219
|
+
`contextWasteScore: ${wasteScore}`,
|
|
161
220
|
`activeTools: ${report.metrics.averageActiveTools}`,
|
|
162
|
-
`
|
|
163
|
-
`
|
|
221
|
+
`toolSchemaPrefixShare: ${formatPercent(report.metrics.toolSchemaPrefixShare)}`,
|
|
222
|
+
`toolSchemaToSystemRatio: ${report.metrics.toolSchemaToSystemRatio}`,
|
|
223
|
+
`duplicateReads: ${report.metrics.duplicateReads}/${report.metrics.comparableReadCalls} comparable (${report.metrics.readCalls} observed; coverage ${formatPercent(report.metrics.readEvidenceCoverage)})`,
|
|
224
|
+
`fallbackRereads: ${report.metrics.contextFallbackRereads}/${report.metrics.contextSelections}`,
|
|
164
225
|
`duplicateOutput: ${formatPercent(report.metrics.duplicateOutputRate)}`,
|
|
165
226
|
`lowConfidencePacks: ${report.metrics.lowConfidencePacks}/${report.sample.contextPacks}`,
|
|
227
|
+
`editRecovery: ${report.metrics.editRecoveryContextCount}/${report.metrics.editRecoveryFailures} failures returned context; ${report.metrics.editRecoverySuppressedFailures} suppressed; ${report.metrics.editRecoveryEstimatedTokens} estimated tokens; classification coverage ${formatPercent(report.metrics.editRecoveryFailureEvidenceCoverage)}`,
|
|
166
228
|
`taskEfficiency: ${taskEfficiency ? `${taskEfficiency.solver.route}; verify=${taskEfficiency.verification.attempts}; outcome=${taskEfficiency.outcome.task}` : "no active task"}`,
|
|
167
229
|
...report.recommendations.map((recommendation) => `- ${recommendation}`)
|
|
168
230
|
].join("\n"), { ...report, taskEfficiency });
|
|
@@ -175,6 +237,19 @@ export function registerContextCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
175
237
|
function compactCurrentSession(ctx: ExtensionContext): void {
|
|
176
238
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
177
239
|
const instructions = semanticCompactionInstructions(ctx.cwd, sessionId);
|
|
240
|
+
if (semanticCompactionCancelled(instructions)) {
|
|
241
|
+
telemetry(ctx, {
|
|
242
|
+
event: "compaction_cancelled",
|
|
243
|
+
mode: "semantic",
|
|
244
|
+
reason: "lossless-task-truth-exceeds-carry-target",
|
|
245
|
+
hasTaskContract: Boolean(compactSessionTask(ctx.cwd, sessionId))
|
|
246
|
+
});
|
|
247
|
+
ctx.ui.notify("Piagent kept the current context because compacting it would lose required task details.", "warning");
|
|
248
|
+
emitRuntimeMessage(ctx, "piagent-context-compaction-cancelled", instructions, {
|
|
249
|
+
reason: "lossless-task-truth-exceeds-carry-target"
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
178
253
|
telemetry(ctx, {
|
|
179
254
|
event: "compaction_requested",
|
|
180
255
|
mode: "semantic",
|
|
@@ -367,10 +442,10 @@ export function registerContextCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
367
442
|
content: [
|
|
368
443
|
`mode: ${orchestration.defaultMode}`,
|
|
369
444
|
`helpersMode: ${helpersMode()}`,
|
|
370
|
-
`
|
|
445
|
+
`helpers: max ${orchestration.maxConcurrentSubagents} fresh read-only total; requires >=30% projected net token saving`,
|
|
371
446
|
`lenses: ${orchestration.defaultReviewLenses.join(", ")}`,
|
|
372
447
|
`fieldGuide: ${orchestration.fieldGuide.enabled ? `${fieldGuidePath} (${fieldGuideExists ? "exists" : "missing"})` : "off"}`,
|
|
373
|
-
"writer:
|
|
448
|
+
"writer: parent only; helper workers and retries are disabled"
|
|
374
449
|
].join("\n"),
|
|
375
450
|
display: true,
|
|
376
451
|
details: {
|
|
@@ -11,11 +11,11 @@ export function registerKnowledgeTools(pi: ExtensionAPI, deps: Record<string, an
|
|
|
11
11
|
registerPiagentTool(pi, {
|
|
12
12
|
name: "piagent_orchestration_policy",
|
|
13
13
|
label: "Piagent Orchestration Policy",
|
|
14
|
-
description: "Return
|
|
15
|
-
promptSnippet: "Use this before planning medium/large tasks so
|
|
14
|
+
description: "Return parent-direct helper limits, review lenses, model-role, and Field Guide policy for the current project.",
|
|
15
|
+
promptSnippet: "Use this before planning medium/large tasks so the parent stays direct and helper use remains a measured token optimization.",
|
|
16
16
|
promptGuidelines: [
|
|
17
|
-
"Default to the parent
|
|
18
|
-
"Use
|
|
17
|
+
"Default to the parent model working directly; review quality alone does not justify another model run.",
|
|
18
|
+
"Use at most one fresh read-only helper only with two independent lanes and at least 30% projected total token savings; never delegate implementation or retry a deterministic failure.",
|
|
19
19
|
"Treat Field Guide memory as advisory and verify it against current repository files."
|
|
20
20
|
],
|
|
21
21
|
parameters: Type.Object({
|
|
@@ -45,7 +45,9 @@ export function registerKnowledgeTools(pi: ExtensionAPI, deps: Record<string, an
|
|
|
45
45
|
path: fieldGuidePath,
|
|
46
46
|
exists: fieldGuideExists
|
|
47
47
|
},
|
|
48
|
-
|
|
48
|
+
helperBudget: "1-readonly-total/0-retries/0-writers",
|
|
49
|
+
minimumProjectedNetSaving: 0.3,
|
|
50
|
+
stance: "parent-direct; one fresh read-only helper only when runtime-measured net token savings justify it"
|
|
49
51
|
};
|
|
50
52
|
const text = params.detail === "full"
|
|
51
53
|
? JSON.stringify(payload, null, 2)
|
|
@@ -53,6 +55,8 @@ export function registerKnowledgeTools(pi: ExtensionAPI, deps: Record<string, an
|
|
|
53
55
|
`mode: ${payload.defaultMode}`,
|
|
54
56
|
`maxConcurrentSubagents: ${payload.maxConcurrentSubagents}`,
|
|
55
57
|
`helpersMode: ${payload.helpersMode}`,
|
|
58
|
+
`helperBudget: ${payload.helperBudget}`,
|
|
59
|
+
`minimumProjectedNetSaving: ${Math.round(payload.minimumProjectedNetSaving * 100)}%`,
|
|
56
60
|
`reviewLenses: ${payload.defaultReviewLenses.join(", ")}`,
|
|
57
61
|
`fieldGuide: ${payload.fieldGuide.enabled ? `${payload.fieldGuide.path} (${payload.fieldGuide.exists ? "exists" : "missing"})` : "off"}`,
|
|
58
62
|
`fieldGuidePolicy: ${payload.fieldGuide.writePolicy}, maxLines=${payload.fieldGuide.maxLines}`,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { OPERATOR_REQUEST_MAX_CHARS } from "../../extensions/task-state.js";
|
|
2
|
+
|
|
3
|
+
type SessionContext = {
|
|
4
|
+
sessionManager: {
|
|
5
|
+
getBranch?: () => unknown;
|
|
6
|
+
getEntries?: () => unknown;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function userMessageText(message: unknown): string {
|
|
11
|
+
if (!message || typeof message !== "object" || (message as Record<string, unknown>).role !== "user") return "";
|
|
12
|
+
const content = (message as Record<string, unknown>).content;
|
|
13
|
+
if (typeof content === "string") return content;
|
|
14
|
+
if (!Array.isArray(content)) return "";
|
|
15
|
+
// The host stores the exact operator prose in the first text block. Later
|
|
16
|
+
// text blocks may contain extracted attachment bodies and must not be copied
|
|
17
|
+
// into private task truth as if the operator typed them.
|
|
18
|
+
const first = content.find((block) => block && typeof block === "object"
|
|
19
|
+
&& (block as Record<string, unknown>).type === "text"
|
|
20
|
+
&& typeof (block as Record<string, unknown>).text === "string") as Record<string, unknown> | undefined;
|
|
21
|
+
return typeof first?.text === "string" ? first.text : "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function latestOperatorRequest(ctx: SessionContext): string | undefined {
|
|
25
|
+
let entries: unknown[] = [];
|
|
26
|
+
try {
|
|
27
|
+
const branch = ctx.sessionManager.getBranch?.();
|
|
28
|
+
entries = Array.isArray(branch) ? branch : [];
|
|
29
|
+
if (entries.length === 0) {
|
|
30
|
+
const all = ctx.sessionManager.getEntries?.();
|
|
31
|
+
entries = Array.isArray(all) ? all : [];
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
37
|
+
const entry = entries[index] as Record<string, any> | undefined;
|
|
38
|
+
if (entry?.type !== "message") continue;
|
|
39
|
+
const text = userMessageText(entry.message);
|
|
40
|
+
if (text.trim()) return text;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function boundedOperatorRequest(value: unknown, redactText: (value: string) => string): string | undefined {
|
|
46
|
+
if (typeof value !== "string" || !value.trim()) return undefined;
|
|
47
|
+
const redacted = redactText(value);
|
|
48
|
+
return Array.from(redacted).length <= OPERATOR_REQUEST_MAX_CHARS ? redacted : undefined;
|
|
49
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { stageContextDelivery } from "../context/context-delivery.ts";
|
|
3
|
+
import { formatContextEfficiencyReport } from "../context/context-efficiency-format.ts";
|
|
2
4
|
|
|
3
5
|
type PiagentToolGroup = any;
|
|
4
6
|
type TechStackManifest = any;
|
|
@@ -6,7 +8,7 @@ type TechStackManifest = any;
|
|
|
6
8
|
|
|
7
9
|
export function registerPolicyTools(pi: ExtensionAPI, deps: Record<string, any>): void {
|
|
8
10
|
const {
|
|
9
|
-
PIAGENT_TOOL_NAMES, READ_ONLY_TOOL_NAMES, StringEnum, Type, activateToolGroups,
|
|
11
|
+
PIAGENT_TOOL_NAMES, READ_ONLY_TOOL_NAMES, StringEnum, Type, activateToolGroups, activeSessionTask,
|
|
10
12
|
buildContextEfficiencyReport, buildContextIndexStatus, buildContextIndexV2, buildContextPack, buildContextPreflight,
|
|
11
13
|
buildTestImpact, buildUsageSnapshot, candidateFileBudget, contextBudgetConfig, contextIndexExcludePatterns,
|
|
12
14
|
contextIndexV2Status, crypto, dynamicToolsEnabled, effectiveProtectedPaths, ensureContextIndexV2,
|
|
@@ -28,7 +30,7 @@ export function registerPolicyTools(pi: ExtensionAPI, deps: Record<string, any>)
|
|
|
28
30
|
"When recovery is necessary, load only the smallest group that resolves the reported missing evidence."
|
|
29
31
|
],
|
|
30
32
|
parameters: Type.Object({
|
|
31
|
-
groups: Type.Array(StringEnum(["intake", "governance", "task", "recovery", "policy", "retrieval", "knowledge", "onboarding", "usage"] as const), { minItems: 1 })
|
|
33
|
+
groups: Type.Array(StringEnum(["intake", "governance", "task", "recovery", "policy", "retrieval", "source", "knowledge", "onboarding", "usage"] as const), { minItems: 1 })
|
|
32
34
|
}),
|
|
33
35
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
34
36
|
const groups = [...new Set(params.groups)] as PiagentToolGroup[];
|
|
@@ -142,7 +144,48 @@ export function registerPolicyTools(pi: ExtensionAPI, deps: Record<string, any>)
|
|
|
142
144
|
limit: 18,
|
|
143
145
|
excludePatterns
|
|
144
146
|
});
|
|
145
|
-
|
|
147
|
+
telemetry(ctx, { event: "context_pack", turnId: runtimeState.currentTurn(ctx)?.turnId, source: "context-tool", queryHash: pack.queryHash, confidence: pack.confidence, candidates: pack.candidates, selected: pack.selected.length, estimatedTokens: pack.estimatedTokens, selectedPaths: pack.selected.map((item) => item.path) });
|
|
148
|
+
const task = activeSessionTask(ctx.cwd, ctx.sessionManager.getSessionId());
|
|
149
|
+
const deliveryId = task?.trace?.outcome === "pending" && pack.selected.length > 0 ? crypto.randomUUID() : undefined;
|
|
150
|
+
if (deliveryId) {
|
|
151
|
+
const packRetrievalKey = retrievalKey(ctx, params.query);
|
|
152
|
+
stageContextDelivery(ctx, {
|
|
153
|
+
deliveryId,
|
|
154
|
+
taskRunId: task.taskRunId,
|
|
155
|
+
turnId: runtimeState.currentTurn(ctx)?.turnId,
|
|
156
|
+
entries: pack.selected.map((item) => ({
|
|
157
|
+
path: item.path,
|
|
158
|
+
reason: "Runtime confirmed delivery of an explicit Context Engine tool pack."
|
|
159
|
+
})),
|
|
160
|
+
pack: {
|
|
161
|
+
retrievalKey: packRetrievalKey,
|
|
162
|
+
queryHash: pack.queryHash,
|
|
163
|
+
confidence: pack.confidence,
|
|
164
|
+
estimatedTokens: pack.estimatedTokens,
|
|
165
|
+
paths: pack.selected.map((item) => item.path)
|
|
166
|
+
},
|
|
167
|
+
injection: {
|
|
168
|
+
source: "context-tool",
|
|
169
|
+
queryHash: pack.queryHash,
|
|
170
|
+
confidence: pack.confidence,
|
|
171
|
+
estimatedTokens: pack.estimatedTokens,
|
|
172
|
+
selectedItems: pack.selected.map((item) => ({
|
|
173
|
+
path: item.path,
|
|
174
|
+
estimatedTokens: item.estimatedTokens,
|
|
175
|
+
sources: item.sources,
|
|
176
|
+
links: item.links,
|
|
177
|
+
fileContentHash: item.fileContentHash,
|
|
178
|
+
...(item.sanitizedContentDigest ? { sanitizedContentDigest: item.sanitizedContentDigest } : {}),
|
|
179
|
+
payloadHash: item.payloadHash,
|
|
180
|
+
representation: item.representation,
|
|
181
|
+
ranges: item.ranges,
|
|
182
|
+
generation: item.generation,
|
|
183
|
+
sensitiveContentRedacted: item.sensitiveContentRedacted
|
|
184
|
+
}))
|
|
185
|
+
}
|
|
186
|
+
}, { state: runtimeState, telemetry });
|
|
187
|
+
}
|
|
188
|
+
result = { ...pack, text: undefined, status, contextDelivery: deliveryId ? { schemaVersion: 1, deliveryId } : undefined };
|
|
146
189
|
text = pack.text;
|
|
147
190
|
} else if (params.action === "impact") {
|
|
148
191
|
await ensureContextIndexV2(ctx.cwd, { excludePatterns, rebuildMissing: false });
|
|
@@ -156,15 +199,7 @@ export function registerPolicyTools(pi: ExtensionAPI, deps: Record<string, any>)
|
|
|
156
199
|
} else {
|
|
157
200
|
result = buildContextEfficiencyReport(ctx.cwd);
|
|
158
201
|
const report = result as ReturnType<typeof buildContextEfficiencyReport>;
|
|
159
|
-
text =
|
|
160
|
-
`contextWasteScore: ${report.metrics.contextWasteScore}/100 (lower is better)`,
|
|
161
|
-
`activeTools: ${report.metrics.averageActiveTools}`,
|
|
162
|
-
`toolSchemaShare: ${formatPercent(report.metrics.toolSchemaShare)}`,
|
|
163
|
-
`duplicateReads: ${report.metrics.duplicateReads}/${report.metrics.readCalls}`,
|
|
164
|
-
`duplicateOutput: ${formatPercent(report.metrics.duplicateOutputRate)}`,
|
|
165
|
-
`lowConfidencePacks: ${report.metrics.lowConfidencePacks}/${report.sample.contextPacks}`,
|
|
166
|
-
...report.recommendations.map((recommendation) => `- ${recommendation}`)
|
|
167
|
-
].join("\n");
|
|
202
|
+
text = formatContextEfficiencyReport(report, formatPercent);
|
|
168
203
|
}
|
|
169
204
|
telemetry(ctx, {
|
|
170
205
|
event: "context_engine_action",
|
|
@@ -394,8 +429,8 @@ export function registerPolicyTools(pi: ExtensionAPI, deps: Record<string, any>)
|
|
|
394
429
|
registerPiagentTool(pi, {
|
|
395
430
|
name: "piagent_task_gate_check",
|
|
396
431
|
label: "Piagent Task Gate Check",
|
|
397
|
-
description: "Check whether a governed task has enough context,
|
|
398
|
-
promptSnippet: "Use
|
|
432
|
+
description: "Check whether a governed task has enough context, current-tree exact verifier evidence, and trace before claiming done or rerunning verification.",
|
|
433
|
+
promptSnippet: "Use before final and before repeating an exact verifier; run only commands listed as missing for the current tree.",
|
|
399
434
|
parameters: Type.Object({
|
|
400
435
|
taskId: Type.String({ minLength: 1 }),
|
|
401
436
|
changedFiles: Type.Optional(Type.Array(Type.String()))
|
|
@@ -416,7 +451,7 @@ export function registerPolicyTools(pi: ExtensionAPI, deps: Record<string, any>)
|
|
|
416
451
|
...verifierCommandInstructions(result.missingVerifyCommands),
|
|
417
452
|
`warnings: ${result.warnings.join("; ") || "none"}`
|
|
418
453
|
].join("\n");
|
|
419
|
-
return { content: [{ type: "text", text }], details: { ...result, task: projected } };
|
|
454
|
+
return { content: [{ type: "text", text }], details: { ...result, task: projected ? { taskId: projected.taskId, taskRunId: projected.taskRunId } : undefined } };
|
|
420
455
|
}
|
|
421
456
|
});
|
|
422
457
|
|
|
@@ -334,7 +334,7 @@ export function registerSessionCommands(pi: ExtensionAPI, deps: Record<string, a
|
|
|
334
334
|
const approvals = feature ? [feature.externalAction ? "external-action" : "", feature.destructiveAction ? "destructive-action" : "", feature.permissionExpansion ? "permission-expansion" : ""].filter(Boolean) : [];
|
|
335
335
|
const modelRoute = feature ? await evaluateModelRoute?.(ctx, feature, snapshot) : undefined;
|
|
336
336
|
const retrievalRoute = feature ? await evaluateRetrievalRoute?.(ctx, feature) : undefined;
|
|
337
|
-
return { runtime: snapshot, modelRoute: modelRoute?.status === "ok" ? modelRoute.decision : null, retrievalRoute: retrievalRoute ?? null, scope: task?.scope ?? [], protectedPaths: effectiveProtectedPaths(policy, profile).readProtectedPaths, activeToolGroups: pi.getActiveTools(), helperMode: helpersMode(), helperBudget: "
|
|
337
|
+
return { runtime: snapshot, modelRoute: modelRoute?.status === "ok" ? modelRoute.decision : null, retrievalRoute: retrievalRoute ?? null, scope: task?.scope ?? [], protectedPaths: effectiveProtectedPaths(policy, profile).readProtectedPaths, activeToolGroups: pi.getActiveTools(), helperMode: helpersMode(), helperBudget: "1-readonly-total/0-retries/0-writers", executionBackend: "host", executionBoundary: "host execution is not a sandbox", approvals, blockers: feature?.protectedTarget ? ["protected-target"] : [], controlMode: evaluation.status === "ok" && evaluation.decision.mode === "shadow" ? "shadow" : resolveRuntimePolicy(profile).finalGate === "enforce" ? "enforce" : "assist" };
|
|
338
338
|
}
|
|
339
339
|
});
|
|
340
340
|
|