@corca-org/ceal-host-linux-arm64 1.0.18 → 1.0.19
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/bin/ceal-host +0 -0
- package/libexec/ceal-host/claude-hook.mjs +1924 -522
- package/libexec/ceal-host/claude-invocation-authentication.mjs +1806 -330
- package/libexec/ceal-host/claude-producer.mjs +1773 -412
- package/libexec/ceal-host/codex-hook.mjs +1427 -1013
- package/libexec/ceal-host/codex-invocation-authentication.mjs +3071 -515
- package/libexec/ceal-host/codex-producer.mjs +815 -439
- package/libexec/ceal-host/control.mjs +2266 -1095
- package/libexec/ceal-host/relay.mjs +468 -103
- package/package.json +1 -1
- package/share/ceal-host/bundle-manifest.json +12 -12
- package/share/ceal-host/bundle-manifest.sigstore.json +1 -1
|
@@ -153,6 +153,9 @@ var client_wire_contract_default = {
|
|
|
153
153
|
"document"
|
|
154
154
|
],
|
|
155
155
|
optional_fields: [
|
|
156
|
+
"operation_id",
|
|
157
|
+
"visible_output_max_bytes",
|
|
158
|
+
"local_delivery",
|
|
156
159
|
"verified_artifact"
|
|
157
160
|
],
|
|
158
161
|
bare_document_fields: [
|
|
@@ -266,6 +269,7 @@ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verifie
|
|
|
266
269
|
var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
|
|
267
270
|
var CEAL_PROTOCOL_VERSION = "1.4.0";
|
|
268
271
|
var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
|
|
272
|
+
var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
|
|
269
273
|
var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
|
|
270
274
|
"audited_call_pending",
|
|
271
275
|
"continuation_read_pending",
|
|
@@ -289,6 +293,7 @@ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
|
|
|
289
293
|
// packages/ceal-client-protocol/src/operation-next-actions.ts
|
|
290
294
|
var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
|
|
291
295
|
var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
|
|
296
|
+
var CEAL_ANSWER_WITH_GAP_NEXT_ACTION = "answer_with_gap";
|
|
292
297
|
var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
|
|
293
298
|
"select_did_you_mean",
|
|
294
299
|
"choose_new_output_path",
|
|
@@ -342,10 +347,20 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
|
|
|
342
347
|
"retry_after",
|
|
343
348
|
// The ref names a container of rows (a Notion database or data source), which
|
|
344
349
|
// has no body of its own; the caller searches its rows instead of reading it.
|
|
345
|
-
"search_container_rows"
|
|
350
|
+
"search_container_rows",
|
|
351
|
+
// A settled unknown write names the exact receipt Operation that can inspect
|
|
352
|
+
// its outcome without issuing another provider mutation.
|
|
353
|
+
"write_receipt.get",
|
|
354
|
+
// Command resolution carries the exact required Operation sequence beside
|
|
355
|
+
// this action, so the caller can execute each declared input in order.
|
|
356
|
+
"follow_required_action_sequence",
|
|
357
|
+
// The command needs caller-owned local materialization (for example an
|
|
358
|
+
// @path file) before the Gateway can receive the argument.
|
|
359
|
+
"materialize_local_argument"
|
|
346
360
|
];
|
|
347
361
|
var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
|
|
348
362
|
var NON_REMEDY_NEXT_ACTION_VALUES = [
|
|
363
|
+
CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
349
364
|
// Only an administrator can take the named step -- approving a place for an
|
|
350
365
|
// Operation, granting a withheld capability -- so a non-administrator asks
|
|
351
366
|
// one. The refusal names the administrator step; this word is the ask.
|
|
@@ -393,7 +408,58 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
|
|
|
393
408
|
"select_exact_approval"
|
|
394
409
|
];
|
|
395
410
|
var CEAL_NON_REMEDY_NEXT_ACTIONS = Object.freeze(NON_REMEDY_NEXT_ACTION_VALUES);
|
|
396
|
-
var
|
|
411
|
+
var CEAL_DECLARED_NEXT_ACTIONS = Object.freeze([...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS, ...CEAL_NON_REMEDY_NEXT_ACTIONS]);
|
|
412
|
+
var DECLARED = new Set(CEAL_DECLARED_NEXT_ACTIONS);
|
|
413
|
+
function defineCealNonModelNextActions(actions) {
|
|
414
|
+
return actions;
|
|
415
|
+
}
|
|
416
|
+
var NON_MODEL_NEXT_ACTION_VALUES = defineCealNonModelNextActions([
|
|
417
|
+
CEAL_INSPECT_RECEIPT_NEXT_ACTION,
|
|
418
|
+
"await_pending_approval",
|
|
419
|
+
"inspect_gateway",
|
|
420
|
+
"operator_action",
|
|
421
|
+
"none",
|
|
422
|
+
"check_gateway",
|
|
423
|
+
"inspect_context_store",
|
|
424
|
+
"inspect_local_cache",
|
|
425
|
+
"inspect_local_client",
|
|
426
|
+
"inspect_local_command",
|
|
427
|
+
"inspect_local_output",
|
|
428
|
+
"inspect_local_route",
|
|
429
|
+
"inspect_request",
|
|
430
|
+
"reconcile",
|
|
431
|
+
"reconcile_occurrence",
|
|
432
|
+
"retry_after_owner_recovery",
|
|
433
|
+
"select_exact_approval"
|
|
434
|
+
]);
|
|
435
|
+
var NON_MODEL_NEXT_ACTIONS = new Set(NON_MODEL_NEXT_ACTION_VALUES);
|
|
436
|
+
function isCealModelActionableNonRemedyNextAction(action) {
|
|
437
|
+
return !NON_MODEL_NEXT_ACTIONS.has(action);
|
|
438
|
+
}
|
|
439
|
+
var CEAL_MODEL_ACTIONABLE_NEXT_ACTIONS = Object.freeze([
|
|
440
|
+
...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS,
|
|
441
|
+
...CEAL_NON_REMEDY_NEXT_ACTIONS.filter(isCealModelActionableNonRemedyNextAction)
|
|
442
|
+
]);
|
|
443
|
+
var MODEL_ACTIONABLE = new Set(CEAL_MODEL_ACTIONABLE_NEXT_ACTIONS);
|
|
444
|
+
var NON_MODEL_ACTION_TO_MODEL_ACTION = Object.freeze({
|
|
445
|
+
[CEAL_INSPECT_RECEIPT_NEXT_ACTION]: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
446
|
+
await_pending_approval: "ask_admin",
|
|
447
|
+
inspect_gateway: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
448
|
+
operator_action: "ask_admin",
|
|
449
|
+
none: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
450
|
+
check_gateway: "ask_admin",
|
|
451
|
+
inspect_context_store: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
452
|
+
inspect_local_cache: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
453
|
+
inspect_local_client: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
454
|
+
inspect_local_command: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
455
|
+
inspect_local_output: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
456
|
+
inspect_local_route: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
457
|
+
inspect_request: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
458
|
+
reconcile: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
|
|
459
|
+
reconcile_occurrence: "ask_admin",
|
|
460
|
+
retry_after_owner_recovery: "ask_admin",
|
|
461
|
+
select_exact_approval: "ask_admin"
|
|
462
|
+
});
|
|
397
463
|
var RETRY_PROMISE_NEXT_ACTIONS = ["retry", "retry_after"];
|
|
398
464
|
var RETRY_PROMISE = new Set(RETRY_PROMISE_NEXT_ACTIONS);
|
|
399
465
|
var RECOVERABLE = new Set(CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS);
|
|
@@ -663,21 +729,15 @@ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
|
|
|
663
729
|
// packages/ceal-client-protocol/src/domain-vocabulary.ts
|
|
664
730
|
var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
|
|
665
731
|
var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
|
|
666
|
-
var CEAL_PROVIDER_BOUNDARY_KINDS = vocabulary([
|
|
667
|
-
"github_account",
|
|
668
|
-
"github_organization",
|
|
669
|
-
"google_workspace_domain",
|
|
670
|
-
"notion_workspace",
|
|
671
|
-
"slack_workspace"
|
|
672
|
-
]);
|
|
673
|
-
var CEAL_PROVIDER_BOUNDARY_EVIDENCE = vocabulary(["provider_readback", "operator_stated"]);
|
|
674
732
|
var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
|
|
675
733
|
var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
|
|
676
734
|
var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
|
|
677
735
|
var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
|
|
678
736
|
var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
|
|
679
|
-
var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "
|
|
737
|
+
var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
|
|
738
|
+
var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
|
|
680
739
|
var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
|
|
740
|
+
var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
|
|
681
741
|
var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
|
|
682
742
|
|
|
683
743
|
// packages/ceal-client-protocol/src/safe-json-budget.ts
|
|
@@ -853,7 +913,7 @@ var CEAL_SCHEMA_LITERALS = [
|
|
|
853
913
|
"ceal.operation_receipt.v1",
|
|
854
914
|
"ceal.operation_result.v1",
|
|
855
915
|
"ceal.operation_result.compact.v1",
|
|
856
|
-
"ceal.
|
|
916
|
+
"ceal.local_result_file.v1",
|
|
857
917
|
"ceal.local_result_root.v1",
|
|
858
918
|
"ceal.owner_bootstrap_exchange_request.v1",
|
|
859
919
|
"ceal.owner_bootstrap_exchange_result.v1",
|
|
@@ -947,41 +1007,6 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
|
|
|
947
1007
|
}
|
|
948
1008
|
});
|
|
949
1009
|
|
|
950
|
-
// packages/ceal-client-protocol/src/provider-operation-vocabulary.ts
|
|
951
|
-
var CEAL_FILE_TYPE_FAMILIES = vocabulary(["all", "image", "pdf"]);
|
|
952
|
-
var CEAL_GITHUB_ISSUE_STATES = vocabulary(["open", "closed", "all"]);
|
|
953
|
-
var CEAL_NOTION_UPDATABLE_BLOCK_TYPES = vocabulary([
|
|
954
|
-
"paragraph",
|
|
955
|
-
"heading_1",
|
|
956
|
-
"heading_2",
|
|
957
|
-
"heading_3",
|
|
958
|
-
"bulleted_list_item",
|
|
959
|
-
"numbered_list_item",
|
|
960
|
-
"to_do",
|
|
961
|
-
"code"
|
|
962
|
-
]);
|
|
963
|
-
var CEAL_NOTION_NEUTRAL_TYPES = vocabulary([
|
|
964
|
-
"text",
|
|
965
|
-
"number",
|
|
966
|
-
"boolean",
|
|
967
|
-
"date",
|
|
968
|
-
"select",
|
|
969
|
-
"multi_select",
|
|
970
|
-
"people",
|
|
971
|
-
"url",
|
|
972
|
-
"email",
|
|
973
|
-
"phone",
|
|
974
|
-
"unsupported"
|
|
975
|
-
]);
|
|
976
|
-
var CEAL_NOTION_IDENTITY_GAP_REASONS = vocabulary([
|
|
977
|
-
"identity_unavailable",
|
|
978
|
-
"identity_stale",
|
|
979
|
-
"identity_ambiguous",
|
|
980
|
-
"identity_revoked",
|
|
981
|
-
"identity_unlinked"
|
|
982
|
-
]);
|
|
983
|
-
var CEAL_NOTION_STRING_VALUE_TYPES = vocabulary(["text", "select", "url", "email", "phone"]);
|
|
984
|
-
|
|
985
1010
|
// packages/ceal-client-protocol/src/opaque-reference.ts
|
|
986
1011
|
var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "block", "object"]);
|
|
987
1012
|
var CEAL_OPAQUE_REF_KINDS = vocabulary([...CEAL_OPAQUE_HANDLE_KINDS, "result", "operation-receipt", "reply-receipt", "field", "notion-data-source"]);
|
|
@@ -1014,6 +1039,7 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
|
|
|
1014
1039
|
"resource_modified"
|
|
1015
1040
|
]);
|
|
1016
1041
|
var CEAL_ACTIVITY_CONNECTOR_KINDS = vocabulary(["slack", "github", "google-calendar", "google-drive", "notion"]);
|
|
1042
|
+
var CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE = "unsupported_event_kind";
|
|
1017
1043
|
var CEAL_ACTIVITY_GAP_CODES = vocabulary([
|
|
1018
1044
|
"provider_page_budget",
|
|
1019
1045
|
"call_deadline",
|
|
@@ -1021,7 +1047,7 @@ var CEAL_ACTIVITY_GAP_CODES = vocabulary([
|
|
|
1021
1047
|
"provider_cursor_unavailable",
|
|
1022
1048
|
"malformed_provider_page",
|
|
1023
1049
|
"visibility_incomplete",
|
|
1024
|
-
|
|
1050
|
+
CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE,
|
|
1025
1051
|
"direct_messages_excluded"
|
|
1026
1052
|
]);
|
|
1027
1053
|
var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
|
|
@@ -1086,6 +1112,8 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
|
|
|
1086
1112
|
modified_at: { required: false, timestamp: true },
|
|
1087
1113
|
modified_at_local: { required: false, timestamp: true },
|
|
1088
1114
|
viewed_by_me_at: { required: false, timestamp: true },
|
|
1115
|
+
own_ceal_write: { required: false, timestamp: false },
|
|
1116
|
+
owned_by_me: { required: false, timestamp: false },
|
|
1089
1117
|
visibility: { required: false, timestamp: false },
|
|
1090
1118
|
start: { required: false, timestamp: false },
|
|
1091
1119
|
end: { required: false, timestamp: false },
|
|
@@ -1119,6 +1147,15 @@ function cealExcludedTargetCoverageJsonSchema() {
|
|
|
1119
1147
|
};
|
|
1120
1148
|
}
|
|
1121
1149
|
|
|
1150
|
+
// packages/ceal-client-protocol/src/gateway-write-identity.ts
|
|
1151
|
+
var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
|
|
1152
|
+
var CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN = /^gateway-write-request:[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/u;
|
|
1153
|
+
var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
|
|
1154
|
+
replay_identity: "idempotency_claim_sha256",
|
|
1155
|
+
lookup_handle: "write_request_sha256",
|
|
1156
|
+
collision_evidence: "normalized_mutation_sha256"
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1122
1159
|
// packages/ceal-client-protocol/src/write-safety-finding.ts
|
|
1123
1160
|
var CEAL_WRITE_SAFETY_FINDING_STATUSES = vocabulary(["warning", "unchecked"]);
|
|
1124
1161
|
var CEAL_WRITE_SAFETY_AUDIENCES = vocabulary(["workspace", "person", "members", "unknown"]);
|
|
@@ -1146,7 +1183,11 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
|
|
|
1146
1183
|
"refresh_revoked",
|
|
1147
1184
|
"authority_replaced",
|
|
1148
1185
|
"refresh_recovery_unavailable",
|
|
1149
|
-
"refresh_recovery_expired"
|
|
1186
|
+
"refresh_recovery_expired",
|
|
1187
|
+
// The serving gate answers this while the Gateway is still starting and the
|
|
1188
|
+
// refresh was never attempted; the same attempt stays retryable. It is never
|
|
1189
|
+
// stored by the session owner, only answered at the serving edge.
|
|
1190
|
+
"gateway_starting"
|
|
1150
1191
|
]);
|
|
1151
1192
|
|
|
1152
1193
|
// packages/ceal-client-protocol/src/request-validation-primitives.ts
|
|
@@ -1179,7 +1220,7 @@ var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
|
|
|
1179
1220
|
var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority", "prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
|
|
1180
1221
|
var CEAL_REQUEST_JSON_SCHEMA = {
|
|
1181
1222
|
type: "object",
|
|
1182
|
-
maxProperties:
|
|
1223
|
+
maxProperties: 11,
|
|
1183
1224
|
additionalProperties: false,
|
|
1184
1225
|
properties: {
|
|
1185
1226
|
schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
|
|
@@ -1203,7 +1244,8 @@ var CEAL_REQUEST_JSON_SCHEMA = {
|
|
|
1203
1244
|
host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1204
1245
|
host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1205
1246
|
host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
1206
|
-
requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." }
|
|
1247
|
+
requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
|
|
1248
|
+
device_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source, description: "Device that submitted this Request through its client session; absent for Host turns and older records." }
|
|
1207
1249
|
},
|
|
1208
1250
|
required: CEAL_REQUEST_KEYS
|
|
1209
1251
|
};
|
|
@@ -1262,6 +1304,7 @@ var REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES = {
|
|
|
1262
1304
|
retryable: { type: "boolean" },
|
|
1263
1305
|
source: { type: "string", enum: ["provider", "gateway"] },
|
|
1264
1306
|
retry_after_ms: { type: "integer", minimum: 0, maximum: CEAL_RETRY_AFTER_MAX_MS },
|
|
1307
|
+
write_request_ref: { type: "string", pattern: CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN.source, maxLength: 128 },
|
|
1265
1308
|
excluded_targets: cealExcludedTargetCoverageJsonSchema(),
|
|
1266
1309
|
repaired_input: {},
|
|
1267
1310
|
unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
|
|
@@ -1326,6 +1369,43 @@ function cealHostObservationRef(producer, digest2) {
|
|
|
1326
1369
|
if (!HOST_OBSERVATION_PRODUCER.test(producer) || !HOST_OBSERVATION_DIGEST.test(digest2)) invalid("Ceal Host observation reference parts are invalid.");
|
|
1327
1370
|
return `${CEAL_HOST_OBSERVATION_REF_PREFIX}${producer}-${digest2}`;
|
|
1328
1371
|
}
|
|
1372
|
+
var HOST_TOKEN_OBSERVATION_BREAKDOWN_KEYS = vocabulary(["cached_input", "cache_write_input", "reasoning_output"]);
|
|
1373
|
+
function createHostTokenObservationValue(counts, source) {
|
|
1374
|
+
const core = validTokenCore(counts);
|
|
1375
|
+
if (typeof source !== "string" || source.length === 0 || source.length > 256) invalid("Ceal Host token observation source is invalid.");
|
|
1376
|
+
const value = { status: "available", unit: "tokens", input: core.input, output: core.output, total: core.total, source };
|
|
1377
|
+
for (const breakdown of validTokenBreakdowns(counts)) value[breakdown.key] = breakdown.tokens;
|
|
1378
|
+
assertHostObservationValue(value, "token");
|
|
1379
|
+
return value;
|
|
1380
|
+
}
|
|
1381
|
+
function validTokenCore(counts) {
|
|
1382
|
+
if (!isOperationRecord(counts) || !safeCount(counts.input) || !safeCount(counts.output) || !safeCount(counts.total)) invalid("Ceal Host token observation counts are invalid.");
|
|
1383
|
+
if (counts.total !== counts.input + counts.output) invalid("Ceal Host token observation counts are invalid.");
|
|
1384
|
+
return { input: counts.input, output: counts.output, total: counts.total };
|
|
1385
|
+
}
|
|
1386
|
+
function validTokenBreakdowns(counts) {
|
|
1387
|
+
const breakdowns = [
|
|
1388
|
+
{ key: "cached_input", tokens: counts.cached_input },
|
|
1389
|
+
{ key: "cache_write_input", tokens: counts.cache_write_input },
|
|
1390
|
+
{ key: "reasoning_output", tokens: counts.reasoning_output }
|
|
1391
|
+
];
|
|
1392
|
+
const stated = breakdowns.filter((breakdown) => breakdown.tokens !== void 0).map((breakdown) => ({ key: breakdown.key, tokens: Number(breakdown.tokens) }));
|
|
1393
|
+
for (const breakdown of stated) {
|
|
1394
|
+
if (!safeCount(breakdown.tokens)) invalid("Ceal Host token observation counts are invalid.");
|
|
1395
|
+
}
|
|
1396
|
+
const cached = counts.cached_input ?? 0;
|
|
1397
|
+
const created = counts.cache_write_input ?? 0;
|
|
1398
|
+
const reasoning = counts.reasoning_output ?? 0;
|
|
1399
|
+
if (cached + created > counts.input || reasoning > counts.output) invalid("Ceal Host token observation counts are invalid.");
|
|
1400
|
+
return stated;
|
|
1401
|
+
}
|
|
1402
|
+
function hostObservationNotRecorded(reason) {
|
|
1403
|
+
if (typeof reason !== "string" || reason.length === 0 || reason.length > 256) invalid("Ceal Host observation gap reason is invalid.");
|
|
1404
|
+
return { status: "not_recorded", reason };
|
|
1405
|
+
}
|
|
1406
|
+
function safeCount(value) {
|
|
1407
|
+
return Number.isSafeInteger(value) && Number(value) >= 0;
|
|
1408
|
+
}
|
|
1329
1409
|
function validateCealHostObservationDraft(value) {
|
|
1330
1410
|
const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
|
|
1331
1411
|
requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
|
|
@@ -1477,12 +1557,83 @@ var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
|
|
|
1477
1557
|
"host_input_mismatch",
|
|
1478
1558
|
"host_prompt_mismatch"
|
|
1479
1559
|
]);
|
|
1560
|
+
var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
|
|
1561
|
+
"invalid_arguments",
|
|
1562
|
+
"options_invalid",
|
|
1563
|
+
"session_unavailable",
|
|
1564
|
+
"context_unavailable",
|
|
1565
|
+
"context_replaced",
|
|
1566
|
+
"no_binding",
|
|
1567
|
+
"context_stale",
|
|
1568
|
+
"context_expired",
|
|
1569
|
+
"host_source_refused",
|
|
1570
|
+
"host_credential_refused",
|
|
1571
|
+
"gateway_unavailable",
|
|
1572
|
+
"gateway_rate_limited",
|
|
1573
|
+
"gateway_refused",
|
|
1574
|
+
"gateway_response_invalid",
|
|
1575
|
+
"producer_frame_invalid",
|
|
1576
|
+
"relay_permission_denied",
|
|
1577
|
+
"relay_unavailable",
|
|
1578
|
+
"transient_retryable",
|
|
1579
|
+
"mint_failed",
|
|
1580
|
+
"relay_failed",
|
|
1581
|
+
"host_refusal_invalid"
|
|
1582
|
+
]);
|
|
1583
|
+
var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
|
|
1584
|
+
invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
|
|
1585
|
+
options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
|
|
1586
|
+
session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
|
|
1587
|
+
context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "refresh_host_invocation_context", remedy: "the Host has no invocation context from the current transcript turn; run `ceal-host install` to repair the Host hook registration, then retry this command on a fresh Host turn" }),
|
|
1588
|
+
context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
|
|
1589
|
+
no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
|
|
1590
|
+
context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
|
|
1591
|
+
context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
|
|
1592
|
+
host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
|
|
1593
|
+
host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
|
|
1594
|
+
gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
|
|
1595
|
+
gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
|
|
1596
|
+
gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
|
|
1597
|
+
gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
|
|
1598
|
+
producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin", remedy: "ask an administrator to inspect and repair the producer frame, then start a fresh Host turn" }),
|
|
1599
|
+
relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox", remedy: "an agent sandbox denied the Host Relay socket; run `ceal` as the only command, with no pipe, redirect, or `&&`, so the Host allow rule runs it outside the sandbox" }),
|
|
1600
|
+
relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
|
|
1601
|
+
transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
|
|
1602
|
+
mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
|
|
1603
|
+
relay_failed: Object.freeze({ classification: "host_relay_failed", next_action: "answer_with_gap" }),
|
|
1604
|
+
host_refusal_invalid: Object.freeze({ classification: "host_refusal_invalid", next_action: "answer_with_gap" })
|
|
1605
|
+
});
|
|
1606
|
+
|
|
1607
|
+
// packages/ceal-client-protocol/src/host-service-diagnostic.ts
|
|
1608
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_PRODUCERS = vocabulary(["claude", "codex"]);
|
|
1609
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
|
|
1610
|
+
"hook_invoked",
|
|
1611
|
+
"registration_written",
|
|
1612
|
+
"hook_failed",
|
|
1613
|
+
"watcher_turn_observed",
|
|
1614
|
+
"current_prompt_registered",
|
|
1615
|
+
"current_prompt_registration_failed",
|
|
1616
|
+
"activation_recorded",
|
|
1617
|
+
"activation_failed",
|
|
1618
|
+
"watcher_scan_failed",
|
|
1619
|
+
"activation_wait_skipped",
|
|
1620
|
+
"activation_wait_engaged",
|
|
1621
|
+
"activation_wait_completed",
|
|
1622
|
+
"activation_wait_exhausted"
|
|
1623
|
+
]);
|
|
1624
|
+
var CEAL_HOST_SERVICE_DIAGNOSTIC_FAILURE_KINDS = vocabulary([
|
|
1625
|
+
"malformed_line",
|
|
1626
|
+
"other",
|
|
1627
|
+
"payload_rejected",
|
|
1628
|
+
"read_error",
|
|
1629
|
+
"size_budget",
|
|
1630
|
+
"symlink"
|
|
1631
|
+
]);
|
|
1480
1632
|
|
|
1481
1633
|
// packages/ceal-client-protocol/src/client-result-materialization.ts
|
|
1482
1634
|
var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "unsupported", "download_failed", "permission_denied"]);
|
|
1483
|
-
var
|
|
1484
|
-
var
|
|
1485
|
-
var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "local_result_root", "continue_argv", "model_disclosure"]);
|
|
1635
|
+
var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
|
|
1636
|
+
var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "items_path", "row_count", "result_complete", "coverage", "local_result_root", "model_disclosure", "continue_argv", "how_to_read"]);
|
|
1486
1637
|
|
|
1487
1638
|
// packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
|
|
1488
1639
|
var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -1512,14 +1663,6 @@ var CEAL_GATEWAY_ANNOUNCEMENT_POLICY_NON_CLAIMS = vocabulary([
|
|
|
1512
1663
|
"target_specific_scope_not_declared"
|
|
1513
1664
|
]);
|
|
1514
1665
|
|
|
1515
|
-
// packages/ceal-client-protocol/src/gateway-write-identity.ts
|
|
1516
|
-
var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
|
|
1517
|
-
var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
|
|
1518
|
-
replay_identity: "idempotency_claim_sha256",
|
|
1519
|
-
lookup_handle: "write_request_sha256",
|
|
1520
|
-
collision_evidence: "normalized_mutation_sha256"
|
|
1521
|
-
});
|
|
1522
|
-
|
|
1523
1666
|
// packages/ceal-client-protocol/src/gateway-scoped-identity-projection-validation.ts
|
|
1524
1667
|
var PROJECTION_REVISION_KEYS = Object.freeze(["graph_revision", "subject_key_revision", "projection_revision"]);
|
|
1525
1668
|
|
|
@@ -1532,6 +1675,18 @@ var CEAL_SUPPORTED_GATEWAY_PROTOCOL_RANGE = Object.freeze({
|
|
|
1532
1675
|
// packages/ceal-client-protocol/src/admin-projection-vocabulary.ts
|
|
1533
1676
|
var ADMIN_PROJECTION_STATES = vocabulary(["ready", "empty", "partial", "unknown"]);
|
|
1534
1677
|
var ADMIN_VIEW_KINDS = vocabulary(["request_detail", "resource_access_timeline", "weekly_usage"]);
|
|
1678
|
+
var ADMIN_RECORD_PROJECTION_KINDS = vocabulary([
|
|
1679
|
+
"request_list",
|
|
1680
|
+
"usage_series",
|
|
1681
|
+
"connector_health",
|
|
1682
|
+
"person_connections",
|
|
1683
|
+
"client_sessions",
|
|
1684
|
+
"knowledge_base",
|
|
1685
|
+
"change_history",
|
|
1686
|
+
"approval_queue",
|
|
1687
|
+
"access_group_list",
|
|
1688
|
+
"capability_catalogue"
|
|
1689
|
+
]);
|
|
1535
1690
|
var ADMIN_GAP_KINDS = vocabulary(["unknown", "unavailable", "partial"]);
|
|
1536
1691
|
var ADMIN_UNAVAILABLE_REASONS = vocabulary([
|
|
1537
1692
|
"not_recorded",
|
|
@@ -1555,7 +1710,11 @@ var ADMIN_SOURCE_OWNERS = vocabulary([
|
|
|
1555
1710
|
"person",
|
|
1556
1711
|
"resource",
|
|
1557
1712
|
"prompt",
|
|
1558
|
-
"usage"
|
|
1713
|
+
"usage",
|
|
1714
|
+
"connector",
|
|
1715
|
+
"session",
|
|
1716
|
+
"knowledge",
|
|
1717
|
+
"policy"
|
|
1559
1718
|
]);
|
|
1560
1719
|
var ADMIN_COMPLETENESS_STATES = vocabulary(["complete", "partial", "unknown"]);
|
|
1561
1720
|
var ADMIN_OPERATION_OUTCOMES = vocabulary(["completed", "failed", "denied", "cancelled", "unknown"]);
|
|
@@ -1790,6 +1949,15 @@ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
|
|
|
1790
1949
|
function isHostProducerFrameKind(value) {
|
|
1791
1950
|
return typeof value === "string" && FRAME_KINDS.has(value);
|
|
1792
1951
|
}
|
|
1952
|
+
var HOST_PRODUCER_FRAME_ERROR_CODES = [
|
|
1953
|
+
"invalid_frame_encoding",
|
|
1954
|
+
"invalid_frame_length",
|
|
1955
|
+
"frame_truncated",
|
|
1956
|
+
"unsupported_frame_schema",
|
|
1957
|
+
"invalid_frame_shape",
|
|
1958
|
+
"invalid_producer_identity",
|
|
1959
|
+
"frame_too_large"
|
|
1960
|
+
];
|
|
1793
1961
|
var HostProducerFrameError = class extends Error {
|
|
1794
1962
|
code;
|
|
1795
1963
|
constructor(code, message = code) {
|
|
@@ -1824,6 +1992,9 @@ function decodeHostProducerFrame(input) {
|
|
|
1824
1992
|
validateFrame(value);
|
|
1825
1993
|
return value;
|
|
1826
1994
|
}
|
|
1995
|
+
function isHostSafeRef(value) {
|
|
1996
|
+
return safeRef(value);
|
|
1997
|
+
}
|
|
1827
1998
|
function validateFrame(value) {
|
|
1828
1999
|
if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
1829
2000
|
if (value.schema_version !== HOST_PRODUCER_FRAME_SCHEMA) throw new HostProducerFrameError("unsupported_frame_schema", `unsupported_frame_schema: ${refusalFact("schema_version", value.schema_version, HOST_PRODUCER_FRAME_SCHEMA)}`);
|
|
@@ -1911,6 +2082,15 @@ function exactOptional(value, required, optional) {
|
|
|
1911
2082
|
return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
1912
2083
|
}
|
|
1913
2084
|
|
|
2085
|
+
// host/relay/src/host-producer-core.ts
|
|
2086
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
2087
|
+
import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
|
|
2088
|
+
import { mkdir as mkdir2, open as open3, readFile, rename as rename2, writeFile } from "node:fs/promises";
|
|
2089
|
+
import { join as join2 } from "node:path";
|
|
2090
|
+
|
|
2091
|
+
// host/relay/src/relay-ipc.ts
|
|
2092
|
+
import { createConnection, createServer } from "node:net";
|
|
2093
|
+
|
|
1914
2094
|
// host/relay/src/durable-atomic-replacement.ts
|
|
1915
2095
|
import { O_RDONLY } from "node:constants";
|
|
1916
2096
|
import { lstat as lstat2, mkdir, open as open2, rename, unlink } from "node:fs/promises";
|
|
@@ -1928,17 +2108,6 @@ var DEFAULT_PORT = {
|
|
|
1928
2108
|
// host/relay/src/relay-request-binding-store.ts
|
|
1929
2109
|
var MAX_STATE_BYTES = 8 * 1024 * 1024;
|
|
1930
2110
|
|
|
1931
|
-
// host/relay/src/relay-quarantine-store.ts
|
|
1932
|
-
var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
|
|
1933
|
-
|
|
1934
|
-
// host/relay/src/relay-admission-store.ts
|
|
1935
|
-
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
1936
|
-
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
1937
|
-
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
1938
|
-
|
|
1939
|
-
// host/relay/src/relay-ipc.ts
|
|
1940
|
-
import { createConnection, createServer } from "node:net";
|
|
1941
|
-
|
|
1942
2111
|
// host/relay/src/current-prompt-custody.ts
|
|
1943
2112
|
var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
|
|
1944
2113
|
|
|
@@ -1971,6 +2140,8 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
|
|
|
1971
2140
|
"gateway_unavailable",
|
|
1972
2141
|
"gateway_refused",
|
|
1973
2142
|
"gateway_response_invalid",
|
|
2143
|
+
"gateway_rate_limited",
|
|
2144
|
+
"producer_frame_invalid",
|
|
1974
2145
|
"deadline",
|
|
1975
2146
|
"cancelled",
|
|
1976
2147
|
"mint_failed",
|
|
@@ -1984,6 +2155,17 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
|
|
|
1984
2155
|
"host_input_mismatch",
|
|
1985
2156
|
"host_prompt_mismatch"
|
|
1986
2157
|
]);
|
|
2158
|
+
var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
|
|
2159
|
+
"context_stale",
|
|
2160
|
+
"context_expired",
|
|
2161
|
+
"host_source_refused",
|
|
2162
|
+
"host_credential_refused",
|
|
2163
|
+
"gateway_unavailable",
|
|
2164
|
+
"gateway_rate_limited",
|
|
2165
|
+
"gateway_refused",
|
|
2166
|
+
"gateway_response_invalid",
|
|
2167
|
+
"producer_frame_invalid"
|
|
2168
|
+
]);
|
|
1987
2169
|
var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
|
|
1988
2170
|
var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
|
|
1989
2171
|
"permission_denied",
|
|
@@ -2005,6 +2187,9 @@ var HostRelayIpcError = class extends Error {
|
|
|
2005
2187
|
this.failure = failure;
|
|
2006
2188
|
}
|
|
2007
2189
|
};
|
|
2190
|
+
function hostRelayExchangeFailure(error) {
|
|
2191
|
+
return error instanceof HostRelayIpcError ? error.failure : void 0;
|
|
2192
|
+
}
|
|
2008
2193
|
function socketErrorFailure(error) {
|
|
2009
2194
|
switch (errorCode(error)) {
|
|
2010
2195
|
case "EACCES":
|
|
@@ -2147,22 +2332,348 @@ function encodeLengthPrefixed(value) {
|
|
|
2147
2332
|
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2148
2333
|
return output;
|
|
2149
2334
|
}
|
|
2150
|
-
function exactKeys2(value,
|
|
2151
|
-
|
|
2335
|
+
function exactKeys2(value, required, optional = []) {
|
|
2336
|
+
const keys = Object.keys(value);
|
|
2337
|
+
return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
2152
2338
|
}
|
|
2153
2339
|
function errorCode(error) {
|
|
2154
2340
|
return record2(error) && typeof error.code === "string" ? error.code : null;
|
|
2155
2341
|
}
|
|
2156
2342
|
|
|
2343
|
+
// host/relay/src/host-producer-core.ts
|
|
2344
|
+
var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
|
|
2345
|
+
function isHostTranscriptCursorReason(value) {
|
|
2346
|
+
return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
|
|
2347
|
+
}
|
|
2348
|
+
var TRANSCRIPT_MISSING_REASON = "transcript_missing";
|
|
2349
|
+
var HOST_TRANSCRIPT_READ_CHUNK_BYTES = 256 * 1024;
|
|
2350
|
+
async function readTranscriptCompleteChunk(handle, offset, size) {
|
|
2351
|
+
const available = Math.max(0, size - offset);
|
|
2352
|
+
if (available === 0) return "empty";
|
|
2353
|
+
const chunks = [];
|
|
2354
|
+
let position = offset;
|
|
2355
|
+
let total = 0;
|
|
2356
|
+
let lastNewline = -1;
|
|
2357
|
+
while (position < size) {
|
|
2358
|
+
const buffer = Buffer.alloc(Math.min(HOST_TRANSCRIPT_READ_CHUNK_BYTES, size - position));
|
|
2359
|
+
const read = await handle.read(buffer, 0, buffer.length, position);
|
|
2360
|
+
if (read.bytesRead === 0) break;
|
|
2361
|
+
const chunk = buffer.subarray(0, read.bytesRead);
|
|
2362
|
+
chunks.push(chunk);
|
|
2363
|
+
const newline = chunk.lastIndexOf(10);
|
|
2364
|
+
if (newline >= 0) lastNewline = total + newline;
|
|
2365
|
+
total += chunk.length;
|
|
2366
|
+
position += chunk.length;
|
|
2367
|
+
if (lastNewline >= 0) break;
|
|
2368
|
+
}
|
|
2369
|
+
if (lastNewline < 0) return "partial";
|
|
2370
|
+
return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
|
|
2371
|
+
}
|
|
2372
|
+
async function readTranscriptAnchor(handle, offset, anchorBytes) {
|
|
2373
|
+
const start = Math.max(0, offset - anchorBytes);
|
|
2374
|
+
const anchor = Buffer.alloc(offset - start);
|
|
2375
|
+
if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, start);
|
|
2376
|
+
return { start, sha256: transcriptSha256(anchor) };
|
|
2377
|
+
}
|
|
2378
|
+
async function transcriptAnchorMatches(handle, cursor) {
|
|
2379
|
+
const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
|
|
2380
|
+
if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
|
|
2381
|
+
return transcriptSha256(buffer) === cursor.anchor_sha256;
|
|
2382
|
+
}
|
|
2383
|
+
function transcriptCursorIdentityReason(cursor, transcriptPath, device, inode) {
|
|
2384
|
+
if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== transcriptPath) return "transcript_replaced";
|
|
2385
|
+
return null;
|
|
2386
|
+
}
|
|
2387
|
+
async function transcriptCursorBoundsReason(handle, cursor, size) {
|
|
2388
|
+
if (size < cursor.offset) return "transcript_truncated";
|
|
2389
|
+
if (cursor.offset > 0 && !await transcriptAnchorMatches(handle, cursor)) return "transcript_rewritten";
|
|
2390
|
+
return null;
|
|
2391
|
+
}
|
|
2392
|
+
function transcriptSha256(value) {
|
|
2393
|
+
return createHash3("sha256").update(value).digest("hex");
|
|
2394
|
+
}
|
|
2395
|
+
function transcriptObjectSha256(value) {
|
|
2396
|
+
return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
|
|
2397
|
+
}
|
|
2398
|
+
function isTranscriptRecord(value) {
|
|
2399
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2400
|
+
}
|
|
2401
|
+
function isMissingTranscriptError(error) {
|
|
2402
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
2403
|
+
}
|
|
2404
|
+
function transcriptTimestamp(now, fail) {
|
|
2405
|
+
const value = now();
|
|
2406
|
+
if (!Number.isFinite(value.getTime())) throw fail();
|
|
2407
|
+
return value.toISOString();
|
|
2408
|
+
}
|
|
2409
|
+
function transcriptExpiration(now, retentionMs, fail) {
|
|
2410
|
+
return new Date(Date.parse(transcriptTimestamp(now, fail)) + retentionMs).toISOString();
|
|
2411
|
+
}
|
|
2412
|
+
function createTranscriptWatcherBase(options, owner) {
|
|
2413
|
+
if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0) throw owner.invalid_outbox();
|
|
2414
|
+
return {
|
|
2415
|
+
outboxRetentionMs: options.retention_ms ?? owner.default_retention_ms,
|
|
2416
|
+
now: options.now ?? (() => /* @__PURE__ */ new Date()),
|
|
2417
|
+
log: options.log ?? ((line) => {
|
|
2418
|
+
process.stderr.write(`${line}
|
|
2419
|
+
`);
|
|
2420
|
+
}),
|
|
2421
|
+
producerInstallationRef: options.producer_installation_ref
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
async function scanTranscriptRegistrations(registrations, scanOne) {
|
|
2425
|
+
let records = 0;
|
|
2426
|
+
let enqueued = 0;
|
|
2427
|
+
let quarantined = 0;
|
|
2428
|
+
for (const registration of registrations) {
|
|
2429
|
+
const result = await scanOne(registration);
|
|
2430
|
+
records += result.records;
|
|
2431
|
+
enqueued += result.enqueued;
|
|
2432
|
+
if (result.quarantined) quarantined += 1;
|
|
2433
|
+
}
|
|
2434
|
+
return { registrations: registrations.length, records, enqueued, quarantined };
|
|
2435
|
+
}
|
|
2436
|
+
function formatRetiredTranscriptLog(producerLabel, transcriptPath) {
|
|
2437
|
+
return `${producerLabel} retired a transcript registration: transcript_path=${JSON.stringify(transcriptPath)}, reason=${TRANSCRIPT_MISSING_REASON}.`;
|
|
2438
|
+
}
|
|
2439
|
+
var HostTranscriptWatcher = class {
|
|
2440
|
+
outboxRetentionMs;
|
|
2441
|
+
now;
|
|
2442
|
+
log;
|
|
2443
|
+
producerInstallationRef;
|
|
2444
|
+
clockFailure;
|
|
2445
|
+
constructor(options, owner) {
|
|
2446
|
+
const base = createTranscriptWatcherBase(options, owner);
|
|
2447
|
+
this.outboxRetentionMs = base.outboxRetentionMs;
|
|
2448
|
+
this.now = base.now;
|
|
2449
|
+
this.log = base.log;
|
|
2450
|
+
this.producerInstallationRef = base.producerInstallationRef;
|
|
2451
|
+
this.clockFailure = owner.clock_failure;
|
|
2452
|
+
}
|
|
2453
|
+
async scanOnce() {
|
|
2454
|
+
return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
|
|
2455
|
+
}
|
|
2456
|
+
async scanRegistration(registration) {
|
|
2457
|
+
return this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
|
|
2458
|
+
missing: () => this.retireMissing(registration),
|
|
2459
|
+
failed: (handle, error) => this.scanFailed(handle, registration, error)
|
|
2460
|
+
});
|
|
2461
|
+
}
|
|
2462
|
+
async openTranscript(registration, scan, handlers) {
|
|
2463
|
+
let handle;
|
|
2464
|
+
try {
|
|
2465
|
+
handle = await open3(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
|
|
2466
|
+
return await scan(handle);
|
|
2467
|
+
} catch (error) {
|
|
2468
|
+
if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
|
|
2469
|
+
if (hostRelayExchangeFailure(error) !== void 0) throw error;
|
|
2470
|
+
return handlers.failed(handle, error);
|
|
2471
|
+
} finally {
|
|
2472
|
+
await handle?.close();
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* A transcript the Host deleted never comes back, so retrying its
|
|
2477
|
+
* registration once per reconcile interval is a failure with no end.
|
|
2478
|
+
* Retire it at the scan that finds it missing and say so once. Only
|
|
2479
|
+
* ENOENT means gone; a permission or busy failure is about this moment,
|
|
2480
|
+
* not about the file, and keeps the registration for the next scan.
|
|
2481
|
+
*/
|
|
2482
|
+
async retireMissingTranscript(transcriptPath, producerLabel, retire) {
|
|
2483
|
+
await retire();
|
|
2484
|
+
this.log(formatRetiredTranscriptLog(producerLabel, transcriptPath));
|
|
2485
|
+
return { records: 0, enqueued: 0, quarantined: false };
|
|
2486
|
+
}
|
|
2487
|
+
stamp() {
|
|
2488
|
+
return transcriptTimestamp(this.now, this.clockFailure);
|
|
2489
|
+
}
|
|
2490
|
+
expire(retentionMs) {
|
|
2491
|
+
return transcriptExpiration(this.now, retentionMs, this.clockFailure);
|
|
2492
|
+
}
|
|
2493
|
+
sha(value) {
|
|
2494
|
+
return transcriptSha256(value);
|
|
2495
|
+
}
|
|
2496
|
+
objectSha(value) {
|
|
2497
|
+
return transcriptObjectSha256(value);
|
|
2498
|
+
}
|
|
2499
|
+
isRecord(value) {
|
|
2500
|
+
return isTranscriptRecord(value);
|
|
2501
|
+
}
|
|
2502
|
+
readChunk(handle, offset, size) {
|
|
2503
|
+
return readTranscriptCompleteChunk(handle, offset, size);
|
|
2504
|
+
}
|
|
2505
|
+
readAnchor(handle, offset, anchorBytes) {
|
|
2506
|
+
return readTranscriptAnchor(handle, offset, anchorBytes);
|
|
2507
|
+
}
|
|
2508
|
+
cursorIdentityReason(cursor, transcriptPath, device, inode) {
|
|
2509
|
+
return transcriptCursorIdentityReason(cursor, transcriptPath, device, inode);
|
|
2510
|
+
}
|
|
2511
|
+
cursorBoundsReason(handle, cursor, size) {
|
|
2512
|
+
return transcriptCursorBoundsReason(handle, cursor, size);
|
|
2513
|
+
}
|
|
2514
|
+
};
|
|
2515
|
+
var HOST_PRODUCER_STATE_IDENTITY = {
|
|
2516
|
+
codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
|
|
2517
|
+
claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
|
|
2518
|
+
};
|
|
2519
|
+
var HostProducerDrainCore = class {
|
|
2520
|
+
host;
|
|
2521
|
+
relay;
|
|
2522
|
+
statePath;
|
|
2523
|
+
stateSchema;
|
|
2524
|
+
installationRef;
|
|
2525
|
+
epoch;
|
|
2526
|
+
now;
|
|
2527
|
+
tail = Promise.resolve();
|
|
2528
|
+
constructor(host, runtime) {
|
|
2529
|
+
if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
|
|
2530
|
+
const epoch = runtime.producer_epoch ?? 1;
|
|
2531
|
+
if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
|
|
2532
|
+
this.host = host;
|
|
2533
|
+
this.relay = runtime.relay;
|
|
2534
|
+
this.statePath = join2(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
|
|
2535
|
+
this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
|
|
2536
|
+
this.installationRef = runtime.producer_installation_ref;
|
|
2537
|
+
this.epoch = epoch;
|
|
2538
|
+
this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
|
|
2539
|
+
}
|
|
2540
|
+
drainOutbox() {
|
|
2541
|
+
const run = this.tail.then(() => this.drainLocked());
|
|
2542
|
+
this.tail = run.then(() => void 0, () => void 0);
|
|
2543
|
+
return run;
|
|
2544
|
+
}
|
|
2545
|
+
async drainLocked() {
|
|
2546
|
+
const read = await this.host.listEnvelopes();
|
|
2547
|
+
let admitted = 0;
|
|
2548
|
+
let expired = 0;
|
|
2549
|
+
let retained = 0;
|
|
2550
|
+
for (const envelope of read.entries) {
|
|
2551
|
+
const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
|
|
2552
|
+
if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
|
|
2553
|
+
await this.host.removeEnvelope(envelope);
|
|
2554
|
+
expired += 1;
|
|
2555
|
+
continue;
|
|
2556
|
+
}
|
|
2557
|
+
const frames = await this.reserve(envelope);
|
|
2558
|
+
let complete = true;
|
|
2559
|
+
for (const frame of frames) {
|
|
2560
|
+
const outcome = await this.relay.admit(frame);
|
|
2561
|
+
if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
|
|
2562
|
+
complete = false;
|
|
2563
|
+
break;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
if (!complete) {
|
|
2567
|
+
retained += 1;
|
|
2568
|
+
break;
|
|
2569
|
+
}
|
|
2570
|
+
await this.host.removeEnvelope(envelope);
|
|
2571
|
+
await this.release(this.host.submissionRefOf(envelope));
|
|
2572
|
+
admitted += 1;
|
|
2573
|
+
}
|
|
2574
|
+
return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
|
|
2575
|
+
}
|
|
2576
|
+
async hasReservation(submissionRef) {
|
|
2577
|
+
return (await this.readState()).pending[submissionRef] !== void 0;
|
|
2578
|
+
}
|
|
2579
|
+
async reserve(envelope) {
|
|
2580
|
+
const state = await this.readState();
|
|
2581
|
+
const submissionRef = this.host.submissionRefOf(envelope);
|
|
2582
|
+
const existing = state.pending[submissionRef];
|
|
2583
|
+
if (existing !== void 0) return existing;
|
|
2584
|
+
const drafts = await this.host.mapEnvelope(envelope);
|
|
2585
|
+
const frames = drafts.map((draft, offset) => ({
|
|
2586
|
+
schema_version: "ceal.host_producer_frame.v1",
|
|
2587
|
+
producer_id: this.host.producer_id,
|
|
2588
|
+
producer_installation_ref: this.installationRef,
|
|
2589
|
+
producer_epoch: this.epoch,
|
|
2590
|
+
sequence: state.next_sequence + offset,
|
|
2591
|
+
frame_kind: draft.frame_kind,
|
|
2592
|
+
occurred_at: this.host.createdAtOf(envelope),
|
|
2593
|
+
payload: draft.payload
|
|
2594
|
+
}));
|
|
2595
|
+
await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
|
|
2596
|
+
return frames;
|
|
2597
|
+
}
|
|
2598
|
+
async release(submissionRef) {
|
|
2599
|
+
const state = await this.readState();
|
|
2600
|
+
if (state.pending[submissionRef] === void 0) return;
|
|
2601
|
+
const pending = { ...state.pending };
|
|
2602
|
+
delete pending[submissionRef];
|
|
2603
|
+
await this.writeState({ ...state, pending });
|
|
2604
|
+
}
|
|
2605
|
+
async readState() {
|
|
2606
|
+
try {
|
|
2607
|
+
const value = JSON.parse(await readFile(this.statePath, "utf8"));
|
|
2608
|
+
return this.decodeState(value);
|
|
2609
|
+
} catch (error) {
|
|
2610
|
+
if (errorCode2(error) !== "ENOENT") throw error;
|
|
2611
|
+
return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
async writeState(state) {
|
|
2615
|
+
await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
|
|
2616
|
+
const temporary = `${this.statePath}.${process.pid}.new`;
|
|
2617
|
+
await writeFile(temporary, JSON.stringify(state), { mode: 384 });
|
|
2618
|
+
await rename2(temporary, this.statePath);
|
|
2619
|
+
}
|
|
2620
|
+
decodeState(value) {
|
|
2621
|
+
const label = this.host.producer_label;
|
|
2622
|
+
const fail = (code, message) => this.host.fail(code, message);
|
|
2623
|
+
if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
|
|
2624
|
+
throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
|
|
2625
|
+
{ name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
|
|
2626
|
+
{ name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
|
|
2627
|
+
])}).`);
|
|
2628
|
+
}
|
|
2629
|
+
if (Number(value.producer_epoch) > this.epoch) throw fail("storage", `${label} producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${this.epoch}`)}).`);
|
|
2630
|
+
const pending = {};
|
|
2631
|
+
const storedEpoch = Number(value.producer_epoch);
|
|
2632
|
+
for (const [submissionRef, frames] of Object.entries(value.pending)) {
|
|
2633
|
+
if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
|
|
2634
|
+
pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
|
|
2635
|
+
}
|
|
2636
|
+
return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
|
|
2637
|
+
}
|
|
2638
|
+
decodeStoredFrame(value, storedEpoch) {
|
|
2639
|
+
const label = this.host.producer_label;
|
|
2640
|
+
const json = Buffer.from(JSON.stringify(value), "utf8");
|
|
2641
|
+
const encoded = Buffer.allocUnsafe(json.length + 4);
|
|
2642
|
+
encoded.writeUInt32BE(json.length, 0);
|
|
2643
|
+
json.copy(encoded, 4);
|
|
2644
|
+
const frame = decodeHostProducerFrame(encoded);
|
|
2645
|
+
if (frame.producer_id !== this.host.producer_id || frame.producer_installation_ref !== this.installationRef || frame.producer_epoch > storedEpoch) throw this.host.fail("storage", `${label} producer pending frame identity is malformed (${refusalFacts([
|
|
2646
|
+
{ name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
|
|
2647
|
+
{ name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
|
|
2648
|
+
{ name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
|
|
2649
|
+
])}).`);
|
|
2650
|
+
return frame;
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
function isDrainStateHeader(value, schema, installationRef) {
|
|
2654
|
+
return isTranscriptRecord(value) && value.schema_version === schema && value.producer_installation_ref === installationRef && Number.isSafeInteger(value.producer_epoch) && Number(value.producer_epoch) > 0 && Number.isSafeInteger(value.next_sequence) && Number(value.next_sequence) > 0 && isTranscriptRecord(value.pending);
|
|
2655
|
+
}
|
|
2656
|
+
function errorCode2(error) {
|
|
2657
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
// host/relay/src/relay-quarantine-store.ts
|
|
2661
|
+
var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
|
|
2662
|
+
var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
|
|
2663
|
+
var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
|
|
2664
|
+
|
|
2665
|
+
// host/relay/src/relay-admission-store.ts
|
|
2666
|
+
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
2667
|
+
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
2668
|
+
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
2669
|
+
|
|
2157
2670
|
// host/codex/src/codex-producer.ts
|
|
2158
|
-
import { createHash as
|
|
2159
|
-
import { mkdir as mkdir3, readFile, rename as rename3, writeFile } from "node:fs/promises";
|
|
2160
|
-
import { join as join3 } from "node:path";
|
|
2671
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2161
2672
|
|
|
2162
2673
|
// host/codex/src/codex-outbox.ts
|
|
2163
|
-
import { O_NOFOLLOW, O_RDONLY as
|
|
2164
|
-
import { lstat as lstat3, mkdir as
|
|
2165
|
-
import { dirname, isAbsolute, join as
|
|
2674
|
+
import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
|
|
2675
|
+
import { lstat as lstat3, mkdir as mkdir3, open as open4, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
|
|
2676
|
+
import { dirname, isAbsolute, join as join3 } from "node:path";
|
|
2166
2677
|
|
|
2167
2678
|
// host/invocation-context.ts
|
|
2168
2679
|
var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
|
|
@@ -2176,17 +2687,32 @@ function hasHostInvocationIdentityKeys(value) {
|
|
|
2176
2687
|
function hasHostInvocationContextKeys(value, optional = []) {
|
|
2177
2688
|
return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
|
|
2178
2689
|
}
|
|
2690
|
+
async function readLatestSessionProjection(file, hostSourceRef, hostSessionRef, readProjection) {
|
|
2691
|
+
const context = await readProjection(file);
|
|
2692
|
+
if (context === null || context.identity.host_source_ref !== hostSourceRef || context.identity.host_session_ref !== hostSessionRef) return null;
|
|
2693
|
+
return context;
|
|
2694
|
+
}
|
|
2695
|
+
function isLiveSessionProjection(context, now) {
|
|
2696
|
+
return context !== null && Date.parse(context.expires_at) > now.getTime();
|
|
2697
|
+
}
|
|
2179
2698
|
function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor) {
|
|
2180
2699
|
const context = {
|
|
2181
2700
|
schema_version: descriptor.schema_version,
|
|
2182
2701
|
identity,
|
|
2183
2702
|
prompt_ref: promptRef,
|
|
2184
2703
|
expires_at: expiresAt,
|
|
2704
|
+
...descriptor.turn_generation_ref === void 0 ? {} : { turn_generation_ref: descriptor.turn_generation_ref },
|
|
2185
2705
|
...descriptor.working_directory === void 0 ? {} : { working_directory: descriptor.working_directory }
|
|
2186
2706
|
};
|
|
2187
2707
|
descriptor.validate(context);
|
|
2188
2708
|
return Object.freeze(context);
|
|
2189
2709
|
}
|
|
2710
|
+
function isHostInvocationTurnSelection(value) {
|
|
2711
|
+
return isRecord2(value) && Object.keys(value).length === 5 && value.schema_version === "ceal.host_invocation_turn_selection.v1" && ["host_source_ref", "host_session_ref", "prompt_ref", "turn_generation_ref"].every((key) => safeRef2(value[key]));
|
|
2712
|
+
}
|
|
2713
|
+
function invocationTurnSelectionMatches(context, selection) {
|
|
2714
|
+
return selection === null || context !== null && selection.host_source_ref === context.identity.host_source_ref && selection.host_session_ref === context.identity.host_session_ref && selection.prompt_ref === context.prompt_ref && selection.turn_generation_ref === context.turn_generation_ref;
|
|
2715
|
+
}
|
|
2190
2716
|
function exactKeys3(value, keys) {
|
|
2191
2717
|
const actual = Object.keys(value);
|
|
2192
2718
|
return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
|
|
@@ -2196,6 +2722,12 @@ function requiredKeys(value, required, optional) {
|
|
|
2196
2722
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
2197
2723
|
return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
|
|
2198
2724
|
}
|
|
2725
|
+
function isRecord2(value) {
|
|
2726
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2727
|
+
}
|
|
2728
|
+
function safeRef2(value) {
|
|
2729
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2730
|
+
}
|
|
2199
2731
|
|
|
2200
2732
|
// host/codex/src/codex-types.ts
|
|
2201
2733
|
var CODEX_OUTBOX_SCHEMA_VERSION = "ceal.codex_observation_outbox.v1";
|
|
@@ -2205,10 +2737,6 @@ var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1"
|
|
|
2205
2737
|
var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
|
|
2206
2738
|
var CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION = "ceal.codex_transcript_cursor.v1";
|
|
2207
2739
|
var CODEX_DEFAULT_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
2208
|
-
var CODEX_TRANSCRIPT_CURSOR_REASONS = ["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"];
|
|
2209
|
-
function isCodexTranscriptCursorReason(value) {
|
|
2210
|
-
return typeof value === "string" && CODEX_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
|
|
2211
|
-
}
|
|
2212
2740
|
var CodexHostAdapterError = class extends Error {
|
|
2213
2741
|
name = "CodexHostAdapterError";
|
|
2214
2742
|
code;
|
|
@@ -2219,8 +2747,8 @@ var CodexHostAdapterError = class extends Error {
|
|
|
2219
2747
|
};
|
|
2220
2748
|
|
|
2221
2749
|
// host/codex/src/codex-invocation-context.ts
|
|
2222
|
-
function codexInvocationContextFromTurn(identity, promptRef, expiresAt) {
|
|
2223
|
-
return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext });
|
|
2750
|
+
function codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef) {
|
|
2751
|
+
return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext, turn_generation_ref: turnGenerationRef });
|
|
2224
2752
|
}
|
|
2225
2753
|
function validateCodexHostInvocationContext(value) {
|
|
2226
2754
|
if (!isContextShape(value)) {
|
|
@@ -2230,28 +2758,29 @@ function validateCodexHostInvocationContext(value) {
|
|
|
2230
2758
|
validateContextReferences(value);
|
|
2231
2759
|
validateContextTimes(value);
|
|
2232
2760
|
}
|
|
2233
|
-
function invocationContextFromBinding(binding) {
|
|
2761
|
+
function invocationContextFromBinding(binding, turnGenerationRef) {
|
|
2234
2762
|
const context = {
|
|
2235
2763
|
schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
|
|
2236
2764
|
identity: binding.identity,
|
|
2237
2765
|
prompt_ref: binding.prompt_ref,
|
|
2238
2766
|
request_ref: binding.request_ref,
|
|
2239
2767
|
bound_at: binding.bound_at,
|
|
2240
|
-
expires_at: binding.expires_at
|
|
2768
|
+
expires_at: binding.expires_at,
|
|
2769
|
+
...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
|
|
2241
2770
|
};
|
|
2242
2771
|
validateCodexHostInvocationContext(context);
|
|
2243
2772
|
return Object.freeze(context);
|
|
2244
2773
|
}
|
|
2245
2774
|
function validateIdentity2(value) {
|
|
2246
|
-
if (!
|
|
2775
|
+
if (!isRecord3(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef3)) {
|
|
2247
2776
|
throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
|
|
2248
2777
|
}
|
|
2249
2778
|
}
|
|
2250
2779
|
function isContextShape(value) {
|
|
2251
|
-
return
|
|
2780
|
+
return isRecord3(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
|
|
2252
2781
|
}
|
|
2253
2782
|
function validateContextReferences(value) {
|
|
2254
|
-
if (!
|
|
2783
|
+
if (!safeRef3(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
|
|
2255
2784
|
}
|
|
2256
2785
|
function validateContextTimes(value) {
|
|
2257
2786
|
const expiresAt = value.expires_at;
|
|
@@ -2260,18 +2789,18 @@ function validateContextTimes(value) {
|
|
|
2260
2789
|
if (typeof boundAt === "string" && Date.parse(boundAt) > Date.parse(expiresAt)) throw new CodexHostAdapterError("storage", `Codex Host invocation context has invalid binding time (${refusalFact("bound_at", boundAt, `at or before ${expiresAt}`)}).`);
|
|
2261
2790
|
}
|
|
2262
2791
|
function optionalSafeRef(value) {
|
|
2263
|
-
return value === void 0 ||
|
|
2792
|
+
return value === void 0 || safeRef3(value);
|
|
2264
2793
|
}
|
|
2265
2794
|
function optionalTimestamp(value) {
|
|
2266
2795
|
return value === void 0 || timestamp2(value);
|
|
2267
2796
|
}
|
|
2268
|
-
function
|
|
2797
|
+
function safeRef3(value) {
|
|
2269
2798
|
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2270
2799
|
}
|
|
2271
2800
|
function timestamp2(value) {
|
|
2272
2801
|
return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
|
|
2273
2802
|
}
|
|
2274
|
-
function
|
|
2803
|
+
function isRecord3(value) {
|
|
2275
2804
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2276
2805
|
}
|
|
2277
2806
|
|
|
@@ -2284,20 +2813,22 @@ var CodexOutboxStore = class {
|
|
|
2284
2813
|
bindingsDirectory;
|
|
2285
2814
|
sessionsDirectory;
|
|
2286
2815
|
activeContextsDirectory;
|
|
2816
|
+
turnSelectionsDirectory;
|
|
2287
2817
|
registrationsDirectory;
|
|
2288
2818
|
cursorsDirectory;
|
|
2289
2819
|
constructor(directory) {
|
|
2290
2820
|
if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
|
|
2291
2821
|
this.directory = directory;
|
|
2292
|
-
this.entriesDirectory =
|
|
2293
|
-
this.bindingsDirectory =
|
|
2294
|
-
this.sessionsDirectory =
|
|
2295
|
-
this.activeContextsDirectory =
|
|
2296
|
-
this.
|
|
2297
|
-
this.
|
|
2822
|
+
this.entriesDirectory = join3(directory, "entries");
|
|
2823
|
+
this.bindingsDirectory = join3(directory, "bindings");
|
|
2824
|
+
this.sessionsDirectory = join3(directory, "sessions");
|
|
2825
|
+
this.activeContextsDirectory = join3(directory, "active-contexts");
|
|
2826
|
+
this.turnSelectionsDirectory = join3(directory, "turn-selections");
|
|
2827
|
+
this.registrationsDirectory = join3(directory, "transcript-registrations");
|
|
2828
|
+
this.cursorsDirectory = join3(directory, "transcript-cursors");
|
|
2298
2829
|
}
|
|
2299
2830
|
async prepare() {
|
|
2300
|
-
for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
|
|
2831
|
+
for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
|
|
2301
2832
|
await ensurePrivateOwnerDirectory(path);
|
|
2302
2833
|
}
|
|
2303
2834
|
}
|
|
@@ -2313,7 +2844,7 @@ var CodexOutboxStore = class {
|
|
|
2313
2844
|
for (const name of await readdir(this.entriesDirectory)) {
|
|
2314
2845
|
if (!name.endsWith(".json")) continue;
|
|
2315
2846
|
try {
|
|
2316
|
-
const value = JSON.parse(await readPrivateFile(
|
|
2847
|
+
const value = JSON.parse(await readPrivateFile(join3(this.entriesDirectory, name)));
|
|
2317
2848
|
validateEnvelope(value);
|
|
2318
2849
|
entries.push(value);
|
|
2319
2850
|
} catch {
|
|
@@ -2341,8 +2872,8 @@ var CodexOutboxStore = class {
|
|
|
2341
2872
|
* prompt replaces this projection, so it cannot inherit the prior turn's
|
|
2342
2873
|
* Request by session alone.
|
|
2343
2874
|
*/
|
|
2344
|
-
async activateInvocationContext(identity, promptRef, expiresAt) {
|
|
2345
|
-
const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt);
|
|
2875
|
+
async activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef) {
|
|
2876
|
+
const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef);
|
|
2346
2877
|
await this.prepare();
|
|
2347
2878
|
const path = this.activeContextPath(identity);
|
|
2348
2879
|
try {
|
|
@@ -2356,6 +2887,25 @@ var CodexOutboxStore = class {
|
|
|
2356
2887
|
throw error;
|
|
2357
2888
|
}
|
|
2358
2889
|
}
|
|
2890
|
+
async writeInvocationTurnSelection(selection) {
|
|
2891
|
+
if (!isHostInvocationTurnSelection(selection)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection is invalid.");
|
|
2892
|
+
await this.prepare();
|
|
2893
|
+
await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
|
|
2894
|
+
}
|
|
2895
|
+
async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
|
|
2896
|
+
if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
|
|
2897
|
+
await this.prepare();
|
|
2898
|
+
return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
|
|
2899
|
+
}
|
|
2900
|
+
async attachInvocationTurnGeneration(identity, promptRef, turnGenerationRef) {
|
|
2901
|
+
const selection = await this.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
|
|
2902
|
+
if (selection === null || selection.prompt_ref !== promptRef || selection.turn_generation_ref !== turnGenerationRef) return false;
|
|
2903
|
+
const path = this.activeContextPath(identity);
|
|
2904
|
+
const active = await readOptionalJson(path, validateCodexHostInvocationContext);
|
|
2905
|
+
if (active === null || active.prompt_ref !== promptRef || !sameIdentity(active.identity, identity)) return false;
|
|
2906
|
+
await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
|
|
2907
|
+
return true;
|
|
2908
|
+
}
|
|
2359
2909
|
/**
|
|
2360
2910
|
* Publish a Request reference only while the acknowledged binding is still
|
|
2361
2911
|
* the active turn. A delayed relay response therefore cannot overwrite a
|
|
@@ -2365,17 +2915,25 @@ var CodexOutboxStore = class {
|
|
|
2365
2915
|
validateBinding(binding);
|
|
2366
2916
|
const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
|
|
2367
2917
|
if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
|
|
2368
|
-
await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding));
|
|
2918
|
+
await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
|
|
2369
2919
|
return true;
|
|
2370
2920
|
}
|
|
2371
|
-
/** Return only the
|
|
2921
|
+
/** Return only the live session projection; never fall back to another turn. */
|
|
2372
2922
|
async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
|
|
2373
|
-
if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
|
|
2374
2923
|
if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
|
|
2924
|
+
const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
|
|
2925
|
+
return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
|
|
2926
|
+
}
|
|
2927
|
+
/**
|
|
2928
|
+
* The latest Codex session projection even when past expiry, so the
|
|
2929
|
+
* invocation authenticator can report an expired context distinctly from
|
|
2930
|
+
* a missing one. Every other caller keeps the fail-closed read above.
|
|
2931
|
+
*/
|
|
2932
|
+
async readRawInvocationContext(hostSourceRef, hostSessionRef) {
|
|
2933
|
+
if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
|
|
2375
2934
|
await this.prepare();
|
|
2376
|
-
const context = await
|
|
2377
|
-
|
|
2378
|
-
return Date.parse(context.expires_at) > now.getTime() ? context : null;
|
|
2935
|
+
const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
|
|
2936
|
+
return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
|
|
2379
2937
|
}
|
|
2380
2938
|
/** Clear the projection only if the caller still owns its exact active turn. */
|
|
2381
2939
|
async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
|
|
@@ -2434,7 +2992,7 @@ var CodexOutboxStore = class {
|
|
|
2434
2992
|
for (const name of await readdir(this.registrationsDirectory)) {
|
|
2435
2993
|
if (!name.endsWith(".json")) continue;
|
|
2436
2994
|
try {
|
|
2437
|
-
const value = JSON.parse(await readPrivateFile(
|
|
2995
|
+
const value = JSON.parse(await readPrivateFile(join3(this.registrationsDirectory, name)));
|
|
2438
2996
|
validateRegistration(value);
|
|
2439
2997
|
registrations.push(value);
|
|
2440
2998
|
} catch {
|
|
@@ -2476,22 +3034,25 @@ var CodexOutboxStore = class {
|
|
|
2476
3034
|
}
|
|
2477
3035
|
entryPath(submissionRef) {
|
|
2478
3036
|
if (!SAFE_REF4.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
|
|
2479
|
-
return
|
|
3037
|
+
return join3(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
|
|
2480
3038
|
}
|
|
2481
3039
|
bindingPath(identity) {
|
|
2482
|
-
return
|
|
3040
|
+
return join3(this.bindingsDirectory, `${identityKey(identity)}.json`);
|
|
2483
3041
|
}
|
|
2484
3042
|
sessionPath(sourceRef, sessionRef) {
|
|
2485
|
-
return
|
|
3043
|
+
return join3(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
|
|
2486
3044
|
}
|
|
2487
3045
|
activeContextPath(identity) {
|
|
2488
|
-
return
|
|
3046
|
+
return join3(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
|
|
3047
|
+
}
|
|
3048
|
+
turnSelectionPath(sourceRef, sessionRef) {
|
|
3049
|
+
return join3(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
|
|
2489
3050
|
}
|
|
2490
3051
|
registrationPath(sourceRef, sessionRef) {
|
|
2491
|
-
return
|
|
3052
|
+
return join3(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
|
|
2492
3053
|
}
|
|
2493
3054
|
cursorPath(sourceRef, sessionRef) {
|
|
2494
|
-
return
|
|
3055
|
+
return join3(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
|
|
2495
3056
|
}
|
|
2496
3057
|
};
|
|
2497
3058
|
async function removeOwnerState(path, what) {
|
|
@@ -2529,7 +3090,7 @@ async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
|
|
|
2529
3090
|
}
|
|
2530
3091
|
async function readBindingCandidate(directory, name) {
|
|
2531
3092
|
try {
|
|
2532
|
-
const value = JSON.parse(await readPrivateFile(
|
|
3093
|
+
const value = JSON.parse(await readPrivateFile(join3(directory, name)));
|
|
2533
3094
|
validateBinding(value);
|
|
2534
3095
|
return value;
|
|
2535
3096
|
} catch {
|
|
@@ -2548,14 +3109,14 @@ async function writeAtomicJson(path, value) {
|
|
|
2548
3109
|
if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
|
|
2549
3110
|
const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
2550
3111
|
try {
|
|
2551
|
-
const handle = await
|
|
3112
|
+
const handle = await open4(temp, "wx", 384);
|
|
2552
3113
|
try {
|
|
2553
3114
|
await handle.writeFile(text, "utf8");
|
|
2554
3115
|
await handle.sync();
|
|
2555
3116
|
} finally {
|
|
2556
3117
|
await handle.close();
|
|
2557
3118
|
}
|
|
2558
|
-
await
|
|
3119
|
+
await rename3(temp, path);
|
|
2559
3120
|
await syncDirectory(dirname(path));
|
|
2560
3121
|
} catch (error) {
|
|
2561
3122
|
try {
|
|
@@ -2568,7 +3129,7 @@ async function writeAtomicJson(path, value) {
|
|
|
2568
3129
|
}
|
|
2569
3130
|
async function syncDirectory(path) {
|
|
2570
3131
|
try {
|
|
2571
|
-
const handle = await
|
|
3132
|
+
const handle = await open4(path, "r");
|
|
2572
3133
|
try {
|
|
2573
3134
|
await handle.sync();
|
|
2574
3135
|
} finally {
|
|
@@ -2593,7 +3154,7 @@ async function ensurePrivateOwnerDirectory(path) {
|
|
|
2593
3154
|
await lstat3(path);
|
|
2594
3155
|
} catch (error) {
|
|
2595
3156
|
if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
|
|
2596
|
-
await
|
|
3157
|
+
await mkdir3(path, { recursive: true, mode: 448 });
|
|
2597
3158
|
}
|
|
2598
3159
|
const stats = await lstat3(path);
|
|
2599
3160
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
|
|
@@ -2604,7 +3165,7 @@ async function ensurePrivateOwnerDirectory(path) {
|
|
|
2604
3165
|
async function readPrivateFile(path) {
|
|
2605
3166
|
let handle;
|
|
2606
3167
|
try {
|
|
2607
|
-
handle = await
|
|
3168
|
+
handle = await open4(path, O_RDONLY3 | O_NOFOLLOW2);
|
|
2608
3169
|
const stats = await handle.stat();
|
|
2609
3170
|
const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
|
|
2610
3171
|
if (!stats.isFile()) throw storageError(`Codex owner state path is not a regular file (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a regular-file mode (0o100xxx)")}).`);
|
|
@@ -2616,7 +3177,7 @@ async function readPrivateFile(path) {
|
|
|
2616
3177
|
}
|
|
2617
3178
|
}
|
|
2618
3179
|
function validateEnvelope(value) {
|
|
2619
|
-
if (!
|
|
3180
|
+
if (!isRecord4(value)) throw storageError("Codex outbox entry is malformed.");
|
|
2620
3181
|
if (!sameKeys(value, ["schema_version", "identity", "host_input_ref", "input_kind", "prompt_ref", "observations", "origin_input", "submission_ref", "created_at", "expires_at"], ["request_ref", "codex_turn_id"])) throw storageError(`Codex outbox entry key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the outbox entry key set")}).`);
|
|
2621
3182
|
if (value.schema_version !== CODEX_OUTBOX_SCHEMA_VERSION) throw storageError(`Codex outbox entry is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_OUTBOX_SCHEMA_VERSION}`)}).`);
|
|
2622
3183
|
validateIdentity3(value.identity);
|
|
@@ -2634,7 +3195,7 @@ function validateEnvelopeReferences(value) {
|
|
|
2634
3195
|
if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
|
|
2635
3196
|
}
|
|
2636
3197
|
function validateRegistration(value) {
|
|
2637
|
-
if (!
|
|
3198
|
+
if (!isRecord4(value)) throw storageError("Codex transcript registration is malformed.");
|
|
2638
3199
|
if (!sameKeys(value, ["schema_version", "host_source_ref", "host_session_ref", "codex_session_id", "transcript_path", "registered_at", "expires_at"], ["cwd"])) throw storageError(`Codex transcript registration key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the registration key set")}).`);
|
|
2639
3200
|
if (value.schema_version !== CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION) throw storageError(`Codex transcript registration is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION}`)}).`);
|
|
2640
3201
|
validateRegistrationFields(value);
|
|
@@ -2650,12 +3211,12 @@ function validRegistrationCwd(value) {
|
|
|
2650
3211
|
return value === void 0 || typeof value === "string" && isAbsolute(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
|
|
2651
3212
|
}
|
|
2652
3213
|
function validateCursor(value) {
|
|
2653
|
-
if (!
|
|
3214
|
+
if (!isRecord4(value)) throw storageError("Codex transcript cursor is malformed.");
|
|
2654
3215
|
if (!sameKeys(value, ["schema_version", "host_source_ref", "host_session_ref", "transcript_path", "device", "inode", "offset", "last_ordinal", "anchor_start", "anchor_sha256", "header_validated", "status", "updated_at"], ["active_task", "reason"])) throw storageError(`Codex transcript cursor key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the cursor key set")}).`);
|
|
2655
3216
|
if (value.schema_version !== CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION) throw storageError(`Codex transcript cursor is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION}`)}).`);
|
|
2656
3217
|
if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
|
|
2657
3218
|
if (value.active_task !== void 0 && !validActiveTask(value.active_task)) throw storageError("Codex transcript task cursor is malformed.");
|
|
2658
|
-
if (value.reason !== void 0 && !
|
|
3219
|
+
if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
|
|
2659
3220
|
}
|
|
2660
3221
|
function validCursorSource(value) {
|
|
2661
3222
|
return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
|
|
@@ -2667,7 +3228,7 @@ function validCursorStatus(value) {
|
|
|
2667
3228
|
return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
|
|
2668
3229
|
}
|
|
2669
3230
|
function validActiveTask(value) {
|
|
2670
|
-
if (!
|
|
3231
|
+
if (!isRecord4(value) || !sameKeys(value, ["codex_turn_id", "host_turn_ref", "started_at"], ["origin_host_input_ref", "prompt_ref", "model", "token_usage", "last_total_usage", "token_usage_gap_reason"])) return false;
|
|
2671
3232
|
return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
|
|
2672
3233
|
}
|
|
2673
3234
|
function validActiveTaskIdentity(value) {
|
|
@@ -2683,7 +3244,7 @@ function validActiveTaskUsage(value) {
|
|
|
2683
3244
|
return (value.token_usage === void 0 || validTokenUsage(value.token_usage)) && (value.last_total_usage === void 0 || validTokenUsage(value.last_total_usage)) && (value.token_usage_gap_reason === void 0 || value.token_usage_gap_reason === "token_count_shape_not_attributable");
|
|
2684
3245
|
}
|
|
2685
3246
|
function validTokenUsage(value) {
|
|
2686
|
-
if (!
|
|
3247
|
+
if (!isRecord4(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
|
|
2687
3248
|
if (![value.input_tokens, value.cached_input_tokens, value.cache_write_input_tokens, value.output_tokens, value.reasoning_output_tokens, value.total_tokens].every(nonNegativeInteger)) return false;
|
|
2688
3249
|
return value.total_tokens === Number(value.input_tokens) + Number(value.output_tokens) && Number(value.cached_input_tokens) + Number(value.cache_write_input_tokens) <= Number(value.input_tokens) && Number(value.reasoning_output_tokens) <= Number(value.output_tokens);
|
|
2689
3250
|
}
|
|
@@ -2703,7 +3264,7 @@ function validateEnvelopeTimestamps(value) {
|
|
|
2703
3264
|
if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
|
|
2704
3265
|
}
|
|
2705
3266
|
function validateBinding(value) {
|
|
2706
|
-
if (!
|
|
3267
|
+
if (!isRecord4(value)) throw storageError("Codex turn binding is malformed.");
|
|
2707
3268
|
if (!sameKeys(value, ["schema_version", "identity", "prompt_ref", "request_ref", "codex_turn_ids", "bound_at", "expires_at"])) throw storageError(`Codex turn binding key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the turn binding key set")}).`);
|
|
2708
3269
|
if (value.schema_version !== CODEX_TURN_BINDING_SCHEMA_VERSION) throw storageError(`Codex turn binding is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TURN_BINDING_SCHEMA_VERSION}`)}).`);
|
|
2709
3270
|
validateIdentity3(value.identity);
|
|
@@ -2711,19 +3272,22 @@ function validateBinding(value) {
|
|
|
2711
3272
|
if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
|
|
2712
3273
|
}
|
|
2713
3274
|
function validateSession(value) {
|
|
2714
|
-
if (!
|
|
3275
|
+
if (!isRecord4(value)) throw storageError("Codex session snapshot is malformed.");
|
|
2715
3276
|
if (!sameKeys(value, ["schema_version", "host_session_ref", "host_source_ref", "observed_at", "value", "expires_at"])) throw storageError(`Codex session snapshot key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the session snapshot key set")}).`);
|
|
2716
3277
|
if (value.schema_version !== CODEX_SESSION_SCHEMA_VERSION) throw storageError(`Codex session snapshot is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_SESSION_SCHEMA_VERSION}`)}).`);
|
|
2717
3278
|
if (!SAFE_REF4.test(String(value.host_session_ref)) || !SAFE_REF4.test(String(value.host_source_ref)) || !isTimestamp(value.observed_at) || !isTimestamp(value.expires_at) || !isJsonValue(value.value)) throw storageError("Codex session snapshot fields are malformed.");
|
|
2718
3279
|
}
|
|
3280
|
+
function validateTurnSelection(value) {
|
|
3281
|
+
if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
|
|
3282
|
+
}
|
|
2719
3283
|
function validateIdentity3(value) {
|
|
2720
|
-
if (!
|
|
3284
|
+
if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate))) throw storageError("Codex Host identity is malformed.");
|
|
2721
3285
|
}
|
|
2722
3286
|
function isJsonValue(value) {
|
|
2723
3287
|
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
2724
3288
|
if (typeof value === "number") return Number.isFinite(value);
|
|
2725
3289
|
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
2726
|
-
return
|
|
3290
|
+
return isRecord4(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
|
|
2727
3291
|
}
|
|
2728
3292
|
function isStringList(value) {
|
|
2729
3293
|
return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate));
|
|
@@ -2736,101 +3300,49 @@ function sameKeys(value, required, optional = []) {
|
|
|
2736
3300
|
const keys = Object.keys(value);
|
|
2737
3301
|
return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
|
|
2738
3302
|
}
|
|
2739
|
-
function
|
|
3303
|
+
function isRecord4(value) {
|
|
2740
3304
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2741
3305
|
}
|
|
2742
3306
|
function isNotFound(error) {
|
|
2743
|
-
return
|
|
3307
|
+
return isRecord4(error) && error.code === "ENOENT";
|
|
2744
3308
|
}
|
|
2745
3309
|
function storageError(message) {
|
|
2746
3310
|
return new CodexHostAdapterError("storage", message);
|
|
2747
3311
|
}
|
|
2748
3312
|
|
|
2749
3313
|
// host/codex/src/codex-producer.ts
|
|
2750
|
-
var STATE_SCHEMA = "ceal.codex_producer_state.v1";
|
|
2751
3314
|
var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
2752
3315
|
var CodexProducer = class {
|
|
3316
|
+
producer_id = "codex";
|
|
3317
|
+
producer_label = "Codex";
|
|
3318
|
+
outbox_directory;
|
|
2753
3319
|
store;
|
|
2754
|
-
|
|
2755
|
-
installationRef;
|
|
2756
|
-
epoch;
|
|
2757
|
-
relay;
|
|
2758
|
-
now;
|
|
2759
|
-
tail = Promise.resolve();
|
|
3320
|
+
core;
|
|
2760
3321
|
constructor(options) {
|
|
2761
|
-
if (!SAFE_REF5.test(options.producer_installation_ref)) throw new CodexHostAdapterError("configuration", "Codex producer installation identity is invalid.");
|
|
2762
|
-
const epoch = options.producer_epoch ?? 1;
|
|
2763
|
-
if (!Number.isSafeInteger(epoch) || epoch <= 0) throw new CodexHostAdapterError("configuration", "Codex producer epoch is invalid.");
|
|
2764
3322
|
this.store = new CodexOutboxStore(options.outbox_dir);
|
|
2765
|
-
this.
|
|
2766
|
-
this.
|
|
2767
|
-
this.epoch = epoch;
|
|
2768
|
-
this.relay = options.relay;
|
|
2769
|
-
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
3323
|
+
this.outbox_directory = this.store.directory;
|
|
3324
|
+
this.core = new HostProducerDrainCore(this, options);
|
|
2770
3325
|
}
|
|
2771
3326
|
drainOutbox() {
|
|
2772
|
-
|
|
2773
|
-
this.tail = run.then(() => void 0, () => void 0);
|
|
2774
|
-
return run;
|
|
3327
|
+
return this.core.drainOutbox();
|
|
2775
3328
|
}
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
let admitted = 0;
|
|
2779
|
-
let expired = 0;
|
|
2780
|
-
let retained = 0;
|
|
2781
|
-
for (const envelope of read.entries) {
|
|
2782
|
-
const reserved = await this.hasReservation(envelope.submission_ref);
|
|
2783
|
-
if (!reserved && Date.parse(envelope.expires_at) <= this.now().getTime()) {
|
|
2784
|
-
await this.store.remove(envelope);
|
|
2785
|
-
expired += 1;
|
|
2786
|
-
continue;
|
|
2787
|
-
}
|
|
2788
|
-
const frames = await this.reserve(envelope);
|
|
2789
|
-
let complete = true;
|
|
2790
|
-
for (const frame of frames) {
|
|
2791
|
-
const outcome = await this.relay.admit(frame);
|
|
2792
|
-
if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
|
|
2793
|
-
complete = false;
|
|
2794
|
-
break;
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
if (!complete) {
|
|
2798
|
-
retained += 1;
|
|
2799
|
-
break;
|
|
2800
|
-
}
|
|
2801
|
-
await this.store.remove(envelope);
|
|
2802
|
-
await this.release(envelope.submission_ref);
|
|
2803
|
-
admitted += 1;
|
|
2804
|
-
}
|
|
2805
|
-
return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
|
|
3329
|
+
fail(code, message) {
|
|
3330
|
+
return new CodexHostAdapterError(code, message);
|
|
2806
3331
|
}
|
|
2807
|
-
|
|
2808
|
-
return
|
|
3332
|
+
listEnvelopes() {
|
|
3333
|
+
return this.store.list();
|
|
2809
3334
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
const existing = state.pending[envelope.submission_ref];
|
|
2813
|
-
if (existing !== void 0) return existing;
|
|
2814
|
-
const drafts = await this.mapEnvelope(envelope);
|
|
2815
|
-
const frames = drafts.map((draft, offset) => ({
|
|
2816
|
-
schema_version: "ceal.host_producer_frame.v1",
|
|
2817
|
-
producer_id: "codex",
|
|
2818
|
-
producer_installation_ref: this.installationRef,
|
|
2819
|
-
producer_epoch: this.epoch,
|
|
2820
|
-
sequence: state.next_sequence + offset,
|
|
2821
|
-
frame_kind: draft.frame_kind,
|
|
2822
|
-
occurred_at: envelope.created_at,
|
|
2823
|
-
payload: draft.payload
|
|
2824
|
-
}));
|
|
2825
|
-
await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [envelope.submission_ref]: frames } });
|
|
2826
|
-
return frames;
|
|
3335
|
+
removeEnvelope(envelope) {
|
|
3336
|
+
return this.store.remove(envelope);
|
|
2827
3337
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
3338
|
+
submissionRefOf(envelope) {
|
|
3339
|
+
return envelope.submission_ref;
|
|
3340
|
+
}
|
|
3341
|
+
expiresAtOf(envelope) {
|
|
3342
|
+
return envelope.expires_at;
|
|
3343
|
+
}
|
|
3344
|
+
createdAtOf(envelope) {
|
|
3345
|
+
return envelope.created_at;
|
|
2834
3346
|
}
|
|
2835
3347
|
async mapEnvelope(envelope) {
|
|
2836
3348
|
const prompt = observation(envelope, "prompt");
|
|
@@ -2846,7 +3358,7 @@ var CodexProducer = class {
|
|
|
2846
3358
|
const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
|
|
2847
3359
|
drafts.push({ frame_kind: "session_started", payload: compact({
|
|
2848
3360
|
local_session_ref: envelope.identity.host_session_ref,
|
|
2849
|
-
working_directory_ref: `workspace:${
|
|
3361
|
+
working_directory_ref: `workspace:${createHash4("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
|
|
2850
3362
|
model: recordText(session.value, "model"),
|
|
2851
3363
|
host_version: nestedText(session.value, "host_version"),
|
|
2852
3364
|
observations: [session]
|
|
@@ -2871,21 +3383,6 @@ var CodexProducer = class {
|
|
|
2871
3383
|
}) });
|
|
2872
3384
|
return drafts;
|
|
2873
3385
|
}
|
|
2874
|
-
async readState() {
|
|
2875
|
-
try {
|
|
2876
|
-
const value = JSON.parse(await readFile(this.statePath, "utf8"));
|
|
2877
|
-
return decodeState(value, this.installationRef, this.epoch);
|
|
2878
|
-
} catch (error) {
|
|
2879
|
-
if (errorCode2(error) !== "ENOENT") throw error;
|
|
2880
|
-
return { schema_version: STATE_SCHEMA, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
|
|
2881
|
-
}
|
|
2882
|
-
}
|
|
2883
|
-
async writeState(state) {
|
|
2884
|
-
await mkdir3(this.store.directory, { recursive: true, mode: 448 });
|
|
2885
|
-
const temporary = `${this.statePath}.${process.pid}.new`;
|
|
2886
|
-
await writeFile(temporary, JSON.stringify(state), { mode: 384 });
|
|
2887
|
-
await rename3(temporary, this.statePath);
|
|
2888
|
-
}
|
|
2889
3386
|
};
|
|
2890
3387
|
function mapTerminal(envelope) {
|
|
2891
3388
|
const timing = observation(envelope, "timing");
|
|
@@ -2913,7 +3410,7 @@ function compact(value) {
|
|
|
2913
3410
|
return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
|
|
2914
3411
|
}
|
|
2915
3412
|
function asRecord(value) {
|
|
2916
|
-
return
|
|
3413
|
+
return isRecord5(value) ? value : void 0;
|
|
2917
3414
|
}
|
|
2918
3415
|
function recordText(value, key) {
|
|
2919
3416
|
const record3 = asRecord(value);
|
|
@@ -2927,55 +3424,16 @@ function nonNegativeNumber(value) {
|
|
|
2927
3424
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
2928
3425
|
}
|
|
2929
3426
|
function safeReasonRef(value) {
|
|
2930
|
-
return SAFE_REF5.test(value) ? value : `reason:${
|
|
3427
|
+
return SAFE_REF5.test(value) ? value : `reason:${createHash4("sha256").update(value, "utf8").digest("hex")}`;
|
|
2931
3428
|
}
|
|
2932
|
-
function
|
|
2933
|
-
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
|
|
2934
|
-
}
|
|
2935
|
-
function decodeState(value, installationRef, epoch) {
|
|
2936
|
-
if (!validStateHeader(value, installationRef)) {
|
|
2937
|
-
throw new CodexHostAdapterError("storage", `Codex producer state header is malformed or belongs to another installation (${refusalFacts([
|
|
2938
|
-
{ name: "schema_version", value: isRecord4(value) ? value.schema_version : void 0, expected: STATE_SCHEMA },
|
|
2939
|
-
{ name: "producer_installation_ref", value: isRecord4(value) ? value.producer_installation_ref : void 0, expected: installationRef }
|
|
2940
|
-
])}).`);
|
|
2941
|
-
}
|
|
2942
|
-
if (Number(value.producer_epoch) > epoch) throw new CodexHostAdapterError("storage", `Codex producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${epoch}`)}).`);
|
|
2943
|
-
const pending = {};
|
|
2944
|
-
for (const [submissionRef, frames] of Object.entries(value.pending)) {
|
|
2945
|
-
if (!SAFE_REF5.test(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw new CodexHostAdapterError("storage", "Codex producer pending reservation is malformed.");
|
|
2946
|
-
pending[submissionRef] = frames.map((frame) => decodeStoredFrame(frame, installationRef, Number(value.producer_epoch)));
|
|
2947
|
-
}
|
|
2948
|
-
return { schema_version: STATE_SCHEMA, producer_installation_ref: installationRef, producer_epoch: epoch, next_sequence: Number(value.next_sequence), pending };
|
|
2949
|
-
}
|
|
2950
|
-
function validStateHeader(value, installationRef) {
|
|
2951
|
-
return isRecord4(value) && value.schema_version === STATE_SCHEMA && value.producer_installation_ref === installationRef && Number.isSafeInteger(value.producer_epoch) && Number(value.producer_epoch) > 0 && Number.isSafeInteger(value.next_sequence) && Number(value.next_sequence) > 0 && isRecord4(value.pending);
|
|
2952
|
-
}
|
|
2953
|
-
function decodeStoredFrame(value, installationRef, epoch) {
|
|
2954
|
-
const json = Buffer.from(JSON.stringify(value), "utf8");
|
|
2955
|
-
const encoded = Buffer.allocUnsafe(json.length + 4);
|
|
2956
|
-
encoded.writeUInt32BE(json.length, 0);
|
|
2957
|
-
json.copy(encoded, 4);
|
|
2958
|
-
const frame = decodeHostProducerFrame(encoded);
|
|
2959
|
-
if (frame.producer_id !== "codex" || frame.producer_installation_ref !== installationRef || frame.producer_epoch > epoch) throw new CodexHostAdapterError("storage", `Codex producer pending frame identity is malformed (${refusalFacts([
|
|
2960
|
-
{ name: "producer_id", value: frame.producer_id, expected: "codex" },
|
|
2961
|
-
{ name: "producer_installation_ref", value: frame.producer_installation_ref, expected: installationRef },
|
|
2962
|
-
{ name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${epoch}` }
|
|
2963
|
-
])}).`);
|
|
2964
|
-
return frame;
|
|
2965
|
-
}
|
|
2966
|
-
function isRecord4(value) {
|
|
3429
|
+
function isRecord5(value) {
|
|
2967
3430
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2968
3431
|
}
|
|
2969
3432
|
|
|
2970
|
-
// host/codex/src/codex-transcript-watcher.ts
|
|
2971
|
-
import { createHash as createHash6 } from "node:crypto";
|
|
2972
|
-
import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
|
|
2973
|
-
import { open as open4 } from "node:fs/promises";
|
|
2974
|
-
|
|
2975
3433
|
// host/codex/src/codex-decoder.ts
|
|
2976
|
-
import { createHash as
|
|
3434
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
2977
3435
|
var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
2978
|
-
var MAX_PAYLOAD_BYTES =
|
|
3436
|
+
var MAX_PAYLOAD_BYTES = 512 * 1024;
|
|
2979
3437
|
function observationRef(event, identity, value) {
|
|
2980
3438
|
return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
|
|
2981
3439
|
}
|
|
@@ -2996,14 +3454,14 @@ function turnObservationValue(sessionId, turnRef, status) {
|
|
|
2996
3454
|
return { status, host_session_id_sha256: sha256(sessionId), host_turn_ref: turnRef };
|
|
2997
3455
|
}
|
|
2998
3456
|
function sha256(value) {
|
|
2999
|
-
return
|
|
3457
|
+
return createHash5("sha256").update(value, "utf8").digest("hex");
|
|
3000
3458
|
}
|
|
3001
3459
|
function shortDigest(value) {
|
|
3002
3460
|
return cealRequestSha256(value);
|
|
3003
3461
|
}
|
|
3004
3462
|
|
|
3005
3463
|
// host/codex/src/codex-transcript-baseline.ts
|
|
3006
|
-
import { createHash as
|
|
3464
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
3007
3465
|
|
|
3008
3466
|
// host/codex/src/codex-transcript-decoder.ts
|
|
3009
3467
|
var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
@@ -3015,40 +3473,40 @@ function decodeCodexTranscriptLine(line) {
|
|
|
3015
3473
|
} catch {
|
|
3016
3474
|
reject("Codex transcript record is not valid JSON.");
|
|
3017
3475
|
}
|
|
3018
|
-
if (!
|
|
3476
|
+
if (!isRecord6(value)) reject("Codex transcript record envelope is malformed.");
|
|
3019
3477
|
const ordinal = safeOrdinal(value.ordinal);
|
|
3020
|
-
const
|
|
3021
|
-
if (!
|
|
3022
|
-
if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal,
|
|
3023
|
-
if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal,
|
|
3024
|
-
if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal,
|
|
3025
|
-
if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal,
|
|
3026
|
-
return { kind: "ignored", ordinal, timestamp:
|
|
3027
|
-
}
|
|
3028
|
-
function decodeTurnContext(payload, ordinal,
|
|
3478
|
+
const timestamp4 = safeTimestamp(value.timestamp);
|
|
3479
|
+
if (!isRecord6(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
|
|
3480
|
+
if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
|
|
3481
|
+
if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
|
|
3482
|
+
if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
|
|
3483
|
+
if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
|
|
3484
|
+
return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3485
|
+
}
|
|
3486
|
+
function decodeTurnContext(payload, ordinal, timestamp4) {
|
|
3029
3487
|
return {
|
|
3030
3488
|
kind: "turn_context",
|
|
3031
3489
|
ordinal,
|
|
3032
|
-
timestamp:
|
|
3033
|
-
turn_id:
|
|
3490
|
+
timestamp: timestamp4,
|
|
3491
|
+
turn_id: safeRef4(payload.turn_id, "Codex turn context identity is invalid."),
|
|
3034
3492
|
model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
|
|
3035
3493
|
};
|
|
3036
3494
|
}
|
|
3037
|
-
function decodeSessionMeta(payload, ordinal,
|
|
3038
|
-
const sessionId =
|
|
3495
|
+
function decodeSessionMeta(payload, ordinal, timestamp4) {
|
|
3496
|
+
const sessionId = safeRef4(payload.id, "Codex transcript session identity is invalid.");
|
|
3039
3497
|
const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
|
|
3040
|
-
return { kind: "session_meta", ordinal, timestamp:
|
|
3498
|
+
return { kind: "session_meta", ordinal, timestamp: timestamp4, session_id: sessionId, cli_version: cliVersion };
|
|
3041
3499
|
}
|
|
3042
|
-
function decodeEventMessage(payload, ordinal,
|
|
3500
|
+
function decodeEventMessage(payload, ordinal, timestamp4) {
|
|
3043
3501
|
if (payload.type === "task_started") {
|
|
3044
|
-
return { kind: "task_started", ordinal, timestamp:
|
|
3502
|
+
return { kind: "task_started", ordinal, timestamp: timestamp4, turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
|
|
3045
3503
|
}
|
|
3046
3504
|
if (payload.type === "task_complete") {
|
|
3047
3505
|
return {
|
|
3048
3506
|
kind: "task_complete",
|
|
3049
3507
|
ordinal,
|
|
3050
|
-
timestamp:
|
|
3051
|
-
turn_id:
|
|
3508
|
+
timestamp: timestamp4,
|
|
3509
|
+
turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
|
|
3052
3510
|
started_at: safeNumber(payload.started_at),
|
|
3053
3511
|
completed_at: safeNumber(payload.completed_at),
|
|
3054
3512
|
duration_ms: safeNumber(payload.duration_ms),
|
|
@@ -3059,20 +3517,20 @@ function decodeEventMessage(payload, ordinal, timestamp5) {
|
|
|
3059
3517
|
return {
|
|
3060
3518
|
kind: "turn_aborted",
|
|
3061
3519
|
ordinal,
|
|
3062
|
-
timestamp:
|
|
3063
|
-
turn_id:
|
|
3520
|
+
timestamp: timestamp4,
|
|
3521
|
+
turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
|
|
3064
3522
|
started_at: safeNumber(payload.started_at),
|
|
3065
3523
|
completed_at: safeNumber(payload.completed_at),
|
|
3066
3524
|
duration_ms: safeNumber(payload.duration_ms),
|
|
3067
3525
|
reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
|
|
3068
3526
|
};
|
|
3069
3527
|
}
|
|
3070
|
-
if (payload.type === "token_count") return decodeTokenCount(payload, ordinal,
|
|
3071
|
-
return { kind: "ignored", ordinal, timestamp:
|
|
3528
|
+
if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
|
|
3529
|
+
return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3072
3530
|
}
|
|
3073
|
-
function decodeTokenCount(payload, ordinal,
|
|
3074
|
-
if (payload.info === null) return { kind: "token_count", ordinal, timestamp:
|
|
3075
|
-
if (!
|
|
3531
|
+
function decodeTokenCount(payload, ordinal, timestamp4) {
|
|
3532
|
+
if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
|
|
3533
|
+
if (!isRecord6(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp4, usage_gap_reason: "token_count_shape_not_attributable" };
|
|
3076
3534
|
const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
|
|
3077
3535
|
const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
|
|
3078
3536
|
const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
|
|
@@ -3080,7 +3538,7 @@ function decodeTokenCount(payload, ordinal, timestamp5) {
|
|
|
3080
3538
|
return {
|
|
3081
3539
|
kind: "token_count",
|
|
3082
3540
|
ordinal,
|
|
3083
|
-
timestamp:
|
|
3541
|
+
timestamp: timestamp4,
|
|
3084
3542
|
...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
|
|
3085
3543
|
...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
|
|
3086
3544
|
...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
|
|
@@ -3096,7 +3554,7 @@ function optionalTokenUsage(value) {
|
|
|
3096
3554
|
}
|
|
3097
3555
|
}
|
|
3098
3556
|
function decodeTokenUsage(value) {
|
|
3099
|
-
if (!
|
|
3557
|
+
if (!isRecord6(value)) reject("Codex token usage is malformed.");
|
|
3100
3558
|
const usage = {
|
|
3101
3559
|
input_tokens: safeTokenCount(value.input_tokens),
|
|
3102
3560
|
cached_input_tokens: safeTokenCount(value.cached_input_tokens),
|
|
@@ -3108,20 +3566,20 @@ function decodeTokenUsage(value) {
|
|
|
3108
3566
|
if (usage.total_tokens !== usage.input_tokens + usage.output_tokens || usage.cached_input_tokens + usage.cache_write_input_tokens > usage.input_tokens || usage.reasoning_output_tokens > usage.output_tokens) reject("Codex token usage buckets are inconsistent.");
|
|
3109
3567
|
return usage;
|
|
3110
3568
|
}
|
|
3111
|
-
function decodeResponseItem(payload, ordinal,
|
|
3112
|
-
if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp:
|
|
3569
|
+
function decodeResponseItem(payload, ordinal, timestamp4) {
|
|
3570
|
+
if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3113
3571
|
const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
|
|
3114
3572
|
const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
|
|
3115
|
-
if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp:
|
|
3573
|
+
if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp4 };
|
|
3116
3574
|
const prompt = userTextContent(payload.content);
|
|
3117
3575
|
return {
|
|
3118
3576
|
kind: "user_text",
|
|
3119
3577
|
ordinal,
|
|
3120
|
-
timestamp:
|
|
3578
|
+
timestamp: timestamp4,
|
|
3121
3579
|
prompt,
|
|
3122
3580
|
input_kind: inputKind,
|
|
3123
|
-
message_id:
|
|
3124
|
-
turn_id:
|
|
3581
|
+
message_id: safeRef4(payload.id, "Codex user message identity is invalid."),
|
|
3582
|
+
turn_id: safeRef4(metadata.turn_id, "Codex user message task identity is invalid.")
|
|
3125
3583
|
};
|
|
3126
3584
|
}
|
|
3127
3585
|
function inputKindFromContentItems(kinds) {
|
|
@@ -3130,13 +3588,13 @@ function inputKindFromContentItems(kinds) {
|
|
|
3130
3588
|
return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
|
|
3131
3589
|
}
|
|
3132
3590
|
function userMessageMetadata(value) {
|
|
3133
|
-
if (!
|
|
3591
|
+
if (!isRecord6(value) || !Array.isArray(value.content_item_kinds)) reject("Codex user message provenance is malformed.");
|
|
3134
3592
|
return { ...value, content_item_kinds: value.content_item_kinds };
|
|
3135
3593
|
}
|
|
3136
3594
|
function userTextContent(value) {
|
|
3137
3595
|
if (!Array.isArray(value)) reject(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
|
|
3138
3596
|
if (value.length !== 1) reject(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
|
|
3139
|
-
if (!
|
|
3597
|
+
if (!isRecord6(value[0]) || value[0].type !== "input_text") reject(`Codex user text content is malformed (${refusalFact("item_type", isRecord6(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
|
|
3140
3598
|
return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
|
|
3141
3599
|
}
|
|
3142
3600
|
function safeOrdinal(value) {
|
|
@@ -3157,7 +3615,7 @@ function safeTimestamp(value) {
|
|
|
3157
3615
|
if (!Number.isFinite(Date.parse(value))) reject(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
|
|
3158
3616
|
return value;
|
|
3159
3617
|
}
|
|
3160
|
-
function
|
|
3618
|
+
function safeRef4(value, message) {
|
|
3161
3619
|
if (typeof value !== "string" || !SAFE_REF7.test(value)) reject(message);
|
|
3162
3620
|
return value;
|
|
3163
3621
|
}
|
|
@@ -3172,7 +3630,7 @@ function boundedNonEmptyText(value, maximum, message) {
|
|
|
3172
3630
|
if (result.length === 0) reject(message);
|
|
3173
3631
|
return result;
|
|
3174
3632
|
}
|
|
3175
|
-
function
|
|
3633
|
+
function isRecord6(value) {
|
|
3176
3634
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3177
3635
|
}
|
|
3178
3636
|
function reject(message) {
|
|
@@ -3216,7 +3674,7 @@ function assertCodexTranscriptHeader(registration, record3) {
|
|
|
3216
3674
|
])}).`);
|
|
3217
3675
|
}
|
|
3218
3676
|
function digest(value) {
|
|
3219
|
-
return
|
|
3677
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
3220
3678
|
}
|
|
3221
3679
|
function timestamp3(now) {
|
|
3222
3680
|
const value = now();
|
|
@@ -3232,78 +3690,44 @@ function codexSubmissionReference(hostInputRef, event, ordinal) {
|
|
|
3232
3690
|
}
|
|
3233
3691
|
|
|
3234
3692
|
// host/codex/src/codex-transcript-watcher.ts
|
|
3235
|
-
var
|
|
3236
|
-
var TRANSCRIPT_MISSING_REASON = "transcript_missing";
|
|
3237
|
-
var CodexTranscriptWatcher = class {
|
|
3693
|
+
var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
|
|
3238
3694
|
store;
|
|
3239
|
-
outboxRetentionMs;
|
|
3240
|
-
now;
|
|
3241
|
-
log;
|
|
3242
|
-
producerInstallationRef;
|
|
3243
3695
|
registerCurrentPrompt;
|
|
3244
3696
|
constructor(options) {
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
this.log = options.log ?? ((line) => {
|
|
3250
|
-
process.stderr.write(`${line}
|
|
3251
|
-
`);
|
|
3697
|
+
super(options, {
|
|
3698
|
+
default_retention_ms: CODEX_DEFAULT_RETENTION_MS,
|
|
3699
|
+
invalid_outbox: () => new CodexHostAdapterError("configuration", "Codex transcript watcher outbox is invalid."),
|
|
3700
|
+
clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
|
|
3252
3701
|
});
|
|
3253
|
-
this.
|
|
3702
|
+
this.store = new CodexOutboxStore(options.outbox_dir);
|
|
3254
3703
|
this.registerCurrentPrompt = options.register_current_prompt;
|
|
3255
3704
|
}
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
let records = 0;
|
|
3259
|
-
let enqueued = 0;
|
|
3260
|
-
let quarantined = 0;
|
|
3261
|
-
for (const registration of registrations) {
|
|
3262
|
-
const result = await this.scanRegistration(registration);
|
|
3263
|
-
records += result.records;
|
|
3264
|
-
enqueued += result.enqueued;
|
|
3265
|
-
if (result.quarantined) quarantined += 1;
|
|
3266
|
-
}
|
|
3267
|
-
return { registrations: registrations.length, records, enqueued, quarantined };
|
|
3705
|
+
transcriptPathOf(registration) {
|
|
3706
|
+
return registration.transcript_path;
|
|
3268
3707
|
}
|
|
3269
|
-
async
|
|
3270
|
-
|
|
3271
|
-
try {
|
|
3272
|
-
handle = await open4(registration.transcript_path, O_RDONLY3 | O_NOFOLLOW2);
|
|
3273
|
-
const { size, device, inode } = await ownedCodexTranscriptFile(handle);
|
|
3274
|
-
const preflight = await this.preflight(registration, handle, size, device, inode);
|
|
3275
|
-
if (preflight.cursor === null) return preflight.result;
|
|
3276
|
-
const complete = await readCompleteChunk(handle, preflight.cursor, size);
|
|
3277
|
-
if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
|
|
3278
|
-
return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
|
|
3279
|
-
} catch (error) {
|
|
3280
|
-
if (handle === void 0 && isMissingTranscript(error)) return await this.retireRegistration(registration);
|
|
3281
|
-
await this.quarantineFailure(registration, handle);
|
|
3282
|
-
return { records: 0, enqueued: 0, quarantined: true };
|
|
3283
|
-
} finally {
|
|
3284
|
-
await handle?.close();
|
|
3285
|
-
}
|
|
3708
|
+
async listRegistrations() {
|
|
3709
|
+
return this.store.listTranscriptRegistrations();
|
|
3286
3710
|
}
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
return
|
|
3711
|
+
async scanOpened(handle, registration) {
|
|
3712
|
+
const { size, device, inode } = await ownedCodexTranscriptFile(handle);
|
|
3713
|
+
const preflight = await this.preflight(registration, handle, size, device, inode);
|
|
3714
|
+
if (preflight.cursor === null) return preflight.result;
|
|
3715
|
+
const complete = await this.readChunk(handle, preflight.cursor.offset, size);
|
|
3716
|
+
if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
|
|
3717
|
+
return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
|
|
3718
|
+
}
|
|
3719
|
+
async scanFailed(handle, registration, _error) {
|
|
3720
|
+
await this.quarantineFailure(registration, handle);
|
|
3721
|
+
return { records: 0, enqueued: 0, quarantined: true };
|
|
3722
|
+
}
|
|
3723
|
+
async retireMissing(registration) {
|
|
3724
|
+
return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
|
|
3301
3725
|
}
|
|
3302
3726
|
async preflight(registration, handle, size, device, inode) {
|
|
3303
3727
|
const existing = await this.store.readTranscriptCursor(registration);
|
|
3304
3728
|
let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
|
|
3305
3729
|
if (cursor.status === "quarantined") return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
|
|
3306
|
-
const reason =
|
|
3730
|
+
const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
|
|
3307
3731
|
if (reason === null) return { cursor, result: { records: 0, enqueued: 0, quarantined: false } };
|
|
3308
3732
|
await this.quarantine(registration, cursor, device, inode, reason);
|
|
3309
3733
|
return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
|
|
@@ -3329,14 +3753,12 @@ var CodexTranscriptWatcher = class {
|
|
|
3329
3753
|
async observeSessionMetadata(registration, record3) {
|
|
3330
3754
|
if (record3.kind !== "session_meta") return;
|
|
3331
3755
|
const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
|
|
3332
|
-
if (session !== null &&
|
|
3756
|
+
if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
|
|
3333
3757
|
}
|
|
3334
3758
|
async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
|
|
3335
3759
|
const offset = cursor.offset + consumedBytes;
|
|
3336
|
-
const
|
|
3337
|
-
|
|
3338
|
-
if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, anchorStart);
|
|
3339
|
-
await this.store.writeTranscriptCursor({ schema_version: "ceal.codex_transcript_cursor.v1", host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, transcript_path: registration.transcript_path, device, inode, offset, last_ordinal: lastOrdinal, anchor_start: anchorStart, anchor_sha256: sha2562(anchor), header_validated: true, ...activeTask === void 0 ? {} : { active_task: activeTask }, status: "active", updated_at: timestamp4(this.now) });
|
|
3760
|
+
const anchor = await this.readAnchor(handle, offset, CODEX_TRANSCRIPT_ANCHOR_BYTES);
|
|
3761
|
+
await this.store.writeTranscriptCursor({ schema_version: "ceal.codex_transcript_cursor.v1", host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, transcript_path: registration.transcript_path, device, inode, offset, last_ordinal: lastOrdinal, anchor_start: anchor.start, anchor_sha256: anchor.sha256, header_validated: true, ...activeTask === void 0 ? {} : { active_task: activeTask }, status: "active", updated_at: this.stamp() });
|
|
3340
3762
|
}
|
|
3341
3763
|
async quarantineFailure(registration, handle) {
|
|
3342
3764
|
if (handle === void 0) return;
|
|
@@ -3385,11 +3807,11 @@ var CodexTranscriptWatcher = class {
|
|
|
3385
3807
|
origin_input: origin,
|
|
3386
3808
|
submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
|
|
3387
3809
|
created_at: record3.timestamp,
|
|
3388
|
-
expires_at:
|
|
3810
|
+
expires_at: this.expire(this.outboxRetentionMs)
|
|
3389
3811
|
};
|
|
3390
3812
|
await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
|
|
3391
3813
|
await this.store.put(envelope);
|
|
3392
|
-
if (origin) await this.store
|
|
3814
|
+
if (origin) await activateTranscriptTurnContext(this.store, identity, promptRef, envelope.expires_at);
|
|
3393
3815
|
return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
|
|
3394
3816
|
}
|
|
3395
3817
|
async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
|
|
@@ -3412,16 +3834,21 @@ var CodexTranscriptWatcher = class {
|
|
|
3412
3834
|
origin_input: false,
|
|
3413
3835
|
submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
|
|
3414
3836
|
created_at: record3.timestamp,
|
|
3415
|
-
expires_at:
|
|
3837
|
+
expires_at: this.expire(this.outboxRetentionMs)
|
|
3416
3838
|
});
|
|
3417
3839
|
await this.store.clearInvocationContext(identity, this.now());
|
|
3418
3840
|
return { enqueued: 1 };
|
|
3419
3841
|
}
|
|
3420
3842
|
async quarantine(registration, cursor, device, inode, reason) {
|
|
3421
|
-
const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at:
|
|
3843
|
+
const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
|
|
3422
3844
|
await this.store.writeTranscriptCursor(quarantined);
|
|
3423
3845
|
}
|
|
3424
3846
|
};
|
|
3847
|
+
async function activateTranscriptTurnContext(store, identity, promptRef, expiresAt) {
|
|
3848
|
+
const selection = await store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
|
|
3849
|
+
const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
|
|
3850
|
+
await store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
|
|
3851
|
+
}
|
|
3425
3852
|
function accumulateTokenCount(activeTask, record3) {
|
|
3426
3853
|
if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
|
|
3427
3854
|
const last = record3.last_usage;
|
|
@@ -3455,19 +3882,18 @@ function terminalCostValue() {
|
|
|
3455
3882
|
return notRecorded("provider_cost_not_observed");
|
|
3456
3883
|
}
|
|
3457
3884
|
function notRecorded(reason) {
|
|
3458
|
-
return
|
|
3885
|
+
return hostObservationNotRecorded(reason);
|
|
3459
3886
|
}
|
|
3460
3887
|
function tokenObservationValue(usage) {
|
|
3461
3888
|
return {
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
source: "codex_transcript.event_msg.token_count.info.last_token_usage",
|
|
3889
|
+
...createHostTokenObservationValue({
|
|
3890
|
+
input: usage.input_tokens,
|
|
3891
|
+
output: usage.output_tokens,
|
|
3892
|
+
total: usage.total_tokens,
|
|
3893
|
+
cached_input: usage.cached_input_tokens,
|
|
3894
|
+
cache_write_input: usage.cache_write_input_tokens,
|
|
3895
|
+
reasoning_output: usage.reasoning_output_tokens
|
|
3896
|
+
}, "codex_transcript.event_msg.token_count.info.last_token_usage"),
|
|
3471
3897
|
attribution: "sequential_active_task",
|
|
3472
3898
|
total_usage_role: "dedup_and_reset_detection_only"
|
|
3473
3899
|
};
|
|
@@ -3501,60 +3927,10 @@ function looksLikeStaleRegression(current, previous, last) {
|
|
|
3501
3927
|
if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
|
|
3502
3928
|
return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
|
|
3503
3929
|
}
|
|
3504
|
-
function isMissingTranscript(error) {
|
|
3505
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
3506
|
-
}
|
|
3507
|
-
async function cursorFailureReason(registration, handle, cursor, size, device, inode) {
|
|
3508
|
-
if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== registration.transcript_path) return "transcript_replaced";
|
|
3509
|
-
if (size < cursor.offset) return "transcript_truncated";
|
|
3510
|
-
if (cursor.offset > 0 && !await anchorMatches(handle, cursor)) return "transcript_rewritten";
|
|
3511
|
-
return null;
|
|
3512
|
-
}
|
|
3513
|
-
async function readCompleteChunk(handle, cursor, size) {
|
|
3514
|
-
const available = Math.max(0, size - cursor.offset);
|
|
3515
|
-
if (available === 0) return "empty";
|
|
3516
|
-
const chunks = [];
|
|
3517
|
-
let position = cursor.offset;
|
|
3518
|
-
let total = 0;
|
|
3519
|
-
let lastNewline = -1;
|
|
3520
|
-
while (position < size) {
|
|
3521
|
-
const buffer = Buffer.alloc(Math.min(READ_CHUNK_BYTES, size - position));
|
|
3522
|
-
const read = await handle.read(buffer, 0, buffer.length, position);
|
|
3523
|
-
if (read.bytesRead === 0) break;
|
|
3524
|
-
const chunk = buffer.subarray(0, read.bytesRead);
|
|
3525
|
-
chunks.push(chunk);
|
|
3526
|
-
const newline = chunk.lastIndexOf(10);
|
|
3527
|
-
if (newline >= 0) lastNewline = total + newline;
|
|
3528
|
-
total += chunk.length;
|
|
3529
|
-
position += chunk.length;
|
|
3530
|
-
if (lastNewline >= 0) break;
|
|
3531
|
-
}
|
|
3532
|
-
if (lastNewline < 0) return "partial";
|
|
3533
|
-
return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
|
|
3534
|
-
}
|
|
3535
3930
|
function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
|
|
3536
3931
|
if ((cursor.header_validated || records > 0) && record3.ordinal <= lastOrdinal) throw new CodexHostAdapterError("payload_rejected", `Codex transcript ordinal is not monotonic (${refusalFact("ordinal", record3.ordinal, `greater than ${lastOrdinal}`)}).`);
|
|
3537
3932
|
if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
|
|
3538
3933
|
}
|
|
3539
|
-
async function anchorMatches(handle, cursor) {
|
|
3540
|
-
const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
|
|
3541
|
-
if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
|
|
3542
|
-
return sha2562(buffer) === cursor.anchor_sha256;
|
|
3543
|
-
}
|
|
3544
|
-
function sha2562(value) {
|
|
3545
|
-
return createHash6("sha256").update(value).digest("hex");
|
|
3546
|
-
}
|
|
3547
|
-
function isRecord6(value) {
|
|
3548
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3549
|
-
}
|
|
3550
|
-
function timestamp4(now) {
|
|
3551
|
-
const value = now();
|
|
3552
|
-
if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
|
|
3553
|
-
return value.toISOString();
|
|
3554
|
-
}
|
|
3555
|
-
function expiration(now, retentionMs) {
|
|
3556
|
-
return new Date(Date.parse(timestamp4(now)) + retentionMs).toISOString();
|
|
3557
|
-
}
|
|
3558
3934
|
|
|
3559
3935
|
// host/codex/src/codex-producer-runtime.ts
|
|
3560
3936
|
async function drainCodexProducerOnce(options) {
|