@corca-org/ceal-host-win32-x64 1.0.7 → 1.0.9
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.exe +0 -0
- package/libexec/ceal-host/claude-hook.mjs +147 -45
- package/libexec/ceal-host/claude-invocation-authentication.mjs +99 -124
- package/libexec/ceal-host/claude-producer.mjs +74 -23
- package/libexec/ceal-host/codex-hook.mjs +146 -46
- package/libexec/ceal-host/codex-invocation-authentication.mjs +132 -128
- package/libexec/ceal-host/codex-producer.mjs +134 -31
- package/libexec/ceal-host/control.mjs +154 -38
- package/libexec/ceal-host/relay.mjs +236 -55
- 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",
|
|
@@ -1386,7 +1427,6 @@ var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
|
|
|
1386
1427
|
var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
|
|
1387
1428
|
var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
1388
1429
|
var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
1389
|
-
var DIGEST2 = /^[a-f0-9]{64}$/u;
|
|
1390
1430
|
var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
|
|
1391
1431
|
var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
|
|
1392
1432
|
var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
|
|
@@ -1450,10 +1490,6 @@ function hostProducerInputRef(hostSourceRef, frame, localSessionRef, localTurnRe
|
|
|
1450
1490
|
function hostProducerSubmissionRef(hostSourceRef, frame) {
|
|
1451
1491
|
return requiredIdentity(hostProducerIdentityRefs(hostSourceRef, frame).submission_ref);
|
|
1452
1492
|
}
|
|
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
1493
|
function opaqueHostSourceRef(value) {
|
|
1458
1494
|
return typeof value === "string" && SAFE_REF2.test(value) && !value.startsWith("ceal-host-source:");
|
|
1459
1495
|
}
|
|
@@ -1752,6 +1788,7 @@ function errorCode3(error) {
|
|
|
1752
1788
|
var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
|
|
1753
1789
|
var PRODUCER_ORDER = ["codex", "claude"];
|
|
1754
1790
|
var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
|
|
1791
|
+
var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
|
|
1755
1792
|
var RelayAdmissionStore = class {
|
|
1756
1793
|
tail = Promise.resolve();
|
|
1757
1794
|
root;
|
|
@@ -1822,7 +1859,8 @@ var RelayAdmissionStore = class {
|
|
|
1822
1859
|
if (!head || head.retry_at_ms > options.now_ms) continue;
|
|
1823
1860
|
const input = { frame: structuredClone(head.frame), host_source_ref: options.host_source_ref, submission_ref: hostProducerSubmissionRef(options.host_source_ref, head.frame) };
|
|
1824
1861
|
const outcome = await deliver(input);
|
|
1825
|
-
|
|
1862
|
+
const exhausted = retryExhausted(outcome, head);
|
|
1863
|
+
if (outcome.status === "retryable" && !exhausted) {
|
|
1826
1864
|
scheduleRetry(head, options.now_ms, outcome.reason);
|
|
1827
1865
|
retained.push(input.submission_ref);
|
|
1828
1866
|
await this.write(state);
|
|
@@ -1830,9 +1868,9 @@ var RelayAdmissionStore = class {
|
|
|
1830
1868
|
}
|
|
1831
1869
|
const installation2 = state.installations[installationKey(head.frame)];
|
|
1832
1870
|
if (!installation2) throw new TypeError("Host Relay delivery installation is unavailable.");
|
|
1833
|
-
if (outcome.status === "refused") {
|
|
1871
|
+
if (outcome.status === "refused" || exhausted) {
|
|
1834
1872
|
await this.quarantine.retainFrame(head.frame, "gateway_refused");
|
|
1835
|
-
installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref,
|
|
1873
|
+
installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
|
|
1836
1874
|
refused.push(input.submission_ref);
|
|
1837
1875
|
} else {
|
|
1838
1876
|
await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
|
|
@@ -1866,6 +1904,14 @@ function replayCode(existing, hash, sequence, installation2) {
|
|
|
1866
1904
|
function bytes(entries) {
|
|
1867
1905
|
return entries.reduce((total, entry2) => total + entry2.charged_bytes, 0);
|
|
1868
1906
|
}
|
|
1907
|
+
function retryExhausted(outcome, entry2) {
|
|
1908
|
+
return outcome.status === "retryable" && entry2.retry_attempts >= MAX_RETRYABLE_ATTEMPTS;
|
|
1909
|
+
}
|
|
1910
|
+
function refusalCause(outcome, entry2) {
|
|
1911
|
+
if (outcome.status === "refused") return { code: outcome.code, message: outcome.message };
|
|
1912
|
+
const reason = outcome.status === "retryable" ? outcome.reason ?? "no reason reported" : "no reason reported";
|
|
1913
|
+
return { code: "retry_exhausted", message: `Gateway delivery stayed retryable through ${entry2.retry_attempts} attempts: ${reason}` };
|
|
1914
|
+
}
|
|
1869
1915
|
function scheduleRetry(entry2, nowMs, reason) {
|
|
1870
1916
|
if (reason === void 0) delete entry2.retry_reason;
|
|
1871
1917
|
else entry2.retry_reason = reason;
|
|
@@ -2622,6 +2668,52 @@ function acknowledgement(value) {
|
|
|
2622
2668
|
// host/relay/src/relay-ipc.ts
|
|
2623
2669
|
import { chmod, lstat as lstat3, unlink as unlink2 } from "node:fs/promises";
|
|
2624
2670
|
import { createConnection, createServer } from "node:net";
|
|
2671
|
+
|
|
2672
|
+
// host/relay/src/current-prompt-custody.ts
|
|
2673
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2674
|
+
var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
|
|
2675
|
+
var MAX_CURRENT_PROMPTS = 1024;
|
|
2676
|
+
var HostCurrentPromptCustody = class {
|
|
2677
|
+
#records = /* @__PURE__ */ new Map();
|
|
2678
|
+
#consumed = /* @__PURE__ */ new Map();
|
|
2679
|
+
#now;
|
|
2680
|
+
constructor(now = Date.now) {
|
|
2681
|
+
this.#now = now;
|
|
2682
|
+
}
|
|
2683
|
+
register(identity, prompt, expiresAt) {
|
|
2684
|
+
const bytes2 = Buffer.byteLength(prompt, "utf8");
|
|
2685
|
+
const expiry = Date.parse(expiresAt);
|
|
2686
|
+
if (bytes2 === 0 || bytes2 > HOST_CURRENT_PROMPT_MAX_BYTES || !Number.isFinite(expiry) || expiry <= this.#now()) throw new TypeError("current_prompt_unavailable");
|
|
2687
|
+
if (hostProducerPromptRef(createHash4("sha256").update(prompt, "utf8").digest("hex")) !== identity.prompt_ref) throw new TypeError("current_prompt_unavailable");
|
|
2688
|
+
this.#purge();
|
|
2689
|
+
const key = promptKey(identity);
|
|
2690
|
+
if (this.#consumed.has(key)) return;
|
|
2691
|
+
if (!this.#records.has(key) && this.#records.size + this.#consumed.size >= MAX_CURRENT_PROMPTS) throw new TypeError("current_prompt_unavailable");
|
|
2692
|
+
this.#records.set(key, { prompt, expires_at_ms: expiry });
|
|
2693
|
+
}
|
|
2694
|
+
/** Transfer this turn's prompt into at most one authenticated invocation. */
|
|
2695
|
+
take(identity) {
|
|
2696
|
+
this.#purge();
|
|
2697
|
+
const key = promptKey(identity);
|
|
2698
|
+
const prompt = this.#records.get(key)?.prompt;
|
|
2699
|
+
if (prompt !== void 0) {
|
|
2700
|
+
const expiresAt = this.#records.get(key)?.expires_at_ms;
|
|
2701
|
+
this.#records.delete(key);
|
|
2702
|
+
if (expiresAt !== void 0) this.#consumed.set(key, expiresAt);
|
|
2703
|
+
}
|
|
2704
|
+
return prompt;
|
|
2705
|
+
}
|
|
2706
|
+
#purge() {
|
|
2707
|
+
const now = this.#now();
|
|
2708
|
+
for (const [key, value] of this.#records) if (value.expires_at_ms <= now) this.#records.delete(key);
|
|
2709
|
+
for (const [key, expiresAt] of this.#consumed) if (expiresAt <= now) this.#consumed.delete(key);
|
|
2710
|
+
}
|
|
2711
|
+
};
|
|
2712
|
+
function promptKey(value) {
|
|
2713
|
+
return [value.producer_id, value.producer_installation_ref, value.local_session_ref, value.local_turn_ref, value.prompt_ref].join("\0");
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
// host/relay/src/relay-ipc.ts
|
|
2625
2717
|
var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
|
|
2626
2718
|
"schema_version",
|
|
2627
2719
|
"producer_id",
|
|
@@ -2642,6 +2734,8 @@ var HOST_RELAY_BINDING_QUERY_SCHEMA = "ceal.host_relay_binding_query.v1";
|
|
|
2642
2734
|
var HOST_RELAY_BINDING_RESULT_SCHEMA = "ceal.host_relay_binding_result.v1";
|
|
2643
2735
|
var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v1";
|
|
2644
2736
|
var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v1";
|
|
2737
|
+
var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
|
|
2738
|
+
var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
|
|
2645
2739
|
var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
|
|
2646
2740
|
var HostRelayIpcError = class extends Error {
|
|
2647
2741
|
code;
|
|
@@ -2655,7 +2749,8 @@ async function startHostRelayIpcServer(options) {
|
|
|
2655
2749
|
const active = /* @__PURE__ */ new Map();
|
|
2656
2750
|
const sockets = /* @__PURE__ */ new Set();
|
|
2657
2751
|
const quarantine = options.quarantine ?? options.admission.quarantine;
|
|
2658
|
-
const
|
|
2752
|
+
const currentPrompts = options.currentPrompts ?? new HostCurrentPromptCustody();
|
|
2753
|
+
const server = createServer((socket) => serveSocket(socket, options.admission, options.bindings, currentPrompts, options.mintInvocationContext, quarantine, active, sockets));
|
|
2659
2754
|
await listen(server, options.endpoint);
|
|
2660
2755
|
if (process.platform !== "win32") await chmod(options.endpoint, 384);
|
|
2661
2756
|
return { endpoint: options.endpoint, close: () => closeServer(server, sockets, options.endpoint) };
|
|
@@ -2667,12 +2762,12 @@ function encodeHostRelayIpcResponse(response2) {
|
|
|
2667
2762
|
body.copy(result2, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2668
2763
|
return result2;
|
|
2669
2764
|
}
|
|
2670
|
-
function serveSocket(socket, admission, bindings,
|
|
2671
|
-
const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve() };
|
|
2765
|
+
function serveSocket(socket, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active, sockets) {
|
|
2766
|
+
const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve(), abort: new AbortController() };
|
|
2672
2767
|
sockets.add(socket);
|
|
2673
2768
|
socket.on("data", (chunk) => {
|
|
2674
2769
|
state.buffer = Buffer.concat([state.buffer, Buffer.from(chunk)]);
|
|
2675
|
-
state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings,
|
|
2770
|
+
state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)).catch(() => {
|
|
2676
2771
|
writeResponse(socket, errorResponse("relay_unavailable"));
|
|
2677
2772
|
socket.end();
|
|
2678
2773
|
});
|
|
@@ -2680,24 +2775,26 @@ function serveSocket(socket, admission, bindings, mintInvocationContext, quarant
|
|
|
2680
2775
|
socket.once("error", () => closeConnection(socket, state, active, sockets));
|
|
2681
2776
|
socket.once("close", () => closeConnection(socket, state, active, sockets));
|
|
2682
2777
|
socket.once("end", () => {
|
|
2683
|
-
if (state.buffer.length > 0
|
|
2778
|
+
if (state.buffer.length > 0 && currentPromptWire(state.buffer)) {
|
|
2779
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2780
|
+
socket.end();
|
|
2781
|
+
} else if (state.buffer.length > 0) void quarantine.retainMalformed(state.buffer, "frame_truncated").finally(() => {
|
|
2684
2782
|
writeResponse(socket, errorResponse("frame_truncated"));
|
|
2685
2783
|
socket.end();
|
|
2686
2784
|
});
|
|
2687
2785
|
else socket.end();
|
|
2688
2786
|
});
|
|
2689
2787
|
}
|
|
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,
|
|
2788
|
+
async function drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
|
|
2789
|
+
while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)) {
|
|
2692
2790
|
}
|
|
2693
2791
|
}
|
|
2694
|
-
async function processBufferedRequest(socket, state, admission, bindings,
|
|
2792
|
+
async function processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
|
|
2695
2793
|
const length = state.buffer.readUInt32BE(0);
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
await
|
|
2700
|
-
writeResponse(socket, errorResponse(code));
|
|
2794
|
+
const promptWire = currentPromptWire(state.buffer);
|
|
2795
|
+
const maximum = promptWire ? HOST_CURRENT_PROMPT_MAX_BYTES + 4096 : HOST_PRODUCER_MAX_JSON_BYTES;
|
|
2796
|
+
if (length === 0 || length > maximum) {
|
|
2797
|
+
await refuseInvalidBufferedRequest(socket, state.buffer, length, promptWire, quarantine);
|
|
2701
2798
|
state.buffer = Buffer.alloc(0);
|
|
2702
2799
|
socket.end();
|
|
2703
2800
|
return false;
|
|
@@ -2709,15 +2806,40 @@ async function processBufferedRequest(socket, state, admission, bindings, mintIn
|
|
|
2709
2806
|
try {
|
|
2710
2807
|
request2 = decodeIpcRequest(encoded);
|
|
2711
2808
|
} catch (error) {
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2809
|
+
await refuseMalformedRequest(socket, encoded, promptWire, error, quarantine);
|
|
2810
|
+
return true;
|
|
2811
|
+
}
|
|
2812
|
+
if (request2.schema_version === HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) {
|
|
2813
|
+
try {
|
|
2814
|
+
currentPrompts.register(request2, request2.current_prompt, request2.context_expires_at);
|
|
2815
|
+
writeCurrentPromptResponse(socket, "registered");
|
|
2816
|
+
} catch {
|
|
2817
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2818
|
+
}
|
|
2715
2819
|
return true;
|
|
2716
2820
|
}
|
|
2717
|
-
if (await processHostQuery(socket, request2, bindings,
|
|
2821
|
+
if (await processHostQuery(socket, request2, bindings, currentPrompts, mintInvocationContext2, state.abort.signal)) return true;
|
|
2718
2822
|
await processProducerRequest(socket, state, request2, encoded, admission, quarantine, active);
|
|
2719
2823
|
return true;
|
|
2720
2824
|
}
|
|
2825
|
+
async function refuseInvalidBufferedRequest(socket, rawBuffer, length, promptWire, quarantine) {
|
|
2826
|
+
if (promptWire) {
|
|
2827
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2830
|
+
const code = length === 0 ? "invalid_frame_length" : "frame_too_large";
|
|
2831
|
+
await quarantine.retainMalformed(rawBuffer.subarray(0, Math.min(rawBuffer.length, length + HOST_RELAY_IPC_LENGTH_BYTES)), code);
|
|
2832
|
+
writeResponse(socket, errorResponse(code));
|
|
2833
|
+
}
|
|
2834
|
+
async function refuseMalformedRequest(socket, encoded, promptWire, error, quarantine) {
|
|
2835
|
+
if (promptWire) {
|
|
2836
|
+
writeCurrentPromptResponse(socket, "current_prompt_unavailable");
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
const code = error instanceof HostProducerFrameError ? error.code : "invalid_frame_shape";
|
|
2840
|
+
await quarantine.retainMalformed(encoded, code);
|
|
2841
|
+
writeResponse(socket, errorResponse(code));
|
|
2842
|
+
}
|
|
2721
2843
|
async function processProducerRequest(socket, state, request2, encoded, admission, quarantine, active) {
|
|
2722
2844
|
if (!("producer_epoch" in request2)) throw new HostRelayIpcError("relay_unavailable");
|
|
2723
2845
|
const ownership = claimProducer(socket, state, request2, active);
|
|
@@ -2729,13 +2851,13 @@ async function processProducerRequest(socket, state, request2, encoded, admissio
|
|
|
2729
2851
|
}
|
|
2730
2852
|
writeResponse(socket, admissionResponse(await admission.admit(request2)));
|
|
2731
2853
|
}
|
|
2732
|
-
async function processHostQuery(socket, request2, bindings, mint) {
|
|
2854
|
+
async function processHostQuery(socket, request2, bindings, currentPrompts, mint, signal) {
|
|
2733
2855
|
if (request2.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
|
|
2734
2856
|
writeBindingResponse(socket, await bindings.query(bindingQueryFromRequest(request2)));
|
|
2735
2857
|
return true;
|
|
2736
2858
|
}
|
|
2737
2859
|
if (request2.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
|
|
2738
|
-
writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, mint));
|
|
2860
|
+
writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, currentPrompts, mint, signal));
|
|
2739
2861
|
return true;
|
|
2740
2862
|
}
|
|
2741
2863
|
return false;
|
|
@@ -2755,6 +2877,7 @@ function claimProducer(socket, state, frame, active) {
|
|
|
2755
2877
|
}
|
|
2756
2878
|
function closeConnection(socket, state, active, sockets) {
|
|
2757
2879
|
state.closed = true;
|
|
2880
|
+
state.abort.abort();
|
|
2758
2881
|
sockets.delete(socket);
|
|
2759
2882
|
if (state.producer_key !== void 0 && active.get(state.producer_key)?.socket === socket) active.delete(state.producer_key);
|
|
2760
2883
|
}
|
|
@@ -2768,11 +2891,15 @@ function writeBindingResponse(socket, result2) {
|
|
|
2768
2891
|
function writeInvocationContextResponse(socket, response2) {
|
|
2769
2892
|
if (!socket.destroyed) socket.write(encodeLengthPrefixed(response2));
|
|
2770
2893
|
}
|
|
2771
|
-
|
|
2894
|
+
function writeCurrentPromptResponse(socket, status) {
|
|
2895
|
+
if (!socket.destroyed) socket.write(encodeLengthPrefixed({ schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status }));
|
|
2896
|
+
}
|
|
2897
|
+
async function resolveInvocationContext(request2, bindings, currentPrompts, mint, signal) {
|
|
2772
2898
|
if (mint === void 0) throw new HostRelayIpcError("relay_unavailable");
|
|
2773
2899
|
const binding = await bindings.query(bindingQueryFromRequest(request2));
|
|
2774
2900
|
if (binding.status !== "ready") return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, ...binding };
|
|
2775
|
-
const
|
|
2901
|
+
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 });
|
|
2902
|
+
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
2903
|
return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "ready", result: result2 };
|
|
2777
2904
|
}
|
|
2778
2905
|
function admissionResponse(result2) {
|
|
@@ -2788,16 +2915,29 @@ function record4(value) {
|
|
|
2788
2915
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2789
2916
|
}
|
|
2790
2917
|
function decodeIpcRequest(input) {
|
|
2791
|
-
const value = decodeLengthPrefixedJson(input, HOST_PRODUCER_MAX_JSON_BYTES);
|
|
2792
|
-
|
|
2918
|
+
const value = decodeLengthPrefixedJson(input, Math.max(HOST_PRODUCER_MAX_JSON_BYTES, HOST_CURRENT_PROMPT_MAX_BYTES + 4096));
|
|
2919
|
+
const local = decodeLocalRequest(value);
|
|
2920
|
+
if (local !== void 0) return local;
|
|
2921
|
+
return decodeHostProducerFrame(input);
|
|
2922
|
+
}
|
|
2923
|
+
function decodeLocalRequest(value) {
|
|
2924
|
+
if (!record4(value)) return void 0;
|
|
2925
|
+
if (value.schema_version === HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) {
|
|
2926
|
+
if (!validCurrentPromptRegisterRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
2927
|
+
return value;
|
|
2928
|
+
}
|
|
2929
|
+
if (value.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
|
|
2793
2930
|
if (!validBindingQueryRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
2794
2931
|
return value;
|
|
2795
2932
|
}
|
|
2796
|
-
if (value
|
|
2933
|
+
if (value.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
|
|
2797
2934
|
if (!validInvocationContextQueryRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
|
|
2798
2935
|
return value;
|
|
2799
2936
|
}
|
|
2800
|
-
return
|
|
2937
|
+
return void 0;
|
|
2938
|
+
}
|
|
2939
|
+
function validCurrentPromptRegisterRequest(value) {
|
|
2940
|
+
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
2941
|
}
|
|
2802
2942
|
function validBindingQueryRequest(value) {
|
|
2803
2943
|
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 +2970,18 @@ function encodeLengthPrefixed(value) {
|
|
|
2830
2970
|
body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
|
|
2831
2971
|
return output;
|
|
2832
2972
|
}
|
|
2973
|
+
function currentPromptWire(value) {
|
|
2974
|
+
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"));
|
|
2975
|
+
}
|
|
2833
2976
|
function exactKeys4(value, keys) {
|
|
2834
2977
|
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2835
2978
|
}
|
|
2836
2979
|
function safeRef3(value) {
|
|
2837
2980
|
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
|
|
2838
2981
|
}
|
|
2982
|
+
function validTimestamp2(value) {
|
|
2983
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
2984
|
+
}
|
|
2839
2985
|
async function assertEndpointVacant(endpoint) {
|
|
2840
2986
|
try {
|
|
2841
2987
|
await lstat3(endpoint);
|
|
@@ -2931,7 +3077,7 @@ async function serveHostRelay(config, signal, dependencies = {}) {
|
|
|
2931
3077
|
} });
|
|
2932
3078
|
let server;
|
|
2933
3079
|
try {
|
|
2934
|
-
server = await (dependencies.startIpc ?? startHostRelayIpcServer)({ endpoint: config.ipc_endpoint, admission, bindings, mintInvocationContext: (input, invocationSignal) =>
|
|
3080
|
+
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
3081
|
while (!signal.aborted) {
|
|
2936
3082
|
const round = await admission.drainRound((input) => bridge.deliver(input), { now_ms: (dependencies.now ?? Date.now)(), host_source_ref: config.host_source_ref });
|
|
2937
3083
|
if (round.delivered.length === 0 && round.refused.length === 0) await (dependencies.wait ?? ((milliseconds, waitSignal) => waitForAbort(waitSignal, milliseconds)))(config.drain_interval_ms, signal);
|
|
@@ -2940,6 +3086,41 @@ async function serveHostRelay(config, signal, dependencies = {}) {
|
|
|
2940
3086
|
await server?.close();
|
|
2941
3087
|
}
|
|
2942
3088
|
}
|
|
3089
|
+
async function mintInvocationContext(gateway, input, callerSignal, timeoutMs, observe, scheduleDeadline) {
|
|
3090
|
+
const controller2 = new AbortController();
|
|
3091
|
+
const started = process.hrtime.bigint();
|
|
3092
|
+
let cancellation = null;
|
|
3093
|
+
let outcome = "failed";
|
|
3094
|
+
const cancel = (cause) => {
|
|
3095
|
+
if (cancellation === null) cancellation = cause;
|
|
3096
|
+
controller2.abort();
|
|
3097
|
+
};
|
|
3098
|
+
const callerCancelled = () => cancel("caller_cancelled");
|
|
3099
|
+
const clearDeadline = scheduleDeadline(() => cancel("deadline"), timeoutMs);
|
|
3100
|
+
if (callerSignal.aborted) callerCancelled();
|
|
3101
|
+
else callerSignal.addEventListener("abort", callerCancelled, { once: true });
|
|
3102
|
+
const cancelled = new Promise((_resolve, reject) => controller2.signal.addEventListener("abort", () => reject(new Error("invocation mint cancelled")), { once: true }));
|
|
3103
|
+
try {
|
|
3104
|
+
const result2 = await Promise.race([gateway.mintInvocationContext(input, controller2.signal), cancelled]);
|
|
3105
|
+
outcome = "completed";
|
|
3106
|
+
return result2;
|
|
3107
|
+
} catch (error) {
|
|
3108
|
+
outcome = cancellation ?? "failed";
|
|
3109
|
+
throw error;
|
|
3110
|
+
} finally {
|
|
3111
|
+
clearDeadline();
|
|
3112
|
+
callerSignal.removeEventListener("abort", callerCancelled);
|
|
3113
|
+
observe({ outcome, elapsed_ms: Number((process.hrtime.bigint() - started) / 1000000n) });
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
function scheduleInvocationMintDeadline(expire, milliseconds) {
|
|
3117
|
+
const timeout = setTimeout(expire, milliseconds);
|
|
3118
|
+
return () => clearTimeout(timeout);
|
|
3119
|
+
}
|
|
3120
|
+
function reportInvocationMint(observation) {
|
|
3121
|
+
process.stderr.write(`[host-relay-invocation-mint] outcome=${observation.outcome} elapsed_ms=${observation.elapsed_ms}
|
|
3122
|
+
`);
|
|
3123
|
+
}
|
|
2943
3124
|
async function runHostRelayCli(args, signal, dependencies = {}) {
|
|
2944
3125
|
try {
|
|
2945
3126
|
const configPath = parseServeArgs(args);
|