@corca-org/ceal-host-linux-arm64 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/ceal-host +0 -0
- package/libexec/ceal-host/claude-hook.mjs +149 -46
- package/libexec/ceal-host/claude-invocation-authentication.mjs +103 -127
- package/libexec/ceal-host/claude-producer.mjs +76 -24
- package/libexec/ceal-host/codex-hook.mjs +148 -47
- package/libexec/ceal-host/codex-invocation-authentication.mjs +136 -131
- package/libexec/ceal-host/codex-producer.mjs +136 -32
- package/libexec/ceal-host/control.mjs +157 -40
- package/libexec/ceal-host/relay.mjs +240 -58
- package/package.json +1 -1
- package/share/ceal-host/bundle-manifest.json +12 -12
- package/share/ceal-host/bundle-manifest.sigstore.json +1 -1
|
@@ -74,11 +74,28 @@ var client_wire_contract_default = {
|
|
|
74
74
|
],
|
|
75
75
|
bare_document_fields: [
|
|
76
76
|
"invocation",
|
|
77
|
-
"
|
|
77
|
+
"required_action_sequence",
|
|
78
|
+
"entrypoints",
|
|
78
79
|
"common_concepts",
|
|
79
80
|
"operations",
|
|
80
81
|
"catalog_revision"
|
|
81
82
|
],
|
|
83
|
+
prompt_field: "prompt",
|
|
84
|
+
prompt_schema_version: "ceal.prompt.v1",
|
|
85
|
+
focused_prompt_document_fields: [
|
|
86
|
+
"catalog_revision",
|
|
87
|
+
"prompt"
|
|
88
|
+
],
|
|
89
|
+
focused_prompt_continuation_document_fields: [
|
|
90
|
+
"catalog_revision",
|
|
91
|
+
"remaining_work",
|
|
92
|
+
"prompt"
|
|
93
|
+
],
|
|
94
|
+
discovery_command: "discovery",
|
|
95
|
+
discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
|
|
96
|
+
discovery_manifest_document_fields: [
|
|
97
|
+
"discovery_manifest"
|
|
98
|
+
],
|
|
82
99
|
exit_code_max: 125,
|
|
83
100
|
bare_document_max_bytes: 65536,
|
|
84
101
|
complete_max_bytes: 66019,
|
|
@@ -105,8 +122,15 @@ var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = artifact.max_bytes;
|
|
|
105
122
|
var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
|
|
106
123
|
var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = request.schema_version;
|
|
107
124
|
var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
|
|
108
|
-
var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_FIELDS = response.bare_document_fields;
|
|
109
125
|
var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
|
|
126
|
+
var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
|
|
127
|
+
var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
|
|
128
|
+
var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
|
|
129
|
+
var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
|
|
130
|
+
var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
|
|
131
|
+
var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
|
|
132
|
+
var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
|
|
133
|
+
var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
|
|
110
134
|
var CEAL_COMMAND_RESPONSE_MAX_BYTES = response.absolute_transport_max_bytes;
|
|
111
135
|
|
|
112
136
|
// packages/ceal-client-protocol/src/vocabulary.ts
|
|
@@ -142,7 +166,7 @@ var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate
|
|
|
142
166
|
var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
|
|
143
167
|
var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
|
|
144
168
|
var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
|
|
145
|
-
var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "
|
|
169
|
+
var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
|
|
146
170
|
var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
|
|
147
171
|
"approval_not_required_by_policy",
|
|
148
172
|
"interactive_pending",
|
|
@@ -157,6 +181,8 @@ var CEAL_CAPABILITY_READINESS_VALUES = vocabulary(["ready", "degraded", "unavail
|
|
|
157
181
|
var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
|
|
158
182
|
var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
|
|
159
183
|
var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
|
|
184
|
+
var CEAL_GATEWAY_READ_REUSE_DISPOSITIONS = vocabulary(["response_cache_hit", "corpus_hit", "corpus_hit_after_revalidation", "corpus_partial_provider_supplement", "provider_direct", "provider_continuation", "reuse_unavailable"]);
|
|
185
|
+
var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
|
|
160
186
|
var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
|
|
161
187
|
var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
|
|
162
188
|
var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
|
|
@@ -429,8 +455,10 @@ function requireIsoTimestamp(value, message) {
|
|
|
429
455
|
var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
|
|
430
456
|
|
|
431
457
|
// packages/ceal-client-protocol/src/operation-contract-validation.ts
|
|
432
|
-
var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["
|
|
458
|
+
var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["access_group", "instance_binding", "target", "admission_recheck"]);
|
|
433
459
|
var MAX_OPERATION_INPUT_RESOLVER_BINDINGS = 96;
|
|
460
|
+
var CEAL_OPERATION_DESCRIPTOR_REQUIRED_ENVELOPE_KEYS = Object.freeze(["schema_version", "id", "input_contract", "result_contract", "policy"]);
|
|
461
|
+
var CEAL_OPERATION_DESCRIPTOR_OPTIONAL_ENVELOPE_KEYS = Object.freeze(["input_resolution", "summary"]);
|
|
434
462
|
var CEAL_OPERATION_RESULT_KEYS = vocabulary(["ok", "operation_id", "operation_receipt", "schema_version", "value"]);
|
|
435
463
|
var CEAL_OPERATION_COMPACT_RESULT_KEYS = vocabulary(["ok", "operation_evidence", "operation_id", "schema_version", "value"]);
|
|
436
464
|
|
|
@@ -504,6 +532,7 @@ var CEAL_SCHEMA_LITERALS = [
|
|
|
504
532
|
"ceal.operation_descriptor.v1",
|
|
505
533
|
"ceal.operation_error.v1",
|
|
506
534
|
"ceal.operation_failure.v1",
|
|
535
|
+
"ceal.operation_failure.compact.v1",
|
|
507
536
|
"ceal.operation_receipt.v1",
|
|
508
537
|
"ceal.operation_result.v1",
|
|
509
538
|
"ceal.operation_result.compact.v1",
|
|
@@ -529,17 +558,16 @@ var CEAL_BOUNDED_SERIES_CATALOG = Object.freeze({
|
|
|
529
558
|
engagement_signal: (root) => join(root, "runtime-state", "slack-feedback.jsonl"),
|
|
530
559
|
runtime_error: (root) => join(root, "runtime-state", "runtime-errors.jsonl"),
|
|
531
560
|
turn_bridge_request: (root) => join(root, ".ceal", "turn-bridge", "requests.jsonl"),
|
|
532
|
-
channel_log: (root) => join(root, "log.jsonl"),
|
|
533
561
|
thread_run_events: (root) => join(root, "run-events.jsonl"),
|
|
534
562
|
bounded_store_sidecar: (root) => `${root}.jsonl`,
|
|
535
563
|
gateway_audit_archive: (root) => `${root}.jsonl`,
|
|
536
564
|
gateway_capability_audit: (root) => join(root, "capability-audit.jsonl"),
|
|
537
565
|
gateway_retrieval_waste_partition: (root) => `${root}.jsonl`,
|
|
538
566
|
gateway_access_policy_publication: (root) => join(root, "access-policy-publications.jsonl"),
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
567
|
+
gateway_access_group_connector_control_audit: (root) => `${root}.audit.jsonl`,
|
|
568
|
+
gateway_access_group_connector_scope_audit: (root) => join(root, "profile-connector-scope-audit.jsonl"),
|
|
569
|
+
gateway_access_group_connector_activity_scope_audit: (root) => join(root, "profile-connector-activity-scope-audit.jsonl"),
|
|
570
|
+
gateway_access_group_connector_readiness_audit: (root) => join(root, "profile-connector-readiness.audit.jsonl"),
|
|
543
571
|
gateway_organization_audit_ledger: (root) => join(root, "organization-ledger.jsonl"),
|
|
544
572
|
gateway_personal_client_audit: (root) => join(root, "audit.jsonl"),
|
|
545
573
|
gateway_personal_client_access_audit: (root) => join(root, "access-audit.jsonl"),
|
|
@@ -590,12 +618,6 @@ var CEAL_AGENT_SESSION_COMMIT_KEYS = vocabulary(["attempt_ref", "expected_sessio
|
|
|
590
618
|
// packages/ceal-client-protocol/src/operation-next-actions.ts
|
|
591
619
|
var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
|
|
592
620
|
"select_did_you_mean",
|
|
593
|
-
// The graph, not the argument list, is what the caller must change: the
|
|
594
|
-
// resolver that owns this input has no producing node upstream, and no edit
|
|
595
|
-
// to the invocation can conjure one. `resolver_dependency_absent` carried no
|
|
596
|
-
// remedy at all rather than borrow a word that means something else, so the
|
|
597
|
-
// scorer read a fully-diagnosed, caller-fixable refusal as a failed run.
|
|
598
|
-
"request.graph.append",
|
|
599
621
|
"choose_new_output_path",
|
|
600
622
|
"choose_new_idempotency_key",
|
|
601
623
|
"restart_search",
|
|
@@ -647,8 +669,6 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
|
|
|
647
669
|
"reconcile_occurrence",
|
|
648
670
|
"reduce_request_size",
|
|
649
671
|
"repair_or_adopt_session",
|
|
650
|
-
"request.effect_approval.read",
|
|
651
|
-
"request.run",
|
|
652
672
|
"retry",
|
|
653
673
|
// The owner -- a correlation hook, an approval hook -- is not serving right
|
|
654
674
|
// now. The caller changes nothing and the same call succeeds once the owner
|
|
@@ -745,12 +765,12 @@ var CEAL_REQUEST_JSON_SCHEMA = {
|
|
|
745
765
|
additionalProperties: false,
|
|
746
766
|
properties: {
|
|
747
767
|
instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
748
|
-
|
|
768
|
+
access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
749
769
|
principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
750
770
|
execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
751
771
|
authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
|
|
752
772
|
},
|
|
753
|
-
required: ["instance_ref", "
|
|
773
|
+
required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
|
|
754
774
|
},
|
|
755
775
|
prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
756
776
|
host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
|
|
@@ -876,7 +896,7 @@ var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "mode
|
|
|
876
896
|
function isCealHostPromptObservationValue(value) {
|
|
877
897
|
return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
|
|
878
898
|
}
|
|
879
|
-
var HOST_RESERVED_KEY = /^(?:admission|approval|audit|authorization|cancellation|capability|effect|grant|occurrence|operation|policy|profile|provider_readback|receipt|reconciliation|replay|target|write_request)(?:_|$)/iu;
|
|
899
|
+
var HOST_RESERVED_KEY = /^(?:access_group|admission|approval|audit|authorization|cancellation|capability|effect|grant|occurrence|operation|policy|profile|provider_readback|receipt|reconciliation|replay|target|write_request)(?:_|$)/iu;
|
|
880
900
|
function assertHostObservationValue(value, kind) {
|
|
881
901
|
if (value === void 0) invalid("Ceal Host observation value is invalid.");
|
|
882
902
|
if (kind === "prompt" && !isCealHostPromptObservationValue(value)) invalid("Ceal Host prompt observation must contain only its body digest.");
|
|
@@ -896,6 +916,14 @@ function inspectHostKeys(value) {
|
|
|
896
916
|
}
|
|
897
917
|
}
|
|
898
918
|
|
|
919
|
+
// packages/ceal-client-protocol/src/host-prompt-ref.ts
|
|
920
|
+
var CEAL_HOST_PROMPT_DIGEST_PATTERN = "^[a-f0-9]{64}$";
|
|
921
|
+
var PROMPT_DIGEST = new RegExp(CEAL_HOST_PROMPT_DIGEST_PATTERN, "u");
|
|
922
|
+
function hostProducerPromptRef(promptSha256) {
|
|
923
|
+
if (!PROMPT_DIGEST.test(promptSha256)) throw new TypeError("Canonical Host prompt digest is invalid.");
|
|
924
|
+
return `ceal-host-prompt:${promptSha256}`;
|
|
925
|
+
}
|
|
926
|
+
|
|
899
927
|
// packages/ceal-client-protocol/src/request-effect-approval.ts
|
|
900
928
|
var CEAL_EFFECT_APPROVAL_DECISION_CHECK_PHRASES = Object.freeze([
|
|
901
929
|
"observed after this approval was raised and before it expires",
|
|
@@ -911,6 +939,12 @@ var OWNER_WRITE_STATES = Object.freeze(["attempt_started", "provider_acknowledge
|
|
|
911
939
|
var OWNER_EFFECT_STATES = Object.freeze(["none", "applied", "failed", "unknown", "reconciled"]);
|
|
912
940
|
var OWNER_RECEIPT_STATES = Object.freeze(["pending", "available", "failed", "unknown", "reconciled"]);
|
|
913
941
|
|
|
942
|
+
// packages/ceal-client-protocol/src/thread-excerpt.ts
|
|
943
|
+
var CEAL_THREAD_RECENT_WINDOW = 6;
|
|
944
|
+
var CEAL_THREAD_LAST_APP_MESSAGES_WINDOW = 3;
|
|
945
|
+
var CEAL_THREAD_OLDER_SUMMARY_WINDOW = 4;
|
|
946
|
+
var CEAL_FED_THREAD_MESSAGE_LIMIT = CEAL_THREAD_RECENT_WINDOW + CEAL_THREAD_OLDER_SUMMARY_WINDOW + CEAL_THREAD_LAST_APP_MESSAGES_WINDOW;
|
|
947
|
+
|
|
914
948
|
// packages/ceal-client-protocol/src/request-graph-readiness.ts
|
|
915
949
|
var REQUEST_GRAPH_PRODUCER_TO_APPEND_SCHEMA = {
|
|
916
950
|
type: "object",
|
|
@@ -1010,6 +1044,13 @@ function exactKeys(value, expected) {
|
|
|
1010
1044
|
var REQUIRED_FIELDS = Object.freeze(["schema_version", "operation_id", "local_path", "content_json_pointer", "size_bytes", "sha256", "read_argv"]);
|
|
1011
1045
|
var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS, "local_result_root", "model_disclosure"]);
|
|
1012
1046
|
|
|
1047
|
+
// packages/ceal-client-protocol/src/session-start-affordance.ts
|
|
1048
|
+
var CEAL_SESSION_ENTRY_INVOCATION = "ceal";
|
|
1049
|
+
var CEAL_LINK_RESOURCE_PRECEDENCE = `When the user asks to use Ceal or provides a link to information that may be available through installed organizational capabilities, run bare \`${CEAL_SESSION_ENTRY_INVOCATION}\`. The Host supplies the current user prompt without exposing it to the client command, and the Gateway returns the applicable entry in that one response. Treat a supplied link as a candidate Ceal resource rather than a public web-search target. Reach for a generic web fetch or web search only when the Gateway offered nothing.`;
|
|
1050
|
+
|
|
1051
|
+
// packages/ceal-client-protocol/src/discovery-manifest.ts
|
|
1052
|
+
var CEAL_DISCOVERY_MANIFEST_CONNECTOR_KINDS = vocabulary(["github", "google-workspace", "notion", "slack"]);
|
|
1053
|
+
|
|
1013
1054
|
// packages/ceal-client-protocol/src/conversation-contracts.ts
|
|
1014
1055
|
var CEAL_APPROVAL_POLICY_KINDS = vocabulary(["requester_only", "named_users", "role_based"]);
|
|
1015
1056
|
var CEAL_APPROVAL_TARGET_KINDS = vocabulary([
|
|
@@ -1226,7 +1267,7 @@ var CEAL_PRESENTATION_INTENTS = vocabulary(["progress", ...CEAL_FINAL_PRESENTATI
|
|
|
1226
1267
|
|
|
1227
1268
|
// packages/ceal-client-protocol/src/personal-client-vocabulary.ts
|
|
1228
1269
|
var CEAL_PERSONAL_CLIENT_BINDING_KEYS = vocabulary([
|
|
1229
|
-
"
|
|
1270
|
+
"access_group_ref",
|
|
1230
1271
|
"membership_ref",
|
|
1231
1272
|
"registration_ref",
|
|
1232
1273
|
"client_ref",
|
|
@@ -1241,7 +1282,8 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
|
|
|
1241
1282
|
"refresh_replayed",
|
|
1242
1283
|
"refresh_revoked",
|
|
1243
1284
|
"authority_replaced",
|
|
1244
|
-
"refresh_recovery_unavailable"
|
|
1285
|
+
"refresh_recovery_unavailable",
|
|
1286
|
+
"refresh_recovery_expired"
|
|
1245
1287
|
]);
|
|
1246
1288
|
|
|
1247
1289
|
// packages/ceal-client-protocol/src/device-enrollment.ts
|
|
@@ -1268,8 +1310,8 @@ function hostTerminalFailure(error, component) {
|
|
|
1268
1310
|
if (code === "ENOENT") return { code: "host_dependency_unavailable", message: `A command or file the ${component} Host needs is unavailable: ${detail}`, next_action: "Install the missing dependency or restore the missing file, then rerun this command." };
|
|
1269
1311
|
if (code === "EACCES" || code === "EPERM") return { code: "host_permission_denied", message: `The ${component} Host was refused access to a local path: ${detail}`, next_action: "Repair the ownership or mode of the named path, then rerun this command." };
|
|
1270
1312
|
if (code === "ENOSPC") return { code: "host_storage_unavailable", message: `The ${component} Host could not write local state: ${detail}`, next_action: "Free local disk space, then rerun this command." };
|
|
1271
|
-
if (code !== null && HOST_OWNED_CODE.test(code)) return { code, message: `The ${component} Host command failed: ${detail}`, next_action: `Resolve the named failure above; run \`ceal-host doctor
|
|
1272
|
-
return { code: "host_failure_unclassified", message: `The ${component} Host command failed for a cause it cannot classify: ${detail}`, next_action: `Run \`ceal-host doctor
|
|
1313
|
+
if (code !== null && HOST_OWNED_CODE.test(code)) return { code, message: `The ${component} Host command failed: ${detail}`, next_action: `Resolve the named failure above; run \`ceal-host doctor\` only if it reports installed ${component} Host drift.` };
|
|
1314
|
+
return { code: "host_failure_unclassified", message: `The ${component} Host command failed for a cause it cannot classify: ${detail}`, next_action: `Run \`ceal-host doctor\`; if it reports no drift then the ${component} Host configuration is not the cause, and the message above is the only evidence of what is.` };
|
|
1273
1315
|
}
|
|
1274
1316
|
var DOCTOR_FLAGS = Object.freeze({
|
|
1275
1317
|
"--expected-sha256": "expected_sha256",
|
|
@@ -1386,7 +1428,6 @@ var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
|
|
|
1386
1428
|
var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
|
|
1387
1429
|
var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
1388
1430
|
var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
1389
|
-
var DIGEST2 = /^[a-f0-9]{64}$/u;
|
|
1390
1431
|
var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
|
|
1391
1432
|
var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
|
|
1392
1433
|
var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
|
|
@@ -1450,10 +1491,6 @@ function hostProducerInputRef(hostSourceRef, frame, localSessionRef, localTurnRe
|
|
|
1450
1491
|
function hostProducerSubmissionRef(hostSourceRef, frame) {
|
|
1451
1492
|
return requiredIdentity(hostProducerIdentityRefs(hostSourceRef, frame).submission_ref);
|
|
1452
1493
|
}
|
|
1453
|
-
function hostProducerPromptRef(promptSha256) {
|
|
1454
|
-
if (!DIGEST2.test(promptSha256)) throw new TypeError("Canonical Host prompt digest is invalid.");
|
|
1455
|
-
return `ceal-host-prompt:${promptSha256}`;
|
|
1456
|
-
}
|
|
1457
1494
|
function opaqueHostSourceRef(value) {
|
|
1458
1495
|
return typeof value === "string" && SAFE_REF2.test(value) && !value.startsWith("ceal-host-source:");
|
|
1459
1496
|
}
|
|
@@ -1752,6 +1789,7 @@ function errorCode3(error) {
|
|
|
1752
1789
|
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
1753
1790
|
var PRODUCER_ORDER = ["codex", "claude"];
|
|
1754
1791
|
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
1792
|
+
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
1755
1793
|
var RelayAdmissionStore = class {
|
|
1756
1794
|
tail = Promise.resolve();
|
|
1757
1795
|
root;
|
|
@@ -1822,7 +1860,8 @@ var RelayAdmissionStore = class {
|
|
|
1822
1860
|
if (!head || head.retry_at_ms > options.now_ms) continue;
|
|
1823
1861
|
const input = { frame: structuredClone(head.frame), host_source_ref: options.host_source_ref, submission_ref: hostProducerSubmissionRef(options.host_source_ref, head.frame) };
|
|
1824
1862
|
const outcome = await deliver(input);
|
|
1825
|
-
|
|
1863
|
+
const exhausted = retryExhausted(outcome, head);
|
|
1864
|
+
if (outcome.status === "retryable" && !exhausted) {
|
|
1826
1865
|
scheduleRetry(head, options.now_ms, outcome.reason);
|
|
1827
1866
|
retained.push(input.submission_ref);
|
|
1828
1867
|
await this.write(state);
|
|
@@ -1830,9 +1869,9 @@ var RelayAdmissionStore = class {
|
|
|
1830
1869
|
}
|
|
1831
1870
|
const installation2 = state.installations[installationKey(head.frame)];
|
|
1832
1871
|
if (!installation2) throw new TypeError("Host Relay delivery installation is unavailable.");
|
|
1833
|
-
if (outcome.status === "refused") {
|
|
1872
|
+
if (outcome.status === "refused" || exhausted) {
|
|
1834
1873
|
await this.quarantine.retainFrame(head.frame, "gateway_refused");
|
|
1835
|
-
installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref,
|
|
1874
|
+
installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
|
|
1836
1875
|
refused.push(input.submission_ref);
|
|
1837
1876
|
} else {
|
|
1838
1877
|
await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
|
|
@@ -1866,6 +1905,14 @@ function replayCode(existing, hash, sequence, installation2) {
|
|
|
1866
1905
|
function bytes(entries) {
|
|
1867
1906
|
return entries.reduce((total, entry2) => total + entry2.charged_bytes, 0);
|
|
1868
1907
|
}
|
|
1908
|
+
function retryExhausted(outcome, entry2) {
|
|
1909
|
+
return outcome.status === "retryable" && entry2.retry_attempts >= MAX_RETRYABLE_ATTEMPTS;
|
|
1910
|
+
}
|
|
1911
|
+
function refusalCause(outcome, entry2) {
|
|
1912
|
+
if (outcome.status === "refused") return { code: outcome.code, message: outcome.message };
|
|
1913
|
+
const reason = outcome.status === "retryable" ? outcome.reason ?? "no reason reported" : "no reason reported";
|
|
1914
|
+
return { code: "retry_exhausted", message: `Gateway delivery stayed retryable through ${entry2.retry_attempts} attempts: ${reason}` };
|
|
1915
|
+
}
|
|
1869
1916
|
function scheduleRetry(entry2, nowMs, reason) {
|
|
1870
1917
|
if (reason === void 0) delete entry2.retry_reason;
|
|
1871
1918
|
else entry2.retry_reason = reason;
|
|
@@ -2622,6 +2669,52 @@ function acknowledgement(value) {
|
|
|
2622
2669
|
// host/relay/src/relay-ipc.ts
|
|
2623
2670
|
import { chmod, lstat as lstat3, unlink as unlink2 } from "node:fs/promises";
|
|
2624
2671
|
import { createConnection, createServer } from "node:net";
|
|
2672
|
+
|
|
2673
|
+
// host/relay/src/current-prompt-custody.ts
|
|
2674
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2675
|
+
var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
|
|
2676
|
+
var MAX_CURRENT_PROMPTS = 1024;
|
|
2677
|
+
var HostCurrentPromptCustody = class {
|
|
2678
|
+
#records = /* @__PURE__ */ new Map();
|
|
2679
|
+
#consumed = /* @__PURE__ */ new Map();
|
|
2680
|
+
#now;
|
|
2681
|
+
constructor(now = Date.now) {
|
|
2682
|
+
this.#now = now;
|
|
2683
|
+
}
|
|
2684
|
+
register(identity, prompt, expiresAt) {
|
|
2685
|
+
const bytes2 = Buffer.byteLength(prompt, "utf8");
|
|
2686
|
+
const expiry = Date.parse(expiresAt);
|
|
2687
|
+
if (bytes2 === 0 || bytes2 > HOST_CURRENT_PROMPT_MAX_BYTES || !Number.isFinite(expiry) || expiry <= this.#now()) throw new TypeError("current_prompt_unavailable");
|
|
2688
|
+
if (hostProducerPromptRef(createHash4("sha256").update(prompt, "utf8").digest("hex")) !== identity.prompt_ref) throw new TypeError("current_prompt_unavailable");
|
|
2689
|
+
this.#purge();
|
|
2690
|
+
const key = promptKey(identity);
|
|
2691
|
+
if (this.#consumed.has(key)) return;
|
|
2692
|
+
if (!this.#records.has(key) && this.#records.size + this.#consumed.size >= MAX_CURRENT_PROMPTS) throw new TypeError("current_prompt_unavailable");
|
|
2693
|
+
this.#records.set(key, { prompt, expires_at_ms: expiry });
|
|
2694
|
+
}
|
|
2695
|
+
/** Transfer this turn's prompt into at most one authenticated invocation. */
|
|
2696
|
+
take(identity) {
|
|
2697
|
+
this.#purge();
|
|
2698
|
+
const key = promptKey(identity);
|
|
2699
|
+
const prompt = this.#records.get(key)?.prompt;
|
|
2700
|
+
if (prompt !== void 0) {
|
|
2701
|
+
const expiresAt = this.#records.get(key)?.expires_at_ms;
|
|
2702
|
+
this.#records.delete(key);
|
|
2703
|
+
if (expiresAt !== void 0) this.#consumed.set(key, expiresAt);
|
|
2704
|
+
}
|
|
2705
|
+
return prompt;
|
|
2706
|
+
}
|
|
2707
|
+
#purge() {
|
|
2708
|
+
const now = this.#now();
|
|
2709
|
+
for (const [key, value] of this.#records) if (value.expires_at_ms <= now) this.#records.delete(key);
|
|
2710
|
+
for (const [key, expiresAt] of this.#consumed) if (expiresAt <= now) this.#consumed.delete(key);
|
|
2711
|
+
}
|
|
2712
|
+
};
|
|
2713
|
+
function promptKey(value) {
|
|
2714
|
+
return [value.producer_id, value.producer_installation_ref, value.local_session_ref, value.local_turn_ref, value.prompt_ref].join("\0");
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
// host/relay/src/relay-ipc.ts
|
|
2625
2718
|
var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
|
|
2626
2719
|
"schema_version",
|
|
2627
2720
|
"producer_id",
|
|
@@ -2642,6 +2735,8 @@ var HOST_RELAY_BINDING_QUERY_SCHEMA = "ceal.host_relay_binding_query.v1";
|
|
|
2642
2735
|
var HOST_RELAY_BINDING_RESULT_SCHEMA = "ceal.host_relay_binding_result.v1";
|
|
2643
2736
|
var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v1";
|
|
2644
2737
|
var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v1";
|
|
2738
|
+
var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
|
|
2739
|
+
var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
|
|
2645
2740
|
var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
2646
2741
|
var HostRelayIpcError = class extends Error {
|
|
2647
2742
|
code;
|
|
@@ -2655,7 +2750,8 @@ async function startHostRelayIpcServer(options) {
|
|
|
2655
2750
|
const active = /* @__PURE__ */ new Map();
|
|
2656
2751
|
const sockets = /* @__PURE__ */ new Set();
|
|
2657
2752
|
const quarantine = options.quarantine ?? options.admission.quarantine;
|
|
2658
|
-
const
|
|
2753
|
+
const currentPrompts = options.currentPrompts ?? new HostCurrentPromptCustody();
|
|
2754
|
+
const server = createServer((socket) => serveSocket(socket, options.admission, options.bindings, currentPrompts, options.mintInvocationContext, quarantine, active, sockets));
|
|
2659
2755
|
await listen(server, options.endpoint);
|
|
2660
2756
|
if (process.platform !== "win32") await chmod(options.endpoint, 384);
|
|
2661
2757
|
return { endpoint: options.endpoint, close: () => closeServer(server, sockets, options.endpoint) };
|
|
@@ -2667,12 +2763,12 @@ function encodeHostRelayIpcResponse(response2) {
|
|
|
2667
2763
|
body.copy(result2, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2668
2764
|
return result2;
|
|
2669
2765
|
}
|
|
2670
|
-
function serveSocket(socket, admission, bindings,
|
|
2671
|
-
const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve() };
|
|
2766
|
+
function serveSocket(socket, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active, sockets) {
|
|
2767
|
+
const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve(), abort: new AbortController() };
|
|
2672
2768
|
sockets.add(socket);
|
|
2673
2769
|
socket.on("data", (chunk) => {
|
|
2674
2770
|
state.buffer = Buffer.concat([state.buffer, Buffer.from(chunk)]);
|
|
2675
|
-
state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings,
|
|
2771
|
+
state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)).catch(() => {
|
|
2676
2772
|
writeResponse(socket, errorResponse("relay_unavailable"));
|
|
2677
2773
|
socket.end();
|
|
2678
2774
|
});
|
|
@@ -2680,24 +2776,26 @@ function serveSocket(socket, admission, bindings, mintInvocationContext, quarant
|
|
|
2680
2776
|
socket.once("error", () => closeConnection(socket, state, active, sockets));
|
|
2681
2777
|
socket.once("close", () => closeConnection(socket, state, active, sockets));
|
|
2682
2778
|
socket.once("end", () => {
|
|
2683
|
-
if (state.buffer.length > 0
|
|
2779
|
+
if (state.buffer.length > 0 && currentPromptWire(state.buffer)) {
|
|
2780
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2781
|
+
socket.end();
|
|
2782
|
+
} else if (state.buffer.length > 0) void quarantine.retainMalformed(state.buffer, "frame_truncated").finally(() => {
|
|
2684
2783
|
writeResponse(socket, errorResponse("frame_truncated"));
|
|
2685
2784
|
socket.end();
|
|
2686
2785
|
});
|
|
2687
2786
|
else socket.end();
|
|
2688
2787
|
});
|
|
2689
2788
|
}
|
|
2690
|
-
async function drainFrames(socket, state, admission, bindings,
|
|
2691
|
-
while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, admission, bindings,
|
|
2789
|
+
async function drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
|
|
2790
|
+
while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)) {
|
|
2692
2791
|
}
|
|
2693
2792
|
}
|
|
2694
|
-
async function processBufferedRequest(socket, state, admission, bindings,
|
|
2793
|
+
async function processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
|
|
2695
2794
|
const length = state.buffer.readUInt32BE(0);
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
await
|
|
2700
|
-
writeResponse(socket, errorResponse(code));
|
|
2795
|
+
const promptWire = currentPromptWire(state.buffer);
|
|
2796
|
+
const maximum = promptWire ? HOST_CURRENT_PROMPT_MAX_BYTES + 4096 : HOST_PRODUCER_MAX_JSON_BYTES;
|
|
2797
|
+
if (length === 0 || length > maximum) {
|
|
2798
|
+
await refuseInvalidBufferedRequest(socket, state.buffer, length, promptWire, quarantine);
|
|
2701
2799
|
state.buffer = Buffer.alloc(0);
|
|
2702
2800
|
socket.end();
|
|
2703
2801
|
return false;
|
|
@@ -2709,15 +2807,40 @@ async function processBufferedRequest(socket, state, admission, bindings, mintIn
|
|
|
2709
2807
|
try {
|
|
2710
2808
|
request2 = decodeIpcRequest(encoded);
|
|
2711
2809
|
} catch (error) {
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2810
|
+
await refuseMalformedRequest(socket, encoded, promptWire, error, quarantine);
|
|
2811
|
+
return true;
|
|
2812
|
+
}
|
|
2813
|
+
if (request2.schema_version === HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) {
|
|
2814
|
+
try {
|
|
2815
|
+
currentPrompts.register(request2, request2.current_prompt, request2.context_expires_at);
|
|
2816
|
+
writeCurrentPromptResponse(socket, "registered");
|
|
2817
|
+
} catch {
|
|
2818
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2819
|
+
}
|
|
2715
2820
|
return true;
|
|
2716
2821
|
}
|
|
2717
|
-
if (await processHostQuery(socket, request2, bindings,
|
|
2822
|
+
if (await processHostQuery(socket, request2, bindings, currentPrompts, mintInvocationContext2, state.abort.signal)) return true;
|
|
2718
2823
|
await processProducerRequest(socket, state, request2, encoded, admission, quarantine, active);
|
|
2719
2824
|
return true;
|
|
2720
2825
|
}
|
|
2826
|
+
async function refuseInvalidBufferedRequest(socket, rawBuffer, length, promptWire, quarantine) {
|
|
2827
|
+
if (promptWire) {
|
|
2828
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2829
|
+
return;
|
|
2830
|
+
}
|
|
2831
|
+
const code = length === 0 ? "invalid_frame_length" : "frame_too_large";
|
|
2832
|
+
await quarantine.retainMalformed(rawBuffer.subarray(0, Math.min(rawBuffer.length, length + HOST_RELAY_IPC_LENGTH_BYTES)), code);
|
|
2833
|
+
writeResponse(socket, errorResponse(code));
|
|
2834
|
+
}
|
|
2835
|
+
async function refuseMalformedRequest(socket, encoded, promptWire, error, quarantine) {
|
|
2836
|
+
if (promptWire) {
|
|
2837
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2838
|
+
return;
|
|
2839
|
+
}
|
|
2840
|
+
const code = error instanceof HostProducerFrameError ? error.code : "invalid_frame_shape";
|
|
2841
|
+
await quarantine.retainMalformed(encoded, code);
|
|
2842
|
+
writeResponse(socket, errorResponse(code));
|
|
2843
|
+
}
|
|
2721
2844
|
async function processProducerRequest(socket, state, request2, encoded, admission, quarantine, active) {
|
|
2722
2845
|
if (!("producer_epoch" in request2)) throw new HostRelayIpcError("relay_unavailable");
|
|
2723
2846
|
const ownership = claimProducer(socket, state, request2, active);
|
|
@@ -2729,13 +2852,13 @@ async function processProducerRequest(socket, state, request2, encoded, admissio
|
|
|
2729
2852
|
}
|
|
2730
2853
|
writeResponse(socket, admissionResponse(await admission.admit(request2)));
|
|
2731
2854
|
}
|
|
2732
|
-
async function processHostQuery(socket, request2, bindings, mint) {
|
|
2855
|
+
async function processHostQuery(socket, request2, bindings, currentPrompts, mint, signal) {
|
|
2733
2856
|
if (request2.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
|
|
2734
2857
|
writeBindingResponse(socket, await bindings.query(bindingQueryFromRequest(request2)));
|
|
2735
2858
|
return true;
|
|
2736
2859
|
}
|
|
2737
2860
|
if (request2.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
|
|
2738
|
-
writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, mint));
|
|
2861
|
+
writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, currentPrompts, mint, signal));
|
|
2739
2862
|
return true;
|
|
2740
2863
|
}
|
|
2741
2864
|
return false;
|
|
@@ -2755,6 +2878,7 @@ function claimProducer(socket, state, frame, active) {
|
|
|
2755
2878
|
}
|
|
2756
2879
|
function closeConnection(socket, state, active, sockets) {
|
|
2757
2880
|
state.closed = true;
|
|
2881
|
+
state.abort.abort();
|
|
2758
2882
|
sockets.delete(socket);
|
|
2759
2883
|
if (state.producer_key !== void 0 && active.get(state.producer_key)?.socket === socket) active.delete(state.producer_key);
|
|
2760
2884
|
}
|
|
@@ -2768,11 +2892,15 @@ function writeBindingResponse(socket, result2) {
|
|
|
2768
2892
|
function writeInvocationContextResponse(socket, response2) {
|
|
2769
2893
|
if (!socket.destroyed) socket.write(encodeLengthPrefixed(response2));
|
|
2770
2894
|
}
|
|
2771
|
-
|
|
2895
|
+
function writeCurrentPromptResponse(socket, status) {
|
|
2896
|
+
if (!socket.destroyed) socket.write(encodeLengthPrefixed({ schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status }));
|
|
2897
|
+
}
|
|
2898
|
+
async function resolveInvocationContext(request2, bindings, currentPrompts, mint, signal) {
|
|
2772
2899
|
if (mint === void 0) throw new HostRelayIpcError("relay_unavailable");
|
|
2773
2900
|
const binding = await bindings.query(bindingQueryFromRequest(request2));
|
|
2774
2901
|
if (binding.status !== "ready") return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, ...binding };
|
|
2775
|
-
const
|
|
2902
|
+
const currentPrompt = currentPrompts.take({ producer_id: request2.producer_id, producer_installation_ref: request2.producer_installation_ref, local_session_ref: request2.local_session_ref, local_turn_ref: request2.local_turn_ref, prompt_ref: binding.binding.prompt_ref });
|
|
2903
|
+
const result2 = await mint({ client_nonce: request2.client_nonce, context_expires_at: binding.binding.context_expires_at ?? binding.binding.bound_at, request_work_context: relayRequestWorkContextFromBinding(binding.binding), ...currentPrompt === void 0 ? {} : { current_prompt: currentPrompt } }, signal);
|
|
2776
2904
|
return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "ready", result: result2 };
|
|
2777
2905
|
}
|
|
2778
2906
|
function admissionResponse(result2) {
|
|
@@ -2788,16 +2916,29 @@ function record4(value) {
|
|
|
2788
2916
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2789
2917
|
}
|
|
2790
2918
|
function decodeIpcRequest(input) {
|
|
2791
|
-
const value = decodeLengthPrefixedJson(input, HOST_PRODUCER_MAX_JSON_BYTES);
|
|
2792
|
-
|
|
2919
|
+
const value = decodeLengthPrefixedJson(input, Math.max(HOST_PRODUCER_MAX_JSON_BYTES, HOST_CURRENT_PROMPT_MAX_BYTES + 4096));
|
|
2920
|
+
const local = decodeLocalRequest(value);
|
|
2921
|
+
if (local !== void 0) return local;
|
|
2922
|
+
return decodeHostProducerFrame(input);
|
|
2923
|
+
}
|
|
2924
|
+
function decodeLocalRequest(value) {
|
|
2925
|
+
if (!record4(value)) return void 0;
|
|
2926
|
+
if (value.schema_version === HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) {
|
|
2927
|
+
if (!validCurrentPromptRegisterRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
2928
|
+
return value;
|
|
2929
|
+
}
|
|
2930
|
+
if (value.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
|
|
2793
2931
|
if (!validBindingQueryRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
2794
2932
|
return value;
|
|
2795
2933
|
}
|
|
2796
|
-
if (value
|
|
2934
|
+
if (value.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
|
|
2797
2935
|
if (!validInvocationContextQueryRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
2798
2936
|
return value;
|
|
2799
2937
|
}
|
|
2800
|
-
return
|
|
2938
|
+
return void 0;
|
|
2939
|
+
}
|
|
2940
|
+
function validCurrentPromptRegisterRequest(value) {
|
|
2941
|
+
return validQueryIdentity(value, HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) && exactKeys4(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "prompt_ref", "current_prompt", "context_expires_at"]) && safeRef3(value.prompt_ref) && typeof value.current_prompt === "string" && Buffer.byteLength(value.current_prompt, "utf8") > 0 && Buffer.byteLength(value.current_prompt, "utf8") <= HOST_CURRENT_PROMPT_MAX_BYTES && validTimestamp2(value.context_expires_at);
|
|
2801
2942
|
}
|
|
2802
2943
|
function validBindingQueryRequest(value) {
|
|
2803
2944
|
return validQueryIdentity(value, HOST_RELAY_BINDING_QUERY_SCHEMA) && exactKeys4(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref"]);
|
|
@@ -2830,12 +2971,18 @@ function encodeLengthPrefixed(value) {
|
|
|
2830
2971
|
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2831
2972
|
return output;
|
|
2832
2973
|
}
|
|
2974
|
+
function currentPromptWire(value) {
|
|
2975
|
+
return value.subarray(HOST_RELAY_IPC_LENGTH_BYTES, Math.min(value.length, HOST_RELAY_IPC_LENGTH_BYTES + 128)).includes(Buffer.from(`"schema_version":"${HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA}"`, "utf8"));
|
|
2976
|
+
}
|
|
2833
2977
|
function exactKeys4(value, keys) {
|
|
2834
2978
|
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2835
2979
|
}
|
|
2836
2980
|
function safeRef3(value) {
|
|
2837
2981
|
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2838
2982
|
}
|
|
2983
|
+
function validTimestamp2(value) {
|
|
2984
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
2985
|
+
}
|
|
2839
2986
|
async function assertEndpointVacant(endpoint) {
|
|
2840
2987
|
try {
|
|
2841
2988
|
await lstat3(endpoint);
|
|
@@ -2931,7 +3078,7 @@ async function serveHostRelay(config, signal, dependencies = {}) {
|
|
|
2931
3078
|
} });
|
|
2932
3079
|
let server;
|
|
2933
3080
|
try {
|
|
2934
|
-
server = await (dependencies.startIpc ?? startHostRelayIpcServer)({ endpoint: config.ipc_endpoint, admission, bindings, mintInvocationContext: (input, invocationSignal) =>
|
|
3081
|
+
server = await (dependencies.startIpc ?? startHostRelayIpcServer)({ endpoint: config.ipc_endpoint, admission, bindings, mintInvocationContext: (input, invocationSignal) => mintInvocationContext(gateway, input, invocationSignal, config.gateway_timeout_ms, dependencies.observeInvocationMint ?? reportInvocationMint, dependencies.scheduleInvocationMintDeadline ?? scheduleInvocationMintDeadline) });
|
|
2935
3082
|
while (!signal.aborted) {
|
|
2936
3083
|
const round = await admission.drainRound((input) => bridge.deliver(input), { now_ms: (dependencies.now ?? Date.now)(), host_source_ref: config.host_source_ref });
|
|
2937
3084
|
if (round.delivered.length === 0 && round.refused.length === 0) await (dependencies.wait ?? ((milliseconds, waitSignal) => waitForAbort(waitSignal, milliseconds)))(config.drain_interval_ms, signal);
|
|
@@ -2940,6 +3087,41 @@ async function serveHostRelay(config, signal, dependencies = {}) {
|
|
|
2940
3087
|
await server?.close();
|
|
2941
3088
|
}
|
|
2942
3089
|
}
|
|
3090
|
+
async function mintInvocationContext(gateway, input, callerSignal, timeoutMs, observe, scheduleDeadline) {
|
|
3091
|
+
const controller2 = new AbortController();
|
|
3092
|
+
const started = process.hrtime.bigint();
|
|
3093
|
+
let cancellation = null;
|
|
3094
|
+
let outcome = "failed";
|
|
3095
|
+
const cancel = (cause) => {
|
|
3096
|
+
if (cancellation === null) cancellation = cause;
|
|
3097
|
+
controller2.abort();
|
|
3098
|
+
};
|
|
3099
|
+
const callerCancelled = () => cancel("caller_cancelled");
|
|
3100
|
+
const clearDeadline = scheduleDeadline(() => cancel("deadline"), timeoutMs);
|
|
3101
|
+
if (callerSignal.aborted) callerCancelled();
|
|
3102
|
+
else callerSignal.addEventListener("abort", callerCancelled, { once: true });
|
|
3103
|
+
const cancelled = new Promise((_resolve, reject) => controller2.signal.addEventListener("abort", () => reject(new Error("invocation mint cancelled")), { once: true }));
|
|
3104
|
+
try {
|
|
3105
|
+
const result2 = await Promise.race([gateway.mintInvocationContext(input, controller2.signal), cancelled]);
|
|
3106
|
+
outcome = "completed";
|
|
3107
|
+
return result2;
|
|
3108
|
+
} catch (error) {
|
|
3109
|
+
outcome = cancellation ?? "failed";
|
|
3110
|
+
throw error;
|
|
3111
|
+
} finally {
|
|
3112
|
+
clearDeadline();
|
|
3113
|
+
callerSignal.removeEventListener("abort", callerCancelled);
|
|
3114
|
+
observe({ outcome, elapsed_ms: Number((process.hrtime.bigint() - started) / 1000000n) });
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
function scheduleInvocationMintDeadline(expire, milliseconds) {
|
|
3118
|
+
const timeout = setTimeout(expire, milliseconds);
|
|
3119
|
+
return () => clearTimeout(timeout);
|
|
3120
|
+
}
|
|
3121
|
+
function reportInvocationMint(observation) {
|
|
3122
|
+
process.stderr.write(`[host-relay-invocation-mint] outcome=${observation.outcome} elapsed_ms=${observation.elapsed_ms}
|
|
3123
|
+
`);
|
|
3124
|
+
}
|
|
2943
3125
|
async function runHostRelayCli(args, signal, dependencies = {}) {
|
|
2944
3126
|
try {
|
|
2945
3127
|
const configPath = parseServeArgs(args);
|