@ddlqhd/agent-sdk 0.1.0 → 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.
Files changed (49) hide show
  1. package/README.md +4 -2
  2. package/dist/{chunk-5QMA2YBY.cjs → chunk-6X7EYQLS.cjs} +782 -114
  3. package/dist/chunk-6X7EYQLS.cjs.map +1 -0
  4. package/dist/{chunk-NDSL7NPN.js → chunk-D3UZNLZO.js} +769 -71
  5. package/dist/chunk-D3UZNLZO.js.map +1 -0
  6. package/dist/{chunk-Q3SOMX26.js → chunk-EQ5CXH44.js} +772 -111
  7. package/dist/chunk-EQ5CXH44.js.map +1 -0
  8. package/dist/chunk-LOYIGOBZ.js +54 -0
  9. package/dist/chunk-LOYIGOBZ.js.map +1 -0
  10. package/dist/{chunk-OHXW2YM6.js → chunk-MEJHTQJM.js} +289 -166
  11. package/dist/chunk-MEJHTQJM.js.map +1 -0
  12. package/dist/chunk-NYZD3THB.cjs +1521 -0
  13. package/dist/chunk-NYZD3THB.cjs.map +1 -0
  14. package/dist/chunk-OZO7D77N.cjs +59 -0
  15. package/dist/chunk-OZO7D77N.cjs.map +1 -0
  16. package/dist/{chunk-JF5AJQMU.cjs → chunk-Z45DHTDX.cjs} +291 -170
  17. package/dist/chunk-Z45DHTDX.cjs.map +1 -0
  18. package/dist/cli/index.cjs +47 -39
  19. package/dist/cli/index.cjs.map +1 -1
  20. package/dist/cli/index.js +22 -14
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/{index-DPsZ1zat.d.ts → index-Cw3SfEAB.d.ts} +20 -34
  23. package/dist/{index-RTPmFjMp.d.cts → index-D2Qntkn_.d.cts} +20 -34
  24. package/dist/index.cjs +125 -89
  25. package/dist/index.d.cts +62 -22
  26. package/dist/index.d.ts +62 -22
  27. package/dist/index.js +4 -4
  28. package/dist/models/index.cjs +19 -15
  29. package/dist/models/index.d.cts +55 -6
  30. package/dist/models/index.d.ts +55 -6
  31. package/dist/models/index.js +2 -2
  32. package/dist/tools/index.cjs +53 -61
  33. package/dist/tools/index.d.cts +3 -3
  34. package/dist/tools/index.d.ts +3 -3
  35. package/dist/tools/index.js +2 -2
  36. package/dist/{types-C0aX_Qdp.d.cts → types-CWPAYWzr.d.cts} +307 -61
  37. package/dist/{types-C0aX_Qdp.d.ts → types-CWPAYWzr.d.ts} +307 -61
  38. package/package.json +25 -14
  39. package/dist/chunk-5QMA2YBY.cjs.map +0 -1
  40. package/dist/chunk-CNSGZVRN.cjs +0 -152
  41. package/dist/chunk-CNSGZVRN.cjs.map +0 -1
  42. package/dist/chunk-JF5AJQMU.cjs.map +0 -1
  43. package/dist/chunk-NDSL7NPN.js.map +0 -1
  44. package/dist/chunk-OHXW2YM6.js.map +0 -1
  45. package/dist/chunk-Q3SOMX26.js.map +0 -1
  46. package/dist/chunk-WH3APNQ5.js +0 -147
  47. package/dist/chunk-WH3APNQ5.js.map +0 -1
  48. package/dist/chunk-X35MHWXE.cjs +0 -817
  49. package/dist/chunk-X35MHWXE.cjs.map +0 -1
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var chunkJF5AJQMU_cjs = require('./chunk-JF5AJQMU.cjs');
4
+ var chunkNYZD3THB_cjs = require('./chunk-NYZD3THB.cjs');
5
+ var chunkZ45DHTDX_cjs = require('./chunk-Z45DHTDX.cjs');
5
6
  var fs = require('fs');
6
7
  var path = require('path');
8
+ var url = require('url');
7
9
  var crypto = require('crypto');
8
10
  var os = require('os');
9
11
  var index_js = require('@modelcontextprotocol/sdk/client/index.js');
@@ -13,6 +15,29 @@ var zod = require('zod');
13
15
  var child_process = require('child_process');
14
16
  var util = require('util');
15
17
 
