needle-cloud 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -147,15 +147,8 @@ type RecentChatsResponse$1 = {
147
147
  }
148
148
 
149
149
 
150
- /** Tool definition provided by the client for client-side execution. */
151
- type ClientToolDefinition$1 = {
152
- name: string,
153
- description: string,
154
- parameters?: Record<string, any>,
155
- }
156
-
157
150
  /** Context block sent by the client (e.g. page metadata, scene hierarchy). */
158
- type ClientContext$1 = {
151
+ type ClientContext = {
159
152
  type: "text",
160
153
  text: string,
161
154
  }
@@ -183,7 +176,7 @@ type ChatMessage = {
183
176
  interrupted?: boolean,
184
177
  } | null,
185
178
  }
186
- type AIChatGETResponse$1 = {
179
+ type AIChatGETResponse = {
187
180
  chat_id: string,
188
181
  messages: Array<ChatMessage>,
189
182
  token_usage: AiTokenUsageInfo | null,
@@ -192,7 +185,7 @@ type AIChatGETResponse$1 = {
192
185
  }
193
186
 
194
187
  /** Response type when using stream: false in the request body. */
195
- type AIChatSyncResponse$1 = {
188
+ type AIChatSyncResponse = {
196
189
  chat_id: string,
197
190
  message_id: string,
198
191
  role: "assistant",
@@ -202,21 +195,154 @@ type AIChatSyncResponse$1 = {
202
195
  token_usage?: AiTokenUsageInfo | null,
203
196
  }
204
197
 
205
- /** Discriminated union for events yielded by the SSE chat stream. */
206
- type ChatStreamEvent$1 = { /** SSE event id for position tracking. */ id?: number } & (
198
+ /**
199
+ * Discriminated union for events yielded by the SSE chat stream.
200
+ *
201
+ * **Minimal handling** — for a basic chat UI, handle these:
202
+ * - `delta` — append to the current message
203
+ * - `done` — message complete, read `token_usage` for limits
204
+ * - `error` — display error to user
205
+ *
206
+ * **Full handling** — for a complete implementation:
207
+ * - `delta` / `message` — streaming text chunks / complete message text
208
+ * - `message_id` — server-assigned ID for the AI message (for storage/reference)
209
+ * - `chat_id` — server-assigned chat ID (emitted on first message when chat is created)
210
+ * - `tool_call` / `tool_result` — AI called a tool; tool returned a result (for UI status indicators)
211
+ * - `status` — human-readable status text (e.g. "Searching docs...", "Thinking...")
212
+ * - `stopped` — generation was interrupted by the user (via `interruptChat()`)
213
+ * - `done` — stream finished; includes `token_usage` with current usage/limits
214
+ * - `error` — something went wrong; `message` contains the error description
215
+ */
216
+ type ChatStreamEvent = { /** SSE event id for position tracking. */ id?: number } & (
217
+ /** Streaming text chunk — append to the current AI message. */
207
218
  | { type: "delta", content: string }
219
+ /** Complete message text (sent once at the end, contains the full response). */
208
220
  | { type: "message", content: string }
221
+ /** Server-assigned message ID for the AI response. */
209
222
  | { type: "message_id", message_id: string }
223
+ /** The AI invoked a tool. Use for UI indicators (e.g. "Running get_screenshot..."). */
210
224
  | { type: "tool_call", name: string, args: Record<string, any> }
225
+ /** A tool finished executing. The AI will continue generating with the result. */
211
226
  | { type: "tool_result", name: string }
212
- | { type: "client_tool_request", request_id: string, name: string, args: Record<string, any> }
227
+ /** An error occurred. Display `message` to the user. */
213
228
  | { type: "error", message: string }
229
+ /** Generation was interrupted by the user (via `interruptChat()`). */
214
230
  | { type: "stopped" }
231
+ /** Informational status update (e.g. "Searching documentation..."). */
215
232
  | { type: "status", message: string }
233
+ /** Stream complete. `token_usage` contains current usage and remaining quota. */
216
234
  | { type: "done", token_usage: AiTokenUsageInfo }
235
+ /** Server-assigned chat ID (emitted when a new chat is created on the first message). */
217
236
  | { type: "chat_id", chat_id: string }
218
237
  )
219
238
 
239
+
240
+ // ─── WebSocket Tool Connection Types ────────────────────────────────
241
+
242
+ /** Tool definition for registering tools via WebSocket. */
243
+ type ToolDefinition$1 = {
244
+ name: string,
245
+ description: string,
246
+ inputSchema: Record<string, any>,
247
+ }
248
+
249
+
250
+ // ─── ChatSession Types ──────────────────────────────────────────────
251
+
252
+ /**
253
+ * Options for `createChatSession()`.
254
+ *
255
+ * A ChatSession coordinates HTTP chat requests and an optional WebSocket
256
+ * tool connection into a single abstraction. If `tools` are provided,
257
+ * the session connects via WebSocket and waits for tool registration
258
+ * before allowing messages. If no tools are provided, it's HTTP-only.
259
+ */
260
+ type ChatSessionOptions$1 = {
261
+ /** Source identifier (e.g. "editor", "cli", "my-app"). Defaults to "sdk". */
262
+ source?: string,
263
+ /** Tools to register via WebSocket. If empty/omitted, no WS connection is made. */
264
+ tools?: ToolDefinition$1[],
265
+ /**
266
+ * Called when the server requests tool execution.
267
+ * Return `{ result: ... }` on success or `{ error: "..." }` on failure.
268
+ * Required if `tools` is non-empty.
269
+ */
270
+ onToolRequest?: (name: string, args: Record<string, any>) => Promise<{ result?: any, error?: string }>,
271
+ /**
272
+ * How long (ms) to wait for the WebSocket to connect and register tools
273
+ * before `ready` rejects. Defaults to 5000. Set to 0 to skip WS entirely.
274
+ */
275
+ toolReadyTimeout?: number,
276
+ /** Use personal chat context instead of team. Defaults to false (team). */
277
+ personal?: boolean,
278
+ }
279
+
280
+ /**
281
+ * A coordinated chat session that manages both HTTP chat and WebSocket tool connections.
282
+ *
283
+ * Created via `createChatSession()`. The `ready` promise resolves once the session
284
+ * is fully initialized (WS connected + tools registered, or immediately if no tools).
285
+ *
286
+ * @example
287
+ * ```js
288
+ * const session = createChatSession(authArgs, {
289
+ * tools: [{ name: "screenshot", description: "Take screenshot", inputSchema: {} }],
290
+ * onToolRequest: async (name, args) => ({ result: "data..." }),
291
+ * });
292
+ *
293
+ * await session.ready;
294
+ *
295
+ * for await (const event of session.sendMessage("my-chat", "Hello")) {
296
+ * if (event.type === "delta") process.stdout.write(event.content);
297
+ * }
298
+ *
299
+ * session.close();
300
+ * ```
301
+ */
302
+ type ChatSessionHandle$1 = {
303
+ /**
304
+ * Resolves when the session is ready to send messages.
305
+ * - With tools: resolves after WS connects and tools are registered.
306
+ * - Without tools: resolves immediately.
307
+ * Rejects if the WS connection fails or `toolReadyTimeout` is exceeded.
308
+ */
309
+ readonly ready: Promise<void>,
310
+ /**
311
+ * Send a message to a chat. Returns an async generator of stream events.
312
+ * Internally awaits `ready` before sending.
313
+ */
314
+ sendMessage(slug: string, message: string, options?: ChatSessionSendOptions$1): AsyncGenerator<ChatStreamEvent>,
315
+ /**
316
+ * Send a message and get a single JSON response (non-streaming).
317
+ * Internally awaits `ready` before sending.
318
+ */
319
+ sendMessageSync(slug: string, message: string, options?: ChatSessionSendOptions$1): Promise<AIChatSyncResponse>,
320
+ /** Interrupt an active AI generation for the given chat slug. */
321
+ interruptChat(slug: string): Promise<void>,
322
+ /** Read chat history for a slug. */
323
+ readChat(slug: string, options?: { offset?: number, limit?: number }): Promise<AIChatGETResponse>,
324
+ /** List recent chats. */
325
+ listChats(): Promise<RecentChatsResponse$1>,
326
+ /** Update the tools registered with the server. No-op if no WS connection. */
327
+ updateTools(tools: ToolDefinition$1[]): void,
328
+ /** Most recent token usage info, auto-updated from `done` events. Null until first message completes. */
329
+ readonly usage: AiTokenUsageInfo | null,
330
+ /** Whether the WebSocket tool connection is active. Always false if no tools were provided. */
331
+ readonly toolsConnected: boolean,
332
+ /** Close the session (WebSocket + cleanup). */
333
+ close(): void,
334
+ }
335
+
336
+ /** Options for `ChatSessionHandle.sendMessage()` and `sendMessageSync()`. */
337
+ type ChatSessionSendOptions$1 = {
338
+ /** Full URL of the page (for context). */
339
+ full_url?: string,
340
+ /** Pathname of the page (for context). */
341
+ pathname?: string,
342
+ /** Additional context blocks to send with the message. */
343
+ context?: ClientContext[],
344
+ }
345
+
220
346
  /**
221
347
  * @typedef {{ name: string, mimetype: string, buffer:Buffer }} Filelike
222
348
  * @typedef {import("../web.types.js").AuthData} AuthData
@@ -353,96 +479,57 @@ type Deployment = {
353
479
  */
354
480
  declare function listChats(opts?: ChatAuthOpts): Promise<RecentChatsResponse>;
355
481
  /**
356
- * Read an AI chat by slug. Returns JSON with messages by default.
357
- * When `reconnect: true`, attempts to reconnect to an active SSE stream.
358
- * @overload
359
- * @param {string} slug
360
- * @param {ChatAuthOpts & { offset?: number, limit?: number, personal?: boolean, reconnect?: false }} [opts]
361
- * @returns {Promise<AIChatGETResponse>}
362
- */
363
- declare function readChat(slug: string, opts?: ChatAuthOpts & {
364
- offset?: number;
365
- limit?: number;
366
- personal?: boolean;
367
- reconnect?: false;
368
- }): Promise<AIChatGETResponse>;
369
- /**
370
- * @overload
371
- * @param {string} slug
372
- * @param {ChatAuthOpts & { personal?: boolean, reconnect: true, signal?: AbortSignal }} opts
373
- * @returns {Promise<AsyncGenerator<ChatStreamEvent> | null>}
374
- */
375
- declare function readChat(slug: string, opts: ChatAuthOpts & {
376
- personal?: boolean;
377
- reconnect: true;
378
- signal?: AbortSignal;
379
- }): Promise<AsyncGenerator<ChatStreamEvent> | null>;
380
- /**
381
- * Send a message to an AI chat.
382
- * @overload
383
- * @param {string} slug
384
- * @param {string} message
385
- * @param {ChatAuthOpts & { stream?: false, source?: string, personal?: boolean, full_url?: string, pathname?: string, client_tools?: ClientToolDefinition[], context?: ClientContext[] }} [opts]
386
- * @returns {Promise<AIChatSyncResponse>}
387
- */
388
- declare function sendChatMessage(slug: string, message: string, opts?: ChatAuthOpts & {
389
- stream?: false;
390
- source?: string;
391
- personal?: boolean;
392
- full_url?: string;
393
- pathname?: string;
394
- client_tools?: ClientToolDefinition[];
395
- context?: ClientContext[];
396
- }): Promise<AIChatSyncResponse>;
397
- /**
398
- * @overload
399
- * @param {string} slug
400
- * @param {string} message
401
- * @param {ChatAuthOpts & { stream: true, source?: string, personal?: boolean, full_url?: string, pathname?: string, client_tools?: ClientToolDefinition[], context?: ClientContext[] }} opts
402
- * @returns {Promise<AsyncGenerator<ChatStreamEvent>>}
403
- */
404
- declare function sendChatMessage(slug: string, message: string, opts: ChatAuthOpts & {
405
- stream: true;
406
- source?: string;
407
- personal?: boolean;
408
- full_url?: string;
409
- pathname?: string;
410
- client_tools?: ClientToolDefinition[];
411
- context?: ClientContext[];
412
- }): Promise<AsyncGenerator<ChatStreamEvent>>;
413
- /**
414
- * Interrupt an active AI generation for the given chat slug.
415
- * @param {string} slug
416
- * @param {ChatAuthOpts & { personal?: boolean }} [opts]
417
- * @returns {Promise<void>}
418
- */
419
- declare function interruptChat(slug: string, opts?: ChatAuthOpts & {
420
- personal?: boolean;
421
- }): Promise<void>;
422
- /**
423
- * Submit a client-side tool execution result back to the server.
424
- * Call this when you receive a `client_tool_request` event from the SSE stream.
425
- * @param {string} requestId - The `request_id` from the `client_tool_request` event
426
- * @param {{ result?: any, error?: string }} outcome - The tool result or error
427
- * @param {ChatAuthOpts & { personal?: boolean }} [opts]
428
- * @returns {Promise<void>}
482
+ * Create a coordinated chat session with optional WebSocket tool support.
483
+ *
484
+ * This is the primary API for interacting with Needle Cloud AI chat.
485
+ * It combines HTTP chat requests and an optional WebSocket tool connection
486
+ * into a single abstraction.
487
+ *
488
+ * If `tools` are provided, the session connects via WebSocket and waits
489
+ * for tool registration before allowing messages. If no tools are provided,
490
+ * it's HTTP-only.
491
+ *
492
+ * @example
493
+ * ```js
494
+ * import { createChatSession } from "needle-cloud";
495
+ *
496
+ * // Simple chat (no tools)
497
+ * const session = await createChatSession();
498
+ * await session.ready;
499
+ * for await (const event of session.sendMessage("my-chat", "Hello")) {
500
+ * if (event.type === "delta") process.stdout.write(event.content);
501
+ * }
502
+ * session.close();
503
+ * ```
504
+ *
505
+ * @example
506
+ * ```js
507
+ * // Chat with tools
508
+ * const session = await createChatSession({
509
+ * tools: [{ name: "screenshot", description: "Take screenshot", inputSchema: {} }],
510
+ * onToolRequest: async (name, args) => ({ result: "data" }),
511
+ * });
512
+ * await session.ready; // waits for WS + tool registration
513
+ * for await (const event of session.sendMessage("my-chat", "Take a screenshot")) {
514
+ * if (event.type === "delta") process.stdout.write(event.content);
515
+ * }
516
+ * session.close();
517
+ * ```
518
+ *
519
+ * @param {import("@needle-tools/cloud-sdk/types/api.ai.js").ChatSessionOptions} [options]
520
+ * @param {ChatAuthOpts} [authOpts]
521
+ * @returns {Promise<import("@needle-tools/cloud-sdk/types/api.ai.js").ChatSessionHandle>}
429
522
  */
430
- declare function submitToolResult(requestId: string, outcome: {
431
- result?: any;
432
- error?: string;
433
- }, opts?: ChatAuthOpts & {
434
- personal?: boolean;
435
- }): Promise<void>;
523
+ declare function createChatSession(options?: ChatSessionOptions$1, authOpts?: ChatAuthOpts): Promise<ChatSessionHandle$1>;
436
524
  type ChatAuthOpts = {
437
525
  org?: string;
438
526
  authToken?: string;
439
527
  };
440
528
  type RecentChatsResponse = RecentChatsResponse$1;
441
- type AIChatGETResponse = AIChatGETResponse$1;
442
- type ChatStreamEvent = ChatStreamEvent$1;
443
- type ClientToolDefinition = ClientToolDefinition$1;
444
- type ClientContext = ClientContext$1;
445
- type AIChatSyncResponse = AIChatSyncResponse$1;
529
+ type ChatSessionOptions = ChatSessionOptions$1;
530
+ type ChatSessionHandle = ChatSessionHandle$1;
531
+ type ChatSessionSendOptions = ChatSessionSendOptions$1;
532
+ type ToolDefinition = ToolDefinition$1;
446
533
 
447
534
  /**
448
535
  * Start the checkout process
@@ -461,5 +548,5 @@ declare namespace AuthScopes {
461
548
  let All: string[];
462
549
  }
463
550
 
464
- export { Auth, AuthScopes, NeedleLoginButton, getDeployments, getUserLicenses, interruptChat, listChats, ownsProduct, readChat, sendChatMessage, startCheckoutSession, submitToolResult, uploadFiles };
465
- export type { AIChatGETResponse, AIChatSyncResponse, AuthData, AuthInitOpts, ChatAuthOpts, ChatStreamEvent, ClientContext, ClientToolDefinition, Deployment, Filelike, LogtoUserCustomData, RecentChatsResponse, ResourceUrl, UserInfoResponse };
551
+ export { Auth, AuthScopes, NeedleLoginButton, createChatSession, getDeployments, getUserLicenses, listChats, ownsProduct, startCheckoutSession, uploadFiles };
552
+ export type { AuthData, AuthInitOpts, ChatAuthOpts, ChatSessionHandle, ChatSessionOptions, ChatSessionSendOptions, Deployment, Filelike, LogtoUserCustomData, RecentChatsResponse, ResourceUrl, ToolDefinition, UserInfoResponse };