@linnlabs/linnkit 0.9.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 (81) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/linnkit.cjs +7 -0
  3. package/dist/{agentSpec-EkmviZjy.d.cts → agentSpec-Du4Iye0q.d.cts} +16 -1
  4. package/dist/{agentSpec-EkmviZjy.d.ts → agentSpec-Du4Iye0q.d.ts} +16 -1
  5. package/dist/cli.cjs +118 -65
  6. package/dist/cli.cjs.map +1 -1
  7. package/dist/cli.js +118 -65
  8. package/dist/cli.js.map +1 -1
  9. package/dist/context-manager.cjs +234 -32
  10. package/dist/context-manager.cjs.map +1 -1
  11. package/dist/context-manager.d.cts +52 -15
  12. package/dist/context-manager.d.ts +52 -15
  13. package/dist/context-manager.js +234 -33
  14. package/dist/context-manager.js.map +1 -1
  15. package/dist/{context-trace-HE2qY5Q-.d.cts → context-trace-BHKDS-eq.d.cts} +2 -2
  16. package/dist/{context-trace-DRi5M4lX.d.ts → context-trace-CHbqHmyE.d.ts} +2 -2
  17. package/dist/contracts.cjs +3 -1
  18. package/dist/contracts.cjs.map +1 -1
  19. package/dist/contracts.d.cts +3 -3
  20. package/dist/contracts.d.ts +3 -3
  21. package/dist/contracts.js +3 -1
  22. package/dist/contracts.js.map +1 -1
  23. package/dist/{defaultGraphExecutor-BBswR8wn.d.ts → defaultGraphExecutor-B29_qTHy.d.ts} +16 -15
  24. package/dist/{defaultGraphExecutor-BIjJj7WF.d.cts → defaultGraphExecutor-C2E59v_R.d.cts} +16 -15
  25. package/dist/{index-BanRABEt.d.cts → index-BAaUP9yU.d.cts} +26 -14
  26. package/dist/{index-Z8NXKNwI.d.ts → index-BaVpVNi2.d.ts} +26 -14
  27. package/dist/{index-DO4dQgf2.d.cts → index-BnYCS8Zg.d.cts} +2 -2
  28. package/dist/{index-CJeWHopy.d.ts → index-C0DAjsdX.d.ts} +2 -2
  29. package/dist/{index-Dl5PLgAv.d.cts → index-CKQzzZ5Y.d.cts} +2 -2
  30. package/dist/{index-CHqwkvGp.d.ts → index-D0mKxTR5.d.ts} +2 -2
  31. package/dist/index.cjs +186 -85
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +10 -10
  34. package/dist/index.d.ts +10 -10
  35. package/dist/index.js +186 -85
  36. package/dist/index.js.map +1 -1
  37. package/dist/{ports-DnLuKfpE.d.ts → ports-DpPTFhSd.d.ts} +2 -2
  38. package/dist/{ports-DaatKJXp.d.cts → ports-s-tSp3sB.d.cts} +2 -2
  39. package/dist/quickstart.cjs +119 -65
  40. package/dist/quickstart.cjs.map +1 -1
  41. package/dist/quickstart.d.cts +7 -7
  42. package/dist/quickstart.d.ts +7 -7
  43. package/dist/quickstart.js +119 -65
  44. package/dist/quickstart.js.map +1 -1
  45. package/dist/{runAgent-CPj_9e58.d.ts → runAgent-C6F-399C.d.ts} +5 -5
  46. package/dist/{runAgent-HYKlXbVr.d.cts → runAgent-ilEj66Ik.d.cts} +5 -5
  47. package/dist/{runHandle-D3gPsD7B.d.cts → runHandle-BNOqS-Bl.d.cts} +3 -3
  48. package/dist/{runHandle-CyXvzgzk.d.ts → runHandle-BdLXOFqF.d.ts} +3 -3
  49. package/dist/runtime-kernel/events.cjs +1 -0
  50. package/dist/runtime-kernel/events.cjs.map +1 -1
  51. package/dist/runtime-kernel/events.d.cts +4 -4
  52. package/dist/runtime-kernel/events.d.ts +4 -4
  53. package/dist/runtime-kernel/events.js +1 -0
  54. package/dist/runtime-kernel/events.js.map +1 -1
  55. package/dist/runtime-kernel.cjs +181 -82
  56. package/dist/runtime-kernel.cjs.map +1 -1
  57. package/dist/runtime-kernel.d.cts +8 -8
  58. package/dist/runtime-kernel.d.ts +8 -8
  59. package/dist/runtime-kernel.js +181 -83
  60. package/dist/runtime-kernel.js.map +1 -1
  61. package/dist/testkit.cjs +181 -82
  62. package/dist/testkit.cjs.map +1 -1
  63. package/dist/testkit.d.cts +8 -8
  64. package/dist/testkit.d.ts +8 -8
  65. package/dist/testkit.js +181 -82
  66. package/dist/testkit.js.map +1 -1
  67. package/dist/{todo-B1PmDlp3.d.cts → todo-Ca8llpRQ.d.cts} +1 -1
  68. package/dist/{todo-B1PmDlp3.d.ts → todo-Ca8llpRQ.d.ts} +1 -1
  69. package/dist/{toolContracts-CLkQmhTG.d.cts → toolContracts-Bm3EZ1UM.d.cts} +13 -2
  70. package/dist/{toolContracts-Blll0241.d.ts → toolContracts-f8lzZBNa.d.ts} +13 -2
  71. package/docs/integration/README.md +1 -1
  72. package/docs/integration/agent-registration-guide.md +1 -1
  73. package/docs/integration/child-runs.md +4 -1
  74. package/docs/integration/context-engineering.md +30 -15
  75. package/docs/integration/context-fences.md +32 -3
  76. package/docs/integration/llm-provider.md +1 -1
  77. package/docs/integration/persistence.md +1 -0
  78. package/docs/integration/run-supervisor.md +3 -0
  79. package/docs/integration/tool-development-guide.md +7 -5
  80. package/docs/integration/tool-history.md +43 -17
  81. package/package.json +4 -3