18
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
19
+ var pkgDir = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-6X7EYQLS.cjs', document.baseURI).href))));
20
+ var pkgPath = path.join(pkgDir, "..", "package.json");
21
+ var PACKAGE_VERSION = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
22
+
23
+ // src/core/types.ts
24
+ var MODEL_STREAM_EVENT_TYPES = [
25
+ "text_start",
26
+ "text_delta",
27
+ "text_end",
28
+ "tool_call_start",
29
+ "tool_call_delta",
30
+ "tool_call",
31
+ "tool_call_end",
32
+ "thinking_start",
33
+ "thinking",
34
+ "thinking_end",
35
+ "model_usage"
36
+ ];
37
+ var MODEL_STREAM_EVENT_TYPE_SET = new Set(MODEL_STREAM_EVENT_TYPES);
38
+ function isModelStreamEventType(type) {
39
+ return MODEL_STREAM_EVENT_TYPE_SET.has(type);
40
+ }
16
41
  var JsonlStorage = class {
17
42
  basePath;
18
43
  constructor(config = {}) {
@@ -415,6 +440,7 @@ When to use tools:
415
440
  - **Glob** to find paths by pattern \u2014 not \`find\` or \`ls\` for discovery
416
441
  - **Grep** to search file contents \u2014 not \`grep\` or \`rg\` in the shell (built-in line-by-line regex search; correct integration)
417
442
  - **WebFetch** / **WebSearch** when the task needs HTTP or web search (when configured)
443
+ - **TodoWrite** for structured multi-step task lists (see **Task Management with Todo List** below)
418
444
 
419
445
  Reserve **Bash** for real shell needs: \`git\`, package managers, build commands, compilers, and other operations that require a shell or are not covered above.
420
446
 
@@ -435,7 +461,7 @@ Skills are instruction guides for specialized tasks. When activated, you receive
435
461
 
436
462
  ## Task Execution Principles
437
463
 
438
- 1. **Plan First for Complex Tasks**: For multi-step tasks, you MUST call \`TaskCreate\` BEFORE any other tool. Do NOT skip this step.
464
+ 1. **Plan First for Complex Tasks**: For multi-step tasks, you MUST call \`TodoWrite\` BEFORE any other tool. Do NOT skip this step.
439
465
  2. **Be Direct**: Go straight to the point. Try the simplest approach first.
440
466
  3. **Be Concise**: If you can say it in one sentence, don't use three.
441
467
  4. **Read Before Modify**: Always understand existing code before changing it.
@@ -445,17 +471,17 @@ Skills are instruction guides for specialized tasks. When activated, you receive
445
471
 
446
472
  ## Task Management with Todo List
447
473
 
448
- **MANDATORY**: For multi-step tasks, call \`TaskCreate\` FIRST.
474
+ **MANDATORY**: For multi-step tasks, call \`TodoWrite\` FIRST.
449
475
 
450
476
  **Workflow:**
451
- 1. Receive complex task -> call \`TaskCreate\` immediately
452
- 2. Start first task (in_progress) -> complete -> mark completed
453
- 3. Move to next task -> repeat
454
- 4. Cancel tasks that become irrelevant
477
+ 1. Receive complex task -> call \`TodoWrite\` immediately
478
+ 2. Mark tasks \`in_progress\` / \`completed\` as you work; several items may be \`in_progress\` at once when work is parallel
479
+ 3. **Replan freely:** if the plan was wrong or incomplete, call \`TodoWrite\` again with a revised full list (add, remove, reorder, or rewrite steps)
480
+ 4. **Before you finish your response** for a multi-step request, ensure **every** todo is \`completed\` via \`TodoWrite\` (unless you intentionally pause for a follow-up turn). Do not leave \`pending\` / \`in_progress\` items when the work is done
455
481
 
456
482
  **Example:**
457
483
  User: "Open Google, search X, summarize results, open first link, extract info"
458
- -> Multi-step task detected -> call \`TaskCreate\` FIRST, then execute.
484
+ -> Multi-step task detected -> call \`TodoWrite\` FIRST, then execute.
459
485
 
460
486
  ## Output Format
461
487
 
@@ -556,8 +582,16 @@ ${combinedContent}
556
582
  };
557
583
  }
558
584
  };
559
- function isStdioConfig(config) {
560
- return "command" in config;
585
+
586
+ // src/mcp/mcp-tool-name.ts
587
+ function formatMcpToolName(serverName, toolName) {
588
+ return `mcp__${serverName}__${toolName}`;
589
+ }
590
+ function isMcpPrefixedToolName(name) {
591
+ if (!name.startsWith("mcp__")) {
592
+ return false;
593
+ }
594
+ return name.slice("mcp__".length).includes("__");
561
595
  }
562
596
  var MCPClient = class {
563
597
  client;
@@ -569,16 +603,24 @@ var MCPClient = class {
569
603
  constructor(config) {
570
604
  this._name = config.name;
571
605
  this.client = new index_js.Client(
572
- { name: "agent-sdk-client", version: "0.1.0" },
606
+ { name: "agent-sdk-client", version: PACKAGE_VERSION },
573
607
  { capabilities: {} }
574
608
  );
575
- if (isStdioConfig(config)) {
609
+ if (config.transport === "stdio") {
610
+ if (!config.command) {
611
+ throw new Error(`MCP server "${config.name}": stdio transport requires command`);
612
+ }
613
+ const cwd = (config.cwd ?? "").trim();
576
614
  this.transport = new stdio_js.StdioClientTransport({
577
615
  command: config.command,
578
616
  args: config.args,
579
- env: config.env
617
+ env: config.env,
618
+ ...cwd !== "" ? { cwd } : {}
580
619
  });
581
620
  } else {
621
+ if (!config.url) {
622
+ throw new Error(`MCP server "${config.name}": http transport requires url`);
623
+ }
582
624
  this.transport = new streamableHttp_js.StreamableHTTPClientTransport(
583
625
  new URL(config.url),
584
626
  { requestInit: { headers: config.headers } }
@@ -687,7 +729,7 @@ var MCPClient = class {
687
729
  }
688
730
  toToolDefinitions() {
689
731
  return this._tools.map((tool) => ({
690
- name: `mcp_${this._name}__${tool.name}`,
732
+ name: formatMcpToolName(this._name, tool.name),
691
733
  description: tool.description || `MCP tool: ${tool.name}`,
692
734
  parameters: this.convertSchema(tool.inputSchema),
693
735
  handler: async (args) => this.callTool(tool.name, args),
@@ -697,7 +739,7 @@ var MCPClient = class {
697
739
  }
698
740
  convertSchema(schema) {
699
741
  if (!schema || !schema.properties) {
700
- return zod.z.object({}).passthrough();
742
+ return zod.z.looseObject({});
701
743
  }
702
744
  const shape = {};
703
745
  for (const [key, value] of Object.entries(schema.properties)) {
@@ -718,7 +760,7 @@ var MCPClient = class {
718
760
  zodField = zod.z.array(zod.z.any());
719
761
  break;
720
762
  case "object":
721
- zodField = zod.z.object({}).passthrough();
763
+ zodField = zod.z.looseObject({});
722
764
  break;
723
765
  default:
724
766
  zodField = zod.z.any();
@@ -762,7 +804,7 @@ var MCPAdapter = class {
762
804
  await client.connect();
763
805
  this.clients.set(config.name, client);
764
806
  for (const tool of client.tools) {
765
- const fullName = `mcp_${config.name}__${tool.name}`;
807
+ const fullName = formatMcpToolName(config.name, tool.name);
766
808
  this.toolMap.set(fullName, { client, toolName: tool.name });
767
809
  }
768
810
  }
@@ -1314,9 +1356,12 @@ var StreamChunkProcessor = class {
1314
1356
  currentToolCall = null;
1315
1357
  lastUsage;
1316
1358
  inTextBlock = false;
1359
+ inThinkingBlock = false;
1317
1360
  emitTextBoundaries;
1361
+ emitThinkingBoundaries;
1318
1362
  constructor(options) {
1319
1363
  this.emitTextBoundaries = options?.emitTextBoundaries ?? true;
1364
+ this.emitThinkingBoundaries = options?.emitThinkingBoundaries ?? true;
1320
1365
  }
1321
1366
  processChunk(chunk) {
1322
1367
  const events = [];
@@ -1326,8 +1371,15 @@ var StreamChunkProcessor = class {
1326
1371
  this.inTextBlock = false;
1327
1372
  }
1328
1373
  };
1374
+ const endThinkingBlockIfNeeded = () => {
1375
+ if (this.emitThinkingBoundaries && this.inThinkingBlock) {
1376
+ events.push({ type: "thinking_end" });
1377
+ this.inThinkingBlock = false;
1378
+ }
1379
+ };
1329
1380
  switch (chunk.type) {
1330
1381
  case "text":
1382
+ endThinkingBlockIfNeeded();
1331
1383
  if (chunk.content) {
1332
1384
  if (this.emitTextBoundaries && !this.inTextBlock) {
1333
1385
  events.push({ type: "text_start" });
@@ -1337,6 +1389,7 @@ var StreamChunkProcessor = class {
1337
1389
  }
1338
1390
  break;
1339
1391
  case "tool_call_start":
1392
+ endThinkingBlockIfNeeded();
1340
1393
  endTextBlockIfNeeded();
1341
1394
  if (this.currentToolCall) {
1342
1395
  events.push(...this.finalizeStreamingToolCall());
@@ -1382,6 +1435,7 @@ var StreamChunkProcessor = class {
1382
1435
  }
1383
1436
  break;
1384
1437
  case "tool_call": {
1438
+ endThinkingBlockIfNeeded();
1385
1439
  endTextBlockIfNeeded();
1386
1440
  if (!chunk.toolCall) break;
1387
1441
  const tc = chunk.toolCall;
@@ -1400,6 +1454,7 @@ var StreamChunkProcessor = class {
1400
1454
  break;
1401
1455
  }
1402
1456
  case "tool_call_end":
1457
+ endThinkingBlockIfNeeded();
1403
1458
  endTextBlockIfNeeded();
1404
1459
  if (this.currentToolCall) {
1405
1460
  events.push(...this.finalizeStreamingToolCall());
@@ -1407,6 +1462,16 @@ var StreamChunkProcessor = class {
1407
1462
  break;
1408
1463
  case "thinking":
1409
1464
  endTextBlockIfNeeded();
1465
+ if (this.emitThinkingBoundaries) {
1466
+ const opensBlock = !this.inThinkingBlock && (chunk.content !== void 0 || chunk.signature !== void 0);
1467
+ if (opensBlock) {
1468
+ events.push({
1469
+ type: "thinking_start",
1470
+ ...chunk.signature !== void 0 ? { signature: chunk.signature } : {}
1471
+ });
1472
+ this.inThinkingBlock = true;
1473
+ }
1474
+ }
1410
1475
  if (chunk.content !== void 0) {
1411
1476
  events.push({
1412
1477
  type: "thinking",
@@ -1415,7 +1480,12 @@ var StreamChunkProcessor = class {
1415
1480
  });
1416
1481
  }
1417
1482
  break;
1483
+ case "thinking_block_end":
1484
+ endThinkingBlockIfNeeded();
1485
+ endTextBlockIfNeeded();
1486
+ break;
1418
1487
  case "error":
1488
+ endThinkingBlockIfNeeded();
1419
1489
  endTextBlockIfNeeded();
1420
1490
  if (chunk.error) {
1421
1491
  events.push({
@@ -1443,6 +1513,10 @@ var StreamChunkProcessor = class {
1443
1513
  /** End open text block and finalize any in-progress streamed tool call. */
1444
1514
  flush() {
1445
1515
  const events = [];
1516
+ if (this.emitThinkingBoundaries && this.inThinkingBlock) {
1517
+ events.push({ type: "thinking_end" });
1518
+ this.inThinkingBlock = false;
1519
+ }
1446
1520
  if (this.emitTextBoundaries && this.inTextBlock) {
1447
1521
  events.push({ type: "text_end" });
1448
1522
  this.inTextBlock = false;
@@ -1587,11 +1661,52 @@ var SummarizationCompressor = class {
1587
1661
  this.options = options;
1588
1662
  }
1589
1663
  name = "summarization";
1664
+ getSessionId() {
1665
+ return this.options.sessionIdProvider?.() ?? this.options.sessionId;
1666
+ }
1590
1667
  async compress(messages, targetTokens) {
1668
+ const startedAt = Date.now();
1591
1669
  const preserveRecent = this.options.preserveRecent ?? 6;
1670
+ const sessionId = this.getSessionId();
1671
+ chunkNYZD3THB_cjs.emitSDKLog({
1672
+ logger: this.options.logger,
1673
+ logLevel: this.options.logLevel,
1674
+ level: "info",
1675
+ event: {
1676
+ component: "memory",
1677
+ event: "context.compress.start",
1678
+ message: "Starting context compression",
1679
+ operation: "compress",
1680
+ sessionId,
1681
+ metadata: {
1682
+ compressor: this.name,
1683
+ messageCount: messages.length,
1684
+ targetTokens,
1685
+ preserveRecent
1686
+ }
1687
+ }
1688
+ });
1592
1689
  const systemMessages = messages.filter((m) => m.role === "system");
1593
1690
  const nonSystemMessages = messages.filter((m) => m.role !== "system");
1594
1691
  if (nonSystemMessages.length <= preserveRecent) {
1692
+ chunkNYZD3THB_cjs.emitSDKLog({
1693
+ logger: this.options.logger,
1694
+ logLevel: this.options.logLevel,
1695
+ level: "debug",
1696
+ event: {
1697
+ component: "memory",
1698
+ event: "context.compress.skipped",
1699
+ message: "Skipped compression because there are not enough messages",
1700
+ operation: "compress",
1701
+ sessionId,
1702
+ durationMs: Date.now() - startedAt,
1703
+ metadata: {
1704
+ compressor: this.name,
1705
+ messageCount: messages.length,
1706
+ preserveRecent
1707
+ }
1708
+ }
1709
+ });
1595
1710
  return messages;
1596
1711
  }
1597
1712
  const recentMessages = nonSystemMessages.slice(-preserveRecent);
@@ -1601,21 +1716,68 @@ var SummarizationCompressor = class {
1601
1716
  this.options.maxSummaryTokens ?? 4e3,
1602
1717
  Math.floor(targetTokens * 0.3)
1603
1718
  );
1604
- const summaryResponse = await this.model.complete({
1605
- messages: [
1606
- { role: "system", content: summaryPrompt },
1607
- ...messagesToSummarize
1608
- ],
1609
- maxTokens
1610
- });
1611
- return [
1612
- ...systemMessages,
1613
- {
1614
- role: "system",
1615
- content: this.wrapSummary(summaryResponse.content)
1616
- },
1617
- ...recentMessages
1618
- ];
1719
+ try {
1720
+ const summaryResponse = await this.model.complete({
1721
+ messages: [
1722
+ { role: "system", content: summaryPrompt },
1723
+ ...messagesToSummarize
1724
+ ],
1725
+ maxTokens,
1726
+ logger: this.options.logger,
1727
+ logLevel: this.options.logLevel,
1728
+ redaction: this.options.redaction,
1729
+ sessionId
1730
+ });
1731
+ const compressedMessages = [
1732
+ ...systemMessages,
1733
+ {
1734
+ role: "system",
1735
+ content: this.wrapSummary(summaryResponse.content)
1736
+ },
1737
+ ...recentMessages
1738
+ ];
1739
+ chunkNYZD3THB_cjs.emitSDKLog({
1740
+ logger: this.options.logger,
1741
+ logLevel: this.options.logLevel,
1742
+ level: "info",
1743
+ event: {
1744
+ component: "memory",
1745
+ event: "context.compress.end",
1746
+ message: "Context compression completed",
1747
+ operation: "compress",
1748
+ sessionId,
1749
+ durationMs: Date.now() - startedAt,
1750
+ metadata: {
1751
+ compressor: this.name,
1752
+ originalMessageCount: messages.length,
1753
+ compressedMessageCount: compressedMessages.length
1754
+ }
1755
+ }
1756
+ });
1757
+ return compressedMessages;
1758
+ } catch (error) {
1759
+ const err = error instanceof Error ? error : new Error(String(error));
1760
+ chunkNYZD3THB_cjs.emitSDKLog({
1761
+ logger: this.options.logger,
1762
+ logLevel: this.options.logLevel,
1763
+ level: "error",
1764
+ event: {
1765
+ component: "memory",
1766
+ event: "context.compress.error",
1767
+ message: "Context compression failed",
1768
+ operation: "compress",
1769
+ sessionId,
1770
+ durationMs: Date.now() - startedAt,
1771
+ errorName: err.name,
1772
+ errorMessage: err.message,
1773
+ metadata: {
1774
+ compressor: this.name,
1775
+ messageCount: messages.length
1776
+ }
1777
+ }
1778
+ });
1779
+ throw err;
1780
+ }
1619
1781
  }
1620
1782
  /**
1621
1783
  * 构建默认摘要提示 (借鉴 Opencode 模板)
@@ -1801,21 +1963,7 @@ var ContextManager = class {
1801
1963
  };
1802
1964
 
1803
1965
  // src/core/agent.ts
1804
- function toMCPClientConfig(config) {
1805
- if (config.transport === "http") {
1806
- return {
1807
- name: config.name,
1808
- url: config.url,
1809
- headers: config.headers
1810
- };
1811
- }
1812
- return {
1813
- name: config.name,
1814
- command: config.command,
1815
- args: config.args,
1816
- env: config.env
1817
- };
1818
- }
1966
+ var DEFAULT_MAX_ITERATIONS = 400;
1819
1967
  var Agent = class _Agent {
1820
1968
  config;
1821
1969
  toolRegistry;
@@ -1833,22 +1981,39 @@ var Agent = class _Agent {
1833
1981
  // inputTokens/outputTokens: 累计消耗
1834
1982
  // totalTokens: 累计总消耗 (inputTokens + outputTokens)
1835
1983
  sessionUsage = _Agent.createEmptySessionUsage();
1984
+ static resolveModel(config) {
1985
+ if (config.model) {
1986
+ if (config.modelConfig) {
1987
+ throw new Error("AgentConfig: pass only one of `model` or `modelConfig`");
1988
+ }
1989
+ return config.model;
1990
+ }
1991
+ if (config.modelConfig) {
1992
+ return chunkNYZD3THB_cjs.createModel(config.modelConfig, config.env);
1993
+ }
1994
+ throw new Error("AgentConfig: `model` or `modelConfig` is required");
1995
+ }
1836
1996
  constructor(config) {
1997
+ const resolvedModel = _Agent.resolveModel(config);
1837
1998
  this.config = {
1838
- maxIterations: 200,
1999
+ maxIterations: DEFAULT_MAX_ITERATIONS,
1839
2000
  streaming: true,
1840
- ...config
2001
+ ...config,
2002
+ model: resolvedModel,
2003
+ modelConfig: void 0
1841
2004
  };
2005
+ this.config.maxIterations = this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
1842
2006
  this.skillRegistry = createSkillRegistry({
1843
- cwd: config.cwd,
1844
- userBasePath: config.userBasePath
2007
+ cwd: this.config.cwd,
2008
+ userBasePath: this.config.userBasePath
1845
2009
  });
1846
- this.toolRegistry = new chunkJF5AJQMU_cjs.ToolRegistry({
2010
+ this.toolRegistry = new chunkZ45DHTDX_cjs.ToolRegistry({
1847
2011
  executionPolicy: {
1848
2012
  disallowedTools: this.config.disallowedTools,
1849
2013
  allowedTools: this.config.allowedTools,
1850
2014
  canUseTool: this.config.canUseTool
1851
- }
2015
+ },
2016
+ hookObserver: this.config.callbacks?.lifecycle?.hooks
1852
2017
  });
1853
2018
  this.registerInitialTools();
1854
2019
  const subagentEnabled = this.config.subagent?.enabled !== false;
@@ -1856,29 +2021,46 @@ var Agent = class _Agent {
1856
2021
  if (this.toolRegistry.has("Agent")) {
1857
2022
  this.toolRegistry.unregister("Agent");
1858
2023
  }
1859
- this.toolRegistry.register(chunkJF5AJQMU_cjs.createAgentTool({
2024
+ this.toolRegistry.register(chunkZ45DHTDX_cjs.createAgentTool({
1860
2025
  runner: (request, context) => this.runSubagent(request, context)
1861
2026
  }));
1862
2027
  } else if (this.toolRegistry.has("Agent")) {
1863
2028
  this.toolRegistry.unregister("Agent");
1864
2029
  }
1865
- if (config.hookManager) {
1866
- this.toolRegistry.setHookManager(config.hookManager);
1867
- } else if (config.hookConfigDir !== void 0) {
1868
- const hm = chunkJF5AJQMU_cjs.HookManager.create();
2030
+ if (this.config.hookManager) {
2031
+ this.toolRegistry.setHookManager(this.config.hookManager);
2032
+ } else if (this.config.hookConfigDir !== void 0) {
2033
+ const hm = chunkZ45DHTDX_cjs.HookManager.create();
1869
2034
  this.toolRegistry.setHookManager(hm);
1870
- this.hookDiscoverPromise = hm.discoverAndLoad(config.hookConfigDir);
2035
+ this.hookDiscoverPromise = hm.discoverAndLoad(this.config.hookConfigDir);
1871
2036
  }
1872
2037
  this.sessionManager = new SessionManager({
1873
- type: config.storage?.type || "jsonl",
1874
- basePath: getSessionStoragePath(config.userBasePath)
2038
+ type: this.config.storage?.type || "jsonl",
2039
+ basePath: getSessionStoragePath(this.config.userBasePath)
1875
2040
  });
1876
- if (config.contextManagement !== false) {
1877
- const cmConfig = config.contextManagement === true ? {} : config.contextManagement ?? {};
1878
- this.contextManager = new ContextManager(config.model, cmConfig);
2041
+ if (this.config.contextManagement !== false) {
2042
+ const cmConfig = this.config.contextManagement === true ? {} : this.config.contextManagement ?? {};
2043
+ const compressor = cmConfig.compressor ?? new SummarizationCompressor(this.config.model, {
2044
+ logger: this.config.logger,
2045
+ logLevel: this.config.logLevel,
2046
+ redaction: this.config.redaction,
2047
+ sessionIdProvider: () => this.sessionManager.sessionId ?? void 0
2048
+ });
2049
+ this.contextManager = new ContextManager(this.config.model, {
2050
+ ...cmConfig,
2051
+ compressor
2052
+ });
1879
2053
  }
1880
2054
  this.initPromise = this.initializeAsync();
1881
2055
  }
2056
+ log(level, event) {
2057
+ chunkNYZD3THB_cjs.emitSDKLog({
2058
+ logger: this.config.logger,
2059
+ logLevel: this.config.logLevel,
2060
+ level,
2061
+ event
2062
+ });
2063
+ }
1882
2064
  /**
1883
2065
  * 注册内置 + 自定义工具,或仅 {@link AgentConfig.exclusiveTools}。
1884
2066
  */
@@ -1892,7 +2074,7 @@ var Agent = class _Agent {
1892
2074
  }
1893
2075
  return;
1894
2076
  }
1895
- const builtins = chunkJF5AJQMU_cjs.getAllBuiltinTools(this.skillRegistry, {
2077
+ const builtins = chunkZ45DHTDX_cjs.getAllBuiltinTools(this.skillRegistry, {
1896
2078
  resolve: this.config.askUserQuestion
1897
2079
  }).filter((t) => !this.toolRegistry.isDisallowed(t.name));
1898
2080
  this.toolRegistry.registerMany(builtins);
@@ -1923,7 +2105,14 @@ var Agent = class _Agent {
1923
2105
  await this.initializeMCP(this.config.mcpServers);
1924
2106
  }
1925
2107
  } catch (err) {
1926
- console.error("Failed to initialize:", err);
2108
+ const error = err instanceof Error ? err : new Error(String(err));
2109
+ this.log("error", {
2110
+ component: "agent",
2111
+ event: "agent.initialize.error",
2112
+ message: "Failed to initialize agent resources",
2113
+ errorName: error.name,
2114
+ errorMessage: error.message
2115
+ });
1927
2116
  }
1928
2117
  }
1929
2118
  /**
@@ -1942,7 +2131,17 @@ var Agent = class _Agent {
1942
2131
  try {
1943
2132
  await this.connectMCP(serverConfig);
1944
2133
  } catch (err) {
1945
- console.error(`Failed to connect MCP server "${serverConfig.name}":`, err);
2134
+ const error = err instanceof Error ? err : new Error(String(err));
2135
+ this.log("error", {
2136
+ component: "tooling",
2137
+ event: "mcp.connect.error",
2138
+ message: `Failed to connect MCP server "${serverConfig.name}"`,
2139
+ errorName: error.name,
2140
+ errorMessage: error.message,
2141
+ metadata: {
2142
+ serverName: serverConfig.name
2143
+ }
2144
+ });
1946
2145
  }
1947
2146
  }
1948
2147
  }
@@ -1954,6 +2153,74 @@ var Agent = class _Agent {
1954
2153
  sessionId: this.sessionManager.sessionId ?? void 0
1955
2154
  };
1956
2155
  }
2156
+ baseRunContext() {
2157
+ return {
2158
+ sessionId: this.sessionManager.sessionId ?? void 0,
2159
+ cwd: this.config.cwd
2160
+ };
2161
+ }
2162
+ /**
2163
+ * 分发流式事件到 `callbacks.onEvent` 与 `lifecycle.onModelEvent` / `onModelUsage`。
2164
+ */
2165
+ emitStreamEvent(event) {
2166
+ try {
2167
+ this.config.callbacks?.onEvent?.(event);
2168
+ const lifecycle = this.config.callbacks?.lifecycle;
2169
+ if (lifecycle?.onModelEvent && isModelStreamEventType(event.type)) {
2170
+ lifecycle.onModelEvent(event);
2171
+ }
2172
+ if (event.type === "model_usage" && lifecycle?.onModelUsage) {
2173
+ lifecycle.onModelUsage({
2174
+ ...this.baseRunContext(),
2175
+ usage: event.usage,
2176
+ iteration: event.iteration,
2177
+ phase: event.phase
2178
+ });
2179
+ }
2180
+ } catch (err) {
2181
+ const e = err instanceof Error ? err : new Error(String(err));
2182
+ this.emitAgentError(e, { phase: "lifecycle_callback" });
2183
+ }
2184
+ }
2185
+ /** 标注、触发观察回调并返回供 `yield` 的事件 */
2186
+ streamOut(event, iteration) {
2187
+ const out = iteration !== void 0 ? this.annotateStreamEvent(event, iteration) : this.annotateStreamEvent(event);
2188
+ this.emitStreamEvent(out);
2189
+ return out;
2190
+ }
2191
+ emitAgentError(error, ctx) {
2192
+ try {
2193
+ this.config.callbacks?.lifecycle?.onAgentError?.(error, ctx);
2194
+ this.config.callbacks?.onError?.(error, ctx);
2195
+ } catch (err) {
2196
+ this.log("error", {
2197
+ component: "agent",
2198
+ event: "agent.callback.error",
2199
+ message: "Agent error callback threw",
2200
+ errorName: err instanceof Error ? err.name : "Error",
2201
+ errorMessage: err instanceof Error ? err.message : String(err)
2202
+ });
2203
+ }
2204
+ }
2205
+ safeLifecycleVoid(fn) {
2206
+ try {
2207
+ fn();
2208
+ } catch (err) {
2209
+ const e = err instanceof Error ? err : new Error(String(err));
2210
+ this.emitAgentError(e, { phase: "lifecycle_callback" });
2211
+ }
2212
+ }
2213
+ emitRunEnd(args) {
2214
+ this.safeLifecycleVoid(() => {
2215
+ this.config.callbacks?.lifecycle?.onRunEnd?.({
2216
+ ...this.baseRunContext(),
2217
+ reason: args.reason,
2218
+ iterations: args.iterations,
2219
+ usage: args.usage,
2220
+ error: args.error
2221
+ });
2222
+ });
2223
+ }
1957
2224
  static createEmptySessionUsage() {
1958
2225
  return {
1959
2226
  contextTokens: 0,
@@ -1977,8 +2244,8 @@ var Agent = class _Agent {
1977
2244
  let envSection = "";
1978
2245
  if (shouldIncludeEnv) {
1979
2246
  const cwd = this.config.cwd || process.cwd();
1980
- const envInfo = chunkJF5AJQMU_cjs.getEnvironmentInfo(cwd);
1981
- envSection = chunkJF5AJQMU_cjs.formatEnvironmentSection(envInfo);
2247
+ const envInfo = chunkZ45DHTDX_cjs.getEnvironmentInfo(cwd);
2248
+ envSection = chunkZ45DHTDX_cjs.formatEnvironmentSection(envInfo);
1982
2249
  }
1983
2250
  if (!customPrompt) {
1984
2251
  let basePrompt = DEFAULT_SYSTEM_PROMPT;
@@ -2015,20 +2282,45 @@ ${content}`;
2015
2282
  }
2016
2283
  try {
2017
2284
  this.messages = await this.sessionManager.resumeSession(options.sessionId);
2285
+ this.safeLifecycleVoid(() => {
2286
+ this.config.callbacks?.lifecycle?.onSessionResume?.({
2287
+ sessionId: options.sessionId,
2288
+ messageCount: this.messages.length
2289
+ });
2290
+ });
2018
2291
  } catch {
2019
2292
  this.sessionManager.createSession(options.sessionId);
2293
+ this.safeLifecycleVoid(() => {
2294
+ this.config.callbacks?.lifecycle?.onSessionCreate?.({
2295
+ sessionId: this.sessionManager.sessionId ?? void 0
2296
+ });
2297
+ });
2020
2298
  }
2021
2299
  } else if (!this.sessionManager.sessionId) {
2022
2300
  this.resetSessionState();
2023
2301
  this.sessionManager.createSession();
2302
+ this.safeLifecycleVoid(() => {
2303
+ this.config.callbacks?.lifecycle?.onSessionCreate?.({
2304
+ sessionId: this.sessionManager.sessionId ?? void 0
2305
+ });
2306
+ });
2024
2307
  }
