@agentscope-ai/agentscope 0.0.3 → 0.0.4

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 (65) hide show
  1. package/dist/agent/index.d.mts +7 -7
  2. package/dist/agent/index.d.ts +7 -7
  3. package/dist/agent/index.js +14 -7
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/agent/index.mjs +14 -7
  6. package/dist/agent/index.mjs.map +1 -1
  7. package/dist/{base-Bo8TzBQq.d.mts → base-1YVBgB4n.d.mts} +2 -2
  8. package/dist/{base-D9uCcDjZ.d.mts → base-B_MQMHWr.d.mts} +3 -3
  9. package/dist/{base-TYjCCv7T.d.ts → base-BherSLRs.d.ts} +3 -3
  10. package/dist/{base-Co-MzdN5.d.ts → base-CY4DMBH1.d.ts} +1 -1
  11. package/dist/{base-t7G4uaR_.d.ts → base-ChWjyzPL.d.ts} +2 -2
  12. package/dist/{base-Dh5vEBQD.d.mts → base-ClilytRZ.d.mts} +1 -1
  13. package/dist/{block-7fd6byyN.d.mts → block-B72uPF1H.d.mts} +5 -3
  14. package/dist/{block-7fd6byyN.d.ts → block-B72uPF1H.d.ts} +5 -3
  15. package/dist/event/index.d.mts +1 -1
  16. package/dist/event/index.d.ts +1 -1
  17. package/dist/formatter/index.d.mts +4 -3
  18. package/dist/formatter/index.d.ts +4 -3
  19. package/dist/formatter/index.js.map +1 -1
  20. package/dist/formatter/index.mjs.map +1 -1
  21. package/dist/{index-DaopL-Vp.d.ts → index-BNfyKbQN.d.ts} +1 -1
  22. package/dist/{index-BVNbIN62.d.mts → index-UQCwdfet.d.mts} +1 -1
  23. package/dist/mcp/index.d.mts +2 -2
  24. package/dist/mcp/index.d.ts +2 -2
  25. package/dist/message/index.d.mts +3 -2
  26. package/dist/message/index.d.ts +3 -2
  27. package/dist/message/index.js +165 -0
  28. package/dist/message/index.js.map +1 -1
  29. package/dist/message/index.mjs +164 -0
  30. package/dist/message/index.mjs.map +1 -1
  31. package/dist/{message-DZN7LetB.d.ts → message-CPZd0NIc.d.ts} +13 -2
  32. package/dist/{message-CYnHiEVt.d.mts → message-DgpfAaHK.d.mts} +13 -2
  33. package/dist/model/index.d.mts +6 -5
  34. package/dist/model/index.d.ts +6 -5
  35. package/dist/model/index.js +22 -11
  36. package/dist/model/index.js.map +1 -1
  37. package/dist/model/index.mjs +22 -11
  38. package/dist/model/index.mjs.map +1 -1
  39. package/dist/storage/index.d.mts +4 -3
  40. package/dist/storage/index.d.ts +4 -3
  41. package/dist/tool/index.d.mts +4 -4
  42. package/dist/tool/index.d.ts +4 -4
  43. package/dist/{toolkit-BuMTkbGg.d.ts → toolkit-DeOlul5Y.d.ts} +2 -2
  44. package/dist/{toolkit-CH9qKAy9.d.mts → toolkit-jwe7NmVJ.d.mts} +2 -2
  45. package/package.json +1 -1
  46. package/src/agent/agent.test.ts +41 -8
  47. package/src/agent/agent.ts +15 -9
  48. package/src/formatter/dashscope-chat-formatter.test.ts +3 -0
  49. package/src/formatter/openai-chat-formatter.test.ts +9 -1
  50. package/src/mcp/http.test.ts +2 -0
  51. package/src/mcp/stdio.test.ts +1 -0
  52. package/src/message/append-event.test.ts +783 -0
  53. package/src/message/block.ts +6 -2
  54. package/src/message/index.ts +3 -0
  55. package/src/message/message.test.ts +2 -0
  56. package/src/message/message.ts +209 -0
  57. package/src/model/dashscope-model.test.ts +4 -0
  58. package/src/model/dashscope-model.ts +3 -0
  59. package/src/model/deepseek-model.test.ts +2 -0
  60. package/src/model/deepseek-model.ts +3 -0
  61. package/src/model/ollama-model.test.ts +1 -0
  62. package/src/model/ollama-model.ts +2 -0
  63. package/src/model/openai-model.ts +3 -0
  64. package/src/storage/file-system.test.ts +1 -0
  65. package/src/tool/toolkit.test.ts +12 -0
