@caupulican/pi-adaptative 0.80.96 → 0.80.98
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 +35 -0
- package/dist/core/agent-session.d.ts +19 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +185 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.d.ts +17 -0
- package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -0
- package/dist/core/autonomy/envelope-enforcement.js +80 -0
- package/dist/core/autonomy/envelope-enforcement.js.map +1 -0
- package/dist/core/context/brain-curator.d.ts +7 -0
- package/dist/core/context/brain-curator.d.ts.map +1 -1
- package/dist/core/context/brain-curator.js +6 -0
- package/dist/core/context/brain-curator.js.map +1 -1
- package/dist/core/context/context-composition.d.ts.map +1 -1
- package/dist/core/context/context-composition.js +1 -1
- package/dist/core/context/context-composition.js.map +1 -1
- package/dist/core/delegation/session-worker-result.d.ts +8 -2
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
- package/dist/core/delegation/session-worker-result.js +18 -1
- package/dist/core/delegation/session-worker-result.js.map +1 -1
- package/dist/core/learning/observation-store.d.ts +20 -0
- package/dist/core/learning/observation-store.d.ts.map +1 -0
- package/dist/core/learning/observation-store.js +101 -0
- package/dist/core/learning/observation-store.js.map +1 -0
- package/dist/core/model-router/executor-route.d.ts +8 -0
- package/dist/core/model-router/executor-route.d.ts.map +1 -0
- package/dist/core/model-router/executor-route.js +33 -0
- package/dist/core/model-router/executor-route.js.map +1 -0
- package/dist/core/model-router/tool-escalation.d.ts +2 -0
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +6 -0
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/research/research-runner.d.ts +8 -1
- package/dist/core/research/research-runner.d.ts.map +1 -1
- package/dist/core/research/research-runner.js +13 -1
- package/dist/core/research/research-runner.js.map +1 -1
- package/dist/core/research/workspace-collector.d.ts +25 -0
- package/dist/core/research/workspace-collector.d.ts.map +1 -0
- package/dist/core/research/workspace-collector.js +286 -0
- package/dist/core/research/workspace-collector.js.map +1 -0
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/interactive/components/fitness-role-selector.d.ts +1 -1
- package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/fitness-role-selector.js +5 -0
- package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +147 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +21 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -25,6 +25,7 @@ import { evaluateToolGate } from "./autonomy/gates.js";
|
|
|
25
25
|
import { LaneTracker } from "./autonomy/lane-tracker.js";
|
|
26
26
|
import { appendLaneRecordSnapshot, getLaneRecordSnapshots } from "./autonomy/session-lane-record.js";
|
|
27
27
|
import { composeSubagentSystemPrompt } from "./autonomy/subagent-prompt.js";
|
|
28
|
+
import { AUTONOMY_TELEMETRY_EVENT_TYPES, redactTelemetryValue, } from "./autonomy/telemetry-events.js";
|
|
28
29
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
29
30
|
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
30
31
|
// (module-scope helper for curation goal extraction defined below the imports)
|
|
@@ -57,6 +58,7 @@ import { buildGoalRuntimeSnapshot, } from "./goals/goal-runtime-snapshot.js";
|
|
|
57
58
|
import { appendGoalStateSnapshot, getLatestGoalStateSnapshot } from "./goals/session-goal-state.js";
|
|
58
59
|
import { appendLearningAuditSnapshot, getLearningAuditSnapshots, proposalFromReflectionWrite, rollbackPlanForReflectionWrite, } from "./learning/learning-audit.js";
|
|
59
60
|
import { evaluateLearningDecision } from "./learning/learning-gate.js";
|
|
61
|
+
import { ObservationStore, observationKey } from "./learning/observation-store.js";
|
|
60
62
|
import { decideDemand, ReflectionEngine, } from "./learning/reflection-engine.js";
|
|
61
63
|
import { appendLearningDecisionSnapshot, getLearningDecisionSnapshots } from "./learning/session-learning-decision.js";
|
|
62
64
|
import { isPromotedFrontmatter, SkillCurator } from "./learning/skill-curator.js";
|
|
@@ -69,6 +71,7 @@ import { createCustomMessage } from "./messages.js";
|
|
|
69
71
|
import { deriveModelCapabilityProfile, filterToolNamesForCapability, } from "./model-capability.js";
|
|
70
72
|
import { resolveCliModel, resolveProfileModelSettings } from "./model-resolver.js";
|
|
71
73
|
import { collectModelRouterConfigDiagnostics } from "./model-router/config-diagnostics.js";
|
|
74
|
+
import { classifyExecutorTurn } from "./model-router/executor-route.js";
|
|
72
75
|
import { classifyModelRouterRoute } from "./model-router/intent-classifier.js";
|
|
73
76
|
import { ROUTE_JUDGE_MAX_OUTPUT_TOKENS, runRouteJudge } from "./model-router/route-judge.js";
|
|
74
77
|
import { bufferModelRouterSessionCustomMessage, bufferModelRouterSessionMessage, createModelRouterSessionBuffer, flushModelRouterSessionBuffer, } from "./model-router/session-buffer.js";
|
|
@@ -79,6 +82,7 @@ import { expandPromptTemplate } from "./prompt-templates.js";
|
|
|
79
82
|
import { runModelFitnessProbe } from "./research/model-fitness.js";
|
|
80
83
|
import { runResearch } from "./research/research-runner.js";
|
|
81
84
|
import { appendEvidenceBundleSnapshot, getEvidenceBundleSnapshots, getLatestEvidenceBundleSnapshot, } from "./research/session-evidence-bundle.js";
|
|
85
|
+
import { collectWorkspaceSources } from "./research/workspace-collector.js";
|
|
82
86
|
import { stripResourceProfileBlocks } from "./resource-profile-blocks.js";
|
|
83
87
|
import { classifyToolTrust, UNTRUSTED_BOUNDARY_SYSTEM_RULE, wrapUntrustedText } from "./security/untrusted-boundary.js";
|
|
84
88
|
import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
|
|
@@ -142,6 +146,9 @@ function formatModelRouterModel(model) {
|
|
|
142
146
|
function persistModelRouterDecision(sessionManager, decision) {
|
|
143
147
|
sessionManager.appendCustomEntry(MODEL_ROUTER_DECISION_CUSTOM_TYPE, decision);
|
|
144
148
|
}
|
|
149
|
+
/** Custom-entry type for G3 autonomy telemetry. Distinct from the router/lane record types so a
|
|
150
|
+
* telemetry consumer can filter on it without decoding operational snapshots. */
|
|
151
|
+
const AUTONOMY_TELEMETRY_CUSTOM_TYPE = "autonomy-telemetry";
|
|
145
152
|
/** Read a packed grep/find tool result's `details.artifactId`, if present, without `any`. */
|
|
146
153
|
function extractArtifactId(message) {
|
|
147
154
|
if (!message || message.role !== "toolResult")
|
|
@@ -256,6 +263,7 @@ export class AgentSession {
|
|
|
256
263
|
_baseToolDefinitions = new Map();
|
|
257
264
|
_cwd;
|
|
258
265
|
_agentDir;
|
|
266
|
+
_collectWorkspaceSources;
|
|
259
267
|
_extensionRunnerRef;
|
|
260
268
|
_initialActiveToolNames;
|
|
261
269
|
_allowedToolNames;
|
|
@@ -323,6 +331,7 @@ export class AgentSession {
|
|
|
323
331
|
this._customTools = config.customTools ?? [];
|
|
324
332
|
this._cwd = config.cwd;
|
|
325
333
|
this._agentDir = config.agentDir ?? getAgentDir();
|
|
334
|
+
this._collectWorkspaceSources = config.collectWorkspaceSources ?? collectWorkspaceSources;
|
|
326
335
|
this._modelRegistry = config.modelRegistry;
|
|
327
336
|
this._extensionRunnerRef = config.extensionRunnerRef;
|
|
328
337
|
this._initialActiveToolNames = config.initialActiveToolNames;
|
|
@@ -1213,7 +1222,13 @@ export class AgentSession {
|
|
|
1213
1222
|
writePayloads,
|
|
1214
1223
|
curation: curationSettings.enabled
|
|
1215
1224
|
? {
|
|
1216
|
-
resolveDigest: (digestKey) =>
|
|
1225
|
+
resolveDigest: (digestKey) => {
|
|
1226
|
+
const digest = this._brainCurator.getDigest(digestKey);
|
|
1227
|
+
// Count serves on the REAL per-turn pass only, never the report path.
|
|
1228
|
+
if (digest !== undefined && writePayloads)
|
|
1229
|
+
this._brainCurator.noteDigestServed();
|
|
1230
|
+
return digest;
|
|
1231
|
+
},
|
|
1217
1232
|
// Only the real per-turn pass enqueues work; the read-only report path
|
|
1218
1233
|
// (writePayloads=false) stays side-effect free.
|
|
1219
1234
|
onPacked: writePayloads
|
|
@@ -1315,7 +1330,12 @@ export class AgentSession {
|
|
|
1315
1330
|
_installAgentToolHooks() {
|
|
1316
1331
|
this.agent.beforeToolCall = async ({ toolCall, args }) => {
|
|
1317
1332
|
if (this._activeModelRouterRoute &&
|
|
1318
|
-
shouldEscalateModelRouterTool({
|
|
1333
|
+
shouldEscalateModelRouterTool({
|
|
1334
|
+
tier: this._activeModelRouterRoute.tier,
|
|
1335
|
+
toolName: toolCall.name,
|
|
1336
|
+
args,
|
|
1337
|
+
reasonCode: this._activeModelRouterRoute.reasonCode,
|
|
1338
|
+
})) {
|
|
1319
1339
|
this._modelRouterEscalationRequested = true;
|
|
1320
1340
|
this.agent.abort();
|
|
1321
1341
|
return {
|
|
@@ -2037,12 +2057,54 @@ export class AgentSession {
|
|
|
2037
2057
|
return false;
|
|
2038
2058
|
return this._modelRegistry.hasConfiguredAuth(resolved.model);
|
|
2039
2059
|
}
|
|
2060
|
+
_resolveExecutorRoute(prompt, executorPattern) {
|
|
2061
|
+
if (!executorPattern)
|
|
2062
|
+
return undefined;
|
|
2063
|
+
try {
|
|
2064
|
+
const verdict = classifyExecutorTurn(prompt, this.settingsManager.getToolkitScripts());
|
|
2065
|
+
if (!verdict.execute)
|
|
2066
|
+
return undefined;
|
|
2067
|
+
const resolved = resolveCliModel({ cliModel: executorPattern, modelRegistry: this._modelRegistry });
|
|
2068
|
+
if (!resolved.model || !this._modelRegistry.hasConfiguredAuth(resolved.model))
|
|
2069
|
+
return undefined;
|
|
2070
|
+
// Fitness gate: the executor must have PROVEN tool-calling on this host (same
|
|
2071
|
+
// canonical-ref discipline as the curation gate).
|
|
2072
|
+
const canonicalRef = `${resolved.model.provider}/${resolved.model.id}`;
|
|
2073
|
+
const fitness = FitnessStore.forAgentDir(this._agentDir)
|
|
2074
|
+
.getForHost()
|
|
2075
|
+
.find((entry) => entry.model === canonicalRef);
|
|
2076
|
+
const toolCall = fitness?.report.toolCall;
|
|
2077
|
+
if (!toolCall || toolCall.succeeded < Math.ceil(toolCall.total * (2 / 3)))
|
|
2078
|
+
return undefined;
|
|
2079
|
+
this._lastModelRouterIntent = "research";
|
|
2080
|
+
return {
|
|
2081
|
+
decision: {
|
|
2082
|
+
tier: "cheap",
|
|
2083
|
+
risk: "scoped-write",
|
|
2084
|
+
confidence: 1,
|
|
2085
|
+
reasonCode: "executor_direct",
|
|
2086
|
+
reasons: [`Executor lane: Level-0 direct hit on toolkit script "${verdict.scriptName}"`],
|
|
2087
|
+
},
|
|
2088
|
+
model: resolved.model,
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
catch {
|
|
2092
|
+
return undefined;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2040
2095
|
_resolveModelRouterTurnRoute(prompt) {
|
|
2041
2096
|
const settings = this.settingsManager.getModelRouterSettings();
|
|
2042
2097
|
if (!settings.enabled) {
|
|
2043
2098
|
this._lastModelRouterSkipReason = "disabled";
|
|
2044
2099
|
return undefined;
|
|
2045
2100
|
}
|
|
2101
|
+
// G16 executor lane: a Level-0 DIRECT toolkit hit on a command-shaped prompt routes the
|
|
2102
|
+
// whole turn to the configured local executor (tool-call-fitness-gated) instead of
|
|
2103
|
+
// spending the frontier model on a one-tool reflex. Ambiguity never routes here — it
|
|
2104
|
+
// stays with the big model and the reflex brain. Deterministic, so the judge is skipped.
|
|
2105
|
+
const executorRoute = this._resolveExecutorRoute(prompt, settings.executorModel);
|
|
2106
|
+
if (executorRoute)
|
|
2107
|
+
return executorRoute;
|
|
2046
2108
|
const decision = classifyModelRouterRoute(prompt);
|
|
2047
2109
|
this._lastModelRouterIntent = decision.tier === "cheap" ? "research" : "modify";
|
|
2048
2110
|
// Learning tier must not be selected for normal user prompts
|
|
@@ -2128,6 +2190,9 @@ export class AgentSession {
|
|
|
2128
2190
|
return undefined;
|
|
2129
2191
|
if (options?.skipJudge)
|
|
2130
2192
|
return baseline;
|
|
2193
|
+
// Deterministic executor routes need no judge (Level-0 already decided).
|
|
2194
|
+
if (baseline.decision.reasonCode === "executor_direct")
|
|
2195
|
+
return baseline;
|
|
2131
2196
|
const settings = this.settingsManager.getModelRouterSettings();
|
|
2132
2197
|
if (!settings.judgeEnabled)
|
|
2133
2198
|
return baseline;
|
|
@@ -2336,6 +2401,19 @@ export class AgentSession {
|
|
|
2336
2401
|
}
|
|
2337
2402
|
if (persistDecision && completedDecision) {
|
|
2338
2403
|
persistModelRouterDecision(this.sessionManager, completedDecision);
|
|
2404
|
+
// G3: one route event per user-facing routed turn (the escalation retry runs with
|
|
2405
|
+
// persistDecision=false, so it does not double-emit). Codes/numbers only — no prompt text.
|
|
2406
|
+
this._emitAutonomyTelemetry({
|
|
2407
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.routeDecision,
|
|
2408
|
+
timestamp: new Date().toISOString(),
|
|
2409
|
+
payload: {
|
|
2410
|
+
tier: completedDecision.route.tier,
|
|
2411
|
+
risk: completedDecision.route.risk,
|
|
2412
|
+
reasonCode: completedDecision.route.reasonCode,
|
|
2413
|
+
confidence: completedDecision.route.confidence,
|
|
2414
|
+
outcome: completedDecision.outcome,
|
|
2415
|
+
},
|
|
2416
|
+
});
|
|
2339
2417
|
}
|
|
2340
2418
|
if (thrownError) {
|
|
2341
2419
|
throw thrownError;
|
|
@@ -5007,8 +5085,24 @@ export class AgentSession {
|
|
|
5007
5085
|
getLaneRecords() {
|
|
5008
5086
|
return this._laneTracker.getRecords();
|
|
5009
5087
|
}
|
|
5010
|
-
|
|
5011
|
-
|
|
5088
|
+
/**
|
|
5089
|
+
* G3: bounded autonomy-telemetry sink. Passes the whole event through {@link redactTelemetryValue}
|
|
5090
|
+
* (the taxonomy's redaction contract) before storing it, so a secret that leaked into a payload
|
|
5091
|
+
* field never lands in the session log. Observe-only: a failure here can never surface into the
|
|
5092
|
+
* turn it is measuring, so the whole body is swallowed. Payloads MUST stay small (ids, codes,
|
|
5093
|
+
* numbers) — never prompt/summary text; callers own that discipline.
|
|
5094
|
+
*/
|
|
5095
|
+
_emitAutonomyTelemetry(event) {
|
|
5096
|
+
try {
|
|
5097
|
+
const redacted = redactTelemetryValue(event);
|
|
5098
|
+
this.sessionManager.appendCustomEntry(AUTONOMY_TELEMETRY_CUSTOM_TYPE, { version: 1, ...redacted });
|
|
5099
|
+
}
|
|
5100
|
+
catch {
|
|
5101
|
+
// Telemetry is best-effort: swallow so a sink failure cannot break the observed turn.
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
saveWorkerResultSnapshot(result, request) {
|
|
5105
|
+
return appendWorkerResultSnapshot(this.sessionManager, result, request);
|
|
5012
5106
|
}
|
|
5013
5107
|
getWorkerResultSnapshots() {
|
|
5014
5108
|
return getWorkerResultSnapshots(this.sessionManager.getEntries());
|
|
@@ -5285,9 +5379,17 @@ export class AgentSession {
|
|
|
5285
5379
|
const startedRecord = this._laneTracker.start({ type: "research", goalId: demand.goalId });
|
|
5286
5380
|
try {
|
|
5287
5381
|
let spentUsage;
|
|
5382
|
+
// Best-effort, pointer-first workspace evidence. Derives search terms from the goal/requirement
|
|
5383
|
+
// text (not the identity-key query) and is bounded + silent-on-failure: [] == today's behavior.
|
|
5384
|
+
const workspaceSources = await this._collectWorkspaceSources({
|
|
5385
|
+
query: `${demand.context}\n${demand.query}`,
|
|
5386
|
+
cwd: this._cwd,
|
|
5387
|
+
maxSources: settings.maxSources,
|
|
5388
|
+
});
|
|
5288
5389
|
const result = await runResearch({
|
|
5289
5390
|
query: demand.query,
|
|
5290
5391
|
context: demand.context,
|
|
5392
|
+
sources: workspaceSources,
|
|
5291
5393
|
envelope: this._buildResearchLaneEnvelope(settings.maxUsd, laneProfile),
|
|
5292
5394
|
maxUsd: settings.maxUsd,
|
|
5293
5395
|
maxSources: settings.maxSources,
|
|
@@ -5346,6 +5448,20 @@ export class AgentSession {
|
|
|
5346
5448
|
});
|
|
5347
5449
|
if (record) {
|
|
5348
5450
|
appendLaneRecordSnapshot(this.sessionManager, record);
|
|
5451
|
+
// G3: a research lane's product is an evidence bundle, so its terminal record maps to
|
|
5452
|
+
// the evidence_bundle event. Lane outcome only (status/reasonCode/cost) — no findings text.
|
|
5453
|
+
this._emitAutonomyTelemetry({
|
|
5454
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.evidenceBundle,
|
|
5455
|
+
timestamp: new Date().toISOString(),
|
|
5456
|
+
payload: {
|
|
5457
|
+
laneId: record.laneId,
|
|
5458
|
+
laneType: record.type,
|
|
5459
|
+
status: record.status,
|
|
5460
|
+
reasonCode: record.reasonCode ?? null,
|
|
5461
|
+
costUsd: record.costUsd ?? null,
|
|
5462
|
+
hasEvidence: record.evidenceEntryId !== undefined,
|
|
5463
|
+
},
|
|
5464
|
+
});
|
|
5349
5465
|
}
|
|
5350
5466
|
return { started: true, record, result };
|
|
5351
5467
|
}
|
|
@@ -5356,6 +5472,18 @@ export class AgentSession {
|
|
|
5356
5472
|
});
|
|
5357
5473
|
if (record && !this._disposed) {
|
|
5358
5474
|
appendLaneRecordSnapshot(this.sessionManager, record);
|
|
5475
|
+
this._emitAutonomyTelemetry({
|
|
5476
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.evidenceBundle,
|
|
5477
|
+
timestamp: new Date().toISOString(),
|
|
5478
|
+
payload: {
|
|
5479
|
+
laneId: record.laneId,
|
|
5480
|
+
laneType: record.type,
|
|
5481
|
+
status: record.status,
|
|
5482
|
+
reasonCode: record.reasonCode ?? null,
|
|
5483
|
+
costUsd: record.costUsd ?? null,
|
|
5484
|
+
hasEvidence: record.evidenceEntryId !== undefined,
|
|
5485
|
+
},
|
|
5486
|
+
});
|
|
5359
5487
|
}
|
|
5360
5488
|
const message = error instanceof Error ? error.message : String(error);
|
|
5361
5489
|
this._emit({ type: "warning", message: `Research lane failed: ${message}` });
|
|
@@ -5458,7 +5586,7 @@ export class AgentSession {
|
|
|
5458
5586
|
});
|
|
5459
5587
|
return { started: true, record, outcome };
|
|
5460
5588
|
}
|
|
5461
|
-
this.saveWorkerResultSnapshot(outcome.result);
|
|
5589
|
+
this.saveWorkerResultSnapshot(outcome.result, workerRequest);
|
|
5462
5590
|
if (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {
|
|
5463
5591
|
this.addSpawnedUsage(spentUsage, { label: "worker-delegation", reportId: usageReportId });
|
|
5464
5592
|
}
|
|
@@ -5469,6 +5597,19 @@ export class AgentSession {
|
|
|
5469
5597
|
});
|
|
5470
5598
|
if (record) {
|
|
5471
5599
|
appendLaneRecordSnapshot(this.sessionManager, record);
|
|
5600
|
+
// G3: worker lane terminal record -> worker_result event. Lane outcome only
|
|
5601
|
+
// (status/reasonCode/cost) — never the worker's summary/changed-file text.
|
|
5602
|
+
this._emitAutonomyTelemetry({
|
|
5603
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerResult,
|
|
5604
|
+
timestamp: new Date().toISOString(),
|
|
5605
|
+
payload: {
|
|
5606
|
+
laneId: record.laneId,
|
|
5607
|
+
laneType: record.type,
|
|
5608
|
+
status: record.status,
|
|
5609
|
+
reasonCode: record.reasonCode ?? null,
|
|
5610
|
+
costUsd: record.costUsd ?? null,
|
|
5611
|
+
},
|
|
5612
|
+
});
|
|
5472
5613
|
}
|
|
5473
5614
|
return { started: true, record, outcome };
|
|
5474
5615
|
}
|
|
@@ -5479,6 +5620,17 @@ export class AgentSession {
|
|
|
5479
5620
|
});
|
|
5480
5621
|
if (record && !this._disposed) {
|
|
5481
5622
|
appendLaneRecordSnapshot(this.sessionManager, record);
|
|
5623
|
+
this._emitAutonomyTelemetry({
|
|
5624
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerResult,
|
|
5625
|
+
timestamp: new Date().toISOString(),
|
|
5626
|
+
payload: {
|
|
5627
|
+
laneId: record.laneId,
|
|
5628
|
+
laneType: record.type,
|
|
5629
|
+
status: record.status,
|
|
5630
|
+
reasonCode: record.reasonCode ?? null,
|
|
5631
|
+
costUsd: record.costUsd ?? null,
|
|
5632
|
+
},
|
|
5633
|
+
});
|
|
5482
5634
|
}
|
|
5483
5635
|
const message = error instanceof Error ? error.message : String(error);
|
|
5484
5636
|
this._emit({ type: "warning", message: `Worker delegation failed: ${message}` });
|
|
@@ -5750,17 +5902,32 @@ export class AgentSession {
|
|
|
5750
5902
|
// every pass, so advancing it for a no-op (which stores nothing) would make later passes
|
|
5751
5903
|
// reuse ids — and rollback keys on the id, so a collision blocks or misdirects rollback.
|
|
5752
5904
|
let auditSequence = getLearningAuditSnapshots(this.sessionManager.getEntries()).length;
|
|
5905
|
+
// G6 evidence strength: durable proposals accumulate observation counts across passes/sessions
|
|
5906
|
+
// so the gate can distinguish a one-off cue from a repeatedly-confirmed lesson. Built once per
|
|
5907
|
+
// pass; every increment is best-effort (store IO must never break reflection).
|
|
5908
|
+
const observationStore = ObservationStore.forAgentDir(this._agentDir);
|
|
5753
5909
|
let writeIndex = 0;
|
|
5754
5910
|
for (const write of result.writes) {
|
|
5755
5911
|
writeIndex += 1;
|
|
5756
5912
|
const proposalId = `${input.reportId ?? "reflection"}-w${writeIndex}`;
|
|
5757
5913
|
const proposal = proposalFromReflectionWrite(write, proposalId);
|
|
5758
5914
|
const rollback = rollbackPlanForReflectionWrite(write);
|
|
5915
|
+
let observations = 1;
|
|
5916
|
+
if (policy.enabled) {
|
|
5917
|
+
try {
|
|
5918
|
+
observations = observationStore.increment(observationKey(proposal.layer, proposal.summary));
|
|
5919
|
+
}
|
|
5920
|
+
catch {
|
|
5921
|
+
// A store read/write failure falls back to a fresh count of 1, which keeps the gate
|
|
5922
|
+
// proposal-first (never spuriously auto-applies) rather than crashing the pass.
|
|
5923
|
+
observations = 1;
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5759
5926
|
const decision = policy.enabled
|
|
5760
5927
|
? evaluateLearningDecision({
|
|
5761
5928
|
proposal,
|
|
5762
5929
|
confidence: policy.reflectionSourceConfidence,
|
|
5763
|
-
observations
|
|
5930
|
+
observations,
|
|
5764
5931
|
contradictions: 0,
|
|
5765
5932
|
settings: {
|
|
5766
5933
|
enabled: true,
|
|
@@ -5779,6 +5946,18 @@ export class AgentSession {
|
|
|
5779
5946
|
requiresApproval: false,
|
|
5780
5947
|
};
|
|
5781
5948
|
this.saveLearningDecisionSnapshot(decision);
|
|
5949
|
+
// G3: learning-gate outcome. Codes/numbers only — never the proposal summary/memory text.
|
|
5950
|
+
this._emitAutonomyTelemetry({
|
|
5951
|
+
type: AUTONOMY_TELEMETRY_EVENT_TYPES.learningDecision,
|
|
5952
|
+
timestamp: new Date().toISOString(),
|
|
5953
|
+
payload: {
|
|
5954
|
+
kind: decision.kind,
|
|
5955
|
+
reasonCode: decision.reasonCode,
|
|
5956
|
+
layer: proposal.layer,
|
|
5957
|
+
confidence: decision.confidence,
|
|
5958
|
+
requiresApproval: decision.requiresApproval,
|
|
5959
|
+
},
|
|
5960
|
+
});
|
|
5782
5961
|
if (decision.kind === "apply") {
|
|
5783
5962
|
await this._applyReflectionWrite(write, signal);
|
|
5784
5963
|
}
|