@deepagents/context 0.12.0 → 0.12.1

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
@@ -222,7 +222,7 @@ function message(content) {
222
222
  } : content;
223
223
  return {
224
224
  id: message2.id,
225
- name: "message",
225
+ name: message2.role,
226
226
  data: "content",
227
227
  type: "message",
228
228
  persist: true,
@@ -244,6 +244,22 @@ function assistantText(content, options) {
244
244
  parts: [{ type: "text", text: content }]
245
245
  });
246
246
  }
247
+ var LAZY_ID = Symbol("lazy-id");
248
+ function isLazyFragment(fragment2) {
249
+ return LAZY_ID in fragment2;
250
+ }
251
+ function lastAssistantMessage(content) {
252
+ return {
253
+ name: "assistant",
254
+ type: "message",
255
+ persist: true,
256
+ data: "content",
257
+ [LAZY_ID]: {
258
+ type: "last-assistant",
259
+ content
260
+ }
261
+ };
262
+ }
247
263
 
248
264
  // packages/context/src/lib/renderers/abstract.renderer.ts
249
265
  import pluralize from "pluralize";
@@ -1208,6 +1224,12 @@ var ContextEngine = class {
1208
1224
  if (this.#pendingMessages.length === 0) {
1209
1225
  return;
1210
1226
  }
1227
+ for (let i = 0; i < this.#pendingMessages.length; i++) {
1228
+ const fragment2 = this.#pendingMessages[i];
1229
+ if (isLazyFragment(fragment2)) {
1230
+ this.#pendingMessages[i] = await this.#resolveLazyFragment(fragment2);
1231
+ }
1232
+ }
1211
1233
  let parentId = this.#branch.headMessageId;
1212
1234
  const now = Date.now();
1213
1235
  for (const fragment2 of this.#pendingMessages) {
@@ -1227,6 +1249,39 @@ var ContextEngine = class {
1227
1249
  this.#branch.headMessageId = parentId;
1228
1250
  this.#pendingMessages = [];
1229
1251
  }
1252
+ /**
1253
+ * Resolve a lazy fragment by finding the appropriate ID.
1254
+ */
1255
+ async #resolveLazyFragment(fragment2) {
1256
+ const lazy = fragment2[LAZY_ID];
1257
+ if (lazy.type === "last-assistant") {
1258
+ const lastId = await this.#getLastAssistantId();
1259
+ return assistantText(lazy.content, { id: lastId ?? crypto.randomUUID() });
1260
+ }
1261
+ throw new Error(`Unknown lazy fragment type: ${lazy.type}`);
1262
+ }
1263
+ /**
1264
+ * Find the most recent assistant message ID (pending or persisted).
1265
+ */
1266
+ async #getLastAssistantId() {
1267
+ for (let i = this.#pendingMessages.length - 1; i >= 0; i--) {
1268
+ const msg = this.#pendingMessages[i];
1269
+ if (msg.name === "assistant" && !isLazyFragment(msg)) {
1270
+ return msg.id;
1271
+ }
1272
+ }
1273
+ if (this.#branch?.headMessageId) {
1274
+ const chain = await this.#store.getMessageChain(
1275
+ this.#branch.headMessageId
1276
+ );
1277
+ for (let i = chain.length - 1; i >= 0; i--) {
1278
+ if (chain[i].name === "assistant") {
1279
+ return chain[i].id;
1280
+ }
1281
+ }
1282
+ }
1283
+ return void 0;
1284
+ }
1230
1285
  /**
1231
1286
  * Estimate token count and cost for the full context.
1232
1287
  *
@@ -1506,6 +1561,35 @@ var ContextEngine = class {
1506
1561
  consolidate() {
1507
1562
  return void 0;
1508
1563
  }
1564
+ /**
1565
+ * Extract skill path mappings from available_skills fragments.
1566
+ * Returns array of { host, sandbox } for mounting in sandbox filesystem.
1567
+ *
1568
+ * Reads the original `paths` configuration stored in fragment metadata
1569
+ * by the skills() fragment helper.
1570
+ *
1571
+ * @example
1572
+ * ```ts
1573
+ * const context = new ContextEngine({ store, chatId, userId })
1574
+ * .set(skills({ paths: [{ host: './skills', sandbox: '/skills' }] }));
1575
+ *
1576
+ * const mounts = context.getSkillMounts();
1577
+ * // [{ host: './skills', sandbox: '/skills' }]
1578
+ * ```
1579
+ */
1580
+ getSkillMounts() {
1581
+ const mounts = [];
1582
+ for (const fragment2 of this.#fragments) {
1583
+ if (fragment2.name === "available_skills" && fragment2.metadata && Array.isArray(fragment2.metadata.paths)) {
1584
+ for (const mapping of fragment2.metadata.paths) {
1585
+ if (typeof mapping === "object" && mapping !== null && typeof mapping.host === "string" && typeof mapping.sandbox === "string") {
1586
+ mounts.push({ host: mapping.host, sandbox: mapping.sandbox });
1587
+ }
1588
+ }
1589
+ }
1590
+ }
1591
+ return mounts;
1592
+ }
1509
1593
  /**
1510
1594
  * Inspect the full context state for debugging.
1511
1595
  * Returns a JSON-serializable object with context information.
@@ -1816,7 +1900,7 @@ var errorRecoveryGuardrail = {
1816
1900
  }
1817
1901
  return logAndFail(
1818
1902
  "Unknown error",
1819
- `An error occurred: ${errorText.slice(0, 100)}. Let me try a different approach.`
1903
+ `An error occurred: ${errorText}. Let me try a different approach.`
1820
1904
  );
1821
1905
  }
1822
1906
  };
@@ -2642,9 +2726,13 @@ function discoverSkillsInDirectory(directory) {
2642
2726
 
2643
2727
  // packages/context/src/lib/skills/fragments.ts
2644
2728
  function skills(options) {
2729
+ const pathMapping = /* @__PURE__ */ new Map();
2730
+ for (const { host, sandbox } of options.paths) {
2731
+ pathMapping.set(host, sandbox);
2732
+ }
2645
2733
  const skillsMap = /* @__PURE__ */ new Map();
