@ai-matrx/coding-sessions 0.1.86 → 0.1.88

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.
@@ -135,6 +135,7 @@ function stripAgentBlock(text) {
135
135
  // src/engine/agent-attach.ts
136
136
  var AGENT_MCP_SERVER_NAME = "matrx-agent";
137
137
  var AGENT_PLUGIN_NAME = "matrx-agent";
138
+ var CODEX_REPLACEMENT_CLAUSE = "If a later message in this chat begins with an <ai_matrx_agent> block, that block replaces these AI Matrx agent instructions from then on; an <ai_matrx_agent_removed> block withdraws them.";
138
139
  function escapeAttr(value) {
139
140
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
140
141
  }
@@ -183,9 +184,12 @@ function renderCodexSkillsList(bundle, skillsRoot) {
183
184
  ];
184
185
  return lines.join("\n");
185
186
  }
186
- function renderFallbackBlock(bundle, skillsRoot) {
187
+ function renderFallbackBlock(bundle, skillsRoot, options = {}) {
187
188
  const skills = renderCodexSkillsList(bundle, skillsRoot);
188
- const body = renderAgentInstructions(bundle).trim().replace(/^(<ai_matrx_agent [^>]*>)/, "$1\n\nThe instructions below are your AI Matrx agent for this chat from now on; they replace any AI Matrx agent instructions given earlier.");
189
+ const lead = options.replaces ? `These instructions REPLACE the earlier AI Matrx agent "${options.replaces}" from this message on. Where they differ from anything said before \u2014 including how earlier replies ended \u2014 follow these.` : "The instructions below are your AI Matrx agent for this chat from now on; they replace any AI Matrx agent instructions given earlier.";
190
+ const body = renderAgentInstructions(bundle).trim().replace(/^(<ai_matrx_agent [^>]*>)/, `$1
191
+
192
+ ${lead}`);
189
193
  return skills ? `${body}
190
194
 
191
195
  ${skills}
@@ -254,10 +258,16 @@ async function writeAgentAttachment(dir, bundle, options) {
254
258
  pluginDir,
255
259
  mcpConfigFile,
256
260
  mcpUrl,
257
- // Same order as Claude's: the skills list first, the agent's words last.
258
- codexInstructions: skillsList ? `${skillsList}
261
+ // Same order as Claude's: the skills list first, the agent's words last —
262
+ // then the one sentence that lets a later block replace them. Codex ranks
263
+ // developer instructions above a user message, so without this permission
264
+ // a mid-chat switch or update is ignored (measured live: the v2 block was
265
+ // delivered and Codex kept ending with v1's line).
266
+ codexInstructions: `${skillsList ? `${skillsList}
259
267
 
260
- ${instructions}` : instructions
268
+ ` : ""}${instructions}
269
+ ${CODEX_REPLACEMENT_CLAUSE}
270
+ `
261
271
  };
262
272
  }
263
273
  function agentArgsFor(provider, attachment, options) {
@@ -315,7 +325,7 @@ function sessionAgentRecord(bundle, options) {
315
325
  ...options.variables ? { variables: options.variables } : {}
316
326
  };
317
327
  }
318
- var AGENT_REMOVED_BLOCK = "<ai_matrx_agent_removed>The AI Matrx agent instructions given earlier in this chat no longer apply.</ai_matrx_agent_removed>\n\n";
328
+ var AGENT_REMOVED_BLOCK = "<ai_matrx_agent_removed>The AI Matrx agent instructions given earlier in this chat no longer apply \u2014 including any rule about how replies end. Answer normally from this message on.</ai_matrx_agent_removed>\n\n";
319
329
  async function codexCompactionDroppedAgent(rolloutFile, sinceIso) {
320
330
  const text = await import_promises2.default.readFile(rolloutFile, "utf8").catch(() => "");
321
331
  if (!text.includes('"type":"compacted"')) return false;
@@ -647,7 +657,7 @@ function createClaudeNormalizer() {
647
657
  if (typeof content === "string") {
648
658
  if (isSyntheticClaudeUserText(content) || content.trim().length === 0) return [];
649
659
  userCounter += 1;
650
- return [{ kind: "user", id: str(entry.uuid) ?? `user-${userCounter}`, text: content, at }];
660
+ return [{ kind: "user", id: str(entry.uuid) ?? `user-${userCounter}`, text: stripAgentBlock(content), at }];
651
661
  }
652
662
  if (!Array.isArray(content)) return [];
653
663
  const items = [];
@@ -671,7 +681,7 @@ function createClaudeNormalizer() {
671
681
  items.unshift({
672
682
  kind: "user",
673
683
  id: str(entry.uuid) ?? `user-${userCounter}`,
674
- text: typed.join("\n\n"),
684
+ text: stripAgentBlock(typed.join("\n\n")),
675
685
  at
676
686
  });
677
687
  }
@@ -2490,7 +2500,7 @@ async function createCodingSessionsEngine(options = {}) {
2490
2500
  let cliPrompt = prompt;
2491
2501
  let delivered = null;
2492
2502
  if (!session.agent && session.agentRemovedDue) {
2493
- if (provider === "codex") cliPrompt = `${AGENT_REMOVED_BLOCK}${prompt}`;
2503
+ cliPrompt = `${AGENT_REMOVED_BLOCK}${prompt}`;
2494
2504
  delivered = { agentRemovedDue: false };
2495
2505
  }
2496
2506
  if (session.agent) {
@@ -2510,8 +2520,8 @@ async function createCodingSessionsEngine(options = {}) {
2510
2520
  mcpUrl: await agents.mcpUrlFor(session.id)
2511
2521
  });
2512
2522
  agentArgs = agentArgsFor(provider, attachment, { resuming: session.providerSessionId !== null });
2513
- if (provider === "codex" && session.agent.blockDue) {
2514
- cliPrompt = `${renderFallbackBlock(bundle, import_node_path9.default.join(attachment.dir, "skills"))}${prompt}`;
2523
+ if (session.agent.blockDue) {
2524
+ cliPrompt = `${renderFallbackBlock(bundle, import_node_path9.default.join(attachment.dir, "skills"), { replaces: session.agent.replaces })}${prompt}`;
2515
2525
  }
2516
2526
  delivered = { agent: { ...session.agent, blockDue: false, deliveredAt: run.startedAt } };
2517
2527
  }
@@ -2716,7 +2726,8 @@ async function createCodingSessionsEngine(options = {}) {
2716
2726
  variables: selection.variables ?? {}
2717
2727
  }),
2718
2728
  blockDue: options2.blockDue,
2719
- deliveredAt: null
2729
+ deliveredAt: null,
2730
+ replaces: options2.replaces ?? null
2720
2731
  };
2721
2732
  }
2722
2733
  function killGroup(liveRun) {
@@ -3011,11 +3022,14 @@ async function createCodingSessionsEngine(options = {}) {
3011
3022
  const session = index.session(String(sessionId ?? ""));
3012
3023
  if (!session) throw new Error("This session is not in the list anymore.");
3013
3024
  if (!selection) {
3014
- const told = session.provider === "codex" && session.agent?.deliveredAt != null;
3025
+ const told = session.agent?.deliveredAt != null;
3015
3026
  return saveSession({ ...session, agent: null, agentRemovedDue: told });
3016
3027
  }
3028
+ const previous = session.agent && session.agent.deliveredAt != null ? session.agent : null;
3029
+ const started = session.providerSessionId !== null;
3017
3030
  const agent = await attachAgent(session.id, selection, {
3018
- blockDue: session.provider === "codex" && session.providerSessionId !== null
3031
+ blockDue: started,
3032
+ replaces: previous ? `${previous.name}${previous.versionNumber !== null ? ` v${previous.versionNumber}` : ""}` : null
3019
3033
  });
3020
3034
  return saveSession({ ...session, agent, agentRemovedDue: false });
3021
3035
  },