@cortexkit/pi-magic-context 0.17.2 → 0.18.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.
package/dist/index.js CHANGED
@@ -158111,6 +158111,25 @@ var MIGRATIONS = [
158111
158111
  WHERE type = 'tool' AND tool_owner_message_id IS NULL;
158112
158112
  `);
158113
158113
  }
158114
+ },
158115
+ {
158116
+ version: 11,
158117
+ description: "Add todo state synthesis columns to session_meta",
158118
+ up: (db) => {
158119
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
158120
+ if (!cols.some((c) => c.name === "last_todo_state")) {
158121
+ db.exec("ALTER TABLE session_meta ADD COLUMN last_todo_state TEXT DEFAULT ''");
158122
+ }
158123
+ if (!cols.some((c) => c.name === "todo_synthetic_call_id")) {
158124
+ db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_call_id TEXT DEFAULT ''");
158125
+ }
158126
+ if (!cols.some((c) => c.name === "todo_synthetic_anchor_message_id")) {
158127
+ db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_anchor_message_id TEXT DEFAULT ''");
158128
+ }
158129
+ if (!cols.some((c) => c.name === "todo_synthetic_state_json")) {
158130
+ db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_state_json TEXT DEFAULT ''");
158131
+ }
158132
+ }
158114
158133
  }
158115
158134
  ];
158116
158135
  function ensureMigrationsTable(db) {
@@ -158685,6 +158704,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
158685
158704
  note_nudge_trigger_message_id TEXT DEFAULT '',
158686
158705
  note_nudge_sticky_text TEXT DEFAULT '',
158687
158706
  note_nudge_sticky_message_id TEXT DEFAULT '',
158707
+ last_todo_state TEXT DEFAULT '',
158708
+ todo_synthetic_call_id TEXT DEFAULT '',
158709
+ todo_synthetic_anchor_message_id TEXT DEFAULT '',
158710
+ todo_synthetic_state_json TEXT DEFAULT '',
158688
158711
  is_subagent INTEGER DEFAULT 0,
158689
158712
  last_context_percentage REAL DEFAULT 0,
158690
158713
  last_input_tokens INTEGER DEFAULT 0,
@@ -158749,6 +158772,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
158749
158772
  ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
158750
158773
  ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
158751
158774
  ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
158775
+ ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
158776
+ ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
158777
+ ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
158778
+ ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
158752
158779
  ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
158753
158780
  ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
158754
158781
  ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
@@ -158813,6 +158840,10 @@ function healNullTextColumns(db) {
158813
158840
  ["note_nudge_trigger_message_id", ""],
158814
158841
  ["note_nudge_sticky_text", ""],
158815
158842
  ["note_nudge_sticky_message_id", ""],
158843
+ ["last_todo_state", ""],
158844
+ ["todo_synthetic_call_id", ""],
158845
+ ["todo_synthetic_anchor_message_id", ""],
158846
+ ["todo_synthetic_state_json", ""],
158816
158847
  ["system_prompt_hash", ""],
158817
158848
  ["stripped_placeholder_ids", ""],
158818
158849
  ["memory_block_cache", ""],
@@ -158906,7 +158937,8 @@ var META_COLUMNS = {
158906
158937
  systemPromptTokens: "system_prompt_tokens",
158907
158938
  conversationTokens: "conversation_tokens",
158908
158939
  toolCallTokens: "tool_call_tokens",
158909
- clearedReasoningThroughTag: "cleared_reasoning_through_tag"
158940
+ clearedReasoningThroughTag: "cleared_reasoning_through_tag",
158941
+ lastTodoState: "last_todo_state"
158910
158942
  };
158911
158943
  var BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress"]);
158912
158944
  function isStringOrNull(value) {
@@ -158919,7 +158951,7 @@ function isSessionMetaRow(row) {
158919
158951
  if (row === null || typeof row !== "object")
158920
158952
  return false;
158921
158953
  const r = row;
158922
- return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag);
158954
+ return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state);
158923
158955
  }
158924
158956
  function getDefaultSessionMeta(sessionId) {
158925
158957
  return {
@@ -158939,7 +158971,8 @@ function getDefaultSessionMeta(sessionId) {
158939
158971
  systemPromptTokens: 0,
158940
158972
  conversationTokens: 0,
158941
158973
  toolCallTokens: 0,
158942
- clearedReasoningThroughTag: 0
158974
+ clearedReasoningThroughTag: 0,
158975
+ lastTodoState: ""
158943
158976
  };
158944
158977
  }
158945
158978
  function ensureSessionMetaRow(db, sessionId) {
@@ -158951,6 +158984,7 @@ function toSessionMeta(row) {
158951
158984
  const transformErrorRaw = typeof row.last_transform_error === "string" ? row.last_transform_error : "";
158952
158985
  const cacheTtlRaw = typeof row.cache_ttl === "string" && row.cache_ttl.length > 0 ? row.cache_ttl : "5m";
158953
158986
  const systemPromptHashRaw = row.system_prompt_hash == null ? "" : row.system_prompt_hash;
158987
+ const lastTodoStateRaw = typeof row.last_todo_state === "string" ? row.last_todo_state : "";
158954
158988
  const numOrZero = (value) => typeof value === "number" ? value : 0;
158955
158989
  return {
158956
158990
  sessionId: row.session_id,
@@ -158969,7 +159003,8 @@ function toSessionMeta(row) {
158969
159003
  systemPromptTokens: numOrZero(row.system_prompt_tokens),
158970
159004
  conversationTokens: numOrZero(row.conversation_tokens),
158971
159005
  toolCallTokens: numOrZero(row.tool_call_tokens),
158972
- clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag)
159006
+ clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag),
159007
+ lastTodoState: lastTodoStateRaw
158973
159008
  };
158974
159009
  }
158975
159010
 
@@ -159185,7 +159220,7 @@ function resolveIsSubagentFromOpenCodeDb(sessionId) {
159185
159220
 
159186
159221
  // ../plugin/src/features/magic-context/storage-meta-session.ts
159187
159222
  function getOrCreateSessionMeta(db, sessionId) {
159188
- const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag FROM session_meta WHERE session_id = ?").get(sessionId);
159223
+ const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag, last_todo_state FROM session_meta WHERE session_id = ?").get(sessionId);
159189
159224
  if (isSessionMetaRow(result)) {
159190
159225
  return toSessionMeta(result);
159191
159226
  }
@@ -159751,14 +159786,118 @@ function expandFallbackChain(chain) {
159751
159786
  }
159752
159787
  return models;
159753
159788
  }
159789
+ function getAgentFallbackModels(agent) {
159790
+ const requirement = AGENT_MODEL_REQUIREMENTS[agent];
159791
+ if (!requirement)
159792
+ return;
159793
+ return expandFallbackChain(requirement.fallbackChain);
159794
+ }
159754
159795
 
159755
159796
  // ../plugin/src/shared/models-dev-cache.ts
159756
159797
  init_data_path();
159757
- init_logger();
159758
159798
  import { createHash as createHash3 } from "node:crypto";
159759
159799
  import { existsSync as existsSync4, readFileSync } from "node:fs";
159760
159800
  import { homedir as homedir2, platform } from "node:os";
159761
159801
  import { join as join8 } from "node:path";
159802
+
159803
+ // ../plugin/src/shared/jsonc-parser.ts
159804
+ function stripJsonComments(content) {
159805
+ let result = "";
159806
+ let inString = false;
159807
+ let escaped = false;
159808
+ let inLineComment = false;
159809
+ let inBlockComment = false;
159810
+ for (let index = 0;index < content.length; index += 1) {
159811
+ const char = content[index];
159812
+ const next = content[index + 1];
159813
+ if (inLineComment) {
159814
+ if (char === `
159815
+ `) {
159816
+ inLineComment = false;
159817
+ result += char;
159818
+ }
159819
+ continue;
159820
+ }
159821
+ if (inBlockComment) {
159822
+ if (char === "*" && next === "/") {
159823
+ inBlockComment = false;
159824
+ index += 1;
159825
+ }
159826
+ continue;
159827
+ }
159828
+ if (inString) {
159829
+ result += char;
159830
+ if (escaped) {
159831
+ escaped = false;
159832
+ } else if (char === "\\") {
159833
+ escaped = true;
159834
+ } else if (char === '"') {
159835
+ inString = false;
159836
+ }
159837
+ continue;
159838
+ }
159839
+ if (char === '"') {
159840
+ inString = true;
159841
+ result += char;
159842
+ continue;
159843
+ }
159844
+ if (char === "/" && next === "/") {
159845
+ inLineComment = true;
159846
+ index += 1;
159847
+ continue;
159848
+ }
159849
+ if (char === "/" && next === "*") {
159850
+ inBlockComment = true;
159851
+ index += 1;
159852
+ continue;
159853
+ }
159854
+ result += char;
159855
+ }
159856
+ return result;
159857
+ }
159858
+ function stripTrailingCommas(content) {
159859
+ let result = "";
159860
+ let inString = false;
159861
+ let escaped = false;
159862
+ for (let index = 0;index < content.length; index += 1) {
159863
+ const char = content[index];
159864
+ if (inString) {
159865
+ result += char;
159866
+ if (escaped) {
159867
+ escaped = false;
159868
+ } else if (char === "\\") {
159869
+ escaped = true;
159870
+ } else if (char === '"') {
159871
+ inString = false;
159872
+ }
159873
+ continue;
159874
+ }
159875
+ if (char === '"') {
159876
+ inString = true;
159877
+ result += char;
159878
+ continue;
159879
+ }
159880
+ if (char === ",") {
159881
+ let lookahead = index + 1;
159882
+ while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
159883
+ lookahead += 1;
159884
+ }
159885
+ const next = content[lookahead];
159886
+ if (next === "}" || next === "]") {
159887
+ continue;
159888
+ }
159889
+ }
159890
+ result += char;
159891
+ }
159892
+ return result;
159893
+ }
159894
+ function parseJsonc(content) {
159895
+ const normalized = stripTrailingCommas(stripJsonComments(content));
159896
+ return JSON.parse(normalized);
159897
+ }
159898
+
159899
+ // ../plugin/src/shared/models-dev-cache.ts
159900
+ init_logger();
159762
159901
  var RELOAD_INTERVAL_MS = 5 * 60 * 1000;
159763
159902
  var apiCache = null;
159764
159903
  var recentlySeenApiSizes = new Set;
@@ -159833,9 +159972,7 @@ function loadModelsDevMetadataFromFile() {
159833
159972
  try {
159834
159973
  const configPath = getOpencodeConfigPath();
159835
159974
  if (configPath && existsSync4(configPath)) {
159836
- let raw = readFileSync(configPath, "utf-8");
159837
- raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
159838
- const config2 = JSON.parse(raw);
159975
+ const config2 = parseJsonc(readFileSync(configPath, "utf-8"));
159839
159976
  if (config2.provider && typeof config2.provider === "object") {
159840
159977
  for (const [providerId, provider2] of Object.entries(config2.provider)) {
159841
159978
  if (!provider2?.models || typeof provider2.models !== "object")
@@ -160774,6 +160911,53 @@ init_logger();
160774
160911
 
160775
160912
  // ../plugin/src/shared/model-suggestion-retry.ts
160776
160913
  init_logger();
160914
+
160915
+ // ../plugin/src/shared/resolve-fallbacks.ts
160916
+ function resolveFallbackChain(agentName, userFallbacks) {
160917
+ const userList = normalizeUserFallbacks(userFallbacks);
160918
+ if (userList.length > 0) {
160919
+ return dedupe(userList.filter(isValidModelSpec));
160920
+ }
160921
+ const builtin = getAgentFallbackModels(agentName);
160922
+ if (!builtin || builtin.length === 0)
160923
+ return [];
160924
+ return dedupe(builtin.filter(isValidModelSpec));
160925
+ }
160926
+ function normalizeUserFallbacks(userFallbacks) {
160927
+ if (!userFallbacks)
160928
+ return [];
160929
+ if (typeof userFallbacks === "string") {
160930
+ const trimmed = userFallbacks.trim();
160931
+ return trimmed ? [trimmed] : [];
160932
+ }
160933
+ return userFallbacks.map((s) => s.trim()).filter((s) => s.length > 0);
160934
+ }
160935
+ function isValidModelSpec(spec) {
160936
+ const slash = spec.indexOf("/");
160937
+ return slash > 0 && slash < spec.length - 1;
160938
+ }
160939
+ function dedupe(list) {
160940
+ const seen = new Set;
160941
+ const out = [];
160942
+ for (const item of list) {
160943
+ if (seen.has(item))
160944
+ continue;
160945
+ seen.add(item);
160946
+ out.push(item);
160947
+ }
160948
+ return out;
160949
+ }
160950
+ function parseProviderModel(spec) {
160951
+ const slash = spec.indexOf("/");
160952
+ if (slash < 1 || slash >= spec.length - 1)
160953
+ return null;
160954
+ return {
160955
+ providerID: spec.slice(0, slash).trim(),
160956
+ modelID: spec.slice(slash + 1).trim()
160957
+ };
160958
+ }
160959
+
160960
+ // ../plugin/src/shared/model-suggestion-retry.ts
160777
160961
  function extractMessage(error51) {
160778
160962
  if (typeof error51 === "string")
160779
160963
  return error51;
@@ -160828,6 +161012,9 @@ function parseModelSuggestion(error51) {
160828
161012
  };
160829
161013
  }
160830
161014
  async function promptWithTimeout(client, args, timeoutMs, signal) {
161015
+ if (signal?.aborted) {
161016
+ throw new Error("prompt aborted by external signal");
161017
+ }
160831
161018
  const controller = new AbortController;
160832
161019
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
160833
161020
  const onExternalAbort = () => controller.abort();
@@ -160850,16 +161037,39 @@ async function promptWithTimeout(client, args, timeoutMs, signal) {
160850
161037
  signal?.removeEventListener("abort", onExternalAbort);
160851
161038
  }
160852
161039
  }
160853
- async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
160854
- const timeoutMs = options.timeoutMs ?? 300000;
161040
+ function isNonRetryable(error51, externalSignal) {
161041
+ if (externalSignal?.aborted)
161042
+ return true;
161043
+ if (error51 instanceof Error) {
161044
+ if (error51.name === "AbortError")
161045
+ return true;
161046
+ if (error51.message === "prompt aborted by external signal")
161047
+ return true;
161048
+ if (/^prompt timed out after \d+ms$/.test(error51.message))
161049
+ return true;
161050
+ }
161051
+ if (detectOverflow(error51).isOverflow)
161052
+ return true;
161053
+ return false;
161054
+ }
161055
+ function shortErr(error51) {
161056
+ if (error51 instanceof Error) {
161057
+ return error51.name && error51.name !== "Error" ? `${error51.name}: ${error51.message}` : error51.message;
161058
+ }
161059
+ return extractMessage(error51);
161060
+ }
161061
+ async function attemptOnce(client, args, timeoutMs, signal, callContext, label) {
160855
161062
  try {
160856
- await promptWithTimeout(client, args, timeoutMs, options.signal);
161063
+ await promptWithTimeout(client, args, timeoutMs, signal);
161064
+ return;
160857
161065
  } catch (error51) {
161066
+ if (isNonRetryable(error51, signal))
161067
+ throw error51;
160858
161068
  const suggestion = parseModelSuggestion(error51);
160859
161069
  if (!suggestion || !args.body.model) {
160860
161070
  throw error51;
160861
161071
  }
160862
- log("[model-suggestion-retry] Model not found, retrying with suggestion", {
161072
+ log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
160863
161073
  original: `${suggestion.providerID}/${suggestion.modelID}`,
160864
161074
  suggested: suggestion.suggestion
160865
161075
  });
@@ -160872,9 +161082,55 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
160872
161082
  modelID: suggestion.suggestion
160873
161083
  }
160874
161084
  }
160875
- }, timeoutMs, options.signal);
161085
+ }, timeoutMs, signal);
160876
161086
  }
160877
161087
  }
161088
+ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
161089
+ const timeoutMs = options.timeoutMs ?? 300000;
161090
+ const callContext = options.callContext ?? "subagent";
161091
+ const fallbacks = options.fallbackModels ?? [];
161092
+ const explicitPrimaryLabel = args.body.model?.providerID && args.body.model.modelID ? `${args.body.model.providerID}/${args.body.model.modelID}` : "primary";
161093
+ let lastError = null;
161094
+ try {
161095
+ await attemptOnce(client, args, timeoutMs, options.signal, callContext, explicitPrimaryLabel);
161096
+ return;
161097
+ } catch (error51) {
161098
+ lastError = error51;
161099
+ if (isNonRetryable(error51, options.signal))
161100
+ throw error51;
161101
+ if (fallbacks.length === 0) {
161102
+ throw error51;
161103
+ }
161104
+ log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error51)}; trying ${fallbacks.length} fallback(s)`);
161105
+ }
161106
+ for (let i = 0;i < fallbacks.length; i += 1) {
161107
+ const parsed = parseProviderModel(fallbacks[i]);
161108
+ if (!parsed) {
161109
+ log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
161110
+ continue;
161111
+ }
161112
+ const label = `${parsed.providerID}/${parsed.modelID}`;
161113
+ const attemptArgs = {
161114
+ ...args,
161115
+ body: { ...args.body, model: parsed }
161116
+ };
161117
+ try {
161118
+ await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
161119
+ log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
161120
+ return;
161121
+ } catch (error51) {
161122
+ lastError = error51;
161123
+ if (isNonRetryable(error51, options.signal))
161124
+ throw error51;
161125
+ const remaining = fallbacks.length - i - 1;
161126
+ if (remaining > 0) {
161127
+ log(`[${callContext}] ${label} failed: ${shortErr(error51)}; ${remaining} fallback(s) left`);
161128
+ }
161129
+ }
161130
+ }
161131
+ log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
161132
+ throw lastError ?? new Error("All fallback models failed");
161133
+ }
160878
161134
  // ../plugin/src/shared/normalize-sdk-response.ts
