@parall/sdk 1.46.0 → 1.47.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/src/client.ts CHANGED
@@ -95,6 +95,13 @@ import type {
95
95
  CreateChannelConnectionInput,
96
96
  InitiateChannelProvisioningInput,
97
97
  SendChannelMessageInput,
98
+ SlackChannelsPage,
99
+ SlackHistoryPage,
100
+ SlackManifestLinkResult,
101
+ SlackMembersPage,
102
+ SlackReadPageQuery,
103
+ SlackStatusInput,
104
+ SlackUsersPage,
98
105
  SentChannelMessage,
99
106
  UpdateChannelConnectionInput,
100
107
  ExternalIngressEvent,
@@ -1754,11 +1761,17 @@ export class ParallClient {
1754
1761
  return this.request('PATCH', ENDPOINTS.MACHINE_SPEC(orgId, machineId), spec);
1755
1762
  }
1756
1763
 
1757
- /** Signal a local daemon-mode Machine to check for and apply an update. */
1764
+ /** @deprecated Retired server-side (daemon-control-authorization §4.2):
1765
+ * daemons update autonomously (CDN poll + platform release signal). The
1766
+ * endpoint now answers 409 LOCAL_UPDATE_NOT_SUPPORTED unconditionally. */
1758
1767
  async requestMachineUpdate(orgId: string, machineId: string, mandatory = false): Promise<void> {
1759
1768
  await this.request('POST', ENDPOINTS.MACHINE_REQUEST_UPDATE(orgId, machineId), { mandatory });
1760
1769
  }
1761
1770
 
1771
+ /** @deprecated Retired server-side (daemon-control-authorization §4.2):
1772
+ * remote filesystem browse of a member's machine was remote device access.
1773
+ * The endpoint now answers 409 LOCAL_BROWSE_NOT_SUPPORTED unconditionally;
1774
+ * workspace paths are typed in (or picked on the machine's own Desktop). */
1762
1775
  async browseMachineFilesystem(
1763
1776
  orgId: string,
1764
1777
  machineId: string,
@@ -1814,6 +1827,20 @@ export class ParallClient {
1814
1827
  return this.request('GET', ENDPOINTS.THREAD_UNREAD(orgId, chatId, threadRootId));
1815
1828
  }
1816
1829
 
1830
+ /** Advance the per-thread read cursor (forward-only). The server auto-clears
1831
+ * thread-scoped inbox items (thread_reply + in-thread mentions) the cursor
1832
+ * now covers. */
1833
+ async markThreadRead(
1834
+ orgId: string,
1835
+ chatId: string,
1836
+ threadRootId: string,
1837
+ messageId: string,
1838
+ ): Promise<void> {
1839
+ return this.request('POST', ENDPOINTS.THREAD_READ(orgId, chatId, threadRootId), {
1840
+ message_id: messageId,
1841
+ });
1842
+ }
1843
+
1817
1844
  // ---- Inbox ----
1818
1845
 
1819
1846
  async getInbox(
@@ -1854,9 +1881,15 @@ export class ParallClient {
1854
1881
  return this.request('POST', ENDPOINTS.INBOX_ARCHIVE_ALL(orgId));
1855
1882
  }
1856
1883
 
1857
- /** Mark an inbox item as read by its source (source_type + source_id) rather than inbox item ID. */
1858
- async ackInbox(orgId: string, source: { source_type: string; source_id: string }): Promise<void> {
1859
- return this.request('POST', ENDPOINTS.INBOX_ACK(orgId), source);
1884
+ /** Mark inbox items as read by their source (source_type + source_id) or by
1885
+ * group_key, rather than by inbox item ID. The group_key form clears a whole
1886
+ * group at once (e.g. `task:{taskId}` — task_assign/task_update/task_comment
1887
+ * share it), used by the task detail view's auto-ack on open. */
1888
+ async ackInbox(
1889
+ orgId: string,
1890
+ target: { source_type: string; source_id: string } | { group_key: string },
1891
+ ): Promise<void> {
1892
+ return this.request('POST', ENDPOINTS.INBOX_ACK(orgId), target);
1860
1893
  }
1861
1894
 
1862
1895
  async deleteInboxItem(orgId: string, id: string): Promise<void> {
@@ -2420,6 +2453,19 @@ export class ParallClient {
2420
2453
  return this.request('POST', ENDPOINTS.CHANNEL_PROVISIONING(orgId), input);
2421
2454
  }
2422
2455
 
2456
+ /**
2457
+ * Mint a pending slack connection + api.slack.com manifest-prefill link
2458
+ * (guided manual path). Activate the returned connection_id with
2459
+ * deliverChannelCredentials once the user brings back the bot token +
2460
+ * signing secret.
2461
+ */
2462
+ async createSlackManifestLink(
2463
+ orgId: string,
2464
+ input: { agent_id: string },
2465
+ ): Promise<SlackManifestLinkResult> {
2466
+ return this.request('POST', ENDPOINTS.CHANNEL_SLACK_MANIFEST_LINK(orgId), input);
2467
+ }
2468
+
2423
2469
  /**
2424
2470
  * Lazy status poll — server-side this may forward one provider poll, so
2425
2471
  * call it at the session's `poll_interval_seconds` cadence, not faster.
@@ -2450,6 +2496,55 @@ export class ParallClient {
2450
2496
  return this.request('POST', ENDPOINTS.CHANNEL_SEND(orgId), input);
2451
2497
  }
2452
2498
 
2499
+ private slackReadQuery(base: string, query?: SlackReadPageQuery, extra?: Record<string, string>) {
2500
+ const params = new URLSearchParams();
2501
+ if (query?.cursor) params.set('cursor', query.cursor);
2502
+ if (query?.limit) params.set('limit', String(query.limit));
2503
+ for (const [k, v] of Object.entries(extra ?? {})) params.set(k, v);
2504
+ const qs = params.toString();
2505
+ return qs ? `${base}?${qs}` : base;
2506
+ }
2507
+
2508
+ /**
2509
+ * Tier-B read verbs (agent-only): workspace visibility as the bot sees
2510
+ * it. Same live gate as the send verb; authorization beyond it is the
2511
+ * bot's own Slack permissions.
2512
+ */
2513
+ async listSlackChannels(orgId: string, query?: SlackReadPageQuery): Promise<SlackChannelsPage> {
2514
+ return this.request('GET', this.slackReadQuery(ENDPOINTS.SLACK_CHANNELS(orgId), query));
2515
+ }
2516
+
2517
+ async listSlackUsers(orgId: string, query?: SlackReadPageQuery): Promise<SlackUsersPage> {
2518
+ return this.request('GET', this.slackReadQuery(ENDPOINTS.SLACK_USERS(orgId), query));
2519
+ }
2520
+
2521
+ async slackHistory(
2522
+ orgId: string,
2523
+ conversationId: string,
2524
+ query?: SlackReadPageQuery,
2525
+ ): Promise<SlackHistoryPage> {
2526
+ return this.request(
2527
+ 'GET',
2528
+ this.slackReadQuery(ENDPOINTS.SLACK_HISTORY(orgId), query, { conversation: conversationId }),
2529
+ );
2530
+ }
2531
+
2532
+ async slackMembers(
2533
+ orgId: string,
2534
+ conversationId: string,
2535
+ query?: SlackReadPageQuery,
2536
+ ): Promise<SlackMembersPage> {
2537
+ return this.request(
2538
+ 'GET',
2539
+ this.slackReadQuery(ENDPOINTS.SLACK_MEMBERS(orgId), query, { conversation: conversationId }),
2540
+ );
2541
+ }
2542
+
2543
+ /** Set/clear the Agents-pane "typing…" indicator (best-effort cosmetic). */
2544
+ async setSlackStatus(orgId: string, input: SlackStatusInput): Promise<void> {
2545
+ await this.request('POST', ENDPOINTS.SLACK_STATUS(orgId), input);
2546
+ }
2547
+
2453
2548
  async listChannelConversations(
2454
2549
  orgId: string,
2455
2550
  connectionId: string,
package/src/constants.ts CHANGED
@@ -628,12 +628,20 @@ export const ENDPOINTS = {
628
628
  CHANNEL_MESSAGE: (orgId: string, messageId: string) =>
629
629
  `${API_BASE}/orgs/${orgId}/channel-messages/${messageId}`,
630
630
  CHANNEL_PROVISIONING: (orgId: string) => `${API_BASE}/orgs/${orgId}/channel-provisioning`,
631
+ CHANNEL_SLACK_MANIFEST_LINK: (orgId: string) =>
632
+ `${API_BASE}/orgs/${orgId}/channel-provisioning/slack/manifest-link`,
631
633
  CHANNEL_PROVISIONING_SESSION: (orgId: string, sessionId: string) =>
632
634
  `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}`,
633
635
  CHANNEL_PROVISIONING_CANCEL: (orgId: string, sessionId: string) =>
634
636
  `${API_BASE}/orgs/${orgId}/channel-provisioning/${sessionId}/cancel`,
635
637
  // Tier-B platform verb (agent-only): send one message as the bound bot.
636
638
  CHANNEL_SEND: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/channel-send`,
639
+ // Tier-B read verbs (agent-only): workspace visibility as the bot sees it.
640
+ SLACK_CHANNELS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/channels`,
641
+ SLACK_USERS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/users`,
642
+ SLACK_HISTORY: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/history`,
643
+ SLACK_MEMBERS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/members`,
644
+ SLACK_STATUS: (orgId: string) => `${API_BASE}/orgs/${orgId}/agents/me/slack/status`,
637
645
 
638
646
  // Invitations (org-scoped, admin)
639
647
  ORG_INVITATIONS: (orgId: string) => `${API_BASE}/orgs/${orgId}/invitations`,
@@ -774,6 +782,8 @@ export const ENDPOINTS = {
774
782
  CHAT_READ: (orgId: string, chatId: string) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/read`,
775
783
  THREAD_UNREAD: (orgId: string, chatId: string, threadRootId: string) =>
776
784
  `${API_BASE}/orgs/${orgId}/chats/${chatId}/threads/${threadRootId}/unread`,
785
+ THREAD_READ: (orgId: string, chatId: string, threadRootId: string) =>
786
+ `${API_BASE}/orgs/${orgId}/chats/${chatId}/threads/${threadRootId}/read`,
777
787
 
778
788
  // References (org-scoped)
779
789
  REFS_RESOLVE: (orgId: string) => `${API_BASE}/orgs/${orgId}/refs/resolve`,
package/src/types.ts CHANGED
@@ -2535,6 +2535,14 @@ export interface ChannelConnection {
2535
2535
  ingress_url?: string;
2536
2536
  /** Returned once at mint time (create / token regeneration). */
2537
2537
  ingress_token?: string;
2538
+ /**
2539
+ * The in-product scope-upgrade re-auth can act on this connection
2540
+ * (slack, active, provisioned-family — its auth_config carries the
2541
+ * OAuth client). Mirrors the upgrade endpoint's preconditions exactly.
2542
+ * Manual-family connections upgrade via the Slack console; the UI
2543
+ * hides the upgrade CTA when this is false/absent.
2544
+ */
2545
+ upgrade_eligible?: boolean;
2538
2546
  created_at: string;
2539
2547
  updated_at: string;
2540
2548
  }
@@ -2649,16 +2657,35 @@ export type InitiateChannelProvisioningInput =
2649
2657
  provider: 'slack';
2650
2658
  /**
2651
2659
  * The short-lived app-configuration token (12h, generated at
2652
- * api.slack.com/apps). Transits once into apps.manifest.create and is
2653
- * never stored.
2660
+ * api.slack.com/apps). Transits once into apps.manifest.create/update
2661
+ * and is never stored.
2654
2662
  */
2655
2663
  config_token: string;
2664
+ /**
2665
+ * Scope-upgrade re-auth: converge the agent's EXISTING active
2666
+ * connection's app on the current manifest and re-authorize it (bot
2667
+ * token replaced in place, app id preserved) instead of creating a
2668
+ * new app.
2669
+ */
2670
+ upgrade?: boolean;
2656
2671
  }
2657
2672
  | {
2658
2673
  agent_id: string;
2659
2674
  provider: Exclude<ChannelProvider, 'slack'>;
2660
2675
  };
2661
2676
 
2677
+ /**
2678
+ * Manifest-prefill link for the guided manual slack path: the platform
2679
+ * mints a pending connection and returns an api.slack.com link that opens
2680
+ * the create-app form with everything preset (events, scopes, this
2681
+ * connection's webhook URL). The user installs the app themselves and
2682
+ * activates the SAME connection by delivering bot token + signing secret.
2683
+ */
2684
+ export interface SlackManifestLinkResult {
2685
+ connection_id: string;
2686
+ manifest_url: string;
2687
+ }
2688
+
2662
2689
  /**
2663
2690
  * Tier-B platform verb request (agent-only): send as the bound bot.
2664
2691
  * Deliberately narrowed to 'slack' — the verb surface is per-vendor
@@ -2670,9 +2697,12 @@ export interface SendChannelMessageInput {
2670
2697
  /** Vendor-native conversation id from the inbound event (e.g. C…/D…). */
2671
2698
  conversation_id: string;
2672
2699
  /**
2673
- * External message id being answered (channel-domain format). REQUIRED
2674
- * for channel conversations (the reply lands in that message's thread);
2675
- * optional for DMs (always linear).
2700
+ * External message id being answered (channel-domain format:
2701
+ * `{channel}:{ts}`, thread children `{channel}:{root}#{ts}`). REQUIRED
2702
+ * for channel conversations (the reply lands in that message's thread).
2703
+ * In DMs the SESSION never forks, but reply POSITION follows the
2704
+ * question: a thread-child id lands the reply inside that thread, a
2705
+ * bare id (or omitting the field) keeps the flattened main flow.
2676
2706
  */
2677
2707
  reply_to?: string;
2678
2708
  text: string;
@@ -2681,12 +2711,94 @@ export interface SendChannelMessageInput {
2681
2711
  export interface SentChannelMessage {
2682
2712
  channel_type: 'slack';
2683
2713
  conversation_id: string;
2684
- /** Channel-domain external id ({channel}:{ts}) — usable as a reply_to. */
2714
+ /**
2715
+ * Channel-domain external id — `{channel}:{ts}` for top-level posts,
2716
+ * `{channel}:{root}#{ts}` when the reply landed inside a thread — usable
2717
+ * directly as a future reply_to.
2718
+ */
2685
2719
  message_id: string;
2686
2720
  thread_anchor?: string;
2687
2721
  sent_at: string;
2688
2722
  }
2689
2723
 
2724
+ /**
2725
+ * Tier-B read verbs (agent-only): workspace visibility as the bot sees it.
2726
+ * Authorization is the bot's own Slack permissions (invite the bot to a
2727
+ * channel to make its history readable) — reads have no external side
2728
+ * effect, so the seen-conversation restriction of the send verb does not
2729
+ * apply. Cursor pagination follows Slack's contract (empty = last page).
2730
+ */
2731
+ export interface SlackChannelInfo {
2732
+ id: string;
2733
+ name: string;
2734
+ is_private: boolean;
2735
+ is_member: boolean;
2736
+ num_members?: number;
2737
+ topic?: string;
2738
+ }
2739
+
2740
+ export interface SlackChannelsPage {
2741
+ channels: SlackChannelInfo[];
2742
+ next_cursor?: string;
2743
+ }
2744
+
2745
+ export interface SlackUserInfo {
2746
+ id: string;
2747
+ name: string;
2748
+ real_name?: string;
2749
+ is_bot: boolean;
2750
+ deleted?: boolean;
2751
+ }
2752
+
2753
+ export interface SlackUsersPage {
2754
+ users: SlackUserInfo[];
2755
+ next_cursor?: string;
2756
+ }
2757
+
2758
+ export interface SlackHistoryMessage {
2759
+ /**
2760
+ * Synthesized channel-domain id — `{conversation}:{ts}`, or
2761
+ * `{conversation}:{root}#{ts}` for thread children — directly usable as
2762
+ * the send verb's `reply_to` (no client-side root#child derivation).
2763
+ */
2764
+ message_id: string;
2765
+ ts: string;
2766
+ thread_ts?: string;
2767
+ user?: string;
2768
+ bot_id?: string;
2769
+ text: string;
2770
+ }
2771
+
2772
+ export interface SlackHistoryPage {
2773
+ messages: SlackHistoryMessage[];
2774
+ next_cursor?: string;
2775
+ }
2776
+
2777
+ export interface SlackMembersPage {
2778
+ /** Bare Slack user ids — resolve display names via the users verb. */
2779
+ members: string[];
2780
+ next_cursor?: string;
2781
+ }
2782
+
2783
+ /**
2784
+ * Slack-native pagination for the read verbs. Filters are deliberately
2785
+ * FIXED server-side (channels: public+private, archived excluded) — the
2786
+ * public contract is cursor/limit only; widening it is a deliberate scope
2787
+ * decision, not a missing passthrough.
2788
+ */
2789
+ export interface SlackReadPageQuery {
2790
+ cursor?: string;
2791
+ limit?: number;
2792
+ }
2793
+
2794
+ /** Agents-pane "typing…" indicator for one assistant thread (empty status clears). */
2795
+ export interface SlackStatusInput {
2796
+ conversation: string;
2797
+ /** The assistant thread's root ts. */
2798
+ thread_ts: string;
2799
+ status?: string;
2800
+ }
2801
+
2690
2802
  // ============================================================
2691
2803
  // Dispatch Types (agent event delivery)
2692
2804
  // ============================================================