@@ -497,6 +497,7 @@ var AgentSpecBudgetPolicy = z.object({
497
497
  });
498
498
  var AgentSpecToolHistoryPolicy = z.object({
499
499
  strategy: z.enum(["per-pair", "per-run", "none"]).optional(),
500
+ retentionMode: z.enum(["drop", "compress"]).optional(),
500
501
  keepLatestToolPairs: z.number().int().nonnegative().optional(),
501
502
  keepLatestRuns: z.number().int().nonnegative().optional(),
502
503
  maxInteractionGroups: z.number().int().nonnegative().optional(),
@@ -611,12 +612,13 @@ var AgentSpecContextPolicy = z.object({
611
612
  var DEFAULT_CONTEXT_POLICY = {
612
613
  profileId: "agent",
613
614
  budget: {
614
- maxTokens: 12e4,
615
+ maxTokens: 232e3,
615
616
  reservedForResponse: 2400,
616
617
  workingMemoryBudgetPercentage: 0.7
617
618
  },
618
619
  toolHistory: {
619
620
  strategy: "per-run",
621
+ retentionMode: "drop",
620
622
  keepLatestToolPairs: 2,
621
623
  keepLatestRuns: 1,
622
624
  maxInteractionGroups: 12,
@@ -1772,6 +1774,157 @@ function findLastIndex(items, predicate) {
1772
1774
  return -1;
1773
1775
  }
1774
1776
 
1777
+ // src/context-manager/shared/preprocessors/currentTurnMessageAssembler.ts
1778
+ var CurrentTurnMessageAssembler = class extends BasePreprocessor {
1779
+ name = "CurrentTurnMessageAssembler";
1780
+ description = "Assembles current-turn fences into system_prompt and user_input messages";
1781
+ priority = 10;
1782
+ fenceRegistry;
1783
+ constructor(options) {
1784
+ super();
1785
+ this.fenceRegistry = options.fenceRegistry;
1786
+ }
1787
+ async process(messages, _context) {
1788
+ const systemResult = assembleSystemPrompt({ messages, fenceRegistry: this.fenceRegistry });
1789
+ const userResult = assembleCurrentUserInput({
1790
+ messages: systemResult.messages,
1791
+ fenceRegistry: this.fenceRegistry
1792
+ });
1793
+ const modifiedCount = systemResult.modifiedCount + userResult.modifiedCount;
1794
+ return this.createResult(
1795
+ messages,
1796
+ userResult.messages,
1797
+ modifiedCount > 0 ? ["current_turn_message_assembly"] : [],
1798
+ modifiedCount
1799
+ );
1800
+ }
1801
+ };
1802
+ function assembleSystemPrompt(params) {
1803
+ const systemIndex = params.messages.findIndex(
1804
+ (message) => message.role === "system" && message.type === "system_prompt"
1805
+ );
1806
+ if (systemIndex === -1) {
1807
+ return { messages: [...params.messages], modifiedCount: 0 };
1808
+ }
1809
+ const fences = collectAdjacentFences({
1810
+ messages: params.messages,
1811
+ startIndex: systemIndex + 1,
1812
+ direction: 1,
1813
+ fenceRegistry: params.fenceRegistry,
1814
+ matches: (descriptor) => descriptor.llmRole === "system" && descriptor.placement === "after-system"
1815
+ });
1816
+ if (fences.length === 0) {
1817
+ return { messages: [...params.messages], modifiedCount: 0 };
1818
+ }
1819
+ const indexesToRemove = new Set(fences.map((fence) => fence.index));
1820
+ const systemPrompt = params.messages[systemIndex];
1821
+ const assembledSystemPrompt = {
1822
+ ...systemPrompt,
1823
+ content: [
1824
+ systemPrompt.content,
1825
+ ...fences.map(formatFence)
1826
+ ].join("\n\n"),
1827
+ metadata: {
1828
+ ...systemPrompt.metadata,
1829
+ assembledFenceKinds: fences.map((fence) => fence.message.metadata?.fenceKind).filter((kind) => typeof kind === "string")
1830
+ }
1831
+ };
1832
+ return {
1833
+ messages: params.messages.map(
1834
+ (message, index) => index === systemIndex ? assembledSystemPrompt : message
1835
+ ).filter((_, index) => !indexesToRemove.has(index)),
1836
+ modifiedCount: fences.length + 1
1837
+ };
1838
+ }
1839
+ function assembleCurrentUserInput(params) {
1840
+ const currentUserIndex = findLastUserInputIndex(params.messages);
1841
+ if (currentUserIndex === -1) {
1842
+ return { messages: [...params.messages], modifiedCount: 0 };
1843
+ }
1844
+ const beforeFences = collectAdjacentFences({
1845
+ messages: params.messages,
1846
+ startIndex: currentUserIndex - 1,
1847
+ direction: -1,
1848
+ fenceRegistry: params.fenceRegistry,
1849
+ matches: (descriptor) => isUserCurrentTurnPlacement(descriptor, "before-current-user")
1850
+ }).reverse();
1851
+ const afterFences = collectAdjacentFences({
1852
+ messages: params.messages,
1853
+ startIndex: currentUserIndex + 1,
1854
+ direction: 1,
1855
+ fenceRegistry: params.fenceRegistry,
1856
+ matches: (descriptor) => isUserCurrentTurnPlacement(descriptor, "after-current-user")
1857
+ });
1858
+ if (beforeFences.length === 0 && afterFences.length === 0) {
1859
+ return { messages: [...params.messages], modifiedCount: 0 };
1860
+ }
1861
+ const indexesToRemove = /* @__PURE__ */ new Set([
1862
+ ...beforeFences.map((fence) => fence.index),
1863
+ ...afterFences.map((fence) => fence.index)
1864
+ ]);
1865
+ const currentUser = params.messages[currentUserIndex];
1866
+ const assembledUser = {
1867
+ ...currentUser,
1868
+ content: [
1869
+ ...beforeFences.map(formatFence),
1870
+ wrapUserRequest(currentUser.content),
1871
+ ...afterFences.map(formatFence)
1872
+ ].join("\n\n"),
1873
+ metadata: {
1874
+ ...currentUser.metadata,
1875
+ assembledFenceKinds: [
1876
+ ...beforeFences.map((fence) => fence.message.metadata?.fenceKind),
1877
+ ...afterFences.map((fence) => fence.message.metadata?.fenceKind)
1878
+ ].filter((kind) => typeof kind === "string")
1879
+ }
1880
+ };
1881
+ return {
1882
+ messages: params.messages.map(
1883
+ (message, index) => index === currentUserIndex ? assembledUser : message
1884
+ ).filter((_, index) => !indexesToRemove.has(index)),
1885
+ modifiedCount: indexesToRemove.size + 1
1886
+ };
1887
+ }
1888
+ function findLastUserInputIndex(messages) {
1889
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
1890
+ const message = messages[index];
1891
+ if (message.role === "user" && message.type === "user_input") {
1892
+ return index;
1893
+ }
1894
+ }
1895
+ return -1;
1896
+ }
1897
+ function collectAdjacentFences(params) {
1898
+ const result = [];
1899
+ for (let index = params.startIndex; index >= 0 && index < params.messages.length; index += params.direction) {
1900
+ const message = params.messages[index];
1901
+ if (message.type !== "context_injection") {
1902
+ break;
1903
+ }
1904
+ const fenceKind = message.metadata?.fenceKind;
1905
+ if (!fenceKind) {
1906
+ break;
1907
+ }
1908
+ const descriptor = params.fenceRegistry.get(fenceKind);
1909
+ if (!descriptor || !params.matches(descriptor)) {
1910
+ break;
1911
+ }
1912
+ result.push({ index, message, descriptor });
1913
+ }
1914
+ return result;
1915
+ }
1916
+ function isUserCurrentTurnPlacement(descriptor, placement) {
1917
+ return descriptor.llmRole === "user" && descriptor.placement === placement;
1918
+ }
1919
+ function formatFence(fence) {
1920
+ return fence.descriptor.formatter(fence.message.content, fence.message.metadata?.fenceAttrs ?? {});
1921
+ }
1922
+ function wrapUserRequest(content) {
1923
+ return `<user_request>
1924
+ ${content.trim()}
1925
+ </user_request>`;
1926
+ }
1927
+
1775
1928
  // src/context-manager/shared/providers/base.ts
1776
1929
  var TOOL_HISTORY_OVERFLOW_ERROR_CODE = "TOOL_HISTORY_OVERFLOW";
1777
1930
  var SUMMARIZATION_FAILED_ERROR_CODE = "SUMMARIZATION_FAILED";
@@ -2574,7 +2727,7 @@ __export(config_exports, {
2574
2727
  var AGENT_CONTEXT_BUILDER_CONFIG = {
2575
2728
  // === 绝对Token限制设置 ===
2576
2729
  /** 默认最大Token预算上限 */
2577
- DEFAULT_MAX_TOKENS: 12e4,
2730
+ DEFAULT_MAX_TOKENS: 232e3,
2578
2731
  /** 响应预留Token数 */
2579
2732
  RESERVED_FOR_RESPONSE: 2400,
2580
2733
  // === Agent专用工作记忆填充策略 ===
@@ -3187,6 +3340,7 @@ var ToolPairMatcher = class {
3187
3340
  constructor(config) {
3188
3341
  this.config = config;
3189
3342
  }
3343
+ config;
3190
3344
  /**
3191
3345
  * 判断是否为"预处理阶段压缩的工具历史摘要消息"
3192
3346
  * - 该类消息不再是 tool_calls/tool_output 的原始结构,而是 assistant 的自然语言记录
@@ -3367,6 +3521,7 @@ var ToolPairTruncator = class {
3367
3521
  constructor(config) {
3368
3522
  this.config = config;
3369
3523
  }
3524
+ config;
3370
3525
  /**
3371
3526
  * 智能截断超大的工具对
3372
3527
  *
@@ -3963,7 +4118,7 @@ var AgentWorkingMemoryProvider = class extends BaseContextProvider2 {
3963
4118
  let workingMemoryTokens = coreTokens;
3964
4119
  let processedCount = 0;
3965
4120
  const strategiesApplied = [];
3966
- const workingMemoryBudget = Math.floor(availableBudget * config.WORKING_MEMORY_BUDGET_PERCENTAGE);
4121
+ const workingMemoryBudget = Math.floor(context.totalBudget * config.WORKING_MEMORY_BUDGET_PERCENTAGE);
3967
4122
  const remainingBudget = workingMemoryBudget - coreTokens;
3968
4123
  if (remainingBudget <= 0 && config.MIN_TOOL_INTERACTIONS_TO_KEEP <= 0) {
3969
4124
  this.debug("\u26A0\uFE0F \u6838\u5FC3\u4E0A\u4E0B\u6587\u5DF2\u7528\u5C3D\u9884\u7B97\uFF0C\u8DF3\u8FC7\u5DE5\u4F5C\u8BB0\u5FC6\u586B\u5145", {
@@ -4098,6 +4253,7 @@ var Logger = class {
4098
4253
  constructor(moduleName) {
4099
4254
  this.moduleName = moduleName;
4100
4255
  }
4256
+ moduleName;
4101
4257
  debug(message, data) {
4102
4258
  this.log(0 /* DEBUG */, "debug", message, data);
4103
4259
  }
@@ -4345,6 +4501,7 @@ var DefaultTokenizerPort = class {
4345
4501
  constructor(config = {}) {
4346
4502
  this.config = config;
4347
4503
  }
4504
+ config;
4348
4505
  estimateText(text, _modelId) {
4349
4506
  return TokenCalculator.estimateTokens(text, {
4350
4507
  encoding: this.config.encoding,
@@ -5104,6 +5261,7 @@ __export(orchestration_exports, {
5104
5261
  var preprocessors_exports = {};
5105
5262
  __export(preprocessors_exports, {
5106
5263
  BasePreprocessor: () => BasePreprocessor2,
5264
+ CurrentTurnMessageAssembler: () => CurrentTurnMessageAssembler,
5107
5265
  FenceLifetimePreprocessor: () => FenceLifetimePreprocessor,
5108
5266
  HistoryPurificationPreprocessor: () => HistoryPurificationPreprocessor,
5109
5267
  PreprocessorPipeline: () => PreprocessorPipeline,
@@ -5155,7 +5313,7 @@ var DEFAULT_KEEP_LATEST_RUNS = 1;
5155
5313
  var DEFAULT_MAX_INTERACTION_GROUPS = 12;
5156
5314
  var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5157
5315
  name = "ToolHistoryCompressorPreprocessor";
5158
- 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";
5316
+ 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";
5159
5317
  priority = 0;
5160
5318
  summarizer = createDefaultToolOutputSummarizer();
5161
5319
  options;
@@ -5163,6 +5321,7 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5163
5321
  super();
5164
5322
  this.options = {
5165
5323
  strategy: options.strategy ?? "per-run",
5324
+ retentionMode: options.retentionMode ?? "drop",
5166
5325
  keepLatestToolPairs: normalizeNonNegativeInteger4(
5167
5326
  options.keepLatestToolPairs,
5168
5327
  DEFAULT_KEEP_LATEST_TOOL_PAIRS
@@ -5179,7 +5338,7 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5179
5338
  };
5180
5339
  }
5181
5340
  async process(messages, context) {
5182
- this.debug("\u{1F527} \u5F00\u59CB\u5DE5\u5177\u5386\u53F2\u538B\u7F29\u5904\u7406", {
5341
+ this.debug("\u{1F527} \u5F00\u59CB\u5DE5\u5177\u5386\u53F2\u4FDD\u7559\u5904\u7406", {
5183
5342
  \u539F\u59CB\u6D88\u606F\u6570: messages.length
5184
5343
  }, context);
5185
5344
  const currentRunStartIndex = findCurrentRunStartIndex(messages);
@@ -5189,17 +5348,18 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5189
5348
  \u5386\u53F2\u6D88\u606F\u6570: historyMessages.length,
5190
5349
  \u5F53\u524D\u8F6E\u6B21\u6D88\u606F\u6570: currentRunMessages.length,
5191
5350
  \u5F53\u524D\u8F6E\u6B21\u8D77\u70B9\u7D22\u5F15: currentRunStartIndex,
5192
- \u5DE5\u5177\u538B\u7F29\u7B56\u7565: this.options.strategy
5351
+ \u5DE5\u5177\u4FDD\u7559\u7B56\u7565: this.options.strategy,
5352
+ \u5386\u53F2\u5DE5\u5177\u4FDD\u7559\u6A21\u5F0F: this.options.retentionMode
5193
5353
  }, context);
5194
- const compressedHistory = this.compressToolCallPairsInHistory(historyMessages, context);
5195
- const finalMessages = [...compressedHistory, ...currentRunMessages];
5354
+ const processedHistory = this.processToolCallPairsInHistory(historyMessages, context);
5355
+ const finalMessages = [...processedHistory, ...currentRunMessages];
5196
5356
  const originalCount = messages.length;
5197
- const compressedCount = finalMessages.length;
5198
- const removedCount = originalCount - compressedCount;
5199
- const appliedStrategies = removedCount > 0 ? ["tool_history_compression"] : [];
5200
- this.debug("\u2705 \u5DE5\u5177\u5386\u53F2\u538B\u7F29\u5B8C\u6210", {
5357
+ const processedCount = finalMessages.length;
5358
+ const removedCount = originalCount - processedCount;
5359
+ const appliedStrategies = removedCount > 0 ? [this.options.retentionMode === "compress" ? "tool_history_compression" : "tool_history_drop"] : [];
5360
+ this.debug("\u2705 \u5DE5\u5177\u5386\u53F2\u4FDD\u7559\u5904\u7406\u5B8C\u6210", {
5201
5361
  \u539F\u59CB\u6D88\u606F: originalCount,
5202
- \u538B\u7F29\u540E\u6D88\u606F: compressedCount,
5362
+ \u5904\u7406\u540E\u6D88\u606F: processedCount,
5203
5363
  \u51CF\u5C11\u6D88\u606F: removedCount,
5204
5364
  Token\u8282\u7701\u4F30\u8BA1: `\u7EA6${removedCount * 50}\u4E2AToken`
5205
5365
  }, context);
@@ -5220,7 +5380,7 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5220
5380
  }
5221
5381
  return false;
5222
5382
  }
5223
- compressToolCallPairsInHistory(historyMessages, context) {
5383
+ processToolCallPairsInHistory(historyMessages, context) {
5224
5384
  if (historyMessages.length < 2) {
5225
5385
  return historyMessages;
5226
5386
  }
@@ -5241,8 +5401,10 @@ var ToolHistoryCompressorPreprocessor = class extends BasePreprocessor2 {
5241
5401
  if (!group.isComplete || keepAnchorIds.has(group.anchorId)) {
5242
5402
  continue;
5243
5403
  }
5244
- const compressedMessage = this.compressToolInteractionGroup(group, context);
5245
- replacementMap.set(group.assistantIndex, compressedMessage);
5404
+ if (this.options.retentionMode === "compress") {
5405
+ const compressedMessage = this.compressToolInteractionGroup(group, context);
5406
+ replacementMap.set(group.assistantIndex, compressedMessage);
5407
+ }
5246
5408
  for (const messageIndex of group.messageIndexes) {
5247
5409
  messagesToRemove.add(messageIndex);
5248
5410
  }
@@ -5661,6 +5823,7 @@ function createDefaultAgentPreprocessorRegistry(options = {}) {
5661
5823
  registry.register(new ToolReplayProtocolGuardPreprocessor({ policy: options.providerReplay }));
5662
5824
  registry.register(new HistoryPurificationPreprocessor({ logPrefix: "Agent-HistoryPurification" }));
5663
5825
  if (options.fenceRegistry) {
5826
+ registry.register(new CurrentTurnMessageAssembler({ fenceRegistry: options.fenceRegistry }));
5664
5827
  registry.register(new FenceLifetimePreprocessor({ fenceRegistry: options.fenceRegistry }));
5665
5828
  }
5666
5829
  return registry;
@@ -6776,6 +6939,18 @@ var AgentMessageOrchestrator = class {
6776
6939
  tokenizer: this.options.tokenizer,
6777
6940
  tokenizerModelId: this.resolvePreprocessorModel(request)
6778
6941
  });
6942
+ return contextBuilderConfig;
6943
+ }
6944
+ resolveEffectiveContextBudget(contextBuilderConfig) {
6945
+ const maxTokens = contextBuilderConfig.DEFAULT_MAX_TOKENS ?? this.options.tokenBudget.maxTokens;
6946
+ const reservedForResponse = contextBuilderConfig.RESERVED_FOR_RESPONSE ?? this.options.tokenBudget.reservedForResponse;
6947
+ return {
6948
+ maxTokens,
6949
+ reservedForResponse,
6950
+ // 中文备注:ContextManager 接收的是“可放入上下文的输入预算”,不是模型完整窗口。
6951
+ // 因此单个 agent 通过 contextPolicy.budget 覆盖预算时,这里必须同步使用覆盖后的值。
6952
+ totalBudget: maxTokens - reservedForResponse
6953
+ };
6779
6954
  }
6780
6955
  async processAgentConversation(request, history, toolManager, callbacks, extraOptions) {
6781
6956
  const historyCount = history.length;
@@ -6794,7 +6969,8 @@ var AgentMessageOrchestrator = class {
6794
6969
  const allMessages = this.buildCompleteMessageList(request, historyMessages);
6795
6970
  this.debug("Built complete message list", { totalCount: allMessages.length });
6796
6971
  const contextPolicy = this.resolveContextPolicy(request);
6797
- this.applyContextPolicy(request, contextPolicy);
6972
+ const contextBuilderConfig = this.applyContextPolicy(request, contextPolicy);
6973
+ const effectiveContextBudget = this.resolveEffectiveContextBudget(contextBuilderConfig);
6798
6974
  const preprocessorPipeline = this.buildPreprocessorPipelineForRequest(toolManager, request, contextPolicy);
6799
6975
  const modelId = this.resolvePreprocessorModel(request);
6800
6976
  preprocessorPipeline.updateContext({
@@ -6822,7 +6998,8 @@ var AgentMessageOrchestrator = class {
6822
6998
  callbacks,
6823
6999
  void 0,
6824
7000
  extraOptions?.generate,
6825
- contextPolicy
7001
+ contextPolicy,
7002
+ effectiveContextBudget.totalBudget
6826
7003
  );
6827
7004
  this.debug("Context built", { afterContextCount: contextResult.messages.length });
6828
7005
  if (this.options.processing.debugMode) {
@@ -6855,7 +7032,7 @@ var AgentMessageOrchestrator = class {
6855
7032
  processedCount: contextResult.messages.length,
6856
7033
  tokenUsage: {
6857
7034
  estimated: contextResult.tokenUsage.used,
6858
- budget: this.options.tokenBudget.maxTokens,
7035
+ budget: effectiveContextBudget.totalBudget,
6859
7036
  remaining: contextResult.tokenUsage.remaining
6860
7037
  },
6861
7038
  processingStats: contextResult.processingStats,
@@ -6875,13 +7052,13 @@ var AgentMessageOrchestrator = class {
6875
7052
  async runPreprocessorPipeline(preprocessorPipeline, messages) {
6876
7053
  return preprocessorPipeline.process(messages);
6877
7054
  }
6878
- async buildContextFromPreprocessedMessages(request, conversationSession, messages, callbacks, phaseOverride, generate, contextPolicy) {
6879
- const totalBudget = this.options.tokenBudget.maxTokens - this.options.tokenBudget.reservedForResponse;
7055
+ async buildContextFromPreprocessedMessages(request, conversationSession, messages, callbacks, phaseOverride, generate, contextPolicy, totalBudget) {
7056
+ const resolvedTotalBudget = totalBudget ?? this.options.tokenBudget.maxTokens - this.options.tokenBudget.reservedForResponse;
6880
7057
  const contextResult = await this.agentContextManager.buildContextFromPreprocessedMessages(
6881
7058
  request,
6882
7059
  conversationSession,
6883
7060
  messages,
6884
- totalBudget,
7061
+ resolvedTotalBudget,
6885
7062
  callbacks,
6886
7063
  phaseOverride,
6887
7064
  generate,
@@ -6962,22 +7139,33 @@ var BaseAgentTask = class {
6962
7139
  });
6963
7140
  }
6964
7141
  messages.push(...fenceMessages["after-system"]);
7142
+ const currentUserIndex = findCurrentUserInputIndex(history, request.query);
7143
+ const historyBeforeCurrentUser = currentUserIndex === -1 ? history : history.slice(0, currentUserIndex);
7144
+ const currentUserMessage = currentUserIndex === -1 ? this.createCurrentUserMessage(request.query) : history[currentUserIndex];
7145
+ const historyAfterCurrentUser = currentUserIndex === -1 ? [] : history.slice(currentUserIndex + 1);
7146
+ messages.push(...historyBeforeCurrentUser);
6965
7147
  messages.push(...fenceMessages["before-current-user"]);
6966
- const hasUserMessageInHistory = history.some((m) => m.role === "user");
6967
- if (!hasUserMessageInHistory && request.query && request.query.trim()) {
6968
- messages.push({
6969
- id: generateMessageId(),
6970
- role: "user",
6971
- type: "user_input",
6972
- content: request.query.trim(),
6973
- timestamp: Date.now()
6974
- });
7148
+ if (currentUserMessage) {
7149
+ messages.push(currentUserMessage);
6975
7150
  }
6976
7151
  messages.push(...fenceMessages["after-current-user"]);
6977
- messages.push(...history);
7152
+ messages.push(...historyAfterCurrentUser);
6978
7153
  this.insertAfterLastToolResult(messages, fenceMessages["after-last-tool-result"]);
6979
7154
  return messages;
6980
7155
  }
7156
+ createCurrentUserMessage(query) {
7157
+ const content = query.trim();
7158
+ if (!content) {
7159
+ return null;
7160
+ }
7161
+ return {
7162
+ id: generateMessageId(),
7163
+ role: "user",
7164
+ type: "user_input",
7165
+ content,
7166
+ timestamp: Date.now()
7167
+ };
7168
+ }
6981
7169
  createFenceMessages(fences) {
6982
7170
  const grouped = {
6983
7171
  "after-system": [],
@@ -7042,6 +7230,19 @@ function findLastIndex2(items, predicate) {
7042
7230
  }
7043
7231
  return -1;
7044
7232
  }
7233
+ function findCurrentUserInputIndex(history, query) {
7234
+ const normalizedQuery = query.trim();
7235
+ if (!normalizedQuery) {
7236
+ return -1;
7237
+ }
7238
+ for (let index = history.length - 1; index >= 0; index -= 1) {
7239
+ const message = history[index];
7240
+ if (message.role === "user" && message.type === "user_input" && message.content.trim() === normalizedQuery) {
7241
+ return index;
7242
+ }
7243
+ }
7244
+ return -1;
7245
+ }
7045
7246
 
7046
7247
  // src/context-manager/profiles/agent/tools/index.ts
7047
7248
  var tools_exports2 = {};
@@ -8641,6 +8842,6 @@ function convertEventsToChatMessages(events) {
8641
8842
  return messages;
8642
8843
  }
8643
8844
 
8644
- export { AGENT_CONSTANTS, AGENT_CONTEXT_BUILDER_CONFIG, AISummaryGenerator, BaseContextProvider2 as BaseContextProvider, BaseConversationalTask, BasePreprocessor, CHECKPOINT_MARKER_TYPE, ContextProviderRegistry3 as ChatContextProviderRegistry, CoreContextProvider as ChatCoreContextProvider, MessageOrchestrator as ChatMessageOrchestrator, WorkingMemoryProvider as ChatWorkingMemoryProvider, ContextProviderError, ContextProviderRegistry, ContextTraceCollector, DEFAULT_MUST_KEEP_POLICY, FenceLifetimePreprocessor, HistoryPurificationPreprocessor, SUMMARIZATION_FAILED_ERROR_CODE, SummarizationCandidateSelector, SummarizationProvider, SummarizationStateUtils, SummarizationTrigger, TOOL_HISTORY_OVERFLOW_ERROR_CODE, config_exports as agentConfig, context_exports as agentContext, contracts_exports as agentContracts, orchestration_exports as agentOrchestration, preprocessors_exports as agentPreprocessors, agentSpecToContextBuilderConfig, agentSpecToRuntimeOptions, tasks_exports as agentTasks, tools_exports2 as agentTools, utils_exports as agentUtils, aiMessageToChatMessage, buildGenerateRequestFromAgentRequest, chatMessageToAiMessage, contextPolicyToContextBuilderConfig, contextPolicyToExecutionOptions, contextPolicyToMustKeepPolicy, contextPolicyToPreprocessorOptions, contextPolicyToProviderOptions, contextPolicyToRuntimeOptions, contextPolicyToSystemReminderOptions, convertEventToChatMessage, convertEventsToChatMessages, createFenceRegistry, createMessageFormatter, findMatchingTruncationRule, formatAgentLlmMessages, getDefaultTokenConfig, isContextProviderError, mergeContextPolicy, messageFormatter };
8845
+ export { AGENT_CONSTANTS, AGENT_CONTEXT_BUILDER_CONFIG, AISummaryGenerator, BaseContextProvider2 as BaseContextProvider, BaseConversationalTask, BasePreprocessor, CHECKPOINT_MARKER_TYPE, ContextProviderRegistry3 as ChatContextProviderRegistry, CoreContextProvider as ChatCoreContextProvider, MessageOrchestrator as ChatMessageOrchestrator, WorkingMemoryProvider as ChatWorkingMemoryProvider, ContextProviderError, ContextProviderRegistry, ContextTraceCollector, CurrentTurnMessageAssembler, DEFAULT_MUST_KEEP_POLICY, FenceLifetimePreprocessor, HistoryPurificationPreprocessor, SUMMARIZATION_FAILED_ERROR_CODE, SummarizationCandidateSelector, SummarizationProvider, SummarizationStateUtils, SummarizationTrigger, TOOL_HISTORY_OVERFLOW_ERROR_CODE, config_exports as agentConfig, context_exports as agentContext, contracts_exports as agentContracts, orchestration_exports as agentOrchestration, preprocessors_exports as agentPreprocessors, agentSpecToContextBuilderConfig, agentSpecToRuntimeOptions, tasks_exports as agentTasks, tools_exports2 as agentTools, utils_exports as agentUtils, aiMessageToChatMessage, buildGenerateRequestFromAgentRequest, chatMessageToAiMessage, contextPolicyToContextBuilderConfig, contextPolicyToExecutionOptions, contextPolicyToMustKeepPolicy, contextPolicyToPreprocessorOptions, contextPolicyToProviderOptions, contextPolicyToRuntimeOptions, contextPolicyToSystemReminderOptions, convertEventToChatMessage, convertEventsToChatMessages, createFenceRegistry, createMessageFormatter, findMatchingTruncationRule, formatAgentLlmMessages, getDefaultTokenConfig, isContextProviderError, mergeContextPolicy, messageFormatter };
8645
8846
  //# sourceMappingURL=context-manager.js.map
8646
8847
  //# sourceMappingURL=context-manager.js.map