@@ -16,20 +16,24 @@ export interface HintBlock {
16
16
  id: string;
17
17
  }
18
18
 
19
+ export type ToolCallState = 'pending' | 'asking' | 'allowed' | 'submitted' | 'finished';
20
+
19
21
  export interface ToolCallBlock {
20
22
  type: 'tool_call';
21
23
  name: string;
22
24
  id: string;
23
25
  input: string;
24
- awaitUserConfirmation?: boolean;
26
+ state: ToolCallState;
25
27
  }
26
28
 
29
+ export type ToolResultState = 'success' | 'error' | 'interrupted' | 'denied' | 'running';
30
+
27
31
  export interface ToolResultBlock {
28
32
  type: 'tool_result';
29
33
  id: string;
30
34
  name: string;
31
35
  output: string | (TextBlock | DataBlock)[];
32
- state: 'success' | 'error' | 'interrupted' | 'running';
36
+ state: ToolResultState;
33
37
  }
34
38
 
35
39
  export interface Base64Source {
@@ -6,12 +6,15 @@ export {
6
6
  SystemMsg,
7
7
  getTextContent,
8
8
  getContentBlocks,
9
+ appendEvent,
9
10
  } from './message';
10
11
  export {
11
12
  TextBlock,
12
13
  ThinkingBlock,
13
14
  ToolCallBlock,
15
+ ToolCallState,
14
16
  ToolResultBlock,
17
+ ToolResultState,
15
18
  ContentBlock,
16
19
  Base64Source,
17
20
  URLSource,
@@ -38,6 +38,7 @@ describe('Message', () => {
38
38
  id: '1',
39
39
  name: 'test',
40
40
  input: "{ query: 'What is AI?' }",
41
+ state: 'pending',
41
42
  },
42
43
  {
43
44
  type: 'tool_result',
@@ -64,6 +65,7 @@ describe('Message', () => {
64
65
  id: '1',
65
66
  name: 'test',
66
67
  input: "{ query: 'What is AI?' }",
68
+ state: 'pending',
67
69
  },
68
70
  ]);
69
71
  expect(getContentBlocks(msg, 'tool_result')).toStrictEqual([
@@ -6,7 +6,10 @@ import {
6
6
  ToolResultBlock,
7
7
  ToolCallBlock,
8
8
  DataBlock,
9
+ Base64Source,
10
+ URLSource,
9
11
  } from './block';
12
+ import { AgentEvent, EventType } from '../event';
10
13
 
11
14
  /** A chat message exchanged between agents or between an agent and a model. */
12
15
  export interface Msg {
@@ -183,3 +186,209 @@ export function getContentBlocks(
183
186
  if (!blockType) return msg.content;
184
187
  return msg.content.filter(block => block.type === blockType);
185
188
  }
189
+
190
+ /**
191
+ * Find a content block by type and id within a message.
192
+ * @param msg
193
+ * @param blockType
194
+ * @param blockId
195
+ * @returns The matching {@link ContentBlock}, or `undefined` if not found.
196
+ */
197
+ function findBlock(msg: Msg, blockType: string, blockId: string): ContentBlock | undefined {
198
+ return msg.content.find(block => block.type === blockType && block.id === blockId);
199
+ }
200
+
201
+ /**
202
+ * Apply a streaming {@link AgentEvent} to a {@link Msg}, mutating it in place.
203
+ *
204
+ * Only `content` and `finished_at` are ever modified. Events whose
205
+ * `reply_id` does not match `msg.id` are skipped with a warning.
206
+ * @param msg
207
+ * @param event
208
+ * @returns The mutated {@link Msg} object.
209
+ */
210
+ export function appendEvent(msg: Msg, event: AgentEvent): Msg {
211
+ if (!('reply_id' in event)) return msg;
212
+ if (event.reply_id !== msg.id) {
213
+ console.warn(
214
+ `Event reply_id "${event.reply_id}" does not match message id "${msg.id}", skipping.`
215
+ );
216
+ return msg;
217
+ }
218
+
219
+ switch (event.type) {
220
+ case EventType.REPLY_END:
221
+ msg.finished_at = event.created_at;
222
+ break;
223
+
224
+ case EventType.TEXT_BLOCK_START:
225
+ msg.content.push({ type: 'text', id: event.block_id, text: '' });
226
+ break;
227
+
228
+ case EventType.TEXT_BLOCK_DELTA: {
229
+ const block = findBlock(msg, 'text', event.block_id);
230
+ if (!block) {
231
+ console.warn(`TextBlock "${event.block_id}" not found, skipping.`);
232
+ } else {
233
+ (block as TextBlock).text += event.delta;
234
+ }
235
+ break;
236
+ }
237
+
238
+ case EventType.TEXT_BLOCK_END:
239
+ break;
240
+
241
+ case EventType.THINKING_BLOCK_START:
242
+ msg.content.push({ type: 'thinking', id: event.block_id, thinking: '' });
243
+ break;
244
+
245
+ case EventType.THINKING_BLOCK_DELTA: {
246
+ const block = findBlock(msg, 'thinking', event.block_id);
247
+ if (!block) {
248
+ console.warn(`ThinkingBlock "${event.block_id}" not found, skipping.`);
249
+ } else {
250
+ (block as ThinkingBlock).thinking += event.delta;
251
+ }
252
+ break;
253
+ }
254
+
255
+ case EventType.THINKING_BLOCK_END:
256
+ break;
257
+
258
+ case EventType.DATA_BLOCK_START:
259
+ msg.content.push({
260
+ type: 'data',
261
+ id: event.block_id,
262
+ source: { type: 'base64', data: '', media_type: event.media_type },
263
+ });
264
+ break;
265
+
266
+ case EventType.DATA_BLOCK_DELTA: {
267
+ const block = findBlock(msg, 'data', event.block_id);
268
+ if (!block) {
269
+ console.warn(`DataBlock "${event.block_id}" not found, skipping.`);
270
+ } else {
271
+ ((block as DataBlock).source as Base64Source).data += event.data;
272
+ }
273
+ break;
274
+ }
275
+
276
+ case EventType.DATA_BLOCK_END:
277
+ break;
278
+
279
+ case EventType.TOOL_CALL_START:
280
+ msg.content.push({
281
+ type: 'tool_call',
282
+ id: event.tool_call_id,
283
+ name: event.tool_call_name,
284
+ input: '',
285
+ state: 'pending',
286
+ });
287
+ break;
288
+
289
+ case EventType.TOOL_CALL_DELTA: {
290
+ const block = findBlock(msg, 'tool_call', event.tool_call_id);
291
+ if (!block) {
292
+ console.warn(`ToolCallBlock "${event.tool_call_id}" not found, skipping.`);
293
+ } else {
294
+ (block as ToolCallBlock).input += event.delta;
295
+ }
296
+ break;
297
+ }
298
+
299
+ case EventType.TOOL_CALL_END:
300
+ break;
301
+
302
+ case EventType.TOOL_RESULT_START:
303
+ msg.content.push({
304
+ type: 'tool_result',
305
+ id: event.tool_call_id,
306
+ name: event.tool_call_name,
307
+ output: [],
308
+ state: 'running',
309
+ });
310
+ break;
311
+
312
+ case EventType.TOOL_RESULT_TEXT_DELTA: {
313
+ const block = findBlock(msg, 'tool_result', event.tool_call_id);
314
+ if (!block) {
315
+ console.warn(`ToolResultBlock "${event.tool_call_id}" not found, skipping.`);
316
+ } else {
317
+ const trb = block as ToolResultBlock;
318
+ if (typeof trb.output === 'string') {
319
+ trb.output = [{ type: 'text', id: crypto.randomUUID(), text: trb.output }];
320
+ }
321
+ const last = trb.output[trb.output.length - 1];
322
+ if (!last || last.type !== 'text') {
323
+ trb.output.push({
324
+ type: 'text',
325
+ id: event.block_id ?? crypto.randomUUID(),
326
+ text: event.delta,
327
+ });
328
+ } else {
329
+ (last as TextBlock).text += event.delta;
330
+ }
331
+ }
332
+ break;
333
+ }
334
+
335
+ case EventType.TOOL_RESULT_DATA_DELTA: {
336
+ const block = findBlock(msg, 'tool_result', event.tool_call_id);
337
+ if (!block) {
338
+ console.warn(`ToolResultBlock "${event.tool_call_id}" not found, skipping.`);
339
+ } else {
340
+ const trb = block as ToolResultBlock;
341
+ if (typeof trb.output === 'string') {
342
+ trb.output = [{ type: 'text', id: crypto.randomUUID(), text: trb.output }];
343
+ }
344
+ const source: Base64Source | URLSource =
345
+ event.data != null
346
+ ? { type: 'base64', data: event.data, media_type: event.media_type }
347
+ : { type: 'url', url: event.url!, media_type: event.media_type };
348
+ trb.output.push({ type: 'data', id: event.block_id, source });
349
+ }
350
+ break;
351
+ }
352
+
353
+ case EventType.TOOL_RESULT_END: {
354
+ const block = findBlock(msg, 'tool_result', event.tool_call_id);
355
+ if (!block) {
356
+ console.warn(`ToolResultBlock "${event.tool_call_id}" not found, skipping.`);
357
+ } else {
358
+ (block as ToolResultBlock).state = event.state;
359
+ }
360
+ break;
361
+ }
362
+
363
+ case EventType.REQUIRE_USER_CONFIRM:
364
+ for (const tc of event.tool_calls) {
365
+ const b = findBlock(msg, 'tool_call', tc.id);
366
+ if (b) (b as ToolCallBlock).state = 'asking';
367
+ }
368
+ break;
369
+
370
+ case EventType.USER_CONFIRM_RESULT:
371
+ for (const result of event.confirm_results) {
372
+ const b = findBlock(msg, 'tool_call', result.tool_call.id);
373
+ if (b) {
374
+ (b as ToolCallBlock).state = result.confirmed ? 'allowed' : 'finished';
375
+ }
376
+ }
377
+ break;
378
+
379
+ case EventType.REQUIRE_EXTERNAL_EXECUTION:
380
+ for (const tc of event.tool_calls) {
381
+ const b = findBlock(msg, 'tool_call', tc.id);
382
+ if (b) (b as ToolCallBlock).state = 'submitted';
383
+ }
384
+ break;
385
+
386
+ case EventType.EXTERNAL_EXECUTION_RESULT:
387
+ for (const result of event.execution_results) {
388
+ msg.content.push(result);
389
+ }
390
+ break;
391
+ }
392
+
393
+ return msg;
394
+ }
@@ -122,6 +122,7 @@ describe('DashScopeChatModel', () => {
122
122
  name: 'get_current_weather',
123
123
  id: 'call-123',
124
124
  input: '{"location"',
125
+ state: 'pending',
125
126
  });
126
127
 
127
128
  // Chunk 4: Tool call with second part of arguments (delta)
@@ -131,6 +132,7 @@ describe('DashScopeChatModel', () => {
131
132
  name: 'get_current_weather',
132
133
  id: 'call-123',
133
134
  input: ':"Beijing"}',
135
+ state: 'pending',
134
136
  });
135
137
 
136
138
  // Chunk 5: Empty content with usage info
@@ -158,6 +160,7 @@ describe('DashScopeChatModel', () => {
158
160
  name: 'get_current_weather',
159
161
  id: 'call-123',
160
162
  input: '{"location":"Beijing"}',
163
+ state: 'pending',
161
164
  });
162
165
 
163
166
  // Verify usage
@@ -266,6 +269,7 @@ describe('DashScopeChatModel', () => {
266
269
  name: 'get_current_weather',
267
270
  id: 'call-123',
268
271
  input: '{"location":"Beijing"}',
272
+ state: 'pending',
269
273
  });
270
274
 
271
275
  // Verify usage
@@ -231,6 +231,7 @@ export class DashScopeChatModel extends ChatModelBase {
231
231
  id: String(toolCall.id),
232
232
  name: String(toolCall.function.name),
233
233
  input: inputString,
234
+ state: 'pending',
234
235
  });
235
236
  }
236
237
  });
@@ -354,6 +355,7 @@ export class DashScopeChatModel extends ChatModelBase {
354
355
  id: meta.id,
355
356
  name: meta.name,
356
357
  input: deltaArgs,
358
+ state: 'pending',
357
359
  });
358
360
  }
