@piagent/platform 1.5.4 → 1.6.0
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 +136 -0
- package/README.md +9 -8
- package/README.vi.md +9 -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 +68 -0
- package/benchmarks/production-v1/suite.json +42 -3
- package/catalog/capabilities.json +6 -6
- package/docs/command-reference-vietnamese.md +6 -6
- package/docs/context-engine.md +7 -1
- package/docs/distribution-standard.md +7 -7
- package/docs/en/architecture.md +1 -0
- package/docs/languages.json +4 -4
- package/docs/model-options.md +8 -5
- package/docs/operator-manual-vietnamese.md +13 -11
- package/docs/project-adapters.md +2 -2
- package/docs/publishing-for-teams.md +9 -0
- package/docs/quality-benchmark.md +271 -62
- package/docs/release-install-policy.md +10 -9
- 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/task-lifecycle-vietnamese.md +2 -2
- package/docs/team-onboarding.md +2 -2
- package/docs/usage-observability.md +7 -2
- package/docs/vi/architecture.md +1 -0
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +1 -1
- 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 +1 -1
- 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 +1 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +1 -1
- 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 +1 -1
- 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 +1 -1
- package/docs-site/workflows.html +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.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/fs4-readiness-matrix.v1.json +2 -2
- package/evals/fs5-causal-arm.v1.json +2 -2
- package/evals/fs5-pilot-protocol.v1.json +2 -2
- package/evals/fs5-pilot-protocol.v4.json +6 -5
- package/evals/fs5-pilot-protocol.v5.json +7 -6
- package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
- package/package.json +3 -1
- 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.js +3 -1
- package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
- package/packages/piagent-core/benchmark/benchmark-core.js +732 -661
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
- package/packages/piagent-core/benchmark/benchmark-forensics.js +439 -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 +3 -1
- package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +183 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +116 -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-stage-diagnostic.js +782 -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 +128 -2
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +376 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
- package/packages/piagent-core/benchmark/benchmark-usage.js +311 -0
- package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
- package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -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 +34 -11
- 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 +148 -145
- 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-telemetry-integrity.js +65 -0
- package/packages/piagent-core/extensions/criterion-context-pack.js +422 -7
- package/packages/piagent-core/extensions/criterion-graph.js +78 -8
- package/packages/piagent-core/extensions/guard-types.ts +3 -0
- package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +250 -43
- package/packages/piagent-core/extensions/policy-core.js +1 -1
- package/packages/piagent-core/extensions/task-contract-view.js +17 -3
- package/packages/piagent-core/extensions/task-lifecycle.js +7 -2
- package/packages/piagent-core/extensions/task-state.js +40 -134
- package/packages/piagent-core/extensions/verification-intelligence.js +3 -1
- package/packages/piagent-core/extensions/workspace-evidence-roots.js +157 -0
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/policies/base-policy.json +3 -0
- 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 +5 -6
- package/packages/piagent-core/runtime/hooks/input-hook.ts +11 -1
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +7 -2
- package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +84 -102
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +9 -3
- package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
- package/packages/piagent-core/runtime/inspection/approval-broker.ts +29 -5
- 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/tool-failure-classification.ts +53 -0
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +34 -6
- 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/role-policy.ts +1 -1
- package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +4 -2
- package/packages/piagent-core/runtime/quality/exact-output-contract.ts +2 -1
- package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
- package/packages/piagent-core/runtime/quality/performance-assurance.ts +6 -2
- 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/semantic-repair-handshake.ts +55 -2
- package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
- package/packages/piagent-core/runtime/registration/context-commands.ts +66 -5
- package/packages/piagent-core/runtime/registration/policy-tools.ts +46 -11
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +49 -16
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +163 -0
- package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +67 -62
- package/packages/piagent-core/runtime/session/runtime-state.ts +154 -2
- package/packages/piagent-core/runtime/session/system-prompt.ts +4 -4
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
- package/packages/piagent-core/runtime/workflows/task-intake.ts +43 -2
- 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-worker.md +1 -1
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-CxeZqTte.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-DynIMe8I.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +1 -1
- 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 +93 -7
- 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-start.ts +5 -1
- package/packages/piagent-webui/gateway/session-operation-watchdog.ts +158 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +139 -120
- package/packages/piagent-webui/server/loopback-server.ts +8 -0
- package/packages/piagent-webui/server/transcript-projection.ts +22 -4
- package/packages/piagent-webui/shared/text-visibility.ts +10 -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/session-live-state-v1.schema.json +76 -0
- package/schemas/task-contract.schema.json +12 -1
- package/scripts/benchmark-runner-core.mjs +355 -359
- package/scripts/benchmark-runner-finalization.mjs +309 -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/helper-evaluation.mjs +1 -1
- package/scripts/install-global.sh +2 -2
- package/scripts/pi-usage-history.mjs +37 -10
- package/scripts/piagent-dashboard.mjs +13 -1
- package/scripts/setup.sh +2 -2
- package/scripts/verify-local.sh +5 -1
- package/templates/global/settings.json +2 -1
- package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
ensureContextIndexV2,
|
|
8
8
|
estimateContextTokens
|
|
9
9
|
} from "../../extensions/context-engine.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
buildSelectedContextPack,
|
|
12
|
+
composeCriterionContextEntries
|
|
13
|
+
} from "../../extensions/criterion-context-pack.js";
|
|
11
14
|
import { matchesProtectedPath } from "../../extensions/policy-core.js";
|
|
12
15
|
import { selectRepositoryMemoryFacts } from "../../extensions/repository-memory.js";
|
|
13
16
|
import type { TaskContract } from "../../extensions/guard-types.js";
|
|
@@ -15,9 +18,12 @@ import {
|
|
|
15
18
|
contextPlanAcceptsConfidence,
|
|
16
19
|
planAdaptiveContext
|
|
17
20
|
} from "../context/adaptive-planner.ts";
|
|
21
|
+
import { stageContextDelivery } from "../context/context-delivery.ts";
|
|
22
|
+
import { measureContextDeltaShadow, type ContextDeltaShadowMode } from "../context/context-delta-shadow.ts";
|
|
23
|
+
import { buildPrefixTelemetry } from "../context/prefix-telemetry.ts";
|
|
24
|
+
import { formatRepositoryMemoryHints } from "../context/repository-memory-hints.ts";
|
|
18
25
|
import { modelCapabilityFromContext } from "../model/capabilities.ts";
|
|
19
26
|
import type { RuntimeModelSnapshot } from "../model/runtime-snapshot.ts";
|
|
20
|
-
import { runtimeModelSnapshotDigest } from "../model/runtime-snapshot.ts";
|
|
21
27
|
import type { ModelRouteEvaluation } from "../model/model-route-runtime.ts";
|
|
22
28
|
import { buildTaskResumeContext } from "../recovery/resume-state.ts";
|
|
23
29
|
import { planRetrievalRoute } from "../context/retrieval-route-policy.ts";
|
|
@@ -25,7 +31,7 @@ import type { SolverShadowEvaluation } from "../solver/solver-shadow.ts";
|
|
|
25
31
|
import { observeTrajectorySync } from "../trajectory/trajectory-observability.ts";
|
|
26
32
|
import type { TrajectorySyncOptions, TrajectorySyncResult } from "../trajectory/trajectory-runtime.ts";
|
|
27
33
|
import { trajectoryRecommendationRef } from "../trajectory/trajectory-runtime.ts";
|
|
28
|
-
import { RuntimeSessionState } from "../session/runtime-state.ts";
|
|
34
|
+
import { RuntimeSessionState, type ContextInjectionItem } from "../session/runtime-state.ts";
|
|
29
35
|
import {
|
|
30
36
|
compactManagedProjectInstructions,
|
|
31
37
|
rewriteLegacyProjectInstructions
|
|
@@ -37,16 +43,20 @@ import {
|
|
|
37
43
|
automaticTaskIntakeMode
|
|
38
44
|
} from "../workflows/task-intake.ts";
|
|
39
45
|
import { CONTEXT_PACK_MAX_TOKENS } from "../runtime-limits.ts";
|
|
46
|
+
import { modelRouteTelemetry, runtimeSnapshotTelemetry, solverShadowTelemetry } from "./agent-prompt-telemetry.ts";
|
|
40
47
|
|
|
41
48
|
type RuntimeIntakeResult = {
|
|
42
49
|
started: boolean;
|
|
43
50
|
text: string;
|
|
44
51
|
task?: TaskContract;
|
|
52
|
+
plannedContext?: Array<{ path: string; reason: string }>;
|
|
53
|
+
plannedContextComplete?: boolean;
|
|
45
54
|
};
|
|
46
55
|
|
|
47
56
|
type AgentStartHookDependencies = {
|
|
48
57
|
state: RuntimeSessionState;
|
|
49
58
|
autoContextEnabled: boolean;
|
|
59
|
+
contextDeltaShadowMode: ContextDeltaShadowMode;
|
|
50
60
|
activeTask: (ctx: ExtensionContext) => TaskContract | undefined;
|
|
51
61
|
readProtectedPaths: (ctx: ExtensionContext) => string[];
|
|
52
62
|
contextExcludePatterns: (ctx: ExtensionContext) => string[];
|
|
@@ -71,36 +81,18 @@ type AgentStartHookDependencies = {
|
|
|
71
81
|
telemetry: (ctx: ExtensionContext, payload: Record<string, unknown>) => void;
|
|
72
82
|
};
|
|
73
83
|
|
|
74
|
-
function formatRepositoryMemoryHints(candidates: Array<{
|
|
75
|
-
record: { id?: string; fact: string; citations: Array<{ path: string }> };
|
|
76
|
-
matchedTerms: string[];
|
|
77
|
-
}>, budgetTokens: number): { text: string; ids: string[] } {
|
|
78
|
-
if (budgetTokens < 80 || candidates.length === 0) return { text: "", ids: [] };
|
|
79
|
-
const lines = [
|
|
80
|
-
"[Piagent repository memory: advisory only]",
|
|
81
|
-
"Verify every hint against the cited current file before relying on it."
|
|
82
|
-
];
|
|
83
|
-
const ids: string[] = [];
|
|
84
|
-
for (const candidate of candidates) {
|
|
85
|
-
const paths = candidate.record.citations.slice(0, 4).map((citation) => citation.path).join(", ");
|
|
86
|
-
const line = `- ${candidate.record.fact.slice(0, 320)} [sources: ${paths}]`;
|
|
87
|
-
const proposed = [...lines, line].join("\n");
|
|
88
|
-
if (estimateContextTokens(proposed) > budgetTokens) break;
|
|
89
|
-
lines.push(line);
|
|
90
|
-
if (candidate.record.id) ids.push(candidate.record.id);
|
|
91
|
-
}
|
|
92
|
-
return ids.length > 0 ? { text: lines.join("\n"), ids } : { text: "", ids: [] };
|
|
93
|
-
}
|
|
94
|
-
|
|
95
84
|
export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStartHookDependencies): void {
|
|
96
85
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
97
86
|
const projectInstructions = rewriteLegacyProjectInstructions(event.systemPrompt);
|
|
98
87
|
const query = looksLikeGovernedBoilerplate(event.prompt) ? extractTaskRequest(event.prompt) : event.prompt.trim();
|
|
99
88
|
const signal = classifyContextTask(query);
|
|
89
|
+
const turn = dependencies.state.currentTurn(ctx, signal.promptHash) ?? dependencies.state.beginTurn(ctx, signal.promptHash);
|
|
100
90
|
const readProtectedPaths = dependencies.readProtectedPaths(ctx);
|
|
91
|
+
const protectedTarget = signal.paths.some((candidate) => matchesProtectedPath(candidate, readProtectedPaths));
|
|
101
92
|
const protectedOnlyTarget = signal.paths.length > 0
|
|
102
93
|
&& signal.paths.every((candidate) => matchesProtectedPath(candidate, readProtectedPaths));
|
|
103
|
-
const
|
|
94
|
+
const sessionTask = dependencies.activeTask(ctx);
|
|
95
|
+
const activeTask = sessionTask?.trace.outcome === "pending" ? sessionTask : undefined;
|
|
104
96
|
const runtimeIntakeMode = !activeTask ? automaticTaskIntakeMode(query, readProtectedPaths) : undefined;
|
|
105
97
|
const runtimeIntake = Boolean(runtimeIntakeMode);
|
|
106
98
|
const compactMode = protectedOnlyTarget
|
|
@@ -122,10 +114,10 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
122
114
|
.map((tool) => ({
|
|
123
115
|
name: tool.name,
|
|
124
116
|
description: tool.description,
|
|
125
|
-
parameters: tool.parameters
|
|
126
|
-
promptGuidelines: tool.promptGuidelines
|
|
117
|
+
parameters: tool.parameters
|
|
127
118
|
}));
|
|
128
|
-
const
|
|
119
|
+
const prefix = buildPrefixTelemetry(effectiveSystemPrompt, toolMetadata);
|
|
120
|
+
const toolSchemaTokens = estimateContextTokens(prefix.canonicalToolSurface);
|
|
129
121
|
const systemPromptTokens = estimateContextTokens(effectiveSystemPrompt);
|
|
130
122
|
const autoPackUseful = activeTask?.trace.outcome !== "pending"
|
|
131
123
|
&& (runtimeIntake || signal.paths.length === 0);
|
|
@@ -154,6 +146,7 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
154
146
|
if (activeTask) observeTrajectorySync(ctx, dependencies.syncTrajectory?.(ctx, activeTask, { sourceHook: "agent-start", recommendationRef }), dependencies.telemetry);
|
|
155
147
|
dependencies.telemetry(ctx, {
|
|
156
148
|
event: "agent_prompt",
|
|
149
|
+
turnId: turn.turnId,
|
|
157
150
|
promptHash: signal.promptHash,
|
|
158
151
|
promptChars: signal.promptChars,
|
|
159
152
|
workflow: signal.workflow,
|
|
@@ -162,56 +155,16 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
162
155
|
activePiagentTools: [...active].filter((toolName) => PIAGENT_TOOL_NAMES.has(toolName)).length,
|
|
163
156
|
toolSchemaTokens,
|
|
164
157
|
systemPromptTokens,
|
|
165
|
-
systemPromptHash:
|
|
158
|
+
systemPromptHash: prefix.systemPromptHash,
|
|
159
|
+
toolSchemaHash: prefix.toolSchemaHash,
|
|
160
|
+
prefixSurfaceHash: prefix.prefixSurfaceHash,
|
|
161
|
+
taskRunId: activeTask?.taskRunId,
|
|
166
162
|
legacyProjectInstructionsRewritten: projectInstructions.rewritten,
|
|
167
163
|
managedInstructionsCompacted: compactedInstructions.compacted,
|
|
168
164
|
contextUsage: ctx.getContextUsage(),
|
|
169
|
-
runtimeSnapshot: runtimeSnapshot
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
digest: runtimeModelSnapshotDigest(runtimeSnapshot),
|
|
173
|
-
provider: runtimeSnapshot.provider,
|
|
174
|
-
modelId: runtimeSnapshot.modelId,
|
|
175
|
-
contextWindow: runtimeSnapshot.contextWindow,
|
|
176
|
-
requestedThinkingLevel: runtimeSnapshot.requestedThinkingLevel,
|
|
177
|
-
effectiveThinkingLevel: runtimeSnapshot.effectiveThinkingLevel,
|
|
178
|
-
warningCount: runtimeSnapshot.warnings.length
|
|
179
|
-
}
|
|
180
|
-
: undefined,
|
|
181
|
-
solverShadow: solverShadow?.status === "ok"
|
|
182
|
-
? {
|
|
183
|
-
mode: solverShadow.decision.mode,
|
|
184
|
-
route: solverShadow.decision.route,
|
|
185
|
-
featureHash: solverShadow.features.featureHash,
|
|
186
|
-
reasonCodes: solverShadow.decision.reasonCodes,
|
|
187
|
-
confidence: solverShadow.decision.confidence,
|
|
188
|
-
reused: solverShadow.reused,
|
|
189
|
-
persisted: solverShadow.persisted,
|
|
190
|
-
durationMs: solverShadow.durationMs,
|
|
191
|
-
warnings: solverShadow.warnings
|
|
192
|
-
}
|
|
193
|
-
: solverShadow,
|
|
194
|
-
modelRoute: modelRoute?.status === "ok"
|
|
195
|
-
? {
|
|
196
|
-
mode: modelRoute.decision.mode,
|
|
197
|
-
objective: modelRoute.decision.objective,
|
|
198
|
-
capabilityBand: modelRoute.decision.capabilityBand,
|
|
199
|
-
safetyFloor: modelRoute.decision.safetyFloor,
|
|
200
|
-
disposition: modelRoute.decision.disposition,
|
|
201
|
-
selectionSource: modelRoute.decision.selectionSource,
|
|
202
|
-
provider: modelRoute.decision.provider,
|
|
203
|
-
modelId: modelRoute.decision.modelId,
|
|
204
|
-
effort: modelRoute.decision.effort,
|
|
205
|
-
downgradeSteps: modelRoute.decision.downgradeSteps,
|
|
206
|
-
enforced: modelRoute.decision.enforced,
|
|
207
|
-
decisionDigest: modelRoute.decision.decisionDigest,
|
|
208
|
-
reasonCodes: modelRoute.decision.reasonCodes,
|
|
209
|
-
reused: modelRoute.reused,
|
|
210
|
-
persisted: modelRoute.persisted,
|
|
211
|
-
durationMs: modelRoute.durationMs,
|
|
212
|
-
warnings: modelRoute.warnings
|
|
213
|
-
}
|
|
214
|
-
: modelRoute
|
|
165
|
+
runtimeSnapshot: runtimeSnapshotTelemetry(runtimeSnapshot),
|
|
166
|
+
solverShadow: solverShadowTelemetry(solverShadow),
|
|
167
|
+
modelRoute: modelRouteTelemetry(modelRoute)
|
|
215
168
|
});
|
|
216
169
|
|
|
217
170
|
const finishAgentStart = async (contextMessage?: {
|
|
@@ -225,36 +178,133 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
225
178
|
const intake = await dependencies.startAutomaticTask(query, ctx);
|
|
226
179
|
if (intake?.task) observeTrajectorySync(ctx, dependencies.syncTrajectory?.(ctx, intake.task, { sourceHook: "agent-start", recommendationRef }), dependencies.telemetry);
|
|
227
180
|
if (!selectedContext && !intake) return systemPromptUpdate;
|
|
228
|
-
const
|
|
229
|
-
?
|
|
230
|
-
|
|
181
|
+
const discoveryItems = selectedContext?.customType === "piagent-context-pack-v2" && Array.isArray(selectedContext.details.selectedItems)
|
|
182
|
+
? selectedContext.details.selectedItems as Array<Record<string, unknown>>
|
|
183
|
+
: [];
|
|
184
|
+
const discoveryPlan = selectedContext?.customType === "piagent-context-pack-v2"
|
|
185
|
+
&& selectedContext.details.contextPlan && typeof selectedContext.details.contextPlan === "object"
|
|
186
|
+
? selectedContext.details.contextPlan as { budgetTokens?: unknown; limit?: unknown }
|
|
187
|
+
: undefined;
|
|
188
|
+
const fallbackBudget = signal.paths.length === 0 ? 680 : signal.lane === "tiny" ? 420 : 560;
|
|
189
|
+
const criterionBudget = Number.isFinite(Number(discoveryPlan?.budgetTokens))
|
|
190
|
+
? Math.max(100, Math.min(CONTEXT_PACK_MAX_TOKENS, Math.trunc(Number(discoveryPlan?.budgetTokens))))
|
|
191
|
+
: fallbackBudget;
|
|
192
|
+
const criterionLimit = Number.isFinite(Number(discoveryPlan?.limit))
|
|
193
|
+
? Math.max(1, Math.min(6, Math.trunc(Number(discoveryPlan?.limit))))
|
|
194
|
+
: signal.paths.length > 0 ? 3 : 4;
|
|
195
|
+
const criterionMode = dependencies.autoContextEnabled && intake?.task?.criterionGraph?.mode === "criterion-graph";
|
|
196
|
+
const criterionEntries = intake?.task?.criterionGraph?.mode === "criterion-graph"
|
|
197
|
+
? composeCriterionContextEntries({
|
|
198
|
+
explicitPaths: signal.paths,
|
|
199
|
+
criteria: intake.task.acceptanceCriteria,
|
|
200
|
+
plannedEntries: intake.plannedContext ?? [],
|
|
201
|
+
plannedSelectionComplete: intake.plannedContextComplete === true,
|
|
202
|
+
retrievedItems: discoveryItems
|
|
203
|
+
}, { limit: criterionLimit })
|
|
204
|
+
: [];
|
|
205
|
+
const criterionContext = criterionMode
|
|
206
|
+
? buildSelectedContextPack(ctx.cwd, criterionEntries, {
|
|
207
|
+
budgetTokens: criterionBudget,
|
|
208
|
+
limit: criterionLimit,
|
|
209
|
+
focusText: [query, ...intake.task.acceptanceCriteria].join("\n"),
|
|
210
|
+
excludePatterns: dependencies.contextExcludePatterns(ctx)
|
|
231
211
|
})
|
|
232
212
|
: undefined;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
213
|
+
const criterionReasonCode = !dependencies.autoContextEnabled
|
|
214
|
+
? "auto-context-disabled"
|
|
215
|
+
: intake?.task?.criterionGraph?.mode !== "criterion-graph"
|
|
216
|
+
? "criterion-graph-unavailable"
|
|
217
|
+
: criterionEntries.length === 0
|
|
218
|
+
? "no-candidates"
|
|
219
|
+
: !criterionContext?.selected.length ? "no-readable-selection" : "selected";
|
|
220
|
+
if (intake?.task) dependencies.telemetry(ctx, {
|
|
221
|
+
event: "criterion_context_pack", turnId: turn.turnId, selected: criterionContext?.selected.length ?? 0,
|
|
222
|
+
candidates: criterionEntries.length,
|
|
223
|
+
budgetTokens: criterionBudget,
|
|
224
|
+
estimatedTokens: criterionContext?.estimatedTokens ?? 0,
|
|
225
|
+
reasonCode: criterionReasonCode,
|
|
226
|
+
selectedPaths: criterionContext?.selected.map((entry) => entry.path) ?? []
|
|
236
227
|
});
|
|
237
|
-
const
|
|
228
|
+
const composedContext = criterionContext?.selected.length ? criterionContext : undefined;
|
|
229
|
+
const deliveredSelectedContext = criterionMode ? undefined : selectedContext;
|
|
230
|
+
const content = [deliveredSelectedContext?.content, intake?.text, composedContext?.text].filter(Boolean).join("\n\n");
|
|
231
|
+
const deliveryTask = intake?.task ?? activeTask;
|
|
232
|
+
const selectedPackPaths = deliveredSelectedContext?.customType === "piagent-context-pack-v2" && Array.isArray(deliveredSelectedContext.details.paths)
|
|
233
|
+
? deliveredSelectedContext.details.paths.filter((value): value is string => typeof value === "string")
|
|
234
|
+
: [];
|
|
235
|
+
const criterionPaths = composedContext?.selected.map((entry) => entry.path) ?? [];
|
|
236
|
+
const selectedPackItems = (deliveredSelectedContext?.details.selectedItems as ContextInjectionItem[] | undefined)
|
|
237
|
+
?? selectedPackPaths.map((path) => ({ path, estimatedTokens: 0 }));
|
|
238
|
+
const injectionItems: ContextInjectionItem[] = composedContext?.selected ?? selectedPackItems;
|
|
239
|
+
const deliveryEntries = new Map<string, { path: string; reason: string }>();
|
|
240
|
+
for (const filePath of selectedPackPaths) {
|
|
241
|
+
deliveryEntries.set(filePath, {
|
|
242
|
+
path: filePath,
|
|
243
|
+
reason: "Runtime confirmed delivery of a bounded Context Engine navigation pack."
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
for (const filePath of criterionPaths) {
|
|
247
|
+
deliveryEntries.set(filePath, {
|
|
248
|
+
path: filePath,
|
|
249
|
+
reason: "Runtime confirmed delivery of criterion-selected context."
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
const deliveryId = deliveryTask && deliveryEntries.size > 0 ? crypto.randomUUID() : undefined;
|
|
253
|
+
if (deliveryTask && deliveryId) {
|
|
254
|
+
const retrievalKey = typeof deliveredSelectedContext?.details.retrievalKey === "string" ? deliveredSelectedContext.details.retrievalKey : undefined;
|
|
255
|
+
stageContextDelivery(ctx, {
|
|
256
|
+
deliveryId,
|
|
257
|
+
taskRunId: deliveryTask.taskRunId,
|
|
258
|
+
turnId: turn.turnId,
|
|
259
|
+
entries: [...deliveryEntries.values()],
|
|
260
|
+
pack: retrievalKey
|
|
261
|
+
? {
|
|
262
|
+
retrievalKey,
|
|
263
|
+
queryHash: String(deliveredSelectedContext?.details.queryHash ?? ""),
|
|
264
|
+
confidence: String(deliveredSelectedContext?.details.confidence ?? "unknown"),
|
|
265
|
+
estimatedTokens: Number(deliveredSelectedContext?.details.estimatedTokens ?? 0),
|
|
266
|
+
paths: selectedPackPaths
|
|
267
|
+
}
|
|
268
|
+
: undefined,
|
|
269
|
+
injection: {
|
|
270
|
+
source: composedContext ? "criterion-pack" : deliveredSelectedContext?.customType === "piagent-context-pack-v2" ? "auto-pack" : "criterion-seed",
|
|
271
|
+
queryHash: String(deliveredSelectedContext?.details.queryHash ?? signal.promptHash),
|
|
272
|
+
confidence: String(deliveredSelectedContext?.details.confidence ?? (criterionPaths.length > 0 ? "high" : "unknown")),
|
|
273
|
+
estimatedTokens: Number(deliveredSelectedContext?.details.estimatedTokens ?? composedContext?.estimatedTokens ?? 0),
|
|
274
|
+
selectedItems: injectionItems
|
|
275
|
+
}
|
|
276
|
+
}, { state: dependencies.state, telemetry: dependencies.telemetry });
|
|
277
|
+
}
|
|
238
278
|
return {
|
|
239
279
|
...(systemPromptUpdate ?? {}),
|
|
240
280
|
message: {
|
|
241
|
-
customType:
|
|
281
|
+
customType: deliveredSelectedContext?.customType ?? "piagent-runtime-task-intake",
|
|
242
282
|
content,
|
|
243
283
|
display: false,
|
|
244
284
|
details: {
|
|
245
|
-
...(
|
|
285
|
+
...(deliveredSelectedContext?.details ?? {}),
|
|
286
|
+
...(composedContext ? {
|
|
287
|
+
schemaVersion: 1,
|
|
288
|
+
queryHash: signal.promptHash,
|
|
289
|
+
estimatedTokens: composedContext.estimatedTokens,
|
|
290
|
+
paths: composedContext.selected.map((entry) => entry.path),
|
|
291
|
+
selectedItems: composedContext.selected
|
|
292
|
+
} : {}),
|
|
293
|
+
contextDelivery: deliveryId ? { schemaVersion: 1, deliveryId } : undefined,
|
|
246
294
|
runtimeTask: intake?.task
|
|
247
295
|
? {
|
|
248
296
|
taskId: intake.task.taskId,
|
|
249
297
|
taskRunId: intake.task.taskRunId,
|
|
298
|
+
changeMode: intake.task.changeMode,
|
|
299
|
+
mutationPolicy: intake.task.mutationPolicy,
|
|
250
300
|
scope: intake.task.scope,
|
|
251
301
|
verifyCommands: intake.task.verifyCommands,
|
|
252
302
|
criterionGraph: intake.task.criterionGraph ? { mode: intake.task.criterionGraph.mode, graphDigest: intake.task.criterionGraph.graphDigest, nodes: intake.task.criterionGraph.nodes.length } : null,
|
|
253
303
|
intakeMode: intake.task.intakeMode
|
|
254
304
|
}
|
|
255
305
|
: undefined,
|
|
256
|
-
criterionContext:
|
|
257
|
-
paths:
|
|
306
|
+
criterionContext: composedContext ? {
|
|
307
|
+
paths: composedContext.selected.map((entry) => entry.path), estimatedTokens: composedContext.estimatedTokens
|
|
258
308
|
} : undefined,
|
|
259
309
|
runtimeIntakeStarted: intake?.started ?? false
|
|
260
310
|
}
|
|
@@ -263,6 +313,9 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
263
313
|
};
|
|
264
314
|
|
|
265
315
|
const packKey = dependencies.promptPackKey(ctx, signal.promptHash);
|
|
316
|
+
if (!autoPackUseful && activeTask?.trace.outcome === "pending" && query.length >= 20 && signal.workflow !== "usage" && dependencies.autoContextEnabled) {
|
|
317
|
+
await measureContextDeltaShadow({ ctx, query, turnId: turn.turnId, task: activeTask, mode: dependencies.contextDeltaShadowMode, protectedTarget, excludePatterns: dependencies.contextExcludePatterns(ctx), telemetry: dependencies.telemetry });
|
|
318
|
+
}
|
|
266
319
|
if (
|
|
267
320
|
query.length < 20
|
|
268
321
|
|| signal.workflow === "usage"
|
|
@@ -304,6 +357,7 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
304
357
|
if (!status.exists || status.stale) {
|
|
305
358
|
dependencies.telemetry(ctx, {
|
|
306
359
|
event: "context_pack",
|
|
360
|
+
turnId: turn.turnId,
|
|
307
361
|
queryHash: signal.promptHash,
|
|
308
362
|
confidence: "none",
|
|
309
363
|
candidates: 0,
|
|
@@ -348,6 +402,7 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
348
402
|
});
|
|
349
403
|
dependencies.telemetry(ctx, {
|
|
350
404
|
event: "context_pack",
|
|
405
|
+
turnId: turn.turnId,
|
|
351
406
|
queryHash: pack.queryHash,
|
|
352
407
|
confidence: pack.confidence,
|
|
353
408
|
candidates: pack.candidates,
|
|
@@ -379,10 +434,12 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
379
434
|
}
|
|
380
435
|
if (!contextPlanAcceptsConfidence(plan, pack.confidence) || pack.selected.length === 0) return finishAgentStart();
|
|
381
436
|
const memoryBudgetTokens = Math.max(0, plan.budgetTokens - pack.estimatedTokens);
|
|
382
|
-
const memoryHints =
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
437
|
+
const memoryHints = runtimeIntake
|
|
438
|
+
? { text: "", ids: [] }
|
|
439
|
+
: formatRepositoryMemoryHints(
|
|
440
|
+
selectRepositoryMemoryFacts(ctx.cwd, query, { limit: 2, excludePatterns }),
|
|
441
|
+
memoryBudgetTokens
|
|
442
|
+
);
|
|
386
443
|
dependencies.telemetry(ctx, {
|
|
387
444
|
event: "repository_memory_selected",
|
|
388
445
|
queryHash: signal.promptHash,
|
|
@@ -392,27 +449,29 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
392
449
|
estimatedTokens: estimateContextTokens(memoryHints.text),
|
|
393
450
|
planReceipt: plan.receipt
|
|
394
451
|
});
|
|
395
|
-
dependencies.state.rememberInjectedContextPack(ctx, dependencies.retrievalKey(ctx, query), {
|
|
396
|
-
queryHash: pack.queryHash,
|
|
397
|
-
confidence: pack.confidence,
|
|
398
|
-
estimatedTokens: pack.estimatedTokens,
|
|
399
|
-
paths: pack.selected.map((item) => item.path)
|
|
400
|
-
});
|
|
401
|
-
for (const selected of pack.selected) {
|
|
402
|
-
dependencies.state.rememberObservedContext(ctx, {
|
|
403
|
-
path: selected.path,
|
|
404
|
-
reason: "Runtime injected a bounded Context Engine navigation pack."
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
452
|
return finishAgentStart({
|
|
408
453
|
customType: "piagent-context-pack-v2",
|
|
409
454
|
content: [pack.text, memoryHints.text].filter(Boolean).join("\n\n"),
|
|
410
455
|
details: {
|
|
411
456
|
schemaVersion: 2,
|
|
412
457
|
queryHash: pack.queryHash,
|
|
458
|
+
retrievalKey: dependencies.retrievalKey(ctx, query),
|
|
413
459
|
confidence: pack.confidence,
|
|
414
460
|
estimatedTokens: pack.estimatedTokens,
|
|
415
461
|
paths: pack.selected.map((item) => item.path),
|
|
462
|
+
selectedItems: pack.selected.map((item) => ({
|
|
463
|
+
path: item.path,
|
|
464
|
+
estimatedTokens: item.estimatedTokens,
|
|
465
|
+
sources: item.sources,
|
|
466
|
+
links: item.links,
|
|
467
|
+
fileContentHash: item.fileContentHash,
|
|
468
|
+
...(item.sanitizedContentDigest ? { sanitizedContentDigest: item.sanitizedContentDigest } : {}),
|
|
469
|
+
payloadHash: item.payloadHash,
|
|
470
|
+
representation: item.representation,
|
|
471
|
+
ranges: item.ranges,
|
|
472
|
+
generation: item.generation,
|
|
473
|
+
sensitiveContentRedacted: item.sensitiveContentRedacted
|
|
474
|
+
})),
|
|
416
475
|
repositoryMemoryIds: memoryHints.ids,
|
|
417
476
|
currentSnapshot: plan.currentSnapshot,
|
|
418
477
|
contextPlan: plan
|
|
@@ -421,6 +480,7 @@ export function registerAgentStartHook(pi: ExtensionAPI, dependencies: AgentStar
|
|
|
421
480
|
} catch (error) {
|
|
422
481
|
dependencies.telemetry(ctx, {
|
|
423
482
|
event: "context_pack",
|
|
483
|
+
turnId: turn.turnId,
|
|
424
484
|
queryHash: signal.promptHash,
|
|
425
485
|
confidence: "none",
|
|
426
486
|
candidates: 0,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
acceptanceCriticalRecoveryProjection,
|
|
7
7
|
applyAcceptanceRecoveryProvenance
|
|
8
8
|
} from "../../extensions/acceptance-receipt.js";
|
|
9
|
+
import { hasDurableContextEvidence } from "../../extensions/context-evidence.js";
|
|
9
10
|
import type { TaskContract } from "../../extensions/guard-types.js";
|
|
10
11
|
import { runtimeLifecycleMode, workingTreeEvidenceDigest } from "../../extensions/task-lifecycle.js";
|
|
11
12
|
import { recordCompletionAudit } from "../../extensions/task-runtime-audit.js";
|
|
@@ -18,8 +19,7 @@ import {
|
|
|
18
19
|
looksLikeCompletionClaim,
|
|
19
20
|
looksLikeIncompleteHandoff
|
|
20
21
|
} from "../session/message-signals.ts";
|
|
21
|
-
import { RuntimeSessionState } from "../session/runtime-state.ts";
|
|
22
|
-
import type { ObservedTaskContext } from "../session/runtime-state.ts";
|
|
22
|
+
import { RuntimeSessionState, type ObservedTaskContext } from "../session/runtime-state.ts";
|
|
23
23
|
import type { RecoveryDecision } from "../recovery/recovery-policy.ts";
|
|
24
24
|
import { buildHandoffProjection, handoffProjectionPath, writeHandoffProjection } from "../recovery/handoff-projection.ts";
|
|
25
25
|
import { evaluateExactFinalOutputContract } from "../quality/exact-output-contract.ts";
|
|
@@ -177,7 +177,7 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
|
|
|
177
177
|
let task = flushObservedTaskContext(
|
|
178
178
|
pi,
|
|
179
179
|
ctx,
|
|
180
|
-
state.
|
|
180
|
+
state.qualifiedTaskContext(ctx),
|
|
181
181
|
maxManifestFiles,
|
|
182
182
|
"context_observed_before_handoff"
|
|
183
183
|
) ?? activeTask(ctx);
|
|
@@ -187,7 +187,7 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
|
|
|
187
187
|
const completionClaim = looksLikeCompletionClaim(text);
|
|
188
188
|
const incompleteHandoff = looksLikeIncompleteHandoff(text);
|
|
189
189
|
if (task.trace.outcome !== "pending") return;
|
|
190
|
-
const readOnlyEvidenceObserved = task.changeMode === "read-only"
|
|
190
|
+
const readOnlyEvidenceObserved = (task.changeMode === "read-only" || task.mutationPolicy === "forbidden") && hasDurableContextEvidence(task);
|
|
191
191
|
const latestExactVerifier = latestObservedVerification(task.verifyEvidence.filter((evidence) => evidence.matchedProfileCommand === true));
|
|
192
192
|
const potentiallyFinalEvidence = task.observedChangedFiles.length > 0
|
|
193
193
|
|| latestExactVerifier?.exitCode === 0
|
|
@@ -298,7 +298,6 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
|
|
|
298
298
|
projected = withRecoveryProvenance(ctx, projected, projectedGate, currentDigests, null);
|
|
299
299
|
task = writeTask(ctx.cwd, projected);
|
|
300
300
|
observeTrajectorySync(ctx, syncTrajectory?.(ctx, task, { sourceHook: "completion" }), telemetry);
|
|
301
|
-
state.cacheTaskIdentity(ctx, task);
|
|
302
301
|
state.clearPerformanceReview(task.taskRunId);
|
|
303
302
|
state.clearObservedContext(ctx);
|
|
304
303
|
activateBaseTools(ctx);
|
|
@@ -387,7 +386,7 @@ export function registerCompletionHook(pi: ExtensionAPI, dependencies: Completio
|
|
|
387
386
|
...verifierInstructions(gate.missingVerifyCommands),
|
|
388
387
|
"Do not broaden task scope, repeat a failed hypothesis, expand permission, or perform an external action."
|
|
389
388
|
]
|
|
390
|
-
: selectedRecovery.reasonCodes.includes("unknown-diagnostic-pass") || task.changeMode === "read-only"
|
|
389
|
+
: selectedRecovery.reasonCodes.includes("unknown-diagnostic-pass") || task.changeMode === "read-only" || task.mutationPolicy === "forbidden"
|
|
391
390
|
? [
|
|
392
391
|
...(gate.missingVerifyCommands.length > 0
|
|
393
392
|
? ["Run only the missing exact verifier commands against the current working tree.", ...verifierInstructions(gate.missingVerifyCommands)]
|
|
@@ -11,6 +11,7 @@ import { buildHandoffProjection, writeHandoffProjection } from "../recovery/hand
|
|
|
11
11
|
import { buildContextPreflight, buildUsageSnapshot } from "../session/usage.ts";
|
|
12
12
|
import { activeTaskToolGroups, toolGroupsForPrompt } from "../tools/tool-groups.ts";
|
|
13
13
|
import type { PiagentToolGroup } from "../tools/tool-groups.ts";
|
|
14
|
+
import type { RuntimeSessionState } from "../session/runtime-state.ts";
|
|
14
15
|
import {
|
|
15
16
|
buildFreshCommand,
|
|
16
17
|
chooseFreshWorkflow,
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
} from "../workflows/task-intake.ts";
|
|
27
28
|
|
|
28
29
|
type InputHookDependencies = {
|
|
30
|
+
state: RuntimeSessionState;
|
|
29
31
|
boilerplateCollapseChars: number;
|
|
30
32
|
activeTask: (ctx: ExtensionContext) => TaskContract | undefined;
|
|
31
33
|
authorityPolicy: (ctx: ExtensionContext, task: TaskContract) => AuthorityResumeDecision;
|
|
@@ -44,7 +46,14 @@ export function registerInputHook(pi: ExtensionAPI, dependencies: InputHookDepen
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
const taskSignal = classifyContextTask(text);
|
|
47
|
-
const
|
|
49
|
+
const sessionTask = dependencies.activeTask(ctx);
|
|
50
|
+
if (sessionTask && sessionTask.trace.outcome !== "pending") dependencies.state.clearTaskBoundary(ctx, sessionTask.taskRunId);
|
|
51
|
+
else if (!sessionTask) {
|
|
52
|
+
const cachedTask = dependencies.state.taskIdentity(ctx);
|
|
53
|
+
if (cachedTask) dependencies.state.clearTaskBoundary(ctx, cachedTask.taskRunId);
|
|
54
|
+
}
|
|
55
|
+
const activeTask = sessionTask?.trace.outcome === "pending" ? sessionTask : undefined;
|
|
56
|
+
const turn = dependencies.state.beginTurn(ctx, taskSignal.promptHash);
|
|
48
57
|
const authorityPolicy = activeTask?.trace.outcome === "pending" ? dependencies.authorityPolicy(ctx, activeTask) : undefined;
|
|
49
58
|
let authorityHandoffReady = false;
|
|
50
59
|
if (activeTask && authorityPolicy?.disposition === "new-attempt-required") {
|
|
@@ -79,6 +88,7 @@ export function registerInputHook(pi: ExtensionAPI, dependencies: InputHookDepen
|
|
|
79
88
|
: promptGroups);
|
|
80
89
|
dependencies.telemetry(ctx, {
|
|
81
90
|
event: "user_input",
|
|
91
|
+
turnId: turn.turnId,
|
|
82
92
|
source: event.source,
|
|
83
93
|
promptHash: taskSignal.promptHash,
|
|
84
94
|
promptChars: taskSignal.promptChars,
|
|
@@ -4,6 +4,7 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
|
|
|
4
4
|
import type { TaskContract } from "../../extensions/guard-types.js";
|
|
5
5
|
import { RuntimeSessionState } from "../session/runtime-state.ts";
|
|
6
6
|
import type { ObservedTaskContext } from "../session/runtime-state.ts";
|
|
7
|
+
import { confirmContextDelivery, contextDeliveryIdFromDetails } from "../context/context-delivery.ts";
|
|
7
8
|
|
|
8
9
|
type TelemetryWriter = (ctx: ExtensionContext, payload: Record<string, unknown>) => void;
|
|
9
10
|
|
|
@@ -39,6 +40,20 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
|
|
|
39
40
|
flushObservedTaskContext
|
|
40
41
|
} = dependencies;
|
|
41
42
|
|
|
43
|
+
pi.on("message_start", async (event, ctx) => {
|
|
44
|
+
const message = event.message as unknown as { role?: unknown; details?: unknown };
|
|
45
|
+
if (message.role !== "custom") return;
|
|
46
|
+
const deliveryId = contextDeliveryIdFromDetails(message.details);
|
|
47
|
+
if (!deliveryId) return;
|
|
48
|
+
confirmContextDelivery(pi, ctx, deliveryId, {
|
|
49
|
+
state,
|
|
50
|
+
maxManifestFiles,
|
|
51
|
+
activeTask: (deliveryContext) => activeTask(deliveryContext.cwd, deliveryContext.sessionManager.getSessionId()),
|
|
52
|
+
flushObservedTaskContext,
|
|
53
|
+
telemetry
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
42
57
|
pi.on("session_info_changed", async (event, ctx) => {
|
|
43
58
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
44
59
|
const task = activeTask(ctx.cwd, sessionId);
|
|
@@ -58,6 +73,7 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
|
|
|
58
73
|
|
|
59
74
|
pi.on("turn_end", async (event, ctx) => {
|
|
60
75
|
const message = event.message as unknown as { usage?: unknown; stopReason?: unknown; role?: unknown };
|
|
76
|
+
const task = activeTask(ctx.cwd, ctx.sessionManager.getSessionId());
|
|
61
77
|
telemetry(ctx, {
|
|
62
78
|
event: "turn_end",
|
|
63
79
|
turnIndex: event.turnIndex,
|
|
@@ -65,9 +81,13 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
|
|
|
65
81
|
role: message.role,
|
|
66
82
|
stopReason: message.stopReason,
|
|
67
83
|
usage: message.usage,
|
|
68
|
-
contextUsage: ctx.getContextUsage()
|
|
84
|
+
contextUsage: ctx.getContextUsage(),
|
|
85
|
+
taskId: task?.taskId,
|
|
86
|
+
taskRunId: task?.taskRunId,
|
|
87
|
+
taskOutcome: task?.trace.outcome
|
|
69
88
|
});
|
|
70
89
|
dependencies.onTurnEnd?.(ctx);
|
|
90
|
+
if (task && task.trace.outcome !== "pending") state.clearTaskBoundary(ctx, task.taskRunId);
|
|
71
91
|
});
|
|
72
92
|
|
|
73
93
|
pi.on("agent_settled", async (_event, ctx) => {
|
|
@@ -96,7 +116,7 @@ export function registerSessionHooks(pi: ExtensionAPI, dependencies: SessionHook
|
|
|
96
116
|
flushObservedTaskContext(
|
|
97
117
|
pi,
|
|
98
118
|
ctx,
|
|
99
|
-
state.
|
|
119
|
+
state.qualifiedTaskContext(ctx),
|
|
100
120
|
maxManifestFiles,
|
|
101
121
|
"context_observed_before_shutdown"
|
|
102
122
|
);
|
|
@@ -139,8 +139,9 @@ export function registerSessionStartHook(pi: ExtensionAPI, dependencies: Session
|
|
|
139
139
|
dependencies.bindTask(ctx.cwd, sessionId, sessionName, resumedTask);
|
|
140
140
|
}
|
|
141
141
|
if (resumedTask?.workingTreeDigestMigration && resumedTask.workingTreeDigestMigration.status !== "refreshed") dependencies.state.clearDigestMigrationState(ctx, resumedTask.taskRunId, resumedTask.taskId);
|
|
142
|
-
dependencies.state.cacheTaskIdentity(ctx, resumedTask);
|
|
143
|
-
|
|
142
|
+
if (resumedTask?.trace.outcome === "pending") dependencies.state.cacheTaskIdentity(ctx, resumedTask);
|
|
143
|
+
else dependencies.state.clearSession(ctx);
|
|
144
|
+
const resumeState = resumedTask?.trace.outcome === "pending" ? dependencies.inspectResume(ctx.cwd, resumedTask, sessionId) : undefined;
|
|
144
145
|
if (resumeState) dependencies.state.rememberResumeState(resumeState);
|
|
145
146
|
if (resumedTask && resumeState?.enforcementSafe) observeTrajectorySync(ctx, dependencies.syncTrajectory?.(ctx, resumedTask), dependencies.telemetry);
|
|
146
147
|
let taskRecovery: Record<string, unknown> | undefined;
|
|
@@ -217,6 +218,10 @@ export function registerSessionStartHook(pi: ExtensionAPI, dependencies: Session
|
|
|
217
218
|
}
|
|
218
219
|
dependencies.telemetry(ctx, {
|
|
219
220
|
event: "session_start",
|
|
221
|
+
// Benchmark and efficiency projections must be able to distinguish a
|
|
222
|
+
// genuine zero-recovery session from telemetry produced before this
|
|
223
|
+
// receipt/result protocol existed.
|
|
224
|
+
editRecoveryContextTelemetryVersion: 1,
|
|
220
225
|
activeTools: pi.getActiveTools().length,
|
|
221
226
|
index: engineStatus,
|
|
222
227
|
taskMigration: migration,
|