@rudderhq/agent-runtime-utils 0.7.13 → 0.7.15

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 (38) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/rudder-agent-contract.d.ts +5 -0
  6. package/dist/rudder-agent-contract.d.ts.map +1 -0
  7. package/dist/rudder-agent-contract.generated.d.ts +8322 -0
  8. package/dist/rudder-agent-contract.generated.d.ts.map +1 -0
  9. package/dist/rudder-agent-contract.generated.js +9320 -0
  10. package/dist/rudder-agent-contract.generated.js.map +1 -0
  11. package/dist/rudder-agent-contract.js +31 -0
  12. package/dist/rudder-agent-contract.js.map +1 -0
  13. package/dist/rudder-agent-contract.test.d.ts +2 -0
  14. package/dist/rudder-agent-contract.test.d.ts.map +1 -0
  15. package/dist/rudder-agent-contract.test.js +69 -0
  16. package/dist/rudder-agent-contract.test.js.map +1 -0
  17. package/dist/rudder-mcp-contract.d.ts +5939 -932
  18. package/dist/rudder-mcp-contract.d.ts.map +1 -1
  19. package/dist/rudder-mcp-contract.js +7 -805
  20. package/dist/rudder-mcp-contract.js.map +1 -1
  21. package/dist/rudder-mcp-tool-descriptors.generated.d.ts +5111 -1
  22. package/dist/rudder-mcp-tool-descriptors.generated.d.ts.map +1 -1
  23. package/dist/rudder-mcp-tool-descriptors.generated.js +5999 -104
  24. package/dist/rudder-mcp-tool-descriptors.generated.js.map +1 -1
  25. package/dist/server-utils.instructions.d.ts.map +1 -1
  26. package/dist/server-utils.instructions.js +26 -6
  27. package/dist/server-utils.instructions.js.map +1 -1
  28. package/dist/server-utils.prompt-boundaries.test.d.ts +2 -0
  29. package/dist/server-utils.prompt-boundaries.test.d.ts.map +1 -0
  30. package/dist/server-utils.prompt-boundaries.test.js +44 -0
  31. package/dist/server-utils.prompt-boundaries.test.js.map +1 -0
  32. package/dist/server-utils.prompts.d.ts +23 -10
  33. package/dist/server-utils.prompts.d.ts.map +1 -1
  34. package/dist/server-utils.prompts.js +65 -27
  35. package/dist/server-utils.prompts.js.map +1 -1
  36. package/dist/server-utils.test.js +65 -19
  37. package/dist/server-utils.test.js.map +1 -1
  38. package/package.json +2 -2
@@ -918,7 +918,9 @@ describe("loadAgentInstructionsPrefix", () => {
918
918
  instructionsFilePath: "",
919
919
  onLog: async () => { },
920
920
  });
921
- expect(loaded.prefix).toContain("# Rudder Agent Operating Contract");
921
+ expect(loaded.prefix).toContain("<rudder_agent_operating_contract>");
922
+ expect(loaded.prefix).toContain("</rudder_agent_operating_contract>");
923
+ expect(loaded.prefix).not.toContain("# Rudder Agent Operating Contract");
922
924
  expect(loaded.prefix).toContain(RUDDER_AGENT_OPERATING_CONTRACT);
923
925
  expect(loaded.prefix).toContain("installed but not enabled");
924
926
  expect(loaded.prefix).toContain("library:projects/<project-key>/");
@@ -971,7 +973,8 @@ describe("loadAgentInstructionsPrefix", () => {
971
973
  includeHeartbeatInstructions: true,
972
974
  onLog: async () => { },
973
975
  });
974
- expect(loaded.prefix).toContain("# Rudder Agent Operating Contract");
976
+ expect(loaded.prefix).toContain("<rudder_agent_operating_contract>");
977
+ expect(loaded.prefix).toContain("<rudder_heartbeat_instruction>");
975
978
  expect(loaded.prefix).toContain(RUDDER_AGENT_HEARTBEAT_INSTRUCTION);
