@inferencesh/sdk 0.6.14 → 0.6.19

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 (89) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/actions.js +10 -0
  3. package/dist/agent/provider.d.ts +2 -1
  4. package/dist/agent/provider.js +5 -5
  5. package/dist/agent/types.d.ts +3 -0
  6. package/dist/api/apps.d.ts +4 -0
  7. package/dist/api/apps.js +6 -0
  8. package/dist/api/index.d.ts +3 -3
  9. package/dist/http/index.d.ts +3 -3
  10. package/dist/index.d.ts +9 -9
  11. package/dist/types.d.ts +131 -19
  12. package/dist/types.js +26 -9
  13. package/package.json +8 -5
  14. package/dist/agent/actions.test.d.ts +0 -1
  15. package/dist/agent/actions.test.js +0 -820
  16. package/dist/agent/api.test.d.ts +0 -1
  17. package/dist/agent/api.test.js +0 -246
  18. package/dist/agent/reducer.test.d.ts +0 -1
  19. package/dist/agent/reducer.test.js +0 -131
  20. package/dist/agent/types.test.d.ts +0 -1
  21. package/dist/agent/types.test.js +0 -75
  22. package/dist/api/agents.test.d.ts +0 -1
  23. package/dist/api/agents.test.js +0 -1014
  24. package/dist/api/api-keys.test.d.ts +0 -1
  25. package/dist/api/api-keys.test.js +0 -44
  26. package/dist/api/apps.test.d.ts +0 -1
  27. package/dist/api/apps.test.js +0 -135
  28. package/dist/api/chats.test.d.ts +0 -1
  29. package/dist/api/chats.test.js +0 -85
  30. package/dist/api/engines.test.d.ts +0 -1
  31. package/dist/api/engines.test.js +0 -133
  32. package/dist/api/files.test.d.ts +0 -1
  33. package/dist/api/files.test.js +0 -256
  34. package/dist/api/flow-runs.test.d.ts +0 -1
  35. package/dist/api/flow-runs.test.js +0 -97
  36. package/dist/api/flows.test.d.ts +0 -1
  37. package/dist/api/flows.test.js +0 -118
  38. package/dist/api/integrations.test.d.ts +0 -1
  39. package/dist/api/integrations.test.js +0 -109
  40. package/dist/api/knowledge.test.d.ts +0 -1
  41. package/dist/api/knowledge.test.js +0 -238
  42. package/dist/api/mcp-servers.test.d.ts +0 -1
  43. package/dist/api/mcp-servers.test.js +0 -98
  44. package/dist/api/projects.test.d.ts +0 -1
  45. package/dist/api/projects.test.js +0 -61
  46. package/dist/api/search.test.d.ts +0 -1
  47. package/dist/api/search.test.js +0 -50
  48. package/dist/api/secrets.test.d.ts +0 -1
  49. package/dist/api/secrets.test.js +0 -61
  50. package/dist/api/sessions.test.d.ts +0 -1
  51. package/dist/api/sessions.test.js +0 -61
  52. package/dist/api/tasks.test.d.ts +0 -1
  53. package/dist/api/tasks.test.js +0 -381
  54. package/dist/api/teams.test.d.ts +0 -1
  55. package/dist/api/teams.test.js +0 -139
  56. package/dist/client.test.d.ts +0 -1
  57. package/dist/client.test.js +0 -446
  58. package/dist/http/client.test.d.ts +0 -1
  59. package/dist/http/client.test.js +0 -435
  60. package/dist/http/errors.test.d.ts +0 -1
  61. package/dist/http/errors.test.js +0 -66
  62. package/dist/http/poll.test.d.ts +0 -1
  63. package/dist/http/poll.test.js +0 -146
  64. package/dist/http/streamable.test.d.ts +0 -4
  65. package/dist/http/streamable.test.js +0 -510
  66. package/dist/integration.test.d.ts +0 -9
  67. package/dist/integration.test.js +0 -107
  68. package/dist/proxy/express.test.d.ts +0 -1
  69. package/dist/proxy/express.test.js +0 -106
  70. package/dist/proxy/hono.test.d.ts +0 -1
  71. package/dist/proxy/hono.test.js +0 -90
  72. package/dist/proxy/index.test.d.ts +0 -1
  73. package/dist/proxy/index.test.js +0 -173
  74. package/dist/proxy/nextjs.test.d.ts +0 -1
  75. package/dist/proxy/nextjs.test.js +0 -125
  76. package/dist/proxy/remix.test.d.ts +0 -1
  77. package/dist/proxy/remix.test.js +0 -66
  78. package/dist/proxy/svelte.test.d.ts +0 -1
  79. package/dist/proxy/svelte.test.js +0 -69
  80. package/dist/sessions.integration.test.d.ts +0 -13
  81. package/dist/sessions.integration.test.js +0 -310
  82. package/dist/stream.test.d.ts +0 -1
  83. package/dist/stream.test.js +0 -363
  84. package/dist/streamable.integration.test.d.ts +0 -11
  85. package/dist/streamable.integration.test.js +0 -150
  86. package/dist/tool-builder.test.d.ts +0 -1
  87. package/dist/tool-builder.test.js +0 -407
  88. package/dist/utils.test.d.ts +0 -1
  89. package/dist/utils.test.js +0 -43
