@yushaw/sanqian-sdk 0.1.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.
@@ -0,0 +1,471 @@
1
+ /**
2
+ * Sanqian SDK Type Definitions
3
+ */
4
+ interface SDKConfig {
5
+ /** Unique app identifier (e.g., "sanqian-todolist") */
6
+ appName: string;
7
+ /** App version string */
8
+ appVersion: string;
9
+ /** Display name shown in Sanqian UI */
10
+ displayName?: string;
11
+ /** Command to launch this app (for auto-start) */
12
+ launchCommand?: string;
13
+ /** Tools provided by this app */
14
+ tools: ToolDefinition[];
15
+ /** Reconnect interval in ms (default: 5000) */
16
+ reconnectInterval?: number;
17
+ /** Heartbeat interval in ms (default: 30000) */
18
+ heartbeatInterval?: number;
19
+ /** Tool execution timeout in ms (default: 30000) */
20
+ toolExecutionTimeout?: number;
21
+ /**
22
+ * Auto-launch Sanqian if not running (default: false)
23
+ * When enabled, SDK will try to start Sanqian in hidden/tray mode
24
+ */
25
+ autoLaunchSanqian?: boolean;
26
+ /**
27
+ * Custom path to Sanqian executable (optional)
28
+ * If not provided, SDK will search in standard installation locations
29
+ */
30
+ sanqianPath?: string;
31
+ }
32
+ interface ToolDefinition {
33
+ /** Tool name (without app prefix) */
34
+ name: string;
35
+ /** Tool description for LLM */
36
+ description: string;
37
+ /** JSON Schema for parameters */
38
+ parameters: JSONSchema;
39
+ /** Handler function */
40
+ handler: (args: any) => Promise<any>;
41
+ }
42
+ interface JSONSchema {
43
+ type: "object" | "array" | "string" | "number" | "boolean";
44
+ properties?: Record<string, JSONSchemaProperty>;
45
+ required?: string[];
46
+ items?: JSONSchemaProperty;
47
+ description?: string;
48
+ }
49
+ interface JSONSchemaProperty {
50
+ type: "string" | "number" | "boolean" | "array" | "object";
51
+ description?: string;
52
+ enum?: (string | number)[];
53
+ default?: unknown;
54
+ items?: JSONSchemaProperty;
55
+ properties?: Record<string, JSONSchemaProperty>;
56
+ required?: string[];
57
+ format?: string;
58
+ }
59
+ interface ConnectionInfo {
60
+ version: number;
61
+ port: number;
62
+ ws_path: string;
63
+ token: string;
64
+ pid: number;
65
+ started_at: string;
66
+ }
67
+ interface ConnectionState {
68
+ connected: boolean;
69
+ registering: boolean;
70
+ registered: boolean;
71
+ lastError?: Error;
72
+ reconnectAttempts: number;
73
+ }
74
+ /** Remote tool definition for dynamic tool injection */
75
+ interface RemoteToolDefinition {
76
+ /** Tool name */
77
+ name: string;
78
+ /** Tool description for LLM */
79
+ description: string;
80
+ /** JSON Schema for parameters */
81
+ parameters: JSONSchema;
82
+ }
83
+ interface ChatRequest {
84
+ /** Agent ID (can be short name, SDK auto-adds app prefix) */
85
+ agentId: string;
86
+ /** Messages to send */
87
+ messages: ChatMessage[];
88
+ /** Conversation ID for stateful mode (server stores messages) */
89
+ conversationId?: string;
90
+ /** Enable streaming (default: true) */
91
+ stream?: boolean;
92
+ /** Dynamic tools to inject at call time */
93
+ remoteTools?: RemoteToolDefinition[];
94
+ }
95
+ interface ChatMessage {
96
+ role: "user" | "assistant" | "system" | "tool";
97
+ content: string;
98
+ tool_calls?: ToolCall[];
99
+ tool_call_id?: string;
100
+ }
101
+ interface ToolCall {
102
+ id: string;
103
+ type: "function";
104
+ function: {
105
+ name: string;
106
+ arguments: string;
107
+ };
108
+ }
109
+ interface ChatResponse {
110
+ message: ChatMessage;
111
+ conversationId: string;
112
+ usage?: {
113
+ prompt_tokens: number;
114
+ completion_tokens: number;
115
+ total_tokens: number;
116
+ };
117
+ }
118
+ interface ChatStreamEvent {
119
+ type: "text" | "tool_call" | "done" | "error";
120
+ content?: string;
121
+ tool_call?: ToolCall;
122
+ conversationId?: string;
123
+ error?: string;
124
+ }
125
+ /** Agent configuration for create/update */
126
+ interface AgentConfig {
127
+ /** Unique agent ID within this app (e.g., "assistant") */
128
+ agent_id: string;
129
+ /** Display name */
130
+ name: string;
131
+ /** Description */
132
+ description?: string;
133
+ /** System prompt */
134
+ system_prompt?: string;
135
+ /** Tool names from this app to enable (without prefix) */
136
+ tools?: string[];
137
+ }
138
+ /** Agent info returned from list */
139
+ interface AgentInfo {
140
+ /** Full agent ID (app_name:agent_id) */
141
+ agent_id: string;
142
+ name: string;
143
+ description?: string;
144
+ /** Tool names with sdk_ prefix */
145
+ tools: string[];
146
+ created_at?: string;
147
+ }
148
+ /** Conversation info */
149
+ interface ConversationInfo {
150
+ conversation_id: string;
151
+ agent_id: string;
152
+ title?: string;
153
+ message_count: number;
154
+ created_at?: string;
155
+ updated_at?: string;
156
+ }
157
+ /** Message in a conversation */
158
+ interface ConversationMessage {
159
+ id: string;
160
+ role: "user" | "assistant" | "system" | "tool";
161
+ content: string;
162
+ tool_calls?: ToolCall[] | null;
163
+ tool_call_id?: string | null;
164
+ created_at?: string;
165
+ }
166
+ /** Full conversation with messages */
167
+ interface ConversationDetail extends ConversationInfo {
168
+ messages?: ConversationMessage[];
169
+ }
170
+ /** Agent update configuration (all fields optional except agent_id) */
171
+ interface AgentUpdateConfig {
172
+ /** Agent ID to update */
173
+ agent_id: string;
174
+ /** New display name */
175
+ name?: string;
176
+ /** New description */
177
+ description?: string;
178
+ /** New system prompt */
179
+ system_prompt?: string;
180
+ /** New tool names from this app to enable (without prefix) */
181
+ tools?: string[];
182
+ }
183
+ interface SDKEvents {
184
+ connected: () => void;
185
+ disconnected: (reason: string) => void;
186
+ registered: () => void;
187
+ error: (error: Error) => void;
188
+ tool_call: (call: {
189
+ name: string;
190
+ arguments: Record<string, unknown>;
191
+ }) => void;
192
+ }
193
+ type SDKEventName = keyof SDKEvents;
194
+
195
+ /**
196
+ * Sanqian SDK Client
197
+ *
198
+ * Main class for connecting to Sanqian and registering tools.
199
+ */
200
+
201
+ declare class SanqianSDK {
202
+ private config;
203
+ private discovery;
204
+ private ws;
205
+ private connectionInfo;
206
+ private state;
207
+ private toolHandlers;
208
+ private pendingRequests;
209
+ private heartbeatTimer;
210
+ private reconnectTimer;
211
+ private eventListeners;
212
+ constructor(config: SDKConfig);
213
+ /**
214
+ * Connect to Sanqian
215
+ *
216
+ * Reads connection info, establishes WebSocket, and registers app.
217
+ * Returns when registration is complete.
218
+ *
219
+ * If autoLaunchSanqian is enabled and Sanqian is not running,
220
+ * SDK will attempt to start it in hidden/tray mode.
221
+ */
222
+ connect(): Promise<void>;
223
+ /**
224
+ * Connect with known connection info
225
+ */
226
+ private connectWithInfo;
227
+ /**
228
+ * Disconnect from Sanqian
229
+ */
230
+ disconnect(): Promise<void>;
231
+ private register;
232
+ private handleMessage;
233
+ private handleChatStream;
234
+ private handleToolCall;
235
+ private sendToolResult;
236
+ private handleDisconnect;
237
+ private scheduleReconnect;
238
+ private stopReconnect;
239
+ private startHeartbeat;
240
+ private stopHeartbeat;
241
+ private send;
242
+ private sendAndWait;
243
+ /**
244
+ * Get current connection state
245
+ */
246
+ getState(): ConnectionState;
247
+ /**
248
+ * Check if connected and registered
249
+ */
250
+ isConnected(): boolean;
251
+ /**
252
+ * Update tool list dynamically
253
+ */
254
+ updateTools(tools: ToolDefinition[]): Promise<void>;
255
+ /**
256
+ * Create or update a private agent
257
+ *
258
+ * Private agents are only visible to this SDK app, not in Sanqian UI.
259
+ * If agent with same ID exists, it will be updated.
260
+ *
261
+ * @param config - Agent configuration
262
+ * @returns Full agent info (or agent_id string for backward compatibility)
263
+ */
264
+ createAgent(config: AgentConfig): Promise<AgentInfo>;
265
+ /**
266
+ * List all private agents owned by this app
267
+ */
268
+ listAgents(): Promise<AgentInfo[]>;
269
+ /**
270
+ * Delete a private agent
271
+ */
272
+ deleteAgent(agentId: string): Promise<void>;
273
+ /**
274
+ * Update a private agent
275
+ *
276
+ * Only updates the fields that are provided.
277
+ * @param agentId - Agent ID (short name or full)
278
+ * @param updates - Fields to update
279
+ * @returns Updated agent info
280
+ */
281
+ updateAgent(agentId: string, updates: Omit<AgentUpdateConfig, "agent_id">): Promise<AgentInfo>;
282
+ /**
283
+ * List conversations for this app
284
+ */
285
+ listConversations(options?: {
286
+ agentId?: string;
287
+ limit?: number;
288
+ offset?: number;
289
+ }): Promise<{
290
+ conversations: ConversationInfo[];
291
+ total: number;
292
+ }>;
293
+ /**
294
+ * Get conversation details with messages
295
+ */
296
+ getConversation(conversationId: string, options?: {
297
+ includeMessages?: boolean;
298
+ messageLimit?: number;
299
+ messageOffset?: number;
300
+ }): Promise<ConversationDetail>;
301
+ /**
302
+ * Delete a conversation
303
+ */
304
+ deleteConversation(conversationId: string): Promise<void>;
305
+ private streamHandlers;
306
+ /**
307
+ * Send a chat message to an agent (non-streaming)
308
+ *
309
+ * Supports two modes:
310
+ * - Stateless (no conversationId): Caller maintains message history
311
+ * - Stateful (with conversationId): Server stores messages in conversations table
312
+ *
313
+ * @param agentId - Agent ID (short name or full, SDK auto-prefixes)
314
+ * @param messages - Messages to send
315
+ * @param options - Optional settings including conversationId and remoteTools
316
+ * @returns Chat response with assistant message and conversation ID
317
+ */
318
+ chat(agentId: string, messages: ChatMessage[], options?: {
319
+ conversationId?: string;
320
+ remoteTools?: RemoteToolDefinition[];
321
+ }): Promise<ChatResponse>;
322
+ /**
323
+ * Send a chat message to an agent with streaming response
324
+ *
325
+ * Supports two modes:
326
+ * - Stateless (no conversationId): Caller maintains message history
327
+ * - Stateful (with conversationId): Server stores messages in conversations table
328
+ *
329
+ * @param agentId - Agent ID (short name or full, SDK auto-prefixes)
330
+ * @param messages - Messages to send
331
+ * @param options - Optional settings including conversationId and remoteTools
332
+ * @returns AsyncIterable of stream events
333
+ */
334
+ chatStream(agentId: string, messages: ChatMessage[], options?: {
335
+ conversationId?: string;
336
+ remoteTools?: RemoteToolDefinition[];
337
+ }): AsyncGenerator<ChatStreamEvent>;
338
+ /**
339
+ * Start a new conversation with an agent
340
+ *
341
+ * Returns a Conversation object for convenient multi-turn chat.
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * const conv = sdk.startConversation('assistant')
346
+ * const r1 = await conv.send('Hello')
347
+ * const r2 = await conv.send('Follow up question')
348
+ * console.log(conv.id) // conversation ID
349
+ * ```
350
+ */
351
+ startConversation(agentId: string): Conversation;
352
+ /**
353
+ * Add event listener
354
+ */
355
+ on<T extends SDKEventName>(event: T, listener: SDKEvents[T]): this;
356
+ /**
357
+ * Remove event listener
358
+ */
359
+ off<T extends SDKEventName>(event: T, listener: SDKEvents[T]): this;
360
+ private emit;
361
+ private generateId;
362
+ private createTimeout;
363
+ }
364
+ /**
365
+ * Conversation helper for multi-turn chat
366
+ *
367
+ * Automatically manages conversationId for stateful conversations.
368
+ */
369
+ declare class Conversation {
370
+ private sdk;
371
+ private agentId;
372
+ private _conversationId;
373
+ constructor(sdk: SanqianSDK, agentId: string, conversationId?: string);
374
+ /**
375
+ * Get the conversation ID (available after first message)
376
+ */
377
+ get id(): string | null;
378
+ /**
379
+ * Send a message and get a response
380
+ *
381
+ * First call creates a new conversation, subsequent calls continue it.
382
+ */
383
+ send(content: string, options?: {
384
+ remoteTools?: RemoteToolDefinition[];
385
+ }): Promise<ChatResponse>;
386
+ /**
387
+ * Send a message with streaming response
388
+ */
389
+ sendStream(content: string, options?: {
390
+ remoteTools?: RemoteToolDefinition[];
391
+ }): AsyncGenerator<ChatStreamEvent>;
392
+ /**
393
+ * Delete this conversation
394
+ */
395
+ delete(): Promise<void>;
396
+ /**
397
+ * Get conversation details including message history
398
+ */
399
+ getDetails(options?: {
400
+ messageLimit?: number;
401
+ }): Promise<ConversationDetail>;
402
+ }
403
+
404
+ /**
405
+ * Service Discovery Module
406
+ *
407
+ * Reads Sanqian's connection info from ~/.sanqian/runtime/connection.json
408
+ * and monitors file changes for reconnection.
409
+ * Also handles auto-launching Sanqian when needed.
410
+ */
411
+
412
+ declare class DiscoveryManager {
413
+ private connectionInfo;
414
+ private watcher;
415
+ private onChange;
416
+ private pollInterval;
417
+ /**
418
+ * Get the path to connection.json
419
+ */
420
+ getConnectionFilePath(): string;
421
+ /**
422
+ * Read and validate connection info
423
+ *
424
+ * Returns null if:
425
+ * - File doesn't exist
426
+ * - File is invalid JSON
427
+ * - Process is not running
428
+ */
429
+ read(): ConnectionInfo | null;
430
+ /**
431
+ * Start watching for connection file changes
432
+ */
433
+ startWatching(onChange: (info: ConnectionInfo | null) => void): void;
434
+ private setupWatcher;
435
+ /**
436
+ * Stop watching
437
+ */
438
+ stopWatching(): void;
439
+ /**
440
+ * Check if a process is running by PID
441
+ */
442
+ private isProcessRunning;
443
+ /**
444
+ * Get cached connection info (may be stale)
445
+ */
446
+ getCached(): ConnectionInfo | null;
447
+ /**
448
+ * Build WebSocket URL from connection info
449
+ */
450
+ buildWebSocketUrl(info: ConnectionInfo): string;
451
+ /**
452
+ * Build HTTP base URL from connection info
453
+ */
454
+ buildHttpUrl(info: ConnectionInfo): string;
455
+ /**
456
+ * Find Sanqian executable path
457
+ * Searches in standard installation locations for each platform
458
+ */
459
+ findSanqianPath(customPath?: string): string | null;
460
+ /**
461
+ * Launch Sanqian in hidden/tray mode
462
+ * Returns true if launch was initiated successfully
463
+ */
464
+ launchSanqian(customPath?: string): boolean;
465
+ /**
466
+ * Check if Sanqian is running
467
+ */
468
+ isSanqianRunning(): boolean;
469
+ }
470
+
471
+ export { type AgentConfig, type AgentInfo, type AgentUpdateConfig, type ChatMessage, type ChatRequest, type ChatResponse, type ChatStreamEvent, type ConnectionInfo, type ConnectionState, Conversation, type ConversationDetail, type ConversationInfo, type ConversationMessage, DiscoveryManager, type JSONSchema, type JSONSchemaProperty, type RemoteToolDefinition, type SDKConfig, type SDKEventName, type SDKEvents, SanqianSDK, type ToolCall, type ToolDefinition };