359
361
  });
@@ -387,6 +389,7 @@ export class DashScopeChatModel extends ChatModelBase {
387
389
  id: meta.id,
388
390
  name: meta.name,
389
391
  input: accToolInputs.get(index) || '{}',
392
+ state: 'pending',
390
393
  });
391
394
  });
392
395
 
@@ -106,6 +106,7 @@ describe('DeepSeekChatModel', () => {
106
106
  name: 'get_current_weather',
107
107
  id: 'call-123',
108
108
  input: '{"location":"Beijing"}',
109
+ state: 'pending',
109
110
  });
110
111
 
111
112
  // Verify usage
@@ -209,6 +210,7 @@ describe('DeepSeekChatModel', () => {
209
210
  name: 'get_current_weather',
210
211
  id: 'call-123',
211
212
  input: '{"location":"Beijing"}',
213
+ state: 'pending',
212
214
  });
213
215
 
214
216
  // Verify usage
@@ -191,6 +191,7 @@ export class DeepSeekChatModel extends ChatModelBase {
191
191
  id: String(toolCall.id),
192
192
  name: String(toolCall.function.name),
193
193
  input: inputString,
194
+ state: 'pending',
194
195
  });
195
196
  }
196
197
  });
@@ -314,6 +315,7 @@ export class DeepSeekChatModel extends ChatModelBase {
314
315
  id: meta.id,
315
316
  name: meta.name,
316
317
  input: deltaArgs,
318
+ state: 'pending',
317
319
  });
