negotium 0.1.19 → 0.1.21

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 (46) hide show
  1. package/dist/agent-helpers.js +146 -23
  2. package/dist/agent-helpers.js.map +14 -12
  3. package/dist/cron.js +137 -52
  4. package/dist/cron.js.map +20 -19
  5. package/dist/hosted-agent.js +29 -17
  6. package/dist/hosted-agent.js.map +7 -7
  7. package/dist/main.js +145 -55
  8. package/dist/main.js.map +20 -19
  9. package/dist/mcp-factories.js +23 -22
  10. package/dist/mcp-factories.js.map +3 -3
  11. package/dist/prompts.js +98 -9
  12. package/dist/prompts.js.map +6 -5
  13. package/dist/runtime/scripts/browser-passkey-policy.mjs +36 -0
  14. package/dist/runtime/scripts/browser-vault-transform.mjs +33 -0
  15. package/dist/runtime/scripts/mcp-patchright-http.mjs +22 -4
  16. package/dist/runtime/src/agents/archiver.ts +0 -14
  17. package/dist/runtime/src/agents/claude-provider.ts +11 -7
  18. package/dist/runtime/src/agents/execution-host.ts +10 -1
  19. package/dist/runtime/src/agents/idle-archiver.ts +21 -0
  20. package/dist/runtime/src/agents/maestro-provider.ts +9 -14
  21. package/dist/runtime/src/agents/mcp-tools/self-config.ts +1 -1
  22. package/dist/runtime/src/agents/mcp-tools/spawn-subagent.ts +6 -1
  23. package/dist/runtime/src/agents/memory-archive-policy.ts +34 -0
  24. package/dist/runtime/src/agents/model-catalog.ts +84 -18
  25. package/dist/runtime/src/mcp/factories/vault.ts +36 -34
  26. package/dist/runtime/src/mcp/vault-server.ts +1 -0
  27. package/dist/runtime/src/platform/mcp-config.ts +4 -8
  28. package/dist/runtime/src/platform/playwright/manager.ts +5 -2
  29. package/dist/runtime/src/prompts/builders.ts +36 -7
  30. package/dist/runtime/src/runtime/turn-runner.ts +2 -0
  31. package/dist/runtime/src/storage/topic-archive.ts +5 -2
  32. package/dist/runtime/src/topics/lifecycle.ts +2 -1
  33. package/dist/runtime/src/topics/session.ts +2 -0
  34. package/dist/runtime/src/version.ts +1 -1
  35. package/dist/storage.js +23 -3
  36. package/dist/storage.js.map +5 -4
  37. package/dist/types/packages/core/src/agents/claude-provider.d.ts +1 -0
  38. package/dist/types/packages/core/src/agents/execution-host.d.ts +2 -0
  39. package/dist/types/packages/core/src/agents/idle-archiver.d.ts +2 -0
  40. package/dist/types/packages/core/src/agents/memory-archive-policy.d.ts +14 -0
  41. package/dist/types/packages/core/src/agents/model-catalog.d.ts +77 -0
  42. package/dist/types/packages/core/src/mcp/factories/vault.d.ts +1 -0
  43. package/dist/types/packages/core/src/prompts/builders.d.ts +5 -1
  44. package/dist/types/packages/core/src/storage/topic-archive.d.ts +1 -0
  45. package/dist/types/packages/core/src/version.d.ts +1 -1
  46. package/package.json +2 -2
