@linnlabs/linnkit 0.8.0 → 0.10.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 (83) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/bin/linnkit.cjs +7 -0
  5. package/dist/{agentSpec-EkmviZjy.d.cts → agentSpec-Du4Iye0q.d.cts} +16 -1
  6. package/dist/{agentSpec-EkmviZjy.d.ts → agentSpec-Du4Iye0q.d.ts} +16 -1
  7. package/dist/cli.cjs +234 -91
  8. package/dist/cli.cjs.map +1 -1
  9. package/dist/cli.js +234 -91
  10. package/dist/cli.js.map +1 -1
  11. package/dist/context-manager.cjs +230 -32
  12. package/dist/context-manager.cjs.map +1 -1
  13. package/dist/context-manager.d.cts +52 -15
  14. package/dist/context-manager.d.ts +52 -15
  15. package/dist/context-manager.js +230 -33
  16. package/dist/context-manager.js.map +1 -1
  17. package/dist/{context-trace-HE2qY5Q-.d.cts → context-trace-BHKDS-eq.d.cts} +2 -2
  18. package/dist/{context-trace-DRi5M4lX.d.ts → context-trace-CHbqHmyE.d.ts} +2 -2
  19. package/dist/contracts.cjs +3 -1
  20. package/dist/contracts.cjs.map +1 -1
  21. package/dist/contracts.d.cts +3 -3
  22. package/dist/contracts.d.ts +3 -3
  23. package/dist/contracts.js +3 -1
  24. package/dist/contracts.js.map +1 -1
  25. package/dist/{defaultGraphExecutor-BBswR8wn.d.ts → defaultGraphExecutor-B29_qTHy.d.ts} +16 -15
  26. package/dist/{defaultGraphExecutor-BIjJj7WF.d.cts → defaultGraphExecutor-C2E59v_R.d.cts} +16 -15
  27. package/dist/{index-Cm-JbzTH.d.cts → index-BAaUP9yU.d.cts} +38 -15
  28. package/dist/{index-DRBWi1fy.d.ts → index-BaVpVNi2.d.ts} +38 -15
  29. package/dist/{index-DO4dQgf2.d.cts → index-BnYCS8Zg.d.cts} +2 -2
  30. package/dist/{index-CJeWHopy.d.ts → index-C0DAjsdX.d.ts} +2 -2
  31. package/dist/{index-Dl5PLgAv.d.cts → index-CKQzzZ5Y.d.cts} +2 -2
  32. package/dist/{index-CHqwkvGp.d.ts → index-D0mKxTR5.d.ts} +2 -2
  33. package/dist/index.cjs +327 -110
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +10 -10
  36. package/dist/index.d.ts +10 -10
  37. package/dist/index.js +327 -110
  38. package/dist/index.js.map +1 -1
  39. package/dist/{ports-DnLuKfpE.d.ts → ports-DpPTFhSd.d.ts} +2 -2
  40. package/dist/{ports-DaatKJXp.d.cts → ports-s-tSp3sB.d.cts} +2 -2
  41. package/dist/quickstart.cjs +232 -88
  42. package/dist/quickstart.cjs.map +1 -1
  43. package/dist/quickstart.d.cts +7 -7
  44. package/dist/quickstart.d.ts +7 -7
  45. package/dist/quickstart.js +232 -88
  46. package/dist/quickstart.js.map +1 -1
  47. package/dist/{runAgent-CPj_9e58.d.ts → runAgent-C6F-399C.d.ts} +5 -5
  48. package/dist/{runAgent-HYKlXbVr.d.cts → runAgent-ilEj66Ik.d.cts} +5 -5
  49. package/dist/{runHandle-D3gPsD7B.d.cts → runHandle-BNOqS-Bl.d.cts} +3 -3
  50. package/dist/{runHandle-CyXvzgzk.d.ts → runHandle-BdLXOFqF.d.ts} +3 -3
  51. package/dist/runtime-kernel/events.cjs +1 -0
  52. package/dist/runtime-kernel/events.cjs.map +1 -1
  53. package/dist/runtime-kernel/events.d.cts +4 -4
  54. package/dist/runtime-kernel/events.d.ts +4 -4
  55. package/dist/runtime-kernel/events.js +1 -0
  56. package/dist/runtime-kernel/events.js.map +1 -1
  57. package/dist/runtime-kernel.cjs +318 -103
  58. package/dist/runtime-kernel.cjs.map +1 -1
  59. package/dist/runtime-kernel.d.cts +8 -8
  60. package/dist/runtime-kernel.d.ts +8 -8
  61. package/dist/runtime-kernel.js +315 -104
  62. package/dist/runtime-kernel.js.map +1 -1
  63. package/dist/testkit.cjs +331 -116
  64. package/dist/testkit.cjs.map +1 -1
  65. package/dist/testkit.d.cts +8 -8
  66. package/dist/testkit.d.ts +8 -8
  67. package/dist/testkit.js +331 -116
  68. package/dist/testkit.js.map +1 -1
  69. package/dist/{todo-B1PmDlp3.d.cts → todo-Ca8llpRQ.d.cts} +1 -1
  70. package/dist/{todo-B1PmDlp3.d.ts → todo-Ca8llpRQ.d.ts} +1 -1
  71. package/dist/{toolContracts-CLkQmhTG.d.cts → toolContracts-Bm3EZ1UM.d.cts} +13 -2
  72. package/dist/{toolContracts-Blll0241.d.ts → toolContracts-f8lzZBNa.d.ts} +13 -2
  73. package/docs/integration/README.md +1 -1
  74. package/docs/integration/agent-registration-guide.md +1 -1
  75. package/docs/integration/child-runs.md +4 -1
  76. package/docs/integration/context-engineering.md +30 -15
  77. package/docs/integration/context-fences.md +32 -3
  78. package/docs/integration/llm-provider.md +1 -1
  79. package/docs/integration/persistence.md +1 -0
  80. package/docs/integration/run-supervisor.md +3 -0
  81. package/docs/integration/tool-development-guide.md +7 -5
  82. package/docs/integration/tool-history.md +43 -17
  83. package/package.json +5 -4