318
320
  }
319
321
  });
@@ -347,6 +349,7 @@ export class DeepSeekChatModel extends ChatModelBase {
347
349
  id: meta.id,
348
350
  name: meta.name,
349
351
  input: accToolInputs.get(index) || '{}',
352
+ state: 'pending',
350
353
  });
351
354
  });
352
355
 
@@ -106,6 +106,7 @@ describe('OllamaChatModel', () => {
106
106
  type: 'tool_call',
107
107
  name: 'get_current_weather',
108
108
  input: '{"location":"Beijing"}',
109
+ state: 'pending',
109
110
  });
110
111
 
111
112
  // Verify usage
@@ -212,6 +212,7 @@ export class OllamaChatModel extends ChatModelBase {
212
212
  id: toolId,
213
213
  name: func.name,
214
214
  input: JSON.stringify(func.arguments),
215
+ state: 'pending' as const,
215
216
  };
216
217
 
217
218
  toolCalls.set(toolId, toolCallBlock);
@@ -284,6 +285,7 @@ export class OllamaChatModel extends ChatModelBase {
284
285
  id: `${idx}_${toolCall.function.name}`,
285
286
  name: toolCall.function.name,
286
287
  input: JSON.stringify(toolCall.function.arguments),
288
+ state: 'pending',
287
289
  });