2646
- for (const dir of options.paths) {
2647
- const discovered = discoverSkillsInDirectory(dir);
2734
+ for (const { host } of options.paths) {
2735
+ const discovered = discoverSkillsInDirectory(host);
2648
2736
  for (const skill of discovered) {
2649
2737
  skillsMap.set(skill.name, skill);
2650
2738
  }
@@ -2659,14 +2747,26 @@ function skills(options) {
2659
2747
  (s) => !options.exclude.includes(s.name)
2660
2748
  );
2661
2749
  }
2662
- const skillFragments = filteredSkills.map((skill) => ({
2663
- name: "skill",
2664
- data: {
2665
- name: skill.name,
2666
- path: skill.skillMdPath,
2667
- description: skill.description
2750
+ const skillFragments = filteredSkills.map((skill) => {
2751
+ const originalPath = skill.skillMdPath;
2752
+ let sandboxPath = originalPath;
2753
+ for (const [host, sandbox] of pathMapping) {
2754
+ if (originalPath.startsWith(host)) {
2755
+ const relativePath = originalPath.slice(host.length);
2756
+ sandboxPath = sandbox + relativePath;
2757
+ break;
2758
+ }
2668
2759
  }
2669
- }));
2760
+ return {
2761
+ name: "skill",
2762
+ data: {
2763
+ name: skill.name,
2764
+ path: sandboxPath,
2765
+ description: skill.description
2766
+ },
2767
+ metadata: { originalPath }
2768
+ };
2769
+ });
2670
2770
  return {
2671
2771
  name: "available_skills",
2672
2772
  data: [
@@ -2675,7 +2775,11 @@ function skills(options) {
2675
2775
  data: SKILLS_INSTRUCTIONS
2676
2776
  },
2677
2777
  ...skillFragments
2678
- ]
2778
+ ],
2779
+ metadata: {
2780
+ paths: options.paths
2781
+ // Store original path mappings for getSkillMounts()
2782
+ }
2679
2783
  };
2680
2784
  }
