@sema-agent/client-core 0.105.0 → 0.106.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +220 -0
- package/README.md +26 -11
- package/dist/adapt/arms.js +10 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +13 -2
- package/dist/adapter/activeRunSelfHeal.js +80 -7
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +20 -19
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/adapter/downstream/wiringManifestView.d.ts +1 -3
- package/dist/adapter/downstream/wiringManifestView.js +0 -1
- package/dist/adapter/runStream.js +3 -4
- package/dist/approvalReachWire.d.ts +1 -0
- package/dist/approvalReachWire.js +4 -1
- package/dist/approvalSeat.d.ts +21 -0
- package/dist/approvalSeat.js +73 -0
- package/dist/assistantInbox.d.ts +2 -0
- package/dist/assistantInbox.js +3 -0
- package/dist/checkpointRowVerdict.d.ts +23 -0
- package/dist/checkpointRowVerdict.js +89 -0
- package/dist/coreValuePorts.d.ts +12 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideFailureNote.js +3 -1
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +29 -1
- package/dist/declared/supportFloorDeclared.js +2 -2
- package/dist/deviceRebind.d.ts +7 -0
- package/dist/deviceRebind.js +39 -5
- package/dist/engineAddress.d.ts +3 -0
- package/dist/engineAddress.js +25 -0
- package/dist/engineDirectory.js +9 -17
- package/dist/engineErrorCodes.d.ts +8 -0
- package/dist/engineErrorCodes.js +8 -0
- package/dist/engineNoticeCodes.d.ts +26 -3
- package/dist/engineNoticeCodes.js +52 -7
- package/dist/engineRowRef.js +1 -1
- package/dist/errorSupplementRoles.js +2 -0
- package/dist/eventLeg.d.ts +2 -2
- package/dist/eventLeg.js +2 -1
- package/dist/fleet/fleetProjection.js +26 -5
- package/dist/generated/engineFactTables.d.ts +2 -1
- package/dist/generated/engineFactTables.js +3 -1
- package/dist/generated/engineNoticeTables.js +19 -4
- package/dist/generated/sdkFactTables.d.ts +3 -0
- package/dist/generated/sdkFactTables.js +15 -0
- package/dist/generated/settingsSchemaFns.d.ts +11 -0
- package/dist/generated/settingsSchemaFns.js +2 -1
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +1 -1
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -1
- package/dist/generated/settingsSchemaSettingsSources.js +22 -2
- package/dist/hitl/approvalLiveFace.d.ts +17 -0
- package/dist/hitl/approvalLiveFace.js +35 -0
- package/dist/hitl/approvalQueueRow.d.ts +21 -0
- package/dist/hitl/approvalQueueRow.js +69 -0
- package/dist/hitl/approvalsFeed.d.ts +5 -4
- package/dist/hitl/approvalsFeed.js +38 -6
- package/dist/hitl/askParkRowRouting.d.ts +4 -3
- package/dist/hitl/askParkRowRouting.js +15 -3
- package/dist/hitl/automaticAnswerVerdict.js +13 -10
- package/dist/hitl/crashConverged.d.ts +5 -1
- package/dist/hitl/decisionConflict.js +2 -1
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +1 -0
- package/dist/hitl/decisionSend.js +14 -2
- package/dist/hitl/frameRouter.js +4 -5
- package/dist/hitl/hitlBridge.d.ts +1 -1
- package/dist/hitl/hitlBridge.js +26 -5
- package/dist/hitl/livePendingAsk.d.ts +5 -0
- package/dist/hitl/livePendingAsk.js +6 -1
- package/dist/hitl/planReviewCard.d.ts +2 -0
- package/dist/hitl/planReviewCard.js +21 -0
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +101 -36
- package/dist/hitl/sessionAllowRoute.d.ts +2 -0
- package/dist/hitl/sessionAllowRoute.js +7 -0
- package/dist/hitl/sessionPolicyWire.d.ts +1 -7
- package/dist/hitl/sessionPolicyWire.js +3 -43
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +13 -0
- package/dist/hitl/toolApprovalWire.d.ts +3 -2
- package/dist/hitl/toolApprovalWire.js +79 -37
- package/dist/hostSettingsSource.d.ts +4 -1
- package/dist/hostSettingsSource.js +11 -6
- package/dist/hostTurnSettings.d.ts +4 -5
- package/dist/hostTurnSettings.js +80 -19
- package/dist/i18n/messages.en.d.ts +35 -12
- package/dist/i18n/messages.en.js +36 -13
- package/dist/i18n/messages.zh.js +38 -13
- package/dist/index.d.ts +21 -2
- package/dist/index.js +11 -2
- package/dist/liveInitToolFace.js +0 -1
- package/dist/liveModelCatalog.d.ts +15 -0
- package/dist/liveModelCatalog.js +40 -0
- package/dist/mcpWireCaps.js +1 -1
- package/dist/modelCapabilityProbe.js +66 -33
- package/dist/ownKey.d.ts +0 -1
- package/dist/ownKey.js +0 -2
- package/dist/permissionsDeclaration.d.ts +2 -2
- package/dist/permissionsDeclaration.js +12 -14
- package/dist/projectSeed.d.ts +39 -0
- package/dist/projectSeed.js +80 -0
- package/dist/promptDelivery.js +1 -1
- package/dist/replayBody.d.ts +7 -6
- package/dist/replayBody.js +62 -7
- package/dist/request/taskRequest.js +3 -4
- package/dist/ruleCompileVerdict.d.ts +0 -2
- package/dist/ruleCompileVerdict.js +0 -31
- package/dist/ruleRefusalSentence.js +0 -3
- package/dist/runReattachPolicy.d.ts +3 -0
- package/dist/runReattachPolicy.js +15 -2
- package/dist/runTerminal.js +30 -8
- package/dist/sandboxWire.d.ts +0 -3
- package/dist/sandboxWire.js +0 -9
- package/dist/seam.d.ts +14 -7
- package/dist/seam.js +12 -0
- package/dist/seatContract.d.ts +57 -7
- package/dist/seatContract.js +132 -3
- package/dist/serverSupportRange.d.ts +18 -0
- package/dist/serverSupportRange.js +25 -0
- package/dist/sessionEngine.d.ts +156 -0
- package/dist/sessionEngine.js +464 -0
- package/dist/sessionMap.d.ts +11 -1
- package/dist/sessionMap.js +35 -9
- package/dist/sessionMemorySync.d.ts +31 -0
- package/dist/sessionMemorySync.js +95 -0
- package/dist/sessionRowTag.d.ts +4 -0
- package/dist/sessionRowTag.js +18 -0
- package/dist/settingsLayerAdmission.d.ts +1 -0
- package/dist/settingsLayerAdmission.js +4 -1
- package/dist/toolResult.js +1 -1
- package/dist/wireRefusalCopy.js +2 -6
- package/docs/INTEGRATION-CLIENTS.md +1022 -16
- package/package.json +5 -5
|
@@ -3,7 +3,8 @@ import { rowIdTail } from '../workflow.js';
|
|
|
3
3
|
import { cycleSeqValue } from '../cycleOrder.js';
|
|
4
4
|
import { frozenSet } from '../frozenSet.js';
|
|
5
5
|
import { guardedRead, readOwnDataValue } from '../ownKey.js';
|
|
6
|
-
import { CORE_RESERVED_AGENT_NAMES } from '../generated/engineFactTables.js';
|
|
6
|
+
import { CORE_RESERVED_AGENT_NAMES, CORE_WORKFLOW_AGENT_PARKED_ERROR_CODE } from '../generated/engineFactTables.js';
|
|
7
|
+
import { runParkedOf as coreRunParkedOf } from '../coreValuePorts.js';
|
|
7
8
|
export function coerceTaskStatus(s) {
|
|
8
9
|
if (s === 'parked')
|
|
9
10
|
return 'awaiting approval';
|
|
@@ -31,9 +32,9 @@ export function coerceWorkflowStatus(s) {
|
|
|
31
32
|
}
|
|
32
33
|
export function workflowRunDisplayStatusOf(run) {
|
|
33
34
|
const status = runField(run, 'status');
|
|
34
|
-
if (
|
|
35
|
+
if (parkedWindowOf(run, status))
|
|
35
36
|
return 'awaiting approval';
|
|
36
|
-
if (status === 'failed' && runField(run, 'errorCode') ===
|
|
37
|
+
if (status === 'failed' && runField(run, 'errorCode') === CORE_WORKFLOW_AGENT_PARKED_ERROR_CODE)
|
|
37
38
|
return 'awaiting approval';
|
|
38
39
|
switch (status) {
|
|
39
40
|
case 'completed':
|
|
@@ -52,7 +53,27 @@ export function workflowRunDisplayStatusOf(run) {
|
|
|
52
53
|
return 'idle';
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
+
function parkedWindowOf(run, status) {
|
|
57
|
+
if (runField(run, 'parked') === true)
|
|
58
|
+
return true;
|
|
59
|
+
if (guardedRead(() => (typeof run === 'object' && run !== null ? !Object.hasOwn(run, 'parked') : undefined)) !== true)
|
|
60
|
+
return false;
|
|
61
|
+
const agents = runField(run, 'agents');
|
|
62
|
+
if (typeof status !== 'string' || guardedRead(() => Array.isArray(agents)) !== true)
|
|
63
|
+
return false;
|
|
64
|
+
return guardedRead(() => {
|
|
65
|
+
const rows = [];
|
|
66
|
+
const list = agents;
|
|
67
|
+
for (const k of Object.keys(list)) {
|
|
68
|
+
if (!/^(?:0|[1-9]\d*)$/.test(k))
|
|
69
|
+
continue;
|
|
70
|
+
const a = readOwnDataValue(list, k);
|
|
71
|
+
const st = typeof a === 'object' && a !== null ? runField(a, 'status') : undefined;
|
|
72
|
+
rows.push({ status: typeof st === 'string' ? st : '' });
|
|
73
|
+
}
|
|
74
|
+
return coreRunParkedOf({ status, agents: rows });
|
|
75
|
+
}) === true;
|
|
76
|
+
}
|
|
56
77
|
function runField(run, key) {
|
|
57
78
|
return guardedRead(() => typeof run === 'object' && run !== null && !Array.isArray(run) ? readOwnDataValue(run, key) : undefined);
|
|
58
79
|
}
|
|
@@ -362,7 +383,7 @@ export const FLEET_WORKFLOW_ROW_KEYS_NOT_PROJECTED = {
|
|
|
362
383
|
errorCode: {
|
|
363
384
|
kind: 'by-design',
|
|
364
385
|
owner: 'client-core 0.103.0 提货',
|
|
365
|
-
reason: '折进 status
|
|
386
|
+
reason: '折进 status:只有引擎的停驻终态码(值取自引擎包根导出,经生成表读)改显示状态(awaiting approval,停驻不是失败),读法唯一处 workflowRunDisplayStatusOf;' +
|
|
366
387
|
'0.95.0 CC-388 把它从视图退出时服务端还不铸,现在铸了也不回到视图 —— run 级别的其它码走 workflow 读面。',
|
|
367
388
|
},
|
|
368
389
|
parked: {
|
|
@@ -48,7 +48,7 @@ export declare const CORE_TASK_NOTIFICATION_TERMINAL_STATUSES: readonly ["comple
|
|
|
48
48
|
export declare const CORE_RESUME_STARTUP_CAUSES: readonly ["environment", "session_gone", "transcript_corrupt", "tool_unavailable", "configuration", "decision_rejected"];
|
|
49
49
|
export declare const CORE_BUILTIN_SUBAGENT_TYPES: readonly ["Explore", "Plan", "fork", "general-purpose"];
|
|
50
50
|
export declare const CORE_RULE_OFFERS_ABSENCES: readonly ["mandated", "allow_outranked", "ask_rule_matched", "lane_cannot_speak"];
|
|
51
|
-
export declare const CORE_TOOL_APPROVAL_CARDS: readonly ["file-edit", "file-write", "notebook-edit", "shell", "fetch", "skill", "workflow", "plan", "question", "generic"];
|
|
51
|
+
export declare const CORE_TOOL_APPROVAL_CARDS: readonly ["file-edit", "file-write", "notebook-edit", "shell", "fetch", "skill", "workflow", "plan", "question", "generic", "computer-access", "computer-control"];
|
|
52
52
|
export declare const CORE_MCP_FAILURE_KINDS: readonly ["connect_refused", "connection_failed", "connection_closed", "unauthorized", "http_status", "not_mcp_response", "spawn_failed", "timeout", "protocol", "invalid_config", "credential_unavailable", "host_refused", "unknown"];
|
|
53
53
|
export declare const CORE_MCP_AUTHORIZATION_REASONS: readonly ["rejected", "scope", "none"];
|
|
54
54
|
export declare const CORE_PERSISTED_RULE_MATCHES: readonly ["exact", "prefix", "wildcard", "pattern", "subpath", "path", "name", "name_prefix", "host", "subdomain", "tool"];
|
|
@@ -72,3 +72,4 @@ export declare const CORE_USER_ATTACHMENT_SEAT: CoreUserAttachmentSeat;
|
|
|
72
72
|
export declare const CORE_USER_ATTACHMENTS_MAX: number;
|
|
73
73
|
export declare const CORE_USER_ATTACHMENT_LABEL_MAX: number;
|
|
74
74
|
export declare const CORE_PRESENT_PLAN_TOOL_NAME: "ExitPlanMode";
|
|
75
|
+
export declare const CORE_WORKFLOW_AGENT_PARKED_ERROR_CODE: "workflow.agent_parked";
|
|
@@ -76,7 +76,6 @@ export const CORE_ENGINE_CARD_TYPES = Object.freeze([
|
|
|
76
76
|
"repo-map",
|
|
77
77
|
"artifact",
|
|
78
78
|
"worktree",
|
|
79
|
-
"task-output",
|
|
80
79
|
"task-stop",
|
|
81
80
|
"monitor-start",
|
|
82
81
|
"send-message",
|
|
@@ -366,6 +365,8 @@ export const CORE_TOOL_APPROVAL_CARDS = Object.freeze([
|
|
|
366
365
|
"plan",
|
|
367
366
|
"question",
|
|
368
367
|
"generic",
|
|
368
|
+
"computer-access",
|
|
369
|
+
"computer-control",
|
|
369
370
|
]);
|
|
370
371
|
export const CORE_MCP_FAILURE_KINDS = Object.freeze([
|
|
371
372
|
"connect_refused",
|
|
@@ -464,3 +465,4 @@ export const CORE_USER_ATTACHMENT_SEAT = Object.freeze({
|
|
|
464
465
|
export const CORE_USER_ATTACHMENTS_MAX = 20;
|
|
465
466
|
export const CORE_USER_ATTACHMENT_LABEL_MAX = 4096;
|
|
466
467
|
export const CORE_PRESENT_PLAN_TOOL_NAME = "ExitPlanMode";
|
|
468
|
+
export const CORE_WORKFLOW_AGENT_PARKED_ERROR_CODE = "workflow.agent_parked";
|
|
@@ -18,6 +18,7 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
18
18
|
"config.path_view_unresolved",
|
|
19
19
|
"config.execution_env_capability_invalid",
|
|
20
20
|
"config.read_deny_floor_unkept",
|
|
21
|
+
"config.read_floor_confinement_unavailable",
|
|
21
22
|
"config.tool_card_undeclared",
|
|
22
23
|
"config.tool_face_undeclared",
|
|
23
24
|
"config.tool_face_invalid",
|
|
@@ -86,7 +87,8 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
86
87
|
"model.capability_downgraded",
|
|
87
88
|
"model.role_defaulted",
|
|
88
89
|
"context.tool_turn_repaired",
|
|
89
|
-
"context.
|
|
90
|
+
"context.media_removed",
|
|
91
|
+
"context.tool_schema_removed",
|
|
90
92
|
"task.user_steer_undrained",
|
|
91
93
|
"task.user_followup_undrained",
|
|
92
94
|
"steering.parked_input_blocked",
|
|
@@ -104,6 +106,9 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
104
106
|
"tool_result.offload_put_failed",
|
|
105
107
|
"tool_result.media_refused",
|
|
106
108
|
"config.image_processor_unavailable",
|
|
109
|
+
"fs.staging_file_left",
|
|
110
|
+
"fs.staging_file_swept",
|
|
111
|
+
"session.lineage_rerooted",
|
|
107
112
|
"instructions.source_changed",
|
|
108
113
|
"session.records_skipped",
|
|
109
114
|
"memory.layer_locked_legacy",
|
|
@@ -130,6 +135,7 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
130
135
|
"config.path_view_unresolved": "operator",
|
|
131
136
|
"config.execution_env_capability_invalid": "operator",
|
|
132
137
|
"config.read_deny_floor_unkept": "operator",
|
|
138
|
+
"config.read_floor_confinement_unavailable": "operator",
|
|
133
139
|
"config.tool_card_undeclared": "operator",
|
|
134
140
|
"config.tool_face_undeclared": "operator",
|
|
135
141
|
"config.tool_face_invalid": "operator",
|
|
@@ -155,7 +161,7 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
155
161
|
"peer.idle_subscription": "user",
|
|
156
162
|
"classifier.denial_limit": "user",
|
|
157
163
|
"classifier.fallback": "operator",
|
|
158
|
-
"classifier.seat_rate_limited": "
|
|
164
|
+
"classifier.seat_rate_limited": "user",
|
|
159
165
|
"classifier.role_defaulted": "operator",
|
|
160
166
|
"classifier.contract_broken": "operator",
|
|
161
167
|
"classifier.unavailable": "user",
|
|
@@ -198,7 +204,8 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
198
204
|
"model.capability_downgraded": "user",
|
|
199
205
|
"model.role_defaulted": "operator",
|
|
200
206
|
"context.tool_turn_repaired": "operator",
|
|
201
|
-
"context.
|
|
207
|
+
"context.media_removed": "user",
|
|
208
|
+
"context.tool_schema_removed": "user",
|
|
202
209
|
"task.user_steer_undrained": "user",
|
|
203
210
|
"task.user_followup_undrained": "user",
|
|
204
211
|
"steering.parked_input_blocked": "user",
|
|
@@ -216,6 +223,9 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
216
223
|
"tool_result.offload_put_failed": "operator",
|
|
217
224
|
"tool_result.media_refused": "operator",
|
|
218
225
|
"config.image_processor_unavailable": "operator",
|
|
226
|
+
"fs.staging_file_left": "operator",
|
|
227
|
+
"fs.staging_file_swept": "operator",
|
|
228
|
+
"session.lineage_rerooted": "user",
|
|
219
229
|
"instructions.source_changed": "user",
|
|
220
230
|
"session.records_skipped": "user",
|
|
221
231
|
"memory.layer_locked_legacy": "operator",
|
|
@@ -248,6 +258,7 @@ export const CORE_NOTICE_MINTER = Object.freeze({
|
|
|
248
258
|
"config.path_view_unresolved": "engine",
|
|
249
259
|
"config.execution_env_capability_invalid": "engine",
|
|
250
260
|
"config.read_deny_floor_unkept": "engine",
|
|
261
|
+
"config.read_floor_confinement_unavailable": "engine",
|
|
251
262
|
"config.tool_card_undeclared": "engine",
|
|
252
263
|
"config.tool_face_undeclared": "engine",
|
|
253
264
|
"config.tool_face_invalid": "engine",
|
|
@@ -316,7 +327,8 @@ export const CORE_NOTICE_MINTER = Object.freeze({
|
|
|
316
327
|
"model.capability_downgraded": "engine",
|
|
317
328
|
"model.role_defaulted": "engine",
|
|
318
329
|
"context.tool_turn_repaired": "engine",
|
|
319
|
-
"context.
|
|
330
|
+
"context.media_removed": "engine",
|
|
331
|
+
"context.tool_schema_removed": "engine",
|
|
320
332
|
"task.user_steer_undrained": "engine",
|
|
321
333
|
"task.user_followup_undrained": "engine",
|
|
322
334
|
"steering.parked_input_blocked": "engine",
|
|
@@ -334,6 +346,9 @@ export const CORE_NOTICE_MINTER = Object.freeze({
|
|
|
334
346
|
"tool_result.offload_put_failed": "engine",
|
|
335
347
|
"tool_result.media_refused": "engine",
|
|
336
348
|
"config.image_processor_unavailable": "engine",
|
|
349
|
+
"fs.staging_file_left": "engine",
|
|
350
|
+
"fs.staging_file_swept": "engine",
|
|
351
|
+
"session.lineage_rerooted": "engine",
|
|
337
352
|
"instructions.source_changed": "server",
|
|
338
353
|
"session.records_skipped": "server",
|
|
339
354
|
"memory.layer_locked_legacy": "server",
|
|
@@ -7,3 +7,6 @@ export declare const SDK_APPROVAL_DECIDE_GATE_KINDS: readonly ["human", "irrever
|
|
|
7
7
|
export declare const SDK_PLAN_REVIEW_GATE_KINDS: readonly ["plan_review"];
|
|
8
8
|
export declare const SDK_PERMISSION_MODE_ADMISSION_FOLDS: readonly ["entry_floor", "disable_auto_mode"];
|
|
9
9
|
export declare const SDK_PERMISSION_MODE_PERSIST_MISSES: readonly ["claim_released", "context_absent", "store_failed"];
|
|
10
|
+
export declare const SDK_DECIDE_BINDING_KEYS: readonly ["boundCallId", "boundInputHash"];
|
|
11
|
+
export declare const SDK_APPROVAL_QUEUE_KINDS: readonly ["checkpoint", "peer_inbound"];
|
|
12
|
+
export declare const SDK_SESSION_MEMORY_UNOBSERVED_REASONS: readonly ["no_settled_run", "run_result_missing", "run_result_unobserved", "memory_not_mounted", "no_leaf"];
|
|
@@ -48,3 +48,18 @@ export const SDK_PERMISSION_MODE_PERSIST_MISSES = Object.freeze([
|
|
|
48
48
|
"context_absent",
|
|
49
49
|
"store_failed",
|
|
50
50
|
]);
|
|
51
|
+
export const SDK_DECIDE_BINDING_KEYS = Object.freeze([
|
|
52
|
+
"boundCallId",
|
|
53
|
+
"boundInputHash",
|
|
54
|
+
]);
|
|
55
|
+
export const SDK_APPROVAL_QUEUE_KINDS = Object.freeze([
|
|
56
|
+
"checkpoint",
|
|
57
|
+
"peer_inbound",
|
|
58
|
+
]);
|
|
59
|
+
export const SDK_SESSION_MEMORY_UNOBSERVED_REASONS = Object.freeze([
|
|
60
|
+
"no_settled_run",
|
|
61
|
+
"run_result_missing",
|
|
62
|
+
"run_result_unobserved",
|
|
63
|
+
"memory_not_mounted",
|
|
64
|
+
"no_leaf",
|
|
65
|
+
]);
|
|
@@ -51,6 +51,17 @@ export declare const SETTINGS_IS_AT_LEAST: (layer: string, minTrust: string) =>
|
|
|
51
51
|
export declare const SETTINGS_MEMBER_ADMISSION: (category: string, member: string) => object;
|
|
52
52
|
export declare const SETTINGS_SAFETY_MERGE_SPEC: object;
|
|
53
53
|
export declare const SETTINGS_LAYER_ADMISSION: (source: string, workspace: string, category: string, member?: string) => string;
|
|
54
|
+
export declare const SETTINGS_BUILD_LAYER_PARTS_UNREAD_NOTICE: (input: {
|
|
55
|
+
readonly source: string;
|
|
56
|
+
readonly workspace: string;
|
|
57
|
+
readonly file: string;
|
|
58
|
+
readonly parts: readonly string[];
|
|
59
|
+
}) => {
|
|
60
|
+
readonly code: string;
|
|
61
|
+
readonly source: string;
|
|
62
|
+
readonly parts: readonly string[];
|
|
63
|
+
readonly line: string;
|
|
64
|
+
} | undefined;
|
|
54
65
|
export declare const SETTINGS_RESOLVE_ACTIVE_TIERS: (models: {
|
|
55
66
|
readonly tierGroups?: readonly {
|
|
56
67
|
readonly name: string;
|
|
@@ -182,8 +182,9 @@ const SETTINGS_SAFETY_MERGE = SETTINGS_SAFETY_MERGE_CLOSURE(SETTINGS_MIN_TRUST_W
|
|
|
182
182
|
export const SETTINGS_IS_AT_LEAST = SETTINGS_SAFETY_MERGE.isAtLeast;
|
|
183
183
|
export const SETTINGS_MEMBER_ADMISSION = SETTINGS_SAFETY_MERGE.memberAdmission;
|
|
184
184
|
export const SETTINGS_SAFETY_MERGE_SPEC = SETTINGS_SAFETY_MERGE.SAFETY_MERGE_SPEC;
|
|
185
|
-
const SETTINGS_LAYER_SOURCES = SETTINGS_LAYER_SOURCES_CLOSURE(SETTINGS_SAFETY_MERGE_SPEC, SETTINGS_IS_AT_LEAST, SETTINGS_MEMBER_ADMISSION);
|
|
185
|
+
const SETTINGS_LAYER_SOURCES = SETTINGS_LAYER_SOURCES_CLOSURE(SETTINGS_SAFETY_MERGE_SPEC, SETTINGS_IS_AT_LEAST, SETTINGS_MEMBER_ADMISSION, SETTINGS_ECHO_CALLER_TEXT, SETTINGS_STRIP_CONTROL_AND_BIDI);
|
|
186
186
|
export const SETTINGS_LAYER_ADMISSION = SETTINGS_LAYER_SOURCES.layerAdmission;
|
|
187
|
+
export const SETTINGS_BUILD_LAYER_PARTS_UNREAD_NOTICE = SETTINGS_LAYER_SOURCES.buildLayerPartsUnreadNotice;
|
|
187
188
|
const SETTINGS_ACTIVE_TIERS = SETTINGS_ACTIVE_TIERS_CLOSURE();
|
|
188
189
|
export const SETTINGS_RESOLVE_ACTIVE_TIERS = SETTINGS_ACTIVE_TIERS.resolveActiveTiers;
|
|
189
190
|
const SETTINGS_TIER_WORDS = SETTINGS_TIER_WORDS_CLOSURE();
|
|
@@ -53,7 +53,7 @@ export const SETTINGS_SAFETY_MERGE_CLOSURE = (MIN_TRUST_WORDS) => {
|
|
|
53
53
|
model: { mergeShape: "replace", minTrust: "session", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "RoleSpec / TaskSpec.{model,thinking}" },
|
|
54
54
|
env: { mergeShape: "concat", minTrust: "project", tighten: { rule: "none" }, enforcement: "resolver", fail: "open", seam: "NodeExecutionEnv.shellEnv (later layer overrides same name)" },
|
|
55
55
|
envSecret: { mergeShape: "replace", minTrust: "global", tighten: { rule: "none" }, enforcement: "resolver", fail: "closed", seam: "§7 secret-ref resolution" },
|
|
56
|
-
memoryScopes: { mergeShape: "concat", minTrust: "global", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "
|
|
56
|
+
memoryScopes: { mergeShape: "concat", minTrust: "global", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "MemoryEngine" },
|
|
57
57
|
autoCompaction: { mergeShape: "replace", minTrust: "session", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "compaction config" },
|
|
58
58
|
ui: { mergeShape: "replace", minTrust: "local", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "shell-only (theme/keybindings/statusLine) — never touches the engine" },
|
|
59
59
|
org: { mergeShape: "replace", minTrust: "managed", tighten: { rule: "none" }, enforcement: "server", fail: "closed", seam: "web-admin → governanceBaseline (SSO/SCIM/audit/budget, TOB-only)" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SETTINGS_LAYER_SOURCES_CLOSURE: (SAFETY_MERGE_SPEC: object, isAtLeast: (layer: string, minTrust: string) => boolean, memberAdmission: (category: string, member: string) => object) => any;
|
|
1
|
+
export declare const SETTINGS_LAYER_SOURCES_CLOSURE: (SAFETY_MERGE_SPEC: object, isAtLeast: (layer: string, minTrust: string) => boolean, memberAdmission: (category: string, member: string) => object, echoCallerText: (text: string) => string, stripControlAndBidi: (text: string) => string) => any;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, memberAdmission) => {
|
|
1
|
+
export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, memberAdmission, echoCallerText, stripControlAndBidi) => {
|
|
2
2
|
const SETTINGS_SOURCES = ["userSettings", "projectSettings", "localSettings", "flagSettings", "policySettings", "foreignProjectSettings"];
|
|
3
3
|
const SETTINGS_SOURCE_CONTRACT = {
|
|
4
4
|
userSettings: { trust: "global", repoControllable: false },
|
|
@@ -41,6 +41,26 @@ export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, mem
|
|
|
41
41
|
const accepted = workspaceAccepted(workspace);
|
|
42
42
|
return layer.tightenOnly === true || (layer.repoControllable && !accepted);
|
|
43
43
|
}
|
|
44
|
+
const LAYER_PARTS_UNREAD_CODE = "settings.layer_parts_unread";
|
|
45
|
+
const NOTICE_PARTS_SHOWN = 16;
|
|
46
|
+
function buildLayerPartsUnreadNotice(input) {
|
|
47
|
+
const layer = settingsSourceContract(input.source);
|
|
48
|
+
if (!readsTightenOnly(layer, input.workspace)) {
|
|
49
|
+
throw new RangeError(`buildLayerPartsUnreadNotice: source '${input.source}' is not read in the tighten direction only under workspace reading '${input.workspace}' — there is nothing "read for restrictions only" to disclose`);
|
|
50
|
+
}
|
|
51
|
+
if (input.parts.length === 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
const cause = layer.tightenOnly === true ? "it is written for another tool" : "this workspace is not trusted";
|
|
54
|
+
const shown = input.parts.slice(0, NOTICE_PARTS_SHOWN).map(echoCallerText);
|
|
55
|
+
const rest = input.parts.length - shown.length;
|
|
56
|
+
const named = rest > 0 ? `${shown.join(", ")}, +${rest} more` : shown.join(", ");
|
|
57
|
+
return {
|
|
58
|
+
code: LAYER_PARTS_UNREAD_CODE,
|
|
59
|
+
source: input.source,
|
|
60
|
+
parts: [...input.parts],
|
|
61
|
+
line: `${stripControlAndBidi(input.file)}: read for restrictions only (${cause}) — not read: ${named}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
44
64
|
function workspaceAccepted(workspace) {
|
|
45
65
|
switch (workspace) {
|
|
46
66
|
case "accepted":
|
|
@@ -54,5 +74,5 @@ export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, mem
|
|
|
54
74
|
}
|
|
55
75
|
}
|
|
56
76
|
}
|
|
57
|
-
return { layerAdmission };
|
|
77
|
+
return { layerAdmission, buildLayerPartsUnreadNotice };
|
|
58
78
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ApprovalMandateWord } from '../gateVocabulary.js';
|
|
2
|
+
export declare const APPROVAL_LIVE_FACE_KEYS: readonly ["mandate", "mandated", "origin"];
|
|
3
|
+
export declare function hasOwnStrictTrue(v: object, key: string): boolean;
|
|
4
|
+
export interface ApprovalLiveFaceFacts {
|
|
5
|
+
mandated?: true;
|
|
6
|
+
mandate?: ApprovalMandateWord;
|
|
7
|
+
origin?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ApprovalLiveFace {
|
|
10
|
+
readonly facts: Readonly<ApprovalLiveFaceFacts>;
|
|
11
|
+
readonly layerUnknown?: 'marked' | 'absent';
|
|
12
|
+
}
|
|
13
|
+
export declare function approvalLiveFaceOf(live: object): ApprovalLiveFace;
|
|
14
|
+
export type ApprovalLiveFaceCarried = ApprovalLiveFaceFacts & {
|
|
15
|
+
readonly liveFactsUnknown?: true;
|
|
16
|
+
};
|
|
17
|
+
export declare function liveFaceCarried(face: ApprovalLiveFace): ApprovalLiveFaceCarried;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readAskOrigin } from '../ownKey.js';
|
|
2
|
+
import { slotPresenceOf, slotReadOf } from '../wireFailureShape.js';
|
|
3
|
+
import { readApprovalMandate } from './toolApprovalWire.js';
|
|
4
|
+
export const APPROVAL_LIVE_FACE_KEYS = Object.freeze(['mandate', 'mandated', 'origin']);
|
|
5
|
+
export function hasOwnStrictTrue(v, key) {
|
|
6
|
+
return Object.hasOwn(v, key) && v[key] === true;
|
|
7
|
+
}
|
|
8
|
+
const APPROVAL_LIVE_FACTS_UNKNOWN_KEY = 'liveFactsUnknown';
|
|
9
|
+
function guarded(read) {
|
|
10
|
+
try {
|
|
11
|
+
return read();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function approvalLiveFaceOf(live) {
|
|
18
|
+
const marker = slotReadOf(live, APPROVAL_LIVE_FACTS_UNKNOWN_KEY);
|
|
19
|
+
const marked = marker.presence === 'unreadable' || (marker.presence === 'present' && marker.value === true);
|
|
20
|
+
const layerAbsent = !marked && APPROVAL_LIVE_FACE_KEYS.every((k) => slotPresenceOf(live, k) === 'absent');
|
|
21
|
+
const facts = {};
|
|
22
|
+
if (guarded(() => hasOwnStrictTrue(live, 'mandated')) === true)
|
|
23
|
+
facts.mandated = true;
|
|
24
|
+
const mandate = guarded(() => readApprovalMandate(live));
|
|
25
|
+
if (mandate !== undefined)
|
|
26
|
+
facts.mandate = mandate;
|
|
27
|
+
const origin = guarded(() => readAskOrigin(live));
|
|
28
|
+
if (origin !== undefined)
|
|
29
|
+
facts.origin = origin;
|
|
30
|
+
const layerUnknown = marked ? 'marked' : layerAbsent ? 'absent' : undefined;
|
|
31
|
+
return Object.freeze({ facts: Object.freeze(facts), ...(layerUnknown !== undefined ? { layerUnknown } : {}) });
|
|
32
|
+
}
|
|
33
|
+
export function liveFaceCarried(face) {
|
|
34
|
+
return face.layerUnknown === 'marked' ? { ...face.facts, [APPROVAL_LIVE_FACTS_UNKNOWN_KEY]: true } : { ...face.facts };
|
|
35
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SDK_APPROVAL_QUEUE_KINDS } from '../generated/sdkFactTables.js';
|
|
2
|
+
export type ApprovalQueueKind = (typeof SDK_APPROVAL_QUEUE_KINDS)[number];
|
|
3
|
+
export type ApprovalQueueRowFamily = ApprovalQueueKind | 'unknown' | 'unreadable';
|
|
4
|
+
export declare function approvalQueueRowFamilyOf(row: object): ApprovalQueueRowFamily;
|
|
5
|
+
export type CheckpointQueueRowSort = 'checkpoint' | 'excluded' | 'unreadable';
|
|
6
|
+
export declare function checkpointQueueRowSortOf(row: object | null | undefined): CheckpointQueueRowSort;
|
|
7
|
+
export declare const QUEUE_ROW_FAMILY_UNREADABLE_GATE = "(unreadable)";
|
|
8
|
+
export interface ApprovalQueuePeerInboundRow {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly recipientSessionId: string;
|
|
11
|
+
readonly lane?: string;
|
|
12
|
+
readonly cause?: string;
|
|
13
|
+
readonly content?: string;
|
|
14
|
+
readonly sentAt?: number;
|
|
15
|
+
readonly heldAt?: number;
|
|
16
|
+
readonly deadline?: number;
|
|
17
|
+
readonly fromSession?: string;
|
|
18
|
+
readonly fromName?: string;
|
|
19
|
+
readonly fromScope?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function peerInboundQueueRowOf(row: object): ApprovalQueuePeerInboundRow | undefined;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { slotReadOf } from '../wireFailureShape.js';
|
|
2
|
+
import { SDK_APPROVAL_QUEUE_KINDS } from '../generated/sdkFactTables.js';
|
|
3
|
+
const _queueKindsPin = true;
|
|
4
|
+
void _queueKindsPin;
|
|
5
|
+
const isApprovalQueueKind = (v) => SDK_APPROVAL_QUEUE_KINDS.includes(v);
|
|
6
|
+
export function approvalQueueRowFamilyOf(row) {
|
|
7
|
+
const kind = slotReadOf(row, 'kind');
|
|
8
|
+
if (kind.presence === 'absent')
|
|
9
|
+
return 'checkpoint';
|
|
10
|
+
if (kind.presence !== 'present' || typeof kind.value !== 'string')
|
|
11
|
+
return 'unreadable';
|
|
12
|
+
return isApprovalQueueKind(kind.value) ? kind.value : 'unknown';
|
|
13
|
+
}
|
|
14
|
+
export function checkpointQueueRowSortOf(row) {
|
|
15
|
+
try {
|
|
16
|
+
if (typeof row !== 'object' || row === null || Array.isArray(row))
|
|
17
|
+
return 'excluded';
|
|
18
|
+
const family = approvalQueueRowFamilyOf(row);
|
|
19
|
+
return family === 'checkpoint' ? 'checkpoint' : family === 'unreadable' ? 'unreadable' : 'excluded';
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return 'unreadable';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export const QUEUE_ROW_FAMILY_UNREADABLE_GATE = '(unreadable)';
|
|
26
|
+
const ownString = (row, key, nonEmpty) => {
|
|
27
|
+
const r = slotReadOf(row, key);
|
|
28
|
+
return r.presence === 'present' && typeof r.value === 'string' && (!nonEmpty || r.value !== '') ? r.value : undefined;
|
|
29
|
+
};
|
|
30
|
+
const ownTime = (row, key) => {
|
|
31
|
+
const r = slotReadOf(row, key);
|
|
32
|
+
return r.presence === 'present' && typeof r.value === 'number' && Number.isFinite(r.value) && r.value >= 0 ? r.value : undefined;
|
|
33
|
+
};
|
|
34
|
+
export function peerInboundQueueRowOf(row) {
|
|
35
|
+
try {
|
|
36
|
+
const id = ownString(row, 'id', true);
|
|
37
|
+
const recipientSessionId = ownString(row, 'recipientSessionId', true);
|
|
38
|
+
if (id === undefined || recipientSessionId === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
const out = { id, recipientSessionId };
|
|
41
|
+
const lane = ownString(row, 'lane', true);
|
|
42
|
+
if (lane !== undefined)
|
|
43
|
+
out.lane = lane;
|
|
44
|
+
const cause = ownString(row, 'cause', true);
|
|
45
|
+
if (cause !== undefined)
|
|
46
|
+
out.cause = cause;
|
|
47
|
+
const content = ownString(row, 'content', false);
|
|
48
|
+
if (content !== undefined)
|
|
49
|
+
out.content = content;
|
|
50
|
+
const sentAt = ownTime(row, 'sentAt');
|
|
51
|
+
if (sentAt !== undefined)
|
|
52
|
+
out.sentAt = sentAt;
|
|
53
|
+
const heldAt = ownTime(row, 'heldAt');
|
|
54
|
+
if (heldAt !== undefined)
|
|
55
|
+
out.heldAt = heldAt;
|
|
56
|
+
const deadline = ownTime(row, 'deadline');
|
|
57
|
+
if (deadline !== undefined)
|
|
58
|
+
out.deadline = deadline;
|
|
59
|
+
for (const k of ['fromSession', 'fromName', 'fromScope']) {
|
|
60
|
+
const v = ownString(row, k, true);
|
|
61
|
+
if (v !== undefined)
|
|
62
|
+
out[k] = v;
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze(out);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { PendingCheckpoint } from '@sema-agent/sdk';
|
|
2
2
|
import { type LivePendingAskView } from './livePendingAsk.js';
|
|
3
|
+
import { type ApprovalQueuePeerInboundRow } from './approvalQueueRow.js';
|
|
4
|
+
import type { ApprovalsListEnvelope } from './crashConverged.js';
|
|
5
|
+
export type { ApprovalQueuePeerInboundRow } from './approvalQueueRow.js';
|
|
3
6
|
export interface ApprovalsFeedClientLike {
|
|
4
7
|
approvals: {
|
|
5
8
|
list(opts?: {
|
|
6
9
|
signal?: AbortSignal;
|
|
7
|
-
}): Promise<
|
|
8
|
-
pending: PendingCheckpoint[];
|
|
9
|
-
livePending?: unknown[];
|
|
10
|
-
}>;
|
|
10
|
+
}): Promise<ApprovalsListEnvelope>;
|
|
11
11
|
stream?(opts?: {
|
|
12
12
|
signal?: AbortSignal;
|
|
13
13
|
}): AsyncGenerator<{
|
|
@@ -20,6 +20,7 @@ export type ApprovalsFeedMode = 'push' | 'poll' | 'idle';
|
|
|
20
20
|
export interface ApprovalsFeedSnapshot {
|
|
21
21
|
kind: 'snapshot';
|
|
22
22
|
pending: PendingCheckpoint[];
|
|
23
|
+
peerInbound?: ApprovalQueuePeerInboundRow[];
|
|
23
24
|
livePending?: LivePendingAskView[];
|
|
24
25
|
livePendingDropped?: number;
|
|
25
26
|
pendingDropped?: number;
|
|
@@ -2,17 +2,40 @@ import { hostLog } from '../host.js';
|
|
|
2
2
|
import { unrefTimer } from '../unrefTimer.js';
|
|
3
3
|
import { readLivePendingRows } from './livePendingAsk.js';
|
|
4
4
|
import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
|
|
5
|
+
import { approvalQueueRowFamilyOf, peerInboundQueueRowOf } from './approvalQueueRow.js';
|
|
6
|
+
import { checkpointRowVerdictOf } from '../checkpointRowVerdict.js';
|
|
7
|
+
const _realClientFitsFeedSlice = true;
|
|
8
|
+
void _realClientFitsFeedSlice;
|
|
5
9
|
const MAX_CONSECUTIVE_POLL_ESCAPES = 5;
|
|
6
10
|
function readDurablePendingRows(raw) {
|
|
7
11
|
if (!Array.isArray(raw))
|
|
8
12
|
return { kind: 'malformed' };
|
|
9
13
|
const rows = [];
|
|
14
|
+
const peer = [];
|
|
10
15
|
let dropped = 0;
|
|
16
|
+
let skipped = 0;
|
|
11
17
|
for (const item of raw) {
|
|
12
18
|
if (item === null || typeof item !== 'object' || Array.isArray(item)) {
|
|
13
19
|
dropped++;
|
|
14
20
|
continue;
|
|
15
21
|
}
|
|
22
|
+
const family = approvalQueueRowFamilyOf(item);
|
|
23
|
+
if (family === 'unknown') {
|
|
24
|
+
skipped++;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (family === 'peer_inbound') {
|
|
28
|
+
const view = peerInboundQueueRowOf(item);
|
|
29
|
+
if (view === undefined)
|
|
30
|
+
dropped++;
|
|
31
|
+
else
|
|
32
|
+
peer.push(view);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (family === 'unreadable') {
|
|
36
|
+
dropped++;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
16
39
|
const sid = item.sessionId;
|
|
17
40
|
if (typeof sid !== 'string' || sid === '') {
|
|
18
41
|
dropped++;
|
|
@@ -20,13 +43,13 @@ function readDurablePendingRows(raw) {
|
|
|
20
43
|
}
|
|
21
44
|
rows.push(item);
|
|
22
45
|
}
|
|
23
|
-
if (raw.length > 0 && rows.length === 0)
|
|
46
|
+
if (raw.length > 0 && rows.length + peer.length + skipped === 0)
|
|
24
47
|
return { kind: 'malformed' };
|
|
25
|
-
return { kind: 'present', rows, dropped };
|
|
48
|
+
return { kind: 'present', rows, peer, dropped };
|
|
26
49
|
}
|
|
27
50
|
function durableDigestOf(rows) {
|
|
28
51
|
return rows
|
|
29
|
-
.map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '']
|
|
52
|
+
.map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '', JSON.stringify(checkpointRowVerdictOf(r) ?? null)]
|
|
30
53
|
.join(''))
|
|
31
54
|
.sort()
|
|
32
55
|
.join('');
|
|
@@ -34,14 +57,20 @@ function durableDigestOf(rows) {
|
|
|
34
57
|
const LIVE_FIELD_SEP = String.fromCharCode(1);
|
|
35
58
|
const LIVE_ROW_SEP = String.fromCharCode(2);
|
|
36
59
|
const LIVE_SECTION_SEP = String.fromCharCode(3);
|
|
37
|
-
function
|
|
60
|
+
function peerDigestOf(peer) {
|
|
61
|
+
return peer
|
|
62
|
+
.map(r => JSON.stringify(r))
|
|
63
|
+
.sort()
|
|
64
|
+
.join(LIVE_ROW_SEP);
|
|
65
|
+
}
|
|
66
|
+
function digestOf(rows, live, dropped = 0, droppedDurable = 0, peer = []) {
|
|
38
67
|
const liveDigest = live === undefined
|
|
39
68
|
? 'absent'
|
|
40
69
|
: live
|
|
41
70
|
.map(r => [r.approvalId, r.toolName, String(r.expiresAtMs), r.sessionId ?? '', r.originTaskId ?? '', r.frame !== undefined ? 'f' : ''].join(LIVE_FIELD_SEP))
|
|
42
71
|
.sort()
|
|
43
72
|
.join(LIVE_ROW_SEP);
|
|
44
|
-
return `${durableDigestOf(rows)}${LIVE_SECTION_SEP}${liveDigest}${LIVE_SECTION_SEP}${dropped}${LIVE_SECTION_SEP}${droppedDurable}`;
|
|
73
|
+
return `${durableDigestOf(rows)}${LIVE_SECTION_SEP}${liveDigest}${LIVE_SECTION_SEP}${dropped}${LIVE_SECTION_SEP}${droppedDurable}${LIVE_SECTION_SEP}${peerDigestOf(peer)}`;
|
|
45
74
|
}
|
|
46
75
|
export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
47
76
|
const pollIntervalMs = opts?.pollIntervalMs ?? 5000;
|
|
@@ -158,6 +187,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
158
187
|
return;
|
|
159
188
|
const seq = ++takeSeq;
|
|
160
189
|
let rows;
|
|
190
|
+
let peer;
|
|
161
191
|
let live;
|
|
162
192
|
let dropped = 0;
|
|
163
193
|
let droppedDurable = 0;
|
|
@@ -212,6 +242,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
212
242
|
throw new TypeError('approvalsFeed: unreadable pending section');
|
|
213
243
|
}
|
|
214
244
|
rows = durableRead.rows;
|
|
245
|
+
peer = durableRead.peer;
|
|
215
246
|
droppedDurable = durableRead.dropped;
|
|
216
247
|
if (durableRead.dropped > 0)
|
|
217
248
|
hostLog('debug', `approvalsFeed: dropped ${durableRead.dropped} malformed pending row(s) — snapshot carries pendingDropped`);
|
|
@@ -220,7 +251,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
220
251
|
return;
|
|
221
252
|
let d;
|
|
222
253
|
try {
|
|
223
|
-
d = digestOf(rows, live, dropped, droppedDurable);
|
|
254
|
+
d = digestOf(rows, live, dropped, droppedDurable, peer);
|
|
224
255
|
}
|
|
225
256
|
catch (e) {
|
|
226
257
|
noteTakeMissed(via, seq);
|
|
@@ -252,6 +283,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
252
283
|
const snap = {
|
|
253
284
|
kind: 'snapshot',
|
|
254
285
|
pending: rows,
|
|
286
|
+
...(peer.length > 0 ? { peerInbound: peer } : {}),
|
|
255
287
|
...(live !== undefined ? { livePending: live } : {}),
|
|
256
288
|
...(dropped > 0 ? { livePendingDropped: dropped } : {}),
|
|
257
289
|
...(droppedDurable > 0 ? { pendingDropped: droppedDurable } : {}),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PendingCheckpoint } from '@sema-agent/sdk';
|
|
2
|
+
import type { ApprovalQueueRow } from './crashConverged.js';
|
|
2
3
|
import type { ParkRowProbe } from './parkRowBirthWait.js';
|
|
3
4
|
import { type ParkOwnershipDeps } from './parkOwnership.js';
|
|
4
5
|
export declare const ASK_PARK_ROW_WAIT_MS = 15000;
|
|
@@ -7,7 +8,7 @@ export interface AskParkRowScanDeps {
|
|
|
7
8
|
isOwned?: (row: PendingCheckpoint) => boolean;
|
|
8
9
|
ownership?: ParkOwnershipDeps;
|
|
9
10
|
}
|
|
10
|
-
export declare function classifyAskParkRows(
|
|
11
|
+
export declare function classifyAskParkRows(queueRows: readonly ApprovalQueueRow[], taskId: string, deps?: AskParkRowScanDeps): ParkRowProbe<PendingCheckpoint>;
|
|
11
12
|
export interface AskParkRowIdentity {
|
|
12
13
|
rowTaskId: string;
|
|
13
14
|
gatedCallId: string | undefined;
|
|
@@ -15,7 +16,7 @@ export interface AskParkRowIdentity {
|
|
|
15
16
|
}
|
|
16
17
|
export declare function askParkRowIdentity(taskId: string, row: PendingCheckpoint): AskParkRowIdentity;
|
|
17
18
|
export declare function askParkRowArm(row: PendingCheckpoint): 'question' | 'tool-gate';
|
|
18
|
-
export declare function askParkRowStillPending(rows: readonly
|
|
19
|
+
export declare function askParkRowStillPending(rows: readonly ApprovalQueueRow[], identity: AskParkRowIdentity): boolean;
|
|
19
20
|
export type AskParkChainFailureDisposition = 'retry' | 'row-gone-after-card' | 'row-unborn';
|
|
20
21
|
export declare function classifyAskParkChainFailure(i: {
|
|
21
22
|
rowStillPending: boolean;
|
|
@@ -29,6 +30,6 @@ export interface RowArmSingleFlight<T> {
|
|
|
29
30
|
export declare function createRowArmSingleFlight<T>(): RowArmSingleFlight<T>;
|
|
30
31
|
export declare function pendingRowIsOwnedAndDecidable(row: PendingCheckpoint, deps?: ParkOwnershipDeps): boolean;
|
|
31
32
|
export interface OwnedPendingListView {
|
|
32
|
-
readonly pending?: readonly
|
|
33
|
+
readonly pending?: readonly ApprovalQueueRow[] | null;
|
|
33
34
|
}
|
|
34
35
|
export declare function countOwnedPendingRows(listed: OwnedPendingListView | null | undefined, deps?: ParkOwnershipDeps): number;
|