@sema-agent/client-core 0.108.0 → 0.109.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +37 -24
  3. package/dist/adapt/arms.js +23 -8
  4. package/dist/adapt/textStream.d.ts +2 -0
  5. package/dist/adapt/textStream.js +37 -16
  6. package/dist/adapter/activeRunSelfHeal.js +1 -1
  7. package/dist/adapter/downstream/eventToSdkMessage.js +2 -1
  8. package/dist/agentSession/engineAgentRegistryRead.js +2 -0
  9. package/dist/bashExitReading.d.ts +12 -0
  10. package/dist/bashExitReading.js +44 -0
  11. package/dist/checkpointRowVerdict.d.ts +1 -1
  12. package/dist/checkpointRowVerdict.js +4 -2
  13. package/dist/compensations.js +1 -1
  14. package/dist/engineAgentAbsence.d.ts +2 -0
  15. package/dist/engineAgentAbsence.js +28 -0
  16. package/dist/engineErrorCodes.d.ts +4 -0
  17. package/dist/engineErrorCodes.js +4 -0
  18. package/dist/engineHealthFacts.d.ts +17 -0
  19. package/dist/engineHealthFacts.js +42 -3
  20. package/dist/engineNoticeCodes.d.ts +128 -0
  21. package/dist/engineNoticeCodes.js +630 -55
  22. package/dist/errorSupplementRoles.js +4 -1
  23. package/dist/fleetTaskDesc.js +3 -3
  24. package/dist/generated/engineFactTables.d.ts +1 -0
  25. package/dist/generated/engineFactTables.js +6 -0
  26. package/dist/generated/engineNoticeTables.js +3 -0
  27. package/dist/hitl/approvalCardReasons.js +22 -4
  28. package/dist/hitl/approvalRequestFrameReading.d.ts +14 -0
  29. package/dist/hitl/approvalRequestFrameReading.js +79 -0
  30. package/dist/hitl/approvalsFeed.js +1 -1
  31. package/dist/hitl/askParkRowRouting.js +5 -2
  32. package/dist/hitl/automaticAnswerVerdict.d.ts +5 -2
  33. package/dist/hitl/automaticAnswerVerdict.js +16 -2
  34. package/dist/hitl/decisionConflict.d.ts +2 -1
  35. package/dist/hitl/decisionConflict.js +4 -1
  36. package/dist/hitl/frameRouter.js +9 -1
  37. package/dist/hitl/hitlBridge.d.ts +4 -0
  38. package/dist/hitl/hitlBridge.js +9 -5
  39. package/dist/hitl/livePendingAsk.js +17 -16
  40. package/dist/hitl/localAllowRule.js +2 -1
  41. package/dist/hitl/noAllowCause.d.ts +1 -1
  42. package/dist/hitl/noAllowCause.js +4 -2
  43. package/dist/hitl/parkExpiryJudgements.js +26 -1
  44. package/dist/hitl/parkOwnership.d.ts +2 -0
  45. package/dist/hitl/parkOwnership.js +48 -8
  46. package/dist/hitl/parkResolver.js +7 -7
  47. package/dist/hitl/parkedUnresumable.d.ts +13 -0
  48. package/dist/hitl/parkedUnresumable.js +80 -0
  49. package/dist/hitl/permissionRuleScope.d.ts +4 -0
  50. package/dist/hitl/permissionRuleScope.js +31 -0
  51. package/dist/hitl/persistedRulesWire.d.ts +2 -0
  52. package/dist/hitl/persistedRulesWire.js +11 -10
  53. package/dist/hitl/sessionAllowRoute.js +5 -4
  54. package/dist/hitl/standingRows.d.ts +1 -5
  55. package/dist/hitl/standingRows.js +15 -14
  56. package/dist/hitl/toolApprovalWire.d.ts +8 -2
  57. package/dist/hitl/toolApprovalWire.js +35 -14
  58. package/dist/hooksWireCaps.js +4 -3
  59. package/dist/hostSettingsSource.js +2 -0
  60. package/dist/i18n/messages.en.d.ts +168 -0
  61. package/dist/i18n/messages.en.js +169 -1
  62. package/dist/i18n/messages.zh.js +169 -1
  63. package/dist/index.d.ts +29 -7
  64. package/dist/index.js +16 -4
  65. package/dist/localEngineJudge.d.ts +75 -0
  66. package/dist/localEngineJudge.js +242 -0
  67. package/dist/localEngineOccupancy.d.ts +88 -0
  68. package/dist/localEngineOccupancy.js +269 -0
  69. package/dist/localEngineSeatReading.d.ts +29 -0
  70. package/dist/localEngineSeatReading.js +294 -0
  71. package/dist/localEngineSpawn.d.ts +113 -0
  72. package/dist/localEngineSpawn.js +486 -0
  73. package/dist/localEngineStep.d.ts +286 -0
  74. package/dist/localEngineStep.js +1086 -0
  75. package/dist/localEngineStopLadder.d.ts +29 -0
  76. package/dist/localEngineStopLadder.js +139 -0
  77. package/dist/localEngineSwapCard.d.ts +43 -0
  78. package/dist/localEngineSwapCard.js +205 -0
  79. package/dist/localEngineTiming.d.ts +8 -0
  80. package/dist/localEngineTiming.js +8 -0
  81. package/dist/mcpReconnect.js +12 -5
  82. package/dist/mcpWireCaps.js +2 -2
  83. package/dist/memoryEntriesWire.d.ts +1 -1
  84. package/dist/memoryEntriesWire.js +5 -0
  85. package/dist/noticePresentation.d.ts +2 -0
  86. package/dist/noticePresentation.js +79 -1
  87. package/dist/ownKey.d.ts +10 -0
  88. package/dist/ownKey.js +15 -1
  89. package/dist/ruleReadings.js +1 -1
  90. package/dist/seam.d.ts +13 -2
  91. package/dist/seam.js +8 -1
  92. package/dist/seatContract.d.ts +42 -4
  93. package/dist/seatContract.js +180 -3
  94. package/dist/sessionBackground.js +2 -0
  95. package/dist/subagentContentStore.d.ts +12 -0
  96. package/dist/subagentContentStore.js +72 -11
  97. package/dist/toolResult.js +18 -5
  98. package/dist/wireFailureShape.d.ts +20 -0
  99. package/dist/wireFailureShape.js +37 -6
  100. package/dist/wireRefusalCopy.d.ts +21 -1
  101. package/dist/wireRefusalCopy.js +91 -2
  102. package/docs/INTEGRATION-CLIENTS.md +1152 -10
  103. package/package.json +3 -3