@@ -499,6 +499,7 @@ var AgentSpecBudgetPolicy = zod.z.object({
499
499
  });
500
500
  var AgentSpecToolHistoryPolicy = zod.z.object({
501
501
  strategy: zod.z.enum(["per-pair", "per-run", "none"]).optional(),
502
+ retentionMode: zod.z.enum(["drop", "compress"]).optional(),
502
503
  keepLatestToolPairs: zod.z.number().int().nonnegative().optional(),
503
504
  keepLatestRuns: zod.z.number().int().nonnegative().optional(),
504
505
  maxInteractionGroups: zod.z.number().int().nonnegative().optional(),
@@ -613,12 +614,13 @@ var AgentSpecContextPolicy = zod.z.object({
613
614
  var DEFAULT_CONTEXT_POLICY = {
614
615
  profileId: "agent",
615
616
  budget: {
616
- maxTokens: 12e4,
617
+ maxTokens: 232e3,
617
618
  reservedForResponse: 2400,
618
619
  workingMemoryBudgetPercentage: 0.7
619
620
  },
620
621
  toolHistory: {
621
622
  strategy: "per-run",
623
+ retentionMode: "drop",
622
624
  keepLatestToolPairs: 2,
623
625
  keepLatestRuns: 1,
624
626
  maxInteractionGroups: 12,
@@ -1774,6 +1776,157 @@ function findLastIndex(items, predicate) {
1774
1776
  return -1;
1775
1777
  }
1776
1778
 
1779
+ // src/context-manager/shared/preprocessors/currentTurnMessageAssembler.ts
1780
+ var CurrentTurnMessageAssembler = class extends BasePreprocessor {
1781
+ name = "CurrentTurnMessageAssembler";
1782
+ description = "Assembles current-turn fences into system_prompt and user_input messages";
1783
+ priority = 10;
1784
+ fenceRegistry;
1785
+ constructor(options) {
1786
+ super();
1787
+ this.fenceRegistry = options.fenceRegistry;
1788
+ }
1789
+ async process(messages, _context) {
1790
+ const systemResult = assembleSystemPrompt({ messages, fenceRegistry: this.fenceRegistry });
1791
+ const userResult = assembleCurrentUserInput({
1792
+ messages: systemResult.messages,
1793
+ fenceRegistry: this.fenceRegistry
1794
+ });
1795
+ const modifiedCount = systemResult.modifiedCount + userResult.modifiedCount;
1796
+ return this.createResult(
1797
+ messages,
1798
+ userResult.messages,
1799
+ modifiedCount > 0 ? ["current_turn_message_assembly"] : [],
1800
+ modifiedCount
1801
+ );
1802
+ }
1803
+ };
1804
+ function assembleSystemPrompt(params) {
1805
+ const systemIndex = params.messages.findIndex(
1806
+ (message) => message.role === "system" && message.type === "system_prompt"
1807
+ );
1808
+ if (systemIndex === -1) {
1809
+ return { messages: [...params.messages], modifiedCount: 0 };
1810
+ }
1811
+ const fences = collectAdjacentFences({
1812
+ messages: params.messages,
1813
+ startIndex: systemIndex + 1,
1814
+ direction: 1,
1815
+ fenceRegistry: params.fenceRegistry,
1816
+ matches: (descriptor) => descriptor.llmRole === "system" && descriptor.placement === "after-system"
1817
+ });
1818
+ if (fences.length === 0) {
1819
+ return { messages: [...params.messages], modifiedCount: 0 };
1820
+ }
1821
+ const indexesToRemove = new Set(fences.map((fence) => fence.index));
1822
+ const systemPrompt = params.messages[systemIndex];
1823
+ const assembledSystemPrompt = {
1824
+ ...systemPrompt,
1825
+ content: [
1826
+ systemPrompt.content,
1827
+ ...fences.map(formatFence)
1828
+ ].join("\n\n"),
1829
+ metadata: {
1830
+ ...systemPrompt.metadata,
1831
+ assembledFenceKinds: fences.map((fence) => fence.message.metadata?.fenceKind).filter((kind) => typeof kind === "string")
1832
+ }
1833
+ };
1834
+ return {
1835
+ messages: params.messages.map(
1836
+ (message, index) => index === systemIndex ? assembledSystemPrompt : message
1837
+ ).filter((_, index) => !indexesToRemove.has(index)),
1838
+ modifiedCount: fences.length + 1
1839
+ };
1840
+ }
1841
+ function assembleCurrentUserInput(params) {
1842
+ const currentUserIndex = findLastUserInputIndex(params.messages);
1843
+ if (currentUserIndex === -1) {
1844
+ return { messages: [...params.messages], modifiedCount: 0 };
1845
+ }
1846
+ const beforeFences = collectAdjacentFences({
1847
+ messages: params.messages,
1848
+ startIndex: currentUserIndex - 1,
1849
+ direction: -1,
1850
+ fenceRegistry: params.fenceRegistry,
1851
+ matches: (descriptor) => isUserCurrentTurnPlacement(descriptor, "before-current-user")
1852
+ }).reverse();
1853
+ const afterFences = collectAdjacentFences({
1854
+ messages: params.messages,
1855
+ startIndex: currentUserIndex + 1,
1856
+ direction: 1,
1857
+ fenceRegistry: params.fenceRegistry,
1858
+ matches: (descriptor) => isUserCurrentTurnPlacement(descriptor, "after-current-user")
1859
+ });
1860
+ if (beforeFences.length === 0 && afterFences.length === 0) {
1861
+ return { messages: [...params.messages], modifiedCount: 0 };
1862
+ }
1863
+ const indexesToRemove = /* @__PURE__ */ new Set([
1864
+ ...beforeFences.map((fence) => fence.index),
1865
+ ...afterFences.map((fence) => fence.index)
1866
+ ]);
1867
+ const currentUser = params.messages[currentUserIndex];
1868
+ const assembledUser = {
1869
+ ...currentUser,
1870
+ content: [
1871
+ ...beforeFences.map(formatFence),
1872
+ wrapUserRequest(currentUser.content),
1873
+ ...afterFences.map(formatFence)
1874
+ ].join("\n\n"),
1875
+ metadata: {
1876
+ ...currentUser.metadata,
1877
+ assembledFenceKinds: [
1878
+ ...beforeFences.map((fence) => fence.message.metadata?.fenceKind),
1879
+ ...afterFences.map((fence) => fence.message.metadata?.fenceKind)
1880
+ ].filter((kind) => typeof kind === "string")
1881
+ }
1882
+ };
1883
+ return {
1884
+ messages: params.messages.map(
1885
+ (message, index) => index === currentUserIndex ? assembledUser : message
1886
+ ).filter((_, index) => !indexesToRemove.has(index)),
1887
+ modifiedCount: indexesToRemove.size + 1
1888
+ };
1889
+ }
1890
+ function findLastUserInputIndex(messages) {
1891
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
1892
+ const message = messages[index];
1893
+ if (message.role === "user" && message.type === "user_input") {
1894
+ return index;
1895
+ }
1896
+ }
1897
+ return -1;
1898
+ }
1899
+ function collectAdjacentFences(params) {
1900
+ const result = [];
1901
+ for (let index = params.startIndex; index >= 0 && index < params.messages.length; index += params.direction) {
1902
+ const message = params.messages[index];
1903
+ if (message.type !== "context_injection") {
1904
+ break;
1905
+ }
1906
+ const fenceKind = message.metadata?.fenceKind;
1907
+ if (!fenceKind) {
1908
+ break;
1909
+ }
1910
+ const descriptor = params.fenceRegistry.get(fenceKind);
1911
+ if (!descriptor || !params.matches(descriptor)) {
1912
+ break;
1913
+ }
1914
+ result.push({ index, message, descriptor });
1915
+ }
1916
+ return result;
1917
+ }
1918
+ function isUserCurrentTurnPlacement(descriptor, placement) {
1919
+ return descriptor.llmRole === "user" && descriptor.placement === placement;
1920
+ }
1921
+ function formatFence(fence) {
1922
+ return fence.descriptor.formatter(fence.message.content, fence.message.metadata?.fenceAttrs ?? {});
1923
+ }
1924
+ function wrapUserRequest(content) {
1925
+ return `<user_request>
1926
+ ${content.trim()}
1927
+ </user_request>`;
1928
+ }
1929
+
1777
1930
  // src/context-manager/shared/providers/base.ts
1778
1931
  var TOOL_HISTORY_OVERFLOW_ERROR_CODE = "TOOL_HISTORY_OVERFLOW";
1779
1932
  var SUMMARIZATION_FAILED_ERROR_CODE = "SUMMARIZATION_FAILED";
@@ -2576,7 +2729,7 @@ __export(config_exports, {
2576
2729
  var AGENT_CONTEXT_BUILDER_CONFIG = {
2577
2730
  // === 绝对Token限制设置 ===
2578
2731
  /** 默认最大Token预算上限 */
2579
- DEFAULT_MAX_TOKENS: 12e4,
2732
+ DEFAULT_MAX_TOKENS: 232e3,
2580
2733
  /** 响应预留Token数 */
2581
2734
  RESERVED_FOR_RESPONSE: 2400,
2582
2735
  // === Agent专用工作记忆填充策略 ===
@@ -3967,7 +4120,7 @@ var AgentWorkingMemoryProvider = class extends BaseContextProvider2 {
3967
4120
  let workingMemoryTokens = coreTokens;
3968
4121
  let processedCount = 0;
3969
4122
  const strategiesApplied = [];
3970
- const workingMemoryBudget = Math.floor(availableBudget * config.WORKING_MEMORY_BUDGET_PERCENTAGE);
4123
+ const workingMemoryBudget = Math.floor(context.totalBudget * config.WORKING_MEMORY_BUDGET_PERCENTAGE);
3971
4124
  const remainingBudget = workingMemoryBudget - coreTokens;
3972
4125
  if (remainingBudget <= 0 && config.MIN_TOOL_INTERACTIONS_TO_KEEP <= 0) {
3973
4126
  this.debug("\u26A0\uFE0F \u6838\u5FC3\u4E0A\u4E0B\u6587\u5DF2\u7528\u5C3D\u9884\u7B97\uFF0C\u8DF3\u8FC7\u5DE5\u4F5C\u8BB0\u5FC6\u586B\u5145", {
@@ -5110,6 +5263,7 @@ __export(orchestration_exports, {
5110
5263
  var preprocessors_exports = {};
5111
5264
  __export(preprocessors_exports, {
5112
5265
  BasePreprocessor: () => BasePreprocessor2,
5266
+ CurrentTurnMessageAssembler: () => CurrentTurnMessageAssembler,
5113
5267
  FenceLifetimePreprocessor: () => FenceLifetimePreprocessor,
5114
5268
  HistoryPurificationPreprocessor: () => HistoryPurificationPreprocessor,
5115
5269
  PreprocessorPipeline: () => PreprocessorPipeline,
@@ -5161,7 +5315,7 @@ var DEFAULT_KEEP_LATEST_RUNS = 1;
5161
5315
  var DEFAULT_MAX_INTERACTION_GROUPS = 12;
5162
5316
  var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5163
5317
  name = "ToolHistoryCompressorPreprocessor";
5164
- description = "\u5DE5\u5177\u5386\u53F2\u538B\u7F29\u5904\u7406\u5668 - \u5C06\u8F83\u65E9\u7684\u5386\u53F2\u5DE5\u5177\u8C03\u7528\u5BF9\u538B\u7F29\u4E3A\u81EA\u7136\u8BED\u8A00\u8BB0\u5F55\u6D88\u606F";
5318
+ description = "\u5DE5\u5177\u5386\u53F2\u4FDD\u7559\u5904\u7406\u5668 - \u6309\u7B56\u7565\u4FDD\u7559\u3001\u5220\u9664\u6216\u538B\u7F29\u8F83\u65E9\u7684\u5386\u53F2\u5DE5\u5177\u8C03\u7528\u5BF9";
5165
5319
  priority = 0;
5166
5320
  summarizer = createDefaultToolOutputSummarizer();
5167
5321
  options;
@@ -5169,6 +5323,7 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5169
5323
  super();
5170
5324
  this.options = {
5171
5325
  strategy: options.strategy ?? "per-run",
5326
+ retentionMode: options.retentionMode ?? "drop",
5172
5327
  keepLatestToolPairs: normalizeNonNegativeInteger4(
5173
5328
  options.keepLatestToolPairs,
5174
5329
  DEFAULT_KEEP_LATEST_TOOL_PAIRS
@@ -5185,7 +5340,7 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5185
5340
  };
5186
5341
  }
5187
5342
  async process(messages, context) {
5188
- this.debug("\u{1F527} \u5F00\u59CB\u5DE5\u5177\u5386\u53F2\u538B\u7F29\u5904\u7406", {
5343
+ this.debug("\u{1F527} \u5F00\u59CB\u5DE5\u5177\u5386\u53F2\u4FDD\u7559\u5904\u7406", {
5189
5344
  \u539F\u59CB\u6D88\u606F\u6570: messages.length
5190
5345
  }, context);
5191
5346
  const currentRunStartIndex = findCurrentRunStartIndex(messages);
@@ -5195,17 +5350,18 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5195
5350
  \u5386\u53F2\u6D88\u606F\u6570: historyMessages.length,
5196
5351
  \u5F53\u524D\u8F6E\u6B21\u6D88\u606F\u6570: currentRunMessages.length,
5197
5352
  \u5F53\u524D\u8F6E\u6B21\u8D77\u70B9\u7D22\u5F15: currentRunStartIndex,
5198
- \u5DE5\u5177\u538B\u7F29\u7B56\u7565: this.options.strategy
5353
+ \u5DE5\u5177\u4FDD\u7559\u7B56\u7565: this.options.strategy,
5354
+ \u5386\u53F2\u5DE5\u5177\u4FDD\u7559\u6A21\u5F0F: this.options.retentionMode
5199
5355
  }, context);
5200
- const compressedHistory = this.compressToolCallPairsInHistory(historyMessages, context);
5201
- const finalMessages = [...compressedHistory, ...currentRunMessages];
5356
+ const processedHistory = this.processToolCallPairsInHistory(historyMessages, context);
5357
+ const finalMessages = [...processedHistory, ...currentRunMessages];
5202
5358
  const originalCount = messages.length;
5203
- const compressedCount = finalMessages.length;
5204
- const removedCount = originalCount - compressedCount;
5205
- const appliedStrategies = removedCount > 0 ? ["tool_history_compression"] : [];
5206
- this.debug("\u2705 \u5DE5\u5177\u5386\u53F2\u538B\u7F29\u5B8C\u6210", {
5359
+ const processedCount = finalMessages.length;
5360
+ const removedCount = originalCount - processedCount;
5361
+ const appliedStrategies = removedCount > 0 ? [this.options.retentionMode === "compress" ? "tool_history_compression" : "tool_history_drop"] : [];
5362
+ this.debug("\u2705 \u5DE5\u5177\u5386\u53F2\u4FDD\u7559\u5904\u7406\u5B8C\u6210", {
5207
5363
  \u539F\u59CB\u6D88\u606F: originalCount,
5208
- \u538B\u7F29\u540E\u6D88\u606F: compressedCount,
5364
+ \u5904\u7406\u540E\u6D88\u606F: processedCount,
5209
5365
  \u51CF\u5C11\u6D88\u606F: removedCount,
5210
5366
  Token\u8282\u7701\u4F30\u8BA1: `\u7EA6${removedCount * 50}\u4E2AToken`
5211
5367
  }, context);
@@ -5226,7 +5382,7 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5226
5382
  }
5227
5383
  return false;
5228
5384
  }
5229
- compressToolCallPairsInHistory(historyMessages, context) {
5385
+ processToolCallPairsInHistory(historyMessages, context) {
5230
5386
  if (historyMessages.length < 2) {
5231
5387
  return historyMessages;
5232
5388
  }
@@ -5247,8 +5403,10 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5247
5403
  if (!group.isComplete || keepAnchorIds.has(group.anchorId)) {
5248
5404
  continue;
5249
5405
  }
5250
- const compressedMessage = this.compressToolInteractionGroup(group, context);
5251
- replacementMap.set(group.assistantIndex, compressedMessage);
5406
+ if (this.options.retentionMode === "compress") {
5407
+ const compressedMessage = this.compressToolInteractionGroup(group, context);
5408
+ replacementMap.set(group.assistantIndex, compressedMessage);
5409
+ }
5252
5410
  for (const messageIndex of group.messageIndexes) {
5253
5411
  messagesToRemove.add(messageIndex);
5254
5412
  }
@@ -5667,6 +5825,7 @@ function createDefaultAgentPreprocessorRegistry(options = {}) {
5667
5825
  registry.register(new ToolReplayProtocolGuardPreprocessor({ policy: options.providerReplay }));
5668
5826
  registry.register(new HistoryPurificationPreprocessor({ logPrefix: "Agent-HistoryPurification" }));
5669
5827
  if (options.fenceRegistry) {
5828
+ registry.register(new CurrentTurnMessageAssembler({ fenceRegistry: options.fenceRegistry }));
5670
5829
  registry.register(new FenceLifetimePreprocessor({ fenceRegistry: options.fenceRegistry }));
5671
5830
  }
5672
5831
  return registry;
@@ -6782,6 +6941,18 @@ var AgentMessageOrchestrator = class {
6782
6941
  tokenizer: this.options.tokenizer,
6783
6942
  tokenizerModelId: this.resolvePreprocessorModel(request)
6784
6943
  });
6944
+ return contextBuilderConfig;
6945
+ }
6946
+ resolveEffectiveContextBudget(contextBuilderConfig) {
6947
+ const maxTokens = contextBuilderConfig.DEFAULT_MAX_TOKENS ?? this.options.tokenBudget.maxTokens;
6948
+ const reservedForResponse = contextBuilderConfig.RESERVED_FOR_RESPONSE ?? this.options.tokenBudget.reservedForResponse;
6949
+ return {
6950
+ maxTokens,
6951
+ reservedForResponse,
6952
+ // 中文备注:ContextManager 接收的是“可放入上下文的输入预算”,不是模型完整窗口。
6953
+ // 因此单个 agent 通过 contextPolicy.budget 覆盖预算时,这里必须同步使用覆盖后的值。
6954
+ totalBudget: maxTokens - reservedForResponse
6955
+ };
6785
6956
  }
6786
6957
  async processAgentConversation(request, history, toolManager, callbacks, extraOptions) {
6787
6958
  const historyCount = history.length;
@@ -6800,7 +6971,8 @@ var AgentMessageOrchestrator = class {
6800
6971
  const allMessages = this.buildCompleteMessageList(request, historyMessages);
6801
6972
  this.debug("Built complete message list", { totalCount: allMessages.length });
6802
6973
  const contextPolicy = this.resolveContextPolicy(request);
6803
- this.applyContextPolicy(request, contextPolicy);
6974
+ const contextBuilderConfig = this.applyContextPolicy(request, contextPolicy);
6975
+ const effectiveContextBudget = this.resolveEffectiveContextBudget(contextBuilderConfig);
6804
6976
  const preprocessorPipeline = this.buildPreprocessorPipelineForRequest(toolManager, request, contextPolicy);
6805
6977
  const modelId = this.resolvePreprocessorModel(request);
6806
6978
  preprocessorPipeline.updateContext({
@@ -6828,7 +7000,8 @@ var AgentMessageOrchestrator = class {
6828
7000
  callbacks,
6829
7001
  void 0,
6830
7002
  extraOptions?.generate,
6831
- contextPolicy
7003
+ contextPolicy,
7004
+ effectiveContextBudget.totalBudget
6832
7005
  );
6833
7006
  this.debug("Context built", { afterContextCount: contextResult.messages.length });
6834
7007
  if (this.options.processing.debugMode) {
@@ -6861,7 +7034,7 @@ var AgentMessageOrchestrator = class {
6861
7034
  processedCount: contextResult.messages.length,
6862
7035
  tokenUsage: {
6863
7036
  estimated: contextResult.tokenUsage.used,
6864
- budget: this.options.tokenBudget.maxTokens,
7037
+ budget: effectiveContextBudget.totalBudget,
6865
7038
  remaining: contextResult.tokenUsage.remaining
6866
7039
  },
6867
7040
  processingStats: contextResult.processingStats,
@@ -6881,13 +7054,13 @@ var AgentMessageOrchestrator = class {
6881
7054
  async runPreprocessorPipeline(preprocessorPipeline, messages) {
6882
7055
  return preprocessorPipeline.process(messages);
6883
7056
  }
6884
- async buildContextFromPreprocessedMessages(request, conversationSession, messages, callbacks, phaseOverride, generate, contextPolicy) {
6885
- const totalBudget = this.options.tokenBudget.maxTokens - this.options.tokenBudget.reservedForResponse;
7057
+ async buildContextFromPreprocessedMessages(request, conversationSession, messages, callbacks, phaseOverride, generate, contextPolicy, totalBudget) {
7058
+ const resolvedTotalBudget = totalBudget ?? this.options.tokenBudget.maxTokens - this.options.tokenBudget.reservedForResponse;
6886
7059
  const contextResult = await this.agentContextManager.buildContextFromPreprocessedMessages(
6887
7060
  request,
6888
7061
  conversationSession,
6889
7062
  messages,
6890
- totalBudget,
7063
+ resolvedTotalBudget,
6891
7064
  callbacks,
6892
7065
  phaseOverride,
6893
7066
  generate,
@@ -6968,22 +7141,33 @@ var BaseAgentTask = class {
6968
7141
  });
6969
7142
  }
6970
7143
  messages.push(...fenceMessages["after-system"]);
7144
+ const currentUserIndex = findCurrentUserInputIndex(history, request.query);
7145
+ const historyBeforeCurrentUser = currentUserIndex === -1 ? history : history.slice(0, currentUserIndex);
7146
+ const currentUserMessage = currentUserIndex === -1 ? this.createCurrentUserMessage(request.query) : history[currentUserIndex];
7147
+ const historyAfterCurrentUser = currentUserIndex === -1 ? [] : history.slice(currentUserIndex + 1);
7148
+ messages.push(...historyBeforeCurrentUser);
6971
7149
  messages.push(...fenceMessages["before-current-user"]);
6972
- const hasUserMessageInHistory = history.some((m) => m.role === "user");
6973
- if (!hasUserMessageInHistory && request.query && request.query.trim()) {
6974
- messages.push({
6975
- id: generateMessageId(),
6976
- role: "user",
6977
- type: "user_input",
6978
- content: request.query.trim(),
6979
- timestamp: Date.now()
6980
- });
7150
+ if (currentUserMessage) {
7151
+ messages.push(currentUserMessage);
6981
7152
  }
6982
7153
  messages.push(...fenceMessages["after-current-user"]);
6983
- messages.push(...history);
7154
+ messages.push(...historyAfterCurrentUser);
6984
7155
  this.insertAfterLastToolResult(messages, fenceMessages["after-last-tool-result"]);
6985
7156
  return messages;
6986
7157
  }
7158
+ createCurrentUserMessage(query) {
7159
+ const content = query.trim();
7160
+ if (!content) {
7161
+ return null;
7162
+ }
7163
+ return {
7164
+ id: generateMessageId(),
7165
+ role: "user",
7166
+ type: "user_input",
7167
+ content,
7168
+ timestamp: Date.now()
7169
+ };
7170
+ }
6987
7171
  createFenceMessages(fences) {
6988
7172
  const grouped = {
6989
7173
  "after-system": [],
@@ -7048,6 +7232,19 @@ function findLastIndex2(items, predicate) {
7048
7232
  }
7049
7233
  return -1;
7050
7234
  }
7235
+ function findCurrentUserInputIndex(history, query) {
7236
+ const normalizedQuery = query.trim();
7237
+ if (!normalizedQuery) {
7238
+ return -1;
7239
+ }
7240
+ for (let index = history.length - 1; index >= 0; index -= 1) {
7241
+ const message = history[index];
7242
+ if (message.role === "user" && message.type === "user_input" && message.content.trim() === normalizedQuery) {
7243
+ return index;
7244
+ }
7245
+ }
7246
+ return -1;
7247
+ }
7051
7248
 
7052
7249
  // src/context-manager/profiles/agent/tools/index.ts
7053
7250
  var tools_exports2 = {};
@@ -8661,6 +8858,7 @@ exports.ChatWorkingMemoryProvider = WorkingMemoryProvider;
8661
8858
  exports.ContextProviderError = ContextProviderError;
8662
8859
  exports.ContextProviderRegistry = ContextProviderRegistry;
8663
8860
  exports.ContextTraceCollector = ContextTraceCollector;
8861
+ exports.CurrentTurnMessageAssembler = CurrentTurnMessageAssembler;
8664
8862
  exports.DEFAULT_MUST_KEEP_POLICY = DEFAULT_MUST_KEEP_POLICY;
8665
8863
  exports.FenceLifetimePreprocessor = FenceLifetimePreprocessor;
8666
8864
  exports.HistoryPurificationPreprocessor = HistoryPurificationPreprocessor;