@unbrained/pm-cli 2026.9.2 → 2026.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +44 -0
- package/dist/cli/after-command-context-usage.js +16 -3
- package/dist/cli-bundle/bundle-manifest.json +151 -151
- package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +230 -0
- package/dist/cli-bundle/chunks/chunk-A24WAVE6.js +8 -0
- package/dist/cli-bundle/chunks/{chunk-TAG4VC22.js → chunk-HI6BHPCU.js} +27 -27
- package/dist/cli-bundle/chunks/{chunk-Y7VOMSZT.js → chunk-I2AS367G.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-X4RCGLTX.js → chunk-OGBVU67G.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-DTGWEL23.js → chunk-RI4XNOYS.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +38 -0
- package/dist/cli-bundle/chunks/{chunk-FZ4Z2J4F.js → chunk-V72UV7QS.js} +76 -79
- package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-T6H5BZCP.js → chunk-X6CMGV6L.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-3WICXLVT.js → chunk-YW4QK2G7.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-XYNX4ASQ.js → register-list-query-Z5YYSJJG.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-WFQ7MJTX.js → register-mutation-ELSP6I4I.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-JVTI7JPP.js → register-operations-OH7R3ZT4.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-KVNC5KPL.js → register-setup-E2AE72QG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-MEASX544.js → chunk-25UJBH4M.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-SVXJYD6G.js → chunk-3646BZ4W.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-53IHPICX.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +176 -0
- package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +54 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4O4CJAR6.js → chunk-6PWPQKDN.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-7N2TV7WZ.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-AJR3OP2E.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +9 -0
- package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +6 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KB5OFSFD.js → chunk-MHKUIPJW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-NBMJD6MK.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-BEVHCEWG.js → chunk-P2GOAOQN.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +2 -0
- package/dist/cli-bundle/main.js +15 -15
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +28 -31
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +43 -36
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +10 -10
- package/dist/core/diagnostics/remediation.js +4 -4
- package/dist/core/history/event-classification.d.ts +21 -0
- package/dist/core/history/event-classification.js +109 -0
- package/dist/core/history/event-index.d.ts +14 -3
- package/dist/core/history/event-index.js +543 -88
- package/dist/core/history/history.d.ts +37 -1
- package/dist/core/history/history.js +320 -71
- package/dist/core/history/replay.js +68 -34
- package/dist/core/history/workspace-history.js +7 -6
- package/dist/core/lock/lock.d.ts +32 -2
- package/dist/core/lock/lock.js +161 -20
- package/dist/core/output/output.js +31 -7
- package/dist/core/shared/author.d.ts +3 -1
- package/dist/core/shared/author.js +111 -23
- package/dist/core/shared/time.d.ts +2 -0
- package/dist/core/shared/time.js +8 -2
- package/dist/core/store/item-metadata-query-index.js +5 -5
- package/dist/sdk/context/recency.d.ts +9 -0
- package/dist/sdk/context/recency.js +34 -0
- package/dist/sdk/context/usage-egress.d.ts +9 -0
- package/dist/sdk/context/usage-egress.js +30 -0
- package/dist/sdk/context-intent-contracts.js +7 -3
- package/dist/sdk/context-relevance.d.ts +23 -0
- package/dist/sdk/context-relevance.js +94 -23
- package/dist/sdk/context-signal-store.d.ts +7 -3
- package/dist/sdk/context-signal-store.js +155 -42
- package/dist/sdk/context-usage.d.ts +54 -0
- package/dist/sdk/context-usage.js +245 -16
- package/dist/sdk/environment/agent-environment.d.ts +296 -0
- package/dist/sdk/environment/agent-environment.js +467 -0
- package/dist/sdk/environment/project-runtime-compatibility.d.ts +19 -1
- package/dist/sdk/environment/project-runtime-compatibility.js +118 -21
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
- package/dist/sdk/governance/health.js +13 -44
- package/dist/sdk/governance/merge-receipt-history.d.ts +62 -0
- package/dist/sdk/governance/merge-receipt-history.js +207 -0
- package/dist/sdk/governance/provenance-health.js +9 -3
- package/dist/sdk/history-compact.js +14 -5
- package/dist/sdk/history-redact.js +58 -23
- package/dist/sdk/history-repair.js +16 -6
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +6 -2
- package/dist/sdk/init.d.ts +2 -0
- package/dist/sdk/init.js +18 -9
- package/dist/sdk/merge/driver.d.ts +3 -1
- package/dist/sdk/merge/driver.js +9 -9
- package/dist/sdk/merge/index.d.ts +1 -1
- package/dist/sdk/merge/index.js +3 -3
- package/dist/sdk/merge/receipts.d.ts +17 -6
- package/dist/sdk/merge/receipts.js +246 -75
- package/dist/sdk/merge/reconcile.d.ts +9 -7
- package/dist/sdk/merge/reconcile.js +175 -12
- package/dist/sdk/merge/three-way.d.ts +22 -2
- package/dist/sdk/merge/three-way.js +92 -25
- package/dist/sdk/query/context.d.ts +3 -1
- package/dist/sdk/query/context.js +21 -9
- package/dist/sdk/query/next.js +18 -9
- package/dist/sdk/runtime-input.d.ts +2 -0
- package/dist/sdk/runtime-input.js +25 -2
- package/dist/sdk/runtime-primitives.d.ts +2 -2
- package/dist/sdk/runtime-primitives.js +4 -4
- package/dist/sdk/runtime.d.ts +1 -0
- package/dist/sdk/runtime.js +17 -26
- package/dist/types.d.ts +27 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_ENVIRONMENTS.md +47 -0
- package/docs/AGENT_PROVENANCE_ADR.md +17 -2
- package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +38 -1
- package/docs/CONTEXT_RELEVANCE.md +44 -1
- package/docs/MERGE_SAFETY.md +119 -23
- package/docs/PERFORMANCE.md +6 -3
- package/docs/README.md +1 -0
- package/docs/READ_OUTPUT_CONTRACTS.md +9 -1
- package/docs/SDK.md +11 -8
- package/docs/SDK_CONTEXT.md +7 -0
- package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +24 -2
- package/docs/SDK_RUNTIME_BOUNDARIES.md +17 -1
- package/docs/examples/sdk-agent-environment/README.md +14 -0
- package/docs/examples/sdk-agent-environment/package.json +8 -0
- package/docs/examples/sdk-agent-environment/run-agent-environment.mjs +154 -0
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +5 -3
- package/marketplace.json +2 -2
- package/package.json +5 -5
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +773 -46
- package/dist/cli-bundle/chunks/chunk-GOACULJW.js +0 -13
- package/dist/cli-bundle/chunks/chunk-NOPL37X4.js +0 -205
- package/dist/cli-bundle/chunks/chunk-UDW64J2W.js +0 -8
- package/dist/cli-bundle/chunks/chunk-ZLJIFSOE.js +0 -35
- package/dist/cli-bundle/focused-chunks/chunk-242AXYB2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2FEZ5SKM.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-6GCRSLPG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-7VATS5QY.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-JEFKLWMM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-MKHG3T76.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-O67VDLOT.js +0 -51
- package/dist/cli-bundle/focused-chunks/chunk-PF3E6Q36.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-QDFJIRKN.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-RMRCQPWU.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-S4U5CN5Q.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-T2LXXSOD.js +0 -158
- package/dist/cli-bundle/focused-chunks/chunk-Z2USIBR2.js +0 -5
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* intents; it never enters item history and is safe to delete or rebuild.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
9
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="997a09a2-cf0c-5384-b457-d9627d465b71")}catch(e){}}();
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { appendFile, mkdir, readFile, rename, stat, writeFile, } from "node:fs/promises";
|
|
12
12
|
import path from "node:path";
|
|
@@ -16,6 +16,154 @@ const DEFAULT_RETENTION_DAYS = 30;
|
|
|
16
16
|
const DAY_MS = 86_400_000;
|
|
17
17
|
const DEFAULT_COMPACTION_BYTES = 262_144;
|
|
18
18
|
const CONTEXT_USAGE_LOCK_ID = "context-usage-ledger";
|
|
19
|
+
const CONTEXT_USAGE_SERVING_RECEIPT = Symbol.for("@unbrained/pm-cli/context-usage-serving-receipt");
|
|
20
|
+
function asObjectRecord(value) {
|
|
21
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
22
|
+
? value
|
|
23
|
+
: null;
|
|
24
|
+
}
|
|
25
|
+
/** Attach a JSON-invisible serving receipt to a result for later egress. */
|
|
26
|
+
export function attachContextUsageServingReceipt(result, receipt) {
|
|
27
|
+
const record = asObjectRecord(result);
|
|
28
|
+
if (record !== null && receipt !== null) {
|
|
29
|
+
record[CONTEXT_USAGE_SERVING_RECEIPT] = receipt;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Copy an attached serving receipt across a result projection boundary. */
|
|
33
|
+
export function propagateContextUsageServingReceipt(source, target) {
|
|
34
|
+
const sourceRecord = asObjectRecord(source);
|
|
35
|
+
const targetRecord = asObjectRecord(target);
|
|
36
|
+
const receipt = sourceRecord?.[CONTEXT_USAGE_SERVING_RECEIPT];
|
|
37
|
+
if (targetRecord !== null && receipt !== undefined) {
|
|
38
|
+
targetRecord[CONTEXT_USAGE_SERVING_RECEIPT] = receipt;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function receiptFromResult(result) {
|
|
42
|
+
return (asObjectRecord(result)?.[CONTEXT_USAGE_SERVING_RECEIPT] ?? null);
|
|
43
|
+
}
|
|
44
|
+
function resultReceiptSaysOmitted(result) {
|
|
45
|
+
const record = asObjectRecord(result);
|
|
46
|
+
for (const key of ["read_output", "context_intent"]) {
|
|
47
|
+
const receipt = asObjectRecord(record?.[key]);
|
|
48
|
+
if (receipt?.result_omitted === true)
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
function addContextUsageId(ids, value) {
|
|
54
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
55
|
+
ids.add(value.trim());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function addContextUsageDirectRows(ids, value) {
|
|
59
|
+
if (!Array.isArray(value))
|
|
60
|
+
return;
|
|
61
|
+
for (const row of value) {
|
|
62
|
+
addContextUsageId(ids, asObjectRecord(row)?.id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function addContextUsageIdList(ids, value) {
|
|
66
|
+
if (!Array.isArray(value))
|
|
67
|
+
return;
|
|
68
|
+
for (const itemId of value)
|
|
69
|
+
addContextUsageId(ids, itemId);
|
|
70
|
+
}
|
|
71
|
+
function collectNextResultItemIds(record, ids) {
|
|
72
|
+
const rows = [
|
|
73
|
+
...(asObjectRecord(record.recommended) === null
|
|
74
|
+
? []
|
|
75
|
+
: [record.recommended]),
|
|
76
|
+
...(Array.isArray(record.ready) ? record.ready : []),
|
|
77
|
+
...(Array.isArray(record.decision_needed) ? record.decision_needed : []),
|
|
78
|
+
...(Array.isArray(record.blocked) ? record.blocked : []),
|
|
79
|
+
...(Array.isArray(record.held_by_others) ? record.held_by_others : []),
|
|
80
|
+
];
|
|
81
|
+
for (const value of rows) {
|
|
82
|
+
const row = asObjectRecord(value);
|
|
83
|
+
addContextUsageId(ids, row?.id);
|
|
84
|
+
for (const blocker of Array.isArray(row?.blockers) ? row.blockers : []) {
|
|
85
|
+
addContextUsageId(ids, asObjectRecord(blocker)?.id);
|
|
86
|
+
}
|
|
87
|
+
for (const unblockedId of Array.isArray(row?.unblocks)
|
|
88
|
+
? row.unblocks
|
|
89
|
+
: []) {
|
|
90
|
+
addContextUsageId(ids, unblockedId);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function collectContextResultItemIds(record, ids) {
|
|
95
|
+
for (const key of [
|
|
96
|
+
"high_level",
|
|
97
|
+
"low_level",
|
|
98
|
+
"blocked_fallback",
|
|
99
|
+
"recently_created",
|
|
100
|
+
"unparented",
|
|
101
|
+
"activity",
|
|
102
|
+
"progress",
|
|
103
|
+
"blockers",
|
|
104
|
+
"staleness",
|
|
105
|
+
]) {
|
|
106
|
+
addContextUsageDirectRows(ids, record[key]);
|
|
107
|
+
}
|
|
108
|
+
for (const value of Array.isArray(record.blockers)
|
|
109
|
+
? record.blockers
|
|
110
|
+
: []) {
|
|
111
|
+
addContextUsageId(ids, asObjectRecord(value)?.blocked_by);
|
|
112
|
+
}
|
|
113
|
+
collectContextNestedItemIds(record, ids);
|
|
114
|
+
}
|
|
115
|
+
function collectContextNestedItemIds(record, ids) {
|
|
116
|
+
for (const value of Array.isArray(record.hierarchy)
|
|
117
|
+
? record.hierarchy
|
|
118
|
+
: []) {
|
|
119
|
+
const node = asObjectRecord(value);
|
|
120
|
+
addContextUsageId(ids, node?.id);
|
|
121
|
+
addContextUsageDirectRows(ids, node?.children);
|
|
122
|
+
}
|
|
123
|
+
for (const key of ["files", "workload"]) {
|
|
124
|
+
for (const value of Array.isArray(record[key]) ? record[key] : []) {
|
|
125
|
+
addContextUsageIdList(ids, asObjectRecord(value)?.items);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const agenda = asObjectRecord(record.agenda);
|
|
129
|
+
for (const value of Array.isArray(agenda?.events) ? agenda.events : []) {
|
|
130
|
+
addContextUsageId(ids, asObjectRecord(value)?.item_id);
|
|
131
|
+
}
|
|
132
|
+
const tests = asObjectRecord(record.tests);
|
|
133
|
+
addContextUsageIdList(ids, tests?.items_failing);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Collect every item identifier visible in a final context or next result.
|
|
137
|
+
* The traversal is shape-aware so summary counters and unrelated identifier
|
|
138
|
+
* fields cannot enter the privacy-minimal usage ledger.
|
|
139
|
+
*/
|
|
140
|
+
export function collectContextUsageDeliveredItemIds(result, surface) {
|
|
141
|
+
const record = asObjectRecord(result);
|
|
142
|
+
if (record === null || resultReceiptSaysOmitted(result))
|
|
143
|
+
return [];
|
|
144
|
+
const ids = new Set();
|
|
145
|
+
if (surface === "next") {
|
|
146
|
+
collectNextResultItemIds(record, ids);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
collectContextResultItemIds(record, ids);
|
|
150
|
+
}
|
|
151
|
+
return [...ids];
|
|
152
|
+
}
|
|
153
|
+
/** Resolve and append one post-egress decision carried by a context result. */
|
|
154
|
+
export async function finalizeContextUsageDelivery(options) {
|
|
155
|
+
const receipt = receiptFromResult(options.result);
|
|
156
|
+
if (receipt === null)
|
|
157
|
+
return false;
|
|
158
|
+
const resultOmitted = resultReceiptSaysOmitted(options.result);
|
|
159
|
+
await recordContextUsageDelivery({
|
|
160
|
+
pmRoot: options.pmRoot,
|
|
161
|
+
receipt,
|
|
162
|
+
deliveredItemIds: collectContextUsageDeliveredItemIds(options.result, receipt.surface),
|
|
163
|
+
resultOmitted,
|
|
164
|
+
});
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
19
167
|
/** Named validation failure emitted by context-usage SDK inputs. */
|
|
20
168
|
export class ContextUsageValidationError extends TypeError {
|
|
21
169
|
/** Stable machine-readable error code for package and CLI hosts. */
|
|
@@ -61,7 +209,7 @@ async function readEvents(options) {
|
|
|
61
209
|
return [];
|
|
62
210
|
}
|
|
63
211
|
}
|
|
64
|
-
async function appendEvents(options, events) {
|
|
212
|
+
async function appendEvents(options, events, deliveryServeId) {
|
|
65
213
|
const maxEvents = options.maxEvents ?? DEFAULT_MAX_EVENTS;
|
|
66
214
|
const retentionDays = options.retentionDays ?? DEFAULT_RETENTION_DAYS;
|
|
67
215
|
if (!Number.isInteger(maxEvents) ||
|
|
@@ -75,6 +223,10 @@ async function appendEvents(options, events) {
|
|
|
75
223
|
const releaseLock = await acquireLock(options.pmRoot, CONTEXT_USAGE_LOCK_ID, 30, `context-usage:${process.pid}`, false, false, 3_000);
|
|
76
224
|
try {
|
|
77
225
|
await mkdir(runtimeDirectory, { recursive: true });
|
|
226
|
+
if (deliveryServeId !== undefined &&
|
|
227
|
+
(await readEvents(options)).some((event) => event.kind === "delivery" && event.serve_id === deliveryServeId)) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
78
230
|
await appendFile(target, events.map((event) => `${JSON.stringify(event)}\n`).join(""), "utf8");
|
|
79
231
|
const customBounds = options.maxEvents !== undefined || options.retentionDays !== undefined;
|
|
80
232
|
if (!customBounds && (await stat(target)).size <= DEFAULT_COMPACTION_BYTES)
|
|
@@ -93,21 +245,70 @@ async function appendEvent(options, event) {
|
|
|
93
245
|
}
|
|
94
246
|
/** Records a propensity-complete context/next serving event. */
|
|
95
247
|
export async function recordContextUsageServing(options) {
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
248
|
+
if ([
|
|
249
|
+
process.env.PM_CONTEXT_USAGE_DISABLED === "1",
|
|
250
|
+
options.enabled === false,
|
|
251
|
+
].includes(true))
|
|
252
|
+
return null;
|
|
99
253
|
if (!options.author.trim() ||
|
|
100
254
|
options.rows.some((row) => !row.id.trim() || !Number.isInteger(row.rank) || row.rank < 1)) {
|
|
101
255
|
throw new ContextUsageValidationError("Context usage serving requires an author and valid ranked rows");
|
|
102
256
|
}
|
|
257
|
+
const normalizedRows = options.rows.map((row) => ({
|
|
258
|
+
...row,
|
|
259
|
+
id: row.id.trim(),
|
|
260
|
+
}));
|
|
261
|
+
if (new Set(normalizedRows.map((row) => row.id)).size !== normalizedRows.length) {
|
|
262
|
+
throw new ContextUsageValidationError("Context usage serving requires unique normalized row ids");
|
|
263
|
+
}
|
|
264
|
+
const receipt = {
|
|
265
|
+
serve_id: randomUUID(),
|
|
266
|
+
author: options.author.trim(),
|
|
267
|
+
surface: options.surface,
|
|
268
|
+
rows: normalizedRows,
|
|
269
|
+
};
|
|
103
270
|
await appendEvent(options, {
|
|
104
271
|
kind: "serve",
|
|
272
|
+
schema_version: 2,
|
|
273
|
+
serve_id: receipt.serve_id,
|
|
105
274
|
at: resolveNow(options).iso,
|
|
106
275
|
author: options.author.trim(),
|
|
107
276
|
surface: options.surface,
|
|
108
277
|
profile: options.profile.trim() || "balanced",
|
|
109
|
-
rows:
|
|
278
|
+
rows: receipt.rows.map((row) => ({ ...row })),
|
|
279
|
+
result_omitted: false,
|
|
280
|
+
packed_item_ids: receipt.rows
|
|
281
|
+
.filter((row) => row.included)
|
|
282
|
+
.map((row) => row.id),
|
|
110
283
|
});
|
|
284
|
+
return receipt;
|
|
285
|
+
}
|
|
286
|
+
/** Append the exact post-egress delivery decision for one serving receipt. */
|
|
287
|
+
export async function recordContextUsageDelivery(options) {
|
|
288
|
+
if (options.receipt === null ||
|
|
289
|
+
process.env.PM_CONTEXT_USAGE_DISABLED === "1" ||
|
|
290
|
+
options.enabled === false) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const rankedIds = new Set(options.receipt.rows.map((row) => row.id));
|
|
294
|
+
const deliveredItemIds = [
|
|
295
|
+
...new Set(options.deliveredItemIds.map((id) => id.trim())),
|
|
296
|
+
];
|
|
297
|
+
if (deliveredItemIds.some((id) => id.length === 0 || !rankedIds.has(id)) ||
|
|
298
|
+
(options.resultOmitted && deliveredItemIds.length > 0)) {
|
|
299
|
+
throw new ContextUsageValidationError("Context usage delivery requires emitted ranked ids and zero ids for an omitted result");
|
|
300
|
+
}
|
|
301
|
+
const delivery = {
|
|
302
|
+
kind: "delivery",
|
|
303
|
+
schema_version: 2,
|
|
304
|
+
serve_id: options.receipt.serve_id,
|
|
305
|
+
at: resolveNow(options).iso,
|
|
306
|
+
author: options.receipt.author,
|
|
307
|
+
surface: options.receipt.surface,
|
|
308
|
+
result_omitted: options.resultOmitted,
|
|
309
|
+
delivered_item_ids: deliveredItemIds,
|
|
310
|
+
};
|
|
311
|
+
await appendEvents(options, [delivery], delivery.serve_id);
|
|
111
312
|
}
|
|
112
313
|
/** Records one subsequent item read or mutation outcome. */
|
|
113
314
|
export async function recordContextUsageTouch(options) {
|
|
@@ -165,6 +366,18 @@ function findTouchTimeInHorizon(touches, itemId, servedAt, horizonMs) {
|
|
|
165
366
|
time >= servedAt &&
|
|
166
367
|
time - servedAt <= horizonMs)?.time;
|
|
167
368
|
}
|
|
369
|
+
function firstDeliveriesByServeId(events, author) {
|
|
370
|
+
const deliveries = new Map();
|
|
371
|
+
for (const event of events) {
|
|
372
|
+
if (event.kind === "delivery" &&
|
|
373
|
+
event.schema_version === 2 &&
|
|
374
|
+
event.author === author &&
|
|
375
|
+
!deliveries.has(event.serve_id)) {
|
|
376
|
+
deliveries.set(event.serve_id, event);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return deliveries;
|
|
380
|
+
}
|
|
168
381
|
/**
|
|
169
382
|
* Derives decayed served-then-touched affinity. A small exploration floor keeps
|
|
170
383
|
* ignored and unseen items eligible, preventing a popularity feedback lock-in.
|
|
@@ -172,26 +385,41 @@ function findTouchTimeInHorizon(touches, itemId, servedAt, horizonMs) {
|
|
|
172
385
|
export async function readContextUsageAffinity(options) {
|
|
173
386
|
if (process.env.PM_CONTEXT_USAGE_DISABLED === "1" ||
|
|
174
387
|
options.enabled === false)
|
|
175
|
-
return {
|
|
388
|
+
return {
|
|
389
|
+
affinity: {},
|
|
390
|
+
positive_judgments: 0,
|
|
391
|
+
serving_events: 0,
|
|
392
|
+
untrusted_serving_events: 0,
|
|
393
|
+
};
|
|
176
394
|
const events = await readEvents(options);
|
|
177
395
|
const now = resolveNow(options).ms;
|
|
178
396
|
const horizonMs = (options.horizonHours ?? 24) * 3_600_000;
|
|
179
|
-
if (!Number.isFinite(horizonMs)
|
|
397
|
+
if (![Number.isFinite(horizonMs), horizonMs > 0].every(Boolean))
|
|
180
398
|
throw new ContextUsageValidationError("Context usage horizonHours must be positive");
|
|
181
399
|
const author = options.author.trim();
|
|
182
400
|
const touches = events
|
|
183
|
-
.filter((event) => event.kind === "touch"
|
|
401
|
+
.filter((event) => event.kind === "touch")
|
|
402
|
+
.filter((event) => event.author === author)
|
|
184
403
|
.map((entry) => ({ entry, time: Date.parse(entry.at) }));
|
|
185
404
|
const scores = new Map();
|
|
186
405
|
let servingEvents = 0;
|
|
406
|
+
let untrustedServingEvents = 0;
|
|
187
407
|
let positiveJudgments = 0;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
408
|
+
const deliveries = firstDeliveriesByServeId(events, author);
|
|
409
|
+
events
|
|
410
|
+
.filter((event) => event.kind === "serve")
|
|
411
|
+
.filter((event) => event.author === author)
|
|
412
|
+
.forEach((event) => {
|
|
413
|
+
if (![event.schema_version === 2, Boolean(event.serve_id)].every(Boolean)) {
|
|
414
|
+
untrustedServingEvents += 1;
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
191
417
|
servingEvents += 1;
|
|
192
418
|
const servedAt = Date.parse(event.at);
|
|
419
|
+
const delivery = deliveries.get(event.serve_id);
|
|
420
|
+
const deliveredIds = new Set(delivery?.delivered_item_ids ?? []);
|
|
193
421
|
for (const row of event.rows) {
|
|
194
|
-
if (!row.
|
|
422
|
+
if (!deliveredIds.has(row.id))
|
|
195
423
|
continue;
|
|
196
424
|
const touchTime = findTouchTimeInHorizon(touches, row.id, servedAt, horizonMs);
|
|
197
425
|
if (touchTime === undefined)
|
|
@@ -200,17 +428,18 @@ export async function readContextUsageAffinity(options) {
|
|
|
200
428
|
const ageDays = Math.max(0, (now - touchTime) / DAY_MS);
|
|
201
429
|
scores.set(row.id, (scores.get(row.id) ?? 0) + Math.exp(-ageDays / 14));
|
|
202
430
|
}
|
|
203
|
-
}
|
|
431
|
+
});
|
|
204
432
|
const maximum = Math.max(0, ...scores.values());
|
|
205
433
|
const affinity = Object.fromEntries([...scores.entries()].map(([id, score]) => [
|
|
206
434
|
id,
|
|
207
|
-
0.05
|
|
435
|
+
maximum === 0 ? 0.05 : 0.05 + (0.95 * score) / maximum,
|
|
208
436
|
]));
|
|
209
437
|
return {
|
|
210
438
|
affinity,
|
|
211
439
|
positive_judgments: positiveJudgments,
|
|
212
440
|
serving_events: servingEvents,
|
|
441
|
+
untrusted_serving_events: untrustedServingEvents,
|
|
213
442
|
};
|
|
214
443
|
}
|
|
215
444
|
//# sourceMappingURL=context-usage.js.map
|
|
216
|
-
//# debugId=
|
|
445
|
+
//# debugId=997a09a2-cf0c-5384-b457-d9627d465b71
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { type WorkspaceRecipe } from "../workspace-recipe.js";
|
|
2
|
+
/** Schema identifier for a portable observation contract. */
|
|
3
|
+
export declare const PM_OBSERVATION_SCHEMA: "pm.agent-observation/v1";
|
|
4
|
+
/** Schema identifier for a deterministic verdict contract. */
|
|
5
|
+
export declare const PM_VERDICT_SCHEMA: "pm.agent-verdict/v1";
|
|
6
|
+
/** Schema identifier for a bounded agent-environment episode. */
|
|
7
|
+
export declare const PM_EPISODE_SCHEMA: "pm.agent-episode/v1";
|
|
8
|
+
/** A JSON-compatible object used as immutable recorded workspace state. */
|
|
9
|
+
export type RecordedStateObject = Readonly<Record<string, unknown>>;
|
|
10
|
+
/** One declared read and its guaranteed token ceiling. */
|
|
11
|
+
export interface ObservationReadDeclaration {
|
|
12
|
+
/** Public SDK or CLI command name used to collect the read. */
|
|
13
|
+
command: string;
|
|
14
|
+
/** Maximum tokens this read may consume. */
|
|
15
|
+
budget_tokens: number;
|
|
16
|
+
}
|
|
17
|
+
/** Emitted-byte calibration for a representative observation corpus. */
|
|
18
|
+
export interface ObservationCalibration {
|
|
19
|
+
/** Stable measurement basis; serialized payload bytes are authoritative. */
|
|
20
|
+
basis: "emitted_bytes";
|
|
21
|
+
/** Historical emitted-byte measurements used to calibrate expectations. */
|
|
22
|
+
samples: readonly number[];
|
|
23
|
+
/** Expected serialized payload size before an observation is served. */
|
|
24
|
+
expected_emitted_bytes: number;
|
|
25
|
+
/** Accepted drift around the expected emitted-byte measurement. */
|
|
26
|
+
tolerance_bytes: number;
|
|
27
|
+
}
|
|
28
|
+
/** Declares whether observation cost varies with corpus size. */
|
|
29
|
+
export type ObservationCorpusDependence = {
|
|
30
|
+
readonly kind: "independent";
|
|
31
|
+
} | {
|
|
32
|
+
readonly kind: "bounded";
|
|
33
|
+
readonly dimension: string;
|
|
34
|
+
readonly maximum: number;
|
|
35
|
+
};
|
|
36
|
+
/** One ordered disclosure tier in an observation degradation ladder. */
|
|
37
|
+
export interface ObservationTier {
|
|
38
|
+
/** Stable tier identity included in every observation receipt. */
|
|
39
|
+
id: string;
|
|
40
|
+
/** Maximum tokens this tier is permitted to emit. */
|
|
41
|
+
max_tokens: number;
|
|
42
|
+
/** Dot-separated recorded-state fields disclosed by the tier. */
|
|
43
|
+
fields: readonly string[];
|
|
44
|
+
}
|
|
45
|
+
/** Portable declaration for a bounded, calibrated observation. */
|
|
46
|
+
export interface ObservationContract {
|
|
47
|
+
/** Versioned schema identity. */
|
|
48
|
+
schema: typeof PM_OBSERVATION_SCHEMA;
|
|
49
|
+
/** Stable contract identity. */
|
|
50
|
+
id: string;
|
|
51
|
+
/** Positive contract revision. */
|
|
52
|
+
version: number;
|
|
53
|
+
/** Reads whose ceilings form the guaranteed collection cost. */
|
|
54
|
+
reads: readonly ObservationReadDeclaration[];
|
|
55
|
+
/** Emitted-byte calibration visible before collection starts. */
|
|
56
|
+
calibration: ObservationCalibration;
|
|
57
|
+
/** Explicit corpus-size dependence of the cost model. */
|
|
58
|
+
corpus_dependence: ObservationCorpusDependence;
|
|
59
|
+
/** Ordered richest-to-smallest degradation ladder. */
|
|
60
|
+
tiers: readonly ObservationTier[];
|
|
61
|
+
}
|
|
62
|
+
/** Pre-call observation-cost description available to schedulers. */
|
|
63
|
+
export interface ObservationCostDescription {
|
|
64
|
+
/** Stable observation identity. */
|
|
65
|
+
contract_id: string;
|
|
66
|
+
/** Observation revision. */
|
|
67
|
+
contract_version: number;
|
|
68
|
+
/** Sum of all declared collection ceilings. */
|
|
69
|
+
guaranteed_ceiling_tokens: number;
|
|
70
|
+
/** Calibrated expected serialized payload size. */
|
|
71
|
+
expected_emitted_bytes: number;
|
|
72
|
+
/** Conservative token estimate derived from emitted bytes. */
|
|
73
|
+
expected_tokens: number;
|
|
74
|
+
/** Accepted emitted-byte calibration drift. */
|
|
75
|
+
tolerance_bytes: number;
|
|
76
|
+
/** Stable calibration basis. */
|
|
77
|
+
calibration_basis: "emitted_bytes";
|
|
78
|
+
/** Declared corpus-size dependence. */
|
|
79
|
+
corpus_dependence: ObservationCorpusDependence;
|
|
80
|
+
}
|
|
81
|
+
/** Audit receipt emitted for every served or refused observation. */
|
|
82
|
+
export interface ObservationReceipt {
|
|
83
|
+
/** Stable observation identity. */
|
|
84
|
+
contract_id: string;
|
|
85
|
+
/** Observation revision. */
|
|
86
|
+
contract_version: number;
|
|
87
|
+
/** Tier whose payload was returned, or null after truthful refusal. */
|
|
88
|
+
served_tier: string | null;
|
|
89
|
+
/** Whether a smaller tier was attempted or served. */
|
|
90
|
+
degraded: boolean;
|
|
91
|
+
/** Tier identities evaluated in deterministic order. */
|
|
92
|
+
attempted_tiers: readonly string[];
|
|
93
|
+
/** Exact serialized payload bytes, or null when nothing was served. */
|
|
94
|
+
emitted_bytes: number | null;
|
|
95
|
+
/** Conservative token estimate, or null when nothing was served. */
|
|
96
|
+
estimated_tokens: number | null;
|
|
97
|
+
/** Stable measurement basis. */
|
|
98
|
+
calibration_basis: "emitted_bytes";
|
|
99
|
+
}
|
|
100
|
+
/** Successful bounded observation with its explicit receipt. */
|
|
101
|
+
export interface ServedObservation<T> {
|
|
102
|
+
/** Discriminator for a payload-bearing response. */
|
|
103
|
+
status: "served";
|
|
104
|
+
/** Payload produced by the declared tier. */
|
|
105
|
+
payload: T;
|
|
106
|
+
/** Cost and degradation evidence. */
|
|
107
|
+
receipt: ObservationReceipt;
|
|
108
|
+
}
|
|
109
|
+
/** Refusal returned when no declared tier can fit the caller's ceiling. */
|
|
110
|
+
export interface RefusedObservation {
|
|
111
|
+
/** Discriminator for a payload-free refusal. */
|
|
112
|
+
status: "refused";
|
|
113
|
+
/** Stable reason callers can route without parsing prose. */
|
|
114
|
+
reason: "no_declared_tier_fits_budget";
|
|
115
|
+
/** Cost and degradation evidence. */
|
|
116
|
+
receipt: ObservationReceipt;
|
|
117
|
+
}
|
|
118
|
+
/** Complete outcome of attempting one declared observation. */
|
|
119
|
+
export type ObservationResult<T> = ServedObservation<T> | RefusedObservation;
|
|
120
|
+
/** Caller-imposed ceiling for one observation response. */
|
|
121
|
+
export interface ObservationRequest {
|
|
122
|
+
/** Maximum response tokens accepted by the caller. */
|
|
123
|
+
budget_tokens: number;
|
|
124
|
+
}
|
|
125
|
+
/** Predicate supported by the versioned total-verdict interpreter. */
|
|
126
|
+
export type VerdictPredicate = {
|
|
127
|
+
readonly id: string;
|
|
128
|
+
readonly kind: "field_equals";
|
|
129
|
+
readonly path: string;
|
|
130
|
+
readonly expected: unknown;
|
|
131
|
+
} | {
|
|
132
|
+
readonly id: string;
|
|
133
|
+
readonly kind: "field_present";
|
|
134
|
+
readonly path: string;
|
|
135
|
+
} | {
|
|
136
|
+
readonly id: string;
|
|
137
|
+
readonly kind: "field_absent";
|
|
138
|
+
readonly path: string;
|
|
139
|
+
};
|
|
140
|
+
/** Declarative composition applied to predicate outcomes. */
|
|
141
|
+
export interface VerdictComposition {
|
|
142
|
+
/** Whether every or at least one referenced predicate must satisfy. */
|
|
143
|
+
operator: "all" | "any";
|
|
144
|
+
/** Ordered predicate identities evaluated by the total verdict. */
|
|
145
|
+
predicate_ids: readonly string[];
|
|
146
|
+
}
|
|
147
|
+
/** Portable named and versioned total-verdict declaration. */
|
|
148
|
+
export interface VerdictContract {
|
|
149
|
+
/** Versioned schema identity. */
|
|
150
|
+
schema: typeof PM_VERDICT_SCHEMA;
|
|
151
|
+
/** Stable contract identity. */
|
|
152
|
+
id: string;
|
|
153
|
+
/** Positive contract revision. */
|
|
154
|
+
version: number;
|
|
155
|
+
/** Predicates evaluated exclusively over recorded state. */
|
|
156
|
+
predicates: readonly VerdictPredicate[];
|
|
157
|
+
/** Explicit deterministic predicate composition. */
|
|
158
|
+
composition: VerdictComposition;
|
|
159
|
+
}
|
|
160
|
+
/** Recorded state and stable snapshot identity supplied by an adapter. */
|
|
161
|
+
export interface WorkspaceRecordedState {
|
|
162
|
+
/** Stable identity of the exact state being evaluated. */
|
|
163
|
+
snapshot_id: string;
|
|
164
|
+
/** Recorded, JSON-compatible project state. */
|
|
165
|
+
state: RecordedStateObject;
|
|
166
|
+
}
|
|
167
|
+
/** Per-predicate evidence in a deterministic total verdict. */
|
|
168
|
+
export interface PredicateVerdict {
|
|
169
|
+
/** Declared predicate identity. */
|
|
170
|
+
id: string;
|
|
171
|
+
/** Whether the predicate is satisfied by recorded state. */
|
|
172
|
+
outcome: "satisfied" | "violated";
|
|
173
|
+
/** Snapshot-qualified JSON pointer to the inspected field. */
|
|
174
|
+
evidence_pointer: string;
|
|
175
|
+
/** Hash of the observed value without duplicating potentially private data. */
|
|
176
|
+
evidence_digest: string;
|
|
177
|
+
}
|
|
178
|
+
/** Total, reproducible result produced by a verdict contract. */
|
|
179
|
+
export interface VerdictResult {
|
|
180
|
+
/** Stable verdict identity. */
|
|
181
|
+
contract_id: string;
|
|
182
|
+
/** Verdict revision. */
|
|
183
|
+
contract_version: number;
|
|
184
|
+
/** Exact recorded-state snapshot evaluated. */
|
|
185
|
+
snapshot_id: string;
|
|
186
|
+
/** Total outcome, including an explicit empty-contract state. */
|
|
187
|
+
outcome: "satisfied" | "violated" | "not_applicable";
|
|
188
|
+
/** Satisfied fraction, or null when no predicates are declared. */
|
|
189
|
+
score: number | null;
|
|
190
|
+
/** Explicitly separates evaluation from reward or learning signals. */
|
|
191
|
+
policy: "verdict_only_no_reward";
|
|
192
|
+
/** Stable explanation for a not-applicable verdict. */
|
|
193
|
+
reason?: "no_predicates_declared";
|
|
194
|
+
/** Ordered predicate evidence. */
|
|
195
|
+
predicates: readonly PredicateVerdict[];
|
|
196
|
+
}
|
|
197
|
+
/** Hard limits enforced within one isolated episode. */
|
|
198
|
+
export interface EpisodeLimits {
|
|
199
|
+
/** Maximum ordinary project-management actions. */
|
|
200
|
+
max_actions: number;
|
|
201
|
+
/** Maximum observations, including the close-time grading read. */
|
|
202
|
+
max_observations: number;
|
|
203
|
+
/** Per-observation response ceiling. */
|
|
204
|
+
max_tokens_per_observation: number;
|
|
205
|
+
}
|
|
206
|
+
/** Portable specification shared by evaluation and training harnesses. */
|
|
207
|
+
export interface EpisodeSpecification {
|
|
208
|
+
/** Versioned schema identity. */
|
|
209
|
+
schema: typeof PM_EPISODE_SCHEMA;
|
|
210
|
+
/** Stable episode identity and session provenance key. */
|
|
211
|
+
id: string;
|
|
212
|
+
/** Positive episode revision. */
|
|
213
|
+
version: number;
|
|
214
|
+
/** Consumer intent without coupling the runtime to a training framework. */
|
|
215
|
+
mode: "benchmark" | "evaluation" | "training" | "scale_transfer";
|
|
216
|
+
/** Deterministic workspace construction recipe. */
|
|
217
|
+
recipe: WorkspaceRecipe;
|
|
218
|
+
/** Canonical pm items that define the task set. */
|
|
219
|
+
task_item_ids: readonly string[];
|
|
220
|
+
/** State fields that observations may disclose. */
|
|
221
|
+
observable_fields: readonly string[];
|
|
222
|
+
/** Grading-only fields that must never enter observations. */
|
|
223
|
+
withheld_fields: readonly string[];
|
|
224
|
+
/** Bounded observation declaration. */
|
|
225
|
+
observation: ObservationContract;
|
|
226
|
+
/** Recorded-state verdict declaration. */
|
|
227
|
+
verdict: VerdictContract;
|
|
228
|
+
/** Hard action and observation limits. */
|
|
229
|
+
limits: EpisodeLimits;
|
|
230
|
+
}
|
|
231
|
+
/** Reset receipt returned by an episode adapter. */
|
|
232
|
+
export interface EpisodeResetReceipt {
|
|
233
|
+
/** Adapter-defined isolated workspace identity. */
|
|
234
|
+
workspace_id: string;
|
|
235
|
+
/** Stable state identity after reset. */
|
|
236
|
+
state_id: string;
|
|
237
|
+
}
|
|
238
|
+
/** Action receipt returned by an episode adapter. */
|
|
239
|
+
export interface EpisodeActionReceipt<TOutput> {
|
|
240
|
+
/** Stable state identity after the action. */
|
|
241
|
+
state_id: string;
|
|
242
|
+
/** Adapter-defined ordinary command result. */
|
|
243
|
+
output: TOutput;
|
|
244
|
+
}
|
|
245
|
+
/** Host boundary for ordinary pm SDK actions and recorded-state reads. */
|
|
246
|
+
export interface EpisodeRuntimeAdapter<TAction, TOutput = unknown> {
|
|
247
|
+
/** Construct a fresh isolated workspace using the declared recipe. */
|
|
248
|
+
reset(recipe: WorkspaceRecipe): Promise<EpisodeResetReceipt>;
|
|
249
|
+
/** Execute one ordinary action, normally by calling `PmClient.run`. */
|
|
250
|
+
execute(action: TAction): Promise<EpisodeActionReceipt<TOutput>>;
|
|
251
|
+
/** Read immutable grading state from the workspace system of record. */
|
|
252
|
+
readRecordedState(): Promise<WorkspaceRecordedState>;
|
|
253
|
+
}
|
|
254
|
+
/** One deterministic entry in a portable episode trajectory. */
|
|
255
|
+
export interface EpisodeTrajectoryEntry {
|
|
256
|
+
/** Monotonic event number within the isolated episode. */
|
|
257
|
+
sequence: number;
|
|
258
|
+
/** Stable event classification. */
|
|
259
|
+
kind: "reset" | "observation" | "action" | "verdict" | "close";
|
|
260
|
+
/** Snapshot, state, or observation tier associated with the event. */
|
|
261
|
+
state_id: string;
|
|
262
|
+
}
|
|
263
|
+
/** Closed episode evidence without reward or framework-specific shaping. */
|
|
264
|
+
export interface ClosedEpisode {
|
|
265
|
+
/** Deterministic total verdict. */
|
|
266
|
+
verdict: VerdictResult;
|
|
267
|
+
/** Complete bounded trajectory. */
|
|
268
|
+
trajectory: readonly EpisodeTrajectoryEntry[];
|
|
269
|
+
/** Explicitly absent to prevent verdicts from becoming reward signals. */
|
|
270
|
+
reward?: never;
|
|
271
|
+
}
|
|
272
|
+
/** Isolated runtime returned for one declared agent episode. */
|
|
273
|
+
export interface PmEpisodeSession<TAction, TOutput> {
|
|
274
|
+
/** Observe recorded state through the declared disclosure ladder. */
|
|
275
|
+
observe(): Promise<ObservationResult<RecordedStateObject>>;
|
|
276
|
+
/** Execute one bounded ordinary project-management action. */
|
|
277
|
+
step(action: TAction): Promise<EpisodeActionReceipt<TOutput>>;
|
|
278
|
+
/** Evaluate the current recorded state without closing the session. */
|
|
279
|
+
score(): Promise<VerdictResult>;
|
|
280
|
+
/** Evaluate and close the episode, returning immutable evidence. */
|
|
281
|
+
close(): Promise<ClosedEpisode>;
|
|
282
|
+
}
|
|
283
|
+
/** Validate, clone, and freeze a portable observation declaration. */
|
|
284
|
+
export declare function defineObservationContract(declaration: ObservationContract): ObservationContract;
|
|
285
|
+
/** Describe guaranteed and calibrated observation cost before collection. */
|
|
286
|
+
export declare function describeObservationCost(contract: ObservationContract): ObservationCostDescription;
|
|
287
|
+
/** Serve the richest declared tier that fits both caller and tier ceilings. */
|
|
288
|
+
export declare function serveDeclaredObservation<T>(contract: ObservationContract, collect: (tier: ObservationTier) => Promise<T>, request: ObservationRequest): Promise<ObservationResult<T>>;
|
|
289
|
+
/** Validate, clone, and freeze a portable total-verdict declaration. */
|
|
290
|
+
export declare function defineVerdictContract(declaration: VerdictContract): VerdictContract;
|
|
291
|
+
/** Evaluate a total verdict exclusively from one immutable recorded snapshot. */
|
|
292
|
+
export declare function evaluateVerdictContract(contract: VerdictContract, recorded: WorkspaceRecordedState): VerdictResult;
|
|
293
|
+
/** Validate, clone, and freeze a portable episode specification. */
|
|
294
|
+
export declare function defineEpisodeSpecification(declaration: EpisodeSpecification): EpisodeSpecification;
|
|
295
|
+
/** Open one isolated, deterministic episode around an adapter's ordinary actions. */
|
|
296
|
+
export declare function openPmEpisode<TAction, TOutput = unknown>(specification: EpisodeSpecification, adapter: EpisodeRuntimeAdapter<TAction, TOutput>): Promise<PmEpisodeSession<TAction, TOutput>>;
|