@askexenow/exe-os 0.9.35 → 0.9.37

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 (67) hide show
  1. package/dist/bin/backfill-conversations.js +5 -1
  2. package/dist/bin/backfill-responses.js +5 -1
  3. package/dist/bin/backfill-vectors.js +1 -1
  4. package/dist/bin/cleanup-stale-review-tasks.js +10 -2
  5. package/dist/bin/cli.js +48 -14
  6. package/dist/bin/exe-agent.js +1 -1
  7. package/dist/bin/exe-assign.js +10 -2
  8. package/dist/bin/exe-boot.js +1 -1
  9. package/dist/bin/exe-call.js +7 -5
  10. package/dist/bin/exe-dispatch.js +10 -2
  11. package/dist/bin/exe-doctor.js +1 -1
  12. package/dist/bin/exe-export-behaviors.js +87 -4
  13. package/dist/bin/exe-forget.js +31 -11
  14. package/dist/bin/exe-gateway.js +10 -2
  15. package/dist/bin/exe-heartbeat.js +10 -2
  16. package/dist/bin/exe-kill.js +10 -2
  17. package/dist/bin/exe-launch-agent.js +85 -7
  18. package/dist/bin/exe-new-employee.js +26 -2
  19. package/dist/bin/exe-pending-messages.js +10 -2
  20. package/dist/bin/exe-pending-notifications.js +10 -2
  21. package/dist/bin/exe-pending-reviews.js +10 -2
  22. package/dist/bin/exe-rename.js +1 -1
  23. package/dist/bin/exe-review.js +10 -2
  24. package/dist/bin/exe-search.js +38 -19
  25. package/dist/bin/exe-session-cleanup.js +14 -3
  26. package/dist/bin/exe-start-codex.js +69 -3
  27. package/dist/bin/exe-start-opencode.js +80 -3
  28. package/dist/bin/exe-status.js +10 -2
  29. package/dist/bin/exe-team.js +10 -2
  30. package/dist/bin/git-sweep.js +10 -2
  31. package/dist/bin/graph-backfill.js +2 -1
  32. package/dist/bin/graph-export.js +10 -2
  33. package/dist/bin/install.js +25 -1
  34. package/dist/bin/intercom-check.js +10 -2
  35. package/dist/bin/scan-tasks.js +10 -2
  36. package/dist/bin/setup.js +7 -5
  37. package/dist/bin/shard-migrate.js +2 -1
  38. package/dist/gateway/index.js +10 -2
  39. package/dist/hooks/bug-report-worker.js +10 -2
  40. package/dist/hooks/codex-stop-task-finalizer.js +10 -2
  41. package/dist/hooks/commit-complete.js +10 -2
  42. package/dist/hooks/error-recall.js +38 -19
  43. package/dist/hooks/ingest-worker.js +9 -2
  44. package/dist/hooks/ingest.js +10 -2
  45. package/dist/hooks/instructions-loaded.js +10 -2
  46. package/dist/hooks/notification.js +10 -2
  47. package/dist/hooks/post-compact.js +10 -2
  48. package/dist/hooks/post-tool-combined.js +47 -21
  49. package/dist/hooks/pre-compact.js +12 -3
  50. package/dist/hooks/pre-tool-use.js +20 -8
  51. package/dist/hooks/prompt-submit.js +133 -20
  52. package/dist/hooks/session-end.js +138 -5
  53. package/dist/hooks/session-start.js +216 -46
  54. package/dist/hooks/stop.js +14 -4
  55. package/dist/hooks/subagent-stop.js +10 -2
  56. package/dist/hooks/summary-worker.js +121 -19
  57. package/dist/index.js +32 -16
  58. package/dist/lib/employee-templates.js +7 -5
  59. package/dist/lib/exe-daemon.js +124 -34
  60. package/dist/lib/hybrid-search.js +38 -19
  61. package/dist/lib/schedules.js +1 -1
  62. package/dist/lib/store.js +10 -2
  63. package/dist/mcp/server.js +118 -34
  64. package/dist/runtime/index.js +32 -16
  65. package/dist/tui/App.js +10 -2
  66. package/package.json +1 -1
  67. package/src/commands/exe/save.md +52 -0
