@ziggs-ai/api-client 0.1.3 → 0.1.5

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.
Files changed (72) hide show
  1. package/README.md +13 -7
  2. package/dist/ConnectionManager.d.ts +46 -0
  3. package/dist/ConnectionManager.js +132 -0
  4. package/dist/http/AgentSearchClient.d.ts +36 -0
  5. package/dist/http/AgentSearchClient.js +72 -0
  6. package/dist/http/AgreementClient.d.ts +153 -0
  7. package/dist/http/AgreementClient.js +477 -0
  8. package/dist/http/ArtifactsClient.d.ts +48 -0
  9. package/dist/http/ArtifactsClient.js +90 -0
  10. package/dist/http/ChatClient.d.ts +34 -0
  11. package/dist/http/ChatClient.js +104 -0
  12. package/dist/http/ContextDiscoveryClient.d.ts +23 -0
  13. package/dist/http/ContextDiscoveryClient.js +35 -0
  14. package/dist/http/ContextReadClient.d.ts +33 -0
  15. package/dist/http/ContextReadClient.js +54 -0
  16. package/dist/http/MarketplaceClient.d.ts +19 -0
  17. package/dist/http/MarketplaceClient.js +72 -0
  18. package/dist/http/MessagesClient.d.ts +26 -0
  19. package/dist/http/MessagesClient.js +49 -0
  20. package/dist/http/ScopeClient.d.ts +33 -0
  21. package/dist/http/ScopeClient.js +39 -0
  22. package/dist/http/TaskClient.d.ts +75 -0
  23. package/dist/http/TaskClient.js +352 -0
  24. package/dist/http/TelemetryClient.d.ts +11 -0
  25. package/dist/http/TelemetryClient.js +53 -0
  26. package/dist/http/index.d.ts +16 -0
  27. package/dist/http/index.js +11 -0
  28. package/dist/index.d.ts +9 -0
  29. package/{src → dist}/index.js +2 -12
  30. package/dist/shared/runtimeLog.d.ts +14 -0
  31. package/dist/shared/runtimeLog.js +64 -0
  32. package/dist/types.d.ts +130 -0
  33. package/dist/types.js +50 -0
  34. package/dist/utils/urlUtils.d.ts +2 -0
  35. package/dist/utils/urlUtils.js +8 -0
  36. package/dist/websocket/ControlSocket.d.ts +13 -0
  37. package/dist/websocket/ControlSocket.js +37 -0
  38. package/dist/websocket/WebSocketClient.d.ts +71 -0
  39. package/dist/websocket/WebSocketClient.js +233 -0
  40. package/dist/websocket/index.js +1 -0
  41. package/package.json +20 -7
  42. package/src/ConnectionManager.ts +172 -0
  43. package/src/http/AgentSearchClient.ts +115 -0
  44. package/src/http/AgreementClient.ts +721 -0
  45. package/src/http/ArtifactsClient.ts +133 -0
  46. package/src/http/ChatClient.ts +147 -0
  47. package/src/http/ContextDiscoveryClient.ts +52 -0
  48. package/src/http/ContextReadClient.ts +83 -0
  49. package/src/http/MarketplaceClient.ts +94 -0
  50. package/src/http/MessagesClient.ts +71 -0
  51. package/src/http/ScopeClient.ts +64 -0
  52. package/src/http/TaskClient.ts +450 -0
  53. package/src/http/{TelemetryClient.js → TelemetryClient.ts} +21 -7
  54. package/src/http/index.ts +26 -0
  55. package/src/index.ts +27 -0
  56. package/src/shared/runtimeLog.ts +68 -0
  57. package/src/types.ts +158 -0
  58. package/src/utils/urlUtils.ts +9 -0
  59. package/src/websocket/ControlSocket.ts +51 -0
  60. package/src/websocket/WebSocketClient.ts +315 -0
  61. package/src/websocket/index.ts +1 -0
  62. package/src/ConnectionManager.js +0 -179
  63. package/src/http/AgentSearchClient.js +0 -113
  64. package/src/http/ContextReader.js +0 -99
  65. package/src/http/ContextWriter.js +0 -98
  66. package/src/http/TaskClient.js +0 -612
  67. package/src/http/index.js +0 -6
  68. package/src/types.js +0 -28
  69. package/src/utils/urlUtils.js +0 -17
  70. package/src/websocket/ControlSocket.js +0 -55
  71. package/src/websocket/WebSocketClient.js +0 -318
  72. /package/{src/websocket/index.js → dist/websocket/index.d.ts} +0 -0
