@akagilnc/pi-workflow-roles 0.1.2397 → 0.1.2402
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/doctor-contracts.js +2 -9
- package/dist/engine-detour-tool.js +10 -35
- package/dist/evidence-child-executor.js +11 -3
- package/dist/merger-contracts.js +2 -8
- package/dist/navigator-attendance.js +1 -9
- package/dist/notary-contracts.js +3 -8
- package/dist/package-contracts/judge-output.js +1 -4
- package/dist/package-contracts/reviewer-output.js +1 -7
- package/dist/package-contracts/terminating-tools.js +5 -10
- package/dist/public-cli/main.js +24 -101
- package/package.json +1 -1
- package/scripts/build-package.mjs +1 -2
- package/src/analyst-metric-families/acceptance-success-rework.ts +3 -6
- package/src/collector-role.ts +1 -8
- package/src/doctor-contracts.ts +3 -18
- package/src/doctor-role.ts +1 -5
- package/src/engine-detour-tool.ts +16 -51
- package/src/evidence-child-executor.ts +11 -3
- package/src/factory-board.ts +2 -4
- package/src/judge-role.ts +1 -7
- package/src/merger-contracts.ts +3 -17
- package/src/merger-role.ts +1 -8
- package/src/navigator-attendance.ts +1 -14
- package/src/notary-contracts.ts +4 -24
- package/src/notary-role.ts +1 -3
- package/src/package-contracts/judge-output.ts +2 -17
- package/src/package-contracts/reviewer-output.ts +2 -21
- package/src/package-contracts/terminating-tools.ts +4 -13
- package/src/package-contracts/worker-output.ts +2 -10
- package/src/public-cli/settlement.ts +8 -20
- package/src/reviewer-role.ts +2 -10
- package/src/role-runtime.ts +1 -28
- package/src/worker-role.ts +2 -14
- package/dist/engine-labor-fallback.js +0 -136
- package/src/engine-labor-fallback.ts +0 -270
package/src/worker-role.ts
CHANGED
|
@@ -6,10 +6,6 @@ import type {
|
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { Type, type Static } from "typebox";
|
|
8
8
|
import { openToolObjectFromUnion } from "./open-tool-schema.ts";
|
|
9
|
-
import {
|
|
10
|
-
readActivationEngineLaborFallbackField,
|
|
11
|
-
withEngineLaborFallbackField,
|
|
12
|
-
} from "./engine-labor-fallback.ts";
|
|
13
9
|
|
|
14
10
|
import type {
|
|
15
11
|
AnyCanonicalSkillBinding,
|
|
@@ -299,11 +295,7 @@ export function createFixerRoleRuntime(
|
|
|
299
295
|
toolCallId,
|
|
300
296
|
});
|
|
301
297
|
}
|
|
302
|
-
|
|
303
|
-
const acceptedDetails = withEngineLaborFallbackField(
|
|
304
|
-
output,
|
|
305
|
-
readActivationEngineLaborFallbackField(),
|
|
306
|
-
);
|
|
298
|
+
const acceptedDetails = output;
|
|
307
299
|
return {
|
|
308
300
|
content: [{ type: "text" as const, text: "Fixer report accepted" }],
|
|
309
301
|
details: acceptedDetails,
|
|
@@ -452,11 +444,7 @@ export function createCoderRoleRuntime(
|
|
|
452
444
|
toolCallId,
|
|
453
445
|
});
|
|
454
446
|
}
|
|
455
|
-
|
|
456
|
-
const acceptedDetails = withEngineLaborFallbackField(
|
|
457
|
-
output,
|
|
458
|
-
readActivationEngineLaborFallbackField(),
|
|
459
|
-
);
|
|
447
|
+
const acceptedDetails = output;
|
|
460
448
|
return {
|
|
461
449
|
content: [{ type: "text" as const, text: "Coder report accepted" }],
|
|
462
450
|
details: acceptedDetails,
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
let activationLatch;
|
|
2
|
-
function buildEngineLaborFallbackField(input) {
|
|
3
|
-
return Object.freeze({
|
|
4
|
-
engineLaborFallback: Object.freeze({
|
|
5
|
-
engine: input.engine,
|
|
6
|
-
failure: input.failure,
|
|
7
|
-
laborBy: "seat"
|
|
8
|
-
})
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
const SEAT_FALLBACK_STATUS_SUFFIX = "-by-fallback";
|
|
12
|
-
function isSeatFallbackTaintedStatus(status) {
|
|
13
|
-
return status.endsWith(SEAT_FALLBACK_STATUS_SUFFIX);
|
|
14
|
-
}
|
|
15
|
-
function seatFallbackBaseStatus(status) {
|
|
16
|
-
return isSeatFallbackTaintedStatus(status) ? status.slice(0, -SEAT_FALLBACK_STATUS_SUFFIX.length) : status;
|
|
17
|
-
}
|
|
18
|
-
function seatFallbackStatusHasLawfulEvidence(status, source) {
|
|
19
|
-
if (!isSeatFallbackTaintedStatus(status)) return true;
|
|
20
|
-
return readEngineLaborFallbackFieldFrom(source) !== void 0;
|
|
21
|
-
}
|
|
22
|
-
function taintStatusForSeatFallback(status) {
|
|
23
|
-
if (status.length === 0 || isSeatFallbackTaintedStatus(status)) return status;
|
|
24
|
-
return `${status}${SEAT_FALLBACK_STATUS_SUFFIX}`;
|
|
25
|
-
}
|
|
26
|
-
const STATUS_DISCRIMINATOR_KEYS = ["judgeStatus", "status"];
|
|
27
|
-
function taintReceiptStatusDiscriminators(receipt) {
|
|
28
|
-
let next;
|
|
29
|
-
for (const key of STATUS_DISCRIMINATOR_KEYS) {
|
|
30
|
-
if (!Object.prototype.hasOwnProperty.call(receipt, key)) continue;
|
|
31
|
-
let value;
|
|
32
|
-
try {
|
|
33
|
-
value = receipt[key];
|
|
34
|
-
} catch {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
if (typeof value !== "string" || value.length === 0) continue;
|
|
38
|
-
const tainted = taintStatusForSeatFallback(value);
|
|
39
|
-
if (tainted === value) continue;
|
|
40
|
-
if (next === void 0) {
|
|
41
|
-
next = { ...receipt };
|
|
42
|
-
}
|
|
43
|
-
next[key] = tainted;
|
|
44
|
-
}
|
|
45
|
-
return next === void 0 ? receipt : next;
|
|
46
|
-
}
|
|
47
|
-
function createEngineLaborFallbackLatch() {
|
|
48
|
-
return { field: void 0 };
|
|
49
|
-
}
|
|
50
|
-
function recordEngineLaborFallback(latch, input) {
|
|
51
|
-
const field = buildEngineLaborFallbackField(input);
|
|
52
|
-
if (latch.field === void 0) latch.field = field;
|
|
53
|
-
return latch.field;
|
|
54
|
-
}
|
|
55
|
-
function readEngineLaborFallbackField(latch) {
|
|
56
|
-
return latch?.field;
|
|
57
|
-
}
|
|
58
|
-
function withEngineLaborFallbackField(receipt, field) {
|
|
59
|
-
if (field !== void 0) {
|
|
60
|
-
const taintedReceipt = taintReceiptStatusDiscriminators(receipt);
|
|
61
|
-
return { ...taintedReceipt, ...field };
|
|
62
|
-
}
|
|
63
|
-
if (!Object.prototype.hasOwnProperty.call(receipt, "engineLaborFallback")) {
|
|
64
|
-
return receipt;
|
|
65
|
-
}
|
|
66
|
-
const { engineLaborFallback: _forged, ...rest } = receipt;
|
|
67
|
-
return rest;
|
|
68
|
-
}
|
|
69
|
-
function installActivationEngineLaborFallbackLatch(latch) {
|
|
70
|
-
activationLatch = latch;
|
|
71
|
-
}
|
|
72
|
-
function clearActivationEngineLaborFallbackLatch() {
|
|
73
|
-
activationLatch = void 0;
|
|
74
|
-
}
|
|
75
|
-
function activationEngineLaborFallbackLatch() {
|
|
76
|
-
return activationLatch;
|
|
77
|
-
}
|
|
78
|
-
function readActivationEngineLaborFallbackField() {
|
|
79
|
-
return readEngineLaborFallbackField(activationLatch);
|
|
80
|
-
}
|
|
81
|
-
function readEngineLaborFallbackFieldFrom(source) {
|
|
82
|
-
if (typeof source !== "object" || source === null || Array.isArray(source)) {
|
|
83
|
-
return void 0;
|
|
84
|
-
}
|
|
85
|
-
let raw;
|
|
86
|
-
try {
|
|
87
|
-
raw = source.engineLaborFallback;
|
|
88
|
-
} catch {
|
|
89
|
-
return void 0;
|
|
90
|
-
}
|
|
91
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
92
|
-
const rec = raw;
|
|
93
|
-
if (typeof rec.engine !== "string" || typeof rec.failure !== "string" || rec.laborBy !== "seat") {
|
|
94
|
-
return void 0;
|
|
95
|
-
}
|
|
96
|
-
return buildEngineLaborFallbackField({
|
|
97
|
-
engine: rec.engine,
|
|
98
|
-
failure: rec.failure
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
function restoreEngineLaborFallbackFromSessionEntries(latch, entries, toolName) {
|
|
102
|
-
for (const entry of entries) {
|
|
103
|
-
if (typeof entry !== "object" || entry === null) continue;
|
|
104
|
-
const row = entry;
|
|
105
|
-
if (row.type !== "message") continue;
|
|
106
|
-
const message = row.message;
|
|
107
|
-
if (typeof message !== "object" || message === null) continue;
|
|
108
|
-
const msg = message;
|
|
109
|
-
if (msg.role !== "toolResult") continue;
|
|
110
|
-
if (msg.toolName !== toolName) continue;
|
|
111
|
-
const field = readEngineLaborFallbackFieldFrom(msg.details);
|
|
112
|
-
if (field === void 0) continue;
|
|
113
|
-
recordEngineLaborFallback(latch, {
|
|
114
|
-
engine: field.engineLaborFallback.engine,
|
|
115
|
-
failure: field.engineLaborFallback.failure
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
export {
|
|
120
|
-
SEAT_FALLBACK_STATUS_SUFFIX,
|
|
121
|
-
activationEngineLaborFallbackLatch,
|
|
122
|
-
buildEngineLaborFallbackField,
|
|
123
|
-
clearActivationEngineLaborFallbackLatch,
|
|
124
|
-
createEngineLaborFallbackLatch,
|
|
125
|
-
installActivationEngineLaborFallbackLatch,
|
|
126
|
-
isSeatFallbackTaintedStatus,
|
|
127
|
-
readActivationEngineLaborFallbackField,
|
|
128
|
-
readEngineLaborFallbackField,
|
|
129
|
-
readEngineLaborFallbackFieldFrom,
|
|
130
|
-
recordEngineLaborFallback,
|
|
131
|
-
restoreEngineLaborFallbackFromSessionEntries,
|
|
132
|
-
seatFallbackBaseStatus,
|
|
133
|
-
seatFallbackStatusHasLawfulEvidence,
|
|
134
|
-
taintStatusForSeatFallback,
|
|
135
|
-
withEngineLaborFallbackField
|
|
136
|
-
};
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* #380 — sole shared seat-fallback declaration after engine detour failure.
|
|
3
|
-
* Detour rejoins the main road (ADR 0069); silence is the only crime.
|
|
4
|
-
* Construction of the typed receipt field lives in exactly one site (S1).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export type EngineLaborFallback = Readonly<{
|
|
8
|
-
engine: string;
|
|
9
|
-
failure: string;
|
|
10
|
-
laborBy: "seat";
|
|
11
|
-
}>;
|
|
12
|
-
|
|
13
|
-
/** Activation-scoped latch holder (one parent seat activation at a time). */
|
|
14
|
-
let activationLatch: EngineLaborFallbackLatch | undefined;
|
|
15
|
-
|
|
16
|
-
/** Sole construction site for typed receipt field `engineLaborFallback` (#380 S1). */
|
|
17
|
-
export function buildEngineLaborFallbackField(input: {
|
|
18
|
-
readonly engine: string;
|
|
19
|
-
readonly failure: string;
|
|
20
|
-
}) {
|
|
21
|
-
return Object.freeze({
|
|
22
|
-
engineLaborFallback: Object.freeze({
|
|
23
|
-
engine: input.engine,
|
|
24
|
-
failure: input.failure,
|
|
25
|
-
laborBy: "seat" as const,
|
|
26
|
-
}),
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Frozen field bag produced by the sole construction site. */
|
|
31
|
-
export type EngineLaborFallbackField = ReturnType<
|
|
32
|
-
typeof buildEngineLaborFallbackField
|
|
33
|
-
>;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Seat-fallback status taint suffix.
|
|
37
|
-
* When engineLaborFallback is declared, typed status discriminators
|
|
38
|
-
* (judgeStatus / status) must not remain clean values like converged/completed.
|
|
39
|
-
* Mechanical form: `${base}-by-fallback` — readable on the status line alone.
|
|
40
|
-
*/
|
|
41
|
-
export const SEAT_FALLBACK_STATUS_SUFFIX = "-by-fallback" as const;
|
|
42
|
-
|
|
43
|
-
export function isSeatFallbackTaintedStatus(status: string): boolean {
|
|
44
|
-
return status.endsWith(SEAT_FALLBACK_STATUS_SUFFIX);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Strip seat-fallback taint for semantic routing / acceptance matching. */
|
|
48
|
-
export function seatFallbackBaseStatus(status: string): string {
|
|
49
|
-
return isSeatFallbackTaintedStatus(status)
|
|
50
|
-
? status.slice(0, -SEAT_FALLBACK_STATUS_SUFFIX.length)
|
|
51
|
-
: status;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* ADR 0071: `-by-fallback` is lawful only with a valid `engineLaborFallback`
|
|
56
|
-
* declaration (latch-shaped triple). Clean statuses do not need the field.
|
|
57
|
-
*/
|
|
58
|
-
export function seatFallbackStatusHasLawfulEvidence(
|
|
59
|
-
status: string,
|
|
60
|
-
source: unknown,
|
|
61
|
-
): boolean {
|
|
62
|
-
if (!isSeatFallbackTaintedStatus(status)) return true;
|
|
63
|
-
return readEngineLaborFallbackFieldFrom(source) !== undefined;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Idempotent taint: clean → `${clean}-by-fallback`; already tainted stays. */
|
|
67
|
-
export function taintStatusForSeatFallback(status: string): string {
|
|
68
|
-
if (status.length === 0 || isSeatFallbackTaintedStatus(status)) return status;
|
|
69
|
-
return `${status}${SEAT_FALLBACK_STATUS_SUFFIX}`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Clean status literal or its seat-fallback tainted form. */
|
|
73
|
-
export type SeatFallbackTaintedStatus<S extends string = string> =
|
|
74
|
-
| S
|
|
75
|
-
| `${S}${typeof SEAT_FALLBACK_STATUS_SUFFIX}`;
|
|
76
|
-
|
|
77
|
-
type TaintDiscriminatorFields<T> = {
|
|
78
|
-
[K in keyof T]: K extends "status" | "judgeStatus"
|
|
79
|
-
? T[K] extends string
|
|
80
|
-
? SeatFallbackTaintedStatus<Extract<T[K], string>>
|
|
81
|
-
: T[K]
|
|
82
|
-
: T[K];
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/** Receipt shape after sole-built field attach + status taint (runtime truth). */
|
|
86
|
-
export type WithEngineLaborFallback<T extends object> = T extends unknown
|
|
87
|
-
? TaintDiscriminatorFields<T> & EngineLaborFallbackField
|
|
88
|
-
: never;
|
|
89
|
-
|
|
90
|
-
const STATUS_DISCRIMINATOR_KEYS = ["judgeStatus", "status"] as const;
|
|
91
|
-
|
|
92
|
-
/** Rewrite known status discriminators on a receipt when seat fallback is declared. */
|
|
93
|
-
function taintReceiptStatusDiscriminators<T extends object>(
|
|
94
|
-
receipt: T,
|
|
95
|
-
): TaintDiscriminatorFields<T> {
|
|
96
|
-
let next: Record<string, unknown> | undefined;
|
|
97
|
-
for (const key of STATUS_DISCRIMINATOR_KEYS) {
|
|
98
|
-
if (!Object.prototype.hasOwnProperty.call(receipt, key)) continue;
|
|
99
|
-
let value: unknown;
|
|
100
|
-
try {
|
|
101
|
-
value = (receipt as Record<string, unknown>)[key];
|
|
102
|
-
} catch {
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (typeof value !== "string" || value.length === 0) continue;
|
|
106
|
-
const tainted = taintStatusForSeatFallback(value);
|
|
107
|
-
if (tainted === value) continue;
|
|
108
|
-
if (next === undefined) {
|
|
109
|
-
next = { ...(receipt as object as Record<string, unknown>) };
|
|
110
|
-
}
|
|
111
|
-
next[key] = tainted;
|
|
112
|
-
}
|
|
113
|
-
return (next === undefined ? receipt : next) as TaintDiscriminatorFields<T>;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export type EngineLaborFallbackLatch = {
|
|
117
|
-
field: EngineLaborFallbackField | undefined;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
export function createEngineLaborFallbackLatch(): EngineLaborFallbackLatch {
|
|
121
|
-
return { field: undefined };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Record first detour failure for this latch (first wins; parallel legs share one field).
|
|
126
|
-
* Always returns the latched first-wins value so tool details and receipt projection match.
|
|
127
|
-
*/
|
|
128
|
-
export function recordEngineLaborFallback(
|
|
129
|
-
latch: EngineLaborFallbackLatch,
|
|
130
|
-
input: { readonly engine: string; readonly failure: string },
|
|
131
|
-
): EngineLaborFallbackField {
|
|
132
|
-
const field = buildEngineLaborFallbackField(input);
|
|
133
|
-
if (latch.field === undefined) latch.field = field;
|
|
134
|
-
return latch.field;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function readEngineLaborFallbackField(
|
|
138
|
-
latch: EngineLaborFallbackLatch | undefined,
|
|
139
|
-
): EngineLaborFallbackField | undefined {
|
|
140
|
-
return latch?.field;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Merge sole-built field into typed receipt details.
|
|
145
|
-
* Spread only — must not construct the field key again (S1).
|
|
146
|
-
* When the field is present, also taint typed status discriminators so a
|
|
147
|
-
* status-line-only reader cannot mistake seat labor for clean engine labor.
|
|
148
|
-
* Without a mechanical latch, strip any model-injected reserved key (no forged declaration).
|
|
149
|
-
* Return type widens when field is attached: discriminators may carry `-by-fallback`
|
|
150
|
-
* and the sole-built field is present (callers must not assume clean-only unions).
|
|
151
|
-
*/
|
|
152
|
-
export function withEngineLaborFallbackField<T extends object>(
|
|
153
|
-
receipt: T,
|
|
154
|
-
field: EngineLaborFallbackField,
|
|
155
|
-
): WithEngineLaborFallback<T>;
|
|
156
|
-
export function withEngineLaborFallbackField<T extends object>(
|
|
157
|
-
receipt: T,
|
|
158
|
-
field: undefined,
|
|
159
|
-
): T;
|
|
160
|
-
export function withEngineLaborFallbackField<T extends object>(
|
|
161
|
-
receipt: T,
|
|
162
|
-
field: EngineLaborFallbackField | undefined,
|
|
163
|
-
): T | WithEngineLaborFallback<T>;
|
|
164
|
-
export function withEngineLaborFallbackField<T extends object>(
|
|
165
|
-
receipt: T,
|
|
166
|
-
field: EngineLaborFallbackField | undefined,
|
|
167
|
-
): T | WithEngineLaborFallback<T> {
|
|
168
|
-
if (field !== undefined) {
|
|
169
|
-
const taintedReceipt = taintReceiptStatusDiscriminators(receipt);
|
|
170
|
-
return { ...taintedReceipt, ...field } as WithEngineLaborFallback<T>;
|
|
171
|
-
}
|
|
172
|
-
if (
|
|
173
|
-
!Object.prototype.hasOwnProperty.call(receipt, "engineLaborFallback")
|
|
174
|
-
) {
|
|
175
|
-
return receipt;
|
|
176
|
-
}
|
|
177
|
-
const { engineLaborFallback: _forged, ...rest } = receipt as T & {
|
|
178
|
-
engineLaborFallback?: unknown;
|
|
179
|
-
};
|
|
180
|
-
return rest as T;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** Install the activation-scoped latch (any role session_start with engine). */
|
|
184
|
-
export function installActivationEngineLaborFallbackLatch(
|
|
185
|
-
latch: EngineLaborFallbackLatch,
|
|
186
|
-
): void {
|
|
187
|
-
activationLatch = latch;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** Clear activation latch (session end / next activation). */
|
|
191
|
-
export function clearActivationEngineLaborFallbackLatch(): void {
|
|
192
|
-
activationLatch = undefined;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** Active activation latch, if any (legs inherit parent seat activation). */
|
|
196
|
-
export function activationEngineLaborFallbackLatch():
|
|
197
|
-
| EngineLaborFallbackLatch
|
|
198
|
-
| undefined {
|
|
199
|
-
return activationLatch;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** Read fallback field from the active activation latch. */
|
|
203
|
-
export function readActivationEngineLaborFallbackField():
|
|
204
|
-
| EngineLaborFallbackField
|
|
205
|
-
| undefined {
|
|
206
|
-
return readEngineLaborFallbackField(activationLatch);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Read a previously attached declaration from a typed receipt / details object.
|
|
211
|
-
* Rebuilds via the sole construction site — callers must spread, never re-key.
|
|
212
|
-
*/
|
|
213
|
-
export function readEngineLaborFallbackFieldFrom(
|
|
214
|
-
source: unknown,
|
|
215
|
-
): EngineLaborFallbackField | undefined {
|
|
216
|
-
if (typeof source !== "object" || source === null || Array.isArray(source)) {
|
|
217
|
-
return undefined;
|
|
218
|
-
}
|
|
219
|
-
let raw: unknown;
|
|
220
|
-
try {
|
|
221
|
-
raw = (source as Record<string, unknown>).engineLaborFallback;
|
|
222
|
-
} catch {
|
|
223
|
-
return undefined;
|
|
224
|
-
}
|
|
225
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return undefined;
|
|
226
|
-
const rec = raw as Record<string, unknown>;
|
|
227
|
-
if (
|
|
228
|
-
typeof rec.engine !== "string" ||
|
|
229
|
-
typeof rec.failure !== "string" ||
|
|
230
|
-
rec.laborBy !== "seat"
|
|
231
|
-
) {
|
|
232
|
-
return undefined;
|
|
233
|
-
}
|
|
234
|
-
return buildEngineLaborFallbackField({
|
|
235
|
-
engine: rec.engine,
|
|
236
|
-
failure: rec.failure,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Restore activation latch from durable session tool results (#380 resume).
|
|
242
|
-
* Scans existing same-session detour tool results only — no sidecar / new entry type.
|
|
243
|
-
* Replays through recordEngineLaborFallback so first-wins + sole producer stay intact.
|
|
244
|
-
*/
|
|
245
|
-
export function restoreEngineLaborFallbackFromSessionEntries(
|
|
246
|
-
latch: EngineLaborFallbackLatch,
|
|
247
|
-
entries: readonly unknown[],
|
|
248
|
-
toolName: string,
|
|
249
|
-
): void {
|
|
250
|
-
for (const entry of entries) {
|
|
251
|
-
if (typeof entry !== "object" || entry === null) continue;
|
|
252
|
-
const row = entry as { type?: unknown; message?: unknown };
|
|
253
|
-
if (row.type !== "message") continue;
|
|
254
|
-
const message = row.message;
|
|
255
|
-
if (typeof message !== "object" || message === null) continue;
|
|
256
|
-
const msg = message as {
|
|
257
|
-
role?: unknown;
|
|
258
|
-
toolName?: unknown;
|
|
259
|
-
details?: unknown;
|
|
260
|
-
};
|
|
261
|
-
if (msg.role !== "toolResult") continue;
|
|
262
|
-
if (msg.toolName !== toolName) continue;
|
|
263
|
-
const field = readEngineLaborFallbackFieldFrom(msg.details);
|
|
264
|
-
if (field === undefined) continue;
|
|
265
|
-
recordEngineLaborFallback(latch, {
|
|
266
|
-
engine: field.engineLaborFallback.engine,
|
|
267
|
-
failure: field.engineLaborFallback.failure,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|