@@ -3201,6 +3201,9 @@ function classifyMemoryType(input) {
3201
3201
  if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
3202
3202
  if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
3203
3203
  if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
3204
+ if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
3205
+ if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
3206
+ if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
3204
3207
  if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
3205
3208
  if (tool === "store_memory" || tool === "manual") return "observation";
3206
3209
  return "raw";
@@ -3343,6 +3346,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
3343
3346
  }
3344
3347
  }
3345
3348
  function schedulePostWriteMemoryHygiene(memoryIds) {
3349
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3346
3350
  if (memoryIds.length === 0) return;
3347
3351
  const run = () => {
3348
3352
  void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
@@ -4341,7 +4345,7 @@ var init_platform_procedures = __esm({
4341
4345
  title: "Chain of command \u2014 who talks to whom",
4342
4346
  domain: "workflow",
4343
4347
  priority: "p0",
4344
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4348
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4345
4349
  },
4346
4350
  {
4347
4351
  title: "Single dispatch path \u2014 create_task only",
@@ -5013,7 +5017,11 @@ async function searchMemories(queryVector, agentId, options) {
5013
5017
  sql += ` AND timestamp >= ?`;
5014
5018
  args.push(options.since);
5015
5019
  }
5016
- if (options?.memoryType) {
5020
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
5021
+ const uniqueTypes = [...new Set(options.memoryTypes)];
5022
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
5023
+ args.push(...uniqueTypes);
5024
+ } else if (options?.memoryType) {
5017
5025
  sql += ` AND memory_type = ?`;
5018
5026
  args.push(options.memoryType);
5019
5027
  }
@@ -6397,6 +6405,17 @@ __export(hybrid_search_exports, {
6397
6405
  rrfMerge: () => rrfMerge,
6398
6406
  rrfMergeMulti: () => rrfMergeMulti
6399
6407
  });
6408
+ function appendMemoryTypeFilter(sql, args, column, options) {
6409
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
6410
+ const uniqueTypes = [...new Set(options.memoryTypes)];
6411
+ sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
6412
+ args.push(...uniqueTypes);
6413
+ } else if (options?.memoryType) {
6414
+ sql += ` AND ${column} = ?`;
6415
+ args.push(options.memoryType);
6416
+ }
6417
+ return sql;
6418
+ }
6400
6419
  async function hybridSearch(queryText, agentId, options) {
6401
6420
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6402
6421
  const config2 = await loadConfig2();
@@ -6492,7 +6511,7 @@ async function hybridSearch(queryText, agentId, options) {
6492
6511
  }
6493
6512
  if (lists.length === 0) return [];
6494
6513
  if (lists.length === 1 && !effectiveIsBroad) return lists[0].slice(0, limit);
6495
- const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, 150) : limit;
6514
+ const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : limit;
6496
6515
  let merged = lists.length === 1 ? lists[0].slice(0, rrfLimit) : rrfMergeMulti(lists, rrfLimit, RRF_K, weights);
6497
6516
  let graphContextMap = /* @__PURE__ */ new Map();
6498
6517
  let entityBoostRan = false;
@@ -6513,6 +6532,7 @@ async function hybridSearch(queryText, agentId, options) {
6513
6532
  returnTopK: 5
6514
6533
  };
6515
6534
  let rerankedAndBlended = null;
6535
+ const rerankReturnLimit = Math.max(limit, auto.returnTopK ?? 5);
6516
6536
  if (effectiveIsBroad && auto.enabled && rerankerAvailable) {
6517
6537
  const cardinality2 = await estimateCardinality(agentId, effectiveOptions);
6518
6538
  if (cardinality2 > auto.broadQueryMinCardinality) {
@@ -6524,16 +6544,16 @@ async function hybridSearch(queryText, agentId, options) {
6524
6544
  text: m.raw_text,
6525
6545
  context: graphContextMap.get(m.id)
6526
6546
  }));
6527
- const scored = await rerankWithContext2(effectiveQuery, candidates, auto.returnTopK);
6547
+ const scored = await rerankWithContext2(effectiveQuery, candidates, rerankReturnLimit);
6528
6548
  rerankedRecords = scored.map((s) => merged[s.index]);
6529
6549
  } else {
6530
6550
  const { rerank: rerank2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
6531
- rerankedRecords = await rerank2(effectiveQuery, merged, auto.returnTopK);
6551
+ rerankedRecords = await rerank2(effectiveQuery, merged, rerankReturnLimit);
6532
6552
  }
6533
6553
  if (rerankedRecords.length > 0) {
6534
6554
  rerankedAndBlended = rrfMergeMulti(
6535
6555
  [rerankedRecords],
6536
- auto.returnTopK,
6556
+ rerankReturnLimit,
6537
6557
  RRF_K
6538
6558
  );
6539
6559
  }
@@ -6541,10 +6561,7 @@ async function hybridSearch(queryText, agentId, options) {
6541
6561
  }
6542
6562
  }
6543
6563
  }
6544
- const finalResults = (rerankedAndBlended ?? merged).slice(
6545
- 0,
6546
- rerankedAndBlended ? auto.returnTopK : limit
6547
- );
6564
+ const finalResults = (rerankedAndBlended ?? merged).slice(0, limit);
6548
6565
  if (options?.includeSource && finalResults.length > 0) {
6549
6566
  await attachDocumentMetadata(finalResults);
6550
6567
  }
@@ -6625,6 +6642,7 @@ async function estimateCardinality(agentId, options) {
6625
6642
  sql += ` AND timestamp >= ?`;
6626
6643
  args.push(options.since);
6627
6644
  }
6645
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6628
6646
  try {
6629
6647
  const result = await client.execute({ sql, args });
6630
6648
  return Number(result.rows[0]?.cnt) || 0;
@@ -6746,10 +6764,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
6746
6764
  sql += ` AND m.timestamp >= ?`;
6747
6765
  args.push(options.since);
6748
6766
  }
6749
- if (options?.memoryType) {
6750
- sql += ` AND m.memory_type = ?`;
6751
- args.push(options.memoryType);
6752
- }
6767
+ sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
6753
6768
  sql += ` ORDER BY rank LIMIT ?`;
6754
6769
  args.push(limit);
6755
6770
  const result = await client.execute({ sql, args });
@@ -6806,9 +6821,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
6806
6821
  AND timestamp >= ? AND timestamp <= ?
6807
6822
  AND COALESCE(status, 'active') = 'active'
6808
6823
  AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
6824
+ ${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
6809
6825
  AND COALESCE(confidence, 0.7) >= 0.3
6810
6826
  ORDER BY timestamp DESC LIMIT ?`,
6811
- args: [agentId, windowStart, killedAt, boundarySlots]
6827
+ args: [
6828
+ agentId,
6829
+ windowStart,
6830
+ killedAt,
6831
+ ...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
6832
+ boundarySlots
6833
+ ]
6812
6834
  });
6813
6835
  for (const row of boundaryResult.rows) {
6814
6836
  sessionBoundaryMemories.push(rowToMemoryRecord(row));
@@ -6854,10 +6876,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
6854
6876
  sql += ` AND timestamp >= ?`;
6855
6877
  args.push(options.since);
6856
6878
  }
6857
- if (options?.memoryType) {
6858
- sql += ` AND memory_type = ?`;
6859
- args.push(options.memoryType);
6860
- }
6879
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6861
6880
  if (textFilter) {
6862
6881
  sql += ` AND raw_text LIKE '%' || ? || '%'`;
6863
6882
  args.push(textFilter);
@@ -7267,6 +7286,67 @@ var init_active_agent = __esm({
7267
7286
  }
7268
7287
  });
7269
7288
 
7289
+ // src/lib/memory-retrieval-modes.ts
7290
+ function applyRetrievalMode(base, mode) {
7291
+ if (!mode || mode === "all") return base;
7292
+ const next = { ...base };
7293
+ switch (mode) {
7294
+ case "decisions_only":
7295
+ next.memoryTypes = ["decision", "adr"];
7296
+ next.includeRaw = false;
7297
+ break;
7298
+ case "behaviors_only":
7299
+ next.memoryTypes = ["behavior"];
7300
+ next.includeRaw = false;
7301
+ break;
7302
+ case "procedures_only":
7303
+ next.memoryTypes = ["procedure"];
7304
+ next.includeRaw = false;
7305
+ break;
7306
+ case "operational":
7307
+ next.memoryTypes = ["raw", "observation"];
7308
+ next.includeRaw = true;
7309
+ break;
7310
+ case "no_raw":
7311
+ next.includeRaw = false;
7312
+ break;
7313
+ case "recent_high_value":
7314
+ next.memoryTypes = ["decision", "adr", "behavior", "procedure"];
7315
+ next.includeRaw = false;
7316
+ break;
7317
+ default:
7318
+ return next;
7319
+ }
7320
+ return next;
7321
+ }
7322
+ function formatRetrievalModes() {
7323
+ return RETRIEVAL_MODES.map((mode) => `${mode}: ${RETRIEVAL_MODE_DESCRIPTIONS[mode]}`).join("; ");
7324
+ }
7325
+ var RETRIEVAL_MODES, RETRIEVAL_MODE_DESCRIPTIONS;
7326
+ var init_memory_retrieval_modes = __esm({
7327
+ "src/lib/memory-retrieval-modes.ts"() {
7328
+ "use strict";
7329
+ RETRIEVAL_MODES = [
7330
+ "all",
7331
+ "decisions_only",
7332
+ "behaviors_only",
7333
+ "procedures_only",
7334
+ "operational",
7335
+ "no_raw",
7336
+ "recent_high_value"
7337
+ ];
7338
+ RETRIEVAL_MODE_DESCRIPTIONS = {
7339
+ all: "All visible memory types.",
7340
+ decisions_only: "Only decisions and ADRs.",
7341
+ behaviors_only: "Only durable behavior/correction memories.",
7342
+ procedures_only: "Only procedures/runbooks.",
7343
+ operational: "Raw operational/debug/tool output.",
7344
+ no_raw: "All non-raw memory types.",
7345
+ recent_high_value: "High-value durable memory types, intended for recency recovery."
7346
+ };
7347
+ }
7348
+ });
7349
+
7270
7350
  // src/mcp/tools/recall-my-memory.ts
7271
7351
  import { z } from "zod";
7272
7352
  function formatSourceLine(record) {
@@ -7304,7 +7384,8 @@ function registerRecallMyMemory(server) {
7304
7384
  ),
7305
7385
  include_source: z.boolean().optional().default(false).describe(
7306
7386
  "When true, attach parent document metadata (filename, mime, source_type) to each result. Default false."
7307
- )
7387
+ ),
7388
+ retrieval_mode: z.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. ${formatRetrievalModes()}`)
7308
7389
  }
