{"version":3,"file":"client.mjs","names":["#apiUrl","#runnerWsUrl","#clientWsUrl","#apiKey","#mcpServerEnabled","#threadCreatedListeners","#threadUpdatedListeners","#threadDeletedListeners","#request","#invokeLifecycleCallback"],"sources":["../../../../src/v2/runtime/intelligence-platform/client.ts"],"sourcesContent":["import { logger } from \"@copilotkit/shared\";\n\n/**\n * Header name carrying the per-call end-user identity that the CopilotKit\n * Intelligence `/mcp` endpoint requires. Internal CopilotKit machinery — the\n * runtime stamps this onto `agent.headers` after `identifyUser` resolves,\n * and the auto-attach in `configureAgentForRequest` reads it back to gate\n * MCP-server attachment and to populate the outbound `X-Cpki-User-Id`\n * header on every MCP request. Not part of the public user API.\n *\n * @internal\n */\nexport const INTELLIGENCE_USER_ID_HEADER = \"x-cpki-user-id\";\n\n/**\n * Error thrown when an Intelligence platform HTTP request returns a non-2xx\n * status. Carries the HTTP {@link status} code so callers can branch on\n * specific failures (e.g. 404 for \"not found\", 409 for \"conflict\") without\n * parsing the error message string.\n *\n * @example\n * ```ts\n * try {\n *   await intelligence.getThread({ threadId });\n * } catch (error) {\n *   if (error instanceof PlatformRequestError && error.status === 404) {\n *     // thread does not exist yet\n *   }\n * }\n * ```\n */\nexport class PlatformRequestError extends Error {\n  constructor(\n    message: string,\n    /** The HTTP status code returned by the platform (e.g. 404, 409, 500). */\n    public readonly status: number,\n  ) {\n    super(message);\n    this.name = \"PlatformRequestError\";\n  }\n}\n\n/**\n * Client for the CopilotKit Intelligence Platform REST API.\n *\n * Construct the client once and pass it to any consumers that need it\n * (e.g. `CopilotRuntime`, `IntelligenceAgentRunner`):\n *\n * ```ts\n * import { CopilotKitIntelligence, CopilotRuntime } from \"@copilotkit/runtime\";\n *\n * const intelligence = new CopilotKitIntelligence({\n *   apiUrl: \"https://api.copilotkit.ai\",\n *   wsUrl: \"wss://api.copilotkit.ai\",\n *   apiKey: process.env.COPILOTKIT_API_KEY!,\n * });\n *\n * const runtime = new CopilotRuntime({\n *   agents,\n *   intelligence,\n * });\n * ```\n */\n\n/** Payload passed to `onThreadDeleted` listeners. */\nexport interface ThreadDeletedPayload {\n  threadId: string;\n  userId: string;\n  agentId: string;\n}\n\nexport interface CopilotKitIntelligenceConfig {\n  /** Base URL of the intelligence platform API, e.g. \"https://api.copilotkit.ai\" */\n  apiUrl: string;\n  /** Intelligence websocket base URL. Runner and client socket URLs are derived from this. */\n  wsUrl: string;\n  /** API key for authenticating with the intelligence platform */\n  apiKey: string;\n  /**\n   * Enable the Intelligence platform's MCP server (bash + thread tools) on\n   * every `BuiltInAgent` run that resolves a user. The auto-attach is\n   * implemented in `configureAgentForRequest`: when this flag is `true`\n   * AND the runtime's `identifyUser` callback has placed a user-id onto\n   * the agent's forwarded headers AND the user has not already configured\n   * an MCP server pointing at the same URL, the server is appended to the\n   * agent's effective MCP server list for that run.\n   *\n   * Defaults to `false` — opt-in. Existing intelligence setups continue to\n   * work without the bash MCP server unless they flip this flag.\n   */\n  mcpServer?: boolean;\n  /**\n   * Initial listener invoked after a thread is created.\n   * Prefer {@link CopilotKitIntelligence.onThreadCreated} for multiple listeners.\n   */\n  onThreadCreated?: (thread: ThreadSummary) => void;\n  /**\n   * Initial listener invoked after a thread is updated.\n   * Prefer {@link CopilotKitIntelligence.onThreadUpdated} for multiple listeners.\n   */\n  onThreadUpdated?: (thread: ThreadSummary) => void;\n  /**\n   * Initial listener invoked after a thread is deleted.\n   * Prefer {@link CopilotKitIntelligence.onThreadDeleted} for multiple listeners.\n   */\n  onThreadDeleted?: (params: ThreadDeletedPayload) => void;\n}\n\n/**\n * Summary metadata for a single thread returned by the platform.\n *\n * This is the shape returned by list, get, create, and update operations.\n * It does not include the thread's message history — use\n * {@link CopilotKitIntelligence.getThreadMessages} for that.\n */\nexport interface ThreadSummary {\n  /** Platform-assigned unique identifier. */\n  id: string;\n  /** Human-readable display name, or `null` if the thread has not been named. */\n  name: string | null;\n  /** ISO-8601 timestamp of the most recent agent run on this thread. */\n  lastRunAt?: string;\n  /** ISO-8601 timestamp of the most recent metadata update. */\n  lastUpdatedAt?: string;\n  /** ISO-8601 timestamp when the thread was created. */\n  createdAt?: string;\n  /** ISO-8601 timestamp when the thread was last updated. */\n  updatedAt?: string;\n  /** Whether the thread has been archived. Archived threads are excluded from default list results. */\n  archived?: boolean;\n  /** The agent that owns this thread. */\n  agentId?: string;\n  /** The user who created this thread. */\n  createdById?: string;\n  /** The organization this thread belongs to. */\n  organizationId?: string;\n}\n\n/** Response from listing threads for a user/agent pair. */\nexport interface ListThreadsResponse {\n  /** The matching threads, sorted by the platform's default ordering. */\n  threads: ThreadSummary[];\n  /** Join code for subscribing to realtime metadata updates for these threads. */\n  joinCode: string;\n  /** Short-lived token for authenticating the realtime subscription. */\n  joinToken?: string;\n  /** Opaque cursor for fetching the next page. `null` or absent when there are no more pages. */\n  nextCursor?: string | null;\n}\n\n/**\n * Fields that can be updated on a thread via {@link CopilotKitIntelligence.updateThread}.\n *\n * Additional platform-specific fields can be passed as extra keys and will be\n * forwarded to the PATCH request body.\n */\nexport interface UpdateThreadRequest {\n  /** New human-readable display name for the thread. */\n  name?: string;\n  [key: string]: unknown;\n}\n\n/** Parameters for creating a new thread via {@link CopilotKitIntelligence.createThread}. */\nexport interface CreateThreadRequest {\n  /** Client-generated unique identifier for the new thread. */\n  threadId: string;\n  /** The user creating the thread. Used for authorization and scoping. */\n  userId: string;\n  /** The agent this thread belongs to. */\n  agentId: string;\n  /** Optional initial display name. If omitted, the thread is unnamed until explicitly renamed. */\n  name?: string;\n}\n\n/** Credentials returned when locking or joining a thread's realtime channel. */\nexport interface ThreadConnectionResponse {\n  /** Canonical platform thread identifier for the run or connection. */\n  threadId: string;\n  /** Canonical platform run identifier for an active run lock. */\n  runId?: string;\n  /** Short-lived token for authenticating the Phoenix channel join. */\n  joinToken: string;\n  /** Lock metadata echoed back by the platform. */\n  lock?: ThreadLockInfo;\n}\n\nexport interface SubscribeToThreadsRequest {\n  userId: string;\n}\n\nexport interface SubscribeToThreadsResponse {\n  joinToken: string;\n}\n\nexport type ConnectThreadResponse = ThreadConnectionResponse | null;\n\nexport interface AcquireThreadLockResponse extends ThreadConnectionResponse {\n  /** Canonical platform run identifier for the acquired lock. */\n  runId: string;\n}\n\n/** A single message within a thread's persisted history. */\nexport interface ThreadMessage {\n  /** Unique identifier for this message. */\n  id: string;\n  /** Message role, e.g. `\"user\"`, `\"assistant\"`, `\"tool\"`. */\n  role: string;\n  /** Text content of the message. May be absent for tool-call-only messages. */\n  content?: string;\n  /** Tool calls initiated by this message (assistant role only). */\n  toolCalls?: Array<{\n    id: string;\n    name: string;\n    /** JSON-encoded arguments passed to the tool. */\n    args: string;\n  }>;\n  /** For tool-result messages, the ID of the tool call this message responds to. */\n  toolCallId?: string;\n}\n\n/** Response from {@link CopilotKitIntelligence.getThreadMessages}. */\nexport interface ThreadMessagesResponse {\n  messages: ThreadMessage[];\n}\n\n/**\n * Persisted AG-UI event for the inspector's debugging views. The platform\n * stores raw events keyed by run; the `_inspect` route returns them in\n * replay order (oldest first) across every run that targeted the thread.\n */\nexport interface ThreadInspectEvent {\n  type: string;\n  [key: string]: unknown;\n}\n\n/**\n * Response from {@link CopilotKitIntelligence.getThreadEvents}. Mirrors the\n * `ThreadEventsResult` shape returned by the platform's\n * `GET /api/_inspect/threads/:id/events` endpoint.\n */\nexport interface ThreadEventsResponse {\n  events: ThreadInspectEvent[];\n  /** Row IDs the platform failed to decode (raw column corrupted). */\n  decodeErrorRowIds: string[];\n  /** True when the platform hit its per-thread event cap. */\n  truncated: boolean;\n}\n\n/**\n * Response from {@link CopilotKitIntelligence.getThreadState}. Mirrors the\n * discriminated `ThreadStateResult` returned by the platform's\n * `GET /api/_inspect/threads/:id/state` endpoint, which folds RFC 6902\n * STATE_DELTA events on top of the latest STATE_SNAPSHOT.\n */\nexport type ThreadStateResponse =\n  | { kind: \"no-snapshot\" }\n  | { kind: \"snapshot-decode-error\" }\n  | { kind: \"snapshot\"; state: unknown; skippedDeltas: number };\n\nexport interface AcquireThreadLockRequest {\n  threadId: string;\n  runId: string;\n  userId: string;\n  agentId: string;\n  /** Custom Redis key prefix for the lock (default: \"thread\"). */\n  lockKeyPrefix?: string;\n  /** Lock TTL in seconds. When set, the lock auto-expires after this duration. */\n  ttlSeconds?: number;\n}\n\nexport interface RenewThreadLockRequest {\n  threadId: string;\n  runId: string;\n  /** New TTL to set on the lock in seconds. */\n  ttlSeconds: number;\n  /** Must match the prefix used when acquiring. */\n  lockKeyPrefix?: string;\n}\n\nexport interface CleanupThreadLockRequest {\n  threadId: string;\n  runId: string;\n}\n\nexport interface RenewThreadLockResponse {\n  ttlSeconds: number;\n}\n\nexport interface ThreadLockInfo {\n  key: string;\n  ttlSeconds: number | null;\n}\n\ninterface ThreadEnvelope {\n  thread: ThreadSummary;\n}\n\nexport class CopilotKitIntelligence {\n  #apiUrl: string;\n  #runnerWsUrl: string;\n  #clientWsUrl: string;\n  #apiKey: string;\n  #mcpServerEnabled: boolean;\n  #threadCreatedListeners = new Set<(thread: ThreadSummary) => void>();\n  #threadUpdatedListeners = new Set<(thread: ThreadSummary) => void>();\n  #threadDeletedListeners = new Set<(params: ThreadDeletedPayload) => void>();\n\n  constructor(config: CopilotKitIntelligenceConfig) {\n    const intelligenceWsUrl = normalizeIntelligenceWsUrl(config.wsUrl);\n\n    this.#apiUrl = config.apiUrl.replace(/\\/$/, \"\");\n    this.#runnerWsUrl = deriveRunnerWsUrl(intelligenceWsUrl);\n    this.#clientWsUrl = deriveClientWsUrl(intelligenceWsUrl);\n    this.#apiKey = config.apiKey;\n    this.#mcpServerEnabled = config.mcpServer ?? false;\n\n    if (config.onThreadCreated) {\n      this.onThreadCreated(config.onThreadCreated);\n    }\n    if (config.onThreadUpdated) {\n      this.onThreadUpdated(config.onThreadUpdated);\n    }\n    if (config.onThreadDeleted) {\n      this.onThreadDeleted(config.onThreadDeleted);\n    }\n  }\n\n  /**\n   * Register a listener invoked whenever a thread is created.\n   *\n   * Multiple listeners can be registered. Each call returns an unsubscribe\n   * function that removes the listener when called.\n   *\n   * @param callback - Receives the newly created {@link ThreadSummary}.\n   * @returns A function that removes this listener when called.\n   *\n   * @example\n   * ```ts\n   * const unsubscribe = intelligence.onThreadCreated((thread) => {\n   *   console.log(\"Thread created:\", thread.id);\n   * });\n   * // later…\n   * unsubscribe();\n   * ```\n   */\n  onThreadCreated(callback: (thread: ThreadSummary) => void): () => void {\n    this.#threadCreatedListeners.add(callback);\n    return () => {\n      this.#threadCreatedListeners.delete(callback);\n    };\n  }\n\n  /**\n   * Register a listener invoked whenever a thread is updated (including archive).\n   *\n   * Multiple listeners can be registered. Each call returns an unsubscribe\n   * function that removes the listener when called.\n   *\n   * @param callback - Receives the updated {@link ThreadSummary}.\n   * @returns A function that removes this listener when called.\n   */\n  onThreadUpdated(callback: (thread: ThreadSummary) => void): () => void {\n    this.#threadUpdatedListeners.add(callback);\n    return () => {\n      this.#threadUpdatedListeners.delete(callback);\n    };\n  }\n\n  /**\n   * Register a listener invoked whenever a thread is deleted.\n   *\n   * Multiple listeners can be registered. Each call returns an unsubscribe\n   * function that removes the listener when called.\n   *\n   * @param callback - Receives the {@link ThreadDeletedPayload} identifying\n   *   the deleted thread.\n   * @returns A function that removes this listener when called.\n   */\n  onThreadDeleted(\n    callback: (params: ThreadDeletedPayload) => void,\n  ): () => void {\n    this.#threadDeletedListeners.add(callback);\n    return () => {\n      this.#threadDeletedListeners.delete(callback);\n    };\n  }\n\n  ɵgetApiUrl(): string {\n    return this.#apiUrl;\n  }\n\n  ɵgetRunnerWsUrl(): string {\n    return this.#runnerWsUrl;\n  }\n\n  ɵgetClientWsUrl(): string {\n    return this.#clientWsUrl;\n  }\n\n  ɵgetRunnerAuthToken(): string {\n    return this.#apiKey;\n  }\n\n  /** @internal Used by the runtime's auto-attach to populate `Authorization`. */\n  ɵgetApiKey(): string {\n    return this.#apiKey;\n  }\n\n  /** @internal Used by the runtime's auto-attach to gate MCP attachment. */\n  ɵisMcpServerEnabled(): boolean {\n    return this.#mcpServerEnabled;\n  }\n\n  async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n    const url = `${this.#apiUrl}${path}`;\n\n    const headers: Record<string, string> = {\n      Authorization: `Bearer ${this.#apiKey}`,\n      \"Content-Type\": \"application/json\",\n    };\n\n    const response = await fetch(url, {\n      method,\n      headers,\n      body: body ? JSON.stringify(body) : undefined,\n    });\n\n    if (!response.ok) {\n      const text = await response.text().catch(() => \"\");\n      logger.error(\n        { status: response.status, body: text, path },\n        \"Intelligence platform request failed\",\n      );\n      throw new PlatformRequestError(\n        `Intelligence platform error ${response.status}: ${text || response.statusText}`,\n        response.status,\n      );\n    }\n\n    const text = await response.text();\n    if (!text) {\n      return undefined as T;\n    }\n    return JSON.parse(text) as T;\n  }\n\n  #invokeLifecycleCallback(\n    callbackName: \"onThreadCreated\" | \"onThreadUpdated\" | \"onThreadDeleted\",\n    payload: ThreadSummary | ThreadDeletedPayload,\n  ): void {\n    const listeners =\n      callbackName === \"onThreadCreated\"\n        ? this.#threadCreatedListeners\n        : callbackName === \"onThreadUpdated\"\n          ? this.#threadUpdatedListeners\n          : this.#threadDeletedListeners;\n\n    for (const callback of listeners) {\n      try {\n        (callback as (p: typeof payload) => void)(payload);\n      } catch (error) {\n        logger.error(\n          { err: error, callbackName, payload },\n          \"Intelligence lifecycle callback failed\",\n        );\n      }\n    }\n  }\n\n  /**\n   * List all non-archived threads for a given user and agent.\n   *\n   * @param params.userId - User whose threads to list.\n   * @param params.agentId - Agent whose threads to list.\n   * @returns The thread list along with realtime subscription credentials.\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async listThreads(params: {\n    userId: string;\n    agentId: string;\n    includeArchived?: boolean;\n    limit?: number;\n    cursor?: string;\n  }): Promise<ListThreadsResponse> {\n    const query: Record<string, string> = {\n      userId: params.userId,\n      agentId: params.agentId,\n    };\n    if (params.includeArchived) query.includeArchived = \"true\";\n    if (params.limit != null) query.limit = String(params.limit);\n    if (params.cursor) query.cursor = params.cursor;\n\n    const qs = new URLSearchParams(query).toString();\n    return this.#request<ListThreadsResponse>(\"GET\", `/api/threads?${qs}`);\n  }\n\n  async ɵsubscribeToThreads(\n    params: SubscribeToThreadsRequest,\n  ): Promise<SubscribeToThreadsResponse> {\n    return this.#request<SubscribeToThreadsResponse>(\n      \"POST\",\n      \"/api/threads/subscribe\",\n      {\n        userId: params.userId,\n      },\n    );\n  }\n\n  /**\n   * Update thread metadata (e.g. name).\n   *\n   * Triggers the `onThreadUpdated` lifecycle callback on success.\n   *\n   * @returns The updated thread summary.\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async updateThread(params: {\n    threadId: string;\n    userId: string;\n    agentId: string;\n    updates: UpdateThreadRequest;\n  }): Promise<ThreadSummary> {\n    const response = await this.#request<ThreadEnvelope>(\n      \"PATCH\",\n      `/api/threads/${encodeURIComponent(params.threadId)}`,\n      {\n        userId: params.userId,\n        agentId: params.agentId,\n        ...params.updates,\n      },\n    );\n    this.#invokeLifecycleCallback(\"onThreadUpdated\", response.thread);\n    return response.thread;\n  }\n\n  /**\n   * Create a new thread on the platform.\n   *\n   * Triggers the `onThreadCreated` lifecycle callback on success.\n   *\n   * @returns The newly created thread summary.\n   * @throws {@link PlatformRequestError} with status 409 if a thread with the\n   *   same `threadId` already exists.\n   */\n  async createThread(params: CreateThreadRequest): Promise<ThreadSummary> {\n    const response = await this.#request<ThreadEnvelope>(\n      \"POST\",\n      `/api/threads`,\n      {\n        threadId: params.threadId,\n        userId: params.userId,\n        agentId: params.agentId,\n        ...(params.name !== undefined ? { name: params.name } : {}),\n      },\n    );\n    this.#invokeLifecycleCallback(\"onThreadCreated\", response.thread);\n    return response.thread;\n  }\n\n  /**\n   * Fetch a single thread by ID.\n   *\n   * @returns The thread summary.\n   * @throws {@link PlatformRequestError} with status 404 if the thread does\n   *   not exist.\n   */\n  async getThread(params: { threadId: string }): Promise<ThreadSummary> {\n    const response = await this.#request<ThreadEnvelope>(\n      \"GET\",\n      `/api/threads/${encodeURIComponent(params.threadId)}`,\n    );\n    return response.thread;\n  }\n\n  /**\n   * Get an existing thread or create it if it does not exist.\n   *\n   * Handles the race where a concurrent request creates the thread between\n   * the initial 404 and the subsequent `createThread` call by catching the\n   * 409 Conflict and retrying the get.\n   *\n   * Triggers the `onThreadCreated` lifecycle callback when a new thread is\n   * created.\n   *\n   * @returns An object containing the thread and a `created` flag indicating\n   *   whether the thread was newly created (`true`) or already existed (`false`).\n   * @throws {@link PlatformRequestError} on non-2xx responses other than\n   *   404 (get) and 409 (create race).\n   */\n  async getOrCreateThread(\n    params: CreateThreadRequest,\n  ): Promise<{ thread: ThreadSummary; created: boolean }> {\n    try {\n      const thread = await this.getThread({ threadId: params.threadId });\n      return { thread, created: false };\n    } catch (error) {\n      if (!(error instanceof PlatformRequestError && error.status === 404)) {\n        throw error;\n      }\n    }\n\n    try {\n      const thread = await this.createThread(params);\n      return { thread, created: true };\n    } catch (error) {\n      // Another request created the thread between our get and create — retry get.\n      if (error instanceof PlatformRequestError && error.status === 409) {\n        const thread = await this.getThread({ threadId: params.threadId });\n        return { thread, created: false };\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * Fetch the full message history for a thread.\n   *\n   * @returns All persisted messages in chronological order.\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async getThreadMessages(params: {\n    threadId: string;\n  }): Promise<ThreadMessagesResponse> {\n    return this.#request<ThreadMessagesResponse>(\n      \"GET\",\n      `/api/threads/${encodeURIComponent(params.threadId)}/messages`,\n    );\n  }\n\n  /**\n   * Fetch the persisted AG-UI event stream for a thread.\n   *\n   * Backed by the platform's `GET /api/_inspect/threads/:id/events`\n   * introspection endpoint (see Intelligence PR #144). Events are returned\n   * in replay order across every run that targeted the thread. The\n   * `_inspect/` prefix flags this as debug-only — production code paths\n   * must not depend on it.\n   *\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async getThreadEvents(params: {\n    threadId: string;\n  }): Promise<ThreadEventsResponse> {\n    return this.#request<ThreadEventsResponse>(\n      \"GET\",\n      `/api/_inspect/threads/${encodeURIComponent(params.threadId)}/events`,\n    );\n  }\n\n  /**\n   * Fetch the current agent state for a thread.\n   *\n   * Backed by the platform's `GET /api/_inspect/threads/:id/state`\n   * introspection endpoint (see Intelligence PR #144). The platform folds\n   * RFC 6902 STATE_DELTA events on top of the latest STATE_SNAPSHOT, so\n   * the returned state reflects the thread's current state — not just the\n   * last snapshot. The discriminated response distinguishes \"no snapshot\n   * persisted yet\" from \"snapshot present\" so consumers can render the\n   * correct empty state.\n   *\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async getThreadState(params: {\n    threadId: string;\n  }): Promise<ThreadStateResponse> {\n    return this.#request<ThreadStateResponse>(\n      \"GET\",\n      `/api/_inspect/threads/${encodeURIComponent(params.threadId)}/state`,\n    );\n  }\n\n  /**\n   * Mark a thread as archived.\n   *\n   * Archived threads are excluded from {@link listThreads} results.\n   * Triggers the `onThreadUpdated` lifecycle callback on success.\n   *\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async archiveThread(params: {\n    threadId: string;\n    userId: string;\n    agentId: string;\n  }): Promise<void> {\n    const response = await this.#request<ThreadEnvelope>(\n      \"PATCH\",\n      `/api/threads/${encodeURIComponent(params.threadId)}`,\n      { userId: params.userId, agentId: params.agentId, archived: true },\n    );\n    this.#invokeLifecycleCallback(\"onThreadUpdated\", response.thread);\n  }\n\n  /**\n   * Permanently delete a thread and its message history.\n   *\n   * This is irreversible. Triggers the `onThreadDeleted` lifecycle callback\n   * on success.\n   *\n   * @throws {@link PlatformRequestError} on non-2xx responses.\n   */\n  async deleteThread(params: {\n    threadId: string;\n    userId: string;\n    agentId: string;\n  }): Promise<void> {\n    await this.#request<void>(\n      \"DELETE\",\n      `/api/threads/${encodeURIComponent(params.threadId)}`,\n      {\n        reason: `Deleted via CopilotKit runtime (userId=${params.userId}, agentId=${params.agentId})`,\n      },\n    );\n    this.#invokeLifecycleCallback(\"onThreadDeleted\", params);\n  }\n\n  async ɵacquireThreadLock(\n    params: AcquireThreadLockRequest,\n  ): Promise<AcquireThreadLockResponse> {\n    return this.#request<AcquireThreadLockResponse>(\n      \"POST\",\n      `/api/threads/${encodeURIComponent(params.threadId)}/lock`,\n      {\n        runId: params.runId,\n        userId: params.userId,\n        agentId: params.agentId,\n        ...(params.lockKeyPrefix !== undefined\n          ? { lockKeyPrefix: params.lockKeyPrefix }\n          : {}),\n        ...(params.ttlSeconds !== undefined\n          ? { ttlSeconds: params.ttlSeconds }\n          : {}),\n      },\n    );\n  }\n\n  async ɵcleanupThreadLock(params: CleanupThreadLockRequest): Promise<void> {\n    return this.#request<void>(\n      \"DELETE\",\n      `/api/threads/${encodeURIComponent(params.threadId)}/lock`,\n      {\n        runId: params.runId,\n      },\n    );\n  }\n\n  async ɵrenewThreadLock(\n    params: RenewThreadLockRequest,\n  ): Promise<RenewThreadLockResponse> {\n    return this.#request<RenewThreadLockResponse>(\n      \"PATCH\",\n      `/api/threads/${encodeURIComponent(params.threadId)}/lock`,\n      {\n        runId: params.runId,\n        ttlSeconds: params.ttlSeconds,\n        ...(params.lockKeyPrefix !== undefined\n          ? { lockKeyPrefix: params.lockKeyPrefix }\n          : {}),\n      },\n    );\n  }\n\n  async ɵgetActiveJoinCode(params: {\n    threadId: string;\n    userId: string;\n  }): Promise<ThreadConnectionResponse> {\n    const qs = new URLSearchParams({ userId: params.userId }).toString();\n    return this.#request<ThreadConnectionResponse>(\n      \"GET\",\n      `/api/threads/${encodeURIComponent(params.threadId)}/join-code?${qs}`,\n    );\n  }\n\n  async ɵconnectThread(params: {\n    threadId: string;\n    userId: string;\n    agentId: string;\n  }): Promise<ConnectThreadResponse> {\n    const result = await this.#request<ThreadConnectionResponse>(\n      \"POST\",\n      `/api/threads/${encodeURIComponent(params.threadId)}/connect`,\n      {\n        userId: params.userId,\n        agentId: params.agentId,\n      },\n    );\n\n    // request() returns undefined for empty/204 responses\n    return result ?? null;\n  }\n}\n\nfunction normalizeIntelligenceWsUrl(wsUrl: string): string {\n  return wsUrl.replace(/\\/$/, \"\");\n}\n\nfunction deriveRunnerWsUrl(wsUrl: string): string {\n  if (wsUrl.endsWith(\"/runner\")) {\n    return wsUrl;\n  }\n\n  if (wsUrl.endsWith(\"/client\")) {\n    return `${wsUrl.slice(0, -\"/client\".length)}/runner`;\n  }\n\n  return `${wsUrl}/runner`;\n}\n\nfunction deriveClientWsUrl(wsUrl: string): string {\n  if (wsUrl.endsWith(\"/client\")) {\n    return wsUrl;\n  }\n\n  if (wsUrl.endsWith(\"/runner\")) {\n    return `${wsUrl.slice(0, -\"/runner\".length)}/client`;\n  }\n\n  return `${wsUrl}/client`;\n}\n"],"mappings":"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"}