@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 CHANGED
@@ -24,11 +24,9 @@ Get your API key from the [inference.sh dashboard](https://app.inference.sh/sett
24
24
  ## Quick Start
25
25
 
26
26
  ```typescript
27
- import { Inference, TaskStatusCompleted } from '@inferencesh/sdk';
27
+ import { inference } from '@inferencesh/sdk';
28
28
 
29
- const client = new Inference({
30
- apiKey: 'your-api-key'
31
- });
29
+ const client = inference({ apiKey: 'your-api-key' });
32
30
 
33
31
  // Run a task and wait for the result
34
32
  const result = await client.run({
@@ -46,9 +44,9 @@ console.log(result.output);
46
44
  ### Basic Usage
47
45
 
48
46
  ```typescript
49
- import { Inference } from '@inferencesh/sdk';
47
+ import { inference } from '@inferencesh/sdk';
50
48
 
51
- const client = new Inference({ apiKey: 'your-api-key' });
49
+ const client = inference({ apiKey: 'your-api-key' });
52
50
 
53
51
  // Wait for result (default behavior)
54
52
  const result = await client.run({
@@ -59,6 +57,18 @@ const result = await client.run({
59
57
  console.log('Output:', result.output);
60
58
  ```
61
59
 
60
+ ### With Setup Parameters
61
+
62
+ Setup parameters configure the app instance (e.g., model selection). Workers with matching setup are "warm" and skip setup:
63
+
64
+ ```typescript
65
+ const result = await client.run({
66
+ app: 'my-app',
67
+ setup: { model: 'schnell' }, // Setup parameters
68
+ input: { prompt: 'hello' }
69
+ });
70
+ ```
71
+
62
72
  ### Fire and Forget
63
73
 
64
74
  ```typescript
@@ -135,11 +145,90 @@ const task = await client.run(
135
145
  await client.cancel(task.id);
136
146
  ```
137
147
 
148
+ ## Agent Chat
149
+
150
+ Chat with AI agents using `client.agent()`.
151
+
152
+ ### Using a Template Agent
153
+
154
+ Use an existing agent from your workspace by its `namespace/name@shortid`:
155
+
156
+ ```typescript
157
+ import { inference } from '@inferencesh/sdk';
158
+
159
+ const client = inference({ apiKey: 'your-api-key' });
160
+
161
+ // Create agent from template
162
+ const agent = client.agent('my-org/assistant@abc123');
163
+
164
+ // Send a message with streaming
165
+ await agent.sendMessage('Hello!', {
166
+ onMessage: (msg) => {
167
+ if (msg.content) {
168
+ for (const c of msg.content) {
169
+ if (c.type === 'text' && c.text) {
170
+ process.stdout.write(c.text);
171
+ }
172
+ }
173
+ }
174
+ }
175
+ });
176
+
177
+ // Clean up
178
+ agent.disconnect();
179
+ ```
180
+
181
+ ### Creating an Ad-Hoc Agent
182
+
183
+ Create agents on-the-fly without saving to your workspace:
184
+
185
+ ```typescript
186
+ import { inference, tool, string } from '@inferencesh/sdk';
187
+
188
+ const client = inference({ apiKey: 'your-api-key' });
189
+
190
+ // Create ad-hoc agent
191
+ const agent = client.agent({
192
+ coreApp: 'infsh/claude-sonnet-4@abc123', // LLM to use
193
+ systemPrompt: 'You are a helpful assistant.',
194
+ tools: [
195
+ tool('get_weather')
196
+ .description('Get current weather')
197
+ .params({ city: string('City name') })
198
+ .handler(async (args) => {
199
+ // Your tool logic here
200
+ return JSON.stringify({ temp: 72, conditions: 'sunny' });
201
+ })
202
+ .build()
203
+ ]
204
+ });
205
+
206
+ await agent.sendMessage('What is the weather in Paris?', {
207
+ onMessage: (msg) => console.log(msg),
208
+ onToolCall: async (call) => {
209
+ // Tool handlers are auto-executed if defined
210
+ }
211
+ });
212
+ ```
213
+
214
+ ### Agent Methods
215
+
216
+ | Method | Description |
217
+ |--------|-------------|
218
+ | `sendMessage(text, options?)` | Send a message to the agent |
219
+ | `getChat(chatId?)` | Get chat history |
220
+ | `stopChat(chatId?)` | Stop current generation |
221
+ | `submitToolResult(toolId, result)` | Submit result for a client tool |
222
+ | `streamMessages(chatId?, options?)` | Stream message updates |
223
+ | `streamChat(chatId?, options?)` | Stream chat updates |
224
+ | `disconnect()` | Clean up streams |
225
+ | `reset()` | Start a new conversation |
226
+
138
227
  ## API Reference
139
228
 
140
- ### `new Inference(config)`
229
+ ### `inference(config)`
141
230
 
142
- Creates a new Inference client.
231
+ Creates a new inference client.
143
232
 
144
233
  | Parameter | Type | Required | Description |
145
234
  |-----------|------|----------|-------------|
@@ -156,6 +245,7 @@ Runs a task on inference.sh.
156
245
  |-----------|------|----------|-------------|
157
246
  | `params.app` | `string` | Yes | App identifier (e.g., `'username/app-name'`) |
158
247
  | `params.input` | `object` | Yes | Input parameters for the app |
248
+ | `params.setup` | `object` | No | Setup parameters (affects worker warmth/scheduling) |
159
249
  | `params.infra` | `string` | No | Infrastructure: `'cloud'` or `'private'` |
160
250
  | `params.variant` | `string` | No | App variant to use |
161
251
 
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Headless Agent SDK
3
+ *
4
+ * Chat with AI agents without UI dependencies.
5
+ */
6
+ import { ChatDTO, ChatMessageDTO, AgentTool, InternalToolsConfig } from './types';
7
+ export interface AgentConfig {
8
+ apiKey: string;
9
+ baseUrl?: string;
10
+ }
11
+ /** Ad-hoc agent configuration (no saved template) */
12
+ export interface AdHocAgentOptions {
13
+ /** Core LLM app: namespace/name@shortid */
14
+ coreApp: string;
15
+ /** LLM parameters */
16
+ coreAppInput?: Record<string, unknown>;
17
+ /** Agent name */
18
+ name?: string;
19
+ /** System prompt */
20
+ systemPrompt?: string;
21
+ /** Tools */
22
+ tools?: AgentTool[];
23
+ /** Internal tools config */
24
+ internalTools?: InternalToolsConfig;
25
+ }
26
+ /** Template agent configuration */
27
+ export interface TemplateAgentOptions {
28
+ /** Agent reference: namespace/name@version (e.g., "my-org/assistant@abc123") */
29
+ agent: string;
30
+ }
31
+ export type AgentOptions = AdHocAgentOptions | TemplateAgentOptions;
32
+ export interface SendMessageOptions {
33
+ /** File attachments (Blob or base64 data URI) */
34
+ files?: (Blob | string)[];
35
+ /** Callback for message updates */
36
+ onMessage?: (message: ChatMessageDTO) => void;
37
+ /** Callback for chat updates */
38
+ onChat?: (chat: ChatDTO) => void;
39
+ /** Callback when a client tool needs execution */
40
+ onToolCall?: (invocation: {
41
+ id: string;
42
+ name: string;
43
+ args: Record<string, unknown>;
44
+ }) => void;
45
+ }
46
+ export declare class Agent {
47
+ private readonly apiKey;
48
+ private readonly baseUrl;
49
+ private readonly options;
50
+ private chatId;
51
+ private stream;
52
+ constructor(config: AgentConfig, options: AgentOptions);
53
+ /** Get current chat ID */
54
+ get currentChatId(): string | null;
55
+ /** Send a message to the agent */
56
+ sendMessage(text: string, options?: SendMessageOptions): Promise<ChatMessageDTO>;
57
+ /** Get chat by ID */
58
+ getChat(chatId?: string): Promise<ChatDTO | null>;
59
+ /** Stop the current chat generation */
60
+ stopChat(): Promise<void>;
61
+ /** Submit a tool result */
62
+ submitToolResult(toolInvocationId: string, result: string): Promise<void>;
63
+ /** Stop streaming and cleanup */
64
+ disconnect(): void;
65
+ /** Reset the agent (start fresh chat) */
66
+ reset(): void;
67
+ /** Upload a file and return the file object */
68
+ uploadFile(data: Blob | string): Promise<{
69
+ uri: string;
70
+ content_type?: string;
71
+ }>;
72
+ private startStreaming;
73
+ private createEventSource;
74
+ private request;
75
+ }
package/dist/agent.js ADDED
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ /**
3
+ * Headless Agent SDK
4
+ *
5
+ * Chat with AI agents without UI dependencies.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Agent = void 0;
9
+ const stream_1 = require("./stream");
10
+ const eventsource_1 = require("eventsource");
11
+ const types_1 = require("./types");
12
+ // =============================================================================
13
+ // Agent Class
14
+ // =============================================================================
15
+ class Agent {
16
+ constructor(config, options) {
17
+ this.chatId = null;
18
+ // Unified stream for both Chat and ChatMessage events (uses TypedEvents)
19
+ this.stream = null;
20
+ this.apiKey = config.apiKey;
21
+ this.baseUrl = config.baseUrl || 'https://api.inference.sh';
22
+ this.options = options;
23
+ }
24
+ /** Get current chat ID */
25
+ get currentChatId() {
26
+ return this.chatId;
27
+ }
28
+ /** Send a message to the agent */
29
+ async sendMessage(text, options = {}) {
30
+ const isAdHoc = 'coreApp' in this.options;
31
+ // Upload files if provided
32
+ let imageUri;
33
+ let fileUris;
34
+ if (options.files && options.files.length > 0) {
35
+ const uploadedFiles = await Promise.all(options.files.map(f => this.uploadFile(f)));
36
+ // Separate images from other files
37
+ const images = uploadedFiles.filter(f => f.content_type?.startsWith('image/'));
38
+ const others = uploadedFiles.filter(f => !f.content_type?.startsWith('image/'));
39
+ if (images.length > 0)
40
+ imageUri = images[0].uri;
41
+ if (others.length > 0)
42
+ fileUris = others.map(f => f.uri);
43
+ }
44
+ // Both template and ad-hoc use /agents/run
45
+ const body = isAdHoc
46
+ ? {
47
+ chat_id: this.chatId,
48
+ core_app: this.options.coreApp,
49
+ core_app_input: this.options.coreAppInput,
50
+ name: this.options.name,
51
+ system_prompt: this.options.systemPrompt,
52
+ tools: this.options.tools,
53
+ internal_tools: this.options.internalTools,
54
+ input: { text, image: imageUri, files: fileUris, role: 'user', context: [], system_prompt: '', context_size: 0 },
55
+ }
56
+ : {
57
+ chat_id: this.chatId,
58
+ agent: this.options.agent,
59
+ input: { text, image: imageUri, files: fileUris, role: 'user', context: [], system_prompt: '', context_size: 0 },
60
+ };
61
+ const response = await this.request('post', '/agents/run', { data: body });
62
+ // Update chat ID if new
63
+ if (!this.chatId && response.assistant_message.chat_id) {
64
+ this.chatId = response.assistant_message.chat_id;
65
+ this.startStreaming(options);
66
+ }
67
+ return response.assistant_message;
68
+ }
69
+ /** Get chat by ID */
70
+ async getChat(chatId) {
71
+ const id = chatId || this.chatId;
72
+ if (!id)
73
+ return null;
74
+ return this.request('get', `/chats/${id}`);
75
+ }
76
+ /** Stop the current chat generation */
77
+ async stopChat() {
78
+ if (!this.chatId)
79
+ return;
80
+ await this.request('post', `/chats/${this.chatId}/stop`);
81
+ }
82
+ /** Submit a tool result */
83
+ async submitToolResult(toolInvocationId, result) {
84
+ if (!this.chatId)
85
+ throw new Error('No active chat');
86
+ await this.request('post', `/chats/${this.chatId}/tool-result`, {
87
+ data: { tool_invocation_id: toolInvocationId, result },
88
+ });
89
+ }
90
+ /** Stop streaming and cleanup */
91
+ disconnect() {
92
+ this.stream?.stop();
93
+ this.stream = null;
94
+ }
95
+ /** Reset the agent (start fresh chat) */
96
+ reset() {
97
+ this.disconnect();
98
+ this.chatId = null;
99
+ }
100
+ /** Upload a file and return the file object */
101
+ async uploadFile(data) {
102
+ // Create file record
103
+ let contentType = 'application/octet-stream';
104
+ let size;
105
+ if (data instanceof Blob) {
106
+ contentType = data.type || 'application/octet-stream';
107
+ size = data.size;
108
+ }
109
+ const files = await this.request('post', '/files', { data: { files: [{ uri: '', content_type: contentType, size }] } });
110
+ const file = files[0];
111
+ if (!file.upload_url)
112
+ throw new Error('No upload URL');
113
+ // Convert to blob if needed
114
+ let blob;
115
+ if (data instanceof Blob) {
116
+ blob = data;
117
+ }
118
+ else if (data.startsWith('data:')) {
119
+ const matches = data.match(/^data:([^;]+);base64,(.+)$/);
120
+ if (!matches)
121
+ throw new Error('Invalid data URI');
122
+ const bytes = Uint8Array.from(atob(matches[2]), c => c.charCodeAt(0));
123
+ blob = new Blob([bytes], { type: matches[1] });
124
+ }
125
+ else {
126
+ const bytes = Uint8Array.from(atob(data), c => c.charCodeAt(0));
127
+ blob = new Blob([bytes], { type: contentType });
128
+ }
129
+ // Upload to signed URL
130
+ const uploadResp = await fetch(file.upload_url, {
131
+ method: 'PUT',
132
+ body: blob,
133
+ headers: { 'Content-Type': blob.type },
134
+ });
135
+ if (!uploadResp.ok)
136
+ throw new Error('Upload failed');
137
+ return { uri: file.uri, content_type: file.content_type };
138
+ }
139
+ // =============================================================================
140
+ // Private Methods
141
+ // =============================================================================
142
+ startStreaming(options) {
143
+ if (!this.chatId)
144
+ return;
145
+ // Unified stream with TypedEvents (single SSE connection for both Chat and ChatMessage)
146
+ this.stream = new stream_1.StreamManager({
147
+ createEventSource: async () => this.createEventSource(`/chats/${this.chatId}/stream`),
148
+ autoReconnect: true,
149
+ });
150
+ // Listen for Chat object updates (status changes)
151
+ this.stream.addEventListener('chats', (chat) => {
152
+ options.onChat?.(chat);
153
+ });
154
+ // Listen for ChatMessage updates
155
+ this.stream.addEventListener('chat_messages', (message) => {
156
+ options.onMessage?.(message);
157
+ // Check for client tool invocations
158
+ if (message.tool_invocations && options.onToolCall) {
159
+ for (const inv of message.tool_invocations) {
160
+ if (inv.type === types_1.ToolTypeClient && inv.status === types_1.ToolInvocationStatusAwaitingInput) {
161
+ options.onToolCall({
162
+ id: inv.id,
163
+ name: inv.function?.name || '',
164
+ args: inv.function?.arguments || {},
165
+ });
166
+ }
167
+ }
168
+ }
169
+ });
170
+ this.stream.connect();
171
+ }
172
+ createEventSource(endpoint) {
173
+ return new eventsource_1.EventSource(`${this.baseUrl}${endpoint}`, {
174
+ fetch: (input, init) => fetch(input, {
175
+ ...init,
176
+ headers: { ...init.headers, Authorization: `Bearer ${this.apiKey}` },
177
+ }),
178
+ });
179
+ }
180
+ async request(method, endpoint, options = {}) {
181
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
182
+ method: method.toUpperCase(),
183
+ headers: {
184
+ 'Content-Type': 'application/json',
185
+ Authorization: `Bearer ${this.apiKey}`,
186
+ },
187
+ body: options.data ? JSON.stringify(options.data) : undefined,
188
+ });
189
+ const json = await response.json();
190
+ if (!response.ok || !json.success) {
191
+ throw new Error(json.error?.message || 'Request failed');
192
+ }
193
+ return json.data;
194
+ }
195
+ }
196
+ exports.Agent = Agent;
package/dist/client.d.ts CHANGED
@@ -1,4 +1,34 @@
1
- import { ApiTaskRequest, TaskDTO as Task, File } from './types';
1
+ import { ApiAppRunRequest, TaskDTO as Task, File, ChatDTO, ChatMessageDTO, AgentTool, InternalToolsConfig } from './types';
2
+ import { EventSource } from 'eventsource';
3
+ /** Ad-hoc agent configuration (no saved template) */
4
+ export interface AdHocAgentConfig {
5
+ /** Core LLM app: namespace/name@shortid */
6
+ coreApp: string;
7
+ /** LLM parameters */
8
+ coreAppInput?: Record<string, unknown>;
9
+ /** Agent name */
10
+ name?: string;
11
+ /** System prompt */
12
+ systemPrompt?: string;
13
+ /** Tools */
14
+ tools?: AgentTool[];
15
+ /** Internal tools config */
16
+ internalTools?: InternalToolsConfig;
17
+ }
18
+ export interface SendMessageOptions {
19
+ /** File attachments (Blob or base64 data URI) */
20
+ files?: (Blob | string)[];
21
+ /** Callback for message updates */
22
+ onMessage?: (message: ChatMessageDTO) => void;
23
+ /** Callback for chat updates */
24
+ onChat?: (chat: ChatDTO) => void;
25
+ /** Callback when a client tool needs execution */
26
+ onToolCall?: (invocation: {
27
+ id: string;
28
+ name: string;
29
+ args: Record<string, unknown>;
30
+ }) => void;
31
+ }
2
32
  export interface UploadFileOptions {
3
33
  filename?: string;
4
34
  contentType?: string;
@@ -38,8 +68,13 @@ export declare class Inference {
38
68
  private readonly apiKey;
39
69
  private readonly baseUrl;
40
70
  constructor(config: InferenceConfig);
41
- private request;
42
- private createEventSource;
71
+ /** @internal */
72
+ _request<T>(method: "get" | "post" | "put" | "delete", endpoint: string, options?: {
73
+ params?: Record<string, any>;
74
+ data?: Record<string, any>;
75
+ }): Promise<T>;
76
+ /** @internal */
77
+ _createEventSource(endpoint: string): EventSource;
43
78
  private _stripTask;
44
79
  private processInputData;
45
80
  /**
@@ -49,22 +84,33 @@ export declare class Inference {
49
84
  * @param options - Run options for waiting, updates, and reconnection
50
85
  * @returns The completed task result
51
86
  *
87
+ * App reference format: `namespace/name@shortid` (version is required)
88
+ *
89
+ * The short ID ensures your code always runs the same version,
90
+ * protecting against breaking changes from app updates.
91
+ *
52
92
  * @example
53
93
  * ```typescript
54
- * // Simple usage - wait for result
55
- * const result = await client.run({ app: 'my-app', input: { prompt: 'hello' } });
94
+ * // Run a specific version (required)
95
+ * const result = await client.run({
96
+ * app: 'okaris/flux@abc1', // version @abc1 is pinned
97
+ * input: { prompt: 'hello' }
98
+ * });
56
99
  *
57
100
  * // With status updates
58
101
  * const result = await client.run(
59
- * { app: 'my-app', input: { prompt: 'hello' } },
102
+ * { app: 'okaris/flux@abc1', input: { prompt: 'hello' } },
60
103
  * { onUpdate: (update) => console.log(update.status) }
61
104
  * );
62
105
  *
63
106
  * // Fire and forget
64
- * const task = await client.run({ app: 'my-app', input: {} }, { wait: false });
107
+ * const task = await client.run(
108
+ * { app: 'okaris/flux@abc1', input: {} },
109
+ * { wait: false }
110
+ * );
65
111
  * ```
66
112
  */
67
- run(params: ApiTaskRequest, options?: RunOptions): Promise<Task>;
113
+ run(params: ApiAppRunRequest, options?: RunOptions): Promise<Task>;
68
114
  uploadFile(data: string | Blob, options?: UploadFileOptions): Promise<File>;
69
115
  /**
70
116
  * Cancel a running task
@@ -72,8 +118,63 @@ export declare class Inference {
72
118
  * @param taskId - The ID of the task to cancel
73
119
  */
74
120
  cancel(taskId: string): Promise<void>;
121
+ /**
122
+ * Create an agent for chat interactions
123
+ *
124
+ * @param config - Either a template reference string (namespace/name@version) or ad-hoc config
125
+ * @returns An Agent instance for chat operations
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * // Template agent
130
+ * const agent = client.agent('okaris/assistant@abc123')
131
+ *
132
+ * // Ad-hoc agent
133
+ * const agent = client.agent({
134
+ * coreApp: 'infsh/claude-sonnet-4@xyz789',
135
+ * systemPrompt: 'You are a helpful assistant',
136
+ * tools: [...]
137
+ * })
138
+ *
139
+ * // Send messages
140
+ * const response = await agent.sendMessage('Hello!')
141
+ * ```
142
+ */
143
+ agent(config: string | AdHocAgentConfig): Agent;
144
+ }
145
+ /**
146
+ * Agent for chat interactions
147
+ *
148
+ * Created via `client.agent()` - do not instantiate directly.
149
+ */
150
+ export declare class Agent {
151
+ private readonly client;
152
+ private readonly config;
153
+ private chatId;
154
+ private stream;
155
+ /** @internal */
156
+ constructor(client: Inference, config: string | AdHocAgentConfig);
157
+ /** Get current chat ID */
158
+ get currentChatId(): string | null;
159
+ /** Send a message to the agent */
160
+ sendMessage(text: string, options?: SendMessageOptions): Promise<ChatMessageDTO>;
161
+ /** Get chat by ID */
162
+ getChat(chatId?: string): Promise<ChatDTO | null>;
163
+ /** Stop the current chat generation */
164
+ stopChat(): Promise<void>;
165
+ /** Submit a tool result */
166
+ submitToolResult(toolInvocationId: string, result: string): Promise<void>;
167
+ /** Stop streaming and cleanup */
168
+ disconnect(): void;
169
+ /** Reset the agent (start fresh chat) */
170
+ reset(): void;
171
+ private startStreaming;
75
172
  }
76
173
  /**
77
- * @deprecated Use `Inference` instead. Will be removed in v1.0.0
174
+ * Factory function for creating an Inference client (lowercase for branding)
175
+ * @example
176
+ * ```typescript
177
+ * const client = inference({ apiKey: 'your-api-key' });
178
+ * ```
78
179
  */
79
- export declare const inference: typeof Inference;
180
+ export declare function inference(config: InferenceConfig): Inference;