package/dist/cron.js CHANGED
@@ -1947,6 +1947,19 @@ function vaultListWithValues(userId) {
1947
1947
  function vaultList(userId) {
1948
1948
  return activeVaultDatabase().prepare("SELECT key, description FROM vault WHERE user_id = ? ORDER BY key").all(userId);
1949
1949
  }
1950
+ function vaultSubstituteDetailed(userId, text) {
1951
+ const entries = new Map(vaultListWithValues(userId).map((entry) => [entry.key, entry.value]));
1952
+ const usedKeys = new Set;
1953
+ const substituted = text.replace(/\{\{([^}]+)\}\}/g, (match, rawKey) => {
1954
+ const key = normalizeVaultKey(rawKey);
1955
+ const value = entries.get(key);
1956
+ if (value === undefined)
1957
+ return match;
1958
+ usedKeys.add(key);
1959
+ return value;
1960
+ });
1961
+ return { text: substituted, usedKeys: [...usedKeys] };
1962
+ }
1950
1963
  function valueReferencesVaultKey(userId, value) {
1951
1964
  const keys = new Set(vaultList(userId).map((entry) => entry.key));
1952
1965
  const visit = (candidate) => {
@@ -2037,7 +2050,7 @@ function createVaultToolPolicy(host) {
2037
2050
  }
2038
2051
  return { isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool };
2039
2052
  }
2040
- var SENSITIVE_RUNTIME_NAMES, VAULT_BROKER_REDIRECT_ERROR = "Vault placeholders must be executed through mcp__vault__vault_run (shell/CLI) or mcp__vault__vault_http_request (HTTP) so secret values cannot enter the model transcript.", defaultVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool;
2053
+ var SENSITIVE_RUNTIME_NAMES, defaultVaultToolPolicy, isVaultBrokerTool, referencesRuntimeSecretStorage, shouldRedirectVaultTool;
2041
2054
  var init_vault_tool_policy = __esm(async () => {
2042
2055
  init_sensitive_path();
2043
2056
  await init_vault();
@@ -2838,9 +2851,7 @@ var init_mcp_config = __esm(() => {
2838
2851
  vault: {
2839
2852
  ...commonRuntimeMcpPolicy("vault"),
2840
2853
  build({ userId, agent }) {
2841
- const args = [`--user-id=${userId}`];
2842
- if (agent === "codex")
2843
- args.push("--http-only=true");
2854
+ const args = [`--user-id=${userId}`, "--list-only=true"];
2844
2855
  return buildStdioMcpServer(agent, VAULT_SERVER, args);
2845
2856
  }
2846
2857
  }
@@ -2870,12 +2881,12 @@ function hostedMcpServers(opts) {
2870
2881
  function redactHostedSecrets(userId, value) {
2871
2882
  return activeHost().redactVaultSecrets(userId, value);
2872
2883
  }
2884
+ function substituteHostedSecrets(userId, value) {
2885
+ return activeHost().substituteVaultSecrets(userId, value);
2886
+ }
2873
2887
  function referencesHostedSecretStorage(value) {
2874
2888
  return activeHost().referencesRuntimeSecretStorage(value);
2875
2889
  }
2876
- function shouldRedirectHostedVaultTool(userId, toolName, input) {
2877
- return activeHost().shouldRedirectVaultTool(userId, toolName, input);
2878
- }
2879
2890
  function hostedClaudeCodeExecutablePath() {
2880
2891
  return activeHost().claudeCodeExecutablePath();
2881
2892
  }
@@ -2891,6 +2902,7 @@ var init_execution_host = __esm(async () => {
2891
2902
  defaultHost = {
2892
2903
  getMcpServersForQuery,
2893
2904
  redactVaultSecrets,
2905
+ substituteVaultSecrets: (userId, value) => vaultSubstituteDetailed(userId, value).text,
2894
2906
  referencesRuntimeSecretStorage,
2895
2907
  shouldRedirectVaultTool,
2896
2908
  claudeCodeExecutablePath: () => CLAUDE_EXECUTABLE,
@@ -2985,6 +2997,9 @@ var DEFAULT_CONTEXT_WARNING_RATIO = 0.8;
2985
2997
  import { spawn as spawn2 } from "child_process";
2986
2998
  import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
2987
2999
  import { query } from "@anthropic-ai/claude-agent-sdk";
3000
+ function substituteClaudeToolInput(userId, input) {
3001
+ return deepMapStrings(input, (value) => substituteHostedSecrets(userId, value));
3002
+ }
2988
3003
  function buildClaudeDisallowedTools(extra = undefined) {
2989
3004
  return [
2990
3005
  ...new Set([
@@ -3215,14 +3230,14 @@ async function* claudeProvider(opts) {
3215
3230
  };
3216
3231
  }
3217
3232
  const userId = opts.userId ?? "";
3218
- if (!shouldRedirectHostedVaultTool(userId, tool_name, tool_input)) {
3233
+ const withVault = substituteClaudeToolInput(userId, tool_input);
3234
+ if (JSON.stringify(withVault) === JSON.stringify(tool_input)) {
3219
3235
  return { continue: true };
3220
3236
  }
3221
3237
  return {
3222
3238
  hookSpecificOutput: {
3223
3239
  hookEventName: "PreToolUse",
3224
- permissionDecision: "deny",
3225
- permissionDecisionReason: VAULT_BROKER_REDIRECT_ERROR
3240
+ updatedInput: withVault
3226
3241
  }
3227
3242
  };
3228
3243
  }
@@ -3432,7 +3447,6 @@ var CLAUDE_DEFAULT_DISALLOWED_TOOLS, CLAUDE_NATIVE_AGENT_TOOLS, CLAUDE_IMAGE_MAX
3432
3447
  var init_claude_provider = __esm(async () => {
3433
3448
  init_claude_registry();
3434
3449
  await init_execution_host();
3435
- await init_vault_tool_policy();
3436
3450
  init_file_events();
3437
3451
  init_logger();
3438
3452
  CLAUDE_DEFAULT_DISALLOWED_TOOLS = [
@@ -3455,7 +3469,7 @@ var init_claude_provider = __esm(async () => {
3455
3469
  });
3456
3470
 
3457
3471
  // ../../packages/core/src/version.ts
3458
- var NEGOTIUM_VERSION = "0.1.19";
3472
+ var NEGOTIUM_VERSION = "0.1.21";
3459
3473
 
3460
3474
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
3461
3475
  import { spawn as spawn3 } from "child_process";
@@ -4093,14 +4107,12 @@ function buildMaestroDisallowedTools(callerDisallowedTools = []) {
4093
4107
  function buildVaultHook(userId) {
4094
4108
  return {
4095
4109
  name: "vault-guard",
4096
- pre({ toolName, input }) {
4110
+ pre({ input }) {
4097
4111
  if (referencesHostedSecretStorage(input)) {
4098
4112
  return { decision: "block", error: "Runtime secret storage access is not permitted" };
4099
4113
  }
4100
- if (shouldRedirectHostedVaultTool(userId, toolName, input)) {
4101
- return { decision: "block", error: VAULT_BROKER_REDIRECT_ERROR };
4102
- }
4103
- return { decision: "allow" };
4114
+ const substituted = deepMapStrings(input, (value) => substituteHostedSecrets(userId, value));
4115
+ return JSON.stringify(substituted) === JSON.stringify(input) ? { decision: "allow" } : { decision: "modify", input: substituted };
4104
4116
  },
4105
4117
  post({ output }) {
4106
4118
  const redacted = redactHostedSecrets(userId, output);
@@ -4156,7 +4168,6 @@ var MAESTRO_DEFAULT_MAX_TOKENS = 32768, PROVIDER_ASK_USER_TOOL = "AskUserQuestio
4156
4168
  var init_maestro_provider = __esm(async () => {
4157
4169
  init_maestro_bootstrap_env();
4158
4170
  await init_execution_host();
4159
- await init_vault_tool_policy();
4160
4171
  MAESTRO_NATIVE_TASK_TOOLS = [
4161
4172
  "TaskCreate",
4162
4173
  "TaskUpdate",
@@ -5437,6 +5448,10 @@ var init_ask_user = __esm(async () => {
5437
5448
  });
5438
5449
 
5439
5450
  // ../../packages/core/src/agents/model-catalog.ts
5451
+ function formatSelectableModel(candidate) {
5452
+ const tier = `${candidate.intelligenceTier[0].toUpperCase()}${candidate.intelligenceTier.slice(1)}`;
5453
+ return `${candidate.agent} / \`${candidate.model}\` [${tier}-level]: ${candidate.routingSummary}`;
5454
+ }
5440
5455
  function selectableModel(value) {
5441
5456
  const normalized = value.trim().toLowerCase();
5442
5457
  return SELECTABLE_MODELS.find((candidate) => candidate.model === normalized);
@@ -5459,7 +5474,7 @@ function resolveModelForAgent(agent, requested, registry) {
5459
5474
  return defaultModel;
5460
5475
  return registry.validateModel(requested) ? requested : defaultModel;
5461
5476
  }
5462
- var MODEL_OWNER, SELECTABLE_MODELS, FALLBACK_ORDER, AGENT_DISPLAY_NAME;
5477
+ var MODEL_OWNER, MODEL_COST_RESEARCHED_AT = "2026-07-19", MODEL_COST_ROUTING_SUMMARY = "Cost basis (2026-07-19): Codex Pro 20x and Claude Max 20x are each $200/month; DeepSeek Pro is pay-per-token. Relative marginal token cost: DeepSeek Pro << Codex < Claude.", CODEX_PRO_20X_COST = "ChatGPT Pro 20x subscription: $200/month", CODEX_COMMUNITY_WEEKLY = "Community plan-level observation: roughly 2\u20134B raw/cached tokens per week; fresh-input equivalent is much lower and unstable (low confidence)", CLAUDE_MAX_20X_COST = "Claude Max 20x subscription: $200/month", CLAUDE_COMMUNITY_SESSION = "Community observations vary from roughly 220\u2013250K locally displayed tokens per 5-hour session to billions of cache-heavy raw tokens per week; calibrated reports value a full weekly allowance around $680\u2013$1,900 at API rates. Recent heavy-model reports reach the weekly cap after about 4\u20135 full sessions (low confidence; not a token cap)", SELECTABLE_MODELS, FALLBACK_ORDER, AGENT_DISPLAY_NAME;
5463
5478
  var init_model_catalog = __esm(() => {
5464
5479
  init_config();
5465
5480
  MODEL_OWNER = {
@@ -5479,47 +5494,72 @@ var init_model_catalog = __esm(() => {
5479
5494
  {
5480
5495
  model: "gpt-5.6-sol",
5481
5496
  agent: "codex",
5482
- description: "Latest frontier agentic coding model."
5497
+ description: "Highest-capability Codex route for the hardest agentic coding work.",
5498
+ intelligenceTier: "fable",
5499
+ routingSummary: "hardest coding work; 5x Codex quota cost",
5500
+ accessCost: CODEX_PRO_20X_COST,
5501
+ marginalTokenCost: "Codex credits: $5/M uncached input, $0.50/M cached input, $30/M output",
5502
+ estimatedUsage: `Official Pro 20x range: 300\u20131,800 local messages per 5 hours; quota weight 5x Luna. ${CODEX_COMMUNITY_WEEKLY}`
5483
5503
  },
5484
5504
  {
5485
5505
  model: "gpt-5.6-terra",
5486
5506
  agent: "codex",
5487
- description: "Balanced agentic coding model for everyday work."
5507
+ description: "High-capability Codex route for complex coding and reasoning.",
5508
+ intelligenceTier: "opus",
5509
+ routingSummary: "complex coding and reasoning; 2.5x Codex quota cost",
5510
+ accessCost: CODEX_PRO_20X_COST,
5511
+ marginalTokenCost: "Codex credits: $2.50/M uncached input, $0.25/M cached input, $15/M output",
5512
+ estimatedUsage: `Official Pro 20x range: 400\u20132,200 local messages per 5 hours; quota weight 2.5x Luna. ${CODEX_COMMUNITY_WEEKLY}`
5488
5513
  },
5489
5514
  {
5490
5515
  model: "gpt-5.6-luna",
5491
5516
  agent: "codex",
5492
- description: "Fast and affordable agentic coding model."
5493
- },
5494
- {
5495
- model: "gpt-5.5",
5496
- agent: "codex",
5497
- description: "Frontier model for complex coding, research, and real-world work."
5517
+ description: "Default Codex route with strong everyday coding intelligence.",
5518
+ intelligenceTier: "sonnet",
5519
+ routingSummary: "everyday coding default; lowest Codex quota cost (1x)",
5520
+ accessCost: CODEX_PRO_20X_COST,
5521
+ marginalTokenCost: "Codex credits: $1/M uncached input, $0.10/M cached input, $6/M output",
5522
+ estimatedUsage: `Official Pro 20x range: 1,000\u20135,600 local messages per 5 hours; lowest Codex quota weight (1x). ${CODEX_COMMUNITY_WEEKLY}`
5498
5523
  },
5499
5524
  {
5500
5525
  model: "fable",
5501
5526
  agent: "claude",
5502
- description: "Fable 5 \xB7 Most capable for your hardest and longest-running tasks \xB7 $10/$50 per Mtok"
5527
+ description: "Highest-capability Claude route for the hardest and longest-running tasks.",
5528
+ intelligenceTier: "fable",
5529
+ routingSummary: "hardest long-running work; highest Claude cost; explicit request only",
5530
+ accessCost: CLAUDE_MAX_20X_COST,
5531
+ marginalTokenCost: "Claude API/extra usage: $10/M input, $12.50/M cache write, $1/M cache read, $50/M output",
5532
+ estimatedUsage: `${CLAUDE_COMMUNITY_SESSION}; Fable drains weighted quota fastest, so use only on explicit user request. No stable per-model token cap is published.`
5503
5533
  },
5504
5534
  {
5505
5535
  model: "opus",
5506
5536
  agent: "claude",
5507
- description: "Opus 4.8 with 1M context \xB7 Best for everyday, complex tasks \xB7 $5/$25 per Mtok"
5537
+ description: "High-capability Claude route for complex reasoning and tool-heavy work.",
5538
+ intelligenceTier: "opus",
5539
+ routingSummary: "complex reasoning and tool-heavy work; about 2.5x Sonnet marginal cost",
5540
+ accessCost: CLAUDE_MAX_20X_COST,
5541
+ marginalTokenCost: "Claude API/extra usage: $5/M input, $6.25/M cache write, $0.50/M cache read, $25/M output",
5542
+ estimatedUsage: `${CLAUDE_COMMUNITY_SESSION}; Opus uses the shared all-model weekly pool more quickly than Sonnet. No stable per-model token cap is published.`
5508
5543
  },
5509
5544
  {
5510
5545
  model: "sonnet",
5511
5546
  agent: "claude",
5512
- description: "Sonnet 5 \xB7 Efficient for routine tasks \xB7 $2/$10 per Mtok \xB7 promo through Aug 31"
5547
+ description: "Default Claude route for capable, efficient everyday work.",
5548
+ intelligenceTier: "sonnet",
5549
+ routingSummary: "capable everyday default; lowest Claude model cost",
5550
+ accessCost: CLAUDE_MAX_20X_COST,
5551
+ marginalTokenCost: "Claude API/extra usage introductory rate: $2/M input, $2.50/M cache write, $0.20/M cache read, $10/M output through 2026-08-31; then $3/M input and $15/M output",
5552
+ estimatedUsage: `${CLAUDE_COMMUNITY_SESSION}; Sonnet also has a separate weekly allowance and normally provides the highest Claude throughput. No stable weekly token cap is published.`
5513
5553
  },
5514
5554
  {
5515
5555
  model: "deepseek-pro",
5516
5556
  agent: "maestro",
5517
- description: "Sonnet-level performance at lower cost \xB7 Best for everyday tasks over coding"
5518
- },
5519
- {
5520
- model: "deepseek-flash",
5521
- agent: "maestro",
5522
- description: "DeepSeek V4 Flash \xB7 Fast and low-cost for lightweight everyday tasks"
5557
+ description: "API-priced Sonnet-level route for cost-efficient everyday work.",
5558
+ intelligenceTier: "sonnet",
5559
+ routingSummary: "cost-efficient everyday work; pay-per-token and cheapest route",
5560
+ accessCost: "DeepSeek V4 Pro pay-as-you-go API; no monthly subscription required",
5561
+ marginalTokenCost: "DeepSeek API: $0.435/M uncached input, $0.003625/M cached input, $0.87/M output",
5562
+ estimatedUsage: "No subscription token cap; pay per token. Official account concurrency limit is 500 requests."
5523
5563
  }
5524
5564
  ];
5525
5565
  FALLBACK_ORDER = {
@@ -6155,6 +6195,7 @@ async function spawnPlaywright(instanceKey, userId, reservedPort, browserBin = P
6155
6195
  String(port),
6156
6196
  "--host",
6157
6197
  "127.0.0.1",
6198
+ "--headed",
6158
6199
  "--user-data-dir",
6159
6200
  userDataDir
6160
6201
  ];
@@ -6163,6 +6204,7 @@ async function spawnPlaywright(instanceKey, userId, reservedPort, browserBin = P
6163
6204
  const childEnv = {
6164
6205
  ...process.env,
6165
6206
  NEGOTIUM_BROWSER_CAPABILITY: capability,
6207
+ NEGOTIUM_BROWSER_VAULT_USER_ID: userId,
6166
6208
  ...proxy ? {
6167
6209
  NEGOTIUM_BROWSER_PROXY_SERVER: proxy.server,
6168
6210
  ...proxy.username ? { NEGOTIUM_BROWSER_PROXY_USERNAME: proxy.username } : {},
@@ -6994,7 +7036,7 @@ function loadAgentPrompt(filename) {
6994
7036
  prompt: match[2].trim()
6995
7037
  };
6996
7038
  }
6997
- function buildRuntimeToolSection(agentKind, canSpawnSubagents = false, visualTools = false, fileDeliveryTools = false) {
7039
+ function buildRuntimeToolSection(agentKind, canSpawnSubagents = false, visualTools = false, fileDeliveryTools = false, currentModel, currentEffort) {
6998
7040
  const runtimeNamespace = "mcp__runtime";
6999
7041
  const taskNamespace = "mcp__task";
7000
7042
  const visualToolLine = agentKind === "codex" ? `To display charts, tables, or interactive HTML results to the user, call the \`show_html\` function in the \`${runtimeNamespace}\` namespace with { html: "<complete HTML string>", title?: "optional title" }.` : `To display charts, tables, or interactive HTML results to the user, call the MCP tool "${runtimeNamespace}__show_html" with { html: "<complete HTML string>", title?: "optional title" }.`;
@@ -7052,20 +7094,26 @@ function buildRuntimeToolSection(agentKind, canSpawnSubagents = false, visualToo
7052
7094
  "Do not use session communication to make another topic perform destructive changes without the user's clear intent.",
7053
7095
  ...spawnSubagentSection
7054
7096
  ];
7097
+ const modelCatalog = SELECTABLE_MODELS.map((candidate) => `- ${formatSelectableModel(candidate)}`);
7055
7098
  const topicConfig = [
7056
7099
  "",
7057
7100
  "## Topic Configuration (model / agent / effort)",
7101
+ `Current execution: agent=\`${agentKind}\`, model=\`${currentModel ?? "unknown (call get_model)"}\`, effort=\`${currentEffort ?? "provider default/off"}\`.`,
7058
7102
  "The user's configured agent/model/effort is intentional. Preserve it by default.",
7059
7103
  `When the user explicitly asks to change the model, agent backend, or reasoning effort for THIS topic, call "${runtimeNamespace}__set_model", "${runtimeNamespace}__set_agent", or "${runtimeNamespace}__set_effort". The change applies from your NEXT turn. After calling, briefly confirm and the system will continue with the new setting.`,
7060
7104
  "`set_effort` is available but discouraged; use it only when the user explicitly requests an effort change.",
7061
- "`set_model` may be called autonomously only when the current model is clearly below the task's required capability, such as complex algorithm design, proof-level math, or broad multi-file refactoring. In that case, move up one step within the same agent and end the turn. Do not use vague task complexity as a trigger.",
7105
+ "`set_model` may be called autonomously only when the current model is clearly below the task's required capability, such as complex algorithm design, proof-level math, or broad multi-file refactoring. Choose the best-fit model directly from the same-agent catalog; model selection is not a mandatory one-step ladder. End the turn after changing it. Do not use vague task complexity as a trigger.",
7062
7106
  "`set_agent` autonomous calls are forbidden. Only switch agent when the user explicitly asks to switch runtime, e.g. \u201Ccodex\uB85C \uAC00\u201D, \u201Cclaude\uB85C \uBC14\uAFD4\u201D.",
7063
7107
  "Never use `fable` unless the user explicitly requests it; it is expensive.",
7064
7108
  "",
7065
- "Accepted values:",
7066
- "- claude models: `sonnet` (default), `opus`, `fable`; efforts: `low`, `medium`, `high`, `xhigh`, `max`.",
7067
- "- codex models: `gpt-5.6-luna` (default), `gpt-5.6-terra`, `gpt-5.6-sol`; efforts: `low`, `medium`, `high`, `xhigh`, `max`.",
7068
- "- maestro models: `deepseek-pro` (default), `deepseek-flash`, `deepseek`; efforts: `low`, `medium`, `high`, `xhigh`, `max`.",
7109
+ "Model catalog (capability/cost routing guidance):",
7110
+ MODEL_COST_ROUTING_SUMMARY,
7111
+ ...modelCatalog,
7112
+ "",
7113
+ "Accepted effort values:",
7114
+ "- claude: `low`, `medium`, `high`, `xhigh`, `max`.",
7115
+ "- codex: `low`, `medium`, `high`, `xhigh`, `max`.",
7116
+ "- maestro: `low`, `medium`, `high`, `xhigh`, `max`.",
7069
7117
  "Agent guidance when the user explicitly asks to switch: `codex` for deepest reasoning and complex code/math; `claude` for tool-heavy MCP/file automation; `maestro` for inexpensive fast drafts and lighter experiments."
7070
7118
  ];
7071
7119
  if (agentKind !== "claude") {
@@ -7088,7 +7136,7 @@ function buildTopicSystemPrompt(opts) {
7088
7136
  TOPIC_TITLE: opts.topicTitle,
7089
7137
  WORKSPACE_CWD: opts.workspaceCwd,
7090
7138
  UPLOADS_DIR: uploadsDir
7091
- }) + buildRuntimeToolSection(opts.agentKind, opts.canSpawnSubagents, opts.visualTools, opts.fileDeliveryTools);
7139
+ }) + buildRuntimeToolSection(opts.agentKind, opts.canSpawnSubagents, opts.visualTools, opts.fileDeliveryTools, opts.currentModel, opts.currentEffort);
7092
7140
  if (opts.description?.trim()) {
7093
7141
  prompt += `
7094
7142
 
@@ -7104,7 +7152,7 @@ function buildChannelSystemPrompt(opts) {
7104
7152
  TOPIC_TITLE: opts.topicTitle,
7105
7153
  WORKSPACE_CWD: opts.workspaceCwd,
7106
7154
  UPLOADS_DIR: uploadsDir
7107
- }) + buildRuntimeToolSection(opts.agentKind, false, opts.visualTools, opts.fileDeliveryTools);
7155
+ }) + buildRuntimeToolSection(opts.agentKind, false, opts.visualTools, opts.fileDeliveryTools, opts.currentModel, opts.currentEffort);
7108
7156
  }
7109
7157
  function buildManagerSystemPrompt(opts) {
7110
7158
  return `${buildTopicSystemPrompt(opts)}
@@ -7154,6 +7202,7 @@ User-uploaded files for this Channel are copied under "{{UPLOADS_DIR}}" as attac
7154
7202
  This is the shared "General" hub of the user's workspace.
7155
7203
  Act as the workspace manager: orient the user across topics, summarize what is going on, and route focused work to the right room.`, _topicSystemPromptTemplate = null, _channelSystemPromptTemplate = null, _managerSystemPromptTemplate = null, _visualDesignGuide = null;
7156
7204
  var init_builders = __esm(() => {
7205
+ init_model_catalog();
7157
7206
  init_config();
7158
7207
  init_logger();
7159
7208
  PROMPTS_DIR = resolve6(PROJECT_ROOT, "src/prompts");
@@ -7266,10 +7315,6 @@ function getArchiverDef() {
7266
7315
  }
7267
7316
  function runArchiverTurn(params) {
7268
7317
  const { userId, topicId, topicTitle, archivePath, messageCount, mode = "deleted-topic" } = params;
7269
- if (mode !== "active-topic" && messageCount < MIN_ARCHIVE_MESSAGES) {
7270
- logger.info({ userId, topicTitle, messageCount, min: MIN_ARCHIVE_MESSAGES }, "archiver: skipped \u2014 too few messages to distil");
7271
- return false;
7272
- }
7273
7318
  let archiverDef;
7274
7319
  try {
7275
7320
  archiverDef = getArchiverDef();
@@ -7477,7 +7522,7 @@ ${rolled.join(`
7477
7522
  logger.warn({ err, topicTitle }, "archiver: failed to post #General notification");
7478
7523
  }
7479
7524
  }
7480
- var MAX_BRIEF_ENTRIES = 8, MIN_ARCHIVE_MESSAGES = 4, MAX_SESSION_STEPS = 20, activeArchiverSessions, _archiverDef = null;
7525
+ var MAX_BRIEF_ENTRIES = 8, MAX_SESSION_STEPS = 20, activeArchiverSessions, _archiverDef = null;
7481
7526
  var init_archiver = __esm(async () => {
7482
7527
  await init_agents();
7483
7528
  await init_bus();
@@ -7492,6 +7537,25 @@ var init_archiver = __esm(async () => {
7492
7537
  activeArchiverSessions = new Map;
7493
7538
  });
7494
7539
 
7540
+ // ../../packages/core/src/agents/memory-archive-policy.ts
7541
+ function countMemoryArchiveExchanges(rows) {
7542
+ let waitingForAssistant = false;
7543
+ let completed = 0;
7544
+ for (const row of rows) {
7545
+ const assistant = row.author_id === "ai" || Boolean(row.agent_type);
7546
+ const conversational = row.kind == null || row.kind === "message";
7547
+ if (!assistant && row.author_id !== "system" && conversational) {
7548
+ waitingForAssistant = true;
7549
+ continue;
7550
+ }
7551
+ if (assistant && conversational && waitingForAssistant) {
7552
+ completed++;
7553
+ waitingForAssistant = false;
7554
+ }
7555
+ }
7556
+ return completed;
7557
+ }
7558
+
7495
7559
  // ../../packages/core/src/storage/topic-transcript.ts
7496
7560
  function parseJsonField(value) {
7497
7561
  if (!value)
@@ -7579,8 +7643,9 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
7579
7643
  counter++;
7580
7644
  }
7581
7645
  }
7582
- logger.info({ topicId, topicTitle, archive: path, messageCount: rows.length, lastRowid }, "archiveTopicMessages: archived topic messages");
7583
- return { path, messageCount: rows.length, lastRowid };
7646
+ const exchangeCount = countMemoryArchiveExchanges(rows);
7647
+ logger.info({ topicId, topicTitle, archive: path, messageCount: rows.length, exchangeCount, lastRowid }, "archiveTopicMessages: archived topic messages");
7648
+ return { path, messageCount: rows.length, exchangeCount, lastRowid };
7584
7649
  }
7585
7650
  var init_topic_archive = __esm(async () => {
7586
7651
  init_logger();
@@ -7784,6 +7849,7 @@ function archiveActiveTopicForMemory(topicId, userId, options) {
7784
7849
  if (!options.allowMentionOnly && topic.aiMode === "mention")
7785
7850
  return "mention-only-channel";
7786
7851
  let skipped = "empty";
7852
+ let skipMemoryTurn = false;
7787
7853
  const claim = claimTopicArchiveJob(topicId, (afterRowid) => {
7788
7854
  const pending = getMessagesForTopicAfterRowid(topicId, afterRowid);
7789
7855
  const minMessages = options.minMessages;
@@ -7792,6 +7858,8 @@ function archiveActiveTopicForMemory(topicId, userId, options) {
7792
7858
  logger.debug({ topicId, topicTitle: topic.title, pending: pending.length, minMessages }, "topic-memory-archiver: skipped below threshold");
7793
7859
  return null;
7794
7860
  }
7861
+ const exchangeCount = countMemoryArchiveExchanges(pending);
7862
+ skipMemoryTurn = options.minExchanges !== undefined && exchangeCount < options.minExchanges;
7795
7863
  const archived = (options.archiveMessages ?? archiveTopicMessages)(topicId, topic.title, {
7796
7864
  afterRowid,
7797
7865
  reason: options.reason
@@ -7809,6 +7877,18 @@ function archiveActiveTopicForMemory(topicId, userId, options) {
7809
7877
  if (claim.kind === "busy")
7810
7878
  return "busy";
7811
7879
  const { job } = claim;
7880
+ if (skipMemoryTurn) {
7881
+ settleTopicArchiveJob(topicId, job.archivePath, true);
7882
+ logger.info({
7883
+ topicId,
7884
+ topicTitle: topic.title,
7885
+ messageCount: job.messageCount,
7886
+ minExchanges: options.minExchanges,
7887
+ archive: job.archivePath,
7888
+ reason: options.reason
7889
+ }, "topic-memory-archiver: raw snapshot preserved below exchange threshold");
7890
+ return "below-threshold";
7891
+ }
7812
7892
  const memoryTopic = getTopicMemoryOrigin(topicId) ?? topic;
7813
7893
  const launched = (options.launchArchiver ?? runArchiverTurn)({
7814
7894
  userId,
@@ -9711,6 +9791,7 @@ __export(exports_turn_runner, {
9711
9791
  isPathInside: () => isPathInside,
9712
9792
  isLikelyCurrentChannelTrigger: () => isLikelyCurrentChannelTrigger,
9713
9793
  ingestAttachment: () => ingestAttachment,
9794
+ formatSelectableModel: () => formatSelectableModel,
9714
9795
  formatChannelTranscriptLine: () => formatChannelTranscriptLine,
9715
9796
  escapeRegExp: () => escapeRegExp,
9716
9797
  escapeHtml: () => escapeHtml2,
@@ -9728,6 +9809,8 @@ __export(exports_turn_runner, {
9728
9809
  SESSION_EXPIRED_MSG: () => SESSION_EXPIRED_MSG,
9729
9810
  SELECTABLE_MODELS: () => SELECTABLE_MODELS,
9730
9811
  MODEL_OWNER: () => MODEL_OWNER,
9812
+ MODEL_COST_ROUTING_SUMMARY: () => MODEL_COST_ROUTING_SUMMARY,
9813
+ MODEL_COST_RESEARCHED_AT: () => MODEL_COST_RESEARCHED_AT,
9731
9814
  FALLBACK_ORDER: () => FALLBACK_ORDER,
9732
9815
  AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
9733
9816
  });
@@ -10935,6 +11018,8 @@ function startAiTurn(params) {
10935
11018
  topicTitle: topic.title,
10936
11019
  workspaceCwd,
10937
11020
  agentKind,
11021
+ currentModel: resolvedModel,
11022
+ currentEffort: resolvedEffort,
10938
11023
  description: topic.description,
10939
11024
  canSpawnSubagents: peerBridge?.canSpawnSubagents ?? (topicRecord?.kind === "agent" && !topicRecord.isSubagent),
10940
11025
  visualTools,
@@ -13845,4 +13930,4 @@ export {
13845
13930
  CRON_CONTEXT_RETAIN_TURNS
13846
13931
  };
13847
13932
 
13848
- //# debugId=6720362DC3F70E7F64756E2164756E21
13933
+ //# debugId=85C745F136B1D17364756E2164756E21