@parall/parall 1.63.0 → 1.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +6 -1
- package/dist/index.bundle.mjs +734 -284
- package/package.json +3 -3
- package/skills/parall-browser/SKILL.md +53 -0
- package/skills/parall-clips/SKILL.md +3 -6
- package/src/gateway.ts +6 -1
package/dist/index.bundle.mjs
CHANGED
|
@@ -52286,6 +52286,41 @@ function buildForkResultPrefix(results) {
|
|
|
52286
52286
|
return blocks.join("\n\n") + "\n\n---\n\n";
|
|
52287
52287
|
}
|
|
52288
52288
|
|
|
52289
|
+
// ../agent-core/dist/dispatch-recovery.js
|
|
52290
|
+
var DispatchRecovery = class {
|
|
52291
|
+
scan;
|
|
52292
|
+
stopped;
|
|
52293
|
+
onError;
|
|
52294
|
+
running = false;
|
|
52295
|
+
requested = false;
|
|
52296
|
+
constructor(scan, stopped, onError) {
|
|
52297
|
+
this.scan = scan;
|
|
52298
|
+
this.stopped = stopped;
|
|
52299
|
+
this.onError = onError;
|
|
52300
|
+
}
|
|
52301
|
+
request = () => {
|
|
52302
|
+
if (this.stopped())
|
|
52303
|
+
return;
|
|
52304
|
+
this.requested = true;
|
|
52305
|
+
if (this.running)
|
|
52306
|
+
return;
|
|
52307
|
+
this.running = true;
|
|
52308
|
+
void this.run();
|
|
52309
|
+
};
|
|
52310
|
+
async run() {
|
|
52311
|
+
try {
|
|
52312
|
+
while (this.requested && !this.stopped()) {
|
|
52313
|
+
this.requested = false;
|
|
52314
|
+
await this.scan();
|
|
52315
|
+
}
|
|
52316
|
+
} catch (err) {
|
|
52317
|
+
this.onError(err);
|
|
52318
|
+
} finally {
|
|
52319
|
+
this.running = false;
|
|
52320
|
+
}
|
|
52321
|
+
}
|
|
52322
|
+
};
|
|
52323
|
+
|
|
52289
52324
|
// ../agent-core/dist/gateway-base.js
|
|
52290
52325
|
import * as os from "node:os";
|
|
52291
52326
|
|
|
@@ -52325,6 +52360,7 @@ function browserViewerRequestOptions(command, opts) {
|
|
|
52325
52360
|
|
|
52326
52361
|
// ../sdk/dist/clip-connection-endpoints.js
|
|
52327
52362
|
var clipConnectionEndpoints = {
|
|
52363
|
+
ORG_CLIP_MCP_OAUTH_ATTEMPT: (orgId, clipId, attemptId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-oauth-attempts/${attemptId}`,
|
|
52328
52364
|
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
52329
52365
|
CLIP_CONNECTION_ACCESS: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}/access`,
|
|
52330
52366
|
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`
|
|
@@ -52625,6 +52661,7 @@ var ENDPOINTS = {
|
|
|
52625
52661
|
TRIGGER: (orgId, triggerId) => `${API_BASE2}/orgs/${orgId}/external-triggers/${triggerId}`,
|
|
52626
52662
|
/** @deprecated Use TRIGGER. Same compatibility path. */
|
|
52627
52663
|
EXTERNAL_TRIGGER: (orgId, triggerId) => `${API_BASE2}/orgs/${orgId}/external-triggers/${triggerId}`,
|
|
52664
|
+
PLATFORM_TRIGGER_SCHEMA: (orgId) => `${API_BASE2}/orgs/${orgId}/platform-trigger-schema`,
|
|
52628
52665
|
TRIGGER_RUNS: (orgId) => `${API_BASE2}/orgs/${orgId}/external-trigger-runs`,
|
|
52629
52666
|
/** @deprecated Use TRIGGER_RUNS. Same compatibility path. */
|
|
52630
52667
|
EXTERNAL_TRIGGER_RUNS: (orgId) => `${API_BASE2}/orgs/${orgId}/external-trigger-runs`,
|
|
@@ -52802,6 +52839,8 @@ var ENDPOINTS = {
|
|
|
52802
52839
|
BILLING_CHECKOUT: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/checkout`,
|
|
52803
52840
|
BILLING_AUTO_RELOAD: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/auto-reload`,
|
|
52804
52841
|
BILLING_SETUP_INTENT: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/setup-intent`,
|
|
52842
|
+
BILLING_USAGE_DAILY: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/usage-daily`,
|
|
52843
|
+
BILLING_USAGE_HEATMAP: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/usage-heatmap`,
|
|
52805
52844
|
COMPUTE_PRICING: () => `${API_BASE2}/billing/compute-pricing`,
|
|
52806
52845
|
// Runtime capability table (public, no auth) — SSOT for the create/settings
|
|
52807
52846
|
// interlock: per-runtime compute modes, native model family, cross-family
|
|
@@ -52836,16 +52875,6 @@ var ENDPOINTS = {
|
|
|
52836
52875
|
BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE2}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
|
|
52837
52876
|
// Edge device endpoints
|
|
52838
52877
|
...edgeEndpoints,
|
|
52839
|
-
ORG_BROWSER_ALIASES: (orgId) => `/api/v1/orgs/${orgId}/browser-aliases`,
|
|
52840
|
-
ORG_BROWSER_ALIAS: (orgId, aliasId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}`,
|
|
52841
|
-
ORG_BROWSER_ALIAS_READINESS_CHECKS: (orgId, aliasId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}/readiness-checks`,
|
|
52842
|
-
ORG_BROWSER_ALIAS_READINESS_CHECK: (orgId, aliasId, checkId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}/readiness-checks/${checkId}`,
|
|
52843
|
-
ORG_API_KEY_BROWSER_ALIAS_GRANTS: (orgId, keyId) => `/api/v1/orgs/${orgId}/api-keys/${keyId}/browser-alias-grants`,
|
|
52844
|
-
ORG_API_KEY_BROWSER_ALIAS_GRANT: (orgId, keyId, aliasId) => `/api/v1/orgs/${orgId}/api-keys/${keyId}/browser-alias-grants/${aliasId}`,
|
|
52845
|
-
ORG_MANAGED_ALIASES: (orgId) => `/api/v1/orgs/${orgId}/aliases`,
|
|
52846
|
-
ORG_MANAGED_ALIAS: (orgId, aliasName) => `/api/v1/orgs/${orgId}/aliases/${encodeURIComponent(aliasName)}`,
|
|
52847
|
-
ORG_BROWSER_ALIAS_EXECUTIONS: (orgId) => `/api/v1/orgs/${orgId}/executions`,
|
|
52848
|
-
ORG_BROWSER_ALIAS_EXECUTION: (orgId, requestId) => `/api/v1/orgs/${orgId}/executions/${encodeURIComponent(requestId)}`,
|
|
52849
52878
|
ORG_BROWSER_USE_OPERATIONS: (orgId) => `/api/v1/orgs/${orgId}/browser-use/operations`,
|
|
52850
52879
|
ORG_BROWSER_USE_OPERATION: (orgId, operationId) => `/api/v1/orgs/${orgId}/browser-use/operations/${encodeURIComponent(operationId)}`,
|
|
52851
52880
|
// Per-profile egress proxy (hosted Cloud Profiles; manager-only, human-only).
|
|
@@ -53392,10 +53421,62 @@ var ClipConnectionClient = class extends ChannelConversationClient {
|
|
|
53392
53421
|
async putClipConnectionAccess(orgId, connId, input) {
|
|
53393
53422
|
return this.request("PUT", ENDPOINTS.CLIP_CONNECTION_ACCESS(orgId, connId), input);
|
|
53394
53423
|
}
|
|
53424
|
+
/** Start OAuth using the reviewed platform app or provider registration ladder.
|
|
53425
|
+
* Allow discovery (30s), persistence (10s), and network overhead to finish. */
|
|
53426
|
+
async createClipMCPOAuthConnection(orgId, clipId, serverUrl, alias, oauthClient) {
|
|
53427
|
+
return this.request("POST", ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId), {
|
|
53428
|
+
server_url: serverUrl,
|
|
53429
|
+
auth_type: "oauth",
|
|
53430
|
+
...alias ? { alias } : {},
|
|
53431
|
+
...oauthClient ? { oauth_client: oauthClient } : {}
|
|
53432
|
+
}, void 0, false, { timeoutMs: 5e4 });
|
|
53433
|
+
}
|
|
53434
|
+
/** Cancel exactly one pending attempt; requires its initiator or an org admin. */
|
|
53435
|
+
async cancelClipMCPOAuthAttempt(orgId, clipId, attemptId) {
|
|
53436
|
+
return this.request("DELETE", ENDPOINTS.ORG_CLIP_MCP_OAUTH_ATTEMPT(orgId, clipId, attemptId));
|
|
53437
|
+
}
|
|
53395
53438
|
};
|
|
53396
53439
|
|
|
53397
53440
|
// ../sdk/dist/browser-profile-client.js
|
|
53398
53441
|
var BrowserProfileClient = class extends ClipConnectionClient {
|
|
53442
|
+
/** Metadata-only compatibility discovery. Management scope errors propagate;
|
|
53443
|
+
* callers with a known Profile can execute without this discovery chain. */
|
|
53444
|
+
async listBrowserUseProfiles(orgId, profileId) {
|
|
53445
|
+
const me = await this.request("GET", ENDPOINTS.USERS_ME);
|
|
53446
|
+
const devices = await this.request("GET", ENDPOINTS.ORG_EDGE_DEVICES(orgId));
|
|
53447
|
+
const data = [];
|
|
53448
|
+
for (const device of devices.data) {
|
|
53449
|
+
const personal = device.managed_by === "member";
|
|
53450
|
+
if (personal && device.owner_user_id !== me.id)
|
|
53451
|
+
continue;
|
|
53452
|
+
const profiles = await this.request("GET", ENDPOINTS.ORG_EDGE_PROFILES(orgId, device.id));
|
|
53453
|
+
for (const profile of profiles) {
|
|
53454
|
+
if (profileId && profile.id !== profileId)
|
|
53455
|
+
continue;
|
|
53456
|
+
const access = personal ? null : await this.getBrowserProfileAccess(orgId, device.id, profile.name);
|
|
53457
|
+
if (!personal && !access?.org_public && !(access?.grants ?? []).some((g) => g.user_id === me.id && g.grants.length > 0))
|
|
53458
|
+
continue;
|
|
53459
|
+
data.push({
|
|
53460
|
+
profile_id: profile.id,
|
|
53461
|
+
name: profile.name,
|
|
53462
|
+
device_name: device.name,
|
|
53463
|
+
placement: device.placement ?? "byoc",
|
|
53464
|
+
lifecycle_state: profile.lifecycle_state,
|
|
53465
|
+
can_access: true,
|
|
53466
|
+
availability: device.placement === "hosted" ? device.hosted_state ?? "unknown" : device.status
|
|
53467
|
+
});
|
|
53468
|
+
}
|
|
53469
|
+
}
|
|
53470
|
+
return { data };
|
|
53471
|
+
}
|
|
53472
|
+
/** Submit once: even refresh-enabled clients must not replay browser actions. */
|
|
53473
|
+
async createBrowserUseOperation(orgId, request3) {
|
|
53474
|
+
return this.request("POST", ENDPOINTS.ORG_BROWSER_USE_OPERATIONS(orgId), request3, void 0, true);
|
|
53475
|
+
}
|
|
53476
|
+
/** Recover proof/data without creating a new browser operation. */
|
|
53477
|
+
async getBrowserUseOperation(orgId, operationId, opts) {
|
|
53478
|
+
return this.request("GET", ENDPOINTS.ORG_BROWSER_USE_OPERATION(orgId, operationId), void 0, void 0, false, opts);
|
|
53479
|
+
}
|
|
53399
53480
|
async getBrowserProfileAccess(orgId, edgeId, profileName) {
|
|
53400
53481
|
return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILE_ACCESS(orgId, edgeId, profileName));
|
|
53401
53482
|
}
|
|
@@ -53839,8 +53920,8 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
53839
53920
|
return this.request("POST", ENDPOINTS.AUTH_OAUTH_EXCHANGE, { code });
|
|
53840
53921
|
}
|
|
53841
53922
|
// ---- WebSocket ----
|
|
53842
|
-
async getWsTicket() {
|
|
53843
|
-
return this.request("POST", ENDPOINTS.WS_TICKET);
|
|
53923
|
+
async getWsTicket(req) {
|
|
53924
|
+
return this.request("POST", ENDPOINTS.WS_TICKET, req);
|
|
53844
53925
|
}
|
|
53845
53926
|
// ---- Users ----
|
|
53846
53927
|
async getMe() {
|
|
@@ -54827,8 +54908,8 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
54827
54908
|
* no_action sweep otherwise. Idempotent.
|
|
54828
54909
|
*
|
|
54829
54910
|
* @deprecated Legacy ok-only alias — use {@link completeDispatch} with the
|
|
54830
|
-
* `sources` form, which also carries `turn_outcome`.
|
|
54831
|
-
*
|
|
54911
|
+
* `sources` form, which also carries `turn_outcome`. Retirement conditions:
|
|
54912
|
+
* agent-dispatch-idempotency-design.md#compatibility.
|
|
54832
54913
|
*/
|
|
54833
54914
|
async completeDispatchSources(orgId, req) {
|
|
54834
54915
|
return this.request("POST", ENDPOINTS.DISPATCH_COMPLETE_SOURCES(orgId), req);
|
|
@@ -55071,6 +55152,9 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
55071
55152
|
async getTriggerSchema(orgId, connectionId) {
|
|
55072
55153
|
return this.request("GET", ENDPOINTS.TRIGGER_SCHEMA(orgId, connectionId));
|
|
55073
55154
|
}
|
|
55155
|
+
async getPlatformTriggerSchema(orgId, eventTypes) {
|
|
55156
|
+
return this.request("GET", ENDPOINTS.PLATFORM_TRIGGER_SCHEMA(orgId), void 0, eventTypes && eventTypes.length > 0 ? { event_types: eventTypes.join(",") } : void 0);
|
|
55157
|
+
}
|
|
55074
55158
|
async listTriggerIngressEvents(orgId, filters) {
|
|
55075
55159
|
return this.request("GET", ENDPOINTS.TRIGGER_INGRESS_EVENTS(orgId), void 0, filters);
|
|
55076
55160
|
}
|
|
@@ -55172,8 +55256,8 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
55172
55256
|
return url;
|
|
55173
55257
|
return `${this.baseUrlFor(url)}${url}`;
|
|
55174
55258
|
}
|
|
55175
|
-
async getWikiBlob(orgId, wikiId, params) {
|
|
55176
|
-
const blob = await this.request("GET", ENDPOINTS.WIKI_BLOB(orgId, wikiId), void 0, params);
|
|
55259
|
+
async getWikiBlob(orgId, wikiId, params, opts) {
|
|
55260
|
+
const blob = await this.request("GET", ENDPOINTS.WIKI_BLOB(orgId, wikiId), void 0, params, false, opts);
|
|
55177
55261
|
if (blob.signed_url)
|
|
55178
55262
|
blob.signed_url = this.absoluteMediaUrl(blob.signed_url);
|
|
55179
55263
|
return blob;
|
|
@@ -55546,6 +55630,21 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
55546
55630
|
async getBilling(orgId) {
|
|
55547
55631
|
return this.request("GET", ENDPOINTS.BILLING(orgId));
|
|
55548
55632
|
}
|
|
55633
|
+
async getUsageDaily(orgId, opts) {
|
|
55634
|
+
const params = new URLSearchParams();
|
|
55635
|
+
params.set("start_date", opts.start_date);
|
|
55636
|
+
params.set("end_date", opts.end_date);
|
|
55637
|
+
return this.request("GET", `${ENDPOINTS.BILLING_USAGE_DAILY(orgId)}?${params}`);
|
|
55638
|
+
}
|
|
55639
|
+
async getUsageHeatmap(orgId, opts) {
|
|
55640
|
+
const params = new URLSearchParams();
|
|
55641
|
+
params.set("start_time", opts.start_time);
|
|
55642
|
+
if (opts.limit != null)
|
|
55643
|
+
params.set("limit", String(opts.limit));
|
|
55644
|
+
if (opts.offset != null)
|
|
55645
|
+
params.set("offset", String(opts.offset));
|
|
55646
|
+
return this.request("GET", `${ENDPOINTS.BILLING_USAGE_HEATMAP(orgId)}?${params}`);
|
|
55647
|
+
}
|
|
55549
55648
|
async listBillingTransactions(orgId, opts) {
|
|
55550
55649
|
const params = new URLSearchParams();
|
|
55551
55650
|
if (opts?.cursor)
|
|
@@ -55715,12 +55814,14 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
55715
55814
|
}
|
|
55716
55815
|
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
55717
55816
|
/**
|
|
55718
|
-
* List registry clips visible to the org: its own plus
|
|
55719
|
-
* cross-org entries
|
|
55720
|
-
* connections operate on.
|
|
55817
|
+
* List one page of registry clips visible to the org: its own plus
|
|
55818
|
+
* public+approved cross-org entries, used by installs and connections.
|
|
55721
55819
|
*/
|
|
55722
|
-
async listOrgRegistryClips(orgId) {
|
|
55723
|
-
const
|
|
55820
|
+
async listOrgRegistryClips(orgId, opts) {
|
|
55821
|
+
const params = new URLSearchParams({ limit: String(opts?.limit ?? 100) });
|
|
55822
|
+
if (opts?.offset !== void 0)
|
|
55823
|
+
params.set("offset", String(opts.offset));
|
|
55824
|
+
const resp = await this.request("GET", `${ENDPOINTS.ORG_CLIP_REGISTRY(orgId)}?${params}`);
|
|
55724
55825
|
return resp ?? [];
|
|
55725
55826
|
}
|
|
55726
55827
|
/**
|
|
@@ -55801,7 +55902,6 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
55801
55902
|
/**
|
|
55802
55903
|
* Read a clip's per-org exec access (by user id — humans and agents alike).
|
|
55803
55904
|
* Org-member readable, so a denied caller can learn why exec answered
|
|
55804
|
-
* `CONNECTION_NOT_ALLOWED` (retired: `CLIP_NOT_ALLOWED` / `CLIP_CONNECTION_NOT_ALLOWED`) (agents:
|
|
55805
55905
|
* `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED`). Writing
|
|
55806
55906
|
* it (`putClipAgentExecAccess`) is an org owner/admin's act.
|
|
55807
55907
|
*/
|
|
@@ -55882,69 +55982,6 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
55882
55982
|
async getEdgeProfileOperation(orgId, edgeId, operationId) {
|
|
55883
55983
|
return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILE_OPERATION(orgId, edgeId, operationId));
|
|
55884
55984
|
}
|
|
55885
|
-
/** Create and atomically materialize one Local BYOC Browser Alias. A replay
|
|
55886
|
-
* with the same idempotency key and body returns the original stable ccn_. */
|
|
55887
|
-
async createBrowserAlias(orgId, request3) {
|
|
55888
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIASES(orgId), request3);
|
|
55889
|
-
}
|
|
55890
|
-
async listBrowserAliases(orgId) {
|
|
55891
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIASES(orgId));
|
|
55892
|
-
}
|
|
55893
|
-
async getBrowserAlias(orgId, aliasId) {
|
|
55894
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId));
|
|
55895
|
-
}
|
|
55896
|
-
async renameBrowserAlias(orgId, aliasId, request3) {
|
|
55897
|
-
return this.request("PATCH", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId), request3);
|
|
55898
|
-
}
|
|
55899
|
-
async deleteBrowserAlias(orgId, aliasId, request3) {
|
|
55900
|
-
return this.request("DELETE", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId), request3);
|
|
55901
|
-
}
|
|
55902
|
-
/** Start one durable readiness check. The key is carried as the standard
|
|
55903
|
-
* Idempotency-Key header; the request body is intentionally empty. */
|
|
55904
|
-
async createBrowserAliasReadinessCheck(orgId, aliasId, request3) {
|
|
55905
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIAS_READINESS_CHECKS(orgId, aliasId), void 0, void 0, false, { headers: { "Idempotency-Key": request3.idempotency_key } });
|
|
55906
|
-
}
|
|
55907
|
-
/** Sole durable recovery surface for one readiness request. */
|
|
55908
|
-
async getBrowserAliasReadinessCheck(orgId, aliasId, checkId) {
|
|
55909
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_READINESS_CHECK(orgId, aliasId, checkId));
|
|
55910
|
-
}
|
|
55911
|
-
/** Organization Owner view. Hashes, reviewed snapshots and deltas are
|
|
55912
|
-
* intentionally available only on this human-JWT management surface. */
|
|
55913
|
-
async listBrowserAliasGrants(orgId, keyId) {
|
|
55914
|
-
return this.request("GET", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANTS(orgId, keyId));
|
|
55915
|
-
}
|
|
55916
|
-
async getBrowserAliasGrant(orgId, keyId, aliasId) {
|
|
55917
|
-
return this.request("GET", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANT(orgId, keyId, aliasId));
|
|
55918
|
-
}
|
|
55919
|
-
async replaceBrowserAliasGrant(orgId, keyId, aliasId, request3) {
|
|
55920
|
-
return this.request("PUT", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANT(orgId, keyId, aliasId), request3);
|
|
55921
|
-
}
|
|
55922
|
-
/** Managed-key discovery. The response is already grant-filtered and never
|
|
55923
|
-
* carries contract hashes, review snapshots, Edge IDs or Profile IDs. */
|
|
55924
|
-
async listManagedBrowserAliases(orgId) {
|
|
55925
|
-
return this.request("GET", ENDPOINTS.ORG_MANAGED_ALIASES(orgId));
|
|
55926
|
-
}
|
|
55927
|
-
async getManagedBrowserAlias(orgId, aliasName) {
|
|
55928
|
-
return this.request("GET", ENDPOINTS.ORG_MANAGED_ALIAS(orgId, aliasName));
|
|
55929
|
-
}
|
|
55930
|
-
/** Accept and dispatch one @alias command. request_id is generated by the
|
|
55931
|
-
* caller before local validation and is also the sole durable recovery key. */
|
|
55932
|
-
async createBrowserAliasExecution(orgId, request3) {
|
|
55933
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTIONS(orgId), request3);
|
|
55934
|
-
}
|
|
55935
|
-
async getBrowserAliasExecution(orgId, requestId) {
|
|
55936
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTION(orgId, requestId));
|
|
55937
|
-
}
|
|
55938
|
-
/** Accept one idempotent Browser Use operation for an explicit Profile.
|
|
55939
|
-
* JWT, personal, agent and managed keys use profile access. The Server resolves Profile→Edge. */
|
|
55940
|
-
async createBrowserUseOperation(orgId, request3) {
|
|
55941
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_USE_OPERATIONS(orgId), request3);
|
|
55942
|
-
}
|
|
55943
|
-
/** Recover the durable receipt. Successful data is present only inside the
|
|
55944
|
-
* Server's short encrypted result TTL; terminal proof remains afterwards. */
|
|
55945
|
-
async getBrowserUseOperation(orgId, operationId) {
|
|
55946
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_USE_OPERATION(orgId, operationId));
|
|
55947
|
-
}
|
|
55948
55985
|
/**
|
|
55949
55986
|
* Read a hosted Cloud Profile's egress-proxy status (manager-only: hosted
|
|
55950
55987
|
* human maintainer or org admin). Sanitized — the password never comes back.
|
|
@@ -56054,7 +56091,6 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
56054
56091
|
* - `EDGE_HOSTED_DISABLED_FOR_ORG` 403, `EDGE_REPAIR` 503 (operator-held),
|
|
56055
56092
|
* `EDGE_RUNTIME_UNAVAILABLE` 503 (deployment has no hosted runtime).
|
|
56056
56093
|
* - Access errors (before side effects): human `CONNECTION_NOT_ALLOWED`.
|
|
56057
|
-
* `CLIP_NOT_ALLOWED` / `CLIP_CONNECTION_NOT_ALLOWED` are retired.
|
|
56058
56094
|
* Agent principals receive the historical
|
|
56059
56095
|
* `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED` for one
|
|
56060
56096
|
* release. An org owner/admin can widen access in the clip's settings.
|
|
@@ -56138,17 +56174,6 @@ var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
|
56138
56174
|
timeoutMs: 4e4
|
|
56139
56175
|
});
|
|
56140
56176
|
}
|
|
56141
|
-
/** Start a new Official OAuth MCP connection with the platform-owned app.
|
|
56142
|
-
* Omitting oauth_client is load-bearing: the server resolves the exact
|
|
56143
|
-
* reviewed-version binding and never falls back to DCR/CIMD cross-org. */
|
|
56144
|
-
async createClipMCPOAuthConnection(orgId, clipId, serverUrl, alias, oauthClient) {
|
|
56145
|
-
return this.request("POST", ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId), {
|
|
56146
|
-
server_url: serverUrl,
|
|
56147
|
-
auth_type: "oauth",
|
|
56148
|
-
...alias ? { alias } : {},
|
|
56149
|
-
...oauthClient ? { oauth_client: oauthClient } : {}
|
|
56150
|
-
});
|
|
56151
|
-
}
|
|
56152
56177
|
/** Re-authorize an existing MCP credential slot. */
|
|
56153
56178
|
async initiateClipMCPOAuthById(orgId, clipId, configId, serverUrl, expectedVersion, oauthClient) {
|
|
56154
56179
|
const req = {
|
|
@@ -56337,6 +56362,11 @@ function describeWsStateDetail(detail) {
|
|
|
56337
56362
|
function isRetryableNetworkError(err) {
|
|
56338
56363
|
return err instanceof Error && err.name === "ApiError" && "status" in err && err.status === 0;
|
|
56339
56364
|
}
|
|
56365
|
+
function authRejectionFrom(err) {
|
|
56366
|
+
if (!(err instanceof ApiError) || err.status !== 401)
|
|
56367
|
+
return null;
|
|
56368
|
+
return { status: err.status, code: err.code, message: err.message };
|
|
56369
|
+
}
|
|
56340
56370
|
function isBrowserRuntime() {
|
|
56341
56371
|
return typeof window !== "undefined";
|
|
56342
56372
|
}
|
|
@@ -56345,9 +56375,12 @@ var ParallWs = class {
|
|
|
56345
56375
|
options;
|
|
56346
56376
|
listeners = /* @__PURE__ */ new Map();
|
|
56347
56377
|
stateListeners = /* @__PURE__ */ new Set();
|
|
56378
|
+
authInvalidListeners = /* @__PURE__ */ new Set();
|
|
56348
56379
|
heartbeatTimer = null;
|
|
56349
56380
|
reconnectTimer = null;
|
|
56350
56381
|
reconnectAttempts = 0;
|
|
56382
|
+
/** Ticket attempts in the current auth-invalid episode (reset on success). */
|
|
56383
|
+
authAttempts = 0;
|
|
56351
56384
|
lastSeq = 0;
|
|
56352
56385
|
_state = "disconnected";
|
|
56353
56386
|
intentionalClose = false;
|
|
@@ -56360,6 +56393,7 @@ var ParallWs = class {
|
|
|
56360
56393
|
reconnect: true,
|
|
56361
56394
|
reconnectInterval: 1e3,
|
|
56362
56395
|
maxReconnectInterval: 3e4,
|
|
56396
|
+
maxAuthAttempts: 3,
|
|
56363
56397
|
...options
|
|
56364
56398
|
};
|
|
56365
56399
|
this.lastSeq = options.lastSeq ?? 0;
|
|
@@ -56369,12 +56403,25 @@ var ParallWs = class {
|
|
|
56369
56403
|
}
|
|
56370
56404
|
async connect() {
|
|
56371
56405
|
this.intentionalClose = false;
|
|
56406
|
+
if (this._state === "auth-invalid")
|
|
56407
|
+
this.authAttempts = 0;
|
|
56372
56408
|
this.setupBrowserListeners();
|
|
56373
56409
|
this.setState("connecting");
|
|
56374
56410
|
let ticket;
|
|
56375
56411
|
try {
|
|
56376
56412
|
ticket = await this.options.getTicket();
|
|
56377
56413
|
} catch (err) {
|
|
56414
|
+
const authRejection = authRejectionFrom(err);
|
|
56415
|
+
if (authRejection) {
|
|
56416
|
+
this.authAttempts += 1;
|
|
56417
|
+
if (this.authAttempts < this.options.maxAuthAttempts && this.options.reconnect) {
|
|
56418
|
+
console.warn(`WS ticket auth rejected (attempt ${this.authAttempts}/${this.options.maxAuthAttempts}):`, err);
|
|
56419
|
+
this.scheduleReconnect({ cause: "ticket_failed" });
|
|
56420
|
+
} else {
|
|
56421
|
+
this.enterAuthInvalid(authRejection);
|
|
56422
|
+
}
|
|
56423
|
+
return;
|
|
56424
|
+
}
|
|
56378
56425
|
if (isBrowserRuntime() && isRetryableNetworkError(err)) {
|
|
56379
56426
|
console.warn("Failed to get WS ticket:", err);
|
|
56380
56427
|
} else {
|
|
@@ -56421,6 +56468,7 @@ var ParallWs = class {
|
|
|
56421
56468
|
this.ws.onopen = () => {
|
|
56422
56469
|
clearTimeout(connectTimeout);
|
|
56423
56470
|
this.reconnectAttempts = 0;
|
|
56471
|
+
this.authAttempts = 0;
|
|
56424
56472
|
this.lastReceivedAt = Date.now();
|
|
56425
56473
|
this.setState("connected");
|
|
56426
56474
|
};
|
|
@@ -56508,6 +56556,20 @@ var ParallWs = class {
|
|
|
56508
56556
|
this.stateListeners.delete(handler);
|
|
56509
56557
|
};
|
|
56510
56558
|
}
|
|
56559
|
+
/**
|
|
56560
|
+
* Subscribe to the auth-invalid transition. Fired exactly once when the
|
|
56561
|
+
* client enters the terminal 'auth-invalid' state (a second episode after
|
|
56562
|
+
* a recovered reconnect fires again — one event per transition edge).
|
|
56563
|
+
* Consumers: runtime bridges exit for supervisor re-mint (see
|
|
56564
|
+
* @parall/agent-core gateway-base), the daemon logs recovery guidance for
|
|
56565
|
+
* its machine key, UIs surface a re-authenticate action.
|
|
56566
|
+
*/
|
|
56567
|
+
onAuthInvalid(handler) {
|
|
56568
|
+
this.authInvalidListeners.add(handler);
|
|
56569
|
+
return () => {
|
|
56570
|
+
this.authInvalidListeners.delete(handler);
|
|
56571
|
+
};
|
|
56572
|
+
}
|
|
56511
56573
|
// ---- Internal ----
|
|
56512
56574
|
send(frame) {
|
|
56513
56575
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
@@ -56553,6 +56615,8 @@ var ParallWs = class {
|
|
|
56553
56615
|
}
|
|
56554
56616
|
}
|
|
56555
56617
|
scheduleReconnect(detail) {
|
|
56618
|
+
if (this._state === "auth-invalid")
|
|
56619
|
+
return;
|
|
56556
56620
|
this.setState("reconnecting", { ...detail, attempt: this.reconnectAttempts + 1 });
|
|
56557
56621
|
this.clearReconnect();
|
|
56558
56622
|
const base = Math.min(this.options.reconnectInterval * Math.pow(2, this.reconnectAttempts), this.options.maxReconnectInterval);
|
|
@@ -56568,6 +56632,20 @@ var ParallWs = class {
|
|
|
56568
56632
|
this.reconnectTimer = null;
|
|
56569
56633
|
}
|
|
56570
56634
|
}
|
|
56635
|
+
/**
|
|
56636
|
+
* Enter the terminal auth-invalid state and notify consumers once. Loud on
|
|
56637
|
+
* purpose: before this branch existed, a revoked key produced an infinite
|
|
56638
|
+
* silent connecting→reconnecting loop with no indication that the
|
|
56639
|
+
* credential — not the network — was the problem.
|
|
56640
|
+
*/
|
|
56641
|
+
enterAuthInvalid(event) {
|
|
56642
|
+
this.clearReconnect();
|
|
56643
|
+
this.setState("auth-invalid");
|
|
56644
|
+
console.error(`WS auth-invalid: server rejected this credential (status ${event.status}${event.code ? `, code ${event.code}` : ""}) \u2014 ${event.message}. The key is invalid, expired, or revoked; retrying it cannot succeed, so reconnects are stopped. Recover by refreshing credentials (re-login, or issue a new API key), then connect again.`);
|
|
56645
|
+
for (const listener of this.authInvalidListeners) {
|
|
56646
|
+
listener(event);
|
|
56647
|
+
}
|
|
56648
|
+
}
|
|
56571
56649
|
/** Force-close a dead/stale connection and trigger reconnect. */
|
|
56572
56650
|
forceReconnect(cause) {
|
|
56573
56651
|
this.stopHeartbeat();
|
|
@@ -56672,6 +56750,16 @@ var ParallWs = class {
|
|
|
56672
56750
|
}
|
|
56673
56751
|
};
|
|
56674
56752
|
|
|
56753
|
+
// ../sdk/dist/browser-use-contract.generated.js
|
|
56754
|
+
var browserUseContract = { "actions": { "read": { "grant": "browser.read", "target": "optional_tab", "params": { "required": [], "properties": { "url": { "type": "string", "min_length": 1, "max_length": 8192, "schemes": ["http", "https", "about:blank"] } }, "rules": ["exactly one of params.url or target is required", "params.url creates a hidden Profile-bound tab and closes it before terminal success or failure"], "additional_properties": false }, "success": { "base": null, "fields": { "profile_id": "ebp_identifier", "url": "string", "title": "string", "article": "nullable_article" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "tabs": { "grant": "browser.read", "target": "none", "params": { "required": [], "properties": {}, "additional_properties": false }, "success": { "base": null, "fields": { "tabs": "tab_summary_array" } }, "errors": ["TAB_GONE"] }, "wait": { "grant": "browser.read", "target": "tab", "params": { "required": [], "properties": { "selector": { "type": "string", "min_length": 1, "max_length": 4096 }, "state": { "enum": ["attached", "detached", "visible", "hidden", "load"], "default": "attached" }, "timeout_ms": { "type": "integer", "minimum": 1, "maximum": 3e4, "default": 1e4 } }, "rules": ["selector is required unless state=load", "state=load forbids selector"], "additional_properties": false }, "success": { "base": "tab_state", "fields": { "matched": { "const": true } } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "snapshot": { "grant": "browser.read", "target": "tab", "params": { "required": [], "properties": { "interactive": { "type": "boolean", "default": false }, "compact": { "type": "boolean", "default": false }, "depth": { "type": "integer", "minimum": 0, "maximum": 64 } }, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "snapshot": "string", "snapshot_id": "identifier" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "get": { "grant": "browser.read", "target": "tab_or_ref", "params": { "required": ["prop"], "properties": { "selector": { "type": "string", "min_length": 1, "max_length": 4096 }, "prop": { "enum": ["text", "html", "value", "attr", "title", "url"] }, "name": { "type": "string", "min_length": 1, "max_length": 256 } }, "rules": ["title/url forbid locator and name", "text/html/value require exactly one locator", "attr requires exactly one locator and name"], "additional_properties": false }, "success": { "base": "tab_state", "fields": { "value": "nullable_string" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "STALE_REF", "PAGE_LOAD_FAILED"] }, "screenshot": { "grant": "browser.read", "target": "tab", "params": { "required": [], "properties": {}, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "format": { "const": "png" }, "base64": "canonical_base64" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "open": { "grant": "browser.interact", "target": "none", "params": { "required": ["url"], "properties": { "url": { "type": "string", "min_length": 1, "max_length": 8192, "schemes": ["http", "https", "about:blank"] }, "hidden": { "type": "boolean", "default": false }, "viewport": { "type": "viewport" } }, "additional_properties": false }, "success": { "base": "tab_state", "fields": {} }, "errors": ["PAGE_LOAD_FAILED"] }, "navigate": { "grant": "browser.interact", "target": "tab", "params": { "required": ["url"], "properties": { "url": { "type": "string", "min_length": 1, "max_length": 8192, "schemes": ["http", "https", "about:blank"] } }, "additional_properties": false }, "success": { "base": "tab_state", "fields": {} }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "viewport": { "grant": "browser.interact", "target": "tab", "params": { "required": ["width", "height"], "properties": { "width": { "type": "integer", "minimum": 320, "maximum": 3840 }, "height": { "type": "integer", "minimum": 240, "maximum": 2160 } }, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "viewport": "viewport" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE"] }, "click": { "grant": "browser.interact", "target": "tab_or_ref", "params": { "required": [], "properties": { "selector": "selector" }, "rules": ["exactly one of params.selector or target.ref"], "additional_properties": false }, "success": { "base": "tab_state", "fields": { "clicked": { "const": true } } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "STALE_REF", "PAGE_LOAD_FAILED"] }, "fill": { "grant": "browser.interact", "target": "tab_or_ref", "params": { "required": ["text"], "properties": { "selector": "selector", "text": { "type": "string", "allow_empty": true } }, "rules": ["exactly one of params.selector or target.ref"], "additional_properties": false }, "success": { "base": "tab_state", "fields": { "filled": { "const": true }, "characters": "non_negative_integer" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "STALE_REF", "PAGE_LOAD_FAILED"] }, "type": { "grant": "browser.interact", "target": "tab_or_ref", "params": { "required": ["text"], "properties": { "selector": "selector", "text": { "type": "string", "min_length": 1 } }, "rules": ["exactly one of params.selector or target.ref"], "additional_properties": false }, "success": { "base": "tab_state", "fields": { "typed": { "const": true }, "characters": "non_negative_integer" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "STALE_REF", "PAGE_LOAD_FAILED"] }, "press": { "grant": "browser.interact", "target": "tab", "params": { "required": ["key"], "properties": { "key": "single_unicode_character_or_named_key" }, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "pressed": { "const": true } } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "scroll": { "grant": "browser.interact", "target": "tab", "params": { "required": [], "properties": { "direction": { "enum": ["up", "down", "left", "right"], "default": "down" }, "pixels": { "type": "integer", "minimum": 1, "maximum": 1e5, "default": 500 } }, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "scrolled": { "const": true } } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "close": { "grant": "browser.interact", "target": "tab", "params": { "required": [], "properties": {}, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "closed": { "const": true } } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE"] }, "recover": { "grant": "browser.interact", "target": "tab", "params": { "required": [], "properties": {}, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "recovered_from_tab_id": "identifier" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] }, "eval": { "grant": "browser.advanced", "target": "tab", "params": { "required": ["expression"], "properties": { "expression": { "type": "string", "min_length": 1 }, "timeout_ms": { "type": "integer", "minimum": 1, "maximum": 15e3, "default": 15e3 } }, "additional_properties": false }, "success": { "base": "tab_state", "fields": { "value": "json_value_max_256_kib" } }, "errors": ["TAB_NOT_FOUND", "TAB_GONE", "PAGE_LOAD_FAILED"] } }, "successShapes": { "tab_state": { "required": ["tab_id", "profile_id", "browser_generation", "document_generation", "url", "title"], "fields": { "tab_id": "identifier", "profile_id": "ebp_identifier", "browser_generation": "positive_integer", "document_generation": "positive_integer", "url": "string", "title": "string" }, "additional_properties": false }, "tab_summary": { "base": "tab_state", "required_additions": ["loading"], "fields": { "loading": "boolean" }, "additional_properties": false }, "article": { "required": ["title", "byline", "excerpt", "text", "published_time", "site_name", "length"], "fields": { "title": "nullable_string", "byline": "nullable_string", "excerpt": "nullable_string", "text": "string", "published_time": "nullable_string", "site_name": "nullable_string", "length": "non_negative_integer" }, "additional_properties": false } } };
|
|
56755
|
+
|
|
56756
|
+
// ../sdk/dist/browser-use-validation.js
|
|
56757
|
+
var BROWSER_USE_ACTION_SCHEMAS = browserUseContract.actions;
|
|
56758
|
+
var BROWSER_USE_ACTIONS = Object.freeze(Object.keys(BROWSER_USE_ACTION_SCHEMAS));
|
|
56759
|
+
|
|
56760
|
+
// ../sdk/dist/browser-use-receipt.js
|
|
56761
|
+
var KEYS = "contract_version operation_id request_id profile_id profile_version profile_config_revision action required_grant phase dispatched receipt_id receipt_digest occurred_at tab_id browser_generation duration_ms result_digest result_available result_expires_at data error deadline accepted_at started_at terminal_at updated_at".split(" ");
|
|
56762
|
+
|
|
56675
56763
|
// ../agent-core/dist/fork-state.js
|
|
56676
56764
|
var FORK_CONTINUATION_RETRY_CAP = 256;
|
|
56677
56765
|
function forkContinuationRetryKey(event) {
|
|
@@ -56803,12 +56891,209 @@ function isTypedEvent(event) {
|
|
|
56803
56891
|
return event.type !== "message" && laneTargetUri(event) === void 0;
|
|
56804
56892
|
}
|
|
56805
56893
|
|
|
56806
|
-
// ../agent-core/dist/lane-
|
|
56894
|
+
// ../agent-core/dist/lane-outcome.js
|
|
56807
56895
|
function errorWireClass(cls) {
|
|
56808
56896
|
if (!cls || cls === "ok" || cls === "usage_limit")
|
|
56809
56897
|
return void 0;
|
|
56810
56898
|
return cls;
|
|
56811
56899
|
}
|
|
56900
|
+
|
|
56901
|
+
// ../agent-core/dist/runtime-instance.js
|
|
56902
|
+
function isTurnToken(token) {
|
|
56903
|
+
return token.startsWith("turn_");
|
|
56904
|
+
}
|
|
56905
|
+
|
|
56906
|
+
// ../agent-core/dist/lane-input-receipts.js
|
|
56907
|
+
var LaneInputReceipts = class {
|
|
56908
|
+
opts;
|
|
56909
|
+
confirmations;
|
|
56910
|
+
constructor(opts, confirmations) {
|
|
56911
|
+
this.opts = opts;
|
|
56912
|
+
this.confirmations = confirmations;
|
|
56913
|
+
}
|
|
56914
|
+
lifecycle(lane, messageIds) {
|
|
56915
|
+
const explicit = lane.coverageMode === "explicit";
|
|
56916
|
+
const unique = [...new Set(messageIds)];
|
|
56917
|
+
const dispatchEventIds = unique.map((messageId) => lane.folded.get(messageId)).filter((id) => Boolean(id));
|
|
56918
|
+
if (explicit && dispatchEventIds.length !== unique.length) {
|
|
56919
|
+
throw new Error(`explicit lane ${lane.lane} is missing a folded WorkItem mapping`);
|
|
56920
|
+
}
|
|
56921
|
+
if (!explicit && dispatchEventIds.length === 0)
|
|
56922
|
+
return void 0;
|
|
56923
|
+
return {
|
|
56924
|
+
deliveryKey: dispatchEventIds.join(","),
|
|
56925
|
+
dispatchEventIds,
|
|
56926
|
+
update: explicit ? (state, failure) => this.updateInputState(lane, dispatchEventIds, state, failure) : async () => void 0
|
|
56927
|
+
};
|
|
56928
|
+
}
|
|
56929
|
+
async updateInputState(lane, dispatchEventIds, state, failure) {
|
|
56930
|
+
lane.observedInputs ??= /* @__PURE__ */ new Map();
|
|
56931
|
+
for (const id of dispatchEventIds)
|
|
56932
|
+
lane.observedInputs.set(id, state);
|
|
56933
|
+
let confirmed;
|
|
56934
|
+
const ids = [...dispatchEventIds];
|
|
56935
|
+
const failed = new Set(state === "failed" ? ids : []);
|
|
56936
|
+
const sourceIds = [...lane.folded].filter(([, id]) => failed.has(id)).map(([id]) => id);
|
|
56937
|
+
const request3 = {
|
|
56938
|
+
lane: lane.lane,
|
|
56939
|
+
target_uri: lane.targetUri,
|
|
56940
|
+
thread_root_id: lane.threadRootId,
|
|
56941
|
+
dispatch_event_ids: ids,
|
|
56942
|
+
state,
|
|
56943
|
+
session_id: lane.sessionAmbiguous ? void 0 : lane.sessionId,
|
|
56944
|
+
...state === "failed" && failure ? {
|
|
56945
|
+
outcome_class: errorWireClass(failure.outcomeClass),
|
|
56946
|
+
detail: failure.detail ? redactSecrets(failure.detail, this.opts.knownSecrets).slice(0, 500) : void 0
|
|
56947
|
+
} : {}
|
|
56948
|
+
};
|
|
56949
|
+
await this.confirmations.submit(lane.lane, {
|
|
56950
|
+
label: `input ${state}`,
|
|
56951
|
+
send: async () => {
|
|
56952
|
+
const restore = sourceIds.length ? this.opts.releaseLocalClaims?.(sourceIds) : void 0;
|
|
56953
|
+
let result;
|
|
56954
|
+
try {
|
|
56955
|
+
result = await this.opts.client.updateDispatchInputState(this.opts.orgId, request3);
|
|
56956
|
+
} catch (err) {
|
|
56957
|
+
restore?.();
|
|
56958
|
+
throw err;
|
|
56959
|
+
}
|
|
56960
|
+
if (result.recognized !== ids.length && !isTurnToken(lane.lane)) {
|
|
56961
|
+
restore?.();
|
|
56962
|
+
throw new ApiError(409, "input acknowledgement scope changed", "INPUT_SCOPE_CHANGED");
|
|
56963
|
+
}
|
|
56964
|
+
if (state === "failed") {
|
|
56965
|
+
for (const sourceId of sourceIds) {
|
|
56966
|
+
lane.folded.delete(sourceId);
|
|
56967
|
+
lane.seen.delete(sourceId);
|
|
56968
|
+
}
|
|
56969
|
+
}
|
|
56970
|
+
confirmed = { retry: state === "failed" && result.released > 0 };
|
|
56971
|
+
}
|
|
56972
|
+
});
|
|
56973
|
+
return confirmed ?? { retry: false, pending: true };
|
|
56974
|
+
}
|
|
56975
|
+
async syncAttribution(lane) {
|
|
56976
|
+
if (lane.settlementMode !== "receipt" || lane.settling || lane.sessionAmbiguous || !lane.sessionId || !lane.observedInputs?.size)
|
|
56977
|
+
return;
|
|
56978
|
+
const sessionId = lane.sessionId;
|
|
56979
|
+
const groups = /* @__PURE__ */ new Map();
|
|
56980
|
+
for (const [id, state] of lane.observedInputs) {
|
|
56981
|
+
const ids = groups.get(state) ?? [];
|
|
56982
|
+
ids.push(id);
|
|
56983
|
+
groups.set(state, ids);
|
|
56984
|
+
}
|
|
56985
|
+
for (const [state, ids] of groups) {
|
|
56986
|
+
await this.confirmations.submit(lane.lane, {
|
|
56987
|
+
label: "input session",
|
|
56988
|
+
send: async () => {
|
|
56989
|
+
await this.opts.client.updateDispatchInputState(this.opts.orgId, {
|
|
56990
|
+
lane: lane.lane,
|
|
56991
|
+
target_uri: lane.targetUri,
|
|
56992
|
+
thread_root_id: lane.threadRootId,
|
|
56993
|
+
dispatch_event_ids: ids,
|
|
56994
|
+
state,
|
|
56995
|
+
session_id: sessionId
|
|
56996
|
+
});
|
|
56997
|
+
}
|
|
56998
|
+
});
|
|
56999
|
+
}
|
|
57000
|
+
}
|
|
57001
|
+
};
|
|
57002
|
+
|
|
57003
|
+
// ../agent-core/dist/lane-confirmations.js
|
|
57004
|
+
var LaneConfirmations = class {
|
|
57005
|
+
opts;
|
|
57006
|
+
pending = /* @__PURE__ */ new Map();
|
|
57007
|
+
disposed = false;
|
|
57008
|
+
constructor(opts) {
|
|
57009
|
+
this.opts = opts;
|
|
57010
|
+
}
|
|
57011
|
+
/** Try once inline; a retained write returns without blocking native execution. */
|
|
57012
|
+
async submit(token, write) {
|
|
57013
|
+
if (this.disposed)
|
|
57014
|
+
return;
|
|
57015
|
+
let pending = this.pending.get(token);
|
|
57016
|
+
if (pending) {
|
|
57017
|
+
if (pending.blocked)
|
|
57018
|
+
return;
|
|
57019
|
+
pending.writes.push(write);
|
|
57020
|
+
return;
|
|
57021
|
+
}
|
|
57022
|
+
pending = { writes: [write], failures: 0, blocked: false };
|
|
57023
|
+
this.pending.set(token, pending);
|
|
57024
|
+
await this.run(token, pending);
|
|
57025
|
+
}
|
|
57026
|
+
async run(token, pending) {
|
|
57027
|
+
if (pending.running || pending.blocked || this.pending.get(token) !== pending)
|
|
57028
|
+
return;
|
|
57029
|
+
const recovered = pending.failures > 0;
|
|
57030
|
+
pending.running = Promise.resolve().then(async () => {
|
|
57031
|
+
while (pending.writes.length && this.pending.get(token) === pending) {
|
|
57032
|
+
const write = pending.writes[0];
|
|
57033
|
+
try {
|
|
57034
|
+
await write.send();
|
|
57035
|
+
pending.writes.shift();
|
|
57036
|
+
} catch (err) {
|
|
57037
|
+
if (this.pending.get(token) !== pending)
|
|
57038
|
+
return;
|
|
57039
|
+
if (err instanceof ApiError && err.status === 409 && err.code === "STALE_LANE") {
|
|
57040
|
+
this.pending.delete(token);
|
|
57041
|
+
this.opts.onStale(token);
|
|
57042
|
+
this.opts.onRecovered?.();
|
|
57043
|
+
return;
|
|
57044
|
+
}
|
|
57045
|
+
const transient = !(err instanceof ApiError) || err.status === 0 || err.status >= 500 || err.status === 408 || err.status === 429;
|
|
57046
|
+
if (!transient) {
|
|
57047
|
+
pending.blocked = true;
|
|
57048
|
+
this.opts.log?.error(`lane ${write.label} rejected for ${token}; confirmation retained: ${String(err)}`);
|
|
57049
|
+
return;
|
|
57050
|
+
}
|
|
57051
|
+
pending.failures += 1;
|
|
57052
|
+
this.opts.log?.warn(`lane ${write.label} unconfirmed for ${token}; retry ${pending.failures}: ${String(err)}`);
|
|
57053
|
+
const delays = this.opts.delaysMs?.length ? this.opts.delaysMs : [2e3, 1e4, 3e4, 6e4, 12e4];
|
|
57054
|
+
const delay = delays[Math.min(pending.failures - 1, delays.length - 1)];
|
|
57055
|
+
pending.timer = setTimeout(() => {
|
|
57056
|
+
pending.timer = void 0;
|
|
57057
|
+
void this.run(token, pending);
|
|
57058
|
+
}, delay);
|
|
57059
|
+
pending.timer.unref?.();
|
|
57060
|
+
return;
|
|
57061
|
+
}
|
|
57062
|
+
}
|
|
57063
|
+
if (this.pending.get(token) === pending)
|
|
57064
|
+
this.pending.delete(token);
|
|
57065
|
+
if (recovered)
|
|
57066
|
+
this.opts.onRecovered?.();
|
|
57067
|
+
});
|
|
57068
|
+
try {
|
|
57069
|
+
await pending.running;
|
|
57070
|
+
} finally {
|
|
57071
|
+
pending.running = void 0;
|
|
57072
|
+
}
|
|
57073
|
+
}
|
|
57074
|
+
/** Reconnect/shutdown may accelerate retries; permanent rejections stay visible. */
|
|
57075
|
+
async retryNow() {
|
|
57076
|
+
await Promise.all([...this.pending].map(async ([token, pending]) => {
|
|
57077
|
+
if (pending.timer)
|
|
57078
|
+
clearTimeout(pending.timer);
|
|
57079
|
+
pending.timer = void 0;
|
|
57080
|
+
await this.run(token, pending);
|
|
57081
|
+
}));
|
|
57082
|
+
}
|
|
57083
|
+
forget(token) {
|
|
57084
|
+
const pending = this.pending.get(token);
|
|
57085
|
+
if (pending?.timer)
|
|
57086
|
+
clearTimeout(pending.timer);
|
|
57087
|
+
this.pending.delete(token);
|
|
57088
|
+
}
|
|
57089
|
+
dispose() {
|
|
57090
|
+
this.disposed = true;
|
|
57091
|
+
for (const token of this.pending.keys())
|
|
57092
|
+
this.forget(token);
|
|
57093
|
+
}
|
|
57094
|
+
};
|
|
57095
|
+
|
|
57096
|
+
// ../agent-core/dist/lane-ledger.js
|
|
56812
57097
|
var LedgerUnsupportedError = class extends Error {
|
|
56813
57098
|
};
|
|
56814
57099
|
function bindLaneSession(lane, agentSessionId) {
|
|
@@ -56834,8 +57119,24 @@ function isEndpointMissing2(err) {
|
|
|
56834
57119
|
var LaneLedger = class {
|
|
56835
57120
|
opts;
|
|
56836
57121
|
lanes = /* @__PURE__ */ new Map();
|
|
57122
|
+
confirmations;
|
|
57123
|
+
inputs;
|
|
57124
|
+
claimResponses = /* @__PURE__ */ new Map();
|
|
57125
|
+
claims = /* @__PURE__ */ new Map();
|
|
56837
57126
|
constructor(opts) {
|
|
56838
57127
|
this.opts = opts;
|
|
57128
|
+
this.confirmations = new LaneConfirmations({
|
|
57129
|
+
delaysMs: opts.terminalRetryDelaysMs,
|
|
57130
|
+
log: opts.log,
|
|
57131
|
+
onRecovered: opts.onRecovered,
|
|
57132
|
+
onStale: (token) => {
|
|
57133
|
+
for (const lane of this.lanes.values()) {
|
|
57134
|
+
if (lane.lane === token)
|
|
57135
|
+
this.forgetLane(lane);
|
|
57136
|
+
}
|
|
57137
|
+
}
|
|
57138
|
+
});
|
|
57139
|
+
this.inputs = new LaneInputReceipts(opts, this.confirmations);
|
|
56839
57140
|
}
|
|
56840
57141
|
get contextDir() {
|
|
56841
57142
|
return this.opts.contextDir;
|
|
@@ -56934,7 +57235,16 @@ ${frame}` : frame;
|
|
|
56934
57235
|
* incumbent completes.
|
|
56935
57236
|
*/
|
|
56936
57237
|
async ensureLane(events) {
|
|
56937
|
-
|
|
57238
|
+
const key = this.laneKeyFor(events[events.length - 1]);
|
|
57239
|
+
const prior = this.claims.get(key);
|
|
57240
|
+
const claim = (prior ? prior.catch(() => null) : Promise.resolve()).then(() => this.ensureLaneAttempt(events, false));
|
|
57241
|
+
this.claims.set(key, claim);
|
|
57242
|
+
try {
|
|
57243
|
+
return await claim;
|
|
57244
|
+
} finally {
|
|
57245
|
+
if (this.claims.get(key) === claim)
|
|
57246
|
+
this.claims.delete(key);
|
|
57247
|
+
}
|
|
56938
57248
|
}
|
|
56939
57249
|
/**
|
|
56940
57250
|
* One ensureLane pass. `reclaimed` marks the arbitration retry: STALE_LANE
|
|
@@ -56952,22 +57262,22 @@ ${frame}` : frame;
|
|
|
56952
57262
|
const trigger = events[events.length - 1];
|
|
56953
57263
|
const laneKey = this.laneKeyFor(trigger);
|
|
56954
57264
|
let lane = this.lanes.get(laneKey);
|
|
57265
|
+
if (lane?.settling)
|
|
57266
|
+
return null;
|
|
56955
57267
|
const reused = lane != null;
|
|
56956
57268
|
if (!lane) {
|
|
56957
57269
|
const targetUri = laneTargetUri(trigger) ?? `prll://${trigger.targetId}`;
|
|
56958
|
-
|
|
56959
|
-
|
|
56960
|
-
|
|
56961
|
-
|
|
56962
|
-
|
|
56963
|
-
|
|
56964
|
-
|
|
56965
|
-
|
|
56966
|
-
}
|
|
56967
|
-
|
|
56968
|
-
|
|
56969
|
-
throw err;
|
|
56970
|
-
}
|
|
57270
|
+
const res = await this.claimRecoverably(laneKey, {
|
|
57271
|
+
target_uri: targetUri,
|
|
57272
|
+
thread_root_id: trigger.threadRootId,
|
|
57273
|
+
limit: 100,
|
|
57274
|
+
coverage_mode: this.opts.coverageMode ?? "implicit",
|
|
57275
|
+
settlement_mode: this.opts.instanceId ? this.opts.settlementMode : void 0,
|
|
57276
|
+
resume_received: this.opts.instanceId ? true : void 0,
|
|
57277
|
+
instance_id: this.opts.instanceId
|
|
57278
|
+
});
|
|
57279
|
+
if (!res)
|
|
57280
|
+
return null;
|
|
56971
57281
|
if (!res.claimed || !res.lane) {
|
|
56972
57282
|
if (res.reason === "empty") {
|
|
56973
57283
|
this.opts.log?.warn(`claim for ${targetUri} came back empty \u2014 nothing foldable; leaving to the reconciler`);
|
|
@@ -56990,6 +57300,7 @@ ${frame}` : frame;
|
|
|
56990
57300
|
targetUri,
|
|
56991
57301
|
threadRootId: trigger.threadRootId,
|
|
56992
57302
|
coverageMode: actualCoverage,
|
|
57303
|
+
settlementMode: res.settlement_mode ?? "legacy",
|
|
56993
57304
|
folded: /* @__PURE__ */ new Map(),
|
|
56994
57305
|
framed: [],
|
|
56995
57306
|
seen: /* @__PURE__ */ new Set(),
|
|
@@ -57024,9 +57335,8 @@ ${frame}` : frame;
|
|
|
57024
57335
|
}
|
|
57025
57336
|
return null;
|
|
57026
57337
|
}
|
|
57027
|
-
this.opts.log?.warn(`steer fold failed for ${ev.messageId}
|
|
57028
|
-
|
|
57029
|
-
return null;
|
|
57338
|
+
this.opts.log?.warn(`steer fold failed for ${ev.messageId}; preserving prior members: ${String(err)}`);
|
|
57339
|
+
continue;
|
|
57030
57340
|
}
|
|
57031
57341
|
}
|
|
57032
57342
|
return lane;
|
|
@@ -57040,7 +57350,7 @@ ${frame}` : frame;
|
|
|
57040
57350
|
async steerLive(event) {
|
|
57041
57351
|
const laneKey = this.laneKeyFor(event);
|
|
57042
57352
|
const lane = this.lanes.get(laneKey);
|
|
57043
|
-
if (!lane)
|
|
57353
|
+
if (!lane || lane.settling)
|
|
57044
57354
|
return null;
|
|
57045
57355
|
if (lane.seen.has(event.messageId))
|
|
57046
57356
|
return null;
|
|
@@ -57086,54 +57396,7 @@ ${frame}` : frame;
|
|
|
57086
57396
|
* prompt or injection actually delivers (frame coverage ∪ buffered group).
|
|
57087
57397
|
*/
|
|
57088
57398
|
inputLifecycleFor(lane, messageIds) {
|
|
57089
|
-
|
|
57090
|
-
const unique = [...new Set(messageIds)];
|
|
57091
|
-
const dispatchEventIds = unique.map((messageId) => lane.folded.get(messageId)).filter((id) => Boolean(id));
|
|
57092
|
-
if (explicit && dispatchEventIds.length !== unique.length) {
|
|
57093
|
-
throw new Error(`explicit lane ${lane.lane} is missing a folded WorkItem mapping`);
|
|
57094
|
-
}
|
|
57095
|
-
if (!explicit && dispatchEventIds.length === 0)
|
|
57096
|
-
return void 0;
|
|
57097
|
-
return {
|
|
57098
|
-
deliveryKey: dispatchEventIds.join(","),
|
|
57099
|
-
dispatchEventIds,
|
|
57100
|
-
update: explicit ? (state, failure) => this.updateInputState(lane, dispatchEventIds, state, failure) : async () => void 0
|
|
57101
|
-
};
|
|
57102
|
-
}
|
|
57103
|
-
async updateInputState(lane, dispatchEventIds, state, failure) {
|
|
57104
|
-
const failed = new Set(state === "failed" ? dispatchEventIds : []);
|
|
57105
|
-
const failedSourceIds = [...lane.folded].filter(([, dispatchEventId]) => failed.has(dispatchEventId)).map(([sourceId]) => sourceId);
|
|
57106
|
-
const restoreLocalClaims = failedSourceIds.length > 0 ? this.opts.releaseLocalClaims?.(failedSourceIds) : void 0;
|
|
57107
|
-
try {
|
|
57108
|
-
const result = await this.opts.client.updateDispatchInputState(this.opts.orgId, {
|
|
57109
|
-
lane: lane.lane,
|
|
57110
|
-
target_uri: lane.targetUri,
|
|
57111
|
-
thread_root_id: lane.threadRootId,
|
|
57112
|
-
dispatch_event_ids: dispatchEventIds,
|
|
57113
|
-
state,
|
|
57114
|
-
...state === "failed" && failure ? {
|
|
57115
|
-
outcome_class: errorWireClass(failure.outcomeClass),
|
|
57116
|
-
detail: failure.detail ? redactSecrets(failure.detail, this.opts.knownSecrets).slice(0, 500) : void 0
|
|
57117
|
-
} : {}
|
|
57118
|
-
});
|
|
57119
|
-
if (result.recognized !== dispatchEventIds.length) {
|
|
57120
|
-
throw new Error(`input lifecycle ${state} recognized ${result.recognized}/${dispatchEventIds.length} WorkItems`);
|
|
57121
|
-
}
|
|
57122
|
-
if (state === "failed" && result.released === 0) {
|
|
57123
|
-
restoreLocalClaims?.();
|
|
57124
|
-
return { retry: false };
|
|
57125
|
-
}
|
|
57126
|
-
} catch (err) {
|
|
57127
|
-
restoreLocalClaims?.();
|
|
57128
|
-
throw err;
|
|
57129
|
-
}
|
|
57130
|
-
if (state === "failed") {
|
|
57131
|
-
for (const [sourceId, dispatchEventId] of lane.folded) {
|
|
57132
|
-
if (failed.has(dispatchEventId))
|
|
57133
|
-
lane.folded.delete(sourceId);
|
|
57134
|
-
}
|
|
57135
|
-
}
|
|
57136
|
-
return { retry: state === "failed" };
|
|
57399
|
+
return this.inputs.lifecycle(lane, messageIds);
|
|
57137
57400
|
}
|
|
57138
57401
|
/** Carry the runtime error into the lane's forced completion. */
|
|
57139
57402
|
markTurnError(laneKey, info = {}) {
|
|
@@ -57162,62 +57425,62 @@ ${frame}` : frame;
|
|
|
57162
57425
|
const lane = this.lanes.get(laneKey);
|
|
57163
57426
|
if (!lane || hasMoreLocal)
|
|
57164
57427
|
return;
|
|
57165
|
-
|
|
57166
|
-
|
|
57428
|
+
if (lane.settling)
|
|
57429
|
+
return;
|
|
57430
|
+
lane.settling = true;
|
|
57167
57431
|
const deferred = !lane.turnError && !this.deferredUnsupported ? lane.turnDeferred : void 0;
|
|
57168
57432
|
const outcome = lane.turnError ? "error" : lane.turnDeferred ? this.deferredUnsupported ? "error" : "deferred" : "ok";
|
|
57169
|
-
|
|
57170
|
-
|
|
57171
|
-
|
|
57172
|
-
|
|
57173
|
-
|
|
57174
|
-
|
|
57175
|
-
|
|
57176
|
-
|
|
57177
|
-
|
|
57178
|
-
|
|
57179
|
-
|
|
57180
|
-
|
|
57181
|
-
|
|
57182
|
-
|
|
57183
|
-
|
|
57184
|
-
|
|
57185
|
-
|
|
57186
|
-
|
|
57187
|
-
|
|
57188
|
-
...
|
|
57189
|
-
|
|
57190
|
-
|
|
57191
|
-
|
|
57192
|
-
|
|
57193
|
-
|
|
57194
|
-
|
|
57195
|
-
|
|
57196
|
-
|
|
57197
|
-
} catch (err) {
|
|
57198
|
-
if (isStaleLane(err)) {
|
|
57199
|
-
this.opts.log?.info(`lane complete skipped for ${lane.targetUri} \u2014 taken over`);
|
|
57200
|
-
return;
|
|
57201
|
-
}
|
|
57202
|
-
if (outcome === "deferred" && err instanceof ApiError && err.status === 400) {
|
|
57203
|
-
this.deferredUnsupported = true;
|
|
57204
|
-
this.opts.log?.warn(`server rejected turn_outcome=deferred for ${lane.targetUri} \u2014 falling back to error completes`);
|
|
57433
|
+
const request3 = {
|
|
57434
|
+
lane: lane.lane,
|
|
57435
|
+
target_uri: lane.targetUri,
|
|
57436
|
+
thread_root_id: lane.threadRootId,
|
|
57437
|
+
// An error turn releases its members for retry; a deferred turn
|
|
57438
|
+
// re-delivers them at retry_at without burning redrive budget
|
|
57439
|
+
// (ignored by older servers, which 400 on the unknown enum — see the
|
|
57440
|
+
// fallback below).
|
|
57441
|
+
turn_outcome: outcome,
|
|
57442
|
+
...deferred ? {
|
|
57443
|
+
outcome_class: deferred.outcomeClass,
|
|
57444
|
+
...deferred.retryAt ? { retry_at: deferred.retryAt } : {}
|
|
57445
|
+
} : {},
|
|
57446
|
+
// An error complete carries the bridge's classification and redacted
|
|
57447
|
+
// evidence so the server can persist WHY on the released row
|
|
57448
|
+
// (agent-health-alerting-design.md §4.5). usage_limit never travels
|
|
57449
|
+
// with error: it is the deferred contract, and a server that rejected
|
|
57450
|
+
// deferred (deferredUnsupported) also predates the class field.
|
|
57451
|
+
...outcome === "error" && lane.turnError ? {
|
|
57452
|
+
...errorWireClass(lane.turnError.outcomeClass) ? { outcome_class: errorWireClass(lane.turnError.outcomeClass) } : {},
|
|
57453
|
+
...lane.turnError.detail ? { detail: lane.turnError.detail.slice(0, 500) } : {}
|
|
57454
|
+
} : {},
|
|
57455
|
+
session_id: lane.sessionAmbiguous ? void 0 : lane.sessionId
|
|
57456
|
+
};
|
|
57457
|
+
let fallback = false;
|
|
57458
|
+
await this.confirmations.submit(lane.lane, {
|
|
57459
|
+
label: "complete",
|
|
57460
|
+
send: async () => {
|
|
57205
57461
|
try {
|
|
57206
|
-
await this.opts.client.completeDispatch(this.opts.orgId, {
|
|
57207
|
-
lane:
|
|
57208
|
-
target_uri:
|
|
57209
|
-
thread_root_id:
|
|
57462
|
+
await this.opts.client.completeDispatch(this.opts.orgId, fallback ? {
|
|
57463
|
+
lane: request3.lane,
|
|
57464
|
+
target_uri: request3.target_uri,
|
|
57465
|
+
thread_root_id: request3.thread_root_id,
|
|
57210
57466
|
turn_outcome: "error"
|
|
57211
|
-
});
|
|
57212
|
-
} catch (
|
|
57213
|
-
if (
|
|
57214
|
-
|
|
57215
|
-
|
|
57467
|
+
} : request3);
|
|
57468
|
+
} catch (err) {
|
|
57469
|
+
if (!fallback && outcome === "deferred" && err instanceof ApiError && err.status === 400) {
|
|
57470
|
+
this.deferredUnsupported = true;
|
|
57471
|
+
fallback = true;
|
|
57472
|
+
await this.opts.client.completeDispatch(this.opts.orgId, {
|
|
57473
|
+
lane: request3.lane,
|
|
57474
|
+
target_uri: request3.target_uri,
|
|
57475
|
+
thread_root_id: request3.thread_root_id,
|
|
57476
|
+
turn_outcome: "error"
|
|
57477
|
+
});
|
|
57478
|
+
} else
|
|
57479
|
+
throw err;
|
|
57216
57480
|
}
|
|
57217
|
-
|
|
57481
|
+
this.forgetLane(lane);
|
|
57218
57482
|
}
|
|
57219
|
-
|
|
57220
|
-
}
|
|
57483
|
+
});
|
|
57221
57484
|
}
|
|
57222
57485
|
/**
|
|
57223
57486
|
* Renew one lane by its key — the external runtime-activity hook for
|
|
@@ -57239,6 +57502,8 @@ ${frame}` : frame;
|
|
|
57239
57502
|
* write's incumbency check anyway.
|
|
57240
57503
|
*/
|
|
57241
57504
|
maybeRenew(lane) {
|
|
57505
|
+
if (isTurnToken(lane.lane))
|
|
57506
|
+
return;
|
|
57242
57507
|
const now = Date.now();
|
|
57243
57508
|
const ttl = lane.leaseTtlMs ?? 10 * 6e4;
|
|
57244
57509
|
const until = lane.leaseUntilMs ?? now;
|
|
@@ -57269,26 +57534,40 @@ ${frame}` : frame;
|
|
|
57269
57534
|
*/
|
|
57270
57535
|
async release(laneKey, reason = "unspecified", info) {
|
|
57271
57536
|
const lane = this.lanes.get(laneKey);
|
|
57272
|
-
if (!lane)
|
|
57537
|
+
if (!lane || lane.settling)
|
|
57273
57538
|
return;
|
|
57274
|
-
|
|
57275
|
-
|
|
57276
|
-
|
|
57277
|
-
|
|
57278
|
-
|
|
57279
|
-
|
|
57280
|
-
|
|
57281
|
-
|
|
57282
|
-
|
|
57283
|
-
|
|
57284
|
-
|
|
57285
|
-
|
|
57539
|
+
lane.settling = true;
|
|
57540
|
+
const wireClass = errorWireClass(info?.outcomeClass);
|
|
57541
|
+
const outcome = info && (wireClass || info.detail) ? {
|
|
57542
|
+
...wireClass ? { outcome_class: wireClass } : {},
|
|
57543
|
+
...info.detail ? { detail: redactSecrets(info.detail, this.opts.knownSecrets).slice(0, 500) } : {}
|
|
57544
|
+
} : void 0;
|
|
57545
|
+
await this.confirmations.submit(lane.lane, {
|
|
57546
|
+
label: "release",
|
|
57547
|
+
send: async () => {
|
|
57548
|
+
await this.opts.client.releaseDispatchLane(this.opts.orgId, lane.lane, reason, outcome);
|
|
57549
|
+
this.forgetLane(lane);
|
|
57550
|
+
}
|
|
57551
|
+
});
|
|
57286
57552
|
}
|
|
57287
57553
|
async releaseAll(reason = "shutdown") {
|
|
57554
|
+
await this.confirmations.retryNow();
|
|
57288
57555
|
const keys = [...this.lanes.keys()];
|
|
57289
57556
|
for (const key of keys) {
|
|
57290
57557
|
await this.release(key, reason);
|
|
57291
57558
|
}
|
|
57559
|
+
for (const [key, claim] of this.claimResponses) {
|
|
57560
|
+
if (!claim.response?.lane)
|
|
57561
|
+
continue;
|
|
57562
|
+
const token = claim.response.lane;
|
|
57563
|
+
await this.confirmations.submit(token, {
|
|
57564
|
+
label: "unconsumed claim release",
|
|
57565
|
+
send: async () => {
|
|
57566
|
+
await this.opts.client.releaseDispatchLane(this.opts.orgId, token, reason);
|
|
57567
|
+
this.claimResponses.delete(key);
|
|
57568
|
+
}
|
|
57569
|
+
});
|
|
57570
|
+
}
|
|
57292
57571
|
}
|
|
57293
57572
|
/** True when any lane is currently active (used by shutdown logging). */
|
|
57294
57573
|
get activeCount() {
|
|
@@ -57303,18 +57582,57 @@ ${frame}` : frame;
|
|
|
57303
57582
|
* — the caller must skip processing.
|
|
57304
57583
|
*/
|
|
57305
57584
|
async claimTyped(ref) {
|
|
57306
|
-
|
|
57585
|
+
const key = `typed:${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`}`;
|
|
57586
|
+
if (this.claims.has(key))
|
|
57587
|
+
return null;
|
|
57588
|
+
if (ref.dispatchEventId && this.lanes.has(laneKeyForTarget(`dsp:${ref.dispatchEventId}`)))
|
|
57589
|
+
return null;
|
|
57590
|
+
const claim = this.claimTypedAttempt(ref);
|
|
57591
|
+
this.claims.set(key, claim);
|
|
57307
57592
|
try {
|
|
57308
|
-
|
|
57309
|
-
|
|
57310
|
-
|
|
57311
|
-
|
|
57593
|
+
return await claim;
|
|
57594
|
+
} finally {
|
|
57595
|
+
this.claims.delete(key);
|
|
57596
|
+
}
|
|
57597
|
+
}
|
|
57598
|
+
async claimRecoverably(key, request3) {
|
|
57599
|
+
let claim = this.claimResponses.get(key);
|
|
57600
|
+
if (!claim) {
|
|
57601
|
+
claim = { request: request3 };
|
|
57602
|
+
this.claimResponses.set(key, claim);
|
|
57603
|
+
const captured = claim;
|
|
57604
|
+
await this.confirmations.submit(`claim:${key}`, {
|
|
57605
|
+
label: "claim",
|
|
57606
|
+
send: async () => {
|
|
57607
|
+
try {
|
|
57608
|
+
captured.response = await this.opts.client.claimDispatch(this.opts.orgId, request3);
|
|
57609
|
+
} catch (err) {
|
|
57610
|
+
if (isEndpointMissing2(err))
|
|
57611
|
+
captured.unsupported = true;
|
|
57612
|
+
else
|
|
57613
|
+
throw err;
|
|
57614
|
+
}
|
|
57615
|
+
}
|
|
57312
57616
|
});
|
|
57313
|
-
} catch (err) {
|
|
57314
|
-
if (isEndpointMissing2(err))
|
|
57315
|
-
throw new LedgerUnsupportedError("claim endpoint unavailable");
|
|
57316
|
-
throw err;
|
|
57317
57617
|
}
|
|
57618
|
+
if (claim.unsupported) {
|
|
57619
|
+
this.claimResponses.delete(key);
|
|
57620
|
+
throw new LedgerUnsupportedError("claim endpoint unavailable");
|
|
57621
|
+
}
|
|
57622
|
+
if (!claim.response)
|
|
57623
|
+
return null;
|
|
57624
|
+
this.claimResponses.delete(key);
|
|
57625
|
+
return claim.response;
|
|
57626
|
+
}
|
|
57627
|
+
async claimTypedAttempt(ref) {
|
|
57628
|
+
const res = await this.claimRecoverably(`typed:${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`}`, {
|
|
57629
|
+
dispatch_event_id: ref.dispatchEventId,
|
|
57630
|
+
source_type: ref.dispatchEventId ? void 0 : ref.sourceType,
|
|
57631
|
+
source_id: ref.dispatchEventId ? void 0 : ref.sourceId,
|
|
57632
|
+
instance_id: this.opts.instanceId
|
|
57633
|
+
});
|
|
57634
|
+
if (!res)
|
|
57635
|
+
return null;
|
|
57318
57636
|
if (!res.claimed || !res.lane || !res.events?.length) {
|
|
57319
57637
|
if (res.reason === "stale") {
|
|
57320
57638
|
this.opts.log?.info(`typed dispatch ${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`} resolved by the server as stale (${res.stale_reason ?? "unspecified"})`);
|
|
@@ -57326,6 +57644,8 @@ ${frame}` : frame;
|
|
|
57326
57644
|
}
|
|
57327
57645
|
const workItem = res.events[0];
|
|
57328
57646
|
const targetUri = `dsp:${workItem.id}`;
|
|
57647
|
+
if (this.lanes.has(laneKeyForTarget(targetUri)))
|
|
57648
|
+
return null;
|
|
57329
57649
|
const leaseUntilMs = Date.parse(res.lease_until ?? "");
|
|
57330
57650
|
const lane = {
|
|
57331
57651
|
laneKey: laneKeyForTarget(targetUri),
|
|
@@ -57354,7 +57674,34 @@ ${frame}` : frame;
|
|
|
57354
57674
|
const lane = this.lanes.get(laneKey);
|
|
57355
57675
|
if (!lane)
|
|
57356
57676
|
return;
|
|
57357
|
-
this.
|
|
57677
|
+
this.confirmations.forget(lane.lane);
|
|
57678
|
+
this.forgetLane(lane);
|
|
57679
|
+
}
|
|
57680
|
+
syncInputAttribution(lane) {
|
|
57681
|
+
return this.inputs.syncAttribution(lane);
|
|
57682
|
+
}
|
|
57683
|
+
async confirmTyped(lane, send) {
|
|
57684
|
+
if (lane.settling)
|
|
57685
|
+
return;
|
|
57686
|
+
lane.settling = true;
|
|
57687
|
+
await this.confirmations.submit(lane.lane, {
|
|
57688
|
+
label: "typed complete",
|
|
57689
|
+
send: async () => {
|
|
57690
|
+
await send();
|
|
57691
|
+
this.forgetLane(lane);
|
|
57692
|
+
}
|
|
57693
|
+
});
|
|
57694
|
+
}
|
|
57695
|
+
retryConfirmations() {
|
|
57696
|
+
return this.confirmations.retryNow();
|
|
57697
|
+
}
|
|
57698
|
+
dispose() {
|
|
57699
|
+
this.confirmations.dispose();
|
|
57700
|
+
}
|
|
57701
|
+
forgetLane(lane) {
|
|
57702
|
+
if (this.lanes.get(lane.laneKey) !== lane)
|
|
57703
|
+
return;
|
|
57704
|
+
this.lanes.delete(lane.laneKey);
|
|
57358
57705
|
this.removeLaneContext(lane);
|
|
57359
57706
|
}
|
|
57360
57707
|
/**
|
|
@@ -58297,7 +58644,7 @@ async function dispatchLaneGroup(host, opts) {
|
|
|
58297
58644
|
}
|
|
58298
58645
|
async function dispatchLaneGroupInner(host, opts) {
|
|
58299
58646
|
const ledger = host.laneLedger;
|
|
58300
|
-
|
|
58647
|
+
let event = opts.events[opts.events.length - 1];
|
|
58301
58648
|
let lane;
|
|
58302
58649
|
try {
|
|
58303
58650
|
lane = await runInPhaseSpan("claim", () => ledger.ensureLane(opts.events));
|
|
@@ -58315,18 +58662,51 @@ async function dispatchLaneGroupInner(host, opts) {
|
|
|
58315
58662
|
}
|
|
58316
58663
|
return "foreign";
|
|
58317
58664
|
}
|
|
58665
|
+
const foldedEvents = opts.events.filter((ev) => lane.folded.has(ev.messageId));
|
|
58666
|
+
for (const ev of opts.events) {
|
|
58667
|
+
if (!lane.folded.has(ev.messageId))
|
|
58668
|
+
host.dispatchedMessages.delete(ev.messageId);
|
|
58669
|
+
}
|
|
58670
|
+
if (foldedEvents.length === 0) {
|
|
58671
|
+
await ledger.completeIfIdle(lane.laneKey, unsettledInjections(host, opts.sessionKey) || opts.hasMoreLocal());
|
|
58672
|
+
return "foreign";
|
|
58673
|
+
}
|
|
58674
|
+
opts = { ...opts, events: foldedEvents, earlier: foldedEvents.slice(0, -1) };
|
|
58675
|
+
event = foldedEvents[foldedEvents.length - 1];
|
|
58318
58676
|
const pending = ledger.takeFrame(lane);
|
|
58319
58677
|
const frame = pending.frame;
|
|
58320
58678
|
if (!frame && opts.events.every((ev) => lane.seen.has(ev.messageId))) {
|
|
58321
58679
|
host.opts.log?.info(`lane group for ${event.messageId} already rendered by the server frame \u2014 no turn`);
|
|
58322
58680
|
const acknowledge = host.opts.dispatchAdapter.acknowledgeDiscardedInjection?.bind(host.opts.dispatchAdapter);
|
|
58681
|
+
const withdrawn = [];
|
|
58323
58682
|
if (acknowledge) {
|
|
58324
|
-
|
|
58325
|
-
const
|
|
58326
|
-
|
|
58327
|
-
|
|
58328
|
-
|
|
58683
|
+
try {
|
|
58684
|
+
for (const ev of opts.events) {
|
|
58685
|
+
const deliveryKey = lane.folded.get(ev.messageId);
|
|
58686
|
+
if (!deliveryKey)
|
|
58687
|
+
continue;
|
|
58688
|
+
if (await acknowledge(opts.sessionKey, deliveryKey) === "cancelled")
|
|
58689
|
+
withdrawn.push(ev);
|
|
58690
|
+
}
|
|
58691
|
+
} catch (err) {
|
|
58692
|
+
host.opts.log?.warn(`discarded input acknowledgement failed for ${event.messageId}: ${String(err)}`);
|
|
58693
|
+
}
|
|
58694
|
+
}
|
|
58695
|
+
if (withdrawn.length > 0 && !opts.withdrawnRetry) {
|
|
58696
|
+
for (const ev of withdrawn)
|
|
58697
|
+
host.dispatchedMessages.delete(ev.messageId);
|
|
58698
|
+
await ledger.completeIfIdle(lane.laneKey, unsettledInjections(host, opts.sessionKey));
|
|
58699
|
+
if (ledger.getForEvent(event))
|
|
58700
|
+
return "no_turn";
|
|
58701
|
+
return dispatchLaneGroupInner(host, {
|
|
58702
|
+
...opts,
|
|
58703
|
+
events: withdrawn,
|
|
58704
|
+
earlier: withdrawn.slice(0, -1),
|
|
58705
|
+
withdrawnRetry: true
|
|
58706
|
+
});
|
|
58329
58707
|
}
|
|
58708
|
+
for (const ev of opts.events)
|
|
58709
|
+
host.dispatchedMessages.delete(ev.messageId);
|
|
58330
58710
|
await runInPhaseSpan("settle", () => ledger.completeIfIdle(lane.laneKey, unsettledInjections(host, opts.sessionKey) || opts.hasMoreLocal()));
|
|
58331
58711
|
return "no_turn";
|
|
58332
58712
|
}
|
|
@@ -58512,17 +58892,24 @@ async function consumeTypedDispatch(host, ref, run, hooks) {
|
|
|
58512
58892
|
viaLegacyAck = true;
|
|
58513
58893
|
resolved = settleAck(await runInPhaseSpan("settle", () => hooks.legacyAck(claimed.typedDispatchEventId)));
|
|
58514
58894
|
} else {
|
|
58515
|
-
|
|
58516
|
-
|
|
58517
|
-
|
|
58518
|
-
|
|
58519
|
-
|
|
58520
|
-
|
|
58521
|
-
|
|
58522
|
-
|
|
58523
|
-
|
|
58524
|
-
|
|
58525
|
-
|
|
58895
|
+
await runInPhaseSpan("settle", () => ledger.confirmTyped(claimed, async () => {
|
|
58896
|
+
try {
|
|
58897
|
+
await host.opts.client.completeDispatch(host.opts.config.org_id, {
|
|
58898
|
+
dispatch_event_id: claimed.typedDispatchEventId,
|
|
58899
|
+
lane: claimed.lane,
|
|
58900
|
+
turn_outcome: "ok"
|
|
58901
|
+
});
|
|
58902
|
+
} catch (err) {
|
|
58903
|
+
if (!isByIDCompleteUnsupported(err))
|
|
58904
|
+
throw err;
|
|
58905
|
+
host.typedByIdCompleteUnsupported = true;
|
|
58906
|
+
if (!settleAck(await hooks.legacyAck(claimed.typedDispatchEventId))) {
|
|
58907
|
+
throw new Error("legacy typed acknowledgement unconfirmed");
|
|
58908
|
+
}
|
|
58909
|
+
await host.opts.client.releaseDispatchLane(host.opts.config.org_id, claimed.lane);
|
|
58910
|
+
}
|
|
58911
|
+
}));
|
|
58912
|
+
resolved = true;
|
|
58526
58913
|
}
|
|
58527
58914
|
}
|
|
58528
58915
|
} catch (err) {
|
|
@@ -58532,7 +58919,8 @@ async function consumeTypedDispatch(host, ref, run, hooks) {
|
|
|
58532
58919
|
settle(resolved);
|
|
58533
58920
|
span.setAttribute("dispatch.lane_result", resolved ? "dispatched" : "released");
|
|
58534
58921
|
if (resolved && !viaLegacyAck) {
|
|
58535
|
-
|
|
58922
|
+
if (!claimed.settling)
|
|
58923
|
+
ledger.dropLocal(claimed.laneKey);
|
|
58536
58924
|
} else {
|
|
58537
58925
|
await runInPhaseSpan("settle", () => ledger.completeIfIdle(claimed.laneKey, false).catch(() => {
|
|
58538
58926
|
}));
|
|
@@ -58972,6 +59360,19 @@ var DispatchInactivityDeadline = class {
|
|
|
58972
59360
|
this.onExpire();
|
|
58973
59361
|
}, delayMs);
|
|
58974
59362
|
}
|
|
59363
|
+
/**
|
|
59364
|
+
* Re-arm after an expiry that was only reported, not acted on (the
|
|
59365
|
+
* no-abort default: a long silent turn is logged at intervals, never
|
|
59366
|
+
* killed — attached-turn-ownership).
|
|
59367
|
+
*/
|
|
59368
|
+
rearm() {
|
|
59369
|
+
if (this.disposed || this.timeoutMs <= 0)
|
|
59370
|
+
return;
|
|
59371
|
+
this.expired = false;
|
|
59372
|
+
this.lastActivityAt = Date.now();
|
|
59373
|
+
if (!this.timer)
|
|
59374
|
+
this.arm(this.timeoutMs);
|
|
59375
|
+
}
|
|
58975
59376
|
dispose() {
|
|
58976
59377
|
if (this.disposed)
|
|
58977
59378
|
return;
|
|
@@ -59881,6 +60282,7 @@ function recordToolCall(sessionKey) {
|
|
|
59881
60282
|
}
|
|
59882
60283
|
|
|
59883
60284
|
// ../agent-core/dist/gateway-base.js
|
|
60285
|
+
var AUTH_INVALID_EXIT_CODE = 86;
|
|
59884
60286
|
var TYPED_EVENT_KINDS = {
|
|
59885
60287
|
task_assign: { type: "task", ackSourceType: "task_activity" },
|
|
59886
60288
|
task_update: { type: "task", ackSourceType: "task_activity" },
|
|
@@ -60050,14 +60452,9 @@ var ParallAgentGateway = class {
|
|
|
60050
60452
|
pendingRestartNotification = null;
|
|
60051
60453
|
laneLedger;
|
|
60052
60454
|
stepPersister;
|
|
60053
|
-
//
|
|
60054
|
-
// desired-state reconciler (see session-lifecycle.ts). The gateway only
|
|
60055
|
-
// declares turn boundaries; ordering, retries and stale-finish rejection
|
|
60056
|
-
// live in the coordinator.
|
|
60455
|
+
// Session lifecycle owns ordering, retries and stale-finish rejection.
|
|
60057
60456
|
sessionLifecycle;
|
|
60058
|
-
//
|
|
60059
|
-
// gateway only triggers it; ordering and ownership live in the finalizer
|
|
60060
|
-
// (see fork-session-finalizer.ts).
|
|
60457
|
+
// ForkSessionFinalizer owns seal → drain → close → release.
|
|
60061
60458
|
forkFinalizer;
|
|
60062
60459
|
// Sticky fallback: flipped when the server predates the ledger (claim
|
|
60063
60460
|
// endpoint 404) so every subsequent dispatch uses the legacy flow.
|
|
@@ -60073,10 +60470,12 @@ var ParallAgentGateway = class {
|
|
|
60073
60470
|
SHUTDOWN_DEADLINE_MS;
|
|
60074
60471
|
FORK_DEADLINE_MS;
|
|
60075
60472
|
DISPATCH_DEADLINE_MS;
|
|
60473
|
+
INACTIVITY_WARN_MS;
|
|
60076
60474
|
constructor(opts) {
|
|
60077
60475
|
this.opts = opts;
|
|
60078
60476
|
opts = this.opts = { ...opts, log: redactLogger(opts.log, [opts.config.api_key]) };
|
|
60079
60477
|
if (opts.dispatchContextDir) {
|
|
60478
|
+
const recovery = new DispatchRecovery(() => this.catchUpFromDispatch(), () => this.shuttingDown, (err) => opts.log?.warn(`dispatch recovery failed: ${String(err)}`));
|
|
60080
60479
|
this.laneLedger = new LaneLedger({
|
|
60081
60480
|
client: opts.client,
|
|
60082
60481
|
orgId: opts.config.org_id,
|
|
@@ -60084,12 +60483,17 @@ var ParallAgentGateway = class {
|
|
|
60084
60483
|
log: opts.log,
|
|
60085
60484
|
knownSecrets: [opts.config.api_key],
|
|
60086
60485
|
coverageMode: opts.dispatchAdapter.inputLifecycleMode ?? "implicit",
|
|
60486
|
+
settlementMode: opts.dispatchAdapter.inputSettlementMode,
|
|
60487
|
+
instanceId: opts.instanceId,
|
|
60488
|
+
terminalRetryDelaysMs: opts.laneTerminalRetryDelaysMs,
|
|
60489
|
+
onRecovered: recovery.request,
|
|
60087
60490
|
releaseLocalClaims: (sourceIds) => releaseLocalMessageClaims(this.dispatchedMessages, sourceIds)
|
|
60088
60491
|
});
|
|
60089
60492
|
}
|
|
60090
60493
|
this.SHUTDOWN_DEADLINE_MS = opts.shutdownDeadlineMs ?? 6e4;
|
|
60091
|
-
this.FORK_DEADLINE_MS = opts.forkDeadlineMs ??
|
|
60092
|
-
this.DISPATCH_DEADLINE_MS = opts.dispatchDeadlineMs ??
|
|
60494
|
+
this.FORK_DEADLINE_MS = opts.forkDeadlineMs ?? 0;
|
|
60495
|
+
this.DISPATCH_DEADLINE_MS = opts.dispatchDeadlineMs ?? 0;
|
|
60496
|
+
this.INACTIVITY_WARN_MS = opts.inactivityWarnMs ?? 30 * 6e4;
|
|
60093
60497
|
this.unsubscribeRuntimeActivity = opts.dispatchAdapter.subscribeRuntimeActivity?.((event) => this.handleRuntimeActivity(event));
|
|
60094
60498
|
this.stepPersister = new StepPersister({
|
|
60095
60499
|
client: opts.client,
|
|
@@ -60167,12 +60571,34 @@ var ParallAgentGateway = class {
|
|
|
60167
60571
|
}
|
|
60168
60572
|
});
|
|
60169
60573
|
this.opts.log?.info(`connecting to ${this.opts.connectionLabel ?? "Parall WS"}...`);
|
|
60574
|
+
let settled = false;
|
|
60575
|
+
let onSettled = null;
|
|
60576
|
+
const finish = async (opts) => {
|
|
60577
|
+
if (settled)
|
|
60578
|
+
return;
|
|
60579
|
+
settled = true;
|
|
60580
|
+
await this.shutdown(opts);
|
|
60581
|
+
onSettled?.();
|
|
60582
|
+
};
|
|
60583
|
+
ws.onAuthInvalid((event) => {
|
|
60584
|
+
const exitCode = this.opts.authInvalidExitCode === void 0 ? AUTH_INVALID_EXIT_CODE : this.opts.authInvalidExitCode;
|
|
60585
|
+
log?.error(`AUTH-INVALID agent=${this.opts.agentUserId} status=${event.status}${event.code ? ` code=${event.code}` : ""} \u2014 the server rejected this runtime's credential (${event.message}); the key is invalid, expired, or revoked.`);
|
|
60586
|
+
if (exitCode === null) {
|
|
60587
|
+
log?.error("AUTH-INVALID: reconnects are stopped and this account gateway has shut down. Refresh this account\u2019s credential and start it again; other accounts in this process are unaffected.");
|
|
60588
|
+
} else {
|
|
60589
|
+
log?.error(`AUTH-INVALID: reconnects are stopped. Exiting with code ${exitCode} so the supervisor can re-mint the launch credential and restart this agent; if no supervisor manages this process, replace its PRLL_API_KEY and start it again.`);
|
|
60590
|
+
process.exitCode = exitCode;
|
|
60591
|
+
}
|
|
60592
|
+
void finish({ skipDrain: true });
|
|
60593
|
+
});
|
|
60170
60594
|
await ws.connect();
|
|
60171
60595
|
return new Promise((resolve3) => {
|
|
60172
|
-
|
|
60173
|
-
await this.shutdown();
|
|
60596
|
+
if (settled) {
|
|
60174
60597
|
resolve3();
|
|
60175
|
-
|
|
60598
|
+
return;
|
|
60599
|
+
}
|
|
60600
|
+
onSettled = resolve3;
|
|
60601
|
+
abortSignal.addEventListener("abort", () => void finish());
|
|
60176
60602
|
});
|
|
60177
60603
|
}
|
|
60178
60604
|
tryClaimMessage(id) {
|
|
@@ -60590,6 +61016,7 @@ var ParallAgentGateway = class {
|
|
|
60590
61016
|
step_id: null,
|
|
60591
61017
|
dispatch_event_id: activeLane?.typedDispatchEventId ?? activeLane?.folded.get(event.messageId) ?? null,
|
|
60592
61018
|
lane: activeLane?.lane ?? null,
|
|
61019
|
+
settlement_mode: activeLane?.settlementMode ?? "legacy",
|
|
60593
61020
|
target_uri: activeLane?.targetUri ?? null,
|
|
60594
61021
|
thread_root_id: activeLane?.threadRootId ?? null,
|
|
60595
61022
|
// Typed binding hint for the CLI: which task this dispatch is about
|
|
@@ -60609,13 +61036,19 @@ var ParallAgentGateway = class {
|
|
|
60609
61036
|
threadRootId: contextBody.thread_root_id
|
|
60610
61037
|
});
|
|
60611
61038
|
this.inFlightDispatches++;
|
|
60612
|
-
const
|
|
60613
|
-
|
|
60614
|
-
|
|
60615
|
-
this.opts.
|
|
60616
|
-
|
|
60617
|
-
|
|
61039
|
+
const abortAfterMs = this.DISPATCH_DEADLINE_MS;
|
|
61040
|
+
const dispatchDeadline = this.dispatchInactivityDeadlines.start(sessionKey, abortAfterMs > 0 ? abortAfterMs : this.INACTIVITY_WARN_MS, () => {
|
|
61041
|
+
if (abortAfterMs > 0) {
|
|
61042
|
+
this.opts.log?.warn(`dispatch inactivity deadline exceeded (${abortAfterMs}ms) for ${event.messageId} on ${sessionKey}; aborting`);
|
|
61043
|
+
try {
|
|
61044
|
+
this.opts.dispatchAdapter.abortDispatch?.(sessionKey);
|
|
61045
|
+
} catch (err) {
|
|
61046
|
+
this.opts.log?.warn(`abortDispatch threw for ${sessionKey}: ${String(err)}`);
|
|
61047
|
+
}
|
|
61048
|
+
return;
|
|
60618
61049
|
}
|
|
61050
|
+
this.opts.log?.warn(`no runtime output for ${Math.round(this.INACTIVITY_WARN_MS / 6e4)} min on ${sessionKey} (${event.messageId}); the turn stays open \u2014 only the runtime finishing or a process restart ends it`);
|
|
61051
|
+
dispatchDeadline.rearm();
|
|
60619
61052
|
});
|
|
60620
61053
|
let binding = this.sessionBindings.get(sessionKey);
|
|
60621
61054
|
let inputStepsCreated = false;
|
|
@@ -60646,6 +61079,7 @@ var ParallAgentGateway = class {
|
|
|
60646
61079
|
binding = await runInPhaseSpan("session", () => this.bindRuntimeSession(sessionKey, runtimeEvent, contextFilePath, laneContextFilePath2));
|
|
60647
61080
|
if (activeLane) {
|
|
60648
61081
|
bindLaneSession(activeLane, binding.agentSessionId);
|
|
61082
|
+
await this.laneLedger?.syncInputAttribution(activeLane);
|
|
60649
61083
|
}
|
|
60650
61084
|
if (event.targetType === "channel_conversation" && binding.agentSessionId !== priorAgentSessionId) {
|
|
60651
61085
|
try {
|
|
@@ -61285,9 +61719,11 @@ var ParallAgentGateway = class {
|
|
|
61285
61719
|
const activeFork = createActiveForkState(fork, event.targetId, continuationPrefix);
|
|
61286
61720
|
this.forkStates.set(event.targetId, activeFork);
|
|
61287
61721
|
this.dispatchState.activeForks.set(event.targetId, fork.sessionKey);
|
|
61288
|
-
|
|
61289
|
-
|
|
61290
|
-
|
|
61722
|
+
if (this.FORK_DEADLINE_MS > 0) {
|
|
61723
|
+
activeFork.deadlineTimer = setTimeout(() => {
|
|
61724
|
+
this.abortFork(event.targetId, `deadline exceeded (${this.FORK_DEADLINE_MS}ms)`);
|
|
61725
|
+
}, this.FORK_DEADLINE_MS);
|
|
61726
|
+
}
|
|
61291
61727
|
const firstEventPromise = new Promise((resolve3) => {
|
|
61292
61728
|
activeFork.queue.push({ event, resolve: resolve3 });
|
|
61293
61729
|
});
|
|
@@ -61486,12 +61922,16 @@ ${fullSummary}` : fullSummary;
|
|
|
61486
61922
|
this.sessionId = data.session_id ?? "";
|
|
61487
61923
|
if (this.forkStates.size > 0) {
|
|
61488
61924
|
const targetIds = [...this.forkStates.keys()];
|
|
61489
|
-
|
|
61490
|
-
|
|
61491
|
-
|
|
61925
|
+
if (this.opts.instanceId) {
|
|
61926
|
+
log?.info(`${targetIds.length} active fork(s) continue across the reconnect`);
|
|
61927
|
+
} else {
|
|
61928
|
+
log?.info(`aborting ${targetIds.length} active fork(s) on reconnect`);
|
|
61929
|
+
for (const targetId of targetIds) {
|
|
61930
|
+
this.abortFork(targetId, "ws reconnect");
|
|
61931
|
+
}
|
|
61492
61932
|
}
|
|
61493
61933
|
}
|
|
61494
|
-
if (this.laneLedger && this.inFlightDispatches === 0 && this.laneLedger.activeCount > 0) {
|
|
61934
|
+
if (this.laneLedger && !this.opts.instanceId && this.inFlightDispatches === 0 && this.laneLedger.activeCount > 0) {
|
|
61495
61935
|
log?.info(`releasing ${this.laneLedger.activeCount} stale lane(s) on reconnect`);
|
|
61496
61936
|
await this.laneLedger.releaseAll();
|
|
61497
61937
|
}
|
|
@@ -61538,6 +61978,7 @@ ${fullSummary}` : fullSummary;
|
|
|
61538
61978
|
uptime: os.uptime()
|
|
61539
61979
|
});
|
|
61540
61980
|
}, intervalSec * 1e3);
|
|
61981
|
+
await this.laneLedger?.retryConfirmations();
|
|
61541
61982
|
this.catchUpFromDispatch().catch((err) => {
|
|
61542
61983
|
log?.warn(`dispatch catch-up failed: ${String(err)}`);
|
|
61543
61984
|
});
|
|
@@ -61623,10 +62064,12 @@ ${fullSummary}` : fullSummary;
|
|
|
61623
62064
|
notifyDrainWaiters() {
|
|
61624
62065
|
this.drainGate.notify();
|
|
61625
62066
|
}
|
|
61626
|
-
async shutdown() {
|
|
62067
|
+
async shutdown(opts = { skipDrain: false }) {
|
|
61627
62068
|
this.shuttingDown = true;
|
|
61628
62069
|
this.idleCompact.abort?.();
|
|
61629
|
-
if (!this.isDrained()) {
|
|
62070
|
+
if (opts.skipDrain && !this.isDrained()) {
|
|
62071
|
+
this.opts.log?.warn(`skipping drain (credential rejected): ${this.inFlightDispatches} dispatch(es), ${this.inFlightRuntimeTurns} runtime-initiated turn(s) abandoned to server redelivery`);
|
|
62072
|
+
} else if (!this.isDrained()) {
|
|
61630
62073
|
this.opts.log?.info(`draining ${this.inFlightDispatches} in-flight dispatch(es), ${this.inFlightRuntimeTurns} runtime-initiated turn(s), runtime busy=${this.adapterBusy()}, deadline ${this.SHUTDOWN_DEADLINE_MS}ms`);
|
|
61631
62074
|
await this.drainGate.wait(this.SHUTDOWN_DEADLINE_MS);
|
|
61632
62075
|
if (!this.isDrained()) {
|
|
@@ -61637,7 +62080,7 @@ ${fullSummary}` : fullSummary;
|
|
|
61637
62080
|
}
|
|
61638
62081
|
if (this.heartbeatTimer)
|
|
61639
62082
|
clearInterval(this.heartbeatTimer);
|
|
61640
|
-
if (this.laneLedger
|
|
62083
|
+
if (this.laneLedger) {
|
|
61641
62084
|
this.opts.log?.info(`releasing ${this.laneLedger.activeCount} lane(s) on shutdown`);
|
|
61642
62085
|
await this.laneLedger.releaseAll();
|
|
61643
62086
|
}
|
|
@@ -61657,6 +62100,8 @@ ${fullSummary}` : fullSummary;
|
|
|
61657
62100
|
this.opts.log?.warn(`${lifecycleRemaining} session lifecycle write(s) unreconciled at shutdown`);
|
|
61658
62101
|
}
|
|
61659
62102
|
this.sessionLifecycle.dispose();
|
|
62103
|
+
await this.laneLedger?.retryConfirmations();
|
|
62104
|
+
this.laneLedger?.dispose();
|
|
61660
62105
|
this.opts.ws.disconnect();
|
|
61661
62106
|
this.unsubscribeRuntimeActivity?.();
|
|
61662
62107
|
this.opts.log?.info(`disconnected`);
|
|
@@ -63429,13 +63874,18 @@ var parallGateway = {
|
|
|
63429
63874
|
runtimeKey: orchestratorKey,
|
|
63430
63875
|
runtimeRef: { hostname: os2.hostname(), pid: process.pid },
|
|
63431
63876
|
dispatchAdapter,
|
|
63877
|
+
// One OpenClaw host embeds many account gateways in one process: a
|
|
63878
|
+
// rejected credential stops THIS account's gateway only — it must
|
|
63879
|
+
// not set the host-wide process exit code or claim the process is
|
|
63880
|
+
// exiting.
|
|
63881
|
+
authInvalidExitCode: null,
|
|
63432
63882
|
// Opts openclaw into the dispatch ledger (claim/fold/complete +
|
|
63433
63883
|
// idempotent reply effects) — the same shared-gateway machinery
|
|
63434
63884
|
// claude/codex ride; openclaw stays buffer-only (no mid-turn steer),
|
|
63435
63885
|
// which the ledger does not require. Replies already flow through
|
|
63436
63886
|
// @parall/cli, which reads PRLL_CONTEXT_DIR (injected in hooks.ts)
|
|
63437
63887
|
// to bind dispatch_lane + reply effect keys.
|
|
63438
|
-
// Design: docs/engineering-design/dispatch-
|
|
63888
|
+
// Design: docs/engineering-design/agent-dispatch-idempotency-design.md#effects.
|
|
63439
63889
|
dispatchContextDir: dispatchLaneContextDir(stateDir),
|
|
63440
63890
|
// Per-session context file (PRLL_CONTEXT_FILE contract) — the CLI's
|
|
63441
63891
|
// TYPED dispatch binding (parall tasks update → task_update effect)
|