@inferencesh/sdk 0.1.1 → 0.2.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.
- package/README.md +98 -8
- package/dist/agent.d.ts +75 -0
- package/dist/agent.js +196 -0
- package/dist/client.d.ts +111 -10
- package/dist/client.js +214 -17
- package/dist/client.test.js +101 -10
- package/dist/errors.d.ts +50 -0
- package/dist/errors.js +61 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +22 -2
- package/dist/stream.d.ts +8 -0
- package/dist/stream.js +48 -0
- package/dist/tool-builder.d.ts +82 -0
- package/dist/tool-builder.js +212 -0
- package/dist/tool-builder.test.d.ts +1 -0
- package/dist/tool-builder.test.js +291 -0
- package/dist/types.d.ts +939 -2105
- package/dist/types.js +83 -160
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.Agent = exports.Inference = void 0;
|
|
4
|
+
exports.inference = inference;
|
|
4
5
|
const types_1 = require("./types");
|
|
5
6
|
const stream_1 = require("./stream");
|
|
6
7
|
const eventsource_1 = require("eventsource");
|
|
8
|
+
const errors_1 = require("./errors");
|
|
7
9
|
/**
|
|
8
10
|
* Inference.sh SDK Client
|
|
9
11
|
*
|
|
@@ -21,7 +23,8 @@ class Inference {
|
|
|
21
23
|
this.apiKey = config.apiKey;
|
|
22
24
|
this.baseUrl = config.baseUrl || "https://api.inference.sh";
|
|
23
25
|
}
|
|
24
|
-
|
|
26
|
+
/** @internal */
|
|
27
|
+
async _request(method, endpoint, options = {}) {
|
|
25
28
|
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
26
29
|
if (options.params) {
|
|
27
30
|
Object.entries(options.params).forEach(([key, value]) => {
|
|
@@ -43,13 +46,48 @@ class Inference {
|
|
|
43
46
|
fetchOptions.body = JSON.stringify(options.data);
|
|
44
47
|
}
|
|
45
48
|
const response = await fetch(url.toString(), fetchOptions);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
const responseText = await response.text();
|
|
50
|
+
// Try to parse as JSON
|
|
51
|
+
let data = null;
|
|
52
|
+
try {
|
|
53
|
+
data = JSON.parse(responseText);
|
|
49
54
|
}
|
|
50
|
-
|
|
55
|
+
catch {
|
|
56
|
+
// Not JSON
|
|
57
|
+
}
|
|
58
|
+
// Check for HTTP errors
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
// Check for RequirementsNotMetException (412 with errors array)
|
|
61
|
+
if (response.status === 412 && data && 'errors' in data && Array.isArray(data.errors)) {
|
|
62
|
+
throw errors_1.RequirementsNotMetException.fromResponse(data, response.status);
|
|
63
|
+
}
|
|
64
|
+
// General error handling
|
|
65
|
+
let errorDetail;
|
|
66
|
+
if (data && typeof data === 'object') {
|
|
67
|
+
const apiData = data;
|
|
68
|
+
if (apiData.error) {
|
|
69
|
+
errorDetail = typeof apiData.error === 'object' ? apiData.error.message : String(apiData.error);
|
|
70
|
+
}
|
|
71
|
+
else if ('message' in data) {
|
|
72
|
+
errorDetail = String(data.message);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
errorDetail = JSON.stringify(data);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (responseText) {
|
|
79
|
+
errorDetail = responseText.slice(0, 500);
|
|
80
|
+
}
|
|
81
|
+
throw new errors_1.InferenceError(response.status, errorDetail || 'Request failed', responseText);
|
|
82
|
+
}
|
|
83
|
+
const apiResponse = data;
|
|
84
|
+
if (!apiResponse?.success) {
|
|
85
|
+
throw new errors_1.InferenceError(response.status, apiResponse?.error?.message || 'Request failed', responseText);
|
|
86
|
+
}
|
|
87
|
+
return apiResponse.data;
|
|
51
88
|
}
|
|
52
|
-
|
|
89
|
+
/** @internal */
|
|
90
|
+
_createEventSource(endpoint) {
|
|
53
91
|
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
54
92
|
return new eventsource_1.EventSource(url.toString(), {
|
|
55
93
|
fetch: (input, init) => fetch(input, {
|
|
@@ -112,26 +150,37 @@ class Inference {
|
|
|
112
150
|
* @param options - Run options for waiting, updates, and reconnection
|
|
113
151
|
* @returns The completed task result
|
|
114
152
|
*
|
|
153
|
+
* App reference format: `namespace/name@shortid` (version is required)
|
|
154
|
+
*
|
|
155
|
+
* The short ID ensures your code always runs the same version,
|
|
156
|
+
* protecting against breaking changes from app updates.
|
|
157
|
+
*
|
|
115
158
|
* @example
|
|
116
159
|
* ```typescript
|
|
117
|
-
* //
|
|
118
|
-
* const result = await client.run({
|
|
160
|
+
* // Run a specific version (required)
|
|
161
|
+
* const result = await client.run({
|
|
162
|
+
* app: 'okaris/flux@abc1', // version @abc1 is pinned
|
|
163
|
+
* input: { prompt: 'hello' }
|
|
164
|
+
* });
|
|
119
165
|
*
|
|
120
166
|
* // With status updates
|
|
121
167
|
* const result = await client.run(
|
|
122
|
-
* { app: '
|
|
168
|
+
* { app: 'okaris/flux@abc1', input: { prompt: 'hello' } },
|
|
123
169
|
* { onUpdate: (update) => console.log(update.status) }
|
|
124
170
|
* );
|
|
125
171
|
*
|
|
126
172
|
* // Fire and forget
|
|
127
|
-
* const task = await client.run(
|
|
173
|
+
* const task = await client.run(
|
|
174
|
+
* { app: 'okaris/flux@abc1', input: {} },
|
|
175
|
+
* { wait: false }
|
|
176
|
+
* );
|
|
128
177
|
* ```
|
|
129
178
|
*/
|
|
130
179
|
async run(params, options = {}) {
|
|
131
180
|
const { onUpdate, onPartialUpdate, wait = true, autoReconnect = true, maxReconnects = 5, reconnectDelayMs = 1000, } = options;
|
|
132
181
|
// Process input data and upload any files
|
|
133
182
|
const processedInput = await this.processInputData(params.input);
|
|
134
|
-
const task = await this.
|
|
183
|
+
const task = await this._request("post", "/apps/run", {
|
|
135
184
|
data: {
|
|
136
185
|
...params,
|
|
137
186
|
input: processedInput
|
|
@@ -144,7 +193,7 @@ class Inference {
|
|
|
144
193
|
// Wait for completion with optional updates
|
|
145
194
|
return new Promise((resolve, reject) => {
|
|
146
195
|
const streamManager = new stream_1.StreamManager({
|
|
147
|
-
createEventSource: async () => this.
|
|
196
|
+
createEventSource: async () => this._createEventSource(`/tasks/${task.id}/stream`),
|
|
148
197
|
autoReconnect,
|
|
149
198
|
maxReconnects,
|
|
150
199
|
reconnectDelayMs,
|
|
@@ -189,7 +238,7 @@ class Inference {
|
|
|
189
238
|
path: options.path,
|
|
190
239
|
size: data instanceof Blob ? data.size : undefined,
|
|
191
240
|
};
|
|
192
|
-
const response = await this.
|
|
241
|
+
const response = await this._request("post", "/files", {
|
|
193
242
|
data: {
|
|
194
243
|
files: [fileRequest]
|
|
195
244
|
}
|
|
@@ -246,11 +295,159 @@ class Inference {
|
|
|
246
295
|
* @param taskId - The ID of the task to cancel
|
|
247
296
|
*/
|
|
248
297
|
async cancel(taskId) {
|
|
249
|
-
return this.
|
|
298
|
+
return this._request("post", `/tasks/${taskId}/cancel`);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Create an agent for chat interactions
|
|
302
|
+
*
|
|
303
|
+
* @param config - Either a template reference string (namespace/name@version) or ad-hoc config
|
|
304
|
+
* @returns An Agent instance for chat operations
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```typescript
|
|
308
|
+
* // Template agent
|
|
309
|
+
* const agent = client.agent('okaris/assistant@abc123')
|
|
310
|
+
*
|
|
311
|
+
* // Ad-hoc agent
|
|
312
|
+
* const agent = client.agent({
|
|
313
|
+
* coreApp: 'infsh/claude-sonnet-4@xyz789',
|
|
314
|
+
* systemPrompt: 'You are a helpful assistant',
|
|
315
|
+
* tools: [...]
|
|
316
|
+
* })
|
|
317
|
+
*
|
|
318
|
+
* // Send messages
|
|
319
|
+
* const response = await agent.sendMessage('Hello!')
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
agent(config) {
|
|
323
|
+
return new Agent(this, config);
|
|
250
324
|
}
|
|
251
325
|
}
|
|
252
326
|
exports.Inference = Inference;
|
|
327
|
+
// =============================================================================
|
|
328
|
+
// Agent Class
|
|
329
|
+
// =============================================================================
|
|
253
330
|
/**
|
|
254
|
-
*
|
|
331
|
+
* Agent for chat interactions
|
|
332
|
+
*
|
|
333
|
+
* Created via `client.agent()` - do not instantiate directly.
|
|
255
334
|
*/
|
|
256
|
-
|
|
335
|
+
class Agent {
|
|
336
|
+
/** @internal */
|
|
337
|
+
constructor(client, config) {
|
|
338
|
+
this.chatId = null;
|
|
339
|
+
this.stream = null;
|
|
340
|
+
this.client = client;
|
|
341
|
+
this.config = config;
|
|
342
|
+
}
|
|
343
|
+
/** Get current chat ID */
|
|
344
|
+
get currentChatId() {
|
|
345
|
+
return this.chatId;
|
|
346
|
+
}
|
|
347
|
+
/** Send a message to the agent */
|
|
348
|
+
async sendMessage(text, options = {}) {
|
|
349
|
+
const isTemplate = typeof this.config === 'string';
|
|
350
|
+
// Upload files if provided
|
|
351
|
+
let imageUri;
|
|
352
|
+
let fileUris;
|
|
353
|
+
if (options.files && options.files.length > 0) {
|
|
354
|
+
const uploadedFiles = await Promise.all(options.files.map(f => this.client.uploadFile(f)));
|
|
355
|
+
const images = uploadedFiles.filter(f => f.content_type?.startsWith('image/'));
|
|
356
|
+
const others = uploadedFiles.filter(f => !f.content_type?.startsWith('image/'));
|
|
357
|
+
if (images.length > 0)
|
|
358
|
+
imageUri = images[0].uri;
|
|
359
|
+
if (others.length > 0)
|
|
360
|
+
fileUris = others.map(f => f.uri);
|
|
361
|
+
}
|
|
362
|
+
const body = isTemplate
|
|
363
|
+
? {
|
|
364
|
+
chat_id: this.chatId,
|
|
365
|
+
agent: this.config,
|
|
366
|
+
input: { text, image: imageUri, files: fileUris, role: 'user', context: [], system_prompt: '', context_size: 0 },
|
|
367
|
+
}
|
|
368
|
+
: {
|
|
369
|
+
chat_id: this.chatId,
|
|
370
|
+
core_app: this.config.coreApp,
|
|
371
|
+
core_app_input: this.config.coreAppInput,
|
|
372
|
+
name: this.config.name,
|
|
373
|
+
system_prompt: this.config.systemPrompt,
|
|
374
|
+
tools: this.config.tools,
|
|
375
|
+
internal_tools: this.config.internalTools,
|
|
376
|
+
input: { text, image: imageUri, files: fileUris, role: 'user', context: [], system_prompt: '', context_size: 0 },
|
|
377
|
+
};
|
|
378
|
+
const response = await this.client._request('post', '/agents/run', { data: body });
|
|
379
|
+
if (!this.chatId && response.assistant_message.chat_id) {
|
|
380
|
+
this.chatId = response.assistant_message.chat_id;
|
|
381
|
+
this.startStreaming(options);
|
|
382
|
+
}
|
|
383
|
+
return response.assistant_message;
|
|
384
|
+
}
|
|
385
|
+
/** Get chat by ID */
|
|
386
|
+
async getChat(chatId) {
|
|
387
|
+
const id = chatId || this.chatId;
|
|
388
|
+
if (!id)
|
|
389
|
+
return null;
|
|
390
|
+
return this.client._request('get', `/chats/${id}`);
|
|
391
|
+
}
|
|
392
|
+
/** Stop the current chat generation */
|
|
393
|
+
async stopChat() {
|
|
394
|
+
if (!this.chatId)
|
|
395
|
+
return;
|
|
396
|
+
await this.client._request('post', `/chats/${this.chatId}/stop`);
|
|
397
|
+
}
|
|
398
|
+
/** Submit a tool result */
|
|
399
|
+
async submitToolResult(toolInvocationId, result) {
|
|
400
|
+
if (!this.chatId)
|
|
401
|
+
throw new Error('No active chat');
|
|
402
|
+
await this.client._request('post', `/chats/${this.chatId}/tool-result`, {
|
|
403
|
+
data: { tool_invocation_id: toolInvocationId, result },
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
/** Stop streaming and cleanup */
|
|
407
|
+
disconnect() {
|
|
408
|
+
this.stream?.stop();
|
|
409
|
+
this.stream = null;
|
|
410
|
+
}
|
|
411
|
+
/** Reset the agent (start fresh chat) */
|
|
412
|
+
reset() {
|
|
413
|
+
this.disconnect();
|
|
414
|
+
this.chatId = null;
|
|
415
|
+
}
|
|
416
|
+
startStreaming(options) {
|
|
417
|
+
if (!this.chatId)
|
|
418
|
+
return;
|
|
419
|
+
this.stream = new stream_1.StreamManager({
|
|
420
|
+
createEventSource: async () => this.client._createEventSource(`/chats/${this.chatId}/stream`),
|
|
421
|
+
autoReconnect: true,
|
|
422
|
+
});
|
|
423
|
+
this.stream.addEventListener('chats', (chat) => {
|
|
424
|
+
options.onChat?.(chat);
|
|
425
|
+
});
|
|
426
|
+
this.stream.addEventListener('chat_messages', (message) => {
|
|
427
|
+
options.onMessage?.(message);
|
|
428
|
+
if (message.tool_invocations && options.onToolCall) {
|
|
429
|
+
for (const inv of message.tool_invocations) {
|
|
430
|
+
if (inv.type === types_1.ToolTypeClient && inv.status === types_1.ToolInvocationStatusAwaitingInput) {
|
|
431
|
+
options.onToolCall({
|
|
432
|
+
id: inv.id,
|
|
433
|
+
name: inv.function?.name || '',
|
|
434
|
+
args: inv.function?.arguments || {},
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
this.stream.connect();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
exports.Agent = Agent;
|
|
444
|
+
/**
|
|
445
|
+
* Factory function for creating an Inference client (lowercase for branding)
|
|
446
|
+
* @example
|
|
447
|
+
* ```typescript
|
|
448
|
+
* const client = inference({ apiKey: 'your-api-key' });
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
function inference(config) {
|
|
452
|
+
return new Inference(config);
|
|
453
|
+
}
|
package/dist/client.test.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const client_1 = require("./client");
|
|
4
|
+
const errors_1 = require("./errors");
|
|
4
5
|
// Mock fetch globally
|
|
5
6
|
const mockFetch = jest.fn();
|
|
6
7
|
global.fetch = mockFetch;
|
|
@@ -39,8 +40,12 @@ describe('Inference', () => {
|
|
|
39
40
|
input: { message: 'hello world' },
|
|
40
41
|
output: { result: 'success' },
|
|
41
42
|
};
|
|
43
|
+
const responseData = { success: true, data: mockTask };
|
|
42
44
|
mockFetch.mockResolvedValueOnce({
|
|
43
|
-
|
|
45
|
+
ok: true,
|
|
46
|
+
status: 200,
|
|
47
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
48
|
+
json: () => Promise.resolve(responseData),
|
|
44
49
|
});
|
|
45
50
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
46
51
|
// Use input that won't trigger base64 detection (contains spaces/special chars)
|
|
@@ -55,29 +60,107 @@ describe('Inference', () => {
|
|
|
55
60
|
}));
|
|
56
61
|
});
|
|
57
62
|
it('should throw error on API failure', async () => {
|
|
63
|
+
const responseData = { success: false, error: { message: 'Invalid app' } };
|
|
58
64
|
mockFetch.mockResolvedValueOnce({
|
|
59
|
-
|
|
65
|
+
ok: false,
|
|
66
|
+
status: 400,
|
|
67
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
68
|
+
json: () => Promise.resolve(responseData),
|
|
60
69
|
});
|
|
61
70
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
62
71
|
await expect(client.run({ app: 'invalid-app', input: { message: 'test!' } }, { wait: false })).rejects.toThrow('Invalid app');
|
|
63
72
|
});
|
|
73
|
+
it('should throw RequirementsNotMetException on 412 with errors', async () => {
|
|
74
|
+
const requirementErrors = [
|
|
75
|
+
{
|
|
76
|
+
type: 'secret',
|
|
77
|
+
key: 'OPENAI_API_KEY',
|
|
78
|
+
message: 'Missing secret: OPENAI_API_KEY',
|
|
79
|
+
action: { type: 'add_secret', secret_key: 'OPENAI_API_KEY' },
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: 'integration',
|
|
83
|
+
key: 'google',
|
|
84
|
+
message: 'Integration not connected: google',
|
|
85
|
+
action: { type: 'connect', provider: 'google' },
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
const responseData = { errors: requirementErrors };
|
|
89
|
+
mockFetch.mockResolvedValueOnce({
|
|
90
|
+
ok: false,
|
|
91
|
+
status: 412,
|
|
92
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
93
|
+
json: () => Promise.resolve(responseData),
|
|
94
|
+
});
|
|
95
|
+
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
96
|
+
try {
|
|
97
|
+
await client.run({ app: 'test-app', input: { message: 'test!' } }, { wait: false });
|
|
98
|
+
fail('Expected RequirementsNotMetException to be thrown');
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
expect(e).toBeInstanceOf(errors_1.RequirementsNotMetException);
|
|
102
|
+
const exception = e;
|
|
103
|
+
expect(exception.errors).toHaveLength(2);
|
|
104
|
+
expect(exception.errors[0].type).toBe('secret');
|
|
105
|
+
expect(exception.errors[0].key).toBe('OPENAI_API_KEY');
|
|
106
|
+
expect(exception.errors[1].type).toBe('integration');
|
|
107
|
+
expect(exception.statusCode).toBe(412);
|
|
108
|
+
expect(exception.message).toBe('Missing secret: OPENAI_API_KEY');
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
it('should include action details in RequirementsNotMetException', async () => {
|
|
112
|
+
const requirementErrors = [
|
|
113
|
+
{
|
|
114
|
+
type: 'scope',
|
|
115
|
+
key: 'calendar.readonly',
|
|
116
|
+
message: 'Missing scope: calendar.readonly',
|
|
117
|
+
action: {
|
|
118
|
+
type: 'add_scopes',
|
|
119
|
+
provider: 'google',
|
|
120
|
+
scopes: ['calendar.readonly', 'calendar.events'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
const responseData = { errors: requirementErrors };
|
|
125
|
+
mockFetch.mockResolvedValueOnce({
|
|
126
|
+
ok: false,
|
|
127
|
+
status: 412,
|
|
128
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
129
|
+
json: () => Promise.resolve(responseData),
|
|
130
|
+
});
|
|
131
|
+
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
132
|
+
try {
|
|
133
|
+
await client.run({ app: 'test-app', input: {} }, { wait: false });
|
|
134
|
+
fail('Expected RequirementsNotMetException to be thrown');
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
expect(e).toBeInstanceOf(errors_1.RequirementsNotMetException);
|
|
138
|
+
const exception = e;
|
|
139
|
+
expect(exception.errors[0].action?.type).toBe('add_scopes');
|
|
140
|
+
expect(exception.errors[0].action?.scopes).toEqual(['calendar.readonly', 'calendar.events']);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
64
143
|
});
|
|
65
144
|
describe('cancel', () => {
|
|
66
145
|
it('should make a POST request to cancel endpoint', async () => {
|
|
146
|
+
const responseData = { success: true, data: null };
|
|
67
147
|
mockFetch.mockResolvedValueOnce({
|
|
68
|
-
|
|
148
|
+
ok: true,
|
|
149
|
+
status: 200,
|
|
150
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
151
|
+
json: () => Promise.resolve(responseData),
|
|
69
152
|
});
|
|
70
153
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
71
154
|
await client.cancel('task-123');
|
|
72
155
|
expect(mockFetch).toHaveBeenCalledWith(expect.stringContaining('/tasks/task-123/cancel'), expect.objectContaining({ method: 'POST' }));
|
|
73
156
|
});
|
|
74
157
|
});
|
|
75
|
-
describe('
|
|
76
|
-
it('should export lowercase inference
|
|
77
|
-
expect(client_1.inference).toBe(
|
|
158
|
+
describe('lowercase factory', () => {
|
|
159
|
+
it('should export lowercase inference factory', () => {
|
|
160
|
+
expect(typeof client_1.inference).toBe('function');
|
|
78
161
|
});
|
|
79
|
-
it('should work with lowercase inference', () => {
|
|
80
|
-
const client =
|
|
162
|
+
it('should work with lowercase inference factory', () => {
|
|
163
|
+
const client = (0, client_1.inference)({ apiKey: 'test-api-key' });
|
|
81
164
|
expect(client).toBeInstanceOf(client_1.Inference);
|
|
82
165
|
});
|
|
83
166
|
});
|
|
@@ -92,9 +175,13 @@ describe('uploadFile', () => {
|
|
|
92
175
|
uri: 'https://example.com/file.png',
|
|
93
176
|
upload_url: 'https://upload.example.com/signed-url',
|
|
94
177
|
};
|
|
178
|
+
const responseData = { success: true, data: [mockFile] };
|
|
95
179
|
mockFetch
|
|
96
180
|
.mockResolvedValueOnce({
|
|
97
|
-
|
|
181
|
+
ok: true,
|
|
182
|
+
status: 200,
|
|
183
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
184
|
+
json: () => Promise.resolve(responseData),
|
|
98
185
|
})
|
|
99
186
|
.mockResolvedValueOnce({ ok: true });
|
|
100
187
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
@@ -112,8 +199,12 @@ describe('uploadFile', () => {
|
|
|
112
199
|
uri: 'https://example.com/file.png',
|
|
113
200
|
// Missing upload_url
|
|
114
201
|
};
|
|
202
|
+
const responseData = { success: true, data: [mockFile] };
|
|
115
203
|
mockFetch.mockResolvedValueOnce({
|
|
116
|
-
|
|
204
|
+
ok: true,
|
|
205
|
+
status: 200,
|
|
206
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
207
|
+
json: () => Promise.resolve(responseData),
|
|
117
208
|
});
|
|
118
209
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
119
210
|
await expect(client.uploadFile('SGVsbG8gV29ybGQh', { filename: 'test.txt' })).rejects.toThrow('No upload URL provided by the server');
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for the inference.sh SDK.
|
|
3
|
+
*
|
|
4
|
+
* Note: types.ts contains interfaces (APIError, RequirementsNotMetError) that describe
|
|
5
|
+
* the API response data shapes. These classes are throwable Error subclasses for SDK use.
|
|
6
|
+
*/
|
|
7
|
+
import type { RequirementError } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* General HTTP/API error thrown by the SDK.
|
|
10
|
+
*
|
|
11
|
+
* Note: This is distinct from the `APIError` interface in types.ts which describes
|
|
12
|
+
* the error payload shape in API responses.
|
|
13
|
+
*/
|
|
14
|
+
export declare class InferenceError extends Error {
|
|
15
|
+
readonly statusCode: number;
|
|
16
|
+
readonly responseBody?: string;
|
|
17
|
+
constructor(statusCode: number, message: string, responseBody?: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when app requirements (secrets, integrations, scopes) are not met.
|
|
21
|
+
*
|
|
22
|
+
* Thrown for HTTP 412 responses that contain structured requirement errors.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* try {
|
|
27
|
+
* const task = await client.run(params);
|
|
28
|
+
* } catch (e) {
|
|
29
|
+
* if (e instanceof RequirementsNotMetException) {
|
|
30
|
+
* for (const err of e.errors) {
|
|
31
|
+
* console.log(`Missing ${err.type}: ${err.key}`);
|
|
32
|
+
* if (err.action) {
|
|
33
|
+
* console.log(` Fix: ${err.action.type}`);
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class RequirementsNotMetException extends Error {
|
|
41
|
+
readonly errors: RequirementError[];
|
|
42
|
+
readonly statusCode: number;
|
|
43
|
+
constructor(errors: RequirementError[], statusCode?: number);
|
|
44
|
+
/**
|
|
45
|
+
* Create from API response data.
|
|
46
|
+
*/
|
|
47
|
+
static fromResponse(data: {
|
|
48
|
+
errors?: RequirementError[];
|
|
49
|
+
}, statusCode?: number): RequirementsNotMetException;
|
|
50
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error classes for the inference.sh SDK.
|
|
4
|
+
*
|
|
5
|
+
* Note: types.ts contains interfaces (APIError, RequirementsNotMetError) that describe
|
|
6
|
+
* the API response data shapes. These classes are throwable Error subclasses for SDK use.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.RequirementsNotMetException = exports.InferenceError = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* General HTTP/API error thrown by the SDK.
|
|
12
|
+
*
|
|
13
|
+
* Note: This is distinct from the `APIError` interface in types.ts which describes
|
|
14
|
+
* the error payload shape in API responses.
|
|
15
|
+
*/
|
|
16
|
+
class InferenceError extends Error {
|
|
17
|
+
constructor(statusCode, message, responseBody) {
|
|
18
|
+
super(`HTTP ${statusCode}: ${message}`);
|
|
19
|
+
this.name = 'InferenceError';
|
|
20
|
+
this.statusCode = statusCode;
|
|
21
|
+
this.responseBody = responseBody;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.InferenceError = InferenceError;
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when app requirements (secrets, integrations, scopes) are not met.
|
|
27
|
+
*
|
|
28
|
+
* Thrown for HTTP 412 responses that contain structured requirement errors.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* try {
|
|
33
|
+
* const task = await client.run(params);
|
|
34
|
+
* } catch (e) {
|
|
35
|
+
* if (e instanceof RequirementsNotMetException) {
|
|
36
|
+
* for (const err of e.errors) {
|
|
37
|
+
* console.log(`Missing ${err.type}: ${err.key}`);
|
|
38
|
+
* if (err.action) {
|
|
39
|
+
* console.log(` Fix: ${err.action.type}`);
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
class RequirementsNotMetException extends Error {
|
|
47
|
+
constructor(errors, statusCode = 412) {
|
|
48
|
+
const message = errors.length > 0 ? errors[0].message : 'requirements not met';
|
|
49
|
+
super(message);
|
|
50
|
+
this.name = 'RequirementsNotMetException';
|
|
51
|
+
this.errors = errors;
|
|
52
|
+
this.statusCode = statusCode;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create from API response data.
|
|
56
|
+
*/
|
|
57
|
+
static fromResponse(data, statusCode = 412) {
|
|
58
|
+
return new RequirementsNotMetException(data.errors || [], statusCode);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.RequirementsNotMetException = RequirementsNotMetException;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export { Inference, inference, InferenceConfig, RunOptions, UploadFileOptions } from './client';
|
|
1
|
+
export { Inference, inference, InferenceConfig, RunOptions, UploadFileOptions, Agent, AdHocAgentConfig, SendMessageOptions, } from './client';
|
|
2
|
+
export { AgentConfig, AdHocAgentOptions, TemplateAgentOptions, AgentOptions, } from './agent';
|
|
3
|
+
export { tool, appTool, agentTool, webhookTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional } from './tool-builder';
|
|
2
4
|
export { StreamManager, PartialDataWrapper } from './stream';
|
|
5
|
+
export { InferenceError, RequirementsNotMetException } from './errors';
|
|
3
6
|
export * from './types';
|
|
4
7
|
export type { TaskDTO as Task } from './types';
|
package/dist/index.js
CHANGED
|
@@ -14,13 +14,33 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.StreamManager = exports.inference = exports.Inference = void 0;
|
|
18
|
-
// Main client export
|
|
17
|
+
exports.RequirementsNotMetException = exports.InferenceError = exports.StreamManager = exports.optional = exports.array = exports.object = exports.enumOf = exports.boolean = exports.integer = exports.number = exports.string = exports.internalTools = exports.webhookTool = exports.agentTool = exports.appTool = exports.tool = exports.Agent = exports.inference = exports.Inference = void 0;
|
|
18
|
+
// Main client export (includes Agent)
|
|
19
19
|
var client_1 = require("./client");
|
|
20
20
|
Object.defineProperty(exports, "Inference", { enumerable: true, get: function () { return client_1.Inference; } });
|
|
21
21
|
Object.defineProperty(exports, "inference", { enumerable: true, get: function () { return client_1.inference; } });
|
|
22
|
+
Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return client_1.Agent; } });
|
|
23
|
+
// Tool Builder (fluent API)
|
|
24
|
+
var tool_builder_1 = require("./tool-builder");
|
|
25
|
+
Object.defineProperty(exports, "tool", { enumerable: true, get: function () { return tool_builder_1.tool; } });
|
|
26
|
+
Object.defineProperty(exports, "appTool", { enumerable: true, get: function () { return tool_builder_1.appTool; } });
|
|
27
|
+
Object.defineProperty(exports, "agentTool", { enumerable: true, get: function () { return tool_builder_1.agentTool; } });
|
|
28
|
+
Object.defineProperty(exports, "webhookTool", { enumerable: true, get: function () { return tool_builder_1.webhookTool; } });
|
|
29
|
+
Object.defineProperty(exports, "internalTools", { enumerable: true, get: function () { return tool_builder_1.internalTools; } });
|
|
30
|
+
Object.defineProperty(exports, "string", { enumerable: true, get: function () { return tool_builder_1.string; } });
|
|
31
|
+
Object.defineProperty(exports, "number", { enumerable: true, get: function () { return tool_builder_1.number; } });
|
|
32
|
+
Object.defineProperty(exports, "integer", { enumerable: true, get: function () { return tool_builder_1.integer; } });
|
|
33
|
+
Object.defineProperty(exports, "boolean", { enumerable: true, get: function () { return tool_builder_1.boolean; } });
|
|
34
|
+
Object.defineProperty(exports, "enumOf", { enumerable: true, get: function () { return tool_builder_1.enumOf; } });
|
|
35
|
+
Object.defineProperty(exports, "object", { enumerable: true, get: function () { return tool_builder_1.object; } });
|
|
36
|
+
Object.defineProperty(exports, "array", { enumerable: true, get: function () { return tool_builder_1.array; } });
|
|
37
|
+
Object.defineProperty(exports, "optional", { enumerable: true, get: function () { return tool_builder_1.optional; } });
|
|
22
38
|
// Stream utilities
|
|
23
39
|
var stream_1 = require("./stream");
|
|
24
40
|
Object.defineProperty(exports, "StreamManager", { enumerable: true, get: function () { return stream_1.StreamManager; } });
|
|
41
|
+
// Error classes (throwable)
|
|
42
|
+
var errors_1 = require("./errors");
|
|
43
|
+
Object.defineProperty(exports, "InferenceError", { enumerable: true, get: function () { return errors_1.InferenceError; } });
|
|
44
|
+
Object.defineProperty(exports, "RequirementsNotMetException", { enumerable: true, get: function () { return errors_1.RequirementsNotMetException; } });
|
|
25
45
|
// Types - includes TaskStatus constants and all DTOs
|
|
26
46
|
__exportStar(require("./types"), exports);
|
package/dist/stream.d.ts
CHANGED
|
@@ -24,7 +24,15 @@ export declare class StreamManager<T> {
|
|
|
24
24
|
private initialConnectionAttempts;
|
|
25
25
|
private isConnected;
|
|
26
26
|
private isStopped;
|
|
27
|
+
private eventListeners;
|
|
27
28
|
constructor(options: StreamManagerOptions<T>);
|
|
29
|
+
/**
|
|
30
|
+
* Add a listener for typed SSE events (e.g., 'chats', 'chat_messages')
|
|
31
|
+
* Used when server sends events with `event: eventName` header
|
|
32
|
+
*/
|
|
33
|
+
addEventListener<E = unknown>(eventName: string, callback: (data: E) => void): () => void;
|
|
34
|
+
private setupEventListener;
|
|
35
|
+
private setupAllEventListeners;
|
|
28
36
|
private clearTimeouts;
|
|
29
37
|
private closeEventSource;
|
|
30
38
|
private cleanup;
|