2681
2785
  var SKILLS_INSTRUCTIONS = `When a user's request matches one of the skills listed below, read the skill's SKILL.md file to get detailed instructions before proceeding. Skills provide specialized knowledge and workflows for specific tasks.
@@ -2933,18 +3037,19 @@ var SqliteContextStore = class extends ContextStore {
2933
3037
  // Message Operations (Graph Nodes)
2934
3038
  // ==========================================================================
2935
3039
  async addMessage(message2) {
3040
+ const existingParent = message2.parentId === message2.id ? this.#db.prepare("SELECT parentId FROM messages WHERE id = ?").get(message2.id) : void 0;
3041
+ const parentId = message2.parentId === message2.id ? existingParent?.parentId ?? null : message2.parentId;
2936
3042
  this.#db.prepare(
2937
3043
  `INSERT INTO messages (id, chatId, parentId, name, type, data, createdAt)
2938
3044
  VALUES (?, ?, ?, ?, ?, ?, ?)
2939
3045
  ON CONFLICT(id) DO UPDATE SET
2940
- parentId = excluded.parentId,
2941
3046
  name = excluded.name,
2942
3047
  type = excluded.type,
2943
3048
  data = excluded.data`
2944
3049
  ).run(
2945
3050
  message2.id,
2946
3051
  message2.chatId,
2947
- message2.parentId,
3052
+ parentId,
2948
3053
  message2.name,
2949
3054
  message2.type ?? null,
2950
3055
  JSON.stringify(message2.data),
@@ -3487,13 +3592,9 @@ var Agent = class _Agent {
3487
3592
  writer.write({ type: "finish" });
3488
3593
  return;
3489
3594
  }
3490
- writer.write({
3491
- type: "text-delta",
3492
- id: generateId2(),
3493
- delta: ` ${failureFeedback}`
3494
- });
3595
+ writeText(writer, failureFeedback);
3495
3596
  const selfCorrectionText = accumulatedText + " " + failureFeedback;
3496
- context.set(assistantText(selfCorrectionText));
3597
+ context.set(lastAssistantMessage(selfCorrectionText));
3497
3598
  await context.save();
3498
3599
  currentResult = await this.#createRawStream(
3499
3600
  contextVariables,
@@ -3598,6 +3699,22 @@ var repairToolCall = async ({
3598
3699
  });
3599
3700
  return { ...toolCall, input: JSON.stringify(output) };
3600
3701
  };
3702
+ function writeText(writer, text) {
3703
+ const feedbackPartId = generateId2();
3704
+ writer.write({
3705
+ id: feedbackPartId,
3706
+ type: "text-start"
3707
+ });
3708
+ writer.write({
3709
+ id: feedbackPartId,
3710
+ type: "text-delta",
3711
+ delta: ` ${text}`
3712
+ });
3713
+ writer.write({
3714
+ id: feedbackPartId,
3715
+ type: "text-end"
3716
+ });
3717
+ }
3601
3718
 
3602
3719
  // packages/context/src/lib/render.ts
3603
3720
  function render(tag, ...fragments) {
@@ -3622,6 +3739,7 @@ export {
3622
3739
  DockerfileBuildError,
3623
3740
  DockerfileStrategy,
3624
3741
  InMemoryContextStore,
3742
+ LAZY_ID,
3625
3743
  MarkdownRenderer,
3626
3744
  ModelsRegistry,
3627
3745
  MountPathError,
@@ -3658,7 +3776,9 @@ export {
3658
3776
  isDockerfileOptions,
3659
3777
  isFragment,
3660
3778
  isFragmentObject,
3779
+ isLazyFragment,
3661
3780
  isMessageFragment,
3781
+ lastAssistantMessage,
3662
3782
  loadSkillMetadata,
3663
3783
  message,
3664
3784
  parseFrontmatter,