@@ -1,55 +0,0 @@
1
- import { io } from 'socket.io-client';
2
-
3
- /**
4
- * createControlSocket — raw launcher-control protocol.
5
- *
6
- * Opens a single WebSocket to the backend identified as `role=launcher`, sends
7
- * `launcher:register { agentIds }` on every connect, and invokes `onWake(id)`
8
- * when the backend pushes a `launcher:wake { agentId }` frame.
9
- *
10
- * This is the minimum a non-SDK integrator needs in order to participate in
11
- * the "agents are available" story. Drop-in for other languages by mirroring
12
- * the three frames: connect with `?role=launcher`, emit `launcher:register`,
13
- * handle `launcher:wake`.
14
- *
15
- * @param {object} opts
16
- * @param {string} opts.wsUrl Backend WebSocket URL
17
- * @param {string} opts.operatorKey Operator key (JWT) with `launcher` scope.
18
- * @param {() => string[]} opts.agentIds Returns the current registered agentIds; called on every (re)connect
19
- * @param {(agentId: string) => void} opts.onWake Invoked when the backend requests a wake
20
- * @returns {{ close: () => void, resync: () => void, socket: import('socket.io-client').Socket }}
21
- */
22
- export function createControlSocket({ wsUrl, operatorKey, agentIds, onWake }) {
23
- if (!wsUrl || !operatorKey) throw new Error('[createControlSocket] wsUrl and operatorKey are required');
24
- if (typeof agentIds !== 'function') throw new Error('[createControlSocket] agentIds must be a function returning string[]');
25
- if (typeof onWake !== 'function') throw new Error('[createControlSocket] onWake must be a function');
26
-
27
- const socket = io(wsUrl, {
28
- auth: { token: `Bearer ${operatorKey}` },
29
- query: { token: operatorKey, role: 'launcher' },
30
- extraHeaders: { Authorization: `Bearer ${operatorKey}` },
31
- transports: ['websocket'],
32
- reconnection: true,
33
- reconnectionDelay: 1000,
34
- reconnectionDelayMax: 5000,
35
- });
36
-
37
- socket.on('connect', () => {
38
- const ids = agentIds();
39
- console.log(`[ControlSocket] connected (${socket.id}); registering ${ids.length} agent(s)`);
40
- socket.emit('launcher:register', { agentIds: ids });
41
- });
42
-
43
- socket.on('launcher:wake', ({ agentId }) => {
44
- if (agentId) onWake(agentId);
45
- });
46
-
47
- socket.on('disconnect', (reason) => console.log(`[ControlSocket] disconnected: ${reason}`));
48
- socket.on('connect_error', (err) => console.warn(`[ControlSocket] connect error: ${err.message}`));
49
-
50
- return {
51
- socket,
52
- close: () => socket.disconnect(),
53
- resync: () => { if (socket.connected) socket.emit('launcher:register', { agentIds: agentIds() }); },
54
- };
55
- }
@@ -1,318 +0,0 @@
1
- import { io } from "socket.io-client";
2
- import 'dotenv/config';
3
- import { getWebSocketUrl } from '../utils/urlUtils.js';
4
-
5
- class SessionState {
6
- constructor() {
7
- this.chatId = null;
8
- this.userId = null;
9
- }
10
-
11
- updateFromPayload(payload) {
12
-
13
- if (!payload || typeof payload !== 'object') {
14
- throw new Error('SessionState.updateFromPayload: payload must be an object');
15
- }
16
-
17
- if (payload.chatId) {
18
- if (typeof payload.chatId !== 'string') {
19
- throw new Error('SessionState.updateFromPayload: chatId must be a string');
20
- }
21
- this.chatId = payload.chatId;
22
- }
23
-
24
- if (payload.senderId) {
25
- if (typeof payload.senderId !== 'string') {
26
- throw new Error('SessionState.updateFromPayload: senderId must be a string');
27
- }
28
- this.userId = payload.senderId;
29
- }
30
- }
31
-
32
- isReady() {
33
- return !!(this.userId && this.chatId);
34
- }
35
-
36
- reset() {
37
- this.chatId = null;
38
- this.userId = null;
39
- }
40
-
41
- getMetadata() {
42
- return {
43
- chatId: this.chatId,
44
- userId: this.userId
45
- };
46
- }
47
- }
48
-
49
- export class WebSocketClient {
50
- constructor(options = {}) {
51
- this.wsUrl = options.wsUrl || getWebSocketUrl();
52
- this.operatorKey = options.operatorKey || process.env.ZIGGS_OPERATOR_KEY || null;
53
- this.agentId = options.agentId || null;
54
- this.label = options.label || 'agent';
55
- this.agentName = options.name || null;
56
- this.sessionState = new SessionState();
57
- this.socket = null;
58
- this.messageHandler = null;
59
- this.sessionOperationLimit = options.sessionOperationLimit ?? 30;
60
- // Per-chat operation counters — keyed by chatId to avoid cross-session interference
61
- this.operationCounts = new Map();
62
- }
63
-
64
- setMessageHandler(handler) {
65
- this.messageHandler = handler;
66
- }
67
-
68
- connect() {
69
- if (this.socket?.connected) {
70
- return;
71
- }
72
-
73
- console.log(`[${this.label}] Connecting to ${this.wsUrl}`);
74
- const socketOptions = this.buildSocketOptions();
75
- this.socket = io(this.wsUrl, socketOptions);
76
-
77
- this.socket.on('connect', () => {
78
- console.log(`[${this.label}] Connected`);
79
- });
80
-
81
- this.socket.on('connect_error', (error) => {
82
- console.error(`[${this.label}] Connection error: ${error.message}`);
83
- });
84
-
85
- this.socket.on('disconnect', (reason) => {
86
- const reasonDescriptions = {
87
- 'io server disconnect': 'Server forcefully disconnected the client',
88
- 'io client disconnect': 'Client manually disconnected',
89
- 'ping timeout': 'Server did not respond to ping (connection timeout)',
90
- 'transport close': 'Connection closed by transport layer',
91
- 'transport error': 'Transport error occurred',
92
- 'parse error': 'Error parsing server message',
93
- 'forced close': 'Connection was forcibly closed',
94
- 'forced server close': 'Server forcibly closed the connection'
95
- };
96
-
97
- const description = reasonDescriptions[reason] || 'Unknown disconnect reason';
98
- console.log(`[${this.label}] Disconnected: ${reason} — ${description}`);
99
-
100
- if (reason === 'io server disconnect') {
101
- console.log(`[${this.label}] Server disconnected — resetting session state`);
102
- this.sessionState.reset();
103
- this.operationCounts.clear();
104
- }
105
- });
106
-
107
- this.socket.on('messages', async (payload) => {
108
- try {
109
- await this.handleIncomingMessage(payload);
110
- } catch (error) {
111
- console.error(`[${this.label}] Error handling incoming message:`, error.message);
112
- throw error;
113
- }
114
- });
115
-
116
- this.socket.on('error', (error) => {
117
- console.error(`[${this.label}] Socket.IO error:`, error);
118
- });
119
- }
120
-
121
- connectAsync(timeout = 10_000) {
122
- if (this.socket?.connected) return Promise.resolve(this);
123
- return new Promise((resolve, reject) => {
124
- this.connect();
125
- const timer = setTimeout(
126
- () => reject(new Error(`[${this.label}] Connection timeout after ${timeout}ms`)),
127
- timeout
128
- );
129
- this.socket.once('connect', () => { clearTimeout(timer); resolve(this); });
130
- this.socket.once('connect_error', (err) => { clearTimeout(timer); reject(err); });
131
- });
132
- }
133
-
134
- disconnect() {
135
- if (this.socket) {
136
- this.socket.disconnect();
137
- this.socket = null;
138
- }
139
- }
140
-
141
- sendResponse(content, options = {}) {
142
-
143
- if (typeof content !== 'string' || content.trim().length === 0) {
144
- throw new Error('sendResponse: content must be a non-empty string');
145
- }
146
-
147
- const explicitReceiver = options.receiverId;
148
- const receiver = explicitReceiver || this.sessionState.userId;
149
-
150
- if (!receiver || typeof receiver !== 'string') {
151
- throw new Error('sendResponse: receiver is required (provide via options.receiverId or ensure session state has userId)');
152
- }
153
-
154
- if (!explicitReceiver) {
155
- console.warn(`[${this.label}] sendResponse: no receiverId in options, falling back to sessionState.userId (${receiver}) — pass receiverId explicitly to avoid cross-chat races`);
156
- }
157
-
158
- const explicitChatId = options.chatId;
159
- const chatId = explicitChatId || this.sessionState.chatId;
160
-
161
- if (!chatId) {
162
- throw new Error('sendResponse: chatId is required (provide via options.chatId or ensure session state has chatId)');
163
- }
164
-
165
- if (!explicitChatId) {
166
- console.warn(`[${this.label}] sendResponse: no chatId in options, falling back to sessionState.chatId (${chatId}) — pass chatId explicitly to avoid cross-chat races`);
167
- }
168
-
169
- if (!this.socket) {
170
- throw new Error('sendResponse: socket is not initialized. Call connect() first.');
171
- }
172
- if (!this.socket.connected) {
173
- throw new Error('sendResponse: socket is not connected. Call connect() and wait for connection.');
174
- }
175
-
176
- const messageId = this.generateMessageId();
177
- if (!messageId || typeof messageId !== 'string') {
178
- throw new Error('sendResponse: failed to generate valid messageId');
179
- }
180
-
181
- // Backend socket handler requires entryType + content_type (same as frontend useMessages).
182
- const message = {
183
- receiverId: receiver,
184
- chatId,
185
- messageId: messageId,
186
- text: content,
187
- entryType: options.entryType || 'message',
188
- content_type: options.content_type || options.contentType || 'text'
189
- };
190
-
191
- // Add service object with task if taskId provided
192
- if (options.taskId) {
193
- message.service = { task: { taskId: options.taskId } };
194
- }
195
-
196
- if (!message.receiverId || !message.chatId || !message.messageId || !message.text) {
197
- throw new Error('sendResponse: message validation failed - missing required fields');
198
- }
199
-
200
- const messagePreview = content.length > 100 ? content.substring(0, 100) + '...' : content;
201
- console.log(`📤 Sending message - chatId: ${message.chatId}, receiverId: ${message.receiverId}${options.receiverId ? ' (routed)' : ' (default)'}\n Message: ${messagePreview}`);
202
-
203
- this.socket.emit('chat', message);
204
- }
205
-
206
- getSessionMetadata() {
207
- return this.sessionState.getMetadata();
208
- }
209
-
210
- isConnected() {
211
- return this.socket?.connected || false;
212
- }
213
-
214
- isSessionReady() {
215
- return this.sessionState.isReady();
216
- }
217
-
218
- async handleIncomingMessage(payload) {
219
-
220
- if (!payload || typeof payload !== 'object') {
221
- throw new Error('handleIncomingMessage: payload must be an object');
222
- }
223
-
224
- if (!payload.text || typeof payload.text !== 'string' || payload.text.trim().length === 0) {
225
- throw new Error('handleIncomingMessage: payload.text is required and must be a non-empty string');
226
- }
227
-
228
- if (!payload.chatId || typeof payload.chatId !== 'string') {
229
- throw new Error('handleIncomingMessage: payload.chatId is required and must be a string');
230
- }
231
-
232
- // Extract sender info from new format: sender is { id, type } object
233
- const senderId = payload.sender?.id;
234
- const senderType = payload.sender?.type;
235
-
236
- if (!senderId || typeof senderId !== 'string') {
237
- throw new Error('handleIncomingMessage: payload.sender.id is required and must be a string');
238
- }
239
-
240
- console.log(`📥 Received message - chatId: ${payload.chatId}, sender: ${senderId} (${senderType})`);
241
-
242
- // Ignore own messages to prevent infinite loops
243
- if (this.agentId && senderId === this.agentId) {
244
- return;
245
- }
246
-
247
- // Update session state with extracted senderId (last-seen, for backward compat)
248
- this.sessionState.updateFromPayload({ chatId: payload.chatId, senderId });
249
-
250
- // Enforce per-chat operation limit to prevent infinite loops
251
- const chatOpCount = (this.operationCounts.get(payload.chatId) || 0) + 1;
252
- this.operationCounts.set(payload.chatId, chatOpCount);
253
- if (chatOpCount > this.sessionOperationLimit) {
254
- console.warn(`⚠️ Session operation limit (${this.sessionOperationLimit}) reached for chatId: ${payload.chatId}. Dropping message.`);
255
- await this.sendResponse(
256
- 'This session has reached its operation limit. Please start a new conversation.',
257
- { receiverId: senderId, chatId: payload.chatId }
258
- );
259
- return;
260
- }
261
-
262
- const text = payload.text;
263
-
264
- if (!this.messageHandler) {
265
- throw new Error('handleIncomingMessage: messageHandler is not set. Call setMessageHandler() first.');
266
- }
267
-
268
- const metadata = {
269
- chatId: payload.chatId,
270
- userId: senderId,
271
- sender: payload.sender,
272
- senderId: senderId,
273
- senderType: senderType,
274
- receiver: payload.receiver || null,
275
- receiverId: payload.receiver?.id || null,
276
- entryType: payload.entryType,
277
- content_type: payload.content_type,
278
- service: payload.service || null,
279
- taskId: payload.service?.task?.taskId || null
280
- };
281
-
282
- await this.messageHandler(text, metadata);
283
- }
284
-
285
- buildSocketOptions() {
286
- const options = {
287
- transports: ["websocket"],
288
- reconnection: true,
289
- reconnectionAttempts: Infinity,
290
- reconnectionDelay: 1000,
291
- reconnectionDelayMax: 5000,
292
- timeout: 20000,
293
- autoConnect: true,
294
- forceNew: false,
295
- multiplex: true,
296
- };
297
-
298
- if (this.operatorKey) {
299
- const bearer = `Bearer ${this.operatorKey}`;
300
- // Send token in multiple ways for maximum compatibility:
301
- // 1. Auth object (Socket.IO native)
302
- options.auth = { token: bearer };
303
- if (this.agentName) options.auth.agentName = this.agentName;
304
- // 2. Extra headers (works for direct connections)
305
- options.extraHeaders = { Authorization: bearer };
306
- // 3. Query parameter (works when proxies strip headers, e.g., Cloud Load Balancer)
307
- options.query = { token: bearer };
308
- if (this.agentId) options.query.agentId = this.agentId;
309
- if (this.agentName) options.query.agentName = this.agentName;
310
- }
311
-
312
- return options;
313
- }
314
-
315
- generateMessageId() {
316
- return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
317
- }
318
- }