976
979
  expect(loaded.prefix).toContain("platform-owned heartbeat/self-check pipeline");
977
980
  expect(loaded.commandNotes).toEqual([
@@ -1006,8 +1009,9 @@ describe("loadAgentInstructionsPrefix", () => {
1006
1009
  logs.push({ stream, chunk });
1007
1010
  },
1008
1011
  });
1009
- expect(loaded.prefix).toContain("# Rudder Agent Operating Contract");
1012
+ expect(loaded.prefix).toContain("<rudder_agent_operating_contract>");
1010
1013
  expect(loaded.prefix).toContain("# Agent Instructions");
1014
+ expect(loaded.prefix).toContain("<AGENTS.md>\n# Agent Instructions\n</AGENTS.md>");
1011
1015
  expect(loaded.prefix).toContain("The above AGENTS.md instruction file was loaded from $AGENT_HOME/instructions.");
1012
1016
  expect(loaded.prefix).toContain("relative file references from $AGENT_HOME/instructions/");
1013
1017
  expect(loaded.prefix).not.toContain("Tacit Memory");
@@ -1030,6 +1034,41 @@ describe("loadAgentInstructionsPrefix", () => {
1030
1034
  await fs.rm(root, { recursive: true, force: true });
1031
1035
  }
1032
1036
  });