288
290
  }
289
291
  }
@@ -117,6 +117,7 @@ export class OpenAIChatModel extends ChatModelBase {
117
117
  id: toolCall.id,
118
118
  name: toolCall.function.name,
119
119
  input: toolCall.function.arguments,
120
+ state: 'pending',
120
121
  });
121
122
  }
122
123
  });
@@ -238,6 +239,7 @@ export class OpenAIChatModel extends ChatModelBase {
238
239
  id: meta.id,
239
240
  name: meta.name,
240
241
  input: deltaArgs,
242
+ state: 'pending',
241
243
  });
242
244
  }
243
245
  });
@@ -276,6 +278,7 @@ export class OpenAIChatModel extends ChatModelBase {
276
278
  id: meta.id,
277
279
  name: meta.name,
278
280
  input: accToolInputs.get(index) || '{}',
281
+ state: 'pending',
279
282
  });
280
283
  });
281
284
 
@@ -529,6 +529,7 @@ describe('LocalFileStorage', () => {
529
529
  id: 'call-123',
530
530
  name: 'search',
531
531
  input: JSON.stringify({ query: 'test' }),
532
+ state: 'pending',
532
533
  },
533
534
  ],
534
535
  role: 'assistant',
@@ -92,6 +92,7 @@ describe('Toolkit', () => {
92
92
  type: 'tool_call',
93
93
  name: 'test_function',
94
94
  input: '{"a":"hello","b":5}',
95
+ state: 'pending',
95
96
  id: '1',
96
97
  });