160879
161135
  function normalizeSDKResponse(response, fallback, options) {
160880
161136
  if (response === null || response === undefined) {
@@ -162052,7 +162308,12 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
162052
162308
  system: DREAMER_SYSTEM_PROMPT,
162053
162309
  parts: [{ type: "text", text: prompt, synthetic: true }]
162054
162310
  }
162055
- }, { timeoutMs: Math.min(remainingMs, 5 * 60 * 1000), signal: abortController.signal });
162311
+ }, {
162312
+ timeoutMs: Math.min(remainingMs, 5 * 60 * 1000),
162313
+ signal: abortController.signal,
162314
+ fallbackModels: args.fallbackModels,
162315
+ callContext: "dreamer:user-memories"
162316
+ });
162056
162317
  const messagesResponse = await args.client.session.messages({
162057
162318
  path: { id: agentSessionId },
162058
162319
  query: { directory: args.sessionDirectory }
@@ -162111,7 +162372,8 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
162111
162372
  }
162112
162373
  return result;
162113
162374
  } catch (error51) {
162114
- log(`[dreamer] user-memories: review failed: ${getErrorMessage(error51)}`);
162375
+ const errorDescription = describeError(error51);
162376
+ log(`[dreamer] user-memories: review failed: ${errorDescription.brief}`, errorDescription.stackHead ? { stackHead: errorDescription.stackHead } : undefined);
162115
162377
  return result;
162116
162378
  } finally {
162117
162379
  clearInterval(leaseInterval);
@@ -162143,6 +162405,7 @@ function insertDreamRun(db, run) {
162143
162405
 
162144
162406
  // ../plugin/src/features/magic-context/dreamer/runner.ts
162145
162407
  var dreamProjectDirectories = new Map;
162408
+ var CIRCUIT_BREAKER_THRESHOLD = 3;
162146
162409
  function registerDreamProjectDirectory(projectIdentity, directory) {
162147
162410
  dreamProjectDirectories.set(projectIdentity, directory);
162148
162411
  }
@@ -162159,6 +162422,25 @@ function countNewIds(beforeIds, afterIds) {
162159
162422
  }
162160
162423
  return count;
162161
162424
  }
162425
+ function getCircuitBreakerSignature(error51, brief) {
162426
+ if (error51 instanceof Error && error51.name && error51.name !== "Error") {
162427
+ return error51.name;
162428
+ }
162429
+ const namedError = error51;
162430
+ if (namedError && typeof namedError === "object" && typeof namedError.name === "string" && namedError.name.length > 0 && namedError.name !== "Error") {
162431
+ return namedError.name;
162432
+ }
162433
+ return brief.split(":")[0]?.trim().split(/\s+/)[0] || brief || "unknown";
162434
+ }
162435
+ function shouldSkipCircuitBreaker(error51, brief) {
162436
+ const namedError = error51;
162437
+ const name2 = error51 instanceof Error ? error51.name : namedError && typeof namedError === "object" && typeof namedError.name === "string" ? namedError.name : "";
162438
+ const combined = `${name2} ${brief}`.toLowerCase();
162439
+ return name2 === "AbortError" || combined.includes("lease");
162440
+ }
162441
+ function logWithStackHead(message, stackHead) {
162442
+ log(message, stackHead ? { stackHead } : undefined);
162443
+ }
162162
162444
  function getOpenCodeDbPath2() {
162163
162445
  return join9(getDataDir(), "opencode", "opencode.db");
162164
162446
  }
@@ -162264,7 +162546,12 @@ async function identifyKeyFilesForSession(args) {
162264
162546
  system: KEY_FILES_SYSTEM_PROMPT,
162265
162547
  parts: [{ type: "text", text: prompt, synthetic: true }]
162266
162548
  }
162267
- }, { timeoutMs: Math.min(remainingMs, 300000), signal: abortController.signal });
162549
+ }, {
162550
+ timeoutMs: Math.min(remainingMs, 300000),
162551
+ signal: abortController.signal,
162552
+ fallbackModels: args.fallbackModels,
162553
+ callContext: `dreamer:key-files:${args.sessionId.slice(0, 12)}`
162554
+ });
162268
162555
  const messagesResponse = await args.client.session.messages({
162269
162556
  path: { id: agentSessionId },
162270
162557
  query: { directory: args.sessionDirectory }
@@ -162337,6 +162624,7 @@ async function identifyKeyFiles(args) {
162337
162624
  parentSessionId: args.parentSessionId,
162338
162625
  sessionDirectory: args.sessionDirectory,
162339
162626
  holderId: args.holderId,
162627
+ fallbackModels: args.fallbackModels,
162340
162628
  deadline: args.deadline,
162341
162629
  sessionId,
162342
162630
  config: args.config
@@ -162390,6 +162678,9 @@ async function runDream(args) {
162390
162678
  const deadline = startedAt + args.maxRuntimeMinutes * 60 * 1000;
162391
162679
  const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`) ?? getDreamState(args.db, "last_dream_at");
162392
162680
  log(`[dreamer] last dream at: ${lastDreamAt ?? "never"} (project=${args.projectIdentity})`);
162681
+ let lastErrorSignature = null;
162682
+ let consecutiveSameErrorFailures = 0;
162683
+ let circuitBreakerTripped = false;
162393
162684
  try {
162394
162685
  for (const taskName of args.tasks) {
162395
162686
  if (Date.now() > deadline) {
@@ -162450,7 +162741,9 @@ async function runDream(args) {
162450
162741
  }
162451
162742
  }, {
162452
162743
  timeoutMs: args.taskTimeoutMinutes * 60 * 1000,
162453
- signal: taskAbortController.signal
162744
+ signal: taskAbortController.signal,
162745
+ fallbackModels: args.fallbackModels,
162746
+ callContext: `dreamer:${taskName}`
162454
162747
  });
162455
162748
  const messagesResponse = await args.client.session.messages({
162456
162749
  path: { id: agentSessionId },
@@ -162470,16 +162763,40 @@ async function runDream(args) {
162470
162763
  durationMs,
162471
162764
  result: taskResult
162472
162765
  });
162766
+ lastErrorSignature = null;
162767
+ consecutiveSameErrorFailures = 0;
162473
162768
  } catch (error51) {
162474
162769
  const durationMs = Date.now() - taskStartedAt;
162475
- const errorMsg = getErrorMessage(error51);
162476
- log(`[dreamer] task ${taskName}: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorMsg}`);
162770
+ const errorDescription = describeError(error51);
162771
+ logWithStackHead(`[dreamer] task ${taskName}: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorDescription.brief}`, errorDescription.stackHead);
162477
162772
  result.tasks.push({
162478
162773
  name: taskName,
162479
162774
  durationMs,
162480
162775
  result: null,
162481
- error: errorMsg
162776
+ error: errorDescription.brief
162482
162777
  });
162778
+ if (shouldSkipCircuitBreaker(error51, errorDescription.brief)) {
162779
+ lastErrorSignature = null;
162780
+ consecutiveSameErrorFailures = 0;
162781
+ } else {
162782
+ const signature = getCircuitBreakerSignature(error51, errorDescription.brief);
162783
+ if (signature === lastErrorSignature) {
162784
+ consecutiveSameErrorFailures += 1;
162785
+ } else {
162786
+ lastErrorSignature = signature;
162787
+ consecutiveSameErrorFailures = 1;
162788
+ }
162789
+ if (consecutiveSameErrorFailures >= CIRCUIT_BREAKER_THRESHOLD) {
162790
+ circuitBreakerTripped = true;
162791
+ log(`[dreamer] circuit breaker: ${consecutiveSameErrorFailures} consecutive ${signature} failures — aborting remaining tasks`);
162792
+ result.tasks.push({
162793
+ name: "circuit-breaker",
162794
+ durationMs: 0,
162795
+ result: "",
162796
+ error: `Aborted remaining tasks: ${consecutiveSameErrorFailures} consecutive ${signature} failures. Configure dreamer model/fallback_models in magic-context.jsonc.`
162797
+ });
162798
+ }
162799
+ }
162483
162800
  } finally {
162484
162801
  clearInterval(leaseRenewalInterval);
162485
162802
  if (agentSessionId) {
@@ -162491,8 +162808,20 @@ async function runDream(args) {
162491
162808
  });
162492
162809
  }
162493
162810
  }
162811
+ if (circuitBreakerTripped) {
162812
+ break;
162813
+ }
162814
+ }
162815
+ if (circuitBreakerTripped) {
162816
+ log("[dreamer] circuit breaker: skipping post-task phases");
162817
+ result.tasks.push({
162818
+ name: "post-task-phases",
162819
+ durationMs: 0,
162820
+ result: "",
162821
+ error: "Skipped post-task phases after circuit breaker tripped; configure dreamer model/fallback_models in magic-context.jsonc."
162822
+ });
162494
162823
  }
162495
- if (args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
162824
+ if (!circuitBreakerTripped && args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
162496
162825
  const umStart = Date.now();
162497
162826
  try {
162498
162827
  const reviewResult = await reviewUserMemories({
@@ -162502,7 +162831,8 @@ async function runDream(args) {
162502
162831
  sessionDirectory: args.sessionDirectory,
162503
162832
  holderId,
162504
162833
  deadline,
162505
- promotionThreshold: args.experimentalUserMemories.promotionThreshold
162834
+ promotionThreshold: args.experimentalUserMemories.promotionThreshold,
162835
+ fallbackModels: args.fallbackModels
162506
162836
  });
162507
162837
  const umOutput = `promoted=${reviewResult.promoted} merged=${reviewResult.merged} dismissed=${reviewResult.dismissed} consumed=${reviewResult.candidatesConsumed}`;
162508
162838
  if (reviewResult.promoted > 0 || reviewResult.merged > 0 || reviewResult.dismissed > 0) {
@@ -162514,16 +162844,17 @@ async function runDream(args) {
162514
162844
  result: umOutput
162515
162845
  });
162516
162846
  } catch (error51) {
162517
- log(`[dreamer] user-memory review failed: ${getErrorMessage(error51)}`);
162847
+ const errorDescription = describeError(error51);
162848
+ logWithStackHead(`[dreamer] user-memory review failed: ${errorDescription.brief}`, errorDescription.stackHead);
162518
162849
  result.tasks.push({
162519
162850
  name: "user memories",
162520
162851
  durationMs: Date.now() - umStart,
162521
162852
  result: "",
162522
- error: getErrorMessage(error51)
162853
+ error: errorDescription.brief
162523
162854
  });
162524
162855
  }
162525
162856
  }
162526
- if (Date.now() <= deadline) {
162857
+ if (!circuitBreakerTripped && Date.now() <= deadline) {
162527
162858
  try {
162528
162859
  await evaluateSmartNotes({
162529
162860
  db: args.db,
@@ -162533,13 +162864,15 @@ async function runDream(args) {
162533
162864
  sessionDirectory: args.sessionDirectory,
162534
162865
  holderId,
162535
162866
  deadline,
162536
- result
162867
+ result,
162868
+ fallbackModels: args.fallbackModels
162537
162869
  });
162538
162870
  } catch (error51) {
162539
- log(`[dreamer] smart note evaluation failed: ${getErrorMessage(error51)}`);
162871
+ const errorDescription = describeError(error51);
162872
+ logWithStackHead(`[dreamer] smart note evaluation failed: ${errorDescription.brief}`, errorDescription.stackHead);
162540
162873
  }
162541
162874
  }
162542
- if (args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
162875
+ if (!circuitBreakerTripped && args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
162543
162876
  const kfStart = Date.now();
162544
162877
  try {
162545
162878
  await identifyKeyFiles({
@@ -162550,7 +162883,8 @@ async function runDream(args) {
162550
162883
  sessionDirectory: args.sessionDirectory ?? args.projectIdentity,
162551
162884
  holderId,
162552
162885
  deadline,
162553
- config: args.experimentalPinKeyFiles
162886
+ config: args.experimentalPinKeyFiles,
162887
+ fallbackModels: args.fallbackModels
162554
162888
  });
162555
162889
  result.tasks.push({
162556
162890
  name: "key files",
@@ -162558,12 +162892,13 @@ async function runDream(args) {
162558
162892
  result: "completed"
162559
162893
  });
162560
162894
  } catch (error51) {
162561
- log(`[key-files] identification phase failed: ${getErrorMessage(error51)}`);
162895
+ const errorDescription = describeError(error51);
162896
+ logWithStackHead(`[key-files] identification phase failed: ${errorDescription.brief}`, errorDescription.stackHead);
162562
162897
  result.tasks.push({
162563
162898
  name: "key files",
162564
162899
  durationMs: Date.now() - kfStart,
162565
162900
  result: "",
162566
- error: getErrorMessage(error51)
162901
+ error: errorDescription.brief
162567
162902
  });
162568
162903
  }
162569
162904
  }
@@ -162598,7 +162933,13 @@ async function runDream(args) {
162598
162933
  smartNotesPending: result.smartNotesPending,
162599
162934
  memoryChanges: persistedMemoryChanges
162600
162935
  });
162601
- const POST_TASK_NAMES = new Set(["smart-notes", "user memories", "key files"]);
162936
+ const POST_TASK_NAMES = new Set([
162937
+ "smart-notes",
162938
+ "user memories",
162939
+ "key files",
162940
+ "post-task-phases",
162941
+ "circuit-breaker"
162942
+ ]);
162602
162943
  const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
162603
162944
  if (hasSuccessfulTask) {
162604
162945
  setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
@@ -162677,7 +163018,12 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
162677
163018
  system: DREAMER_SYSTEM_PROMPT,
162678
163019
  parts: [{ type: "text", text: evaluationPrompt, synthetic: true }]
162679
163020
  }
162680
- }, { timeoutMs: Math.min(remainingMs, 300000), signal: abortController.signal });
163021
+ }, {
163022
+ timeoutMs: Math.min(remainingMs, 300000),
163023
+ signal: abortController.signal,
163024
+ fallbackModels: args.fallbackModels,
163025
+ callContext: "dreamer:smart-notes"
163026
+ });
162681
163027
  const messagesResponse = await args.client.session.messages({
162682
163028
  path: { id: agentSessionId },
162683
163029
  query: { directory: args.sessionDirectory ?? args.projectIdentity }
@@ -162736,15 +163082,15 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
162736
163082
  });
162737
163083
  } catch (error51) {
162738
163084
  const durationMs = Date.now() - taskStartedAt;
162739
- const errorMsg = getErrorMessage(error51);
163085
+ const errorDescription = describeError(error51);
162740
163086
  args.result.smartNotesSurfaced = 0;
162741
163087
  args.result.smartNotesPending = pendingNotes.length;
162742
- log(`[dreamer] smart notes: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorMsg}`);
163088
+ logWithStackHead(`[dreamer] smart notes: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorDescription.brief}`, errorDescription.stackHead);
162743
163089
  args.result.tasks.push({
162744
163090
  name: "smart-notes",
162745
163091
  durationMs,
162746
163092
  result: null,
162747
- error: errorMsg
163093
+ error: errorDescription.brief
162748
163094
  });
162749
163095
  } finally {
162750
163096
  clearInterval(leaseInterval);
@@ -162777,7 +163123,8 @@ async function processDreamQueue(args) {
162777
163123
  maxRuntimeMinutes: args.maxRuntimeMinutes,
162778
163124
  sessionDirectory: projectDirectory,
162779
163125
  experimentalUserMemories: args.experimentalUserMemories,
162780
- experimentalPinKeyFiles: args.experimentalPinKeyFiles
163126
+ experimentalPinKeyFiles: args.experimentalPinKeyFiles,
163127
+ fallbackModels: args.fallbackModels
162781
163128
  });
162782
163129
  } catch (error51) {
162783
163130
  log(`[dreamer] runDream threw for ${entry.projectIdentity}: ${getErrorMessage(error51)}`);
@@ -163501,7 +163848,8 @@ async function sweepProject(reg, origin) {
163501
163848
  maxRuntimeMinutes: reg.dreamerConfig.max_runtime_minutes,
163502
163849
  experimentalUserMemories: reg.experimentalUserMemories,
163503
163850
  experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
163504
- projectIdentity: registrationIdentity
163851
+ projectIdentity: registrationIdentity,
163852
+ fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
163505
163853
  });
163506
163854
  } catch (error51) {
163507
163855
  log(`[dreamer] timer-triggered queue processing failed for ${reg.directory}:`, error51);
@@ -165299,8 +165647,9 @@ function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
165299
165647
  continue;
165300
165648
  const messageId = message.info.id;
165301
165649
  let textOrdinal = 0;
165302
- for (let partIndex = 0;partIndex < message.parts.length; partIndex += 1) {
165303
- const part = message.parts[partIndex];
165650
+ const parts = message.parts;
165651
+ for (let partIndex = 0;partIndex < parts.length; partIndex += 1) {
165652
+ const part = parts[partIndex];
165304
165653
  if (part === undefined)
165305
165654
  continue;
165306
165655
  if (part.kind === "text") {
@@ -170399,7 +170748,8 @@ async function runCompressorPass2(args) {
170399
170748
  targetTokens,
170400
170749
  outputCount,
170401
170750
  outputDepth,
170402
- historianTimeoutMs
170751
+ historianTimeoutMs,
170752
+ fallbackModels
170403
170753
  } = args;
170404
170754
  const prompt = buildCompressorPrompt(compartments, currentTokens, targetTokens, outputDepth, outputCount);
170405
170755
  let agentSessionId = null;
@@ -170421,7 +170771,11 @@ async function runCompressorPass2(args) {
170421
170771
  agent: HISTORIAN_AGENT2,
170422
170772
  parts: [{ type: "text", text: prompt, synthetic: true }]
170423
170773
  }
170424
- }, { timeoutMs: historianTimeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS });
170774
+ }, {
170775
+ timeoutMs: historianTimeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
170776
+ fallbackModels,
170777
+ callContext: "compressor"
170778
+ });
170425
170779
  const messagesResponse = await client.session.messages({
170426
170780
  path: { id: agentSessionId },
170427
170781
  query: { directory }
@@ -170559,7 +170913,8 @@ async function runHistorianPrompt(args) {
170559
170913
  timeoutMs,
170560
170914
  dumpLabel,
170561
170915
  modelOverride,
170562
- agentId = HISTORIAN_AGENT
170916
+ agentId = HISTORIAN_AGENT,
170917
+ fallbackModels
170563
170918
  } = args;
170564
170919
  let agentSessionId = null;
170565
170920
  try {
@@ -170586,7 +170941,11 @@ async function runHistorianPrompt(args) {
170586
170941
  ...modelOverride ? { model: modelOverride } : {},
170587
170942
  parts: [{ type: "text", text: prompt, synthetic: true }]
170588
170943
  }
170589
- }, { timeoutMs: timeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS });
170944
+ }, {
170945
+ timeoutMs: timeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
170946
+ fallbackModels: modelOverride ? undefined : fallbackModels,
170947
+ callContext: agentId === HISTORIAN_EDITOR_AGENT ? "historian:editor" : "historian"
170948
+ });
170590
170949
  sessionLog(parentSessionId, `historian: prompt completed (attempt ${retryIndex + 1}/${MAX_HISTORIAN_RETRIES + 1})`);
170591
170950
  break;
170592
170951
  } catch (error51) {
@@ -171042,6 +171401,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
171042
171401
  dumpLabelBase: `partial-recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