7309
7390
  },
7310
7391
  async ({
@@ -7318,7 +7399,8 @@ function registerRecallMyMemory(server) {
7318
7399
  include_archived,
7319
7400
  workspace_id,
7320
7401
  user_id,
7321
- include_source
7402
+ include_source,
7403
+ retrieval_mode
7322
7404
  }) => {
7323
7405
  try {
7324
7406
  if (!recent && !query) {
@@ -7328,7 +7410,7 @@ function registerRecallMyMemory(server) {
7328
7410
  };
7329
7411
  }
7330
7412
  const { agentId } = getActiveAgent();
7331
- const searchOptions = {
7413
+ const searchOptions = applyRetrievalMode({
7332
7414
  projectName: project_name,
7333
7415
  hasError: has_error,
7334
7416
  toolName: tool_name,
@@ -7339,7 +7421,7 @@ function registerRecallMyMemory(server) {
7339
7421
  includeSource: include_source,
7340
7422
  includeDrafts: true,
7341
7423
  ...user_id !== void 0 ? { userId: user_id } : {}
7342
- };
7424
+ }, retrieval_mode);
7343
7425
  let results;
7344
7426
  if (recent) {
7345
7427
  results = await recentRecords(agentId, searchOptions, limit, query);
@@ -7397,6 +7479,7 @@ var init_recall_my_memory = __esm({
7397
7479
  init_hybrid_search();
7398
7480
  init_store();
7399
7481
  init_active_agent();
7482
+ init_memory_retrieval_modes();
7400
7483
  }
7401
7484
  });
7402
7485
 
@@ -7432,10 +7515,11 @@ function registerAskTeamMemory(server) {
7432
7515
  ),
7433
7516
  include_raw: z2.boolean().optional().default(false).describe(
7434
7517
  "Include raw technical memories when ACL allows it (default: non-raw memories only for cross-agent reads)"
7435
- )
7518
+ ),
7519
+ retrieval_mode: z2.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. Raw visibility is still ACL-gated. ${formatRetrievalModes()}`)
7436
7520
  }
7437
7521
  },
7438
- async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw }) => {
7522
+ async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
7439
7523
  try {
7440
7524
  const { agentId: queryingAgentId, agentRole: queryingAgentRole } = getActiveAgent();
7441
7525
  const employees = loadEmployeesSync();
@@ -7444,16 +7528,18 @@ function registerAskTeamMemory(server) {
7444
7528
  const targetRole = targetEmployee?.role ?? "";
7445
7529
  const hasRawAccess = canSeeRaw(queryingRole, targetRole);
7446
7530
  const effectiveIncludeRaw = _include_raw && hasRawAccess;
7447
- const results = await hybridSearch(query, team_member, {
7531
+ const requestedMode = retrieval_mode ?? "all";
7532
+ const safeMode = !effectiveIncludeRaw && ["all", "operational"].includes(requestedMode) ? "no_raw" : requestedMode;
7533
+ const searchOptions = applyRetrievalMode({
7448
7534
  projectName: project_name,
7449
7535
  limit,
7450
7536
  since,
7451
7537
  includeArchived: include_archived,
7452
7538
  includeDrafts: false,
7453
- includeRaw: effectiveIncludeRaw,
7454
- memoryType: void 0
7455
- // Show all memory types — privacy enforced by draft filter + ACL, not type filter
7456
- });
7539
+ includeRaw: effectiveIncludeRaw
7540
+ }, safeMode);
7541
+ if (!effectiveIncludeRaw) searchOptions.includeRaw = false;
7542
+ const results = await hybridSearch(query, team_member, searchOptions);
7457
7543
  if (results.length === 0) {
7458
7544
  return {
7459
7545
  content: [
@@ -7495,6 +7581,7 @@ var init_ask_team_memory = __esm({
7495
7581
  init_hybrid_search();
7496
7582
  init_active_agent();
7497
7583
  init_employees();
7584
+ init_memory_retrieval_modes();
7498
7585
  }
7499
7586
  });
7500
7587
 
@@ -15306,8 +15393,9 @@ var init_starter_packs = __esm({
15306
15393
 
15307
15394
  // src/lib/employee-templates.ts
15308
15395
  function renderClientCOOTemplate(vars) {
15396
+ const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
15309
15397
  for (const key of CLIENT_COO_PLACEHOLDERS) {
15310
- const value = vars[key];
15398
+ const value = resolved[key];
15311
15399
  if (typeof value !== "string" || value.length === 0) {
15312
15400
  throw new Error(
15313
15401
  `renderClientCOOTemplate: missing required variable "${key}"`
@@ -15316,7 +15404,7 @@ function renderClientCOOTemplate(vars) {
15316
15404
  }
15317
15405
  let out = CLIENT_COO_TEMPLATE;
15318
15406
  for (const key of CLIENT_COO_PLACEHOLDERS) {
15319
- out = out.split(`{{${key}}}`).join(vars[key]);
15407
+ out = out.split(`{{${key}}}`).join(resolved[key]);
15320
15408
  }
15321
15409
  if (vars.industry_context) {
15322
15410
  out += "\n" + vars.industry_context;
@@ -15337,7 +15425,7 @@ created_by: system
15337
15425
  ---
15338
15426
  ## Identity
15339
15427
 
15340
- You are {{agent_name}}, the Chief Operating Officer at {{company_name}}.
15428
+ You are {{agent_name}}, the {{title}} at {{company_name}}.
15341
15429
 
15342
15430
  You are {{founder_name}}'s most reliable teammate in business \u2014 the knowledgeable older sibling who has been through it all. You have seen projects succeed and fail. You know what matters and what is noise. You do not get anxious about problems; you see them coming, stay calm, and handle them.
15343
15431
 
@@ -15424,7 +15512,8 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
15424
15512
  CLIENT_COO_PLACEHOLDERS = [
15425
15513
  "agent_name",
15426
15514
  "company_name",
15427
- "founder_name"
15515
+ "founder_name",
15516
+ "title"
15428
15517
  ];
15429
15518
  }
15430
15519
  });
@@ -15598,6 +15687,7 @@ ${vars}`);
15598
15687
  agent_name,
15599
15688
  company_name,
15600
15689
  founder_name,
15690
+ title: "Chief Operating Officer",
15601
15691
  industry_context: pack.identityContext ?? void 0
15602
15692
  });
