@proxysoul/soulforge 2.16.0 → 2.16.1

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.
package/dist/index.js CHANGED
@@ -63415,7 +63415,7 @@ var package_default;
63415
63415
  var init_package = __esm(() => {
63416
63416
  package_default = {
63417
63417
  name: "@proxysoul/soulforge",
63418
- version: "2.16.0",
63418
+ version: "2.16.1",
63419
63419
  description: "Graph-powered code intelligence \u2014 multi-agent coding with codebase-aware AI",
63420
63420
  repository: {
63421
63421
  type: "git",
@@ -95850,6 +95850,22 @@ function buildContextEdits(config2, contextWindow, thinkingEnabled) {
95850
95850
  }
95851
95851
  return edits.length > 0 ? edits : null;
95852
95852
  }
95853
+ function buildCacheProviderOptions(ttl) {
95854
+ const cache = ttl === "1h" ? CACHE_EPHEMERAL_1H : CACHE_EPHEMERAL_5M;
95855
+ return {
95856
+ anthropic: cache,
95857
+ google: cache,
95858
+ proxy: cache,
95859
+ llmgateway: cache,
95860
+ opencode_zen: cache,
95861
+ opencode_go: cache,
95862
+ openrouter: cache,
95863
+ vercel_gateway: cache
95864
+ };
95865
+ }
95866
+ function getEphemeralCache(ttl = "5m") {
95867
+ return ttl === "1h" ? EPHEMERAL_CACHE_1H : EPHEMERAL_CACHE_5M;
95868
+ }
95853
95869
  async function buildAnthropicOptions(modelId, caps, config2) {
95854
95870
  const opts = {};
95855
95871
  const headers = {};
@@ -96186,7 +96202,7 @@ function buildGroqOptions(config2) {
96186
96202
  }
96187
96203
  return { opts };
96188
96204
  }
96189
- var NO_SUPPORT, ANTHROPIC_FULL, OPENAI_FULL, GOOGLE_FULL, XAI_FULL, DEEPSEEK_FULL, OPENROUTER_FULL, GATEWAY_FULL, COMPAT_ONLY, PROVIDER_CONSTRAINTS, LEGACY_PREFIXES, CACHE_EPHEMERAL, EPHEMERAL_CACHE;
96205
+ var NO_SUPPORT, ANTHROPIC_FULL, OPENAI_FULL, GOOGLE_FULL, XAI_FULL, DEEPSEEK_FULL, OPENROUTER_FULL, GATEWAY_FULL, COMPAT_ONLY, PROVIDER_CONSTRAINTS, LEGACY_PREFIXES, CACHE_EPHEMERAL_5M, CACHE_EPHEMERAL_1H, EPHEMERAL_CACHE_5M, EPHEMERAL_CACHE_1H, EPHEMERAL_CACHE;
96190
96206
  var init_provider_options = __esm(() => {
96191
96207
  init_models();
96192
96208
  init_providers();
@@ -96300,17 +96316,15 @@ var init_provider_options = __esm(() => {
96300
96316
  "claude-2",
96301
96317
  "claude-instant"
96302
96318
  ];
96303
- CACHE_EPHEMERAL = { cacheControl: { type: "ephemeral" } };
96304
- EPHEMERAL_CACHE = {
96305
- anthropic: CACHE_EPHEMERAL,
96306
- google: CACHE_EPHEMERAL,
96307
- proxy: CACHE_EPHEMERAL,
96308
- llmgateway: CACHE_EPHEMERAL,
96309
- opencode_zen: CACHE_EPHEMERAL,
96310
- opencode_go: CACHE_EPHEMERAL,
96311
- openrouter: CACHE_EPHEMERAL,
96312
- vercel_gateway: CACHE_EPHEMERAL
96319
+ CACHE_EPHEMERAL_5M = {
96320
+ cacheControl: { type: "ephemeral", ttl: "5m" }
96313
96321
  };
96322
+ CACHE_EPHEMERAL_1H = {
96323
+ cacheControl: { type: "ephemeral", ttl: "1h" }
96324
+ };
96325
+ EPHEMERAL_CACHE_5M = buildCacheProviderOptions("5m");
96326
+ EPHEMERAL_CACHE_1H = buildCacheProviderOptions("1h");
96327
+ EPHEMERAL_CACHE = EPHEMERAL_CACHE_5M;
96314
96328
  });
96315
96329
 
96316
96330
  // src/core/prompts/families/shared-rules.ts
@@ -96329,7 +96343,7 @@ A turn is tool calls followed by exactly one final answer. Between tool calls: z
96329
96343
 
96330
96344
  After the last tool: speak. The final answer is mandatory \u2014 every turn ends with text, never on a tool result. Speak only when (a) the task is complete, (b) a destructive/irreversible action needs confirmation, (c) genuine ambiguity blocks progress, or (d) an unrecoverable error makes further tool calls pointless. Warning about a destructive action: the warning IS the answer \u2014 full sentences, no tool chain first.
96331
96345
 
96332
- Commit boundary: when a turn has 2+ tool calls, call \`set_lockin({on:false})\` as your LAST tool immediately before the final answer. The renderer folds prior tool work into a collapsed rail and streams the answer text visibly. Skip the call for pure-chat turns (no tool work) and for one-tool turns. Don't call it before another tool \u2014 it must be last.
96346
+ Commit boundary \u2014 MANDATORY whenever a turn uses 2+ tool calls (parallel batches in one step count as 2+). Call \`set_lockin({on:false})\` as your LAST tool, after every other tool, immediately before the final answer. Not optional. Not "if convenient." Every multi-tool turn ends with set_lockin \u2192 text. Skip ONLY for pure-chat turns (zero tools) and single-tool turns. Never call before another tool \u2014 it must be the absolute last tool of the turn.
96333
96347
  </tool_loop>
96334
96348
 
96335
96349
  <answer_voice>
@@ -390901,7 +390915,10 @@ function createCodeAgent(model, options) {
390901
390915
  disablePruning: options?.disablePruning,
390902
390916
  tabId: options?.tabId
390903
390917
  });
390904
- const { maxTransientRetries: retryMaxRetries } = resolveRetrySettings(loadConfig().retry, {
390918
+ const cfg = loadConfig();
390919
+ const cacheTtl = cfg.cache?.ttl ?? "5m";
390920
+ const cacheOpts = getEphemeralCache(cacheTtl);
390921
+ const { maxTransientRetries: retryMaxRetries } = resolveRetrySettings(cfg.retry, {
390905
390922
  agent: true
390906
390923
  });
390907
390924
  return new ToolLoopAgent({
@@ -390927,7 +390944,7 @@ Ownership: you own files you edit first. check_edit_conflicts before touching an
390927
390944
  If another agent owns the file: report_finding with the exact edit instead.
390928
390945
  Coordination: report_finding after significant changes (paths, what changed, new exports). Peer findings appear in tool results.`;
390929
390946
  })(),
390930
- providerOptions: EPHEMERAL_CACHE
390947
+ providerOptions: cacheOpts
390931
390948
  },
390932
390949
  stopWhen: stopConditions,
390933
390950
  prepareStep,
@@ -390936,7 +390953,7 @@ Coordination: report_finding after significant changes (paths, what changed, new
390936
390953
  ...options?.providerOptions,
390937
390954
  anthropic: {
390938
390955
  ...options?.providerOptions?.anthropic ?? {},
390939
- cacheControl: { type: "ephemeral" },
390956
+ cacheControl: { type: "ephemeral", ttl: cacheTtl },
390940
390957
  max_tokens: MAX_OUTPUT_TOKENS
390941
390958
  }
390942
390959
  },
@@ -391010,7 +391027,10 @@ function createExploreAgent(model, options) {
391010
391027
  disablePruning: options?.disablePruning,
391011
391028
  tabId: options?.tabId
391012
391029
  });
391013
- const { maxTransientRetries: retryMaxRetries } = resolveRetrySettings(loadConfig().retry, {
391030
+ const cfg = loadConfig();
391031
+ const cacheTtl = cfg.cache?.ttl ?? "5m";
391032
+ const cacheOpts = getEphemeralCache(cacheTtl);
391033
+ const { maxTransientRetries: retryMaxRetries } = resolveRetrySettings(cfg.retry, {
391014
391034
  agent: true
391015
391035
  });
391016
391036
  return new ToolLoopAgent({
@@ -391034,7 +391054,7 @@ function createExploreAgent(model, options) {
391034
391054
  return `${base}
391035
391055
  Coordination: report_finding after discoveries \u2014 especially shared symbols/configs with peer targets. check_findings for peer detail.`;
391036
391056
  })(),
391037
- providerOptions: EPHEMERAL_CACHE
391057
+ providerOptions: cacheOpts
391038
391058
  },
391039
391059
  stopWhen: stopConditions,
391040
391060
  prepareStep,
@@ -391043,7 +391063,7 @@ Coordination: report_finding after discoveries \u2014 especially shared symbols/
391043
391063
  ...options?.providerOptions,
391044
391064
  anthropic: {
391045
391065
  ...options?.providerOptions?.anthropic ?? {},
391046
- cacheControl: { type: "ephemeral" },
391066
+ cacheControl: { type: "ephemeral", ttl: cacheTtl },
391047
391067
  max_tokens: MAX_OUTPUT_TOKENS
391048
391068
  }
391049
391069
  },
@@ -396777,14 +396797,10 @@ function lastStepHadPlanCall(messages) {
396777
396797
  }
396778
396798
  return false;
396779
396799
  }
396780
- function buildForgePrepareStep(isPlanMode, drainSteering, contextManager, tabId, codeExecution3, parentMessagesRef, proxyInstructions) {
396800
+ function buildForgePrepareStep(isPlanMode, drainSteering, contextManager, tabId, codeExecution3, parentMessagesRef, proxyInstructions, cacheOpts = EPHEMERAL_CACHE) {
396781
396801
  const previousInjects = [];
396782
396802
  const recallInjects = [];
396783
396803
  let lastUserTurnCount = 0;
396784
- let lockInToolCallsThisTurn = 0;
396785
- let lockInNudgedOffThisTurn = false;
396786
- let lockInLastUserTurnCount = 0;
396787
- let lockInCommittedThisTurn = false;
396788
396804
  const proxyInstructionsMessage = proxyInstructions ? {
396789
396805
  role: "user",
396790
396806
  content: [
@@ -396795,7 +396811,7 @@ ${proxyInstructions}
396795
396811
  </system-instructions>`
396796
396812
  }
396797
396813
  ],
396798
- providerOptions: EPHEMERAL_CACHE
396814
+ providerOptions: cacheOpts
396799
396815
  } : null;
396800
396816
  return async ({
396801
396817
  stepNumber,
@@ -396845,12 +396861,12 @@ ${proxyInstructions}
396845
396861
  {
396846
396862
  role: "user",
396847
396863
  content: pair[0].content,
396848
- providerOptions: EPHEMERAL_CACHE
396864
+ providerOptions: cacheOpts
396849
396865
  },
396850
396866
  {
396851
396867
  role: "assistant",
396852
396868
  content: pair[1].content,
396853
- providerOptions: EPHEMERAL_CACHE
396869
+ providerOptions: cacheOpts
396854
396870
  }
396855
396871
  ]
396856
396872
  });
@@ -396915,26 +396931,30 @@ ${proxyInstructions}
396915
396931
  hints.push(crossTab);
396916
396932
  }
396917
396933
  {
396918
- const utc = countUserTurns(sanitized);
396919
- if (utc > lockInLastUserTurnCount) {
396920
- lockInLastUserTurnCount = utc;
396921
- lockInToolCallsThisTurn = 0;
396922
- lockInNudgedOffThisTurn = false;
396923
- lockInCommittedThisTurn = false;
396924
- }
396925
- const prev = prevStep;
396926
- const lastHadTools = !!prev?.toolCalls?.length;
396927
- if (lastHadTools) {
396928
- lockInToolCallsThisTurn += prev.toolCalls?.length ?? 0;
396929
- for (const tc of prev.toolCalls ?? []) {
396930
- if (tc.toolName === "set_lockin" && tc.input?.on === false) {
396931
- lockInCommittedThisTurn = true;
396934
+ let toolCallsThisTurn = 0;
396935
+ let committedThisTurn = false;
396936
+ for (let i2 = sanitized.length - 1;i2 >= 0; i2--) {
396937
+ const m = sanitized[i2];
396938
+ if (!m)
396939
+ continue;
396940
+ if (m.role === "user")
396941
+ break;
396942
+ if (m.role !== "assistant" || !Array.isArray(m.content))
396943
+ continue;
396944
+ for (const part of m.content) {
396945
+ if (typeof part !== "object" || part === null || !("type" in part))
396946
+ continue;
396947
+ const p = part;
396948
+ if (p.type !== "tool-call")
396949
+ continue;
396950
+ toolCallsThisTurn++;
396951
+ if (p.toolName === "set_lockin" && p.input?.on === false) {
396952
+ committedThisTurn = true;
396932
396953
  }
396933
396954
  }
396934
396955
  }
396935
- if (!lockInCommittedThisTurn && !lockInNudgedOffThisTurn && lockInToolCallsThisTurn >= 2) {
396956
+ if (!committedThisTurn && toolCallsThisTurn >= 2) {
396936
396957
  hints.push("Multiple tool calls this turn without a commit boundary. Call set_lockin({on:false}) as your LAST tool before your final answer so prior tool work collapses into the rail and your text streams visibly.");
396937
- lockInNudgedOffThisTurn = true;
396938
396958
  }
396939
396959
  }
396940
396960
  if (stepNumber >= PERSONA_NUDGE_START && (stepNumber - PERSONA_NUDGE_START) % PERSONA_NUDGE_INTERVAL === 0) {
@@ -397319,11 +397339,13 @@ function createForgeAgent({
397319
397339
  }
397320
397340
  return names.length < allToolNames.length ? names : undefined;
397321
397341
  };
397342
+ const cacheTtl = loadConfig().cache?.ttl ?? "5m";
397343
+ const cacheOpts = getEphemeralCache(cacheTtl);
397322
397344
  const wrappedProviderOptions = {
397323
397345
  ...providerOptions,
397324
397346
  anthropic: {
397325
397347
  ...providerOptions?.anthropic ?? {},
397326
- cacheControl: { type: "ephemeral" },
397348
+ cacheControl: { type: "ephemeral", ttl: cacheTtl },
397327
397349
  max_tokens: MAX_OUTPUT_TOKENS
397328
397350
  }
397329
397351
  };
@@ -397344,7 +397366,7 @@ function createForgeAgent({
397344
397366
  instructions: isProxyClaude ? undefined : {
397345
397367
  role: "system",
397346
397368
  content: buildInstructions(contextManager, modelId),
397347
- providerOptions: EPHEMERAL_CACHE
397369
+ providerOptions: cacheOpts
397348
397370
  },
397349
397371
  callOptionsSchema: exports_external.object({
397350
397372
  userMessage: exports_external.string().nullable()
@@ -397356,7 +397378,7 @@ function createForgeAgent({
397356
397378
  ...activeTools ? { activeTools } : {}
397357
397379
  };
397358
397380
  },
397359
- prepareStep: buildForgePrepareStep(forgeMode === "plan", drainSteering, contextManager, tabId, canUseCodeExecution, parentMessagesRef, isProxyClaude ? buildInstructions(contextManager, modelId) : undefined),
397381
+ prepareStep: buildForgePrepareStep(forgeMode === "plan", drainSteering, contextManager, tabId, canUseCodeExecution, parentMessagesRef, isProxyClaude ? buildInstructions(contextManager, modelId) : undefined, cacheOpts),
397360
397382
  experimental_repairToolCall: repairToolCall,
397361
397383
  providerOptions: wrappedProviderOptions,
397362
397384
  ...subagentHeaders ? { headers: subagentHeaders } : {}
@@ -413405,6 +413427,20 @@ Project commands: ${parts2.join(" \xB7 ")}` : "";
413405
413427
  hasSoulMapDiff() {
413406
413428
  return this.soulMapDiffChangedFiles.size > 0 && this.isRepoMapReady();
413407
413429
  }
413430
+ lastTurnAt = 0;
413431
+ maybeReseedExpiredCache(idleMs = 270000) {
413432
+ const now2 = Date.now();
413433
+ const prev = this.lastTurnAt;
413434
+ this.lastTurnAt = now2;
413435
+ if (prev === 0)
413436
+ return false;
413437
+ if (now2 - prev < idleMs)
413438
+ return false;
413439
+ if (this.soulMapDiffChangedFiles.size === 0)
413440
+ return false;
413441
+ this.resetForCompaction();
413442
+ return true;
413443
+ }
413408
413444
  };
413409
413445
  });
413410
413446
 
@@ -496419,6 +496455,11 @@ Proceeding without it will significantly reduce capabilities \u2014 no soul tool
496419
496455
  }
496420
496456
  }
