@parall/parall 1.62.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 +829 -315
- package/package.json +3 -3
- package/skills/parall-browser/SKILL.md +53 -0
- package/skills/parall-clips/SKILL.md +17 -4
- 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
|
|
|
@@ -52323,6 +52358,14 @@ function browserViewerRequestOptions(command, opts) {
|
|
|
52323
52358
|
};
|
|
52324
52359
|
}
|
|
52325
52360
|
|
|
52361
|
+
// ../sdk/dist/clip-connection-endpoints.js
|
|
52362
|
+
var clipConnectionEndpoints = {
|
|
52363
|
+
ORG_CLIP_MCP_OAUTH_ATTEMPT: (orgId, clipId, attemptId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/mcp-oauth-attempts/${attemptId}`,
|
|
52364
|
+
CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
|
|
52365
|
+
CLIP_CONNECTION_ACCESS: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}/access`,
|
|
52366
|
+
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`
|
|
52367
|
+
};
|
|
52368
|
+
|
|
52326
52369
|
// ../sdk/dist/attachment-endpoints.js
|
|
52327
52370
|
function attachmentEndpoints(apiBase) {
|
|
52328
52371
|
return {
|
|
@@ -52336,6 +52379,7 @@ function attachmentEndpoints(apiBase) {
|
|
|
52336
52379
|
// ../sdk/dist/edge-endpoints.js
|
|
52337
52380
|
var API_BASE = "/api/v1";
|
|
52338
52381
|
var edgeEndpoints = {
|
|
52382
|
+
ORG_EDGE_PROFILE_ACCESS: (orgId, edgeId, profileName) => `${API_BASE}/orgs/${orgId}/edge/${edgeId}/profiles/${encodeURIComponent(profileName)}/access`,
|
|
52339
52383
|
ORG_EDGE: (orgId) => `${API_BASE}/orgs/${orgId}/edge`,
|
|
52340
52384
|
ORG_EDGE_CONNECT: (orgId) => `${API_BASE}/orgs/${orgId}/edge/connect`,
|
|
52341
52385
|
ORG_EDGE_DEVICES: (orgId) => `${API_BASE}/orgs/${orgId}/edge/devices`,
|
|
@@ -52527,6 +52571,7 @@ var ENDPOINTS = {
|
|
|
52527
52571
|
MACHINES_ME_AGENTS: `${API_BASE2}/machines/me/agents`,
|
|
52528
52572
|
MACHINES_ME_HEALTH: `${API_BASE2}/machines/me/health`,
|
|
52529
52573
|
MACHINES_ME_RUNTIME_REPORT: `${API_BASE2}/machines/me/runtime-report`,
|
|
52574
|
+
MACHINES_ME_DIAGNOSTICS: `${API_BASE2}/machines/me/diagnostics`,
|
|
52530
52575
|
MACHINES_ME_CLIPS: `${API_BASE2}/machines/me/clips`,
|
|
52531
52576
|
MACHINES_ME_BROWSER_PROFILES: `${API_BASE2}/machines/me/browser-profiles`,
|
|
52532
52577
|
MACHINES_ME_BROWSER_PROFILE_STATUS: (profileId) => `${API_BASE2}/machines/me/browser-profiles/${profileId}/status`,
|
|
@@ -52616,6 +52661,7 @@ var ENDPOINTS = {
|
|
|
52616
52661
|
TRIGGER: (orgId, triggerId) => `${API_BASE2}/orgs/${orgId}/external-triggers/${triggerId}`,
|
|
52617
52662
|
/** @deprecated Use TRIGGER. Same compatibility path. */
|
|
52618
52663
|
EXTERNAL_TRIGGER: (orgId, triggerId) => `${API_BASE2}/orgs/${orgId}/external-triggers/${triggerId}`,
|
|
52664
|
+
PLATFORM_TRIGGER_SCHEMA: (orgId) => `${API_BASE2}/orgs/${orgId}/platform-trigger-schema`,
|
|
52619
52665
|
TRIGGER_RUNS: (orgId) => `${API_BASE2}/orgs/${orgId}/external-trigger-runs`,
|
|
52620
52666
|
/** @deprecated Use TRIGGER_RUNS. Same compatibility path. */
|
|
52621
52667
|
EXTERNAL_TRIGGER_RUNS: (orgId) => `${API_BASE2}/orgs/${orgId}/external-trigger-runs`,
|
|
@@ -52713,6 +52759,7 @@ var ENDPOINTS = {
|
|
|
52713
52759
|
// Wiki History (commits, file commits, blame)
|
|
52714
52760
|
WIKI_COMMITS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/commits`,
|
|
52715
52761
|
WIKI_FILE_COMMITS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/file-commits`,
|
|
52762
|
+
WIKI_PATH_ACTIVITY: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/path-activity`,
|
|
52716
52763
|
WIKI_BLAME: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/blame`,
|
|
52717
52764
|
// Wiki Operations (audit log)
|
|
52718
52765
|
WIKI_OPERATIONS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/operations`,
|
|
@@ -52792,6 +52839,8 @@ var ENDPOINTS = {
|
|
|
52792
52839
|
BILLING_CHECKOUT: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/checkout`,
|
|
52793
52840
|
BILLING_AUTO_RELOAD: (orgId) => `${API_BASE2}/orgs/${orgId}/billing/auto-reload`,
|
|
52794
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`,
|
|
52795
52844
|
COMPUTE_PRICING: () => `${API_BASE2}/billing/compute-pricing`,
|
|
52796
52845
|
// Runtime capability table (public, no auth) — SSOT for the create/settings
|
|
52797
52846
|
// interlock: per-runtime compute modes, native model family, cross-family
|
|
@@ -52826,16 +52875,6 @@ var ENDPOINTS = {
|
|
|
52826
52875
|
BROWSER_PROFILE_VIEWER_COMMAND: (orgId, profileId) => `${API_BASE2}/orgs/${orgId}/browser-profiles/${profileId}/viewer/command`,
|
|
52827
52876
|
// Edge device endpoints
|
|
52828
52877
|
...edgeEndpoints,
|
|
52829
|
-
ORG_BROWSER_ALIASES: (orgId) => `/api/v1/orgs/${orgId}/browser-aliases`,
|
|
52830
|
-
ORG_BROWSER_ALIAS: (orgId, aliasId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}`,
|
|
52831
|
-
ORG_BROWSER_ALIAS_READINESS_CHECKS: (orgId, aliasId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}/readiness-checks`,
|
|
52832
|
-
ORG_BROWSER_ALIAS_READINESS_CHECK: (orgId, aliasId, checkId) => `/api/v1/orgs/${orgId}/browser-aliases/${aliasId}/readiness-checks/${checkId}`,
|
|
52833
|
-
ORG_API_KEY_BROWSER_ALIAS_GRANTS: (orgId, keyId) => `/api/v1/orgs/${orgId}/api-keys/${keyId}/browser-alias-grants`,
|
|
52834
|
-
ORG_API_KEY_BROWSER_ALIAS_GRANT: (orgId, keyId, aliasId) => `/api/v1/orgs/${orgId}/api-keys/${keyId}/browser-alias-grants/${aliasId}`,
|
|
52835
|
-
ORG_MANAGED_ALIASES: (orgId) => `/api/v1/orgs/${orgId}/aliases`,
|
|
52836
|
-
ORG_MANAGED_ALIAS: (orgId, aliasName) => `/api/v1/orgs/${orgId}/aliases/${encodeURIComponent(aliasName)}`,
|
|
52837
|
-
ORG_BROWSER_ALIAS_EXECUTIONS: (orgId) => `/api/v1/orgs/${orgId}/executions`,
|
|
52838
|
-
ORG_BROWSER_ALIAS_EXECUTION: (orgId, requestId) => `/api/v1/orgs/${orgId}/executions/${encodeURIComponent(requestId)}`,
|
|
52839
52878
|
ORG_BROWSER_USE_OPERATIONS: (orgId) => `/api/v1/orgs/${orgId}/browser-use/operations`,
|
|
52840
52879
|
ORG_BROWSER_USE_OPERATION: (orgId, operationId) => `/api/v1/orgs/${orgId}/browser-use/operations/${encodeURIComponent(operationId)}`,
|
|
52841
52880
|
// Per-profile egress proxy (hosted Cloud Profiles; manager-only, human-only).
|
|
@@ -52848,8 +52887,7 @@ var ENDPOINTS = {
|
|
|
52848
52887
|
// Same request/reply shape as the v2 browser-profile viewer, on the v3 edge
|
|
52849
52888
|
// pipe. Additive: does NOT replace BROWSER_PROFILE_VIEWER_COMMAND.
|
|
52850
52889
|
ORG_EDGE_VIEWER_COMMAND: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/viewer/command`,
|
|
52851
|
-
|
|
52852
|
-
CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
|
|
52890
|
+
...clipConnectionEndpoints,
|
|
52853
52891
|
// Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
|
|
52854
52892
|
ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
|
|
52855
52893
|
ORG_CLIP_REGISTRY_RESOLVE: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/resolve`,
|
|
@@ -53363,6 +53401,91 @@ var ChannelConversationClient = class extends SlackFilesClient {
|
|
|
53363
53401
|
}
|
|
53364
53402
|
};
|
|
53365
53403
|
|
|
53404
|
+
// ../sdk/dist/clip-connection-client.js
|
|
53405
|
+
var ClipConnectionClient = class extends ChannelConversationClient {
|
|
53406
|
+
// ---- Clip connections ----
|
|
53407
|
+
async listClipConnections(orgId, clipId) {
|
|
53408
|
+
return this.request("GET", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId));
|
|
53409
|
+
}
|
|
53410
|
+
async createClipConnection(orgId, clipId, input) {
|
|
53411
|
+
return this.request("POST", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId), input);
|
|
53412
|
+
}
|
|
53413
|
+
async deleteClipConnection(orgId, connId) {
|
|
53414
|
+
return this.request("DELETE", ENDPOINTS.CLIP_CONNECTION(orgId, connId));
|
|
53415
|
+
}
|
|
53416
|
+
/** Organization members may read; personal connections are owner-only. */
|
|
53417
|
+
async getClipConnectionAccess(orgId, connId) {
|
|
53418
|
+
return this.request("GET", ENDPOINTS.CLIP_CONNECTION_ACCESS(orgId, connId));
|
|
53419
|
+
}
|
|
53420
|
+
/** Human org owner/admin; accepts JWT or personal key. */
|
|
53421
|
+
async putClipConnectionAccess(orgId, connId, input) {
|
|
53422
|
+
return this.request("PUT", ENDPOINTS.CLIP_CONNECTION_ACCESS(orgId, connId), input);
|
|
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
|
+
}
|
|
53438
|
+
};
|
|
53439
|
+
|
|
53440
|
+
// ../sdk/dist/browser-profile-client.js
|
|
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
|
+
}
|
|
53480
|
+
async getBrowserProfileAccess(orgId, edgeId, profileName) {
|
|
53481
|
+
return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILE_ACCESS(orgId, edgeId, profileName));
|
|
53482
|
+
}
|
|
53483
|
+
/** Replace the complete access policy; requires a human org owner/admin. */
|
|
53484
|
+
async putBrowserProfileAccess(orgId, edgeId, profileName, access) {
|
|
53485
|
+
return this.request("PUT", ENDPOINTS.ORG_EDGE_PROFILE_ACCESS(orgId, edgeId, profileName), access);
|
|
53486
|
+
}
|
|
53487
|
+
};
|
|
53488
|
+
|
|
53366
53489
|
// ../sdk/dist/wiki-upload.js
|
|
53367
53490
|
function createWikiUploadFormData(params) {
|
|
53368
53491
|
const form = new FormData();
|
|
@@ -53499,7 +53622,7 @@ function legacyHeartbeatFromReport(report) {
|
|
|
53499
53622
|
detectedRuntimes
|
|
53500
53623
|
};
|
|
53501
53624
|
}
|
|
53502
|
-
var ParallClient = class _ParallClient extends
|
|
53625
|
+
var ParallClient = class _ParallClient extends BrowserProfileClient {
|
|
53503
53626
|
baseUrl;
|
|
53504
53627
|
wikiBaseUrl;
|
|
53505
53628
|
token;
|
|
@@ -53797,8 +53920,8 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
53797
53920
|
return this.request("POST", ENDPOINTS.AUTH_OAUTH_EXCHANGE, { code });
|
|
53798
53921
|
}
|
|
53799
53922
|
// ---- WebSocket ----
|
|
53800
|
-
async getWsTicket() {
|
|
53801
|
-
return this.request("POST", ENDPOINTS.WS_TICKET);
|
|
53923
|
+
async getWsTicket(req) {
|
|
53924
|
+
return this.request("POST", ENDPOINTS.WS_TICKET, req);
|
|
53802
53925
|
}
|
|
53803
53926
|
// ---- Users ----
|
|
53804
53927
|
async getMe() {
|
|
@@ -54533,6 +54656,17 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
54533
54656
|
await this.postMachineHeartbeat(legacyHeartbeatFromReport(report));
|
|
54534
54657
|
return "legacy";
|
|
54535
54658
|
}
|
|
54659
|
+
/**
|
|
54660
|
+
* Upload a diagnostics bundle from the machine itself (`mck_` bearer):
|
|
54661
|
+
* a gzip body the daemon assembled and redacted locally. Multipart so the
|
|
54662
|
+
* meta travels beside the file; the server indexes it for platform staff.
|
|
54663
|
+
*/
|
|
54664
|
+
async uploadMachineDiagnostics(bundle, meta2 = {}) {
|
|
54665
|
+
const form = new FormData();
|
|
54666
|
+
form.append("meta", JSON.stringify(meta2));
|
|
54667
|
+
form.append("bundle", new Blob([new Uint8Array(bundle)], { type: "application/gzip" }), "diagnostics.json.gz");
|
|
54668
|
+
return this.multipartRequest("POST", ENDPOINTS.MACHINES_ME_DIAGNOSTICS, form, false, { timeoutMs: 2 * 60 * 1e3 });
|
|
54669
|
+
}
|
|
54536
54670
|
/**
|
|
54537
54671
|
* @deprecated Legacy form of `putMachineRuntimeReport`, kept for servers
|
|
54538
54672
|
* that predate it. `POST /machines/me/health` — report daemon state. All
|
|
@@ -54774,8 +54908,8 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
54774
54908
|
* no_action sweep otherwise. Idempotent.
|
|
54775
54909
|
*
|
|
54776
54910
|
* @deprecated Legacy ok-only alias — use {@link completeDispatch} with the
|
|
54777
|
-
* `sources` form, which also carries `turn_outcome`.
|
|
54778
|
-
*
|
|
54911
|
+
* `sources` form, which also carries `turn_outcome`. Retirement conditions:
|
|
54912
|
+
* agent-dispatch-idempotency-design.md#compatibility.
|
|
54779
54913
|
*/
|
|
54780
54914
|
async completeDispatchSources(orgId, req) {
|
|
54781
54915
|
return this.request("POST", ENDPOINTS.DISPATCH_COMPLETE_SOURCES(orgId), req);
|
|
@@ -55018,6 +55152,9 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55018
55152
|
async getTriggerSchema(orgId, connectionId) {
|
|
55019
55153
|
return this.request("GET", ENDPOINTS.TRIGGER_SCHEMA(orgId, connectionId));
|
|
55020
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
|
+
}
|
|
55021
55158
|
async listTriggerIngressEvents(orgId, filters) {
|
|
55022
55159
|
return this.request("GET", ENDPOINTS.TRIGGER_INGRESS_EVENTS(orgId), void 0, filters);
|
|
55023
55160
|
}
|
|
@@ -55119,8 +55256,8 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55119
55256
|
return url;
|
|
55120
55257
|
return `${this.baseUrlFor(url)}${url}`;
|
|
55121
55258
|
}
|
|
55122
|
-
async getWikiBlob(orgId, wikiId, params) {
|
|
55123
|
-
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);
|
|
55124
55261
|
if (blob.signed_url)
|
|
55125
55262
|
blob.signed_url = this.absoluteMediaUrl(blob.signed_url);
|
|
55126
55263
|
return blob;
|
|
@@ -55314,6 +55451,10 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55314
55451
|
...params
|
|
55315
55452
|
});
|
|
55316
55453
|
}
|
|
55454
|
+
/** Bounded, ACL-safe activity for one Wiki file path. */
|
|
55455
|
+
async getWikiPathActivity(orgId, wikiId, path11, opts) {
|
|
55456
|
+
return this.request("GET", ENDPOINTS.WIKI_PATH_ACTIVITY(orgId, wikiId), void 0, { path: path11 }, false, opts);
|
|
55457
|
+
}
|
|
55317
55458
|
async getWikiBlame(orgId, wikiId, path11, ref) {
|
|
55318
55459
|
return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path11, ref });
|
|
55319
55460
|
}
|
|
@@ -55489,6 +55630,21 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55489
55630
|
async getBilling(orgId) {
|
|
55490
55631
|
return this.request("GET", ENDPOINTS.BILLING(orgId));
|
|
55491
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
|
+
}
|
|
55492
55648
|
async listBillingTransactions(orgId, opts) {
|
|
55493
55649
|
const params = new URLSearchParams();
|
|
55494
55650
|
if (opts?.cursor)
|
|
@@ -55658,12 +55814,14 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55658
55814
|
}
|
|
55659
55815
|
// ---- Clip registry (v3, api-server org registry — `crg_` entries) ----
|
|
55660
55816
|
/**
|
|
55661
|
-
* List registry clips visible to the org: its own plus
|
|
55662
|
-
* cross-org entries
|
|
55663
|
-
* 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.
|
|
55664
55819
|
*/
|
|
55665
|
-
async listOrgRegistryClips(orgId) {
|
|
55666
|
-
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}`);
|
|
55667
55825
|
return resp ?? [];
|
|
55668
55826
|
}
|
|
55669
55827
|
/**
|
|
@@ -55744,7 +55902,6 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55744
55902
|
/**
|
|
55745
55903
|
* Read a clip's per-org exec access (by user id — humans and agents alike).
|
|
55746
55904
|
* Org-member readable, so a denied caller can learn why exec answered
|
|
55747
|
-
* `CLIP_NOT_ALLOWED` / `CLIP_CONNECTION_NOT_ALLOWED` (agents:
|
|
55748
55905
|
* `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED`). Writing
|
|
55749
55906
|
* it (`putClipAgentExecAccess`) is an org owner/admin's act.
|
|
55750
55907
|
*/
|
|
@@ -55784,6 +55941,19 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55784
55941
|
async deleteEdgeDevice(orgId, edgeId) {
|
|
55785
55942
|
return this.request("DELETE", ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId));
|
|
55786
55943
|
}
|
|
55944
|
+
/** Move the human caller's OWN BYOC device between the org layer and their
|
|
55945
|
+
* personal layer (ADR-020). `member` takes the device — and every clip
|
|
55946
|
+
* connection bound to it — out of the org's sight and into the owner's sole
|
|
55947
|
+
* custody; `org` shares it back, after which an org admin binds clips to it
|
|
55948
|
+
* and the clip's access list governs exec. Idempotent. Refused for hosted
|
|
55949
|
+
* profiles (`EDGE_NOT_PERSONALIZABLE`), for anyone but the owner
|
|
55950
|
+
* (`FORBIDDEN`; someone else's personal device is `NOT_FOUND`), and for
|
|
55951
|
+
* agents. */
|
|
55952
|
+
async setEdgeManagedBy(orgId, edgeId, managedBy) {
|
|
55953
|
+
return this.request("PATCH", ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId), {
|
|
55954
|
+
managed_by: managedBy
|
|
55955
|
+
});
|
|
55956
|
+
}
|
|
55787
55957
|
/** Idempotently remove the human caller's own offline BYOC registration.
|
|
55788
55958
|
* A live connection returns `EDGE_ONLINE`. */
|
|
55789
55959
|
async unregisterEdgeDevice(orgId, edgeId) {
|
|
@@ -55812,69 +55982,6 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55812
55982
|
async getEdgeProfileOperation(orgId, edgeId, operationId) {
|
|
55813
55983
|
return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILE_OPERATION(orgId, edgeId, operationId));
|
|
55814
55984
|
}
|
|
55815
|
-
/** Create and atomically materialize one Local BYOC Browser Alias. A replay
|
|
55816
|
-
* with the same idempotency key and body returns the original stable ccn_. */
|
|
55817
|
-
async createBrowserAlias(orgId, request3) {
|
|
55818
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIASES(orgId), request3);
|
|
55819
|
-
}
|
|
55820
|
-
async listBrowserAliases(orgId) {
|
|
55821
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIASES(orgId));
|
|
55822
|
-
}
|
|
55823
|
-
async getBrowserAlias(orgId, aliasId) {
|
|
55824
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId));
|
|
55825
|
-
}
|
|
55826
|
-
async renameBrowserAlias(orgId, aliasId, request3) {
|
|
55827
|
-
return this.request("PATCH", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId), request3);
|
|
55828
|
-
}
|
|
55829
|
-
async deleteBrowserAlias(orgId, aliasId, request3) {
|
|
55830
|
-
return this.request("DELETE", ENDPOINTS.ORG_BROWSER_ALIAS(orgId, aliasId), request3);
|
|
55831
|
-
}
|
|
55832
|
-
/** Start one durable readiness check. The key is carried as the standard
|
|
55833
|
-
* Idempotency-Key header; the request body is intentionally empty. */
|
|
55834
|
-
async createBrowserAliasReadinessCheck(orgId, aliasId, request3) {
|
|
55835
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIAS_READINESS_CHECKS(orgId, aliasId), void 0, void 0, false, { headers: { "Idempotency-Key": request3.idempotency_key } });
|
|
55836
|
-
}
|
|
55837
|
-
/** Sole durable recovery surface for one readiness request. */
|
|
55838
|
-
async getBrowserAliasReadinessCheck(orgId, aliasId, checkId) {
|
|
55839
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_READINESS_CHECK(orgId, aliasId, checkId));
|
|
55840
|
-
}
|
|
55841
|
-
/** Organization Owner view. Hashes, reviewed snapshots and deltas are
|
|
55842
|
-
* intentionally available only on this human-JWT management surface. */
|
|
55843
|
-
async listBrowserAliasGrants(orgId, keyId) {
|
|
55844
|
-
return this.request("GET", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANTS(orgId, keyId));
|
|
55845
|
-
}
|
|
55846
|
-
async getBrowserAliasGrant(orgId, keyId, aliasId) {
|
|
55847
|
-
return this.request("GET", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANT(orgId, keyId, aliasId));
|
|
55848
|
-
}
|
|
55849
|
-
async replaceBrowserAliasGrant(orgId, keyId, aliasId, request3) {
|
|
55850
|
-
return this.request("PUT", ENDPOINTS.ORG_API_KEY_BROWSER_ALIAS_GRANT(orgId, keyId, aliasId), request3);
|
|
55851
|
-
}
|
|
55852
|
-
/** Managed-key discovery. The response is already grant-filtered and never
|
|
55853
|
-
* carries contract hashes, review snapshots, Edge IDs or Profile IDs. */
|
|
55854
|
-
async listManagedBrowserAliases(orgId) {
|
|
55855
|
-
return this.request("GET", ENDPOINTS.ORG_MANAGED_ALIASES(orgId));
|
|
55856
|
-
}
|
|
55857
|
-
async getManagedBrowserAlias(orgId, aliasName) {
|
|
55858
|
-
return this.request("GET", ENDPOINTS.ORG_MANAGED_ALIAS(orgId, aliasName));
|
|
55859
|
-
}
|
|
55860
|
-
/** Accept and dispatch one @alias command. request_id is generated by the
|
|
55861
|
-
* caller before local validation and is also the sole durable recovery key. */
|
|
55862
|
-
async createBrowserAliasExecution(orgId, request3) {
|
|
55863
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTIONS(orgId), request3);
|
|
55864
|
-
}
|
|
55865
|
-
async getBrowserAliasExecution(orgId, requestId) {
|
|
55866
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTION(orgId, requestId));
|
|
55867
|
-
}
|
|
55868
|
-
/** Accept one idempotent Browser Use operation for an explicit Profile.
|
|
55869
|
-
* The Server resolves Profile→Edge; callers never select an Edge directly. */
|
|
55870
|
-
async createBrowserUseOperation(orgId, request3) {
|
|
55871
|
-
return this.request("POST", ENDPOINTS.ORG_BROWSER_USE_OPERATIONS(orgId), request3);
|
|
55872
|
-
}
|
|
55873
|
-
/** Recover the durable receipt. Successful data is present only inside the
|
|
55874
|
-
* Server's short encrypted result TTL; terminal proof remains afterwards. */
|
|
55875
|
-
async getBrowserUseOperation(orgId, operationId) {
|
|
55876
|
-
return this.request("GET", ENDPOINTS.ORG_BROWSER_USE_OPERATION(orgId, operationId));
|
|
55877
|
-
}
|
|
55878
55985
|
/**
|
|
55879
55986
|
* Read a hosted Cloud Profile's egress-proxy status (manager-only: hosted
|
|
55880
55987
|
* human maintainer or org admin). Sanitized — the password never comes back.
|
|
@@ -55983,9 +56090,8 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
55983
56090
|
* - `EDGE_DEADLINE_EXCEEDED` 504 — arrived late, provably NOT executed.
|
|
55984
56091
|
* - `EDGE_HOSTED_DISABLED_FOR_ORG` 403, `EDGE_REPAIR` 503 (operator-held),
|
|
55985
56092
|
* `EDGE_RUNTIME_UNAVAILABLE` 503 (deployment has no hosted runtime).
|
|
55986
|
-
* - Access errors (
|
|
55987
|
-
*
|
|
55988
|
-
* not cover this connection) — agent principals receive the historical
|
|
56093
|
+
* - Access errors (before side effects): human `CONNECTION_NOT_ALLOWED`.
|
|
56094
|
+
* Agent principals receive the historical
|
|
55989
56095
|
* `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED` for one
|
|
55990
56096
|
* release. An org owner/admin can widen access in the clip's settings.
|
|
55991
56097
|
* - Routing errors: `CONNECTION_REQUIRED`, `CONNECTION_NOT_FOUND`,
|
|
@@ -56007,16 +56113,6 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
56007
56113
|
throw err;
|
|
56008
56114
|
}
|
|
56009
56115
|
}
|
|
56010
|
-
// ---- Clip connections ----
|
|
56011
|
-
async listClipConnections(orgId, clipId) {
|
|
56012
|
-
return this.request("GET", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId));
|
|
56013
|
-
}
|
|
56014
|
-
async createClipConnection(orgId, clipId, input) {
|
|
56015
|
-
return this.request("POST", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId), input);
|
|
56016
|
-
}
|
|
56017
|
-
async deleteClipConnection(orgId, connId) {
|
|
56018
|
-
return this.request("DELETE", ENDPOINTS.CLIP_CONNECTION(orgId, connId));
|
|
56019
|
-
}
|
|
56020
56116
|
// ---- MCP clip server config (same-org or reviewed Official OAuth) ----
|
|
56021
56117
|
/**
|
|
56022
56118
|
* Read the redacted MCP config. 404 NOT_FOUND when the clip has none yet —
|
|
@@ -56078,17 +56174,6 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
|
|
|
56078
56174
|
timeoutMs: 4e4
|
|
56079
56175
|
});
|
|
56080
56176
|
}
|
|
56081
|
-
/** Start a new Official OAuth MCP connection with the platform-owned app.
|
|
56082
|
-
* Omitting oauth_client is load-bearing: the server resolves the exact
|
|
56083
|
-
* reviewed-version binding and never falls back to DCR/CIMD cross-org. */
|
|
56084
|
-
async createClipMCPOAuthConnection(orgId, clipId, serverUrl, alias, oauthClient) {
|
|
56085
|
-
return this.request("POST", ENDPOINTS.ORG_CLIP_MCP_CONFIGS(orgId, clipId), {
|
|
56086
|
-
server_url: serverUrl,
|
|
56087
|
-
auth_type: "oauth",
|
|
56088
|
-
...alias ? { alias } : {},
|
|
56089
|
-
...oauthClient ? { oauth_client: oauthClient } : {}
|
|
56090
|
-
});
|
|
56091
|
-
}
|
|
56092
56177
|
/** Re-authorize an existing MCP credential slot. */
|
|
56093
56178
|
async initiateClipMCPOAuthById(orgId, clipId, configId, serverUrl, expectedVersion, oauthClient) {
|
|
56094
56179
|
const req = {
|
|
@@ -56277,6 +56362,11 @@ function describeWsStateDetail(detail) {
|
|
|
56277
56362
|
function isRetryableNetworkError(err) {
|
|
56278
56363
|
return err instanceof Error && err.name === "ApiError" && "status" in err && err.status === 0;
|
|
56279
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
|
+
}
|
|
56280
56370
|
function isBrowserRuntime() {
|
|
56281
56371
|
return typeof window !== "undefined";
|
|
56282
56372
|
}
|
|
@@ -56285,9 +56375,12 @@ var ParallWs = class {
|
|
|
56285
56375
|
options;
|
|
56286
56376
|
listeners = /* @__PURE__ */ new Map();
|
|
56287
56377
|
stateListeners = /* @__PURE__ */ new Set();
|
|
56378
|
+
authInvalidListeners = /* @__PURE__ */ new Set();
|
|
56288
56379
|
heartbeatTimer = null;
|
|
56289
56380
|
reconnectTimer = null;
|
|
56290
56381
|
reconnectAttempts = 0;
|
|
56382
|
+
/** Ticket attempts in the current auth-invalid episode (reset on success). */
|
|
56383
|
+
authAttempts = 0;
|
|
56291
56384
|
lastSeq = 0;
|
|
56292
56385
|
_state = "disconnected";
|
|
56293
56386
|
intentionalClose = false;
|
|
@@ -56300,6 +56393,7 @@ var ParallWs = class {
|
|
|
56300
56393
|
reconnect: true,
|
|
56301
56394
|
reconnectInterval: 1e3,
|
|
56302
56395
|
maxReconnectInterval: 3e4,
|
|
56396
|
+
maxAuthAttempts: 3,
|
|
56303
56397
|
...options
|
|
56304
56398
|
};
|
|
56305
56399
|
this.lastSeq = options.lastSeq ?? 0;
|
|
@@ -56309,12 +56403,25 @@ var ParallWs = class {
|
|
|
56309
56403
|
}
|
|
56310
56404
|
async connect() {
|
|
56311
56405
|
this.intentionalClose = false;
|
|
56406
|
+
if (this._state === "auth-invalid")
|
|
56407
|
+
this.authAttempts = 0;
|
|
56312
56408
|
this.setupBrowserListeners();
|
|
56313
56409
|
this.setState("connecting");
|
|
56314
56410
|
let ticket;
|
|
56315
56411
|
try {
|
|
56316
56412
|
ticket = await this.options.getTicket();
|
|
56317
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
|
+
}
|
|
56318
56425
|
if (isBrowserRuntime() && isRetryableNetworkError(err)) {
|
|
56319
56426
|
console.warn("Failed to get WS ticket:", err);
|
|
56320
56427
|
} else {
|
|
@@ -56361,6 +56468,7 @@ var ParallWs = class {
|
|
|
56361
56468
|
this.ws.onopen = () => {
|
|
56362
56469
|
clearTimeout(connectTimeout);
|
|
56363
56470
|
this.reconnectAttempts = 0;
|
|
56471
|
+
this.authAttempts = 0;
|
|
56364
56472
|
this.lastReceivedAt = Date.now();
|
|
56365
56473
|
this.setState("connected");
|
|
56366
56474
|
};
|
|
@@ -56448,6 +56556,20 @@ var ParallWs = class {
|
|
|
56448
56556
|
this.stateListeners.delete(handler);
|
|
56449
56557
|
};
|
|
56450
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
|
+
}
|
|
56451
56573
|
// ---- Internal ----
|
|
56452
56574
|
send(frame) {
|
|
56453
56575
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
@@ -56493,6 +56615,8 @@ var ParallWs = class {
|
|
|
56493
56615
|
}
|
|
56494
56616
|
}
|
|
56495
56617
|
scheduleReconnect(detail) {
|
|
56618
|
+
if (this._state === "auth-invalid")
|
|
56619
|
+
return;
|
|
56496
56620
|
this.setState("reconnecting", { ...detail, attempt: this.reconnectAttempts + 1 });
|
|
56497
56621
|
this.clearReconnect();
|
|
56498
56622
|
const base = Math.min(this.options.reconnectInterval * Math.pow(2, this.reconnectAttempts), this.options.maxReconnectInterval);
|
|
@@ -56508,6 +56632,20 @@ var ParallWs = class {
|
|
|
56508
56632
|
this.reconnectTimer = null;
|
|
56509
56633
|
}
|
|
56510
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
|
+
}
|
|
56511
56649
|
/** Force-close a dead/stale connection and trigger reconnect. */
|
|
56512
56650
|
forceReconnect(cause) {
|
|
56513
56651
|
this.stopHeartbeat();
|
|
@@ -56612,6 +56750,16 @@ var ParallWs = class {
|
|
|
56612
56750
|
}
|
|
56613
56751
|
};
|
|
56614
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
|
+
|
|
56615
56763
|
// ../agent-core/dist/fork-state.js
|
|
56616
56764
|
var FORK_CONTINUATION_RETRY_CAP = 256;
|
|
56617
56765
|
function forkContinuationRetryKey(event) {
|
|
@@ -56664,12 +56812,15 @@ function createActiveForkState(fork, targetId, continuationPrefix) {
|
|
|
56664
56812
|
|
|
56665
56813
|
// ../agent-core/dist/redact.js
|
|
56666
56814
|
function redactSecrets(s, knownValues = []) {
|
|
56815
|
+
return maskKnownValues(s, knownValues).replace(/\b(agk|mck|cpk)_[A-Za-z0-9_-]+/g, "$1_***").replace(/\b(sk|pk|rk)-[A-Za-z0-9_-]{8,}/g, "$1-***").replace(/\bAKIA[0-9A-Z]{16}\b/g, "AKIA***").replace(/\b((?:bearer|basic)\s+)[A-Za-z0-9._~+/=-]+/gi, "$1***").replace(/(\b(?:[\w-]*[_-])?(?:api[_-]?key|key|token|secret|password|passwd|authorization)["']?\s*[=:]\s*)(?:"(?:\\.|[^"\\\r\n])*"|'(?:\\.|[^'\\\r\n])*'|[^\s&;,}\]"']+)/gi, "$1***").replace(/[A-Za-z0-9_-]{32,}/g, "***");
|
|
56816
|
+
}
|
|
56817
|
+
function maskKnownValues(s, knownValues) {
|
|
56667
56818
|
let out = s;
|
|
56668
56819
|
for (const v of knownValues) {
|
|
56669
56820
|
if (typeof v === "string" && v.length >= 6)
|
|
56670
56821
|
out = out.split(v).join("***");
|
|
56671
56822
|
}
|
|
56672
|
-
return out
|
|
56823
|
+
return out;
|
|
56673
56824
|
}
|
|
56674
56825
|
function redactTurnOutcome(event, knownValues) {
|
|
56675
56826
|
const redacted = { ...event };
|
|
@@ -56690,6 +56841,16 @@ function describeTurnOutcomeFailure(outcome) {
|
|
|
56690
56841
|
stepMessage: `LLM turn ${outcome.outcome}${retryNote}${outcome.detail ? `: ${outcome.detail}` : ""}`
|
|
56691
56842
|
};
|
|
56692
56843
|
}
|
|
56844
|
+
function redactLogger(log, knownValues) {
|
|
56845
|
+
if (!log)
|
|
56846
|
+
return void 0;
|
|
56847
|
+
return {
|
|
56848
|
+
info: (message) => log.info(redactSecrets(message, knownValues)),
|
|
56849
|
+
warn: (message) => log.warn(redactSecrets(message, knownValues)),
|
|
56850
|
+
error: (message) => log.error(redactSecrets(message, knownValues)),
|
|
56851
|
+
...log.child ? { child: (name) => redactLogger(log.child(name), knownValues) } : {}
|
|
56852
|
+
};
|
|
56853
|
+
}
|
|
56693
56854
|
|
|
56694
56855
|
// ../agent-core/dist/lane-ledger.js
|
|
56695
56856
|
import * as fs2 from "node:fs";
|
|
@@ -56730,12 +56891,209 @@ function isTypedEvent(event) {
|
|
|
56730
56891
|
return event.type !== "message" && laneTargetUri(event) === void 0;
|
|
56731
56892
|
}
|
|
56732
56893
|
|
|
56733
|
-
// ../agent-core/dist/lane-
|
|
56894
|
+
// ../agent-core/dist/lane-outcome.js
|
|
56734
56895
|
function errorWireClass(cls) {
|
|
56735
56896
|
if (!cls || cls === "ok" || cls === "usage_limit")
|
|
56736
56897
|
return void 0;
|
|
56737
56898
|
return cls;
|
|
56738
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
|
|
56739
57097
|
var LedgerUnsupportedError = class extends Error {
|
|
56740
57098
|
};
|
|
56741
57099
|
function bindLaneSession(lane, agentSessionId) {
|
|
@@ -56761,8 +57119,24 @@ function isEndpointMissing2(err) {
|
|
|
56761
57119
|
var LaneLedger = class {
|
|
56762
57120
|
opts;
|
|
56763
57121
|
lanes = /* @__PURE__ */ new Map();
|
|
57122
|
+
confirmations;
|
|
57123
|
+
inputs;
|
|
57124
|
+
claimResponses = /* @__PURE__ */ new Map();
|
|
57125
|
+
claims = /* @__PURE__ */ new Map();
|
|
56764
57126
|
constructor(opts) {
|
|
56765
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);
|
|
56766
57140
|
}
|
|
56767
57141
|
get contextDir() {
|
|
56768
57142
|
return this.opts.contextDir;
|
|
@@ -56861,7 +57235,16 @@ ${frame}` : frame;
|
|
|
56861
57235
|
* incumbent completes.
|
|
56862
57236
|
*/
|
|
56863
57237
|
async ensureLane(events) {
|
|
56864
|
-
|
|
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
|
+
}
|
|
56865
57248
|
}
|
|
56866
57249
|
/**
|
|
56867
57250
|
* One ensureLane pass. `reclaimed` marks the arbitration retry: STALE_LANE
|
|
@@ -56879,22 +57262,22 @@ ${frame}` : frame;
|
|
|
56879
57262
|
const trigger = events[events.length - 1];
|
|
56880
57263
|
const laneKey = this.laneKeyFor(trigger);
|
|
56881
57264
|
let lane = this.lanes.get(laneKey);
|
|
57265
|
+
if (lane?.settling)
|
|
57266
|
+
return null;
|
|
56882
57267
|
const reused = lane != null;
|
|
56883
57268
|
if (!lane) {
|
|
56884
57269
|
const targetUri = laneTargetUri(trigger) ?? `prll://${trigger.targetId}`;
|
|
56885
|
-
|
|
56886
|
-
|
|
56887
|
-
|
|
56888
|
-
|
|
56889
|
-
|
|
56890
|
-
|
|
56891
|
-
|
|
56892
|
-
|
|
56893
|
-
}
|
|
56894
|
-
|
|
56895
|
-
|
|
56896
|
-
throw err;
|
|
56897
|
-
}
|
|
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;
|
|
56898
57281
|
if (!res.claimed || !res.lane) {
|
|
56899
57282
|
if (res.reason === "empty") {
|
|
56900
57283
|
this.opts.log?.warn(`claim for ${targetUri} came back empty \u2014 nothing foldable; leaving to the reconciler`);
|
|
@@ -56917,6 +57300,7 @@ ${frame}` : frame;
|
|
|
56917
57300
|
targetUri,
|
|
56918
57301
|
threadRootId: trigger.threadRootId,
|
|
56919
57302
|
coverageMode: actualCoverage,
|
|
57303
|
+
settlementMode: res.settlement_mode ?? "legacy",
|
|
56920
57304
|
folded: /* @__PURE__ */ new Map(),
|
|
56921
57305
|
framed: [],
|
|
56922
57306
|
seen: /* @__PURE__ */ new Set(),
|
|
@@ -56951,9 +57335,8 @@ ${frame}` : frame;
|
|
|
56951
57335
|
}
|
|
56952
57336
|
return null;
|
|
56953
57337
|
}
|
|
56954
|
-
this.opts.log?.warn(`steer fold failed for ${ev.messageId}
|
|
56955
|
-
|
|
56956
|
-
return null;
|
|
57338
|
+
this.opts.log?.warn(`steer fold failed for ${ev.messageId}; preserving prior members: ${String(err)}`);
|
|
57339
|
+
continue;
|
|
56957
57340
|
}
|
|
56958
57341
|
}
|
|
56959
57342
|
return lane;
|
|
@@ -56967,7 +57350,7 @@ ${frame}` : frame;
|
|
|
56967
57350
|
async steerLive(event) {
|
|
56968
57351
|
const laneKey = this.laneKeyFor(event);
|
|
56969
57352
|
const lane = this.lanes.get(laneKey);
|
|
56970
|
-
if (!lane)
|
|
57353
|
+
if (!lane || lane.settling)
|
|
56971
57354
|
return null;
|
|
56972
57355
|
if (lane.seen.has(event.messageId))
|
|
56973
57356
|
return null;
|
|
@@ -57013,64 +57396,9 @@ ${frame}` : frame;
|
|
|
57013
57396
|
* prompt or injection actually delivers (frame coverage ∪ buffered group).
|
|
57014
57397
|
*/
|
|
57015
57398
|
inputLifecycleFor(lane, messageIds) {
|
|
57016
|
-
|
|
57017
|
-
const unique = [...new Set(messageIds)];
|
|
57018
|
-
const dispatchEventIds = unique.map((messageId) => lane.folded.get(messageId)).filter((id) => Boolean(id));
|
|
57019
|
-
if (explicit && dispatchEventIds.length !== unique.length) {
|
|
57020
|
-
throw new Error(`explicit lane ${lane.lane} is missing a folded WorkItem mapping`);
|
|
57021
|
-
}
|
|
57022
|
-
if (!explicit && dispatchEventIds.length === 0)
|
|
57023
|
-
return void 0;
|
|
57024
|
-
return {
|
|
57025
|
-
deliveryKey: dispatchEventIds.join(","),
|
|
57026
|
-
dispatchEventIds,
|
|
57027
|
-
update: explicit ? (state) => this.updateInputState(lane, dispatchEventIds, state) : async () => void 0
|
|
57028
|
-
};
|
|
57399
|
+
return this.inputs.lifecycle(lane, messageIds);
|
|
57029
57400
|
}
|
|
57030
|
-
|
|
57031
|
-
const failed = new Set(state === "failed" ? dispatchEventIds : []);
|
|
57032
|
-
const failedSourceIds = [...lane.folded].filter(([, dispatchEventId]) => failed.has(dispatchEventId)).map(([sourceId]) => sourceId);
|
|
57033
|
-
const restoreLocalClaims = failedSourceIds.length > 0 ? this.opts.releaseLocalClaims?.(failedSourceIds) : void 0;
|
|
57034
|
-
try {
|
|
57035
|
-
const result = await this.opts.client.updateDispatchInputState(this.opts.orgId, {
|
|
57036
|
-
lane: lane.lane,
|
|
57037
|
-
target_uri: lane.targetUri,
|
|
57038
|
-
thread_root_id: lane.threadRootId,
|
|
57039
|
-
dispatch_event_ids: dispatchEventIds,
|
|
57040
|
-
state
|
|
57041
|
-
});
|
|
57042
|
-
if (result.recognized !== dispatchEventIds.length) {
|
|
57043
|
-
throw new Error(`input lifecycle ${state} recognized ${result.recognized}/${dispatchEventIds.length} WorkItems`);
|
|
57044
|
-
}
|
|
57045
|
-
if (state === "failed" && result.released === 0) {
|
|
57046
|
-
restoreLocalClaims?.();
|
|
57047
|
-
return { retry: false };
|
|
57048
|
-
}
|
|
57049
|
-
} catch (err) {
|
|
57050
|
-
restoreLocalClaims?.();
|
|
57051
|
-
throw err;
|
|
57052
|
-
}
|
|
57053
|
-
if (state === "failed") {
|
|
57054
|
-
for (const [sourceId, dispatchEventId] of lane.folded) {
|
|
57055
|
-
if (failed.has(dispatchEventId))
|
|
57056
|
-
lane.folded.delete(sourceId);
|
|
57057
|
-
}
|
|
57058
|
-
}
|
|
57059
|
-
return { retry: state === "failed" };
|
|
57060
|
-
}
|
|
57061
|
-
/**
|
|
57062
|
-
* Complete the lane when no local work remains for it: the server sweeps
|
|
57063
|
-
* still-leased members as no_action, releases the occupancy row, and
|
|
57064
|
-
* re-drives any same-target pending work. A STALE_LANE answer means a
|
|
57065
|
-
* takeover already owns the resource — local state is dropped either way.
|
|
57066
|
-
*/
|
|
57067
|
-
/**
|
|
57068
|
-
* Record that the turn on this lane surfaced a runtime error. The flow
|
|
57069
|
-
* settles an errored lane immediately (dispatchLaneGroup returns 'failed'
|
|
57070
|
-
* after a forced complete), so the bit normally lives for one turn only —
|
|
57071
|
-
* it is the transport between the gateway's per-session error signal and
|
|
57072
|
-
* this lane's complete request.
|
|
57073
|
-
*/
|
|
57401
|
+
/** Carry the runtime error into the lane's forced completion. */
|
|
57074
57402
|
markTurnError(laneKey, info = {}) {
|
|
57075
57403
|
const lane = this.lanes.get(laneKey);
|
|
57076
57404
|
if (lane)
|
|
@@ -57097,62 +57425,62 @@ ${frame}` : frame;
|
|
|
57097
57425
|
const lane = this.lanes.get(laneKey);
|
|
57098
57426
|
if (!lane || hasMoreLocal)
|
|
57099
57427
|
return;
|
|
57100
|
-
|
|
57101
|
-
|
|
57428
|
+
if (lane.settling)
|
|
57429
|
+
return;
|
|
57430
|
+
lane.settling = true;
|
|
57102
57431
|
const deferred = !lane.turnError && !this.deferredUnsupported ? lane.turnDeferred : void 0;
|
|
57103
57432
|
const outcome = lane.turnError ? "error" : lane.turnDeferred ? this.deferredUnsupported ? "error" : "deferred" : "ok";
|
|
57104
|
-
|
|
57105
|
-
|
|
57106
|
-
|
|
57107
|
-
|
|
57108
|
-
|
|
57109
|
-
|
|
57110
|
-
|
|
57111
|
-
|
|
57112
|
-
|
|
57113
|
-
|
|
57114
|
-
|
|
57115
|
-
|
|
57116
|
-
|
|
57117
|
-
|
|
57118
|
-
|
|
57119
|
-
|
|
57120
|
-
|
|
57121
|
-
|
|
57122
|
-
|
|
57123
|
-
...
|
|
57124
|
-
|
|
57125
|
-
|
|
57126
|
-
|
|
57127
|
-
|
|
57128
|
-
|
|
57129
|
-
|
|
57130
|
-
|
|
57131
|
-
|
|
57132
|
-
} catch (err) {
|
|
57133
|
-
if (isStaleLane(err)) {
|
|
57134
|
-
this.opts.log?.info(`lane complete skipped for ${lane.targetUri} \u2014 taken over`);
|
|
57135
|
-
return;
|
|
57136
|
-
}
|
|
57137
|
-
if (outcome === "deferred" && err instanceof ApiError && err.status === 400) {
|
|
57138
|
-
this.deferredUnsupported = true;
|
|
57139
|
-
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 () => {
|
|
57140
57461
|
try {
|
|
57141
|
-
await this.opts.client.completeDispatch(this.opts.orgId, {
|
|
57142
|
-
lane:
|
|
57143
|
-
target_uri:
|
|
57144
|
-
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,
|
|
57145
57466
|
turn_outcome: "error"
|
|
57146
|
-
});
|
|
57147
|
-
} catch (
|
|
57148
|
-
if (
|
|
57149
|
-
|
|
57150
|
-
|
|
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;
|
|
57151
57480
|
}
|
|
57152
|
-
|
|
57481
|
+
this.forgetLane(lane);
|
|
57153
57482
|
}
|
|
57154
|
-
|
|
57155
|
-
}
|
|
57483
|
+
});
|
|
57156
57484
|
}
|
|
57157
57485
|
/**
|
|
57158
57486
|
* Renew one lane by its key — the external runtime-activity hook for
|
|
@@ -57174,6 +57502,8 @@ ${frame}` : frame;
|
|
|
57174
57502
|
* write's incumbency check anyway.
|
|
57175
57503
|
*/
|
|
57176
57504
|
maybeRenew(lane) {
|
|
57505
|
+
if (isTurnToken(lane.lane))
|
|
57506
|
+
return;
|
|
57177
57507
|
const now = Date.now();
|
|
57178
57508
|
const ttl = lane.leaseTtlMs ?? 10 * 6e4;
|
|
57179
57509
|
const until = lane.leaseUntilMs ?? now;
|
|
@@ -57204,26 +57534,40 @@ ${frame}` : frame;
|
|
|
57204
57534
|
*/
|
|
57205
57535
|
async release(laneKey, reason = "unspecified", info) {
|
|
57206
57536
|
const lane = this.lanes.get(laneKey);
|
|
57207
|
-
if (!lane)
|
|
57537
|
+
if (!lane || lane.settling)
|
|
57208
57538
|
return;
|
|
57209
|
-
|
|
57210
|
-
|
|
57211
|
-
|
|
57212
|
-
|
|
57213
|
-
|
|
57214
|
-
|
|
57215
|
-
|
|
57216
|
-
|
|
57217
|
-
|
|
57218
|
-
|
|
57219
|
-
|
|
57220
|
-
|
|
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
|
+
});
|
|
57221
57552
|
}
|
|
57222
57553
|
async releaseAll(reason = "shutdown") {
|
|
57554
|
+
await this.confirmations.retryNow();
|
|
57223
57555
|
const keys = [...this.lanes.keys()];
|
|
57224
57556
|
for (const key of keys) {
|
|
57225
57557
|
await this.release(key, reason);
|
|
57226
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
|
+
}
|
|
57227
57571
|
}
|
|
57228
57572
|
/** True when any lane is currently active (used by shutdown logging). */
|
|
57229
57573
|
get activeCount() {
|
|
@@ -57238,18 +57582,57 @@ ${frame}` : frame;
|
|
|
57238
57582
|
* — the caller must skip processing.
|
|
57239
57583
|
*/
|
|
57240
57584
|
async claimTyped(ref) {
|
|
57241
|
-
|
|
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);
|
|
57242
57592
|
try {
|
|
57243
|
-
|
|
57244
|
-
|
|
57245
|
-
|
|
57246
|
-
|
|
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
|
+
}
|
|
57247
57616
|
});
|
|
57248
|
-
} catch (err) {
|
|
57249
|
-
if (isEndpointMissing2(err))
|
|
57250
|
-
throw new LedgerUnsupportedError("claim endpoint unavailable");
|
|
57251
|
-
throw err;
|
|
57252
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;
|
|
57253
57636
|
if (!res.claimed || !res.lane || !res.events?.length) {
|
|
57254
57637
|
if (res.reason === "stale") {
|
|
57255
57638
|
this.opts.log?.info(`typed dispatch ${ref.dispatchEventId ?? `${ref.sourceType}:${ref.sourceId}`} resolved by the server as stale (${res.stale_reason ?? "unspecified"})`);
|
|
@@ -57261,6 +57644,8 @@ ${frame}` : frame;
|
|
|
57261
57644
|
}
|
|
57262
57645
|
const workItem = res.events[0];
|
|
57263
57646
|
const targetUri = `dsp:${workItem.id}`;
|
|
57647
|
+
if (this.lanes.has(laneKeyForTarget(targetUri)))
|
|
57648
|
+
return null;
|
|
57264
57649
|
const leaseUntilMs = Date.parse(res.lease_until ?? "");
|
|
57265
57650
|
const lane = {
|
|
57266
57651
|
laneKey: laneKeyForTarget(targetUri),
|
|
@@ -57289,7 +57674,34 @@ ${frame}` : frame;
|
|
|
57289
57674
|
const lane = this.lanes.get(laneKey);
|
|
57290
57675
|
if (!lane)
|
|
57291
57676
|
return;
|
|
57292
|
-
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);
|
|
57293
57705
|
this.removeLaneContext(lane);
|
|
57294
57706
|
}
|
|
57295
57707
|
/**
|
|
@@ -58232,7 +58644,7 @@ async function dispatchLaneGroup(host, opts) {
|
|
|
58232
58644
|
}
|
|
58233
58645
|
async function dispatchLaneGroupInner(host, opts) {
|
|
58234
58646
|
const ledger = host.laneLedger;
|
|
58235
|
-
|
|
58647
|
+
let event = opts.events[opts.events.length - 1];
|
|
58236
58648
|
let lane;
|
|
58237
58649
|
try {
|
|
58238
58650
|
lane = await runInPhaseSpan("claim", () => ledger.ensureLane(opts.events));
|
|
@@ -58250,18 +58662,51 @@ async function dispatchLaneGroupInner(host, opts) {
|
|
|
58250
58662
|
}
|
|
58251
58663
|
return "foreign";
|
|
58252
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];
|
|
58253
58676
|
const pending = ledger.takeFrame(lane);
|
|
58254
58677
|
const frame = pending.frame;
|
|
58255
58678
|
if (!frame && opts.events.every((ev) => lane.seen.has(ev.messageId))) {
|
|
58256
58679
|
host.opts.log?.info(`lane group for ${event.messageId} already rendered by the server frame \u2014 no turn`);
|
|
58257
58680
|
const acknowledge = host.opts.dispatchAdapter.acknowledgeDiscardedInjection?.bind(host.opts.dispatchAdapter);
|
|
58681
|
+
const withdrawn = [];
|
|
58258
58682
|
if (acknowledge) {
|
|
58259
|
-
|
|
58260
|
-
const
|
|
58261
|
-
|
|
58262
|
-
|
|
58263
|
-
|
|
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
|
+
});
|
|
58264
58707
|
}
|
|
58708
|
+
for (const ev of opts.events)
|
|
58709
|
+
host.dispatchedMessages.delete(ev.messageId);
|
|
58265
58710
|
await runInPhaseSpan("settle", () => ledger.completeIfIdle(lane.laneKey, unsettledInjections(host, opts.sessionKey) || opts.hasMoreLocal()));
|
|
58266
58711
|
return "no_turn";
|
|
58267
58712
|
}
|
|
@@ -58447,24 +58892,35 @@ async function consumeTypedDispatch(host, ref, run, hooks) {
|
|
|
58447
58892
|
viaLegacyAck = true;
|
|
58448
58893
|
resolved = settleAck(await runInPhaseSpan("settle", () => hooks.legacyAck(claimed.typedDispatchEventId)));
|
|
58449
58894
|
} else {
|
|
58450
|
-
|
|
58451
|
-
|
|
58452
|
-
|
|
58453
|
-
|
|
58454
|
-
|
|
58455
|
-
|
|
58456
|
-
|
|
58457
|
-
|
|
58458
|
-
|
|
58459
|
-
|
|
58460
|
-
|
|
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;
|
|
58461
58913
|
}
|
|
58462
58914
|
}
|
|
58915
|
+
} catch (err) {
|
|
58916
|
+
ledger.markTurnError(claimed.laneKey, releaseErrorInfo(err, [host.opts.config.api_key]));
|
|
58917
|
+
throw err;
|
|
58463
58918
|
} finally {
|
|
58464
58919
|
settle(resolved);
|
|
58465
58920
|
span.setAttribute("dispatch.lane_result", resolved ? "dispatched" : "released");
|
|
58466
58921
|
if (resolved && !viaLegacyAck) {
|
|
58467
|
-
|
|
58922
|
+
if (!claimed.settling)
|
|
58923
|
+
ledger.dropLocal(claimed.laneKey);
|
|
58468
58924
|
} else {
|
|
58469
58925
|
await runInPhaseSpan("settle", () => ledger.completeIfIdle(claimed.laneKey, false).catch(() => {
|
|
58470
58926
|
}));
|
|
@@ -58904,6 +59360,19 @@ var DispatchInactivityDeadline = class {
|
|
|
58904
59360
|
this.onExpire();
|
|
58905
59361
|
}, delayMs);
|
|
58906
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
|
+
}
|
|
58907
59376
|
dispose() {
|
|
58908
59377
|
if (this.disposed)
|
|
58909
59378
|
return;
|
|
@@ -59813,6 +60282,7 @@ function recordToolCall(sessionKey) {
|
|
|
59813
60282
|
}
|
|
59814
60283
|
|
|
59815
60284
|
// ../agent-core/dist/gateway-base.js
|
|
60285
|
+
var AUTH_INVALID_EXIT_CODE = 86;
|
|
59816
60286
|
var TYPED_EVENT_KINDS = {
|
|
59817
60287
|
task_assign: { type: "task", ackSourceType: "task_activity" },
|
|
59818
60288
|
task_update: { type: "task", ackSourceType: "task_activity" },
|
|
@@ -59982,14 +60452,9 @@ var ParallAgentGateway = class {
|
|
|
59982
60452
|
pendingRestartNotification = null;
|
|
59983
60453
|
laneLedger;
|
|
59984
60454
|
stepPersister;
|
|
59985
|
-
//
|
|
59986
|
-
// desired-state reconciler (see session-lifecycle.ts). The gateway only
|
|
59987
|
-
// declares turn boundaries; ordering, retries and stale-finish rejection
|
|
59988
|
-
// live in the coordinator.
|
|
60455
|
+
// Session lifecycle owns ordering, retries and stale-finish rejection.
|
|
59989
60456
|
sessionLifecycle;
|
|
59990
|
-
//
|
|
59991
|
-
// gateway only triggers it; ordering and ownership live in the finalizer
|
|
59992
|
-
// (see fork-session-finalizer.ts).
|
|
60457
|
+
// ForkSessionFinalizer owns seal → drain → close → release.
|
|
59993
60458
|
forkFinalizer;
|
|
59994
60459
|
// Sticky fallback: flipped when the server predates the ledger (claim
|
|
59995
60460
|
// endpoint 404) so every subsequent dispatch uses the legacy flow.
|
|
@@ -60005,21 +60470,30 @@ var ParallAgentGateway = class {
|
|
|
60005
60470
|
SHUTDOWN_DEADLINE_MS;
|
|
60006
60471
|
FORK_DEADLINE_MS;
|
|
60007
60472
|
DISPATCH_DEADLINE_MS;
|
|
60473
|
+
INACTIVITY_WARN_MS;
|
|
60008
60474
|
constructor(opts) {
|
|
60009
60475
|
this.opts = opts;
|
|
60476
|
+
opts = this.opts = { ...opts, log: redactLogger(opts.log, [opts.config.api_key]) };
|
|
60010
60477
|
if (opts.dispatchContextDir) {
|
|
60478
|
+
const recovery = new DispatchRecovery(() => this.catchUpFromDispatch(), () => this.shuttingDown, (err) => opts.log?.warn(`dispatch recovery failed: ${String(err)}`));
|
|
60011
60479
|
this.laneLedger = new LaneLedger({
|
|
60012
60480
|
client: opts.client,
|
|
60013
60481
|
orgId: opts.config.org_id,
|
|
60014
60482
|
contextDir: opts.dispatchContextDir,
|
|
60015
60483
|
log: opts.log,
|
|
60484
|
+
knownSecrets: [opts.config.api_key],
|
|
60016
60485
|
coverageMode: opts.dispatchAdapter.inputLifecycleMode ?? "implicit",
|
|
60486
|
+
settlementMode: opts.dispatchAdapter.inputSettlementMode,
|
|
60487
|
+
instanceId: opts.instanceId,
|
|
60488
|
+
terminalRetryDelaysMs: opts.laneTerminalRetryDelaysMs,
|
|
60489
|
+
onRecovered: recovery.request,
|
|
60017
60490
|
releaseLocalClaims: (sourceIds) => releaseLocalMessageClaims(this.dispatchedMessages, sourceIds)
|
|
60018
60491
|
});
|
|
60019
60492
|
}
|
|
60020
60493
|
this.SHUTDOWN_DEADLINE_MS = opts.shutdownDeadlineMs ?? 6e4;
|
|
60021
|
-
this.FORK_DEADLINE_MS = opts.forkDeadlineMs ??
|
|
60022
|
-
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;
|
|
60023
60497
|
this.unsubscribeRuntimeActivity = opts.dispatchAdapter.subscribeRuntimeActivity?.((event) => this.handleRuntimeActivity(event));
|
|
60024
60498
|
this.stepPersister = new StepPersister({
|
|
60025
60499
|
client: opts.client,
|
|
@@ -60097,12 +60571,34 @@ var ParallAgentGateway = class {
|
|
|
60097
60571
|
}
|
|
60098
60572
|
});
|
|
60099
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
|
+
});
|
|
60100
60594
|
await ws.connect();
|
|
60101
60595
|
return new Promise((resolve3) => {
|
|
60102
|
-
|
|
60103
|
-
await this.shutdown();
|
|
60596
|
+
if (settled) {
|
|
60104
60597
|
resolve3();
|
|
60105
|
-
|
|
60598
|
+
return;
|
|
60599
|
+
}
|
|
60600
|
+
onSettled = resolve3;
|
|
60601
|
+
abortSignal.addEventListener("abort", () => void finish());
|
|
60106
60602
|
});
|
|
60107
60603
|
}
|
|
60108
60604
|
tryClaimMessage(id) {
|
|
@@ -60183,12 +60679,6 @@ var ParallAgentGateway = class {
|
|
|
60183
60679
|
* this safe: every bridge emits its error events before the turn-boundary
|
|
60184
60680
|
* turn_outcome.
|
|
60185
60681
|
*/
|
|
60186
|
-
/**
|
|
60187
|
-
* Redaction for every runtime-error text that gets persisted or shown: the
|
|
60188
|
-
* turn-outcome detail, the runtime error step and the dispatch-failure
|
|
60189
|
-
* step all surface in the product, and a runtime error can echo the agent
|
|
60190
|
-
* key or a provider credential.
|
|
60191
|
-
*/
|
|
60192
60682
|
redactRuntimeText(text) {
|
|
60193
60683
|
return redactSecrets(text, [this.opts.config.api_key]).slice(0, 2e3);
|
|
60194
60684
|
}
|
|
@@ -60526,6 +61016,7 @@ var ParallAgentGateway = class {
|
|
|
60526
61016
|
step_id: null,
|
|
60527
61017
|
dispatch_event_id: activeLane?.typedDispatchEventId ?? activeLane?.folded.get(event.messageId) ?? null,
|
|
60528
61018
|
lane: activeLane?.lane ?? null,
|
|
61019
|
+
settlement_mode: activeLane?.settlementMode ?? "legacy",
|
|
60529
61020
|
target_uri: activeLane?.targetUri ?? null,
|
|
60530
61021
|
thread_root_id: activeLane?.threadRootId ?? null,
|
|
60531
61022
|
// Typed binding hint for the CLI: which task this dispatch is about
|
|
@@ -60545,13 +61036,19 @@ var ParallAgentGateway = class {
|
|
|
60545
61036
|
threadRootId: contextBody.thread_root_id
|
|
60546
61037
|
});
|
|
60547
61038
|
this.inFlightDispatches++;
|
|
60548
|
-
const
|
|
60549
|
-
|
|
60550
|
-
|
|
60551
|
-
this.opts.
|
|
60552
|
-
|
|
60553
|
-
|
|
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;
|
|
60554
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();
|
|
60555
61052
|
});
|
|
60556
61053
|
let binding = this.sessionBindings.get(sessionKey);
|
|
60557
61054
|
let inputStepsCreated = false;
|
|
@@ -60582,6 +61079,7 @@ var ParallAgentGateway = class {
|
|
|
60582
61079
|
binding = await runInPhaseSpan("session", () => this.bindRuntimeSession(sessionKey, runtimeEvent, contextFilePath, laneContextFilePath2));
|
|
60583
61080
|
if (activeLane) {
|
|
60584
61081
|
bindLaneSession(activeLane, binding.agentSessionId);
|
|
61082
|
+
await this.laneLedger?.syncInputAttribution(activeLane);
|
|
60585
61083
|
}
|
|
60586
61084
|
if (event.targetType === "channel_conversation" && binding.agentSessionId !== priorAgentSessionId) {
|
|
60587
61085
|
try {
|
|
@@ -61221,9 +61719,11 @@ var ParallAgentGateway = class {
|
|
|
61221
61719
|
const activeFork = createActiveForkState(fork, event.targetId, continuationPrefix);
|
|
61222
61720
|
this.forkStates.set(event.targetId, activeFork);
|
|
61223
61721
|
this.dispatchState.activeForks.set(event.targetId, fork.sessionKey);
|
|
61224
|
-
|
|
61225
|
-
|
|
61226
|
-
|
|
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
|
+
}
|
|
61227
61727
|
const firstEventPromise = new Promise((resolve3) => {
|
|
61228
61728
|
activeFork.queue.push({ event, resolve: resolve3 });
|
|
61229
61729
|
});
|
|
@@ -61422,12 +61922,16 @@ ${fullSummary}` : fullSummary;
|
|
|
61422
61922
|
this.sessionId = data.session_id ?? "";
|
|
61423
61923
|
if (this.forkStates.size > 0) {
|
|
61424
61924
|
const targetIds = [...this.forkStates.keys()];
|
|
61425
|
-
|
|
61426
|
-
|
|
61427
|
-
|
|
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
|
+
}
|
|
61428
61932
|
}
|
|
61429
61933
|
}
|
|
61430
|
-
if (this.laneLedger && this.inFlightDispatches === 0 && this.laneLedger.activeCount > 0) {
|
|
61934
|
+
if (this.laneLedger && !this.opts.instanceId && this.inFlightDispatches === 0 && this.laneLedger.activeCount > 0) {
|
|
61431
61935
|
log?.info(`releasing ${this.laneLedger.activeCount} stale lane(s) on reconnect`);
|
|
61432
61936
|
await this.laneLedger.releaseAll();
|
|
61433
61937
|
}
|
|
@@ -61474,6 +61978,7 @@ ${fullSummary}` : fullSummary;
|
|
|
61474
61978
|
uptime: os.uptime()
|
|
61475
61979
|
});
|
|
61476
61980
|
}, intervalSec * 1e3);
|
|
61981
|
+
await this.laneLedger?.retryConfirmations();
|
|
61477
61982
|
this.catchUpFromDispatch().catch((err) => {
|
|
61478
61983
|
log?.warn(`dispatch catch-up failed: ${String(err)}`);
|
|
61479
61984
|
});
|
|
@@ -61559,10 +62064,12 @@ ${fullSummary}` : fullSummary;
|
|
|
61559
62064
|
notifyDrainWaiters() {
|
|
61560
62065
|
this.drainGate.notify();
|
|
61561
62066
|
}
|
|
61562
|
-
async shutdown() {
|
|
62067
|
+
async shutdown(opts = { skipDrain: false }) {
|
|
61563
62068
|
this.shuttingDown = true;
|
|
61564
62069
|
this.idleCompact.abort?.();
|
|
61565
|
-
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()) {
|
|
61566
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`);
|
|
61567
62074
|
await this.drainGate.wait(this.SHUTDOWN_DEADLINE_MS);
|
|
61568
62075
|
if (!this.isDrained()) {
|
|
@@ -61573,7 +62080,7 @@ ${fullSummary}` : fullSummary;
|
|
|
61573
62080
|
}
|
|
61574
62081
|
if (this.heartbeatTimer)
|
|
61575
62082
|
clearInterval(this.heartbeatTimer);
|
|
61576
|
-
if (this.laneLedger
|
|
62083
|
+
if (this.laneLedger) {
|
|
61577
62084
|
this.opts.log?.info(`releasing ${this.laneLedger.activeCount} lane(s) on shutdown`);
|
|
61578
62085
|
await this.laneLedger.releaseAll();
|
|
61579
62086
|
}
|
|
@@ -61593,6 +62100,8 @@ ${fullSummary}` : fullSummary;
|
|
|
61593
62100
|
this.opts.log?.warn(`${lifecycleRemaining} session lifecycle write(s) unreconciled at shutdown`);
|
|
61594
62101
|
}
|
|
61595
62102
|
this.sessionLifecycle.dispose();
|
|
62103
|
+
await this.laneLedger?.retryConfirmations();
|
|
62104
|
+
this.laneLedger?.dispose();
|
|
61596
62105
|
this.opts.ws.disconnect();
|
|
61597
62106
|
this.unsubscribeRuntimeActivity?.();
|
|
61598
62107
|
this.opts.log?.info(`disconnected`);
|
|
@@ -63365,13 +63874,18 @@ var parallGateway = {
|
|
|
63365
63874
|
runtimeKey: orchestratorKey,
|
|
63366
63875
|
runtimeRef: { hostname: os2.hostname(), pid: process.pid },
|
|
63367
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,
|
|
63368
63882
|
// Opts openclaw into the dispatch ledger (claim/fold/complete +
|
|
63369
63883
|
// idempotent reply effects) — the same shared-gateway machinery
|
|
63370
63884
|
// claude/codex ride; openclaw stays buffer-only (no mid-turn steer),
|
|
63371
63885
|
// which the ledger does not require. Replies already flow through
|
|
63372
63886
|
// @parall/cli, which reads PRLL_CONTEXT_DIR (injected in hooks.ts)
|
|
63373
63887
|
// to bind dispatch_lane + reply effect keys.
|
|
63374
|
-
// Design: docs/engineering-design/dispatch-
|
|
63888
|
+
// Design: docs/engineering-design/agent-dispatch-idempotency-design.md#effects.
|
|
63375
63889
|
dispatchContextDir: dispatchLaneContextDir(stateDir),
|
|
63376
63890
|
// Per-session context file (PRLL_CONTEXT_FILE contract) — the CLI's
|
|
63377
63891
|
// TYPED dispatch binding (parall tasks update → task_update effect)
|