2025
2308
  if (this.messages.length === 0) {
2309
+ const usedRuntimePrompt = options?.systemPrompt !== void 0;
2026
2310
  const systemPrompt = this.buildSystemPrompt(
2027
2311
  options?.systemPrompt || this.config.systemPrompt
2028
2312
  );
2029
- this.messages.push({
2313
+ const sysMsg = {
2030
2314
  role: "system",
2031
2315
  content: systemPrompt
2316
+ };
2317
+ this.messages.push(sysMsg);
2318
+ this.safeLifecycleVoid(() => {
2319
+ this.config.callbacks?.lifecycle?.onSystemMessage?.(
2320
+ sysMsg,
2321
+ usedRuntimePrompt ? "runtime_prompt" : "default_prompt",
2322
+ this.baseRunContext()
2323
+ );
2032
2324
  });
2033
2325
  }
2034
2326
  if (this.config.memory !== false) {
@@ -2037,9 +2329,13 @@ ${content}`;
2037
2329
  const memoryManager = new MemoryManager(this.config.cwd, this.config.memoryConfig, this.config.userBasePath);
2038
2330
  const memoryContent = memoryManager.loadMemory();
2039
2331
  if (memoryContent) {
2040
- this.messages.push({
2332
+ const memMsg = {
2041
2333
  role: "system",
2042
2334
  content: memoryContent
2335
+ };
2336
+ this.messages.push(memMsg);
2337
+ this.safeLifecycleVoid(() => {
2338
+ this.config.callbacks?.lifecycle?.onSystemMessage?.(memMsg, "memory", this.baseRunContext());
2043
2339
  });
2044
2340
  }
2045
2341
  }
@@ -2049,21 +2345,60 @@ ${content}`;
2049
2345
  if (processed.invoked) {
2050
2346
  processedInput = processed.prompt;
2051
2347
  }
2052
- this.messages.push({
2348
+ const userMsg = {
2053
2349
  role: "user",
2054
2350
  content: processedInput
2351
+ };
2352
+ this.messages.push(userMsg);
2353
+ this.safeLifecycleVoid(() => {
2354
+ this.config.callbacks?.lifecycle?.onUserMessage?.(
2355
+ userMsg,
2356
+ processed.invoked ? "processed_input" : "raw_input",
2357
+ this.baseRunContext()
2358
+ );
2055
2359
  });
2056
- yield this.annotateStreamEvent({ type: "start", timestamp: Date.now() });
2360
+ this.log("info", {
2361
+ component: "agent",
2362
+ event: "agent.run.start",
2363
+ message: "Starting agent turn",
2364
+ sessionId: this.sessionManager.sessionId ?? void 0,
2365
+ metadata: {
2366
+ inputLength: input.length,
2367
+ processedInputLength: processedInput.length,
2368
+ includeRawStreamEvents: options?.includeRawStreamEvents === true
2369
+ }
2370
+ });
2371
+ this.safeLifecycleVoid(() => {
2372
+ this.config.callbacks?.lifecycle?.onRunStart?.({
2373
+ ...this.baseRunContext(),
2374
+ inputLength: input.length,
2375
+ processedInputLength: processedInput.length,
2376
+ resumeSessionId: options?.sessionId
2377
+ });
2378
+ });
2379
+ yield this.streamOut({ type: "start", timestamp: Date.now() });
2057
2380
  try {
2058
- const maxIterations = this.config.maxIterations || 10;
2381
+ const maxIterations = Math.max(1, this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS);
2059
2382
  let totalUsage = {
2060
2383
  promptTokens: 0,
2061
2384
  completionTokens: 0,
2062
2385
  totalTokens: 0
2063
2386
  };
2064
- for (let iteration = 0; iteration < maxIterations; iteration++) {
2387
+ let iteration = 0;
2388
+ for (; iteration < maxIterations; iteration++) {
2065
2389
  if (signal?.aborted) {
2066
- yield this.annotateStreamEvent(
2390
+ this.log("info", {
2391
+ component: "agent",
2392
+ event: "agent.run.aborted",
2393
+ message: "Agent turn aborted before model request",
2394
+ sessionId: this.sessionManager.sessionId ?? void 0,
2395
+ iteration
2396
+ });
2397
+ this.emitRunEnd({ reason: "aborted", iterations: iteration, usage: totalUsage });
2398
+ this.safeLifecycleVoid(() => {
2399
+ this.config.callbacks?.lifecycle?.onRunAbort?.({ ...this.baseRunContext(), iteration });
2400
+ });
2401
+ yield this.streamOut(
2067
2402
  {
2068
2403
  type: "end",
2069
2404
  usage: totalUsage,
@@ -2074,17 +2409,60 @@ ${content}`;
2074
2409
  );
2075
2410
  return;
2076
2411
  }
2412
+ this.log("debug", {
2413
+ component: "agent",
2414
+ event: "agent.iteration.start",
2415
+ message: "Starting agent iteration",
2416
+ sessionId: this.sessionManager.sessionId ?? void 0,
2417
+ iteration,
2418
+ metadata: {
2419
+ messageCount: this.messages.length,
2420
+ toolCount: this.toolRegistry.getAll().length
2421
+ }
2422
+ });
2423
+ this.safeLifecycleVoid(() => {
2424
+ this.config.callbacks?.lifecycle?.onIterationStart?.({
2425
+ ...this.baseRunContext(),
2426
+ iteration,
2427
+ messageCount: this.messages.length,
2428
+ toolCount: this.toolRegistry.getAll().length
2429
+ });
2430
+ });
2077
2431
  const contextEvents = await this.checkContextCompression();
2078
2432
  for (const event of contextEvents) {
2079
- yield this.annotateStreamEvent(event, iteration);
2433
+ if (event.type === "context_compressed") {
2434
+ this.safeLifecycleVoid(() => {
2435
+ this.config.callbacks?.lifecycle?.onContextCompressed?.({
2436
+ ...this.baseRunContext(),
2437
+ iteration,
2438
+ stats: event.stats
2439
+ });
2440
+ });
2441
+ }
2442
+ yield this.streamOut(event, iteration);
2080
2443
  }
2444
+ this.safeLifecycleVoid(() => {
2445
+ this.config.callbacks?.lifecycle?.onModelRequestStart?.({
2446
+ ...this.baseRunContext(),
2447
+ iteration,
2448
+ messageCount: this.messages.length,
2449
+ toolCount: this.toolRegistry.getAll().length,
2450
+ temperature: this.config.temperature,
2451
+ maxTokens: this.config.maxTokens,
2452
+ includeRawStreamEvents: options?.includeRawStreamEvents
2453
+ });
2454
+ });
2081
2455
  const modelParams = {
2082
2456
  messages: this.messages,
2083
2457
  tools: this.toolRegistry.getAll(),
2084
2458
  temperature: this.config.temperature,
2085
2459
  maxTokens: this.config.maxTokens,
2086
2460
  signal,
2087
- includeRawStreamEvents: options?.includeRawStreamEvents
2461
+ includeRawStreamEvents: options?.includeRawStreamEvents,
2462
+ sessionId: this.sessionManager.sessionId ?? void 0,
2463
+ logger: this.config.logger,
2464
+ logLevel: this.config.logLevel,
2465
+ redaction: this.config.redaction
2088
2466
  };
2089
2467
  const stream = this.config.model.stream(modelParams);
2090
2468
  let hasToolCalls = false;
@@ -2127,7 +2505,7 @@ ${content}`;
2127
2505
  for await (const chunk of stream) {
2128
2506
  if (signal?.aborted) {
2129
2507
  for (const event of chunkProcessor.flush()) {
2130
- const out = this.annotateStreamEvent(event, iteration);
2508
+ const out = this.streamOut(event, iteration);
2131
2509
  yield out;
2132
2510
  applyStreamOut(out);
2133
2511
  }
@@ -2143,13 +2521,37 @@ ${content}`;
2143
2521
  ];
2144
2522
  }
2145
2523
  this.messages.push(assistantMessage2);
2524
+ this.safeLifecycleVoid(() => {
2525
+ this.config.callbacks?.lifecycle?.onAssistantMessage?.(assistantMessage2, {
2526
+ ...this.baseRunContext(),
2527
+ iteration
2528
+ });
2529
+ });
2146
2530
  }
2147
- this.messages.push({
2531
+ const interruptMsg = {
2148
2532
  role: "user",
2149
2533
  content: "[User interrupted the response]"
2534
+ };
2535
+ this.messages.push(interruptMsg);
2536
+ this.safeLifecycleVoid(() => {
2537
+ this.config.callbacks?.lifecycle?.onUserMessage?.(
2538
+ interruptMsg,
2539
+ "interruption_marker",
2540
+ this.baseRunContext()
2541
+ );
2150
2542
  });
2151
2543
  await this.sessionManager.saveMessages(this.messages);
2152
- yield this.annotateStreamEvent(
2544
+ this.safeLifecycleVoid(() => {
2545
+ this.config.callbacks?.lifecycle?.onMessagePersist?.({
2546
+ ...this.baseRunContext(),
2547
+ messageCount: this.messages.length
2548
+ });
2549
+ });
2550
+ this.emitRunEnd({ reason: "aborted", iterations: iteration + 1, usage: totalUsage });
2551
+ this.safeLifecycleVoid(() => {
2552
+ this.config.callbacks?.lifecycle?.onRunAbort?.({ ...this.baseRunContext(), iteration });
2553
+ });
2554
+ yield this.streamOut(
2153
2555
  {
2154
2556
  type: "end",
2155
2557
  usage: totalUsage,
@@ -2163,9 +2565,18 @@ ${content}`;
2163
2565
  }
2164
2566
  const events = chunkProcessor.processChunk(chunk);
2165
2567
  for (const event of events) {
2166
- const out = this.annotateStreamEvent(event, iteration);
2568
+ const out = this.streamOut(event, iteration);
2167
2569
  yield out;
2168
2570
  applyStreamOut(out);
2571
+ if (out.type === "end" && out.reason === "error" && out.error) {
2572
+ this.emitAgentError(out.error, { phase: "model", iteration });
2573
+ this.safeLifecycleVoid(() => {
2574
+ this.config.callbacks?.lifecycle?.onModelRequestError?.(out.error, {
2575
+ phase: "model",
2576
+ iteration
2577
+ });
2578
+ });
2579
+ }
2169
2580
  if (out.type === "end" && out.reason === "error") {
2170
2581
  fatalModelError = true;
2171
2582
  break;
@@ -2179,10 +2590,13 @@ ${content}`;
2179
2590
  return;
2180
2591
  }
2181
2592
  for (const event of chunkProcessor.flush()) {
2182
- const out = this.annotateStreamEvent(event, iteration);
2593
+ const out = this.streamOut(event, iteration);
2183
2594
  yield out;
2184
2595
  applyStreamOut(out);
2185
2596
  }
2597
+ this.safeLifecycleVoid(() => {
2598
+ this.config.callbacks?.lifecycle?.onModelRequestEnd?.({ ...this.baseRunContext(), iteration });
2599
+ });
2186
2600
  const assistantMessage = {
2187
2601
  role: "assistant",
2188
2602
  content: assistantContent
@@ -2204,13 +2618,36 @@ ${content}`;
2204
2618
  assistantMessage.toolCalls = toolCalls;
2205
2619
  }
2206
2620
  this.messages.push(assistantMessage);
2621
+ this.safeLifecycleVoid(() => {
2622
+ this.config.callbacks?.lifecycle?.onAssistantMessage?.(assistantMessage, {
2623
+ ...this.baseRunContext(),
2624
+ iteration
2625
+ });
2626
+ });
2207
2627
  if (!hasToolCalls) {
2628
+ this.log("debug", {
2629
+ component: "agent",
2630
+ event: "agent.iteration.end",
2631
+ message: "Iteration completed without tool calls",
2632
+ sessionId: this.sessionManager.sessionId ?? void 0,
2633
+ iteration,
2634
+ metadata: {
2635
+ assistantContentLength: assistantContent.length
2636
+ }
2637
+ });
2638
+ this.safeLifecycleVoid(() => {
2639
+ this.config.callbacks?.lifecycle?.onIterationEnd?.({
2640
+ ...this.baseRunContext(),
2641
+ iteration,
2642
+ hadToolCalls: false
2643
+ });
2644
+ });
2208
2645
  break;
2209
2646
  }
2210
- const toolResults = await this.executeTools(toolCalls);
2647
+ const toolResults = await this.executeTools(toolCalls, iteration);
2211
2648
  for (const result of toolResults) {
2212
2649
  if (result.isError && result.error) {
2213
- yield this.annotateStreamEvent(
2650
+ yield this.streamOut(
2214
2651
  {
2215
2652
  type: "tool_error",
2216
2653
  toolCallId: result.toolCallId,
@@ -2219,7 +2656,7 @@ ${content}`;
2219
2656
  iteration
2220
2657
  );
2221
2658
  }
2222
- yield this.annotateStreamEvent(
2659
+ yield this.streamOut(
2223
2660
  {
2224
2661
  type: "tool_result",
2225
2662
  toolCallId: result.toolCallId,
@@ -2227,38 +2664,110 @@ ${content}`;
2227
2664
  },
2228
2665
  iteration
2229
2666
  );
2230
- this.messages.push({
2667
+ const toolMsg = {
2231
2668
  role: "tool",
2232
2669
  toolCallId: result.toolCallId,
2233
2670
  content: result.content
2671
+ };
2672
+ this.messages.push(toolMsg);
2673
+ this.safeLifecycleVoid(() => {
2674
+ this.config.callbacks?.lifecycle?.onToolMessage?.(toolMsg, {
2675
+ ...this.baseRunContext(),
2676
+ iteration,
2677
+ toolCallId: result.toolCallId
2678
+ });
2234
2679
  });
2235
2680
  }
2681
+ this.log("debug", {
2682
+ component: "agent",
2683
+ event: "agent.iteration.end",
2684
+ message: "Iteration completed with tool calls",
2685
+ sessionId: this.sessionManager.sessionId ?? void 0,
2686
+ iteration,
2687
+ metadata: {
2688
+ toolCallCount: toolCalls.length,
2689
+ toolResultCount: toolResults.length
2690
+ }
2691
+ });
2692
+ this.safeLifecycleVoid(() => {
2693
+ this.config.callbacks?.lifecycle?.onIterationEnd?.({
2694
+ ...this.baseRunContext(),
2695
+ iteration,
2696
+ hadToolCalls: true
2697
+ });
2698
+ });
2236
2699
  }
2237
2700
  await this.sessionManager.saveMessages(this.messages);
2238
- yield this.annotateStreamEvent({
2701
+ this.safeLifecycleVoid(() => {
2702
+ this.config.callbacks?.lifecycle?.onMessagePersist?.({
2703
+ ...this.baseRunContext(),
2704
+ messageCount: this.messages.length
2705
+ });
2706
+ });
2707
+ const finishedByIterationCap = iteration >= maxIterations;
2708
+ const sessionIterations = finishedByIterationCap ? maxIterations : iteration + 1;
2709
+ yield this.streamOut({
2239
2710
  type: "session_summary",
2240
2711
  usage: totalUsage,
2241
- iterations: Math.min(maxIterations, this.messages.length)
2712
+ iterations: sessionIterations
2242
2713
  });
2243
- yield this.annotateStreamEvent({
2714
+ this.emitRunEnd({
2715
+ reason: finishedByIterationCap ? "max_iterations" : "complete",
2716
+ iterations: sessionIterations,
2717
+ usage: totalUsage
2718
+ });
2719
+ yield this.streamOut({
2244
2720
  type: "end",
2245
2721
  timestamp: Date.now(),
2246
- reason: "complete"
2722
+ reason: finishedByIterationCap ? "max_iterations" : "complete"
2723
+ });
2724
+ this.log("info", {
2725
+ component: "agent",
2726
+ event: "agent.run.end",
2727
+ message: finishedByIterationCap ? "Agent turn stopped at max iterations" : "Agent turn completed",
2728
+ sessionId: this.sessionManager.sessionId ?? void 0,
2729
+ metadata: {
2730
+ iterations: sessionIterations,
2731
+ promptTokens: totalUsage.promptTokens,
2732
+ completionTokens: totalUsage.completionTokens,
2733
+ totalTokens: totalUsage.totalTokens
2734
+ }
2247
2735
  });
2248
2736
  } catch (error) {
2249
2737
  if (error.name === "AbortError") {
2250
- yield this.annotateStreamEvent({
2738
+ this.log("info", {
2739
+ component: "agent",
2740
+ event: "agent.run.aborted",
2741
+ message: "Agent turn aborted",
2742
+ sessionId: this.sessionManager.sessionId ?? void 0
2743
+ });
2744
+ this.emitRunEnd({ reason: "aborted", iterations: 0 });
2745
+ this.safeLifecycleVoid(() => {
2746
+ this.config.callbacks?.lifecycle?.onRunAbort?.({ ...this.baseRunContext() });
2747
+ });
2748
+ yield this.streamOut({
2251
2749
  type: "end",
2252
2750
  timestamp: Date.now(),
2253
2751
  reason: "aborted"
2254
2752
  });
2255
2753
  return;
2256
2754
  }
2257
- yield this.annotateStreamEvent({
2755
+ const err = error instanceof Error ? error : new Error(String(error));
2756
+ this.log("error", {
2757
+ component: "agent",
2758
+ event: "agent.run.error",
2759
+ message: "Agent turn failed",
2760
+ sessionId: this.sessionManager.sessionId ?? void 0,
2761
+ errorName: err.name,
2762
+ errorMessage: err.message
2763
+ });
2764
+ this.emitAgentError(err, { phase: "run" });
2765
+ this.emitRunEnd({ reason: "error", iterations: 0, error: err });
2766
+ yield this.streamOut({
2258
2767
  type: "end",
2259
2768
  timestamp: Date.now(),
2260
2769
  reason: "error",
2261
- error
2770
+ error: err
2262
2771
  });
2263
2772
  }
2264
2773
  }
@@ -2350,6 +2859,12 @@ ${content}`;
2350
2859
  getSkillRegistry() {
2351
2860
  return this.skillRegistry;
2352
2861
  }
2862
+ /**
2863
+ * 解析后的模型适配器(`modelConfig` 已在构造时合并 `env` 并实例化)。
2864
+ */
2865
+ getModel() {
2866
+ return this.config.model;
2867
+ }
2353
2868
  /**
2354
2869
  * 处理用户输入,检测并处理 skill 调用
2355
2870
  * @param input 用户输入
@@ -2435,10 +2950,16 @@ ARGUMENTS: ${args}`;
2435
2950
  if (!this.mcpAdapter) {
2436
2951
  this.mcpAdapter = new MCPAdapter();
2437
2952
  }
2438
- await this.mcpAdapter.addServer(toMCPClientConfig(config));
2953
+ const resolved = config.transport === "stdio" ? {
2954
+ ...config,
2955
+ env: chunkNYZD3THB_cjs.mergeMcpStdioEnv(this.config.env, config.env),
2956
+ cwd: (config.cwd ?? "").trim() || (this.config.cwd || process.cwd())
2957
+ } : config;
2958
+ await this.mcpAdapter.addServer(resolved);
2439
2959
  const mcpTools = this.mcpAdapter.getToolDefinitions();
2960
+ const serverPrefix = formatMcpToolName(config.name, "");
2440
2961
  for (const tool of mcpTools) {
2441
- if (!tool.name.startsWith(`mcp_${config.name}__`)) {
2962
+ if (!tool.name.startsWith(serverPrefix)) {
2442
2963
  continue;
2443
2964
  }
2444
2965
  if (this.toolRegistry.isDisallowed(tool.name)) {
@@ -2454,7 +2975,7 @@ ARGUMENTS: ${args}`;
2454
2975
  if (!this.mcpAdapter) return;
2455
2976
  const tools = this.toolRegistry.getAll();
2456
2977
  for (const tool of tools) {
2457
- if (tool.name.startsWith(`mcp_${name}__`)) {
2978
+ if (tool.name.startsWith(formatMcpToolName(name, ""))) {
2458
2979
  this.toolRegistry.unregister(tool.name);
2459
2980
  }
2460
2981
  }
@@ -2467,7 +2988,7 @@ ARGUMENTS: ${args}`;
2467
2988
  if (!this.mcpAdapter) return;
2468
2989
  const tools = this.toolRegistry.getAll();
2469
2990
  for (const tool of tools) {
2470
- if (tool.name.startsWith("mcp_") && tool.name.includes("__")) {
2991
+ if (isMcpPrefixedToolName(tool.name)) {
2471
2992
  this.toolRegistry.unregister(tool.name);
2472
2993
  }
2473
2994
  }
@@ -2640,7 +3161,10 @@ ${additionalContent}`;
2640
3161
  const normalizedType = request.subagent_type ?? "general-purpose";
2641
3162
  const requestedTimeout = request.timeout_ms ?? subagentConfig.timeoutMs;
2642
3163
  const timeoutMs = Math.min(requestedTimeout, subagentConfig.timeoutMs);
2643
- const maxIterations = Math.max(1, request.max_iterations ?? this.config.maxIterations ?? 50);
3164
+ const maxIterations = Math.max(
3165
+ 1,
3166
+ request.max_iterations ?? this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS
3167
+ );
2644
3168
  const resolved = this.resolveSubagentTools(request);
2645
3169
  if (!resolved.tools) {
2646
3170
  return {
@@ -2712,21 +3236,158 @@ ${additionalContent}`;
2712
3236
  /**
2713
3237
  * 执行工具调用
2714
3238
  */
2715
- async executeTools(toolCalls) {
3239
+ async executeTools(toolCalls, iteration) {
2716
3240
  const results = await Promise.all(
2717
3241
  toolCalls.map(async (tc) => {
2718
- const result = await this.toolRegistry.execute(tc.name, tc.arguments, {
2719
- toolCallId: tc.id,
2720
- projectDir: this.config.cwd || process.cwd(),
2721
- agentDepth: this.agentDepth
3242
+ this.safeLifecycleVoid(() => {
3243
+ this.config.callbacks?.lifecycle?.onToolCallPlanned?.(tc, {
3244
+ ...this.baseRunContext(),
3245
+ iteration
3246
+ });
2722
3247
  });
2723
- const isError = Boolean(result.isError);
2724
- return {
2725
- toolCallId: tc.id,
2726
- content: isError ? `Error: ${result.content}` : result.content,
2727
- isError,
2728
- error: isError ? new Error(result.content) : void 0
2729
- };
3248
+ const startedAt = Date.now();
3249
+ this.safeLifecycleVoid(() => {
3250
+ this.config.callbacks?.lifecycle?.onToolExecutionStart?.({
3251
+ ...this.baseRunContext(),
3252
+ iteration,
3253
+ toolCallId: tc.id,
3254
+ toolName: tc.name,
3255
+ arguments: tc.arguments,
3256
+ projectDir: this.config.cwd || process.cwd(),
3257
+ agentDepth: this.agentDepth
3258
+ });
3259
+ });
3260
+ this.log("info", {
3261
+ component: "tooling",
3262
+ event: "tool.call.start",
3263
+ message: "Executing tool call",
3264
+ sessionId: this.sessionManager.sessionId ?? void 0,
3265
+ toolName: tc.name,
3266
+ toolCallId: tc.id
3267
+ });
3268
+ try {
3269
+ const result = await this.toolRegistry.execute(tc.name, tc.arguments, {
3270
+ toolCallId: tc.id,
3271
+ projectDir: this.config.cwd || process.cwd(),
3272
+ agentDepth: this.agentDepth
3273
+ });
3274
+ const durationMs = Date.now() - startedAt;
3275
+ const isError = Boolean(result.isError);
3276
+ const error = isError ? new Error(result.content) : void 0;
3277
+ this.safeLifecycleVoid(() => {
3278
+ this.config.callbacks?.lifecycle?.onToolExecutionEnd?.({
3279
+ ...this.baseRunContext(),
3280
+ iteration,
3281
+ toolCallId: tc.id,
3282
+ toolName: tc.name,
3283
+ arguments: tc.arguments,
3284
+ projectDir: this.config.cwd || process.cwd(),
3285
+ agentDepth: this.agentDepth,
3286
+ durationMs,
3287
+ isError,
3288
+ executionError: void 0
3289
+ });
3290
+ });
3291
+ this.safeLifecycleVoid(() => {
3292
+ this.config.callbacks?.lifecycle?.onToolResult?.({
3293
+ ...this.baseRunContext(),
3294
+ iteration,
3295
+ toolCallId: tc.id,
3296
+ toolName: tc.name,
3297
+ arguments: tc.arguments,
3298
+ projectDir: this.config.cwd || process.cwd(),
3299
+ agentDepth: this.agentDepth,
3300
+ durationMs,
3301
+ isError,
3302
+ result
3303
+ });
3304
+ });
3305
+ this.log(isError ? "warn" : "info", {
3306
+ component: "tooling",
3307
+ event: isError ? "tool.call.error" : "tool.call.end",
3308
+ message: isError ? "Tool call returned an error" : "Tool call completed",
3309
+ sessionId: this.sessionManager.sessionId ?? void 0,
3310
+ toolName: tc.name,
3311
+ toolCallId: tc.id,
3312
+ durationMs,
3313
+ ...error ? {
3314
+ errorName: error.name,
3315
+ errorMessage: error.message
3316
+ } : {},
3317
+ metadata: {
3318
+ resultLength: result.content.length
3319
+ }
3320
+ });
3321
+ return {
3322
+ toolCallId: tc.id,
3323
+ content: isError ? `Error: ${result.content}` : result.content,
3324
+ isError,
3325
+ error
3326
+ };
3327
+ } catch (error) {
3328
+ const err = error instanceof Error ? error : new Error(String(error));
3329
+ const durationMs = Date.now() - startedAt;
3330
+ const synthetic = { content: err.message, isError: true };
3331
+ this.emitAgentError(err, {
3332
+ phase: "tool",
3333
+ toolName: tc.name,
3334
+ toolCallId: tc.id,
3335
+ iteration
3336
+ });
3337
+ this.safeLifecycleVoid(() => {
3338
+ this.config.callbacks?.lifecycle?.onToolExecutionError?.(err, {
3339
+ phase: "tool",
3340
+ toolName: tc.name,
3341
+ toolCallId: tc.id,
3342
+ iteration
3343
+ });
3344
+ });
3345
+ this.safeLifecycleVoid(() => {
3346
+ this.config.callbacks?.lifecycle?.onToolExecutionEnd?.({
3347
+ ...this.baseRunContext(),
3348
+ iteration,
3349
+ toolCallId: tc.id,
3350
+ toolName: tc.name,
3351
+ arguments: tc.arguments,
3352
+ projectDir: this.config.cwd || process.cwd(),
3353
+ agentDepth: this.agentDepth,
3354
+ durationMs,
3355
+ isError: true,
3356
+ executionError: err
3357
+ });
3358
+ });
3359
+ this.safeLifecycleVoid(() => {
3360
+ this.config.callbacks?.lifecycle?.onToolResult?.({
3361
+ ...this.baseRunContext(),
3362
+ iteration,
3363
+ toolCallId: tc.id,
3364
+ toolName: tc.name,
3365
+ arguments: tc.arguments,
3366
+ projectDir: this.config.cwd || process.cwd(),
3367
+ agentDepth: this.agentDepth,
3368
+ durationMs,
3369
+ isError: true,
3370
+ result: synthetic
3371
+ });
3372
+ });
3373
+ this.log("error", {
3374
+ component: "tooling",
3375
+ event: "tool.call.error",
3376
+ message: "Tool call threw an exception",
3377
+ sessionId: this.sessionManager.sessionId ?? void 0,
3378
+ toolName: tc.name,
3379
+ toolCallId: tc.id,
3380
+ durationMs,
3381
+ errorName: err.name,
3382
+ errorMessage: err.message
3383
+ });
3384
+ return {
3385
+ toolCallId: tc.id,
3386
+ content: `Error: ${err.message}`,
3387
+ isError: true,
3388
+ error: err
3389
+ };
3390
+ }
2730
3391
  })
2731
3392
  );
2732
3393
  return results;
@@ -2770,7 +3431,8 @@ function transformConfig(config) {
2770
3431
  ...transport === "stdio" ? {
2771
3432
  command: serverConfig.command,
2772
3433
  args: serverConfig.args,
2773
- env: serverConfig.env
3434
+ env: serverConfig.env,
3435
+ cwd: serverConfig.cwd
2774
3436
  } : {
2775
3437
  url: serverConfig.url,
2776
3438
  headers: serverConfig.headers
@@ -2852,12 +3514,15 @@ function validateMCPConfig(config) {
2852
3514
  }
2853
3515
 
2854
3516
  exports.Agent = Agent;
3517
+ exports.DEFAULT_MAX_ITERATIONS = DEFAULT_MAX_ITERATIONS;
2855
3518
  exports.DEFAULT_SYSTEM_PROMPT = DEFAULT_SYSTEM_PROMPT;
2856
3519
  exports.JsonlStorage = JsonlStorage;
2857
3520
  exports.MCPAdapter = MCPAdapter;
2858
3521
  exports.MCPClient = MCPClient;
3522
+ exports.MODEL_STREAM_EVENT_TYPES = MODEL_STREAM_EVENT_TYPES;
2859
3523
  exports.MemoryManager = MemoryManager;
2860
3524
  exports.MemoryStorage = MemoryStorage;
3525
+ exports.PACKAGE_VERSION = PACKAGE_VERSION;
2861
3526
  exports.SessionManager = SessionManager;
2862
3527
  exports.SkillLoader = SkillLoader;
2863
3528
  exports.SkillRegistry = SkillRegistry;
@@ -2871,10 +3536,13 @@ exports.createSessionManager = createSessionManager;
2871
3536
  exports.createSkillLoader = createSkillLoader;
2872
3537
  exports.createSkillRegistry = createSkillRegistry;
2873
3538
  exports.createStorage = createStorage;
3539
+ exports.formatMcpToolName = formatMcpToolName;
2874
3540
  exports.getLatestSessionId = getLatestSessionId;
2875
3541
  exports.getSessionStoragePath = getSessionStoragePath;
3542
+ exports.isMcpPrefixedToolName = isMcpPrefixedToolName;
3543
+ exports.isModelStreamEventType = isModelStreamEventType;
2876
3544
  exports.loadMCPConfig = loadMCPConfig;
2877
3545
  exports.parseSkillMd = parseSkillMd;
2878
3546
  exports.validateMCPConfig = validateMCPConfig;
2879
- //# sourceMappingURL=chunk-5QMA2YBY.cjs.map
2880
- //# sourceMappingURL=chunk-5QMA2YBY.cjs.map
3547
+ //# sourceMappingURL=chunk-6X7EYQLS.cjs.map
3548
+ //# sourceMappingURL=chunk-6X7EYQLS.cjs.map