@parall/daemon 1.36.1 → 1.37.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/bundle/manifest.json +11 -11
- package/bundle/parall-browser-pod.js +307 -27
- package/bundle/parall-claude-agent.js +363 -50
- package/bundle/parall-codex-agent.js +362 -48
- package/bundle/parall-daemon.js +33473 -31706
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/clip-runtime/browser-daemon-env.d.ts +29 -0
- package/dist/clip-runtime/browser-daemon-env.d.ts.map +1 -0
- package/dist/clip-runtime/browser-daemon-env.js +70 -0
- package/dist/clip-runtime/browser-profile-manager.d.ts +18 -5
- package/dist/clip-runtime/browser-profile-manager.d.ts.map +1 -1
- package/dist/clip-runtime/browser-profile-manager.js +149 -24
- package/dist/clip-runtime/browser-profile-pool.d.ts +250 -0
- package/dist/clip-runtime/browser-profile-pool.d.ts.map +1 -0
- package/dist/clip-runtime/browser-profile-pool.js +581 -0
- package/dist/clip-runtime/index.d.ts +2 -2
- package/dist/clip-runtime/index.d.ts.map +1 -1
- package/dist/clip-runtime/index.js +2 -1
- package/dist/clip-runtime/process-manager.d.ts +5 -3
- package/dist/clip-runtime/process-manager.d.ts.map +1 -1
- package/dist/clip-runtime/subprocess.d.ts +14 -0
- package/dist/clip-runtime/subprocess.d.ts.map +1 -1
- package/dist/clip-runtime/subprocess.js +49 -0
- package/dist/config.d.ts +14 -15
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -26
- package/dist/daemon-main.d.ts +8 -0
- package/dist/daemon-main.d.ts.map +1 -0
- package/dist/daemon-main.js +165 -0
- package/dist/daemon-paths.d.ts +14 -0
- package/dist/daemon-paths.d.ts.map +1 -0
- package/dist/daemon-paths.js +26 -0
- package/dist/daemon-update-mode.d.ts +8 -0
- package/dist/daemon-update-mode.d.ts.map +1 -0
- package/dist/daemon-update-mode.js +18 -0
- package/dist/index.js +41 -167
- package/dist/runtime-bin-resolver.d.ts +4 -0
- package/dist/runtime-bin-resolver.d.ts.map +1 -1
- package/dist/runtime-bin-resolver.js +40 -7
- package/dist/runtime-detector.d.ts +30 -0
- package/dist/runtime-detector.d.ts.map +1 -0
- package/dist/runtime-detector.js +100 -0
- package/dist/supervisor.d.ts +53 -2
- package/dist/supervisor.d.ts.map +1 -1
- package/dist/supervisor.js +604 -67
- package/dist/update-health-gate.d.ts +66 -0
- package/dist/update-health-gate.d.ts.map +1 -0
- package/dist/update-health-gate.js +93 -0
- package/dist/updater-manifest.d.ts +2 -1
- package/dist/updater-manifest.d.ts.map +1 -1
- package/dist/updater-manifest.js +38 -7
- package/dist/updater.d.ts +13 -2
- package/dist/updater.d.ts.map +1 -1
- package/dist/updater.js +126 -17
- package/package.json +6 -6
|
@@ -26647,6 +26647,17 @@ function buildEventBody(event) {
|
|
|
26647
26647
|
if (event.attachedUri)
|
|
26648
26648
|
lines.push(`[Attached: ${sanitizeMeta(event.attachedUri)}]`);
|
|
26649
26649
|
lines.push("", event.body);
|
|
26650
|
+
} else if (event.type === "channel_message") {
|
|
26651
|
+
lines.push(`[Event: channel.message]`);
|
|
26652
|
+
const providerLabel = sanitizeMeta(event.channelProvider ?? "external IM");
|
|
26653
|
+
const convLabel = event.channelExternalConversationId ? `${sanitizeMeta(event.channelExternalConversationId)} (${sanitizeMeta(event.channelConversationType ?? "conversation")})` : sanitizeMeta(event.channelConversationType ?? "conversation");
|
|
26654
|
+
lines.push(`[Channel: ${providerLabel} | conversation: ${convLabel}]`);
|
|
26655
|
+
lines.push(`[From: ${sanitizeMeta(event.senderName)} (external user, not a Parall member)]`);
|
|
26656
|
+
if (event.channelExternalMessageId) {
|
|
26657
|
+
lines.push(`[External message ID: ${sanitizeMeta(event.channelExternalMessageId)}]`);
|
|
26658
|
+
}
|
|
26659
|
+
lines.push(`[Audience: this conversation lives on ${providerLabel}, OUTSIDE Parall. Readers cannot open prll:// links, Parall cards, or internal attachments \u2014 never include them in replies. Write plain conversational text.]`);
|
|
26660
|
+
lines.push("", event.body);
|
|
26650
26661
|
} else if (event.type === "external_trigger") {
|
|
26651
26662
|
lines.push(`[Event: external.trigger]`);
|
|
26652
26663
|
lines.push(`[Trigger: prll://${event.targetId}]`);
|
|
@@ -26688,7 +26699,7 @@ function buildSendMessageHint(event) {
|
|
|
26688
26699
|
}
|
|
26689
26700
|
if (event.targetId.startsWith("cht_")) {
|
|
26690
26701
|
return `
|
|
26691
|
-
<system-reminder>To reply, run
|
|
26702
|
+
<system-reminder>To reply, run \`parall messages send prll://${event.targetId} --text-file - <<'EOF'\` \u2026 \`EOF\` \u2014 the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
|
|
26692
26703
|
}
|
|
26693
26704
|
if (event.targetId.startsWith("tsk_")) {
|
|
26694
26705
|
return `
|
|
@@ -26697,6 +26708,14 @@ function buildSendMessageHint(event) {
|
|
|
26697
26708
|
if (event.targetId.startsWith("sch_")) {
|
|
26698
26709
|
return `
|
|
26699
26710
|
<system-reminder>To communicate, use the CLI: \`parall messages send\` / \`parall dm\`. Your plain text output is not delivered.</system-reminder>`;
|
|
26711
|
+
}
|
|
26712
|
+
if (event.type === "channel_message") {
|
|
26713
|
+
const clipLabel = event.channelProvider ? `the \`${event.channelProvider}\` clip's` : "your channel provider clip's";
|
|
26714
|
+
const apiLabel = event.channelProvider ?? "external platform";
|
|
26715
|
+
const target = event.channelExternalConversationId ? `{"chat_id": "${event.channelExternalConversationId}", "text": "..."}` : `{"chat_id": "<conversation id>", "text": "..."}`;
|
|
26716
|
+
const threadAlt = event.channelExternalMessageId ? ` To reply in-thread to this specific message, use {"message_id": "${event.channelExternalMessageId}", "text": "..."} instead.` : "";
|
|
26717
|
+
return `
|
|
26718
|
+
<system-reminder>To reply, invoke ${clipLabel} \`send_message\` command with ${target} \u2014 your plain text output is NOT delivered to the external conversation.${threadAlt} The same clip's \`call\` command reaches the wider ${apiLabel} API when needed.</system-reminder>`;
|
|
26700
26719
|
}
|
|
26701
26720
|
if (event.type === "external_trigger" || event.targetId.startsWith("xtr_")) {
|
|
26702
26721
|
return `
|
|
@@ -26904,6 +26923,8 @@ Or upload first and reuse across chats:
|
|
|
26904
26923
|
parall messages send prll://cht_aaa --attachment att_yyy --text "Report"
|
|
26905
26924
|
parall messages send prll://cht_bbb --attachment att_yyy --text "FYI"
|
|
26906
26925
|
|
|
26926
|
+
The \`--text\` captions above are safe short literals. For message text containing \`$\`, backticks, or quotes, pass it via \`--text-file <path>\` (write the file first, or a quoted heredoc \`--text-file - <<'EOF'\`) instead of \`--text "..."\` \u2014 inside double quotes the shell turns \`$1,000\` into \`,000\` and executes \`$(...)\`.
|
|
26927
|
+
|
|
26907
26928
|
### When to reference
|
|
26908
26929
|
|
|
26909
26930
|
- **Origin** \u2014 always link the message or task that triggered your work
|
|
@@ -26954,11 +26975,21 @@ To say something in a chat, you **must** invoke the Parall CLI via your shell/ex
|
|
|
26954
26975
|
|
|
26955
26976
|
All outbound interactions go through the \`parall\` CLI. Credentials are pre-injected as environment variables \u2014 no setup needed. If \`parall\` is not on PATH, use \`npx --yes @parall/cli@latest\` instead.
|
|
26956
26977
|
|
|
26957
|
-
- \`parall messages send prll://cht_xxx --text
|
|
26958
|
-
- \`parall dm prll://usr_xxx --text
|
|
26978
|
+
- \`parall messages send prll://cht_xxx --text-file -\` \u2014 reply into the triggering chat (pipe the body via a quoted heredoc; see Shell-safety below)
|
|
26979
|
+
- \`parall dm prll://usr_xxx --text-file - [--no-reply]\` \u2014 direct message another user
|
|
26959
26980
|
- \`parall tasks update prll://tsk_xxx --status in_progress\` \u2014 task state
|
|
26960
26981
|
- \`parall no-reply [--reason "..."]\` \u2014 explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)
|
|
26961
26982
|
|
|
26983
|
+
**Shell-safety \u2014 never wrap real message content in double quotes.** Your command runs in a shell, which expands \`$\`, backticks, and \`$(...)\` inside \`"..."\` before the CLI sees them: \`--text "That costs $1,000"\` sends \`That costs ,000\`, and \`--text "$(cmd)"\` executes \`cmd\`. Pass message bodies via \`--text-file <path>\` (write the file first \u2014 no shell touches it) or a quoted heredoc that disables expansion:
|
|
26984
|
+
|
|
26985
|
+
\`\`\`bash
|
|
26986
|
+
parall messages send prll://cht_xxx --text-file - <<'EOF'
|
|
26987
|
+
That costs $1,000, and $(whoami) stays literal. I'm on it.
|
|
26988
|
+
EOF
|
|
26989
|
+
\`\`\`
|
|
26990
|
+
|
|
26991
|
+
Keep \`--text "..."\` for short literals with no \`$\`, backtick, or apostrophe.
|
|
26992
|
+
|
|
26962
26993
|
The bridge injects Parall context via environment variables. The static credentials \`PRLL_API_URL\`, \`PRLL_API_KEY\`, and \`PRLL_ORG_ID\` are always set. \`PRLL_CONTEXT_FILE\` points to a per-session JSON file that the gateway updates each dispatch with \`session_id\`, \`chat_id\`, \`trigger_message_id\`, \`no_reply\`, and \`step_id\` (updated per tool call). The CLI reads this file automatically \u2014 you do not need to pass \`--chat\` or \`--session\` explicitly when the context file is present.
|
|
26963
26994
|
|
|
26964
26995
|
## Attachments
|
|
@@ -27003,7 +27034,7 @@ Messages may arrive with a \`[Thread: prll://msg_xxx]\` line in the event block,
|
|
|
27003
27034
|
|
|
27004
27035
|
### CLI usage
|
|
27005
27036
|
- The \`msg_xxx\` from the \`[Thread: prll://msg_xxx]\` line is the thread root ID \u2014 pass it as \`--thread-root-id\`
|
|
27006
|
-
- Reply in a thread: \`parall messages send <chatId> --text
|
|
27037
|
+
- Reply in a thread: \`parall messages send <chatId> --text-file /tmp/reply.md --thread-root-id <msgId>\`
|
|
27007
27038
|
- Read thread replies: \`parall messages list <chatId> --thread-root-id <msgId>\`
|
|
27008
27039
|
|
|
27009
27040
|
### Thread etiquette
|
|
@@ -27104,6 +27135,7 @@ var ENDPOINTS = {
|
|
|
27104
27135
|
// Org-scoped
|
|
27105
27136
|
ORG: (orgId) => `${API_BASE}/orgs/${orgId}`,
|
|
27106
27137
|
ORG_MEMBERS: (orgId) => `${API_BASE}/orgs/${orgId}/members`,
|
|
27138
|
+
ORG_MEMBERS_FORMER: (orgId) => `${API_BASE}/orgs/${orgId}/members/former`,
|
|
27107
27139
|
TEAMS: (orgId) => `${API_BASE}/orgs/${orgId}/teams`,
|
|
27108
27140
|
ORG_MEMBERS_ONLINE: (orgId) => `${API_BASE}/orgs/${orgId}/members/online`,
|
|
27109
27141
|
ORG_MEMBER: (orgId, userId) => `${API_BASE}/orgs/${orgId}/members/${userId}`,
|
|
@@ -27253,6 +27285,19 @@ var ENDPOINTS = {
|
|
|
27253
27285
|
EXTERNAL_TRIGGER: (orgId, triggerId) => `${API_BASE}/orgs/${orgId}/external-triggers/${triggerId}`,
|
|
27254
27286
|
EXTERNAL_TRIGGER_RUNS: (orgId) => `${API_BASE}/orgs/${orgId}/external-trigger-runs`,
|
|
27255
27287
|
EXTERNAL_TRIGGER_RUN: (orgId, runId) => `${API_BASE}/orgs/${orgId}/external-trigger-runs/${runId}`,
|
|
27288
|
+
// External IM channel (org-scoped, platform-mediated Feishu/Slack)
|
|
27289
|
+
CHANNEL_CONNECTIONS: (orgId) => `${API_BASE}/orgs/${orgId}/channel-connections`,
|
|
27290
|
+
CHANNEL_CONNECTION: (orgId, connectionId) => `${API_BASE}/orgs/${orgId}/channel-connections/${connectionId}`,
|
|
27291
|
+
CHANNEL_CONNECTION_CREDENTIALS: (orgId, connectionId) => `${API_BASE}/orgs/${orgId}/channel-connections/${connectionId}/credentials`,
|
|
27292
|
+
CHANNEL_CONNECTION_INGRESS_TOKEN_REGENERATE: (orgId, connectionId) => `${API_BASE}/orgs/${orgId}/channel-connections/${connectionId}/ingress-token/regenerate`,
|
|
27293
|
+
CHANNEL_CONNECTION_CONVERSATIONS: (orgId, connectionId) => `${API_BASE}/orgs/${orgId}/channel-connections/${connectionId}/conversations`,
|
|
27294
|
+
CHANNEL_CONVERSATION: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}`,
|
|
27295
|
+
CHANNEL_CONVERSATION_MESSAGES: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}/messages`,
|
|
27296
|
+
CHANNEL_CONVERSATION_SESSION: (orgId, conversationId) => `${API_BASE}/orgs/${orgId}/channel-conversations/${conversationId}/session`,
|
|
27297
|
+
CHANNEL_MESSAGE: (orgId, messageId) => `${API_BASE}/orgs/${orgId}/channel-messages/${messageId}`,
|
|
27298
|
+
CHANNEL_PROVISIONING: (orgId) => `${API_BASE}/orgs/${orgId}/channel-provisioning`,
|
|
27299
|
+
CHANNEL_PROVISIONING_SESSION: (orgId, sessionId) => `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}`,
|
|
27300
|
+
CHANNEL_PROVISIONING_CANCEL: (orgId, sessionId) => `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}/cancel`,
|
|
27256
27301
|
// Invitations (org-scoped, admin)
|
|
27257
27302
|
ORG_INVITATIONS: (orgId) => `${API_BASE}/orgs/${orgId}/invitations`,
|
|
27258
27303
|
ORG_INVITATION: (orgId, invId) => `${API_BASE}/orgs/${orgId}/invitations/${invId}`,
|
|
@@ -27270,9 +27315,16 @@ var ENDPOINTS = {
|
|
|
27270
27315
|
INVITE_LINK_JOIN: `${API_BASE}/invite-link/join`,
|
|
27271
27316
|
// Wikis (org-scoped, served by wiki-service)
|
|
27272
27317
|
WIKIS: (orgId) => `${WIKI_BASE}/orgs/${orgId}/wikis`,
|
|
27318
|
+
// Recycle bin — soft-deleted wikis (owner only). Must precede WIKI in the
|
|
27319
|
+
// backend router so `deleted` isn't captured as a {wikiId}; the SDK builder
|
|
27320
|
+
// is just a string.
|
|
27321
|
+
WIKIS_DELETED: (orgId) => `${WIKI_BASE}/orgs/${orgId}/wikis/deleted`,
|
|
27322
|
+
// Detail URL — also reused for DELETE (soft-delete) and `${WIKI}/restore`.
|
|
27273
27323
|
WIKI: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}`,
|
|
27324
|
+
WIKI_RESTORE: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/restore`,
|
|
27274
27325
|
WIKI_TREE: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/tree`,
|
|
27275
27326
|
WIKI_BLOB: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/blob`,
|
|
27327
|
+
WIKI_COPY: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/copy`,
|
|
27276
27328
|
WIKI_NODE_SECTIONS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/node-sections`,
|
|
27277
27329
|
WIKI_SEARCH: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/search`,
|
|
27278
27330
|
WIKI_PAGE_INDEX: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/page-index`,
|
|
@@ -27355,6 +27407,14 @@ var ENDPOINTS = {
|
|
|
27355
27407
|
BILLING_AUTO_RELOAD: (orgId) => `${API_BASE}/orgs/${orgId}/billing/auto-reload`,
|
|
27356
27408
|
BILLING_SETUP_INTENT: (orgId) => `${API_BASE}/orgs/${orgId}/billing/setup-intent`,
|
|
27357
27409
|
COMPUTE_PRICING: () => `${API_BASE}/billing/compute-pricing`,
|
|
27410
|
+
// Runtime capability table (public, no auth) — SSOT for the create/settings
|
|
27411
|
+
// interlock: per-runtime compute modes, native model family, cross-family
|
|
27412
|
+
// availability, and recommended model.
|
|
27413
|
+
RUNTIMES: () => `${API_BASE}/runtimes`,
|
|
27414
|
+
// Model catalog (public, no auth) — served from the server's DB-backed
|
|
27415
|
+
// snapshot. Optional include_model keeps an agent's pinned hidden legacy
|
|
27416
|
+
// model representable in settings pickers.
|
|
27417
|
+
MODELS: (includeModel) => includeModel ? `${API_BASE}/models?include_model=${encodeURIComponent(includeModel)}` : `${API_BASE}/models`,
|
|
27358
27418
|
// ADMIN_GRANTS intentionally NOT exported here — it sits under the
|
|
27359
27419
|
// unauthenticated `/internal/admin/*` surface and must not bleed into the
|
|
27360
27420
|
// public SDK. Admin dashboard hits the URL directly from its own client.
|
|
@@ -27367,6 +27427,7 @@ var ENDPOINTS = {
|
|
|
27367
27427
|
AGENT_CLIP: (orgId, agentId, clipId) => `${CLIP_BASE}/orgs/${orgId}/agents/${agentId}/clips/${clipId}`,
|
|
27368
27428
|
CLIP_INVOKE: (orgId) => `${CLIP_BASE}/orgs/${orgId}/invoke`,
|
|
27369
27429
|
CLIP_ONLINE: (orgId) => `${CLIP_BASE}/orgs/${orgId}/online`,
|
|
27430
|
+
BROWSER_RUNTIME_STATUS: (orgId) => `${CLIP_BASE}/orgs/${orgId}/browser-runtime/status`,
|
|
27370
27431
|
BROWSER_PROFILES: (orgId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles`,
|
|
27371
27432
|
BROWSER_PROFILE: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}`,
|
|
27372
27433
|
BROWSER_PROFILE_OPEN: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/open`,
|
|
@@ -27420,10 +27481,13 @@ var WS_EVENTS = {
|
|
|
27420
27481
|
INVITATION_REVOKED: "invitation.revoked",
|
|
27421
27482
|
ORG_JOIN_REQUEST_NEW: "org.join_request.new",
|
|
27422
27483
|
ORG_INVITE_LINK_JOINED: "org.invite_link.joined",
|
|
27484
|
+
ORG_MEMBER_REMOVED: "org.member.removed",
|
|
27423
27485
|
AGENT_CONFIG_UPDATE: "agent_config.update",
|
|
27424
27486
|
PRESENCE_UPDATE: "presence.update",
|
|
27425
27487
|
WIKI_CHANGESET_CREATED: "wiki.changeset.created",
|
|
27426
27488
|
WIKI_CHANGESET_UPDATED: "wiki.changeset.updated",
|
|
27489
|
+
WIKI_DELETED: "wiki.deleted",
|
|
27490
|
+
WIKI_RESTORED: "wiki.restored",
|
|
27427
27491
|
COMMENT_CREATED: "comment.created",
|
|
27428
27492
|
COMMENT_UPDATED: "comment.updated",
|
|
27429
27493
|
COMMENT_DELETED: "comment.deleted",
|
|
@@ -27451,6 +27515,7 @@ var WS_EVENTS = {
|
|
|
27451
27515
|
MACHINE_FILESYSTEM_BROWSE: "machine.filesystem.browse",
|
|
27452
27516
|
MACHINE_UPDATE: "machine.update",
|
|
27453
27517
|
MACHINE_CONFIG_UPDATED: "machine.config.updated",
|
|
27518
|
+
MACHINE_AGENT_CONFIG_UPDATED: "machine.agent_config.updated",
|
|
27454
27519
|
MACHINE_CLIP_SYNC: "machine.clip.sync",
|
|
27455
27520
|
MACHINE_BROWSER_PROFILE_LIFECYCLE: "machine.browser_profile.lifecycle",
|
|
27456
27521
|
MACHINE_BROWSER_PROFILE_VIEWER: "machine.browser_profile.viewer",
|
|
@@ -27790,6 +27855,13 @@ var ParallClient = class _ParallClient {
|
|
|
27790
27855
|
const res = await this.request("GET", ENDPOINTS.ORG_MEMBERS(orgId));
|
|
27791
27856
|
return res.data;
|
|
27792
27857
|
}
|
|
27858
|
+
/** User IDs of soft-removed (former) org members — for marking their avatar /
|
|
27859
|
+
* name as "left" where dormant relations still surface them (DMs, task
|
|
27860
|
+
* assignees, message history). */
|
|
27861
|
+
async getFormerMemberIds(orgId) {
|
|
27862
|
+
const res = await this.request("GET", ENDPOINTS.ORG_MEMBERS_FORMER(orgId));
|
|
27863
|
+
return res.user_ids ?? [];
|
|
27864
|
+
}
|
|
27793
27865
|
async getTeams(orgId) {
|
|
27794
27866
|
const res = await this.request("GET", ENDPOINTS.TEAMS(orgId));
|
|
27795
27867
|
return res.data;
|
|
@@ -28278,20 +28350,25 @@ var ParallClient = class _ParallClient {
|
|
|
28278
28350
|
return res.data;
|
|
28279
28351
|
}
|
|
28280
28352
|
/** `POST /machines/me/browser-profiles/{profileId}/status` — report runtime status. */
|
|
28281
|
-
async reportBrowserProfileStatus(profileId, status, errorMsg) {
|
|
28353
|
+
async reportBrowserProfileStatus(profileId, status, errorMsg, generation) {
|
|
28282
28354
|
await this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_STATUS(profileId), {
|
|
28283
28355
|
status,
|
|
28284
|
-
...errorMsg ? { error_msg: errorMsg } : {}
|
|
28356
|
+
...errorMsg ? { error_msg: errorMsg } : {},
|
|
28357
|
+
...generation !== void 0 ? { generation } : {}
|
|
28285
28358
|
});
|
|
28286
28359
|
}
|
|
28287
28360
|
/**
|
|
28288
28361
|
* `POST /machines/me/health` — bump the Machine's `updated_at` to now and
|
|
28289
|
-
* report daemon state. The daemon
|
|
28290
|
-
*
|
|
28362
|
+
* report daemon state. The daemon calls this on startup and again whenever
|
|
28363
|
+
* periodic runtime re-detection produces a CHANGED result (there is no
|
|
28364
|
+
* fixed-cadence keepalive loop today — steady state posts nothing). All
|
|
28291
28365
|
* fields are optional and only persisted when changed:
|
|
28292
28366
|
* - `daemonVersion` — the running bundle/launcher version.
|
|
28293
28367
|
* - `selfUpdateCapable` — whether the daemon can act on a machine.update
|
|
28294
28368
|
* signal (true under a service manager, false for bare `npx` foreground).
|
|
28369
|
+
* - `detectedRuntimes` — runtime CLIs found on the host. Omitted = no
|
|
28370
|
+
* report this beat (server keeps the stored value); [] = detection ran
|
|
28371
|
+
* and found nothing (server clears to empty).
|
|
28295
28372
|
*/
|
|
28296
28373
|
async postMachineHeartbeat(opts) {
|
|
28297
28374
|
const body = {};
|
|
@@ -28299,6 +28376,8 @@ var ParallClient = class _ParallClient {
|
|
|
28299
28376
|
body.daemon_version = opts.daemonVersion;
|
|
28300
28377
|
if (opts?.selfUpdateCapable !== void 0)
|
|
28301
28378
|
body.self_update_capable = opts.selfUpdateCapable;
|
|
28379
|
+
if (opts?.detectedRuntimes !== void 0)
|
|
28380
|
+
body.detected_runtimes = opts.detectedRuntimes;
|
|
28302
28381
|
return this.request("POST", ENDPOINTS.MACHINES_ME_HEALTH, Object.keys(body).length > 0 ? body : void 0);
|
|
28303
28382
|
}
|
|
28304
28383
|
async reportAgentWorkspaceState(agentId, state) {
|
|
@@ -28617,6 +28696,59 @@ var ParallClient = class _ParallClient {
|
|
|
28617
28696
|
async deleteExternalConnection(orgId, connectionId) {
|
|
28618
28697
|
return this.request("DELETE", ENDPOINTS.EXTERNAL_CONNECTION(orgId, connectionId));
|
|
28619
28698
|
}
|
|
28699
|
+
// ---- External IM channel (org-scoped) ----
|
|
28700
|
+
async createChannelConnection(orgId, input) {
|
|
28701
|
+
return this.request("POST", ENDPOINTS.CHANNEL_CONNECTIONS(orgId), input);
|
|
28702
|
+
}
|
|
28703
|
+
async listChannelConnections(orgId) {
|
|
28704
|
+
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTIONS(orgId));
|
|
28705
|
+
}
|
|
28706
|
+
async getChannelConnection(orgId, connectionId) {
|
|
28707
|
+
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION(orgId, connectionId));
|
|
28708
|
+
}
|
|
28709
|
+
async updateChannelConnection(orgId, connectionId, patch) {
|
|
28710
|
+
return this.request("PATCH", ENDPOINTS.CHANNEL_CONNECTION(orgId, connectionId), patch);
|
|
28711
|
+
}
|
|
28712
|
+
async archiveChannelConnection(orgId, connectionId) {
|
|
28713
|
+
return this.request("DELETE", ENDPOINTS.CHANNEL_CONNECTION(orgId, connectionId));
|
|
28714
|
+
}
|
|
28715
|
+
async deliverChannelCredentials(orgId, connectionId, credentials) {
|
|
28716
|
+
return this.request("POST", ENDPOINTS.CHANNEL_CONNECTION_CREDENTIALS(orgId, connectionId), credentials);
|
|
28717
|
+
}
|
|
28718
|
+
async regenerateChannelIngressToken(orgId, connectionId) {
|
|
28719
|
+
return this.request("POST", ENDPOINTS.CHANNEL_CONNECTION_INGRESS_TOKEN_REGENERATE(orgId, connectionId));
|
|
28720
|
+
}
|
|
28721
|
+
/** Start a Feishu one-click provisioning session (device flow QR). */
|
|
28722
|
+
async initiateChannelProvisioning(orgId, input) {
|
|
28723
|
+
return this.request("POST", ENDPOINTS.CHANNEL_PROVISIONING(orgId), input);
|
|
28724
|
+
}
|
|
28725
|
+
/**
|
|
28726
|
+
* Lazy status poll — server-side this may forward one provider poll, so
|
|
28727
|
+
* call it at the session's `poll_interval_seconds` cadence, not faster.
|
|
28728
|
+
*/
|
|
28729
|
+
async getChannelProvisioningSession(orgId, sessionId) {
|
|
28730
|
+
return this.request("GET", ENDPOINTS.CHANNEL_PROVISIONING_SESSION(orgId, sessionId));
|
|
28731
|
+
}
|
|
28732
|
+
async cancelChannelProvisioning(orgId, sessionId) {
|
|
28733
|
+
return this.request("POST", ENDPOINTS.CHANNEL_PROVISIONING_CANCEL(orgId, sessionId));
|
|
28734
|
+
}
|
|
28735
|
+
async listChannelConversations(orgId, connectionId) {
|
|
28736
|
+
return this.request("GET", ENDPOINTS.CHANNEL_CONNECTION_CONVERSATIONS(orgId, connectionId));
|
|
28737
|
+
}
|
|
28738
|
+
async getChannelConversation(orgId, conversationId) {
|
|
28739
|
+
return this.request("GET", ENDPOINTS.CHANNEL_CONVERSATION(orgId, conversationId));
|
|
28740
|
+
}
|
|
28741
|
+
async listChannelConversationMessages(orgId, conversationId, limit) {
|
|
28742
|
+
return this.request("GET", ENDPOINTS.CHANNEL_CONVERSATION_MESSAGES(orgId, conversationId), void 0, { limit });
|
|
28743
|
+
}
|
|
28744
|
+
async setChannelConversationSession(orgId, conversationId, agentSessionId) {
|
|
28745
|
+
return this.request("PATCH", ENDPOINTS.CHANNEL_CONVERSATION_SESSION(orgId, conversationId), {
|
|
28746
|
+
agent_session_id: agentSessionId
|
|
28747
|
+
});
|
|
28748
|
+
}
|
|
28749
|
+
async getChannelMessage(orgId, messageId) {
|
|
28750
|
+
return this.request("GET", ENDPOINTS.CHANNEL_MESSAGE(orgId, messageId));
|
|
28751
|
+
}
|
|
28620
28752
|
async getExternalTriggerSchema(orgId, connectionId) {
|
|
28621
28753
|
return this.request("GET", ENDPOINTS.EXTERNAL_TRIGGER_SCHEMA(orgId, connectionId));
|
|
28622
28754
|
}
|
|
@@ -28658,6 +28790,23 @@ var ParallClient = class _ParallClient {
|
|
|
28658
28790
|
async getWiki(orgId, wikiId) {
|
|
28659
28791
|
return this.request("GET", ENDPOINTS.WIKI(orgId, wikiId));
|
|
28660
28792
|
}
|
|
28793
|
+
/** Soft-delete an entire wiki (org owner only; the default wiki is
|
|
28794
|
+
* protected → 403 WIKI_PROTECTED). Returns the deleted wiki. Recoverable
|
|
28795
|
+
* via restoreWiki within the retention window. */
|
|
28796
|
+
async deleteWiki(orgId, wikiId) {
|
|
28797
|
+
return this.request("DELETE", ENDPOINTS.WIKI(orgId, wikiId));
|
|
28798
|
+
}
|
|
28799
|
+
/** Restore a soft-deleted wiki (org owner only). 409 WIKI_PURGE_STARTED once
|
|
28800
|
+
* purge has been claimed (no longer restorable), or 404 once the row is gone.
|
|
28801
|
+
* Returns the restored wiki. */
|
|
28802
|
+
async restoreWiki(orgId, wikiId) {
|
|
28803
|
+
return this.request("POST", ENDPOINTS.WIKI_RESTORE(orgId, wikiId));
|
|
28804
|
+
}
|
|
28805
|
+
/** Recycle bin — list soft-deleted wikis for the org (owner only). */
|
|
28806
|
+
async getDeletedWikis(orgId) {
|
|
28807
|
+
const res = await this.request("GET", ENDPOINTS.WIKIS_DELETED(orgId));
|
|
28808
|
+
return res.data;
|
|
28809
|
+
}
|
|
28661
28810
|
async getWikiTree(orgId, wikiId, params) {
|
|
28662
28811
|
return this.request("GET", ENDPOINTS.WIKI_TREE(orgId, wikiId), void 0, params);
|
|
28663
28812
|
}
|
|
@@ -28691,6 +28840,15 @@ var ParallClient = class _ParallClient {
|
|
|
28691
28840
|
blob.signed_url = this.absoluteMediaUrl(blob.signed_url);
|
|
28692
28841
|
return blob;
|
|
28693
28842
|
}
|
|
28843
|
+
/**
|
|
28844
|
+
* Copy one wiki file to another path as an independent snapshot (no sync).
|
|
28845
|
+
* Used to "share a private file out": copy a file from the caller's personal
|
|
28846
|
+
* namespace (`users/{userId}/…`) into the public wiki, leaving the original
|
|
28847
|
+
* untouched. 409 `FILE_EXISTS` if `dest_path` already exists.
|
|
28848
|
+
*/
|
|
28849
|
+
async copyWikiFile(orgId, wikiId, req) {
|
|
28850
|
+
return this.request("POST", ENDPOINTS.WIKI_COPY(orgId, wikiId), req);
|
|
28851
|
+
}
|
|
28694
28852
|
async getWikiNodeSections(orgId, wikiId, params) {
|
|
28695
28853
|
return this.request("GET", ENDPOINTS.WIKI_NODE_SECTIONS(orgId, wikiId), void 0, params);
|
|
28696
28854
|
}
|
|
@@ -28964,6 +29122,19 @@ var ParallClient = class _ParallClient {
|
|
|
28964
29122
|
const resp = await this.request("GET", ENDPOINTS.COMPUTE_PRICING());
|
|
28965
29123
|
return resp.data;
|
|
28966
29124
|
}
|
|
29125
|
+
/** Runtime capability table (public) — SSOT for the create/settings interlock. */
|
|
29126
|
+
async getRuntimes() {
|
|
29127
|
+
const resp = await this.request("GET", ENDPOINTS.RUNTIMES());
|
|
29128
|
+
return resp.data;
|
|
29129
|
+
}
|
|
29130
|
+
/**
|
|
29131
|
+
* Platform model catalog (public) — DB-backed, replaces the compile-time
|
|
29132
|
+
* PLATFORM_MODELS constant. Pass includeModel to keep an agent's pinned
|
|
29133
|
+
* hidden legacy model representable (settings picker).
|
|
29134
|
+
*/
|
|
29135
|
+
async getModels(includeModel) {
|
|
29136
|
+
return this.request("GET", ENDPOINTS.MODELS(includeModel));
|
|
29137
|
+
}
|
|
28967
29138
|
// ---- Clips ----
|
|
28968
29139
|
async listClips(orgId) {
|
|
28969
29140
|
const resp = await this.request("GET", ENDPOINTS.CLIPS(orgId));
|
|
@@ -29008,6 +29179,11 @@ var ParallClient = class _ParallClient {
|
|
|
29008
29179
|
const resp = await this.request("GET", ENDPOINTS.CLIP_ONLINE(orgId));
|
|
29009
29180
|
return resp.data;
|
|
29010
29181
|
}
|
|
29182
|
+
/** Deployment-wide hosted browser runtime availability — drives whether the
|
|
29183
|
+
* create UI offers the platform-hosted placement. Fail-closed server-side. */
|
|
29184
|
+
async getBrowserRuntimeStatus(orgId) {
|
|
29185
|
+
return this.request("GET", ENDPOINTS.BROWSER_RUNTIME_STATUS(orgId));
|
|
29186
|
+
}
|
|
29011
29187
|
/** Org-wide browser-profile discovery list. Returns the sanitized
|
|
29012
29188
|
* {@link BrowserProfileListItem} shape (not the full domain model), each row
|
|
29013
29189
|
* carrying a per-viewer `can_open` control hint. */
|
|
@@ -29667,6 +29843,9 @@ function resolveStepTarget(event) {
|
|
|
29667
29843
|
if (event.type === "external_trigger" || event.targetId.startsWith("xtr_")) {
|
|
29668
29844
|
return { target_type: "external_trigger", target_id: event.targetId };
|
|
29669
29845
|
}
|
|
29846
|
+
if (event.type === "channel_message" || event.targetId.startsWith("chv_")) {
|
|
29847
|
+
return { target_type: "channel_conversation", target_id: event.targetId };
|
|
29848
|
+
}
|
|
29670
29849
|
if (event.type === "wiki_comment") {
|
|
29671
29850
|
return { target_type: "wiki", target_id: event.targetId || void 0 };
|
|
29672
29851
|
}
|
|
@@ -29710,6 +29889,9 @@ var ParallAgentGateway = class {
|
|
|
29710
29889
|
opts;
|
|
29711
29890
|
chatInfoMap = /* @__PURE__ */ new Map();
|
|
29712
29891
|
dispatchedTasks = /* @__PURE__ */ new Set();
|
|
29892
|
+
// connection id → provider alias, for channel_message prompt labeling
|
|
29893
|
+
// (stable mapping; avoids one connection fetch per inbound message).
|
|
29894
|
+
channelConnectionProviders = /* @__PURE__ */ new Map();
|
|
29713
29895
|
dispatchedMessages = /* @__PURE__ */ new Set();
|
|
29714
29896
|
forkStates = /* @__PURE__ */ new Map();
|
|
29715
29897
|
dispatchState = {
|
|
@@ -29883,6 +30065,18 @@ var ParallAgentGateway = class {
|
|
|
29883
30065
|
} catch (err) {
|
|
29884
30066
|
this.opts.log?.error(`external trigger dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
29885
30067
|
}
|
|
30068
|
+
} else if (data.event_type === "channel_message") {
|
|
30069
|
+
if (!data.source_id)
|
|
30070
|
+
return;
|
|
30071
|
+
try {
|
|
30072
|
+
const dispatched = await this.fetchAndHandleChannelMessage(data.source_id);
|
|
30073
|
+
if (dispatched) {
|
|
30074
|
+
this.opts.client.ackDispatchByID(this.opts.config.org_id, data.id).catch(() => {
|
|
30075
|
+
});
|
|
30076
|
+
}
|
|
30077
|
+
} catch (err) {
|
|
30078
|
+
this.opts.log?.error(`channel message dispatch failed for ${data.source_id}: ${String(err)}`);
|
|
30079
|
+
}
|
|
29886
30080
|
} else if (data.event_type === "approval_decided") {
|
|
29887
30081
|
if (!data.source_id)
|
|
29888
30082
|
return;
|
|
@@ -29961,12 +30155,17 @@ var ParallAgentGateway = class {
|
|
|
29961
30155
|
target_type: target.target_type,
|
|
29962
30156
|
target_id: target.target_id,
|
|
29963
30157
|
content: {
|
|
29964
|
-
trigger_type: event.type === "task" ? "task_assign" : event.type === "task_comment" ? "task_comment" : event.type === "wiki_comment" ? "wiki_comment" : event.type === "schedule" ? "schedule_fire" : event.type === "external_trigger" ? "external_trigger" : event.type === "approval" ? "approval_decided" : "mention",
|
|
30158
|
+
trigger_type: event.type === "task" ? "task_assign" : event.type === "task_comment" ? "task_comment" : event.type === "wiki_comment" ? "wiki_comment" : event.type === "schedule" ? "schedule_fire" : event.type === "external_trigger" ? "external_trigger" : event.type === "channel_message" ? "channel_message" : event.type === "approval" ? "approval_decided" : "mention",
|
|
29965
30159
|
trigger_ref: event.type === "task" ? { task_id: event.targetId } : event.type === "task_comment" ? { comment_id: event.messageId, task_id: event.targetId } : event.type === "wiki_comment" ? { comment_id: event.messageId, target_uri: event.replyTargetUri } : event.type === "schedule" ? { schedule_id: event.targetId, run_id: event.messageId } : event.type === "external_trigger" ? {
|
|
29966
30160
|
trigger_id: event.targetId,
|
|
29967
30161
|
run_id: event.messageId,
|
|
29968
30162
|
connection_id: event.externalConnectionId,
|
|
29969
30163
|
ingress_event_id: event.externalIngressEventId
|
|
30164
|
+
} : event.type === "channel_message" ? {
|
|
30165
|
+
conversation_id: event.targetId,
|
|
30166
|
+
channel_message_id: event.messageId,
|
|
30167
|
+
provider: event.channelProvider,
|
|
30168
|
+
external_conversation_id: event.channelExternalConversationId
|
|
29970
30169
|
} : event.type === "approval" ? { approval_id: event.messageId } : { message_id: event.messageId },
|
|
29971
30170
|
sender_id: event.senderId,
|
|
29972
30171
|
sender_name: event.senderName,
|
|
@@ -30217,7 +30416,15 @@ var ParallAgentGateway = class {
|
|
|
30217
30416
|
context: dispatchContext
|
|
30218
30417
|
})) {
|
|
30219
30418
|
if (runtimeEvent.type === "runtime_session") {
|
|
30419
|
+
const priorAgentSessionId = binding?.agentSessionId;
|
|
30220
30420
|
binding = await this.bindRuntimeSession(sessionKey, runtimeEvent, contextFilePath);
|
|
30421
|
+
if (event.targetType === "channel_conversation" && binding.agentSessionId !== priorAgentSessionId) {
|
|
30422
|
+
try {
|
|
30423
|
+
await this.opts.client.setChannelConversationSession(this.opts.config.org_id, event.targetId, binding.agentSessionId);
|
|
30424
|
+
} catch (err) {
|
|
30425
|
+
this.opts.log?.warn(`failed to record session mapping for channel conversation ${event.targetId}: ${String(err)}`);
|
|
30426
|
+
}
|
|
30427
|
+
}
|
|
30221
30428
|
if (!inputStepsCreated) {
|
|
30222
30429
|
if (earlierEvents.length > 0) {
|
|
30223
30430
|
await this.createInputStepsForEarlierEvents(binding.agentSessionId, earlierEvents);
|
|
@@ -31020,6 +31227,75 @@ var ParallAgentGateway = class {
|
|
|
31020
31227
|
return true;
|
|
31021
31228
|
return this.handleExternalTriggerRun(run);
|
|
31022
31229
|
}
|
|
31230
|
+
// fetchAndHandleChannelMessage resolves a channel_message dispatch to its
|
|
31231
|
+
// durable ChannelMessage + conversation and hands it to the inbound
|
|
31232
|
+
// pipeline. targetId = the ChannelConversation id, so per-conversation
|
|
31233
|
+
// multi-turn continuity rides the same per-target session mechanics as
|
|
31234
|
+
// chats. Design: docs/engineering-design/external-im-channel-design.md.
|
|
31235
|
+
async fetchAndHandleChannelMessage(messageId) {
|
|
31236
|
+
if (this.shuttingDown)
|
|
31237
|
+
return false;
|
|
31238
|
+
const claimKey = `channel_message:${messageId}`;
|
|
31239
|
+
if (!this.tryClaimMessage(claimKey))
|
|
31240
|
+
return false;
|
|
31241
|
+
let msg = null;
|
|
31242
|
+
let conv = null;
|
|
31243
|
+
try {
|
|
31244
|
+
msg = await this.opts.client.getChannelMessage(this.opts.config.org_id, messageId);
|
|
31245
|
+
conv = await this.opts.client.getChannelConversation(this.opts.config.org_id, msg.conversation_id);
|
|
31246
|
+
} catch (err) {
|
|
31247
|
+
const status = err?.status;
|
|
31248
|
+
if (status === 404) {
|
|
31249
|
+
this.opts.log?.warn(`channel message ${messageId} not accessible (404), acking stale dispatch`);
|
|
31250
|
+
return true;
|
|
31251
|
+
}
|
|
31252
|
+
this.dispatchedMessages.delete(claimKey);
|
|
31253
|
+
this.opts.log?.warn(`channel message fetch failed for ${messageId}, leaving pending: ${String(err)}`);
|
|
31254
|
+
return false;
|
|
31255
|
+
}
|
|
31256
|
+
if (!msg || !conv) {
|
|
31257
|
+
return true;
|
|
31258
|
+
}
|
|
31259
|
+
this.opts.log?.info(`channel message: ${msg.id} (conversation ${conv.id})`);
|
|
31260
|
+
let provider = this.channelConnectionProviders.get(conv.connection_id);
|
|
31261
|
+
if (!provider) {
|
|
31262
|
+
try {
|
|
31263
|
+
const connection = await this.opts.client.getChannelConnection(this.opts.config.org_id, conv.connection_id);
|
|
31264
|
+
provider = connection.provider;
|
|
31265
|
+
this.channelConnectionProviders.set(conv.connection_id, provider);
|
|
31266
|
+
} catch {
|
|
31267
|
+
provider = void 0;
|
|
31268
|
+
}
|
|
31269
|
+
}
|
|
31270
|
+
const event = {
|
|
31271
|
+
type: "channel_message",
|
|
31272
|
+
targetId: conv.id,
|
|
31273
|
+
targetName: conv.external_user_name || conv.external_conversation_id,
|
|
31274
|
+
targetType: "channel_conversation",
|
|
31275
|
+
senderId: msg.external_user_id || "external",
|
|
31276
|
+
senderName: msg.external_user_name || msg.external_user_id || "external user",
|
|
31277
|
+
messageId: msg.id,
|
|
31278
|
+
body: msg.text,
|
|
31279
|
+
sentAt: msg.received_at,
|
|
31280
|
+
channelProvider: provider,
|
|
31281
|
+
channelConversationType: conv.conversation_type || void 0,
|
|
31282
|
+
channelExternalConversationId: conv.external_conversation_id,
|
|
31283
|
+
channelExternalMessageId: msg.external_message_id,
|
|
31284
|
+
ackSourceType: "channel_message",
|
|
31285
|
+
ackSourceId: msg.id
|
|
31286
|
+
};
|
|
31287
|
+
let dispatched;
|
|
31288
|
+
try {
|
|
31289
|
+
dispatched = await this.handleInboundEvent(event);
|
|
31290
|
+
} catch (err) {
|
|
31291
|
+
this.dispatchedMessages.delete(claimKey);
|
|
31292
|
+
throw err;
|
|
31293
|
+
}
|
|
31294
|
+
if (!dispatched) {
|
|
31295
|
+
this.dispatchedMessages.delete(claimKey);
|
|
31296
|
+
}
|
|
31297
|
+
return dispatched;
|
|
31298
|
+
}
|
|
31023
31299
|
async handleExternalTriggerRun(run) {
|
|
31024
31300
|
if (this.shuttingDown)
|
|
31025
31301
|
return false;
|
|
@@ -31171,6 +31447,8 @@ var ParallAgentGateway = class {
|
|
|
31171
31447
|
dispatched = await this.fetchAndHandleScheduleFire(item.source_id, item.actor_id);
|
|
31172
31448
|
} else if (item.event_type === "external_trigger" && item.source_id) {
|
|
31173
31449
|
dispatched = await this.fetchAndHandleExternalTriggerRun(item.source_id);
|
|
31450
|
+
} else if (item.event_type === "channel_message" && item.source_id) {
|
|
31451
|
+
dispatched = await this.fetchAndHandleChannelMessage(item.source_id);
|
|
31174
31452
|
} else if (item.event_type === "approval_decided" && item.source_id) {
|
|
31175
31453
|
dispatched = await this.fetchAndHandleApprovalDecided(item.source_id, item.actor_id, item.chat_id ?? null);
|
|
31176
31454
|
} else if (item.event_type === "message" && item.source_id && item.chat_id) {
|
|
@@ -31368,6 +31646,9 @@ function resolveRuntimeModel(isOperatorOverride, platformModel, configModel) {
|
|
|
31368
31646
|
const operatorOverride = isOperatorOverride ? platformModel : null;
|
|
31369
31647
|
return operatorOverride ?? configModel ?? platformModel ?? void 0;
|
|
31370
31648
|
}
|
|
31649
|
+
function deriveModelIsPin(defaults, profile) {
|
|
31650
|
+
return defaults.modelIsPin !== void 0 ? defaults.modelIsPin : isPlatformModelOverride(profile);
|
|
31651
|
+
}
|
|
31371
31652
|
var CACHE_FILENAME = "parall-platform-config.json";
|
|
31372
31653
|
var SUPPORTED_SCHEMA_VERSION = 1;
|
|
31373
31654
|
function cachePath(stateDir) {
|
|
@@ -31385,6 +31666,7 @@ function saveCache(stateDir, response) {
|
|
|
31385
31666
|
const cached = {
|
|
31386
31667
|
version: response.version,
|
|
31387
31668
|
config: response.config,
|
|
31669
|
+
modelIsPin: response.model_is_pin,
|
|
31388
31670
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
31389
31671
|
};
|
|
31390
31672
|
const filePath = cachePath(stateDir);
|
|
@@ -31395,23 +31677,27 @@ function saveCache(stateDir, response) {
|
|
|
31395
31677
|
}
|
|
31396
31678
|
function runtimeModelName(canonicalModel, runtimeType, config) {
|
|
31397
31679
|
const runtime = runtimeType?.trim();
|
|
31398
|
-
if (!runtime || runtime === "openclaw")
|
|
31680
|
+
if (!runtime || runtime === "openclaw" || runtime === "hermes")
|
|
31399
31681
|
return canonicalModel;
|
|
31400
31682
|
const models = config.models ?? {};
|
|
31401
31683
|
const providers = models.providers ?? {};
|
|
31402
31684
|
const parall = providers.parall ?? {};
|
|
31403
31685
|
const catalog = Array.isArray(parall.models) ? parall.models : [];
|
|
31404
31686
|
const match = catalog.find((model) => model.id === canonicalModel);
|
|
31405
|
-
|
|
31687
|
+
if (!match)
|
|
31688
|
+
return null;
|
|
31689
|
+
const runtimeNames = match.runtime_names ?? {};
|
|
31406
31690
|
const runtimeName = runtimeNames[runtime];
|
|
31407
|
-
|
|
31691
|
+
if (typeof runtimeName === "string" && runtimeName)
|
|
31692
|
+
return runtimeName;
|
|
31693
|
+
return canonicalModel;
|
|
31408
31694
|
}
|
|
31409
31695
|
function extractDefaults(config, runtimeType) {
|
|
31410
31696
|
const agents = config.agents ?? {};
|
|
31411
31697
|
const defaults = agents.defaults ?? {};
|
|
31412
31698
|
let model = null;
|
|
31413
31699
|
if (typeof defaults.model === "string" && defaults.model) {
|
|
31414
|
-
const canonicalModel = defaults.model.replace(/^parall\//, "");
|
|
31700
|
+
const canonicalModel = defaults.model.replace(/^parall-anthropic\//, "").replace(/^parall\//, "");
|
|
31415
31701
|
model = runtimeModelName(canonicalModel, runtimeType, config);
|
|
31416
31702
|
}
|
|
31417
31703
|
let thinkingEffort = null;
|
|
@@ -31423,13 +31709,20 @@ function extractDefaults(config, runtimeType) {
|
|
|
31423
31709
|
function createPlatformConfigManager(opts) {
|
|
31424
31710
|
const { client, stateDir, runtimeType, log: log2 } = opts;
|
|
31425
31711
|
let cachedVersion;
|
|
31426
|
-
let currentDefaults = {
|
|
31712
|
+
let currentDefaults = {
|
|
31713
|
+
model: null,
|
|
31714
|
+
thinkingEffort: null,
|
|
31715
|
+
modelIsPin: void 0
|
|
31716
|
+
};
|
|
31427
31717
|
let currentRawConfig = null;
|
|
31428
31718
|
const cached = loadCache(stateDir);
|
|
31429
31719
|
if (cached) {
|
|
31430
|
-
cachedVersion = cached.version;
|
|
31720
|
+
cachedVersion = cached.modelIsPin === void 0 ? void 0 : cached.version;
|
|
31431
31721
|
currentRawConfig = cached.config;
|
|
31432
|
-
currentDefaults =
|
|
31722
|
+
currentDefaults = {
|
|
31723
|
+
...extractDefaults(cached.config, runtimeType),
|
|
31724
|
+
modelIsPin: cached.modelIsPin
|
|
31725
|
+
};
|
|
31433
31726
|
}
|
|
31434
31727
|
return {
|
|
31435
31728
|
async fetch() {
|
|
@@ -31455,7 +31748,10 @@ function createPlatformConfigManager(opts) {
|
|
|
31455
31748
|
saveCache(stateDir, fresh);
|
|
31456
31749
|
cachedVersion = fresh.version;
|
|
31457
31750
|
currentRawConfig = fresh.config;
|
|
31458
|
-
currentDefaults =
|
|
31751
|
+
currentDefaults = {
|
|
31752
|
+
...extractDefaults(fresh.config, runtimeType),
|
|
31753
|
+
modelIsPin: fresh.model_is_pin
|
|
31754
|
+
};
|
|
31459
31755
|
return currentDefaults;
|
|
31460
31756
|
},
|
|
31461
31757
|
current() {
|
|
@@ -31572,16 +31868,35 @@ original discussion and its approval/rejection IS the precedent.
|
|
|
31572
31868
|
|
|
31573
31869
|
Each \`[Event: message.new]\` includes \`[Chat: ... (prll://cht_xxx)]\` \u2014 use that chat URI to reply.
|
|
31574
31870
|
|
|
31871
|
+
> **How you pass the message body matters \u2014 your command runs through a shell.**
|
|
31872
|
+
> Inside double quotes the shell expands \`$\`, backticks, and \`$(...)\` *before*
|
|
31873
|
+
> the CLI sees them: \`--text "That costs $1,000"\` sends \`That costs ,000\`, and
|
|
31874
|
+
> \`--text "$(cmd)"\` runs \`cmd\`. Single quotes instead break on apostrophes
|
|
31875
|
+
> (\`I'm\`, \`don't\`). So do **not** wrap real message content in quotes \u2014 pass it
|
|
31876
|
+
> through \`--text-file\` (a written file, or a quoted heredoc \`<<'EOF'\` that
|
|
31877
|
+
> disables all expansion). Reserve \`--text "..."\` for short literals with no
|
|
31878
|
+
> \`$\`, backtick, or apostrophe.
|
|
31879
|
+
|
|
31575
31880
|
\`\`\`bash
|
|
31576
|
-
#
|
|
31577
|
-
|
|
31881
|
+
# One-off reply \u2192 quoted heredoc into stdin. The quoted delimiter <<'EOF'
|
|
31882
|
+
# disables ALL shell expansion, so $, backticks and apostrophes pass verbatim.
|
|
31883
|
+
parall messages send prll://cht_xxx --text-file - <<'PARALL_EOF'
|
|
31884
|
+
Sure \u2014 that's $1,000, and $(whoami) stays literal. I'm on it.
|
|
31885
|
+
PARALL_EOF
|
|
31578
31886
|
|
|
31579
|
-
#
|
|
31580
|
-
|
|
31887
|
+
# Longer / multi-line reply \u2192 write it with your file tool (no shell touches
|
|
31888
|
+
# the body), then point --text-file at the file.
|
|
31889
|
+
parall messages send prll://cht_xxx --text-file /tmp/reply.md
|
|
31890
|
+
|
|
31891
|
+
# Short literal with no $, backtick, or apostrophe \u2192 --text is fine.
|
|
31892
|
+
parall messages send prll://cht_xxx --text "On it"
|
|
31893
|
+
|
|
31894
|
+
# Direct message by user URI or display name (same --text-file / heredoc rules)
|
|
31895
|
+
parall dm prll://usr_xxx --text-file /tmp/reply.md
|
|
31581
31896
|
parall dm "Alice" --text "Hello"
|
|
31582
31897
|
|
|
31583
31898
|
# Thread reply
|
|
31584
|
-
parall messages send prll://cht_xxx --text
|
|
31899
|
+
parall messages send prll://cht_xxx --text-file /tmp/reply.md --thread-root-id 01JWC...
|
|
31585
31900
|
|
|
31586
31901
|
# FYI message (no response expected \u2014 the recipient sees \`[Hint: no_reply]\`)
|
|
31587
31902
|
parall messages send prll://cht_xxx --text "FYI: done" --no-reply
|
|
@@ -31613,7 +31928,9 @@ parall messages send prll://cht_xxx --attachment att_xxx --text "See attached"
|
|
|
31613
31928
|
parall dm "Alice" --file /tmp/report.pdf --text "Report attached"
|
|
31614
31929
|
\`\`\`
|
|
31615
31930
|
|
|
31616
|
-
\`--file\` and \`--attachment\` are mutually exclusive. \`--text\`
|
|
31931
|
+
\`--file\` and \`--attachment\` are mutually exclusive. A caption (\`--text\` for
|
|
31932
|
+
short literals, or \`--text-file\` for anything with \`$\`, backticks, or quotes)
|
|
31933
|
+
can be combined with either.
|
|
31617
31934
|
|
|
31618
31935
|
## Approvals
|
|
31619
31936
|
|
|
@@ -33792,14 +34109,13 @@ async function main() {
|
|
|
33792
34109
|
log: agentLog
|
|
33793
34110
|
});
|
|
33794
34111
|
const platformDefaults = await configMgr.fetch();
|
|
33795
|
-
|
|
33796
|
-
let platformModelOverride = isPlatformModelOverride(me.agent_profile);
|
|
34112
|
+
const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
|
|
33797
34113
|
const resolvedModel = resolveRuntimeModel(platformModelOverride, platformDefaults.model, config.model);
|
|
33798
|
-
const resolvedEffort =
|
|
34114
|
+
const resolvedEffort = platformDefaults.thinkingEffort ?? (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || void 0);
|
|
33799
34115
|
if (platformDefaults.model)
|
|
33800
|
-
agentLog.info(`platform config: model=${platformDefaults.model} \u2192 resolved=${resolvedModel ?? "cli-default"} (${platformModelOverride ? "
|
|
34116
|
+
agentLog.info(`platform config: model=${platformDefaults.model} \u2192 resolved=${resolvedModel ?? "cli-default"} (${platformModelOverride ? "pin/override" : "floor"})`);
|
|
33801
34117
|
if (platformDefaults.thinkingEffort)
|
|
33802
|
-
agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort}
|
|
34118
|
+
agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort}`);
|
|
33803
34119
|
const adapter = new ClaudeCodeAdapter({
|
|
33804
34120
|
claudeBin: config.claudeBin,
|
|
33805
34121
|
claudeHome: config.claudeHome,
|
|
@@ -33824,6 +34140,23 @@ async function main() {
|
|
|
33824
34140
|
if (resolvedEffort) {
|
|
33825
34141
|
adapter.updateConfig({ effort: resolvedEffort });
|
|
33826
34142
|
}
|
|
34143
|
+
const refreshPlatformConfig = async () => {
|
|
34144
|
+
const updated = await configMgr.fetch();
|
|
34145
|
+
let refreshedProfile;
|
|
34146
|
+
if (updated.modelIsPin === void 0) {
|
|
34147
|
+
try {
|
|
34148
|
+
refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId)).agent_profile;
|
|
34149
|
+
} catch (err) {
|
|
34150
|
+
agentLog.warn(`platform config refresh: legacy /agents/me fallback failed: ${String(err)}`);
|
|
34151
|
+
}
|
|
34152
|
+
}
|
|
34153
|
+
const isPin = deriveModelIsPin(updated, refreshedProfile);
|
|
34154
|
+
const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
|
|
34155
|
+
adapter.updateConfig({
|
|
34156
|
+
model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
|
|
34157
|
+
effort: updated.thinkingEffort ?? localEffort
|
|
34158
|
+
});
|
|
34159
|
+
};
|
|
33827
34160
|
const gateway = new ParallAgentGateway({
|
|
33828
34161
|
accountId: agentUserId,
|
|
33829
34162
|
client,
|
|
@@ -33850,28 +34183,8 @@ async function main() {
|
|
|
33850
34183
|
dispatchDeadlineMs: parseDispatchDeadlineMs(process.env.PRLL_DISPATCH_DEADLINE_MS),
|
|
33851
34184
|
contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
|
|
33852
34185
|
stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
|
|
33853
|
-
onConfigUpdate:
|
|
33854
|
-
|
|
33855
|
-
platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
|
|
33856
|
-
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
33857
|
-
const updated = await configMgr.fetch();
|
|
33858
|
-
const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
|
|
33859
|
-
adapter.updateConfig({
|
|
33860
|
-
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
33861
|
-
effort: platformManaged ? updated.thinkingEffort ?? localEffort : localEffort
|
|
33862
|
-
});
|
|
33863
|
-
},
|
|
33864
|
-
onSessionReady: async () => {
|
|
33865
|
-
const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
33866
|
-
platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
|
|
33867
|
-
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
33868
|
-
const updated = await configMgr.fetch();
|
|
33869
|
-
const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
|
|
33870
|
-
adapter.updateConfig({
|
|
33871
|
-
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
33872
|
-
effort: platformManaged ? updated.thinkingEffort ?? localEffort : localEffort
|
|
33873
|
-
});
|
|
33874
|
-
},
|
|
34186
|
+
onConfigUpdate: refreshPlatformConfig,
|
|
34187
|
+
onSessionReady: refreshPlatformConfig,
|
|
33875
34188
|
// Long-lived `claude` subprocesses outlive a single dispatch, so the
|
|
33876
34189
|
// gateway's shuttingDown flag alone does not tear them down. Piggyback on
|
|
33877
34190
|
// onBeforeDisconnect to close stdin and SIGTERM any survivors after
|