496421
496457
  setLoadingStartedAt(Date.now());
496458
+ {
496459
+ const cacheTtl = effectiveConfig2.cache?.ttl ?? "5m";
496460
+ const idleMs = cacheTtl === "1h" ? 3540000 : 270000;
496461
+ contextManager.maybeReseedExpiredCache(idleMs);
496462
+ }
496422
496463
  const agent2 = createForgeAgent({
496423
496464
  model,
496424
496465
  fullModelId: modelId,
@@ -526331,6 +526372,8 @@ function readValuesFromLayer(layer) {
526331
526372
  v4.pruning = layer.contextManagement.pruningTarget;
526332
526373
  else if (layer.contextManagement?.disablePruning !== undefined)
526333
526374
  v4.pruning = layer.contextManagement.disablePruning ? "none" : "subagents";
526375
+ if (layer.cache?.ttl !== undefined)
526376
+ v4.cacheTtl = layer.cache.ttl;
526334
526377
  return v4;
526335
526378
  }
526336
526379
  function effectiveValues(global2, project2) {
@@ -526406,6 +526449,8 @@ function buildPatch(key3, value) {
526406
526449
  return {
526407
526450
  contextManagement: { pruningTarget: value }
526408
526451
  };
526452
+ case "cacheTtl":
526453
+ return { cache: { ttl: value } };
526409
526454
  default:
526410
526455
  return {};
526411
526456
  }
@@ -526882,6 +526927,14 @@ var init_ProviderSettings = __esm(async () => {
526882
526927
  label: "Clear old tool uses",
526883
526928
  desc: "Drop old tool results at 65% ctx. Busts prompt cache when it fires",
526884
526929
  type: "toggle"
526930
+ },
526931
+ { type: "section", label: "Cache" },
526932
+ {
526933
+ key: "cacheTtl",
526934
+ label: "Cache TTL",
526935
+ desc: "5m = free \xB7 1h = ~2\xD7 cache-write cost, 12\xD7 lifetime (long agentic runs)",
526936
+ type: "cycle",
526937
+ options: ["5m", "1h"]
526885
526938
  }
526886
526939
  ];
526887
526940
  OPENAI_ITEMS = [
@@ -527097,7 +527150,8 @@ var init_ProviderSettings = __esm(async () => {
527097
527150
  groqReasoningEffort: "off",
527098
527151
  openaiReasoningSummary: "off",
527099
527152
  openaiVerbosity: "off",
527100
- groqReasoningFormat: "off"
527153
+ groqReasoningFormat: "off",
527154
+ cacheTtl: "5m"
527101
527155
  };
527102
527156
  });
527103
527157
 
@@ -50577,7 +50577,7 @@ var package_default;
50577
50577
  var init_package = __esm(() => {
50578
50578
  package_default = {
50579
50579
  name: "@proxysoul/soulforge",
50580
- version: "2.16.0",
50580
+ version: "2.16.1",
50581
50581
  description: "Graph-powered code intelligence \u2014 multi-agent coding with codebase-aware AI",
50582
50582
  repository: {
50583
50583
  type: "git",
@@ -81645,7 +81645,20 @@ function supportsTemperature(modelId) {
81645
81645
  return true;
81646
81646
  return v.major < 5 && (v.major < 4 || v.minor < 7);
81647
81647
  }
81648
- var NO_SUPPORT, ANTHROPIC_FULL, OPENAI_FULL, GOOGLE_FULL, XAI_FULL, DEEPSEEK_FULL, OPENROUTER_FULL, GATEWAY_FULL, COMPAT_ONLY, PROVIDER_CONSTRAINTS;
81648
+ function buildCacheProviderOptions(ttl) {
81649
+ const cache = ttl === "1h" ? CACHE_EPHEMERAL_1H : CACHE_EPHEMERAL_5M;
81650
+ return {
81651
+ anthropic: cache,
81652
+ google: cache,
81653
+ proxy: cache,
81654
+ llmgateway: cache,
81655
+ opencode_zen: cache,
81656
+ opencode_go: cache,
81657
+ openrouter: cache,
81658
+ vercel_gateway: cache
81659
+ };
81660
+ }
81661
+ var NO_SUPPORT, ANTHROPIC_FULL, OPENAI_FULL, GOOGLE_FULL, XAI_FULL, DEEPSEEK_FULL, OPENROUTER_FULL, GATEWAY_FULL, COMPAT_ONLY, PROVIDER_CONSTRAINTS, CACHE_EPHEMERAL_5M, CACHE_EPHEMERAL_1H, EPHEMERAL_CACHE_5M, EPHEMERAL_CACHE_1H;
81649
81662
  var init_provider_options = __esm(() => {
81650
81663
  init_models();
81651
81664
  init_providers();
@@ -81754,6 +81767,20 @@ var init_provider_options = __esm(() => {
81754
81767
  interleavedThinking: false
81755
81768
  }
81756
81769
  };
81770
+ CACHE_EPHEMERAL_5M = {
81771
+ cacheControl: {
81772
+ type: "ephemeral",
81773
+ ttl: "5m"
81774
+ }
81775
+ };
81776
+ CACHE_EPHEMERAL_1H = {
81777
+ cacheControl: {
81778
+ type: "ephemeral",
81779
+ ttl: "1h"
81780
+ }
81781
+ };
81782
+ EPHEMERAL_CACHE_5M = buildCacheProviderOptions("5m");
81783
+ EPHEMERAL_CACHE_1H = buildCacheProviderOptions("1h");
81757
81784
  });
81758
81785
 
81759
81786
  // src/core/compaction/summarize.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proxysoul/soulforge",
3
- "version": "2.16.0",
3
+ "version": "2.16.1",
4
4
  "description": "Graph-powered code intelligence — multi-agent coding with codebase-aware AI",
5
5
  "repository": {
6
6
  "type": "git",