@inferencesh/sdk 0.6.30 → 0.6.47

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 (53) hide show
  1. package/README.md +35 -0
  2. package/dist/agent/actions.js +72 -13
  3. package/dist/agent/api.d.ts +30 -51
  4. package/dist/agent/api.js +129 -154
  5. package/dist/agent/provider.js +18 -1
  6. package/dist/agent/reducer.js +50 -11
  7. package/dist/agent/types.d.ts +34 -1
  8. package/dist/api/agents.d.ts +23 -14
  9. package/dist/api/agents.js +22 -4
  10. package/dist/api/api-keys.d.ts +4 -3
  11. package/dist/api/apps.d.ts +16 -15
  12. package/dist/api/chats.d.ts +14 -9
  13. package/dist/api/chats.js +6 -0
  14. package/dist/api/engines.d.ts +14 -13
  15. package/dist/api/files.d.ts +4 -3
  16. package/dist/api/files.js +2 -2
  17. package/dist/api/flow-runs.d.ts +8 -7
  18. package/dist/api/flows.d.ts +11 -10
  19. package/dist/api/integrations.d.ts +9 -8
  20. package/dist/api/integrations.js +8 -8
  21. package/dist/api/knowledge.d.ts +25 -24
  22. package/dist/api/mcp-servers.d.ts +10 -9
  23. package/dist/api/projects.d.ts +6 -5
  24. package/dist/api/search.d.ts +3 -2
  25. package/dist/api/secrets.d.ts +6 -5
  26. package/dist/api/sessions.d.ts +5 -4
  27. package/dist/api/sessions.js +2 -3
  28. package/dist/api/tasks.d.ts +14 -11
  29. package/dist/api/tasks.js +10 -4
  30. package/dist/api/teams.d.ts +16 -17
  31. package/dist/delta.d.ts +15 -0
  32. package/dist/delta.js +84 -0
  33. package/dist/hook-builder.d.ts +23 -0
  34. package/dist/hook-builder.js +50 -0
  35. package/dist/http/client.d.ts +9 -1
  36. package/dist/http/client.js +12 -3
  37. package/dist/http/response.d.ts +9 -0
  38. package/dist/http/response.js +1 -0
  39. package/dist/http/stream.d.ts +1 -0
  40. package/dist/http/stream.js +8 -3
  41. package/dist/http/streamable.d.ts +3 -1
  42. package/dist/http/streamable.js +10 -1
  43. package/dist/index.d.ts +11 -5
  44. package/dist/index.js +6 -1
  45. package/dist/proxy/index.d.ts +2 -0
  46. package/dist/proxy/index.js +9 -0
  47. package/dist/tool-builder.d.ts +2 -0
  48. package/dist/tool-builder.js +5 -0
  49. package/dist/types.d.ts +1041 -157
  50. package/dist/types.js +230 -30
  51. package/dist/utils.d.ts +13 -0
  52. package/dist/utils.js +43 -3
  53. package/package.json +8 -5
@@ -1,4 +1,5 @@
1
1
  import { HttpClient } from '../http/client';
2
+ import type { Response } from '../http/response';
2
3
  import { TaskDTO as Task, TaskLogsDTO, TaskTimingsDTO, ApiAppRunRequest, CursorListRequest, CursorListResponse } from '../types';