@@ -1 +0,0 @@
1
- export {};
@@ -1,246 +0,0 @@
1
- import { HttpClient } from '../http/client';
2
- import { FilesAPI } from '../api/files';
3
- import { sendAdHocMessage, sendTemplateMessage, sendMessage, submitToolResult, approveTool, rejectTool, alwaysAllowTool, fetchChat, stopChat, getChatStreamConfig, uploadFile, } from './api';
4
- import { ToolTypeClient } from '../types';
5
- const mockFetch = jest.fn();
6
- global.fetch = mockFetch;
7
- function mockJsonResponse(body) {
8
- mockFetch.mockResolvedValueOnce({
9
- ok: true,
10
- status: 200,
11
- text: () => Promise.resolve(JSON.stringify(body)),
12
- });
13
- }
14
- function makeClient() {
15
- const http = new HttpClient({ apiKey: 'test-key' });
16
- const files = new FilesAPI(http);
17
- return { http, files };
18
- }
19
- const adHocConfig = {
20
- name: 'test-agent',
21
- core_app: { ref: 'openrouter/claude@abc' },
22
- system_prompt: 'Be helpful',
23
- };
24
- const runResponse = {
25
- user_message: { id: 'u1', chat_id: 'chat-1', role: 'user' },
26
- assistant_message: { id: 'a1', chat_id: 'chat-1', role: 'assistant' },
27
- };
28
- describe('agent/api', () => {
29
- beforeEach(() => {
30
- jest.clearAllMocks();
31
- });
32
- describe('sendAdHocMessage', () => {
33
- it('should return null when the API response omits messages', async () => {
34
- mockJsonResponse({});
35
- const result = await sendAdHocMessage(makeClient(), adHocConfig, null, 'hello');
36
- expect(result).toBeNull();
37
- });
38
- it('should strip client tool handlers from the agents/run request body', async () => {
39
- mockJsonResponse(runResponse);
40
- const handler = jest.fn().mockReturnValue('ok');
41
- await sendAdHocMessage(makeClient(), {
42
- ...adHocConfig,
43
- tools: [
44
- {
45
- schema: {
46
- name: 'browser_tool',
47
- type: ToolTypeClient,
48
- description: 'runs in browser',
49
- },
50
- handler,
51
- },
52
- ],
53
- }, null, 'hello');
54
- const [, init] = mockFetch.mock.calls[0];
55
- const body = JSON.parse(String(init.body));
56
- expect(body.agent_config.tools[0]).toEqual({
57
- name: 'browser_tool',
58
- type: ToolTypeClient,
59
- description: 'runs in browser',
60
- });
61
- expect(body.agent_config.tools[0]).not.toHaveProperty('handler');
62
- expect(handler).not.toHaveBeenCalled();
63
- });
64
- });
65
- describe('sendTemplateMessage', () => {
66
- it('should return null when assistant_message is missing', async () => {
67
- mockJsonResponse({
68
- user_message: { id: 'u1', chat_id: 'chat-1', role: 'user' },
69
- });
70
- const result = await sendTemplateMessage(makeClient(), { agent: 'agent-1' }, null, 'hello');
71
- expect(result).toBeNull();
72
- });
73
- it('should omit empty agent field for existing chats', async () => {
74
- mockJsonResponse(runResponse);
75
- await sendTemplateMessage(makeClient(), { agent: '' }, 'chat-existing', 'hi');
76
- const [, init] = mockFetch.mock.calls[0];
77
- const body = JSON.parse(String(init.body));
78
- expect(body.chat_id).toBe('chat-existing');
79
- expect(body).not.toHaveProperty('agent');
80
- });
81
- });
82
- describe('sendMessage', () => {
83
- it('should pass FileRef attachments without uploading', async () => {
84
- mockJsonResponse(runResponse);
85
- const fileRef = {
86
- id: 'f1',
87
- uri: 'inf://files/abc',
88
- filename: 'image.png',
89
- content_type: 'image/png',
90
- };
91
- await sendMessage(makeClient(), adHocConfig, null, 'see image', [fileRef]);
92
- expect(mockFetch).toHaveBeenCalledTimes(1);
93
- const [, init] = mockFetch.mock.calls[0];
94
- const body = JSON.parse(String(init.body));
95
- expect(body.input.attachments).toEqual([fileRef]);
96
- });
97
- it('should omit attachments when every file upload fails', async () => {
98
- const client = makeClient();
99
- const uploadSpy = jest
100
- .spyOn(client.files, 'upload')
101
- .mockRejectedValue(new Error('upload failed'));
102
- mockJsonResponse(runResponse);
103
- const file = new File(['data'], 'doc.txt', { type: 'text/plain' });
104
- await sendMessage(client, adHocConfig, null, 'with file', [file]);
105
- const [, init] = mockFetch.mock.calls[0];
106
- const body = JSON.parse(String(init.body));
107
- expect(body.input.attachments).toBeUndefined();
108
- uploadSpy.mockRestore();
109
- });
110
- it('should upload File inputs before sending', async () => {
111
- const fileRecord = {
112
- id: 'file-1',
113
- uri: 'inf://files/uploaded',
114
- filename: 'hello.txt',
115
- upload_url: 'https://upload.example/put',
116
- content_type: 'text/plain',
117
- };
118
- mockJsonResponse([fileRecord]);
119
- mockFetch.mockResolvedValueOnce({ ok: true, status: 200 });
120
- mockJsonResponse(runResponse);
121
- const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
122
- await sendMessage(makeClient(), adHocConfig, null, 'with file', [file]);
123
- expect(mockFetch).toHaveBeenCalledTimes(3);
124
- const [, runInit] = mockFetch.mock.calls[2];
125
- const body = JSON.parse(String(runInit.body));
126
- expect(body.input.attachments).toEqual([fileRecord]);
127
- });
128
- it('should route template agent configs to /agents/run without agent_config', async () => {
129
- mockJsonResponse(runResponse);
130
- await sendMessage(makeClient(), { agent: 'agent-template-1' }, 'chat-existing', 'hi');
131
- const [, init] = mockFetch.mock.calls[0];
132
- const body = JSON.parse(String(init.body));
133
- expect(body.agent).toBe('agent-template-1');
134
- expect(body.chat_id).toBe('chat-existing');
135
- expect(body).not.toHaveProperty('agent_config');
136
- });
137
- });
138
- describe('submitToolResult', () => {
139
- it('should wrap string results in { result }', async () => {
140
- mockJsonResponse(null);
141
- await submitToolResult(makeClient(), 'inv-1', 'done');
142
- const [url, init] = mockFetch.mock.calls[0];
143
- expect(url).toContain('/tools/inv-1');
144
- expect(JSON.parse(String(init.body))).toEqual({ result: 'done' });
145
- });
146
- it('should pass structured action objects through unchanged', async () => {
147
- mockJsonResponse(null);
148
- const payload = {
149
- action: { type: 'approve', payload: { ok: true } },
150
- };
151
- await submitToolResult(makeClient(), 'inv-2', payload);
152
- const [, init] = mockFetch.mock.calls[0];
153
- expect(JSON.parse(String(init.body))).toEqual(payload);
154
- });
155
- it('should rethrow when the request fails', async () => {
156
- mockFetch.mockRejectedValueOnce(new Error('submit failed'));
157
- await expect(submitToolResult(makeClient(), 'inv-3', 'done')).rejects.toThrow('submit failed');
158
- });
159
- });
160
- describe('fetchChat', () => {
161
- it('should return chat data on success', async () => {
162
- const chat = { id: 'chat-1', status: 'idle' };
163
- mockJsonResponse(chat);
164
- const result = await fetchChat(makeClient(), 'chat-1');
165
- expect(result).toEqual(chat);
166
- });
167
- it('should return null and not throw when the request fails', async () => {
168
- mockFetch.mockRejectedValueOnce(new Error('network error'));
169
- const result = await fetchChat(makeClient(), 'chat-1');
170
- expect(result).toBeNull();
171
- });
172
- });
173
- describe('stopChat', () => {
174
- it('should POST to /chats/{id}/stop', async () => {
175
- mockJsonResponse(null);
176
- await stopChat(makeClient(), 'chat-1');
177
- const [url, init] = mockFetch.mock.calls[0];
178
- expect(url).toContain('/chats/chat-1/stop');
179
- expect(init.method).toBe('POST');
180
- });
181
- it('should swallow errors without throwing', async () => {
182
- mockFetch.mockRejectedValueOnce(new Error('stop failed'));
183
- await expect(stopChat(makeClient(), 'chat-1')).resolves.toBeUndefined();
184
- });
185
- });
186
- describe('HIL tool approval', () => {
187
- it('approveTool should POST to /tools/{id}/invoke', async () => {
188
- mockJsonResponse(null);
189
- await approveTool(makeClient(), 'inv-approve');
190
- const [url, init] = mockFetch.mock.calls[0];
191
- expect(url).toContain('/tools/inv-approve/invoke');
192
- expect(init.method).toBe('POST');
193
- });
194
- it('rejectTool should POST reason to /tools/{id}/reject', async () => {
195
- mockJsonResponse(null);
196
- await rejectTool(makeClient(), 'inv-reject', 'not safe');
197
- const [url, init] = mockFetch.mock.calls[0];
198
- expect(url).toContain('/tools/inv-reject/reject');
199
- expect(JSON.parse(String(init.body))).toEqual({ reason: 'not safe' });
200
- });
201
- it('alwaysAllowTool should POST tool_name to the chat tools endpoint', async () => {
202
- mockJsonResponse(null);
203
- await alwaysAllowTool(makeClient(), 'chat-1', 'inv-allow', 'browser_tool');
204
- const [url, init] = mockFetch.mock.calls[0];
205
- expect(url).toContain('/chats/chat-1/tools/inv-allow/always-allow');
206
- expect(JSON.parse(String(init.body))).toEqual({ tool_name: 'browser_tool' });
207
- });
208
- it('should rethrow when approveTool request fails', async () => {
209
- mockFetch.mockRejectedValueOnce(new Error('approve failed'));
210
- await expect(approveTool(makeClient(), 'inv-1')).rejects.toThrow('approve failed');
211
- });
212
- it('should rethrow when rejectTool request fails', async () => {
213
- mockFetch.mockRejectedValueOnce(new Error('reject failed'));
214
- await expect(rejectTool(makeClient(), 'inv-1', 'unsafe')).rejects.toThrow('reject failed');
215
- });
216
- it('should rethrow when alwaysAllowTool request fails', async () => {
217
- mockFetch.mockRejectedValueOnce(new Error('allow failed'));
218
- await expect(alwaysAllowTool(makeClient(), 'chat-1', 'inv-1', 'browser_tool')).rejects.toThrow('allow failed');
219
- });
220
- });
221
- describe('getChatStreamConfig', () => {
222
- it('should delegate to HttpClient.getStreamableConfig for the chat stream path', () => {
223
- const client = makeClient();
224
- const config = getChatStreamConfig(client, 'chat-xyz');
225
- expect(config.url).toContain('/chats/chat-xyz/stream');
226
- expect(config.headers).toEqual(expect.objectContaining({ Authorization: expect.stringContaining('Bearer') }));
227
- });
228
- });
229
- describe('uploadFile', () => {
230
- it('should delegate to client.files.upload and return the uploaded file ref', async () => {
231
- const client = makeClient();
232
- const fileRecord = {
233
- id: 'file-1',
234
- uri: 'inf://files/uploaded',
235
- filename: 'notes.txt',
236
- content_type: 'text/plain',
237
- };
238
- const uploadSpy = jest.spyOn(client.files, 'upload').mockResolvedValue(fileRecord);
239
- const file = new File(['hello'], 'notes.txt', { type: 'text/plain' });
240
- const result = await uploadFile(client, file);
241
- expect(uploadSpy).toHaveBeenCalledWith(file);
242
- expect(result).toEqual(fileRecord);
243
- uploadSpy.mockRestore();
244
- });
245
- });
246
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,131 +0,0 @@
1
- import { ChatStatusBusy, ChatStatusIdle } from '../types';
2
- import { chatReducer, initialState } from './reducer';
3
- function makeMessage(id, order, chatId = 'chat-1') {
4
- return {
5
- id,
6
- short_id: id,
7
- created_at: '2026-01-01T00:00:00Z',
8
- updated_at: '2026-01-01T00:00:00Z',
9
- user_id: 'user-1',
10
- team_id: 'team-1',
11
- visibility: 'private',
12
- chat_id: chatId,
13
- order,
14
- status: 'completed',
15
- role: 'user',
16
- content: [{ type: 'text', text: `message ${id}` }],
17
- };
18
- }
19
- function makeChat(overrides = {}) {
20
- return {
21
- id: 'chat-1',
22
- short_id: 'c1',
23
- created_at: '2026-01-01T00:00:00Z',
24
- updated_at: '2026-01-01T00:00:00Z',
25
- user_id: 'user-1',
26
- team_id: 'team-1',
27
- visibility: 'private',
28
- status: ChatStatusBusy,
29
- name: 'Test chat',
30
- description: '',
31
- children: [],
32
- chat_messages: [makeMessage('msg-1', 1), makeMessage('msg-2', 2)],
33
- agent_data: {},
34
- ...overrides,
35
- };
36
- }
37
- describe('chatReducer', () => {
38
- it('SET_CHAT should sort messages by order', () => {
39
- const chat = makeChat({
40
- chat_messages: [makeMessage('msg-2', 2), makeMessage('msg-1', 1)],
41
- });
42
- const next = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
43
- expect(next.messages.map((m) => m.id)).toEqual(['msg-1', 'msg-2']);
44
- expect(next.chat?.status).toBe(ChatStatusBusy);
45
- });
46
- it('UPDATE_CHAT should update chat metadata without replacing messages', () => {
47
- const chat = makeChat();
48
- const withMessages = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
49
- const idleChat = makeChat({ status: ChatStatusIdle, chat_messages: [] });
50
- const next = chatReducer(withMessages, { type: 'UPDATE_CHAT', payload: idleChat });
51
- expect(next.chat?.status).toBe(ChatStatusIdle);
52
- expect(next.messages).toHaveLength(2);
53
- expect(next.messages.map((m) => m.id)).toEqual(['msg-1', 'msg-2']);
54
- });
55
- it('UPDATE_CHAT with null payload should leave state unchanged', () => {
56
- const chat = makeChat();
57
- const withChat = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
58
- const next = chatReducer(withChat, { type: 'UPDATE_CHAT', payload: null });
59
- expect(next).toBe(withChat);
60
- });
61
- it('UPDATE_MESSAGE should replace an existing message by id', () => {
62
- const chat = makeChat();
63
- const state = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
64
- const updated = makeMessage('msg-1', 1);
65
- updated.content = [{ type: 'text', text: 'edited' }];
66
- const next = chatReducer(state, { type: 'UPDATE_MESSAGE', payload: updated });
67
- expect(next.messages.find((m) => m.id === 'msg-1')?.content[0]?.text).toBe('edited');
68
- expect(next.messages).toHaveLength(2);
69
- });
70
- it('UPDATE_MESSAGE should append and sort new messages', () => {
71
- const chat = makeChat({ chat_messages: [makeMessage('msg-1', 1)] });
72
- const state = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
73
- const next = chatReducer(state, { type: 'UPDATE_MESSAGE', payload: makeMessage('msg-2', 2) });
74
- expect(next.messages.map((m) => m.id)).toEqual(['msg-1', 'msg-2']);
75
- });
76
- it('SET_CHAT with null should clear chat and messages', () => {
77
- const chat = makeChat();
78
- const state = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
79
- const next = chatReducer(state, { type: 'SET_CHAT', payload: null });
80
- expect(next.chat).toBeNull();
81
- expect(next.messages).toEqual([]);
82
- expect(next.connectionStatus).toBe('idle');
83
- });
84
- it('ADD_MESSAGE should append and sort by order', () => {
85
- const chat = makeChat({ chat_messages: [makeMessage('msg-1', 1)] });
86
- const state = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
87
- const next = chatReducer(state, {
88
- type: 'ADD_MESSAGE',
89
- payload: makeMessage('msg-0', 0),
90
- });
91
- expect(next.messages.map((m) => m.id)).toEqual(['msg-0', 'msg-1']);
92
- });
93
- it('RESET should return initial state', () => {
94
- const chat = makeChat();
95
- const state = chatReducer(initialState, { type: 'SET_CHAT', payload: chat });
96
- expect(chatReducer(state, { type: 'RESET' })).toEqual(initialState);
97
- });
98
- it('SET_CHAT_ID should update chatId', () => {
99
- const next = chatReducer(initialState, { type: 'SET_CHAT_ID', payload: 'chat-99' });
100
- expect(next.chatId).toBe('chat-99');
101
- });
102
- it('SET_MESSAGES should replace the message list', () => {
103
- const messages = [makeMessage('msg-a', 1)];
104
- const next = chatReducer(initialState, { type: 'SET_MESSAGES', payload: messages });
105
- expect(next.messages).toEqual(messages);
106
- });
107
- it('ADD_MESSAGE after SET_MESSAGES should append and sort by order', () => {
108
- const state = chatReducer(initialState, {
109
- type: 'SET_MESSAGES',
110
- payload: [makeMessage('msg-2', 2)],
111
- });
112
- const next = chatReducer(state, { type: 'ADD_MESSAGE', payload: makeMessage('msg-1', 1) });
113
- expect(next.messages.map((m) => m.id)).toEqual(['msg-1', 'msg-2']);
114
- });
115
- it('SET_CONNECTION_STATUS and SET_ERROR should update connection fields', () => {
116
- const streaming = chatReducer(initialState, {
117
- type: 'SET_CONNECTION_STATUS',
118
- payload: 'streaming',
119
- });
120
- expect(streaming.connectionStatus).toBe('streaming');
121
- const errored = chatReducer(streaming, {
122
- type: 'SET_ERROR',
123
- payload: 'stream failed',
124
- });
125
- expect(errored.error).toBe('stream failed');
126
- });
127
- it('should return the same state for unknown action types', () => {
128
- const state = chatReducer(initialState, { type: 'UNKNOWN' });
129
- expect(state).toBe(initialState);
130
- });
131
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,75 +0,0 @@
1
- import { ToolTypeClient } from '../types';
2
- import { isAdHocConfig, isTemplateConfig, isClientTool, extractToolSchemas, extractClientToolHandlers, } from './types';
3
- describe('agent/types helpers', () => {
4
- const adHocConfig = {
5
- core_app: { ref: 'openrouter/claude@abc' },
6
- system_prompt: 'test',
7
- };
8
- const templateConfig = {
9
- agent: 'acme/support@latest',
10
- };
11
- describe('isAdHocConfig', () => {
12
- it('returns true when core_app is present', () => {
13
- expect(isAdHocConfig(adHocConfig)).toBe(true);
14
- });
15
- it('returns false for template config', () => {
16
- expect(isAdHocConfig(templateConfig)).toBe(false);
17
- });
18
- });
19
- describe('isTemplateConfig', () => {
20
- it('returns true when agent reference is present', () => {
21
- expect(isTemplateConfig(templateConfig)).toBe(true);
22
- });
23
- it('returns false for ad-hoc config', () => {
24
- expect(isTemplateConfig(adHocConfig)).toBe(false);
25
- });
26
- });
27
- describe('isClientTool', () => {
28
- it('detects client tools with schema and handler', () => {
29
- const clientTool = {
30
- schema: { name: 'browser_tool', type: ToolTypeClient, description: 'x' },
31
- handler: jest.fn(),
32
- };
33
- expect(isClientTool(clientTool)).toBe(true);
34
- });
35
- it('returns false for plain AgentTool schemas', () => {
36
- expect(isClientTool({ name: 'server_tool', type: ToolTypeClient, description: 'x' })).toBe(false);
37
- });
38
- });
39
- describe('extractToolSchemas', () => {
40
- it('unwraps client tools to schemas only', () => {
41
- const handler = jest.fn();
42
- const schemas = extractToolSchemas([
43
- { name: 'server', type: ToolTypeClient, description: 's' },
44
- {
45
- schema: { name: 'client', type: ToolTypeClient, description: 'c' },
46
- handler,
47
- },
48
- ]);
49
- expect(schemas).toEqual([
50
- { name: 'server', type: ToolTypeClient, description: 's' },
51
- { name: 'client', type: ToolTypeClient, description: 'c' },
52
- ]);
53
- });
54
- });
55
- describe('extractClientToolHandlers', () => {
56
- it('builds a name-to-handler map from mixed tools', () => {
57
- const handlerA = jest.fn();
58
- const handlerB = jest.fn();
59
- const map = extractClientToolHandlers([
60
- { name: 'ignored', type: ToolTypeClient, description: 'no handler' },
61
- {
62
- schema: { name: 'tool_a', type: ToolTypeClient, description: 'a' },
63
- handler: handlerA,
64
- },
65
- {
66
- schema: { name: 'tool_b', type: ToolTypeClient, description: 'b' },
67
- handler: handlerB,
68
- },
69
- ]);
70
- expect(map.size).toBe(2);
71
- expect(map.get('tool_a')).toBe(handlerA);
72
- expect(map.get('tool_b')).toBe(handlerB);
73
- });
74
- });
75
- });
@@ -1 +0,0 @@
1
- export {};