97
98
 
@@ -162,6 +163,7 @@ describe('Toolkit', () => {
162
163
  type: 'tool_call',
163
164
  name: 'test_function',
164
165
  input: '{"a":"hello","b":5}',
166
+ state: 'pending',
165
167
  id: '1b',
166
168
  });
167
169
 
@@ -229,6 +231,7 @@ describe('Toolkit', () => {
229
231
  name: 'no_param_function',
230
232
  id: '2',
231
233
  input: '{}',
234
+ state: 'pending',
232
235
  });
233
236
 
234
237
  for await (const chunk of res) {
@@ -263,6 +266,7 @@ describe('Toolkit', () => {
263
266
  name: 'count_function',
264
267
  id: '3',
265
268
  input: '{"count":3}',
269
+ state: 'pending',
266
270
  });
267
271
 
268
272
  // Verify intermediate chunks
@@ -325,6 +329,7 @@ describe('Toolkit', () => {
325
329
  name: 'async_count_function',
326
330
  id: '4',
327
331
  input: '{"count":2}',
332
+ state: 'pending',
328
333
  });
329
334
 
330
335
  // Verify intermediate chunks
@@ -376,6 +381,7 @@ describe('Toolkit', () => {
376
381
  name: 'string_count_function',
377
382
  id: '8',
378
383
  input: '{"count":3}',
384
+ state: 'pending',
379
385
  });
380
386
 
381
387
  const chunks = [];
@@ -429,6 +435,7 @@ describe('Toolkit', () => {
429
435
  name: 'async_string_count_function',
430
436
  id: '9',
431
437
  input: '{"count":2}',
438
+ state: 'pending',
432
439
  });
433
440
 
434
441
  const chunks = [];
@@ -467,6 +474,7 @@ describe('Toolkit', () => {
467
474
  name: 'non_existent_function',
468
475
  id: '5',
469
476
  input: '{}',
477
+ state: 'pending',
470
478
  });
471
479
 
472
480
  for await (const chunk of res) {
@@ -495,6 +503,7 @@ describe('Toolkit', () => {
495
503
  name: 'test_function',
496
504
  id: '6',
497
505
  input: '{"a":"hello","b":20}',
506
+ state: 'pending',
498
507
  });
499
508
 
500
509
  for await (const chunk of res2) {
@@ -526,6 +535,7 @@ describe('Toolkit', () => {
526
535
  name: 'test_function',
527
536
  id: '7',
528
537
  input: '{"a":"hello","b":20}',
538
+ state: 'pending',
529
539
  });
530
540
 
531
541
  for await (const chunk of res3) {
@@ -582,6 +592,7 @@ This skill demonstrates how to use the Skill tool to retrieve skill content.`;
582
592
  type: 'tool_call',
583
593
  name: 'Skill',
584
594
  input: '{"name":"test_skill"}',
595
+ state: 'pending',
585
596
  id: 'skill_test_1',
586
597
  });
587
598
 
@@ -610,6 +621,7 @@ This skill demonstrates how to use the Skill tool to retrieve skill content.`;
610
621
  type: 'tool_call',
611
622
  name: 'Skill',
612
623
  input: '{"name":"non_existent_skill"}',
624
+ state: 'pending',
613
625
  id: 'skill_test_2',
614
626
  });
615
627