/** * Palantir AIP (AI Platform) API. * AIP Agents (blockingContinue, streamingContinue, sessions, RAG context) * and Language Model proxy endpoints (OpenAI, Anthropic, xAI, Google). * * All AIP Agents endpoints require `preview=true` query parameter. * Language Models use LLM proxy endpoints at `/api/v2/llm/proxy/`. * * @see https://www.palantir.com/docs/foundry/api/v2/aip-agents-v2-resources/ * @see https://www.palantir.com/docs/foundry/api/v2/llm-proxy/ */ import type { PalantirClient } from "./client.js"; import type { AipAgent, AipAgentSession, AipContinueParams, AipContinueResponse, AipStreamingChunk, LanguageModel, ChatCompletionParams, ChatCompletionResponse, PageResponse, PageParams, } from "./types.js"; export class AipNamespace { constructor(private client: PalantirClient) {} // ─── AIP Agents ───────────────────────────────────────────────── // All endpoints require preview=true /** List AIP agents. */ async listAgents(params?: PageParams): Promise> { return this.client.get("/api/v2/aipAgents/agents", { ...params, preview: true, } as Record); } /** Get an AIP agent. */ async getAgent(agentRid: string): Promise { return this.client.get(`/api/v2/aipAgents/agents/${agentRid}`, { preview: true, } as Record); } // ─── Sessions ─────────────────────────────────────────────────── /** Create an agent session. */ async createSession( agentRid: string, params?: { metadata?: Record } ): Promise { return this.client.post( `/api/v2/aipAgents/agents/${agentRid}/sessions?preview=true`, params ); } /** Get a session. */ async getSession(sessionId: string): Promise { return this.client.get(`/api/v2/aipAgents/sessions/${sessionId}`, { preview: true, } as Record); } /** List sessions for the current user. */ async listSessions( params?: PageParams & { agentRid?: string } ): Promise> { return this.client.get("/api/v2/aipAgents/sessions", { ...params, preview: true, } as Record); } // ─── Agent Continue (replaces sendMessage) ────────────────────── /** * Send a message and wait for the full response (blocking). * Uses agent-centric path: /agents/{agentRid}/sessions/{sessionRid}/blockingContinue * @see https://www.palantir.com/docs/foundry/api/v2/aip-agents-v2-resources/sessions/blocking-continue-session/ */ async blockingContinue( agentRid: string, sessionRid: string, params: AipContinueParams ): Promise { return this.client.post( `/api/v2/aipAgents/agents/${agentRid}/sessions/${sessionRid}/blockingContinue?preview=true`, params ); } /** * Send a message and receive streaming response chunks. * Uses agent-centric path: /agents/{agentRid}/sessions/{sessionRid}/streamingContinue * Returns an async iterable of AipStreamingChunk objects. * @see https://www.palantir.com/docs/foundry/api/v2/aip-agents-v2-resources/sessions/streaming-continue-session/ */ async *streamingContinue( agentRid: string, sessionRid: string, params: AipContinueParams ): AsyncGenerator { const token = await this.client.getAccessToken(); const url = `${this.client.stackUrl}/api/v2/aipAgents/agents/${agentRid}/sessions/${sessionRid}/streamingContinue?preview=true`; const response = await this.client.rawFetch(url, { method: "POST", headers: { Authorization: `Bearer ${token ?? ""}`, "Content-Type": "application/json", Accept: "text/event-stream", }, body: JSON.stringify(params), }); if (!response.ok) { throw new Error(`Streaming continue failed: ${response.status} ${response.statusText}`); } const reader = response.body?.getReader(); if (!reader) throw new Error("No response body for streaming"); const decoder = new TextDecoder(); let buffer = ""; let dataBuffer = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() ?? ""; for (const line of lines) { if (line.startsWith("data: ")) { const data = line.slice(6); dataBuffer += data; } else if (line.startsWith("data:")) { // Space-separated continuation per SSE spec dataBuffer += line.slice(5); } else if (line === "" && dataBuffer) { // Empty line = end of event, emit accumulated data const trimmed = dataBuffer.trim(); dataBuffer = ""; if (trimmed === "[DONE]") return; try { yield JSON.parse(trimmed) as AipStreamingChunk; } catch { // Skip malformed chunks } } // Skip event:, id:, retry:, and comment lines } } // Emit any remaining data if (dataBuffer.trim()) { const trimmed = dataBuffer.trim(); if (trimmed !== "[DONE]") { try { yield JSON.parse(trimmed) as AipStreamingChunk; } catch { // Skip malformed chunks } } } } // ─── Session Content & Tracing ────────────────────────────────── /** Get the content (messages/exchanges) of a session. */ async getContent( agentRid: string, sessionRid: string, ): Promise { return this.client.get( `/api/v2/aipAgents/agents/${agentRid}/sessions/${sessionRid}/content`, { preview: true } as Record ); } /** * Cancel an in-progress streamed exchange. * @see https://www.palantir.com/docs/foundry/api/v2/aip-agents-v2-resources/sessions/cancel-session/ */ async cancel( agentRid: string, sessionRid: string, params?: { messageId?: string; clientResponse?: string } ): Promise { return this.client.post( `/api/v2/aipAgents/agents/${agentRid}/sessions/${sessionRid}/cancel?preview=true`, params ); } // ─── Language Models (LLM Proxy) ──────────────────────────────── // Foundry proxies requests to LLM providers via /api/v2/llm/proxy/ /** List available language models. */ async listModels(params?: PageParams): Promise> { return this.client.get("/api/v2/llm/models", params); } /** Get a specific model. */ async getModel(modelId: string): Promise { return this.client.get(`/api/v2/llm/models/${modelId}`); } /** * Chat completion via OpenAI-compatible proxy endpoint. * Supports GPT-4, GPT-4o, etc. * Requires scope: `api:use-language-models-execute` */ async openaiChatCompletion( params: ChatCompletionParams ): Promise { return this.client.post( "/api/v2/llm/proxy/openai/v1/chat/completions", params ); } /** * Chat completion via Anthropic-compatible proxy endpoint. * Supports Claude models. * Requires scope: `api:use-language-models-execute` */ async anthropicChatCompletion( params: Record ): Promise { return this.client.post( "/api/v2/llm/proxy/anthropic/v1/messages", params ); } /** * Chat completion via xAI (Grok) proxy endpoint. * Requires scope: `api:use-language-models-execute` */ async xaiChatCompletion( params: ChatCompletionParams ): Promise { return this.client.post( "/api/v2/llm/proxy/xai/v1/chat/completions", params ); } /** * Chat completion via Google Gemini proxy endpoint. * Requires scope: `api:use-language-models-execute` */ async googleChatCompletion( params: Record ): Promise { return this.client.post( "/api/v2/llm/proxy/google/v1/models:generateContent", params ); } }