15603
15693
  cooSummaryLines = [
@@ -3042,6 +3042,9 @@ function classifyMemoryType(input) {
3042
3042
  if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
3043
3043
  if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
3044
3044
  if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
3045
+ if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
3046
+ if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
3047
+ if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
3045
3048
  if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
3046
3049
  if (tool === "store_memory" || tool === "manual") return "observation";
3047
3050
  return "raw";
@@ -3184,6 +3187,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
3184
3187
  }
3185
3188
  }
3186
3189
  function schedulePostWriteMemoryHygiene(memoryIds) {
3190
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3187
3191
  if (memoryIds.length === 0) return;
3188
3192
  const run = () => {
3189
3193
  void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
@@ -3578,7 +3582,7 @@ var init_platform_procedures = __esm({
3578
3582
  title: "Chain of command \u2014 who talks to whom",
3579
3583
  domain: "workflow",
3580
3584
  priority: "p0",
3581
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
3585
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
3582
3586
  },
3583
3587
  {
3584
3588
  title: "Single dispatch path \u2014 create_task only",
@@ -4250,7 +4254,11 @@ async function searchMemories(queryVector, agentId, options) {
4250
4254
  sql += ` AND timestamp >= ?`;
4251
4255
  args.push(options.since);
4252
4256
  }
4253
- if (options?.memoryType) {
4257
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
4258
+ const uniqueTypes = [...new Set(options.memoryTypes)];
4259
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
4260
+ args.push(...uniqueTypes);
4261
+ } else if (options?.memoryType) {
4254
4262
  sql += ` AND memory_type = ?`;
4255
4263
  args.push(options.memoryType);
4256
4264
  }
@@ -5542,6 +5550,17 @@ var init_entity_boost = __esm({
5542
5550
  init_store();
5543
5551
  init_database();
5544
5552
  var RRF_K = 60;
5553
+ function appendMemoryTypeFilter(sql, args, column, options) {
5554
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
5555
+ const uniqueTypes = [...new Set(options.memoryTypes)];
5556
+ sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
5557
+ args.push(...uniqueTypes);
5558
+ } else if (options?.memoryType) {
5559
+ sql += ` AND ${column} = ?`;
5560
+ args.push(options.memoryType);
5561
+ }
5562
+ return sql;
5563
+ }
5545
5564
  async function hybridSearch(queryText, agentId, options) {
5546
5565
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5547
5566
  const config = await loadConfig2();
@@ -5637,7 +5656,7 @@ async function hybridSearch(queryText, agentId, options) {
5637
5656
  }
5638
5657
  if (lists.length === 0) return [];
5639
5658
  if (lists.length === 1 && !effectiveIsBroad) return lists[0].slice(0, limit);
5640
- const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, 150) : limit;
5659
+ const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : limit;
5641
5660
  let merged = lists.length === 1 ? lists[0].slice(0, rrfLimit) : rrfMergeMulti(lists, rrfLimit, RRF_K, weights);
5642
5661
  let graphContextMap = /* @__PURE__ */ new Map();
5643
5662
  let entityBoostRan = false;
@@ -5658,6 +5677,7 @@ async function hybridSearch(queryText, agentId, options) {
5658
5677
  returnTopK: 5
5659
5678
  };
5660
5679
  let rerankedAndBlended = null;
5680
+ const rerankReturnLimit = Math.max(limit, auto.returnTopK ?? 5);
5661
5681
  if (effectiveIsBroad && auto.enabled && rerankerAvailable) {
5662
5682
  const cardinality2 = await estimateCardinality(agentId, effectiveOptions);
5663
5683
  if (cardinality2 > auto.broadQueryMinCardinality) {
@@ -5669,16 +5689,16 @@ async function hybridSearch(queryText, agentId, options) {
5669
5689
  text: m.raw_text,
5670
5690
  context: graphContextMap.get(m.id)
5671
5691
  }));
5672
- const scored = await rerankWithContext2(effectiveQuery, candidates, auto.returnTopK);
5692
+ const scored = await rerankWithContext2(effectiveQuery, candidates, rerankReturnLimit);
5673
5693
  rerankedRecords = scored.map((s) => merged[s.index]);
5674
5694
  } else {
5675
5695
  const { rerank: rerank2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
5676
- rerankedRecords = await rerank2(effectiveQuery, merged, auto.returnTopK);
5696
+ rerankedRecords = await rerank2(effectiveQuery, merged, rerankReturnLimit);
5677
5697
  }
5678
5698
  if (rerankedRecords.length > 0) {
5679
5699
  rerankedAndBlended = rrfMergeMulti(
5680
5700
  [rerankedRecords],
5681
- auto.returnTopK,
5701
+ rerankReturnLimit,
5682
5702
  RRF_K
5683
5703
  );
5684
5704
  }
@@ -5686,10 +5706,7 @@ async function hybridSearch(queryText, agentId, options) {
5686
5706
  }
5687
5707
  }
5688
5708
  }
5689
- const finalResults = (rerankedAndBlended ?? merged).slice(
5690
- 0,
5691
- rerankedAndBlended ? auto.returnTopK : limit
5692
- );
5709
+ const finalResults = (rerankedAndBlended ?? merged).slice(0, limit);
5693
5710
  if (options?.includeSource && finalResults.length > 0) {
5694
5711
  await attachDocumentMetadata(finalResults);
5695
5712
  }
@@ -5770,6 +5787,7 @@ async function estimateCardinality(agentId, options) {
5770
5787
  sql += ` AND timestamp >= ?`;
5771
5788
  args.push(options.since);
5772
5789
  }
5790
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
5773
5791
  try {
5774
5792
  const result = await client.execute({ sql, args });
5775
5793
  return Number(result.rows[0]?.cnt) || 0;
@@ -5891,10 +5909,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
5891
5909
  sql += ` AND m.timestamp >= ?`;
5892
5910
  args.push(options.since);
5893
5911
  }
5894
- if (options?.memoryType) {
5895
- sql += ` AND m.memory_type = ?`;
5896
- args.push(options.memoryType);
5897
- }
5912
+ sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
5898
5913
  sql += ` ORDER BY rank LIMIT ?`;
5899
5914
  args.push(limit);
5900
5915
  const result = await client.execute({ sql, args });
@@ -5951,9 +5966,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
5951
5966
  AND timestamp >= ? AND timestamp <= ?
5952
5967
  AND COALESCE(status, 'active') = 'active'
5953
5968
  AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
5969
+ ${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
5954
5970
  AND COALESCE(confidence, 0.7) >= 0.3
5955
5971
  ORDER BY timestamp DESC LIMIT ?`,
5956
- args: [agentId, windowStart, killedAt, boundarySlots]
5972
+ args: [
5973
+ agentId,
5974
+ windowStart,
5975
+ killedAt,
5976
+ ...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
5977
+ boundarySlots
5978
+ ]
5957
5979
  });
5958
5980
  for (const row of boundaryResult.rows) {
5959
5981
  sessionBoundaryMemories.push(rowToMemoryRecord(row));
@@ -5999,10 +6021,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
5999
6021
  sql += ` AND timestamp >= ?`;
6000
6022
  args.push(options.since);
6001
6023
  }
6002
- if (options?.memoryType) {
6003
- sql += ` AND memory_type = ?`;
6004
- args.push(options.memoryType);
6005
- }
6024
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6006
6025
  if (textFilter) {
6007
6026
  sql += ` AND raw_text LIKE '%' || ? || '%'`;
6008
6027
  args.push(textFilter);
@@ -2944,7 +2944,7 @@ var init_platform_procedures = __esm({
2944
2944
  title: "Chain of command \u2014 who talks to whom",
2945
2945
  domain: "workflow",
2946
2946
  priority: "p0",
2947
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
2947
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
2948
2948
  },
2949
2949
  {
2950
2950
  title: "Single dispatch path \u2014 create_task only",
package/dist/lib/store.js CHANGED
@@ -2944,7 +2944,7 @@ var init_platform_procedures = __esm({
2944
2944
  title: "Chain of command \u2014 who talks to whom",
2945
2945
  domain: "workflow",
2946
2946
  priority: "p0",
2947
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
2947
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
2948
2948
  },
2949
2949
  {
2950
2950
  title: "Single dispatch path \u2014 create_task only",
@@ -3426,6 +3426,9 @@ function classifyMemoryType(input) {
3426
3426
  if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
3427
3427
  if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
3428
3428
  if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
3429
+ if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
3430
+ if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
3431
+ if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
3429
3432
  if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
3430
3433
  if (tool === "store_memory" || tool === "manual") return "observation";
3431
3434
  return "raw";
@@ -3568,6 +3571,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
3568
3571
  }
3569
3572
  }
3570
3573
  function schedulePostWriteMemoryHygiene(memoryIds) {
3574
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3571
3575
  if (memoryIds.length === 0) return;
3572
3576
  const run = () => {
3573
3577
  void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
@@ -4026,7 +4030,11 @@ async function searchMemories(queryVector, agentId, options) {
4026
4030
  sql += ` AND timestamp >= ?`;
4027
4031
  args.push(options.since);
4028
4032
  }
4029
- if (options?.memoryType) {
4033
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
4034
+ const uniqueTypes = [...new Set(options.memoryTypes)];
4035
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
4036
+ args.push(...uniqueTypes);
4037
+ } else if (options?.memoryType) {
4030
4038
  sql += ` AND memory_type = ?`;
4031
4039
  args.push(options.memoryType);
4032
4040
  }