171043
171402
  timeoutMs: historianTimeoutMs,
171044
171403
  fallbackModelId: deps.fallbackModelId,
171404
+ fallbackModels: deps.fallbackModels,
171045
171405
  twoPass: deps.historianTwoPass,
171046
171406
  callbacks: {
171047
171407
  onRepairRetry: async (error51) => {
@@ -171244,6 +171604,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
171244
171604
  dumpLabelBase: `recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
171245
171605
  timeoutMs: historianTimeoutMs,
171246
171606
  fallbackModelId: deps.fallbackModelId,
171607
+ fallbackModels: deps.fallbackModels,
171247
171608
  twoPass: deps.historianTwoPass,
171248
171609
  callbacks: {
171249
171610
  onRepairRetry: async (error51) => {
@@ -171341,6 +171702,7 @@ Nothing was written.`;
171341
171702
  directory: sessionDirectory,
171342
171703
  historyBudgetTokens: deps.historyBudgetTokens,
171343
171704
  historianTimeoutMs,
171705
+ fallbackModels: deps.fallbackModels,
171344
171706
  minCompartmentRatio: deps.compressorMinCompartmentRatio,
171345
171707
  maxMergeDepth: deps.compressorMaxMergeDepth
171346
171708
  });
@@ -171877,7 +172239,7 @@ import {
171877
172239
  // package.json
171878
172240
  var package_default = {
171879
172241
  name: "@cortexkit/pi-magic-context",
171880
- version: "0.17.2",
172242
+ version: "0.18.0",
171881
172243
  type: "module",
171882
172244
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
171883
172245
  main: "dist/index.js",
@@ -24343,6 +24343,25 @@ var MIGRATIONS = [
24343
24343
  WHERE type = 'tool' AND tool_owner_message_id IS NULL;
24344
24344
  `);
24345
24345
  }
24346
+ },
24347
+ {
24348
+ version: 11,
24349
+ description: "Add todo state synthesis columns to session_meta",
24350
+ up: (db) => {
24351
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
24352
+ if (!cols.some((c) => c.name === "last_todo_state")) {
24353
+ db.exec("ALTER TABLE session_meta ADD COLUMN last_todo_state TEXT DEFAULT ''");
24354
+ }
24355
+ if (!cols.some((c) => c.name === "todo_synthetic_call_id")) {
24356
+ db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_call_id TEXT DEFAULT ''");
24357
+ }
24358
+ if (!cols.some((c) => c.name === "todo_synthetic_anchor_message_id")) {
24359
+ db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_anchor_message_id TEXT DEFAULT ''");
24360
+ }
24361
+ if (!cols.some((c) => c.name === "todo_synthetic_state_json")) {
24362
+ db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_state_json TEXT DEFAULT ''");
24363
+ }
24364
+ }
24346
24365
  }
24347
24366
  ];
24348
24367
  function ensureMigrationsTable(db) {
@@ -157509,6 +157528,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
157509
157528
  note_nudge_trigger_message_id TEXT DEFAULT '',
157510
157529
  note_nudge_sticky_text TEXT DEFAULT '',
157511
157530
  note_nudge_sticky_message_id TEXT DEFAULT '',
157531
+ last_todo_state TEXT DEFAULT '',
157532
+ todo_synthetic_call_id TEXT DEFAULT '',
157533
+ todo_synthetic_anchor_message_id TEXT DEFAULT '',
157534
+ todo_synthetic_state_json TEXT DEFAULT '',
157512
157535
  is_subagent INTEGER DEFAULT 0,
157513
157536
  last_context_percentage REAL DEFAULT 0,
157514
157537
  last_input_tokens INTEGER DEFAULT 0,
@@ -157573,6 +157596,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
157573
157596
  ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
157574
157597
  ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
157575
157598
  ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
157599
+ ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
157600
+ ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
157601
+ ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
157602
+ ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
157576
157603
  ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
157577
157604
  ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
157578
157605
  ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
@@ -157637,6 +157664,10 @@ function healNullTextColumns(db) {
157637
157664
  ["note_nudge_trigger_message_id", ""],
157638
157665
  ["note_nudge_sticky_text", ""],
157639
157666
  ["note_nudge_sticky_message_id", ""],
157667
+ ["last_todo_state", ""],
157668
+ ["todo_synthetic_call_id", ""],
157669
+ ["todo_synthetic_anchor_message_id", ""],
157670
+ ["todo_synthetic_state_json", ""],
157640
157671
  ["system_prompt_hash", ""],
157641
157672
  ["stripped_placeholder_ids", ""],
157642
157673
  ["memory_block_cache", ""],
@@ -163998,7 +164029,8 @@ var META_COLUMNS = {
163998
164029
  systemPromptTokens: "system_prompt_tokens",
163999
164030
  conversationTokens: "conversation_tokens",
164000
164031
  toolCallTokens: "tool_call_tokens",
164001
- clearedReasoningThroughTag: "cleared_reasoning_through_tag"
164032
+ clearedReasoningThroughTag: "cleared_reasoning_through_tag",
164033
+ lastTodoState: "last_todo_state"
164002
164034
  };
164003
164035
  var BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress"]);
164004
164036
  function isStringOrNull(value) {
@@ -164011,7 +164043,7 @@ function isSessionMetaRow(row) {
164011
164043
  if (row === null || typeof row !== "object")
164012
164044
  return false;
164013
164045
  const r = row;
164014
- return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag);
164046
+ return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state);
164015
164047
  }
164016
164048
  function getDefaultSessionMeta(sessionId) {
164017
164049
  return {
@@ -164031,7 +164063,8 @@ function getDefaultSessionMeta(sessionId) {
164031
164063
  systemPromptTokens: 0,
164032
164064
  conversationTokens: 0,
164033
164065
  toolCallTokens: 0,
164034
- clearedReasoningThroughTag: 0
164066
+ clearedReasoningThroughTag: 0,
164067
+ lastTodoState: ""
164035
164068
  };
164036
164069
  }
164037
164070
  function ensureSessionMetaRow(db, sessionId) {
@@ -164043,6 +164076,7 @@ function toSessionMeta(row) {
164043
164076
  const transformErrorRaw = typeof row.last_transform_error === "string" ? row.last_transform_error : "";
164044
164077
  const cacheTtlRaw = typeof row.cache_ttl === "string" && row.cache_ttl.length > 0 ? row.cache_ttl : "5m";
164045
164078
  const systemPromptHashRaw = row.system_prompt_hash == null ? "" : row.system_prompt_hash;
164079
+ const lastTodoStateRaw = typeof row.last_todo_state === "string" ? row.last_todo_state : "";
164046
164080
  const numOrZero = (value) => typeof value === "number" ? value : 0;
164047
164081
  return {
164048
164082
  sessionId: row.session_id,
@@ -164061,7 +164095,8 @@ function toSessionMeta(row) {
164061
164095
  systemPromptTokens: numOrZero(row.system_prompt_tokens),
164062
164096
  conversationTokens: numOrZero(row.conversation_tokens),
164063
164097
  toolCallTokens: numOrZero(row.tool_call_tokens),
164064
- clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag)
164098
+ clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag),
164099
+ lastTodoState: lastTodoStateRaw
164065
164100
  };
164066
164101
  }
164067
164102
 
@@ -164277,7 +164312,7 @@ function resolveIsSubagentFromOpenCodeDb(sessionId) {
164277
164312
 
164278
164313
  // ../plugin/src/features/magic-context/storage-meta-session.ts
164279
164314
  function getOrCreateSessionMeta(db, sessionId) {
164280
- const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag FROM session_meta WHERE session_id = ?").get(sessionId);
164315
+ const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag, last_todo_state FROM session_meta WHERE session_id = ?").get(sessionId);
164281
164316
  if (isSessionMetaRow(result)) {
164282
164317
  return toSessionMeta(result);
164283
164318
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-magic-context",
3
- "version": "0.17.2",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",