@@ -0,0 +1,29 @@
1
+ export declare const LOCAL_ENGINE_STOP_LADDER: Readonly<{
2
+ g: 1000;
3
+ P: 5000;
4
+ H: 20000;
5
+ }>;
6
+ export type StopLadderSignal = 'term' | 'term-2' | 'kill';
7
+ export interface StopLadderState {
8
+ readonly mode: 'idle' | 'forced';
9
+ readonly target: {
10
+ readonly pid: number;
11
+ readonly startedAt?: number;
12
+ };
13
+ readonly t0: number;
14
+ readonly sent: readonly StopLadderSignal[];
15
+ readonly processedAt?: number;
16
+ readonly deadlineAt?: number;
17
+ readonly killedAt?: number;
18
+ }
19
+ export interface StopLadderObservation {
20
+ readonly nowMs: number;
21
+ readonly alive: 'alive' | 'gone' | 'unknown';
22
+ readonly health: object | null;
23
+ }
24
+ export interface StopLadderStepResult {
25
+ readonly state: StopLadderState;
26
+ readonly action: StopLadderSignal | 'wait' | 'done' | 'gave-up';
27
+ readonly waitMs?: number;
28
+ }
29
+ export declare function stopLadderStep(s: StopLadderState, obs: StopLadderObservation): StopLadderStepResult;
@@ -0,0 +1,139 @@
1
+ import { readEngineHealthFacts } from './engineHealthFacts.js';
2
+ import { readOwnDataValue } from './ownKey.js';
3
+ export const LOCAL_ENGINE_STOP_LADDER = Object.freeze({ g: 1000, P: 5000, H: 20000 });
4
+ const SIGTERM_ACTION_ID = 'signal:SIGTERM';
5
+ function own(v, key) {
6
+ if (typeof v !== 'object' || v === null)
7
+ return undefined;
8
+ try {
9
+ return readOwnDataValue(v, key);
10
+ }
11
+ catch {
12
+ return undefined;
13
+ }
14
+ }
15
+ function isTime(v) {
16
+ return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;
17
+ }
18
+ function isPid(v) {
19
+ return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
20
+ }
21
+ const SIGNALS = Object.freeze(['term', 'term-2', 'kill']);
22
+ function stateOf(s) {
23
+ const mode = own(s, 'mode');
24
+ if (mode !== 'idle' && mode !== 'forced')
25
+ return undefined;
26
+ const target = own(s, 'target');
27
+ const pid = own(target, 'pid');
28
+ if (!isPid(pid))
29
+ return undefined;
30
+ const startedAt = own(target, 'startedAt');
31
+ const t0 = own(s, 't0');
32
+ if (!isTime(t0))
33
+ return undefined;
34
+ const sentRaw = own(s, 'sent');
35
+ let sent = [];
36
+ try {
37
+ if (!Array.isArray(sentRaw))
38
+ return undefined;
39
+ for (let i = 0; i < sentRaw.length; i++) {
40
+ const x = own(sentRaw, String(i));
41
+ if (!SIGNALS.includes(x))
42
+ return undefined;
43
+ if (!sent.includes(x))
44
+ sent.push(x);
45
+ }
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ sent = SIGNALS.filter((x) => sent.includes(x));
51
+ const processedAt = own(s, 'processedAt');
52
+ const deadlineAt = own(s, 'deadlineAt');
53
+ const killedAt = own(s, 'killedAt');
54
+ if (processedAt !== undefined && !isTime(processedAt))
55
+ return undefined;
56
+ if (deadlineAt !== undefined && !isTime(deadlineAt))
57
+ return undefined;
58
+ if (killedAt !== undefined && !isTime(killedAt))
59
+ return undefined;
60
+ return {
61
+ mode,
62
+ target: isTime(startedAt) && startedAt > 0 ? { pid, startedAt } : { pid },
63
+ t0,
64
+ sent,
65
+ ...(processedAt !== undefined ? { processedAt } : {}),
66
+ ...(deadlineAt !== undefined ? { deadlineAt } : {}),
67
+ ...(killedAt !== undefined ? { killedAt } : {}),
68
+ };
69
+ }
70
+ function frozen(s) {
71
+ return Object.freeze({ ...s, target: Object.freeze({ ...s.target }), sent: Object.freeze([...s.sent]) });
72
+ }
73
+ function result(s, action, waitMs) {
74
+ return Object.freeze({ state: frozen(s), action, ...(waitMs !== undefined ? { waitMs: Math.max(0, waitMs) } : {}) });
75
+ }
76
+ export function stopLadderStep(s, obs) {
77
+ const st = stateOf(s);
78
+ if (st === undefined) {
79
+ return Object.freeze({ state: s, action: 'gave-up' });
80
+ }
81
+ const nowMs = own(obs, 'nowMs');
82
+ const alive = own(obs, 'alive');
83
+ if (alive === 'gone')
84
+ return result(st, 'done');
85
+ if (!isTime(nowMs))
86
+ return result(st, 'wait');
87
+ const { g, P, H } = LOCAL_ENGINE_STOP_LADDER;
88
+ const health = own(obs, 'health');
89
+ let facts;
90
+ try {
91
+ facts = typeof health === 'object' && health !== null ? readEngineHealthFacts(health) : undefined;
92
+ }
93
+ catch {
94
+ facts = undefined;
95
+ }
96
+ const draining = facts?.draining;
97
+ let next = st;
98
+ if (draining !== undefined) {
99
+ if (st.mode === 'idle') {
100
+ next = { ...next, deadlineAt: Math.max(st.deadlineAt ?? draining.deadlineAt, draining.deadlineAt) };
101
+ }
102
+ else if (st.processedAt === undefined && st.sent.includes('term') && draining.actionId === SIGTERM_ACTION_ID && draining.since >= st.t0) {
103
+ next = { ...next, processedAt: nowMs };
104
+ }
105
+ }
106
+ const isAlive = alive === 'alive';
107
+ if (next.sent.length === 0) {
108
+ if (isAlive)
109
+ return result({ ...next, sent: ['term'] }, 'term');
110
+ return result(next, nowMs >= next.t0 + H ? 'gave-up' : 'wait', next.t0 + H - nowMs);
111
+ }
112
+ const killAt = next.mode === 'idle'
113
+ ? Math.max(next.t0, next.deadlineAt ?? next.t0) + H
114
+ : next.processedAt !== undefined && next.processedAt <= next.t0 + P
115
+ ? next.processedAt + g + H
116
+ : next.t0 + H;
117
+ if (next.killedAt !== undefined || next.sent.includes('kill')) {
118
+ const giveUpAt = (next.killedAt ?? killAt) + H;
119
+ if (nowMs >= giveUpAt)
120
+ return result(next, 'gave-up');
121
+ return result(next, 'wait', giveUpAt - nowMs);
122
+ }
123
+ if (!isAlive) {
124
+ if (nowMs >= killAt)
125
+ return result(next, 'gave-up');
126
+ return result(next, 'wait', killAt - nowMs);
127
+ }
128
+ if (nowMs >= killAt)
129
+ return result({ ...next, sent: [...next.sent, 'kill'], killedAt: nowMs }, 'kill');
130
+ if (next.mode === 'forced' &&
131
+ next.processedAt !== undefined &&
132
+ nowMs >= next.processedAt + g &&
133
+ draining !== undefined &&
134
+ !next.sent.includes('term-2')) {
135
+ return result({ ...next, sent: [...next.sent.filter((x) => x !== 'kill'), 'term-2'] }, 'term-2');
136
+ }
137
+ const term2At = next.mode === 'forced' && next.processedAt !== undefined && !next.sent.includes('term-2') ? next.processedAt + g : Infinity;
138
+ return result(next, 'wait', Math.min(killAt, term2At) - nowMs);
139
+ }
@@ -0,0 +1,43 @@
1
+ import type { LocalEngineAnchoredProcess, LocalEngineRef } from './localEngineJudge.js';
2
+ import type { LocalEngineOccupancy } from './localEngineOccupancy.js';
3
+ import type { UiLanguage } from './env/uiLanguage.js';
4
+ export declare const LOCAL_ENGINE_SWAP_CAUSES: readonly ["version", "config", "credential", "model-default", "user", "unresponsive"];
5
+ export type LocalEngineSwapCause = (typeof LOCAL_ENGINE_SWAP_CAUSES)[number];
6
+ export interface LocalEngineSwapPolicy {
7
+ readonly credentialAuto?: boolean;
8
+ }
9
+ export declare function localEngineSwapAutoable(cause: LocalEngineSwapCause, serving: boolean, policy?: LocalEngineSwapPolicy): boolean;
10
+ export type EngineSwapCardTarget = LocalEngineRef | LocalEngineAnchoredProcess;
11
+ export type EngineSwapCardUnknown = 'others' | 'inflight' | 'bg' | 'self';
12
+ export interface EngineSwapCardInput {
13
+ readonly cause: LocalEngineSwapCause;
14
+ readonly target: EngineSwapCardTarget;
15
+ readonly running?: string;
16
+ readonly own?: string;
17
+ readonly occupancy: LocalEngineOccupancy;
18
+ readonly bgIds: readonly string[] | null;
19
+ }
20
+ export interface EngineSwapCardOthers {
21
+ readonly total: number;
22
+ readonly midTurn: number;
23
+ }
24
+ export interface EngineSwapCard {
25
+ readonly cause: LocalEngineSwapCause;
26
+ readonly target: EngineSwapCardTarget;
27
+ readonly running?: string;
28
+ readonly own?: string;
29
+ readonly others: EngineSwapCardOthers | null;
30
+ readonly inflight: number | null;
31
+ readonly bgLive: number | null;
32
+ readonly unknown: readonly EngineSwapCardUnknown[];
33
+ readonly forcedWithinMs: number;
34
+ readonly fingerprint: string;
35
+ }
36
+ export declare function engineSwapCardOf(input: EngineSwapCardInput): EngineSwapCard | undefined;
37
+ export interface EngineSwapCardText {
38
+ readonly title: string;
39
+ readonly lines: readonly string[];
40
+ readonly force: string;
41
+ readonly wait: string;
42
+ }
43
+ export declare function engineSwapCardText(card: EngineSwapCard, lang?: UiLanguage): EngineSwapCardText | undefined;
@@ -0,0 +1,205 @@
1
+ import { engineIdentityOf } from './engineIdentity.js';
2
+ import { readOwnDataValue } from './ownKey.js';
3
+ import { displayUntrusted } from './displayUntrusted.js';
4
+ import { LOCAL_ENGINE_STOP_LADDER } from './localEngineStopLadder.js';
5
+ import { msg, renderMessage } from './i18n/translate.js';
6
+ export const LOCAL_ENGINE_SWAP_CAUSES = Object.freeze(['version', 'config', 'credential', 'model-default', 'user', 'unresponsive']);
7
+ function isCause(v) {
8
+ return typeof v === 'string' && LOCAL_ENGINE_SWAP_CAUSES.includes(v);
9
+ }
10
+ function isRecord(v) {
11
+ if (typeof v !== 'object' || v === null)
12
+ return false;
13
+ try {
14
+ return !Array.isArray(v);
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ function isArray(v) {
21
+ try {
22
+ return Array.isArray(v);
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ function own(v, key) {
29
+ if (!isRecord(v) && !isArray(v))
30
+ return undefined;
31
+ try {
32
+ return readOwnDataValue(v, key);
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ }
38
+ function isCount(v) {
39
+ return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;
40
+ }
41
+ function isPid(v) {
42
+ return typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
43
+ }
44
+ export function localEngineSwapAutoable(cause, serving, policy) {
45
+ if (!isCause(cause))
46
+ return false;
47
+ if (serving === false)
48
+ return true;
49
+ if (cause === 'version' || cause === 'user')
50
+ return true;
51
+ return cause === 'credential' && own(policy, 'credentialAuto') === true;
52
+ }
53
+ const FORCED_WITHIN_MS = LOCAL_ENGINE_STOP_LADDER.P + LOCAL_ENGINE_STOP_LADDER.g + LOCAL_ENGINE_STOP_LADDER.H;
54
+ function targetOf(t) {
55
+ const pid = own(t, 'pid');
56
+ if (!isPid(pid))
57
+ return undefined;
58
+ const identity = own(t, 'identity');
59
+ if (isRecord(identity)) {
60
+ const port = own(t, 'port');
61
+ if (typeof port !== 'number' || !Number.isInteger(port) || port < 1 || port > 65535)
62
+ return undefined;
63
+ const id = Object.freeze({ ...engineIdentityOf(identity) });
64
+ const version = own(t, 'version');
65
+ const target = Object.freeze({ pid, port, identity: id, ...(typeof version === 'string' && version.length > 0 ? { version } : {}) });
66
+ return { target, key: id };
67
+ }
68
+ const startedAt = own(t, 'startedAt');
69
+ const target = Object.freeze({ pid, ...(typeof startedAt === 'number' && Number.isFinite(startedAt) && startedAt > 0 ? { startedAt } : {}) });
70
+ return { target, key: engineIdentityOf(target) };
71
+ }
72
+ export function engineSwapCardOf(input) {
73
+ try {
74
+ const cause = own(input, 'cause');
75
+ if (!isCause(cause))
76
+ return undefined;
77
+ const t = targetOf(own(input, 'target'));
78
+ if (t === undefined)
79
+ return undefined;
80
+ const occ = own(input, 'occupancy');
81
+ const unknown = [];
82
+ const o = own(occ, 'others');
83
+ const total = own(o, 'total');
84
+ const midTurn = own(o, 'midTurn');
85
+ const others = own(o, 'known') === true && isCount(total) && isCount(midTurn) ? Object.freeze({ total, midTurn }) : null;
86
+ if (others === null)
87
+ unknown.push('others');
88
+ const inflightRaw = own(occ, 'inflight');
89
+ const inflight = isCount(inflightRaw) ? inflightRaw : null;
90
+ if (inflight === null)
91
+ unknown.push('inflight');
92
+ const bgRaw = own(occ, 'bgLive');
93
+ const idsRaw = own(input, 'bgIds');
94
+ let bgIds = null;
95
+ if (Array.isArray(idsRaw)) {
96
+ const list = [];
97
+ let readable = true;
98
+ for (let i = 0; i < idsRaw.length && readable; i++) {
99
+ const id = own(idsRaw, String(i));
100
+ if (typeof id === 'string')
101
+ list.push(id);
102
+ else
103
+ readable = false;
104
+ }
105
+ bgIds = readable ? list : null;
106
+ }
107
+ const bgLive = isCount(bgRaw) && bgIds !== null && bgIds.length === bgRaw ? bgRaw : null;
108
+ if (bgLive === null) {
109
+ unknown.push('bg');
110
+ bgIds = null;
111
+ }
112
+ const self = own(occ, 'self');
113
+ if (self !== 'idle' && self !== 'busy')
114
+ unknown.push('self');
115
+ const runningRaw = own(input, 'running');
116
+ const ownRaw = own(input, 'own');
117
+ const running = typeof runningRaw === 'string' && runningRaw.length > 0 ? runningRaw : undefined;
118
+ const mine = typeof ownRaw === 'string' && ownRaw.length > 0 ? ownRaw : undefined;
119
+ const k = t.key;
120
+ const fingerprint = JSON.stringify([
121
+ 'local-engine-swap-card/1',
122
+ cause,
123
+ [t.target.pid, k.pid ?? null, k.instanceId ?? null, k.startedAt ?? null],
124
+ running ?? null,
125
+ mine ?? null,
126
+ others === null ? null : [others.total, others.midTurn],
127
+ inflight,
128
+ bgLive,
129
+ bgIds === null ? null : [...bgIds].sort(),
130
+ unknown,
131
+ self === 'idle' || self === 'busy' ? self : null,
132
+ ]);
133
+ return Object.freeze({
134
+ cause,
135
+ target: t.target,
136
+ ...(running !== undefined ? { running } : {}),
137
+ ...(mine !== undefined ? { own: mine } : {}),
138
+ others,
139
+ inflight,
140
+ bgLive,
141
+ unknown: Object.freeze(unknown),
142
+ forcedWithinMs: FORCED_WITHIN_MS,
143
+ fingerprint,
144
+ });
145
+ }
146
+ catch {
147
+ return undefined;
148
+ }
149
+ }
150
+ const TITLE_KEYS = Object.freeze({
151
+ version: 'localEngine.card.title.version',
152
+ config: 'localEngine.card.title.config',
153
+ credential: 'localEngine.card.title.credential',
154
+ 'model-default': 'localEngine.card.title.modelDefault',
155
+ user: 'localEngine.card.title.user',
156
+ unresponsive: 'localEngine.card.title.unresponsive',
157
+ });
158
+ const VERSION_DISPLAY_MAX = 64;
159
+ export function engineSwapCardText(card, lang) {
160
+ try {
161
+ const cause = own(card, 'cause');
162
+ const forcedWithinMs = own(card, 'forcedWithinMs');
163
+ if (!isCause(cause) || !isCount(forcedWithinMs))
164
+ return undefined;
165
+ const say = (key, params) => renderMessage(msg(key, params), lang);
166
+ const lines = [];
167
+ const running = own(card, 'running');
168
+ const mine = own(card, 'own');
169
+ if (typeof running === 'string' && running.length > 0 && typeof mine === 'string' && mine.length > 0) {
170
+ lines.push(say('localEngine.card.versions', { running: displayUntrusted(running, { max: VERSION_DISPLAY_MAX }), own: displayUntrusted(mine, { max: VERSION_DISPLAY_MAX }) }));
171
+ }
172
+ const others = own(card, 'others');
173
+ const total = own(others, 'total');
174
+ const midTurn = own(others, 'midTurn');
175
+ if (isCount(total) && isCount(midTurn))
176
+ lines.push(say(total === 1 ? 'localEngine.card.others.one' : 'localEngine.card.others.other', { total, midTurn }));
177
+ else
178
+ lines.push(say('localEngine.card.others.unknown'));
179
+ const inflight = own(card, 'inflight');
180
+ if (isCount(inflight))
181
+ lines.push(say(inflight === 1 ? 'localEngine.card.inflight.one' : 'localEngine.card.inflight.other', { count: inflight }));
182
+ else
183
+ lines.push(say('localEngine.card.inflight.unknown'));
184
+ const bgLive = own(card, 'bgLive');
185
+ if (isCount(bgLive))
186
+ lines.push(say(bgLive === 1 ? 'localEngine.card.background.one' : 'localEngine.card.background.other', { count: bgLive }));
187
+ else
188
+ lines.push(say('localEngine.card.background.unknown'));
189
+ if (isCount(inflight) && inflight > 0 && isCount(bgLive) && bgLive > 0)
190
+ lines.push(say('localEngine.card.overlap'));
191
+ const unknown = own(card, 'unknown');
192
+ if (Array.isArray(unknown) && unknown.includes('self'))
193
+ lines.push(say('localEngine.card.selfUnknown'));
194
+ lines.push(say('localEngine.card.parked'));
195
+ return Object.freeze({
196
+ title: say(TITLE_KEYS[cause]),
197
+ lines: Object.freeze(lines),
198
+ force: say('localEngine.card.force', { seconds: Math.ceil(forcedWithinMs / 1000) }),
199
+ wait: say('localEngine.card.wait'),
200
+ });
201
+ }
202
+ catch {
203
+ return undefined;
204
+ }
205
+ }
@@ -0,0 +1,8 @@
1
+ export declare const LOCAL_ENGINE_TIMING: Readonly<{
2
+ unansweredWaitMs: 60000;
3
+ prepareTimeoutMs: 10000;
4
+ stopProbeTimeoutMs: 4000;
5
+ crashWindowMs: 300000;
6
+ crashMaxDeaths: 3;
7
+ cooldownMs: readonly [60000, 120000, 240000, 480000, 600000, 600000];
8
+ }>;
@@ -0,0 +1,8 @@
1
+ export const LOCAL_ENGINE_TIMING = Object.freeze({
2
+ unansweredWaitMs: 60000,
3
+ prepareTimeoutMs: 10000,
4
+ stopProbeTimeoutMs: 4000,
5
+ crashWindowMs: 300000,
6
+ crashMaxDeaths: 3,
7
+ cooldownMs: Object.freeze([60000, 120000, 240000, 480000, 600000, 600000]),
8
+ });
@@ -1,6 +1,7 @@
1
1
  import { capForDisplay } from './fleetTaskDesc.js';
2
2
  import { ownDataField } from './ownKey.js';
3
3
  import { isSessionIdPathSegment } from './sessionIdSegment.js';
4
+ import { inSlotReadOf, inValueOf } from './wireFailureShape.js';
4
5
  import { readMcpAuthorization } from './mcpLiveness.js';
5
6
  export const MCP_RECONNECT_OUTCOMES = Object.freeze(['accepted', 'refused', 'unsupported']);
6
7
  export const MCP_RECONNECT_TRANSACTION_NOTICE = 'Reconnecting closes the current connection before dialing again. On a healthy server this is a transaction, ' +
@@ -82,8 +83,11 @@ export function projectMcpReconnectResult(body) {
82
83
  added,
83
84
  removed,
84
85
  };
85
- if ('toolNames' in body && body.toolNames !== undefined) {
86
- const toolNames = stringList(body.toolNames);
86
+ const names = inValueOf(body, 'toolNames');
87
+ if (names.state === 'unproven')
88
+ return undefined;
89
+ if (names.state === 'present' && names.value !== undefined) {
90
+ const toolNames = stringList(names.value);
87
91
  if (toolNames === undefined)
88
92
  return undefined;
89
93
  view.toolNames = toolNames;
@@ -93,8 +97,11 @@ export function projectMcpReconnectResult(body) {
93
97
  const status = projectStatus(body.status);
94
98
  if (status !== undefined)
95
99
  view.status = status;
96
- if ('listingIncomplete' in body && body.listingIncomplete !== undefined) {
97
- const li = projectListingIncomplete(body.listingIncomplete);
100
+ const incomplete = inValueOf(body, 'listingIncomplete');
101
+ if (incomplete.state === 'unproven')
102
+ return undefined;
103
+ if (incomplete.state === 'present' && incomplete.value !== undefined) {
104
+ const li = projectListingIncomplete(incomplete.value);
98
105
  if (li === undefined)
99
106
  return undefined;
100
107
  view.listingIncomplete = li;
@@ -116,7 +123,7 @@ function unsettledVerdict(carrier) {
116
123
  }
117
124
  function isUnsettledBody(raw) {
118
125
  try {
119
- return isRecord(raw) && !('outcome' in raw) && raw.errorCode === UNSETTLED_CODE;
126
+ return isRecord(raw) && inSlotReadOf(raw, 'outcome').state === 'absent' && raw.errorCode === UNSETTLED_CODE;
120
127
  }
121
128
  catch {
122
129
  return false;
@@ -329,7 +329,7 @@ function dropNotice(name, reason, problem, opts, path, transportKind) {
329
329
  : reason === 'elicitation_invalid'
330
330
  ? msg('config.mcp.elicitationInvalid', { name: quoted, where })
331
331
  : reason === 'allow_tools_invalid'
332
- ? msg('config.mcp.allowToolsInvalid', { name: quoted, where, problem: capForDisplay(problem ?? '', DROP_PROBLEM_SHOWN) })
332
+ ? msg('config.mcp.allowToolsInvalid', { name: quoted, where, problem: problem ?? '' })
333
333
  : reason === 'identity_headers_both_set'
334
334
  ? msg('config.mcp.identityHeadersBothSet', { name: quoted, where })
335
335
  : reason === 'transport_invalid'
@@ -448,6 +448,6 @@ export function mcpAssertionHeaderNotSentNotice(specs) {
448
448
  const parts = distinct.slice(0, ASSERTION_NOTICE_NAMES_SHOWN).map((x) => `"${x}"`);
449
449
  if (distinct.length > ASSERTION_NOTICE_NAMES_SHOWN)
450
450
  parts.push(`+${distinct.length - ASSERTION_NOTICE_NAMES_SHOWN} more`);
451
- return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.144.0 accept this setting but do not send the header, ` +
451
+ return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.147.0 accept this setting but do not send the header, ` +
452
452
  'and this client cannot tell whether the engine it uses sends it; a connector that requires the header will refuse requests from these servers');
453
453
  }
@@ -61,7 +61,7 @@ export interface MemoryEraseConflictRow {
61
61
  id: string;
62
62
  reason: string;
63
63
  }
64
- declare const MEMORY_ERASE_CARRIER_CLASSES: readonly ["projection", "shadow", "indexLine", "quarantineCopy", "planArchive", "planWorkbook", "evidenceBinding", "backendDerived"];
64
+ declare const MEMORY_ERASE_CARRIER_CLASSES: readonly ["projection", "shadow", "indexLine", "quarantineCopy", "clearanceCustody", "planArchive", "planWorkbook", "evidenceBinding", "backendDerived"];
65
65
  export type MemoryEraseCarrierClass = (typeof MEMORY_ERASE_CARRIER_CLASSES)[number];
66
66
  export type MemoryEraseCarrierReading = {
67
67
  removed: number;
@@ -174,6 +174,7 @@ const MEMORY_ERASE_CARRIER_CLASSES = Object.freeze([
174
174
  'shadow',
175
175
  'indexLine',
176
176
  'quarantineCopy',
177
+ 'clearanceCustody',
177
178
  'planArchive',
178
179
  'planWorkbook',
179
180
  'evidenceBinding',
@@ -237,6 +238,10 @@ function eraseResidualsOf(o, lane) {
237
238
  return null;
238
239
  const carriers = {};
239
240
  for (const cls of MEMORY_ERASE_CARRIER_CLASSES) {
241
+ if (!Object.hasOwn(rawCarriers, cls)) {
242
+ carriers[cls] = { unverified: true };
243
+ continue;
244
+ }
240
245
  const answer = carrierAnswerOf(readThrownSlot(rawCarriers, cls, 'data'));
241
246
  if (answer === null)
242
247
  return null;
@@ -6,7 +6,9 @@ export interface CutForDisplayResult {
6
6
  readonly shown: string;
7
7
  readonly truncated: boolean;
8
8
  }
9
+ export declare function pairSafeCut(text: string, cut: number): number;
9
10
  export declare function cutForDisplay(text: string, budget: number, opts?: CutForDisplayOptions): CutForDisplayResult;
11
+ export declare function elideMiddleForDisplay(text: string, budget: number): string;
10
12
  export type NoticePresentationAudience = 'user' | 'operator' | 'unknown';
11
13
  export type NoticeOutlet = 'present' | 'absent' | 'unknown';
12
14
  export type NoticeOccurrence = {
@@ -69,6 +69,14 @@ function pickCut(src, limit, floor, boundary) {
69
69
  return clause;
70
70
  return word >= floor ? word : -1;
71
71
  }
72
+ export function pairSafeCut(text, cut) {
73
+ if (cut <= 0 || cut >= text.length || text.charAt(cut) !== '\\' || text.charAt(cut - 1) !== '\\')
74
+ return cut;
75
+ let start = cut - 1;
76
+ while (start > 0 && text.charAt(start - 1) === '\\')
77
+ start--;
78
+ return (cut - start) % 2 === 1 ? cut - 1 : cut;
79
+ }
72
80
  export function cutForDisplay(text, budget, opts) {
73
81
  const src = typeof text === 'string' ? text : (guardedRead(() => String(text ?? '')) ?? '');
74
82
  if (typeof budget !== 'number' || !Number.isFinite(budget))
@@ -83,9 +91,79 @@ export function cutForDisplay(text, budget, opts) {
83
91
  const head = capDisplay(src, room, 'escape');
84
92
  const floor = Math.ceil(head.length / CUT_KEEP_DIVISOR);
85
93
  const at = pickCut(src, head.length, floor, boundary);
86
- const kept = (at === -1 ? head : src.slice(0, at)).trimEnd();
94
+ const kept = src.slice(0, pairSafeCut(src, at === -1 ? head.length : at)).trimEnd();
87
95
  return { shown: `${kept}${mark}`, truncated: true };
88
96
  }
97
+ const ELISION_MARK = '…';
98
+ const ELISION_MIN_ROOM = 8;
99
+ const ELISION_SOFT_BACKOFF = 24;
100
+ const CLUSTER_EXTENDER = /^[\p{M}‍︀-️\u{1F3FB}-\u{1F3FF}\u{E0020}-\u{E007F}]/u;
101
+ const REGIONAL_INDICATOR = /^[\u{1F1E6}-\u{1F1FF}]$/u;
102
+ const RTL_LETTER = /^[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Samaritan}\p{Script=Mandaic}]$/u;
103
+ function codePointBefore(text, i) {
104
+ return text.slice(Math.max(0, i - 2), i).match(/[\s\S]$/u)?.[0] ?? '';
105
+ }
106
+ function codePointAfter(text, i) {
107
+ const cp = i < text.length ? text.codePointAt(i) : undefined;
108
+ return cp === undefined ? '' : String.fromCodePoint(cp);
109
+ }
110
+ function hardSafeBoundary(text, i) {
111
+ return i <= 0 || i >= text.length || (capDisplay(text, i, 'escape').length === i && pairSafeCut(text, i) === i);
112
+ }
113
+ function calmBoundary(text, i) {
114
+ const before = codePointBefore(text, i);
115
+ const after = codePointAfter(text, i);
116
+ if (before === '' || after === '')
117
+ return true;
118
+ if (before === '‍' || CLUSTER_EXTENDER.test(after))
119
+ return false;
120
+ if (RTL_LETTER.test(before) || RTL_LETTER.test(after))
121
+ return false;
122
+ if (REGIONAL_INDICATOR.test(before) && REGIONAL_INDICATOR.test(after)) {
123
+ let run = 0;
124
+ for (let j = i; j > 0;) {
125
+ const cp = codePointBefore(text, j);
126
+ if (!REGIONAL_INDICATOR.test(cp))
127
+ break;
128
+ run++;
129
+ j -= cp.length;
130
+ }
131
+ return run % 2 === 0;
132
+ }
133
+ return true;
134
+ }
135
+ function settleOnCalm(text, at, step) {
136
+ for (let k = 0; k <= ELISION_SOFT_BACKOFF; k++) {
137
+ const i = at + step * k;
138
+ if (i < 0 || i > text.length)
139
+ break;
140
+ if (hardSafeBoundary(text, i) && calmBoundary(text, i))
141
+ return i;
142
+ }
143
+ return at;
144
+ }
145
+ export function elideMiddleForDisplay(text, budget) {
146
+ const src = typeof text === 'string' ? text : (guardedRead(() => String(text ?? '')) ?? '');
147
+ if (typeof budget !== 'number' || !Number.isFinite(budget))
148
+ return src;
149
+ const limit = Math.max(0, Math.floor(budget));
150
+ if (src.length <= limit)
151
+ return src;
152
+ const room = limit - ELISION_MARK.length;
153
+ if (room < ELISION_MIN_ROOM)
154
+ return cutForDisplay(src, limit).shown;
155
+ const headRoom = Math.ceil(room / 2);
156
+ const tailRoom = room - headRoom;
157
+ let head = headRoom;
158
+ while (head > 0 && !hardSafeBoundary(src, head))
159
+ head--;
160
+ let tail = src.length - tailRoom;
161
+ while (tail < src.length && !hardSafeBoundary(src, tail))
162
+ tail++;
163
+ head = settleOnCalm(src, head, -1);
164
+ tail = settleOnCalm(src, tail, 1);
165
+ return `${src.slice(0, head).trimEnd()}${ELISION_MARK}${src.slice(tail)}`;
166
+ }
89
167
  export const NOTICE_SEAT_CLASS = Object.freeze({
90
168
  user: Object.freeze({ present: 'persistent+hint', unknown: 'persistent+hint', absent: 'persistent' }),
91
169
  operator: Object.freeze({ present: 'transient', unknown: 'transient', absent: 'diagnostic' }),
package/dist/ownKey.d.ts CHANGED
@@ -32,8 +32,18 @@ export interface HumanInputAttachmentView {
32
32
  kind?: string;
33
33
  outcome: string;
34
34
  label?: string;
35
+ declinedBy?: HumanInputAttachmentDeclinedByView;
36
+ }
37
+ export interface HumanInputAttachmentDeclinedByView {
38
+ kind: 'extension';
39
+ name: string;
35
40
  }
36
41
  export declare function humanInputAttachmentsOf(frame: {} | null | undefined): HumanInputAttachmentView[] | undefined;
42
+ export interface HumanInputAuthorKeys {
43
+ author?: string;
44
+ extension?: string;
45
+ }
46
+ export declare function humanInputAuthorKeys(frame: {} | null | undefined): HumanInputAuthorKeys;
37
47
  export declare function markMcpSectionDroppedNamedRows(rows: object, dropped: ReadonlyMap<string, number>): void;
38
48
  export declare function mcpSectionDroppedNamedRowsOf(rows: object | null | undefined, name: string): number;
39
49
  export interface PromptManifestSectionRow {