1037
+ it("uses a stable escaped wrapper for a non-canonical configured entry file", async () => {
1038
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "rudder-load-agent-instructions-custom-entry-"));
1039
+ const instructionsPath = path.join(root, "instructions", "custom role.md");
1040
+ const contents = " generic entry code block\n\nKeep <angle brackets> and Markdown unchanged.\n";
1041
+ await fs.mkdir(path.dirname(instructionsPath), { recursive: true });
1042
+ await fs.writeFile(instructionsPath, contents, "utf8");
1043
+ try {
1044
+ const loaded = await loadAgentInstructionsPrefix({
1045
+ instructionsFilePath: instructionsPath,
1046
+ onLog: async () => { },
1047
+ });
1048
+ expect(loaded.prefix).toContain(`<agent_instruction_file path="$AGENT_HOME/instructions/custom role.md">\n${contents.trimEnd()}\n</agent_instruction_file>`);
1049
+ expect(loaded.prefix).not.toContain("<custom role.md>");
1050
+ }
1051
+ finally {
1052
+ await fs.rm(root, { recursive: true, force: true });
1053
+ }
1054
+ });
1055
+ it("preserves leading blank lines and indented Markdown in canonical instruction files", async () => {
1056
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "rudder-load-agent-instructions-leading-markdown-"));
1057
+ const instructionsPath = path.join(root, "instructions", "SOUL.md");
1058
+ const contents = "\n canonical code block\n\nKeep the leading bytes.\n";
1059
+ await fs.mkdir(path.dirname(instructionsPath), { recursive: true });
1060
+ await fs.writeFile(instructionsPath, contents, "utf8");
1061
+ try {
1062
+ const loaded = await loadAgentInstructionsPrefix({
1063
+ instructionsFilePath: instructionsPath,
1064
+ onLog: async () => { },
1065
+ });
1066
+ expect(loaded.prefix).toContain(`<SOUL.md>\n${contents.trimEnd()}\n</SOUL.md>`);
1067
+ }
1068
+ finally {
1069
+ await fs.rm(root, { recursive: true, force: true });
1070
+ }
1071
+ });
1033
1072
  it("loads the entry instructions file plus sibling SOUL.md, TOOLS.md, and MEMORY.md", async () => {
1034
1073
  const root = await fs.mkdtemp(path.join(os.tmpdir(), "rudder-load-agent-instructions-memory-"));
1035
1074
  const instructionsPath = path.join(root, "instructions", "AGENTS.md");
@@ -1052,6 +1091,10 @@ describe("loadAgentInstructionsPrefix", () => {
1052
1091
  expect(loaded.prefix).toContain("# Persona");
1053
1092
  expect(loaded.prefix).toContain("# Tools");
1054
1093
  expect(loaded.prefix).toContain("# Tacit Memory");
1094
+ expect(loaded.prefix).toContain("<AGENTS.md>\n# Agent Instructions\n</AGENTS.md>");
1095
+ expect(loaded.prefix).toContain("<SOUL.md>\n# Persona\n\nYou are QA.\n</SOUL.md>");
1096
+ expect(loaded.prefix).toContain("<TOOLS.md>\n# Tools\n\n- Use rudder.\n</TOOLS.md>");
1097
+ expect(loaded.prefix).toContain("<MEMORY.md>\n# Tacit Memory\n\n- Prefer concise updates.\n</MEMORY.md>");
1055
1098
  expect(loaded.prefix).not.toContain("# Heartbeat");
1056
1099
  expect(loaded.prefix).not.toContain("## Current Time");
1057
1100
  expect(loaded.prefix).toContain("The above AGENTS.md, SOUL.md, TOOLS.md, MEMORY.md instruction files were loaded from $AGENT_HOME/instructions.");
@@ -1091,15 +1134,15 @@ describe("loadAgentInstructionsPrefix", () => {
1091
1134
  const loaded = await loadAgentInstructionsPrefix({
1092
1135
  instructionsFilePath: instructionsPath,
1093
1136
  includeHeartbeatInstructions: true,
1094
- instructionContextSections: ["## Recent Rudder Context\n\n#### today memory: 2026-06-21.md\n- Calibrate prompt stack"],
1137
+ instructionContextSections: ["<recent_rudder_context>\n#### today memory: 2026-06-21.md\n- Calibrate prompt stack\n</recent_rudder_context>"],
1095
1138
  onLog: async () => { },
1096
1139
  });
1097
- const operatingContractIndex = loaded.prefix.indexOf("# Rudder Agent Operating Contract");
1140
+ const operatingContractIndex = loaded.prefix.indexOf("<rudder_agent_operating_contract>");
1098
1141
  const soulIndex = loaded.prefix.indexOf("# Persona");
1099
1142
  const toolsIndex = loaded.prefix.indexOf("# Tool Notes");
1100
1143
  const memoryIndex = loaded.prefix.indexOf("# Memory Notes");
1101
- const recentContextIndex = loaded.prefix.indexOf("## Recent Rudder Context");
1102
- const heartbeatIndex = loaded.prefix.indexOf("# Rudder Heartbeat Instruction");
1144
+ const recentContextIndex = loaded.prefix.indexOf("<recent_rudder_context>");
1145
+ const heartbeatIndex = loaded.prefix.indexOf("<rudder_heartbeat_instruction>");
1103
1146
  expect(operatingContractIndex).toBeGreaterThanOrEqual(0);
1104
1147
  expect(soulIndex).toBeGreaterThan(operatingContractIndex);
1105
1148
  expect(toolsIndex).toBeGreaterThan(soulIndex);
@@ -1110,6 +1153,9 @@ describe("loadAgentInstructionsPrefix", () => {
1110
1153
  expect(loaded.prefix).toContain("# Persona");
1111
1154
  expect(loaded.prefix).toContain("# Tool Notes");
1112
1155
  expect(loaded.prefix).toContain("# Memory Notes");
1156
+ expect(loaded.prefix).toContain("<SOUL.md>\n# Persona");
1157
+ expect(loaded.prefix).toContain("<TOOLS.md>\n# Tool Notes");
1158
+ expect(loaded.prefix).toContain("<MEMORY.md>\n# Memory Notes");
1113
1159
  expect(loaded.prefix).not.toContain("## Agent Instruction:");
1114
1160
  expect(loaded.prefix).not.toContain("Agent Instruction: SOUL.md");
1115
1161
  expect(loaded.prefix).not.toContain("The above SOUL.md content was loaded");
@@ -1135,7 +1181,7 @@ describe("loadAgentInstructionsPrefix", () => {
1135
1181
  onLog: async () => { },
1136
1182
  });
1137
1183
  expect(loaded.prefix).toContain("# Persona");
1138
- expect(loaded.prefix).toContain("# Rudder Heartbeat Instruction");
1184
+ expect(loaded.prefix).toContain("<rudder_heartbeat_instruction>");
1139
1185
  expect(loaded.prefix).not.toContain("# Heartbeat\n\n- Check assignments.");
1140
1186
  expect(loaded.commandNotes).toContain("Loaded Rudder heartbeat instructions from runtime code");
1141
1187
  expect(loaded.commandNotes).not.toContain("Loaded supplemental agent heartbeat notes from $AGENT_HOME/instructions/HEARTBEAT.md");
@@ -1159,8 +1205,8 @@ describe("loadAgentInstructionsPrefix", () => {
1159
1205
  try {
1160
1206
  const instructionContext = prepareAgentInstructionRuntimeContext({
1161
1207
  rudderWorkspace: {
1162
- orgResourcesPrompt: "## Your Current Automations\n\n- Morning review",
1163
- resourcesPrompt: "## Your Current Automations\n\n- Morning review",
1208
+ orgResourcesPrompt: "<current_automations>\n- Morning review\n</current_automations>",
1209
+ resourcesPrompt: "<current_automations>\n- Morning review\n</current_automations>",
1164
1210
  },
1165
1211
  });
1166
1212
  const loaded = await loadAgentInstructionsPrefix({
@@ -1169,13 +1215,13 @@ describe("loadAgentInstructionsPrefix", () => {
1169
1215
  instructionContextSections: instructionContext.instructionContextSections,
1170
1216
  onLog: async () => { },
1171
1217
  });
1172
- const operatingContractIndex = loaded.prefix.indexOf("# Rudder Agent Operating Contract");
1218
+ const operatingContractIndex = loaded.prefix.indexOf("<rudder_agent_operating_contract>");
1173
1219
  const agentContractIndex = loaded.prefix.indexOf("# Agent Contract");
1174
1220
  const soulIndex = loaded.prefix.indexOf("# Agent Soul");
1175
1221
  const toolsIndex = loaded.prefix.indexOf("# Agent Tools");
1176
1222
  const memoryIndex = loaded.prefix.indexOf("# Agent Memory");
1177
- const automationsIndex = loaded.prefix.indexOf("## Your Current Automations");
1178
- const heartbeatIndex = loaded.prefix.indexOf("# Rudder Heartbeat Instruction");
1223
+ const automationsIndex = loaded.prefix.indexOf("<current_automations>");
1224
+ const heartbeatIndex = loaded.prefix.indexOf("<rudder_heartbeat_instruction>");
1179
1225
  expect(operatingContractIndex).toBeGreaterThanOrEqual(0);
1180
1226
  expect(agentContractIndex).toBeGreaterThan(operatingContractIndex);
1181
1227
  expect(soulIndex).toBeGreaterThan(agentContractIndex);
@@ -1184,7 +1230,7 @@ describe("loadAgentInstructionsPrefix", () => {
1184
1230
  expect(automationsIndex).toBeGreaterThan(memoryIndex);
1185
1231
  expect(heartbeatIndex).toBeGreaterThan(automationsIndex);
1186
1232
  expect(loaded.prefix).not.toContain("## Current Time");
1187
- expect(loaded.prefix).toMatch(/# Rudder Heartbeat Instruction[\s\S]*runtime\.$/);
1233
+ expect(loaded.prefix).toMatch(/<rudder_heartbeat_instruction>[\s\S]*runtime\.\n<\/rudder_heartbeat_instruction>$/);
1188
1234
  expect(renderTemplate("{{context.rudderWorkspace.orgResourcesPrompt}}", { context: instructionContext.promptContext })).toBe("");
1189
1235
  }
1190
1236
  finally {
@@ -1192,7 +1238,7 @@ describe("loadAgentInstructionsPrefix", () => {
1192
1238
  }
1193
1239
  });
1194
1240
  it("moves all documented resource prompt aliases into the stable instruction stack", async () => {
1195
- const canonicalPrompt = "## Your Current Automations\n\n- Canonical";
1241
+ const canonicalPrompt = "<current_automations>\n- Canonical\n</current_automations>";
1196
1242
  const topLevelOnly = prepareAgentInstructionRuntimeContext({
1197
1243
  rudderResourcesPrompt: canonicalPrompt,
1198
1244
  });
@@ -1214,7 +1260,7 @@ describe("loadAgentInstructionsPrefix", () => {
1214
1260
  expect(renderTemplate("{{context.rudderWorkspace.orgResourcesPrompt}}", { context: legacyOnly.promptContext })).toBe("");
1215
1261
  });
1216
1262
  it("prefers canonical resourcesPrompt and only clears matching resource prompt aliases", async () => {
1217
- const canonicalPrompt = "## Project Context Resources\n\n- Canonical library context";
1263
+ const canonicalPrompt = "<project_context_resources>\n- Canonical library context\n</project_context_resources>";
1218
1264
  const legacyPrompt = "## Legacy Resources\n\n- Legacy fallback";
1219
1265
  const prepared = prepareAgentInstructionRuntimeContext({
1220
1266
  rudderResourcesPrompt: canonicalPrompt,
@@ -1241,7 +1287,7 @@ describe("loadAgentInstructionsPrefix", () => {
1241
1287
  logs.push({ stream, chunk });
1242
1288
  },
1243
1289
  });
1244
- expect(loaded.prefix).toContain("# Rudder Agent Operating Contract");
1290
+ expect(loaded.prefix).toContain("<rudder_agent_operating_contract>");
1245
1291
  expect(loaded.prefix).not.toContain("# Heartbeat");
1246
1292
  expect(loaded.commandNotes).toContain("Ignored legacy HEARTBEAT.md instructions file: $AGENT_HOME/instructions/HEARTBEAT.md");
1247
1293
  expect(loaded.heartbeatFilePath).toBeNull();
@@ -1270,7 +1316,7 @@ describe("loadAgentInstructionsPrefix", () => {
1270
1316
  includeHeartbeatInstructions: true,
1271
1317
  onLog: async () => { },
1272
1318
  });
1273
- expect(loaded.prefix).toContain("# Rudder Heartbeat Instruction");
1319
+ expect(loaded.prefix).toContain("<rudder_heartbeat_instruction>");
1274
1320
  expect(loaded.prefix).not.toContain("# Heartbeat\n\n- Check assignments.");
1275
1321
  expect(loaded.commandNotes).toContain("Loaded Rudder heartbeat instructions from runtime code");
1276
1322
  expect(loaded.commandNotes).toContain("Ignored legacy HEARTBEAT.md instructions file: $AGENT_HOME/instructions/HEARTBEAT.md");
@@ -1296,7 +1342,7 @@ describe("loadAgentInstructionsPrefix", () => {
1296
1342
  logs.push({ stream, chunk });
1297
1343
  },
1298
1344
  });
1299
- expect(loaded.prefix).toContain("# Rudder Agent Operating Contract");
1345
+ expect(loaded.prefix).toContain("<rudder_agent_operating_contract>");
1300
1346
  expect(loaded.prefix).not.toContain("# Agent Instructions");
1301
1347
  expect(loaded.readFailed).toBe(true);
1302
1348
  expect(loaded.commandNotes).toContain("Configured instructionsFilePath $AGENT_HOME/instructions/AGENTS.md, but file could not be read; continuing without injected instructions.");