3
4
  export interface RunOptions {
4
5
  /** Callback for real-time status updates */
@@ -13,6 +14,8 @@ export interface RunOptions {
13
14
  stream?: boolean;
14
15
  /** Polling interval in ms when stream is false. Overrides client default. */
15
16
  pollIntervalMs?: number;
17
+ /** Callback for streaming delta events (token-by-token updates) */
18
+ onDelta?: (delta: Record<string, any>, seq: number) => void;
16
19
  }
17
20
  /**
18
21
  * Tasks API
@@ -23,27 +26,27 @@ export declare class TasksAPI {
23
26
  /**
24
27
  * List tasks with cursor-based pagination
25
28
  */
26
- list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<Task>>;
29
+ list(params?: Partial<CursorListRequest>): Promise<Response<CursorListResponse<Task>>>;
27
30
  /**
28
31
  * List featured tasks with cursor-based pagination
29
32
  */
30
- listFeatured(params?: Partial<CursorListRequest>): Promise<CursorListResponse<Task>>;
33
+ listFeatured(params?: Partial<CursorListRequest>): Promise<Response<CursorListResponse<Task>>>;
31
34
  /**
32
35
  * Get a task by ID
33
36
  */
34
- get(taskId: string): Promise<Task>;
37
+ get(taskId: string): Promise<Response<Task>>;
35
38
  /**
36
39
  * Create and run a task
37
40
  */
38
- create(data: ApiAppRunRequest): Promise<Task>;
41
+ create(data: ApiAppRunRequest): Promise<Response<Task>>;
39
42
  /**
40
43
  * Delete a task
41
44
  */
42
- delete(taskId: string): Promise<void>;
45
+ delete(taskId: string): Promise<Response<void>>;
43
46
  /**
44
47
  * Cancel a running task
45
48
  */
46
- cancel(taskId: string): Promise<void>;
49
+ cancel(taskId: string): Promise<Response<void>>;
47
50
  /**
48
51
  * Create an EventSource for streaming task updates
49
52
  */
@@ -57,22 +60,22 @@ export declare class TasksAPI {
57
60
  /**
58
61
  * Update task visibility
59
62
  */
60
- updateVisibility(taskId: string, visibility: string): Promise<Task>;
63
+ updateVisibility(taskId: string, visibility: string): Promise<Response<Task>>;
61
64
  /**
62
65
  * Feature/unfeature a task
63
66
  */
64
- feature(taskId: string, featured: boolean): Promise<Task>;
67
+ feature(taskId: string, featured: boolean): Promise<Response<Task>>;
65
68
  /**
66
69
  * Get task logs
67
70
  */
68
- getLogs(taskId: string): Promise<TaskLogsDTO>;
71
+ getLogs(taskId: string): Promise<Response<TaskLogsDTO>>;
69
72
  /**
70
73
  * Get task timings
71
74
  */
72
- getTimings(taskId: string): Promise<TaskTimingsDTO>;
75
+ getTimings(taskId: string): Promise<Response<TaskTimingsDTO>>;
73
76
  /**
74
77
  * Get task telemetry
75
78
  */
76
- getTelemetry(taskId: string): Promise<Record<string, unknown>[]>;
79
+ getTelemetry(taskId: string): Promise<Response<Record<string, unknown>[]>>;
77
80
  }
78
81
  export declare function createTasksAPI(http: HttpClient): TasksAPI;
package/dist/api/tasks.js CHANGED
@@ -69,13 +69,14 @@ export class TasksAPI {
69
69
  * Run a task and optionally wait for completion
70
70
  */
71
71
  async run(params, processedInput, options = {}) {
72
- const { onUpdate, onPartialUpdate, wait = true, } = options;
73
- const task = await this.http.request('post', '/apps/run', {
72
+ const { onUpdate, onPartialUpdate, onDelta, wait = true, } = options;
73
+ const resp = await this.http.request('post', '/apps/run', {
74
74
  data: {
75
75
  ...params,
76
76
  input: processedInput,
77
77
  },
78
78
  });
79
+ const task = resp.data;
79
80
  // Return immediately if not waiting
80
81
  if (!wait) {
81
82
  return stripTask(task);
@@ -93,6 +94,7 @@ export class TasksAPI {
93
94
  url,
94
95
  headers,
95
96
  credentials,
97
+ onDelta,
96
98
  onData: (data) => {
97
99
  // Merge new data, preserving existing fields if not in update
98
100
  accumulatedTask = { ...accumulatedTask, ...data };
@@ -144,7 +146,10 @@ export class TasksAPI {
144
146
  let prevStatus = task.status;
145
147
  return new Promise((resolve, reject) => {
146
148
  const poller = new PollManager({
147
- pollFunction: () => this.http.request('get', `/tasks/${task.id}/status`),
149
+ pollFunction: async () => {
150
+ const resp = await this.http.request('get', `/tasks/${task.id}/status`);
151
+ return resp.data;
152
+ },
148
153
  intervalMs,
149
154
  maxRetries: maxReconnects,
150
155
  onData: async (statusData) => {
@@ -153,7 +158,8 @@ export class TasksAPI {
153
158
  prevStatus = statusData.status;
154
159
  // Status changed — fetch full task
155
160
  try {
156
- const fullTask = await this.http.request('get', `/tasks/${task.id}`);
161
+ const fullResp = await this.http.request('get', `/tasks/${task.id}`);
162
+ const fullTask = fullResp.data;
157
163
  const stripped = stripTask(fullTask);
158
164
  onUpdate?.(stripped);
159
165
  if (parseStatus(fullTask.status) === TaskStatusCompleted) {
@@ -1,5 +1,6 @@
1
1
  import { HttpClient } from '../http/client';
2
- import { UserDTO, TeamRelationDTO, TeamMemberDTO, TeamInviteDTO, TeamCreateRequest, TeamMemberAddRequest, TeamInviteCreateRequest } from '../types';
2
+ import type { Response } from '../http/response';
3
+ import { UserDTO, TeamRelationDTO, TeamMemberDTO, TeamInviteDTO, TeamCreateRequest, TeamMemberAddRequest, TeamInviteCreateRequest, AvailabilityResponse } from '../types';
3
4
  export interface MeResponse {
4
5
  user: UserDTO;
5
6
  team?: TeamRelationDTO;
@@ -13,59 +14,57 @@ export declare class TeamsAPI {
13
14
  /**
14
15
  * Get current user and team context
15
16
  */
16
- me(): Promise<MeResponse>;
17
+ me(): Promise<Response<MeResponse>>;
17
18
  /**
18
19
  * List user's teams
19
20
  */
20
- list(): Promise<TeamRelationDTO[]>;
21
+ list(): Promise<Response<TeamRelationDTO[]>>;
21
22
  /**
22
23
  * Get a team by ID
23
24
  */
24
- get(teamId: string): Promise<TeamRelationDTO>;
25
+ get(teamId: string): Promise<Response<TeamRelationDTO>>;
25
26
  /**
26
27
  * Create a new team
27
28
  */
28
- create(data: TeamCreateRequest): Promise<TeamRelationDTO>;
29
+ create(data: TeamCreateRequest): Promise<Response<TeamRelationDTO>>;
29
30
  /**
30
31
  * Update a team
31
32
  */
32
- update(teamId: string, data: Partial<TeamCreateRequest>): Promise<TeamRelationDTO>;
33
+ update(teamId: string, data: Partial<TeamCreateRequest>): Promise<Response<TeamRelationDTO>>;
33
34
  /**
34
35
  * Delete a team
35
36
  */
36
- delete(teamId: string): Promise<void>;
37
+ delete(teamId: string): Promise<Response<void>>;
37
38
  /**
38
39
  * Check username availability
39
40
  */
40
- checkUsername(username: string): Promise<{
41
- available: boolean;
42
- }>;
41
+ checkUsername(username: string): Promise<Response<AvailabilityResponse>>;
43
42
  /**
44
43
  * Get team members
45
44
  */
46
- getMembers(teamId: string): Promise<TeamMemberDTO[]>;
45
+ getMembers(teamId: string): Promise<Response<TeamMemberDTO[]>>;
47
46
  /**
48
47
  * Add a team member
49
48
  */
50
- addMember(teamId: string, data: TeamMemberAddRequest): Promise<TeamMemberDTO>;
49
+ addMember(teamId: string, data: TeamMemberAddRequest): Promise<Response<TeamMemberDTO>>;
51
50
  /**
52
51
  * Remove a team member
53
52
  */
54
- removeMember(teamId: string, userId: string): Promise<void>;
53
+ removeMember(teamId: string, userId: string): Promise<Response<void>>;
55
54
  /**
56
55
  * Update a member's role
57
56
  */
58
- updateMemberRole(teamId: string, userId: string, role: string): Promise<TeamMemberDTO>;
57
+ updateMemberRole(teamId: string, userId: string, role: string): Promise<Response<TeamMemberDTO>>;
59
58
  /**
60
59
  * List team invites
61
60
  */
62
- listInvites(teamId: string): Promise<TeamInviteDTO[]>;
61
+ listInvites(teamId: string): Promise<Response<TeamInviteDTO[]>>;
63
62
  /**
64
63
  * Create an invite
65
64
  */
66
- createInvite(teamId: string, data: TeamInviteCreateRequest): Promise<TeamInviteDTO>;
65
+ createInvite(teamId: string, data: TeamInviteCreateRequest): Promise<Response<TeamInviteDTO>>;
67
66
  /**
68
67
  * Revoke an invite
69
68
  */
70
- revokeInvite(teamId: string, inviteId: string): Promise<void>;
69
+ revokeInvite(teamId: string, inviteId: string): Promise<Response<void>>;
71
70
  }
@@ -0,0 +1,15 @@
1
+ export type { DeltaEvent } from './types';
2
+ export type FieldTags = Record<string, {
3
+ merge: string;
4
+ }>;
5
+ export type FieldTagsRegistry = Map<FieldTags, FieldTags>;
6
+ export declare class DeltaAccumulator {
7
+ private state;
8
+ private tags;
9
+ private registry;
10
+ constructor(tags: FieldTags, registry?: FieldTagsRegistry);
11
+ seed(output: Record<string, any>): void;
12
+ apply(delta: Record<string, any>): void;
13
+ toOutput(): Record<string, any>;
14
+ }
15
+ export declare function createLLMDeltaAccumulator(): DeltaAccumulator;
package/dist/delta.js ADDED
@@ -0,0 +1,84 @@
1
+ import { LLMDelta_fieldTags, ToolCallDelta_fieldTags, ToolCallFunctionDelta_fieldTags, MergeStrategyConcat, MergeStrategyIndexed, MergeStrategyNested, MergeStrategyReplace, } from './types';
2
+ function mergeField(current, incoming, strategy, childTags, registry) {
3
+ if (incoming == null)
4
+ return current;
5
+ switch (strategy) {
6
+ case MergeStrategyConcat:
7
+ return (current ?? '') + incoming;
8
+ case MergeStrategyReplace:
9
+ return incoming;
10
+ case MergeStrategyIndexed:
11
+ return mergeIndexed(current, incoming, childTags, registry);
12
+ case MergeStrategyNested:
13
+ return mergeNested(current, incoming, childTags, registry);
14
+ default:
15
+ return incoming;
16
+ }
17
+ }
18
+ function mergeIndexed(current, incoming, itemTags, registry) {
19
+ const byIndex = new Map();
20
+ if (current) {
21
+ for (const item of current)
22
+ byIndex.set(item.index ?? 0, item);
23
+ }
24
+ for (const item of incoming) {
25
+ const idx = item.index ?? 0;
26
+ const existing = byIndex.get(idx);
27
+ if (!existing) {
28
+ byIndex.set(idx, { ...item });
29
+ }
30
+ else {
31
+ byIndex.set(idx, mergeObject(existing, item, itemTags, registry));
32
+ }
33
+ }
34
+ return Array.from(byIndex.entries())
35
+ .sort(([a], [b]) => a - b)
36
+ .map(([_, v]) => v);
37
+ }
38
+ function mergeNested(current, incoming, nestedTags, registry) {
39
+ if (current == null)
40
+ return { ...incoming };
41
+ return mergeObject(current, incoming, nestedTags, registry);
42
+ }
43
+ function mergeObject(current, incoming, tags, registry) {
44
+ const result = { ...current };
45
+ for (const [key, value] of Object.entries(incoming)) {
46
+ if (value == null)
47
+ continue;
48
+ const strategy = tags[key]?.merge ?? MergeStrategyReplace;
49
+ const childTags = registry?.get(tags) ?? {};
50
+ result[key] = mergeField(result[key], value, strategy, childTags, registry);
51
+ }
52
+ return result;
53
+ }
54
+ export class DeltaAccumulator {
55
+ constructor(tags, registry) {
56
+ this.state = {};
57
+ this.tags = tags;
58
+ this.registry = registry;
59
+ }
60
+ seed(output) {
61
+ for (const [key, value] of Object.entries(output)) {
62
+ if (value != null)
63
+ this.state[key] = value;
64
+ }
65
+ }
66
+ apply(delta) {
67
+ for (const [key, value] of Object.entries(delta)) {
68
+ if (value == null)
69
+ continue;
70
+ const strategy = this.tags[key]?.merge ?? MergeStrategyReplace;
71
+ const childTags = this.registry?.get(this.tags) ?? {};
72
+ this.state[key] = mergeField(this.state[key], value, strategy, childTags, this.registry);
73
+ }
74
+ }
75
+ toOutput() {
76
+ return { ...this.state };
77
+ }
78
+ }
79
+ export function createLLMDeltaAccumulator() {
80
+ const registry = new Map();
81
+ registry.set(LLMDelta_fieldTags, ToolCallDelta_fieldTags);
82
+ registry.set(ToolCallDelta_fieldTags, ToolCallFunctionDelta_fieldTags);
83
+ return new DeltaAccumulator(LLMDelta_fieldTags, registry);
84
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Hook Builder - Fluent API for defining lifecycle hooks
3
+ */
4
+ import { LifecycleHookConfig, HookEvent } from './types';
5
+ export declare class LifecycleHookBuilder {
6
+ private event;
7
+ private handlerType;
8
+ private handlerRef;
9
+ private isAsync?;
10
+ private timeoutSeconds?;
11
+ constructor(event: HookEvent);
12
+ /** Set handler to a webhook URL */
13
+ webhook(url: string): this;
14
+ /** Set handler to a task (agent ref) */
15
+ task(agentRef: string): this;
16
+ /** Set async execution */
17
+ async(enabled: boolean): this;
18
+ /** Set handler timeout in seconds */
19
+ timeout(seconds: number): this;
20
+ build(): LifecycleHookConfig;
21
+ }
22
+ /** Create a lifecycle hook for an agent event */
23
+ export declare const lifecycleHook: (event: HookEvent) => LifecycleHookBuilder;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Hook Builder - Fluent API for defining lifecycle hooks
3
+ */
4
+ import { HookHandlerWebhook, HookHandlerTask } from './types';
5
+ // =============================================================================
6
+ // Hook Builder
7
+ // =============================================================================
8
+ export class LifecycleHookBuilder {
9
+ constructor(event) {
10
+ this.handlerType = HookHandlerWebhook;
11
+ this.handlerRef = '';
12
+ this.event = event;
13
+ }
14
+ /** Set handler to a webhook URL */
15
+ webhook(url) {
16
+ this.handlerType = HookHandlerWebhook;
17
+ this.handlerRef = url;
18
+ return this;
19
+ }
20
+ /** Set handler to a task (agent ref) */
21
+ task(agentRef) {
22
+ this.handlerType = HookHandlerTask;
23
+ this.handlerRef = agentRef;
24
+ return this;
25
+ }
26
+ /** Set async execution */
27
+ async(enabled) {
28
+ this.isAsync = enabled;
29
+ return this;
30
+ }
31
+ /** Set handler timeout in seconds */
32
+ timeout(seconds) {
33
+ this.timeoutSeconds = seconds;
34
+ return this;
35
+ }
36
+ build() {
37
+ return {
38
+ event: this.event,
39
+ type: this.handlerType,
40
+ handler: this.handlerRef,
41
+ async: this.isAsync,
42
+ timeout: this.timeoutSeconds,
43
+ };
44
+ }
45
+ }
46
+ // =============================================================================
47
+ // Public API
48
+ // =============================================================================
49
+ /** Create a lifecycle hook for an agent event */
50
+ export const lifecycleHook = (event) => new LifecycleHookBuilder(event);
@@ -1,9 +1,11 @@
1
+ import type { Response } from './response';
1
2
  import { EventSource } from 'eventsource';
2
3
  /**
3
4
  * Error handler that can intercept errors and optionally retry the request.
4
5
  * Return a promise to retry with a new result, or throw/rethrow to propagate the error.
5
6
  */
6
7
  export type ErrorHandler = (error: unknown, retry: () => Promise<unknown>) => Promise<unknown>;
8
+ export type MessageHandler = (messages: import('../types').ResponseMessage[]) => void;
7
9
  export interface HttpClientConfig {
8
10
  /** Your inference.sh API key (required unless using proxyUrl) */
9
11
  apiKey?: string;
@@ -25,6 +27,11 @@ export interface HttpClientConfig {
25
27
  * Can be used for retry logic, auth refresh, OTP handling, etc.
26
28
  */
27
29
  onError?: ErrorHandler;
30
+ /**
31
+ * Callback fired when a successful response includes messages (warnings, info).
32
+ * Use for surfacing concurrency limits, upgrade prompts, deprecation notices, etc.
33
+ */
34
+ onMessage?: MessageHandler;
28
35
  /**
29
36
  * Use polling instead of SSE for real-time updates (default: true = SSE).
30
37
  * Set to false for environments that can't maintain long-lived connections
@@ -50,6 +57,7 @@ export declare class HttpClient {
50
57
  private readonly customHeaders;
51
58
  private readonly credentials;
52
59
  private readonly onError;
60
+ private readonly onMessage;
53
61
  private readonly streamDefault;
54
62
  private readonly pollInterval;
55
63
  constructor(config: HttpClientConfig);
@@ -71,7 +79,7 @@ export declare class HttpClient {
71
79
  request<T, P extends object = Record<string, unknown>>(method: 'get' | 'post' | 'put' | 'delete', endpoint: string, options?: {
72
80
  params?: P;
73
81
  data?: unknown;
74
- }): Promise<T>;
82
+ }): Promise<Response<T>>;
75
83
  /**
76
84
  * Execute the actual HTTP request (internal)
77
85
  */
@@ -16,9 +16,10 @@ export class HttpClient {
16
16
  this.baseUrl = config.baseUrl || 'https://api.inference.sh';
17
17
  this.proxyUrl = config.proxyUrl;
18
18
  this.getToken = config.getToken;
19
- this.customHeaders = { 'X-Client-Source': 'inference-sdk-js/0.5.13', 'X-API-Version': '2', ...config.headers };
19
+ this.customHeaders = { 'X-Client-Source': 'inference-sdk-js/0.5.13', ...config.headers };
20
20
  this.credentials = config.credentials || 'include';
21
21
  this.onError = config.onError;
22
+ this.onMessage = config.onMessage;
22
23
  this.streamDefault = config.stream ?? true;
23
24
  this.pollInterval = config.pollIntervalMs ?? 2000;
24
25
  }
@@ -136,9 +137,17 @@ export class HttpClient {
136
137
  throw new InferenceError(response.status, errorDetail || 'Request failed', responseText);
137
138
  }
138
139
  if (response.status === 204 || !responseText) {
139
- return undefined;
140
+ return { data: undefined, messages: [] };
141
+ }
142
+ // Unwrap V3 envelope: {"data": <dto>, "messages": [...]}
143
+ if (data && typeof data === 'object' && 'data' in data && !Array.isArray(data)) {
144
+ const messages = data.messages ?? [];
145
+ if (this.onMessage && messages.length) {
146
+ this.onMessage(messages);
147
+ }
148
+ return { data: data.data, messages };
140
149
  }
141
- return data;
150
+ return { data: data, messages: [] };
142
151
  }
143
152
  /**
144
153
  * Get URL and headers for NDJSON streaming.
@@ -0,0 +1,9 @@
1
+ import type { ResponseMessage } from '../types';
2
+ /**
3
+ * Response wraps the V3 API envelope — every API call returns this.
4
+ * Access .data for the DTO and .messages for any warnings the server surfaced.
5
+ */
6
+ export interface Response<T> {
7
+ data: T;
8
+ messages: ResponseMessage[];
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -22,6 +22,7 @@ export declare class StreamManager<T> {
22
22
  private reconnectTimeout;
23
23
  private stopTimeout;
24
24
  private initialConnectionAttempts;
25
+ private consecutiveErrors;
25
26
  private isConnected;
26
27
  private isStopped;
27
28
  private eventListeners;
@@ -15,6 +15,7 @@ export class StreamManager {
15
15
  this.reconnectTimeout = null;
16
16
  this.stopTimeout = null;
17
17
  this.initialConnectionAttempts = 0;
18
+ this.consecutiveErrors = 0;
18
19
  this.isConnected = false;
19
20
  this.isStopped = false;
20
21
  this.eventListeners = new Map();
@@ -112,9 +113,11 @@ export class StreamManager {
112
113
  scheduleReconnect() {
113
114
  if (!this.options.autoReconnect || this.isStopped)
114
115
  return false;
115
- // If we had a successful connection before, always reconnect
116
- // Otherwise, check if we've exceeded initial connection attempts
117
- if (!this.isConnected && this.initialConnectionAttempts >= (this.options.maxReconnects ?? 5)) {
116
+ const maxReconnects = this.options.maxReconnects ?? 5;
117
+ if (!this.isConnected && this.initialConnectionAttempts >= maxReconnects) {
118
+ return false;
119
+ }
120
+ if (this.isConnected && this.consecutiveErrors >= maxReconnects) {
118
121
  return false;
119
122
  }
120
123
  this.reconnectTimeout = setTimeout(() => {
@@ -122,6 +125,7 @@ export class StreamManager {
122
125
  if (!this.isConnected) {
123
126
  this.initialConnectionAttempts++;
124
127
  }
128
+ this.consecutiveErrors++;
125
129
  this.connect();
126
130
  }
127
131
  }, this.options.reconnectDelayMs);
@@ -144,6 +148,7 @@ export class StreamManager {
144
148
  source.onmessage = (e) => {
145
149
  if (this.isStopped)
146
150
  return;
151
+ this.consecutiveErrors = 0;
147
152
  try {
148
153
  const parsed = JSON.parse(e.data);
149
154
  // Check if this is a partial data wrapper from the server
@@ -55,6 +55,8 @@ export interface StreamableManagerOptions<T> {
55
55
  onStart?: () => void;
56
56
  /** Called when stream ends */
57
57
  onEnd?: () => void;
58
+ /** Called for delta events (streaming token deltas) */
59
+ onDelta?: (delta: Record<string, any>, seq: number) => void;
58
60
  }
59
61
  export declare class StreamableManager<T> {
60
62
  private options;
@@ -66,7 +68,7 @@ export declare class StreamableManager<T> {
66
68
  * Add a listener for typed events (e.g., 'chats', 'chat_messages').
67
69
  * Used when server sends events with {"event": "eventName", "data": ...} format.
68
70
  */
69
- addEventListener<E = unknown>(eventName: string, callback: (data: E) => void): () => void;
71
+ addEventListener<E = unknown>(eventName: string, callback: (data: E, fields?: string[]) => void): () => void;
70
72
  start(): Promise<void>;
71
73
  stop(): void;
72
74
  }
@@ -118,11 +118,20 @@ export class StreamableManager {
118
118
  if (!this.isRunning)
119
119
  break;
120
120
  const wrapper = message;
121
+ // Handle delta events
122
+ if (wrapper.event === 'delta' && this.options.onDelta) {
123
+ const payload = wrapper.data;
124
+ if (payload && payload.delta) {
125
+ this.options.onDelta(payload.delta, payload.seq);
126
+ }
127
+ continue;
128
+ }
121
129
  // Handle typed events ({"event": "...", "data": ...})
122
130
  if (wrapper.event && this.eventListeners.has(wrapper.event)) {
123
131
  const listeners = this.eventListeners.get(wrapper.event);
124
132
  const eventData = wrapper.data !== undefined ? wrapper.data : message;
125
- listeners.forEach(callback => callback(eventData));
133
+ const fields = wrapper.fields;
134
+ listeners.forEach(callback => callback(eventData, fields));
126
135
  continue;
127
136
  }
128
137
  // Check if it's a partial update
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- export { HttpClient, type HttpClientConfig, type ErrorHandler, createHttpClient } from './http/client';
1
+ export { HttpClient, type HttpClientConfig, type ErrorHandler, type MessageHandler, createHttpClient } from './http/client';
2
+ export type { Response } from './http/response';
3
+ import type { Response } from './http/response';
2
4
  export { StreamManager, type StreamManagerOptions, type PartialDataWrapper } from './http/stream';
3
5
  export { StreamableManager, type StreamableManagerOptions, type StreamableMessage, streamable, streamableRaw } from './http/streamable';
4
6
  export { PollManager, type PollManagerOptions } from './http/poll';
@@ -22,7 +24,11 @@ export { ProjectsAPI } from './api/projects';
22
24
  export { MCPServersAPI } from './api/mcp-servers';
23
25
  export { tool, appTool, agentTool, webhookTool, httpTool, callTool, mcpTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional, } from './tool-builder';
24
26
  export type { ClientTool, ClientToolHandler } from './tool-builder';
25
- export { parseStatus, isTerminalStatus, isChatBusy } from './utils';
27
+ export { lifecycleHook } from './hook-builder';
28
+ export type { LifecycleHookBuilder } from './hook-builder';
29
+ export { DeltaAccumulator, createLLMDeltaAccumulator, type DeltaEvent, type FieldTags, type FieldTagsRegistry } from './delta';
30
+ export { parseStatus, isTerminalStatus, isChatBusy, pendingApprovals } from './utils';
31
+ export type { PendingApproval } from './utils';
26
32
  export * from './types';
27
33
  export type { TaskDTO as Task } from './types';
28
34
  import { HttpClient, type HttpClientConfig } from './http/client';
@@ -98,7 +104,7 @@ export declare class Inference {
98
104
  _request<T>(method: 'get' | 'post' | 'put' | 'delete', endpoint: string, options?: {
99
105
  params?: Record<string, unknown>;
100
106
  data?: Record<string, unknown>;
101
- }): Promise<T>;
107
+ }): Promise<Response<T>>;
102
108
  /** @internal */
103
109
  _createEventSource(endpoint: string): Promise<import("eventsource").EventSource | null>;
104
110
  /**
@@ -112,11 +118,11 @@ export declare class Inference {
112
118
  /**
113
119
  * Cancel a running task
114
120
  */
115
- cancel(taskId: string): Promise<void>;
121
+ cancel(taskId: string): Promise<Response<void>>;
116
122
  /**
117
123
  * Get a task by ID
118
124
  */
119
- getTask(taskId: string): Promise<Task>;
125
+ getTask(taskId: string): Promise<Response<Task>>;
120
126
  /**
121
127
  * Create an EventSource for streaming task updates
122
128
  */
package/dist/index.js CHANGED
@@ -26,8 +26,12 @@ export { ProjectsAPI } from './api/projects';
26
26
  export { MCPServersAPI } from './api/mcp-servers';
27
27
  // Tool Builder (fluent API)
28
28
  export { tool, appTool, agentTool, webhookTool, httpTool, callTool, mcpTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional, } from './tool-builder';
29
+ // Hook Builder (fluent API)
30
+ export { lifecycleHook } from './hook-builder';
31
+ // Delta accumulator for streaming responses
32
+ export { DeltaAccumulator, createLLMDeltaAccumulator } from './delta';
29
33
  // Status utilities (handle both int and string status values)
30
- export { parseStatus, isTerminalStatus, isChatBusy } from './utils';
34
+ export { parseStatus, isTerminalStatus, isChatBusy, pendingApprovals } from './utils';
31
35
  // Types - includes TaskStatus constants and all DTOs
32
36
  export * from './types';
33
37
  // =============================================================================
@@ -71,6 +75,7 @@ export class Inference {
71
75
  headers: 'headers' in config ? config.headers : undefined,
72
76
  credentials: 'credentials' in config ? config.credentials : undefined,
73
77
  onError: 'onError' in config ? config.onError : undefined,
78
+ onMessage: 'onMessage' in config ? config.onMessage : undefined,
74
79
  stream: 'stream' in config ? config.stream : undefined,
75
80
  pollIntervalMs: 'pollIntervalMs' in config ? config.pollIntervalMs : undefined,
76
81
  });
@@ -51,6 +51,8 @@ export interface ProxyAdapter<T> {
51
51
  export interface ProxyOptions {
52
52
  /** Custom API key (defaults to INFERENCE_API_KEY env var) */
53
53
  apiKey?: string;
54
+ /** Override API base URL (defaults to INFERENCE_API_BASE_URL env var) */
55
+ apiBaseUrl?: string;
54
56
  /** Allow requests to additional domains (besides *.inference.sh) */
55
57
  allowedDomains?: RegExp[];
56
58
  }
@@ -73,6 +73,15 @@ export async function processProxyRequest(adapter, options) {
73
73
  error: `Missing ${INF_TARGET_HEADER} header or ${INF_TARGET_PARAM} query param`,
74
74
  });
75
75
  }
76
+ // 1b. Rewrite base URL if INFERENCE_API_BASE_URL is set
77
+ const overrideBase = options?.apiBaseUrl || process.env.INFERENCE_API_BASE_URL;
78
+ if (overrideBase) {
79
+ const parsed = new URL(targetUrl);
80
+ const override = new URL(overrideBase);
81
+ parsed.protocol = override.protocol;
82
+ parsed.host = override.host;
83
+ targetUrl = parsed.toString();
84
+ }
76
85
  // 2. Validate target domain
77
86
  let host;
78
87
  try {
@@ -126,6 +126,8 @@ declare class InternalToolsBuilder {
126
126
  widget(enabled?: boolean): this;
127
127
  /** Enable finish tool - sub-agents only */
128
128
  finish(enabled?: boolean): this;
129
+ /** Enable meta tools */
130
+ meta(enabled?: boolean): this;
129
131
  /** Enable all internal tools */
130
132
  all(): this;
131
133
  /** Disable all internal tools */