@deepagents/context 0.11.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.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +618 -153
- package/dist/index.js.map +4 -4
- package/dist/lib/agent.d.ts +7 -6
- package/dist/lib/agent.d.ts.map +1 -1
- package/dist/lib/engine.d.ts +25 -5
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/fragments/domain.d.ts +98 -1
- package/dist/lib/fragments/domain.d.ts.map +1 -1
- package/dist/lib/fragments/user.d.ts +8 -8
- package/dist/lib/fragments/user.d.ts.map +1 -1
- package/dist/lib/fragments.d.ts +46 -6
- package/dist/lib/fragments.d.ts.map +1 -1
- package/dist/lib/guardrails/error-recovery.guardrail.d.ts +3 -0
- package/dist/lib/guardrails/error-recovery.guardrail.d.ts.map +1 -0
- package/dist/lib/render.d.ts +21 -0
- package/dist/lib/render.d.ts.map +1 -0
- package/dist/lib/renderers/abstract.renderer.d.ts +10 -2
- package/dist/lib/renderers/abstract.renderer.d.ts.map +1 -1
- package/dist/lib/sandbox/binary-bridges.d.ts.map +1 -1
- package/dist/lib/skills/fragments.d.ts +7 -3
- package/dist/lib/skills/fragments.d.ts.map +1 -1
- package/dist/lib/skills/index.d.ts +9 -4
- package/dist/lib/skills/index.d.ts.map +1 -1
- package/dist/lib/skills/loader.d.ts.map +1 -1
- package/dist/lib/skills/types.d.ts +24 -2
- package/dist/lib/skills/types.d.ts.map +1 -1
- package/dist/lib/store/sqlite.store.d.ts +4 -2
- package/dist/lib/store/sqlite.store.d.ts.map +1 -1
- package/dist/lib/store/store.d.ts +36 -2
- package/dist/lib/store/store.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -175,12 +175,6 @@ function fragment(name, ...children) {
|
|
|
175
175
|
data: children
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
|
-
function role(content) {
|
|
179
|
-
return {
|
|
180
|
-
name: "role",
|
|
181
|
-
data: content
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
178
|
function user(content) {
|
|
185
179
|
const message2 = typeof content === "string" ? {
|
|
186
180
|
id: generateId(),
|
|
@@ -228,7 +222,7 @@ function message(content) {
|
|
|
228
222
|
} : content;
|
|
229
223
|
return {
|
|
230
224
|
id: message2.id,
|
|
231
|
-
name:
|
|
225
|
+
name: message2.role,
|
|
232
226
|
data: "content",
|
|
233
227
|
type: "message",
|
|
234
228
|
persist: true,
|
|
@@ -250,6 +244,22 @@ function assistantText(content, options) {
|
|
|
250
244
|
parts: [{ type: "text", text: content }]
|
|
251
245
|
});
|
|
252
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
|
+
}
|
|
253
263
|
|
|
254
264
|
// packages/context/src/lib/renderers/abstract.renderer.ts
|
|
255
265
|
import pluralize from "pluralize";
|
|
@@ -277,6 +287,68 @@ var ContextRenderer = class {
|
|
|
277
287
|
}
|
|
278
288
|
return groups;
|
|
279
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Remove null/undefined from fragments and fragment data recursively.
|
|
292
|
+
* This protects renderers from nullish values and ensures they are ignored
|
|
293
|
+
* consistently across all output formats.
|
|
294
|
+
*/
|
|
295
|
+
sanitizeFragments(fragments) {
|
|
296
|
+
const sanitized = [];
|
|
297
|
+
for (const fragment2 of fragments) {
|
|
298
|
+
const cleaned = this.sanitizeFragment(fragment2, /* @__PURE__ */ new WeakSet());
|
|
299
|
+
if (cleaned) {
|
|
300
|
+
sanitized.push(cleaned);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return sanitized;
|
|
304
|
+
}
|
|
305
|
+
sanitizeFragment(fragment2, seen) {
|
|
306
|
+
const data = this.sanitizeData(fragment2.data, seen);
|
|
307
|
+
if (data == null) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
...fragment2,
|
|
312
|
+
data
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
sanitizeData(data, seen) {
|
|
316
|
+
if (data == null) {
|
|
317
|
+
return void 0;
|
|
318
|
+
}
|
|
319
|
+
if (isFragment(data)) {
|
|
320
|
+
return this.sanitizeFragment(data, seen) ?? void 0;
|
|
321
|
+
}
|
|
322
|
+
if (Array.isArray(data)) {
|
|
323
|
+
if (seen.has(data)) {
|
|
324
|
+
return void 0;
|
|
325
|
+
}
|
|
326
|
+
seen.add(data);
|
|
327
|
+
const cleaned = [];
|
|
328
|
+
for (const item of data) {
|
|
329
|
+
const sanitizedItem = this.sanitizeData(item, seen);
|
|
330
|
+
if (sanitizedItem != null) {
|
|
331
|
+
cleaned.push(sanitizedItem);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return cleaned;
|
|
335
|
+
}
|
|
336
|
+
if (isFragmentObject(data)) {
|
|
337
|
+
if (seen.has(data)) {
|
|
338
|
+
return void 0;
|
|
339
|
+
}
|
|
340
|
+
seen.add(data);
|
|
341
|
+
const cleaned = {};
|
|
342
|
+
for (const [key, value] of Object.entries(data)) {
|
|
343
|
+
const sanitizedValue = this.sanitizeData(value, seen);
|
|
344
|
+
if (sanitizedValue != null) {
|
|
345
|
+
cleaned[key] = sanitizedValue;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return cleaned;
|
|
349
|
+
}
|
|
350
|
+
return data;
|
|
351
|
+
}
|
|
280
352
|
/**
|
|
281
353
|
* Template method - dispatches value to appropriate handler.
|
|
282
354
|
*/
|
|
@@ -304,7 +376,8 @@ var ContextRenderer = class {
|
|
|
304
376
|
};
|
|
305
377
|
var XmlRenderer = class extends ContextRenderer {
|
|
306
378
|
render(fragments) {
|
|
307
|
-
|
|
379
|
+
const sanitized = this.sanitizeFragments(fragments);
|
|
380
|
+
return sanitized.map((f) => this.#renderTopLevel(f)).filter(Boolean).join("\n");
|
|
308
381
|
}
|
|
309
382
|
#renderTopLevel(fragment2) {
|
|
310
383
|
if (this.isPrimitive(fragment2.data)) {
|
|
@@ -317,10 +390,13 @@ var XmlRenderer = class extends ContextRenderer {
|
|
|
317
390
|
const child = this.renderFragment(fragment2.data, { depth: 1, path: [] });
|
|
318
391
|
return this.#wrap(fragment2.name, [child]);
|
|
319
392
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
393
|
+
if (isFragmentObject(fragment2.data)) {
|
|
394
|
+
return this.#wrap(
|
|
395
|
+
fragment2.name,
|
|
396
|
+
this.renderEntries(fragment2.data, { depth: 1, path: [] })
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return "";
|
|
324
400
|
}
|
|
325
401
|
#renderArray(name, items, depth) {
|
|
326
402
|
const fragmentItems = items.filter(isFragment);
|
|
@@ -328,9 +404,19 @@ var XmlRenderer = class extends ContextRenderer {
|
|
|
328
404
|
const children = [];
|
|
329
405
|
for (const item of nonFragmentItems) {
|
|
330
406
|
if (item != null) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
407
|
+
if (isFragmentObject(item)) {
|
|
408
|
+
children.push(
|
|
409
|
+
this.#wrapIndented(
|
|
410
|
+
pluralize.singular(name),
|
|
411
|
+
this.renderEntries(item, { depth: depth + 2, path: [] }),
|
|
412
|
+
depth + 1
|
|
413
|
+
)
|
|
414
|
+
);
|
|
415
|
+
} else {
|
|
416
|
+
children.push(
|
|
417
|
+
this.#leaf(pluralize.singular(name), String(item), depth + 1)
|
|
418
|
+
);
|
|
419
|
+
}
|
|
334
420
|
}
|
|
335
421
|
}
|
|
336
422
|
if (this.options.groupFragments && fragmentItems.length > 0) {
|
|
@@ -372,8 +458,14 @@ ${this.#indent(safe, 2)}
|
|
|
372
458
|
if (Array.isArray(data)) {
|
|
373
459
|
return this.#renderArrayIndented(name, data, ctx.depth);
|
|
374
460
|
}
|
|
375
|
-
|
|
376
|
-
|
|
461
|
+
if (isFragmentObject(data)) {
|
|
462
|
+
const children = this.renderEntries(data, {
|
|
463
|
+
...ctx,
|
|
464
|
+
depth: ctx.depth + 1
|
|
465
|
+
});
|
|
466
|
+
return this.#wrapIndented(name, children, ctx.depth);
|
|
467
|
+
}
|
|
468
|
+
return "";
|
|
377
469
|
}
|
|
378
470
|
#renderArrayIndented(name, items, depth) {
|
|
379
471
|
const fragmentItems = items.filter(isFragment);
|
|
@@ -381,9 +473,19 @@ ${this.#indent(safe, 2)}
|
|
|
381
473
|
const children = [];
|
|
382
474
|
for (const item of nonFragmentItems) {
|
|
383
475
|
if (item != null) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
476
|
+
if (isFragmentObject(item)) {
|
|
477
|
+
children.push(
|
|
478
|
+
this.#wrapIndented(
|
|
479
|
+
pluralize.singular(name),
|
|
480
|
+
this.renderEntries(item, { depth: depth + 2, path: [] }),
|
|
481
|
+
depth + 1
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
} else {
|
|
485
|
+
children.push(
|
|
486
|
+
this.#leaf(pluralize.singular(name), String(item), depth + 1)
|
|
487
|
+
);
|
|
488
|
+
}
|
|
387
489
|
}
|
|
388
490
|
}
|
|
389
491
|
if (this.options.groupFragments && fragmentItems.length > 0) {
|
|
@@ -412,7 +514,19 @@ ${this.#indent(safe, 2)}
|
|
|
412
514
|
return "";
|
|
413
515
|
}
|
|
414
516
|
const itemTag = pluralize.singular(key);
|
|
415
|
-
const children = items.filter((item) => item != null).map((item) =>
|
|
517
|
+
const children = items.filter((item) => item != null).map((item) => {
|
|
518
|
+
if (isFragment(item)) {
|
|
519
|
+
return this.renderFragment(item, { ...ctx, depth: ctx.depth + 1 });
|
|
520
|
+
}
|
|
521
|
+
if (isFragmentObject(item)) {
|
|
522
|
+
return this.#wrapIndented(
|
|
523
|
+
itemTag,
|
|
524
|
+
this.renderEntries(item, { ...ctx, depth: ctx.depth + 2 }),
|
|
525
|
+
ctx.depth + 1
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
return this.#leaf(itemTag, String(item), ctx.depth + 1);
|
|
529
|
+
});
|
|
416
530
|
return this.#wrapIndented(key, children, ctx.depth);
|
|
417
531
|
}
|
|
418
532
|
renderObject(key, obj, ctx) {
|
|
@@ -464,7 +578,7 @@ ${pad}</${tag}>`;
|
|
|
464
578
|
};
|
|
465
579
|
var MarkdownRenderer = class extends ContextRenderer {
|
|
466
580
|
render(fragments) {
|
|
467
|
-
return fragments.map((f) => {
|
|
581
|
+
return this.sanitizeFragments(fragments).map((f) => {
|
|
468
582
|
const title = `## ${titlecase(f.name)}`;
|
|
469
583
|
if (this.isPrimitive(f.data)) {
|
|
470
584
|
return `${title}
|
|
@@ -478,8 +592,12 @@ ${this.#renderArray(f.data, 0)}`;
|
|
|
478
592
|
return `${title}
|
|
479
593
|
${this.renderFragment(f.data, { depth: 0, path: [] })}`;
|
|
480
594
|
}
|
|
481
|
-
|
|
595
|
+
if (isFragmentObject(f.data)) {
|
|
596
|
+
return `${title}
|
|
482
597
|
${this.renderEntries(f.data, { depth: 0, path: [] }).join("\n")}`;
|
|
598
|
+
}
|
|
599
|
+
return `${title}
|
|
600
|
+
`;
|
|
483
601
|
}).join("\n\n");
|
|
484
602
|
}
|
|
485
603
|
#renderArray(items, depth) {
|
|
@@ -536,14 +654,17 @@ ${this.renderEntries(f.data, { depth: 0, path: [] }).join("\n")}`;
|
|
|
536
654
|
return [header, child].join("\n");
|
|
537
655
|
}
|
|
538
656
|
if (Array.isArray(data)) {
|
|
539
|
-
const
|
|
540
|
-
return [header, ...
|
|
657
|
+
const children = data.filter((item) => item != null).map((item) => this.#arrayItem(item, ctx.depth + 1));
|
|
658
|
+
return [header, ...children].join("\n");
|
|
541
659
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
660
|
+
if (isFragmentObject(data)) {
|
|
661
|
+
const children = this.renderEntries(data, {
|
|
662
|
+
...ctx,
|
|
663
|
+
depth: ctx.depth + 1
|
|
664
|
+
}).join("\n");
|
|
665
|
+
return [header, children].join("\n");
|
|
666
|
+
}
|
|
667
|
+
return header;
|
|
547
668
|
}
|
|
548
669
|
renderPrimitive(key, value, ctx) {
|
|
549
670
|
return this.#leaf(key, value, ctx.depth);
|
|
@@ -564,22 +685,25 @@ ${this.renderEntries(f.data, { depth: 0, path: [] }).join("\n")}`;
|
|
|
564
685
|
};
|
|
565
686
|
var TomlRenderer = class extends ContextRenderer {
|
|
566
687
|
render(fragments) {
|
|
567
|
-
|
|
688
|
+
const rendered = [];
|
|
689
|
+
for (const f of this.sanitizeFragments(fragments)) {
|
|
568
690
|
if (this.isPrimitive(f.data)) {
|
|
569
|
-
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
691
|
+
rendered.push(`${f.name} = ${this.#formatValue(f.data)}`);
|
|
692
|
+
} else if (Array.isArray(f.data)) {
|
|
693
|
+
rendered.push(this.#renderTopLevelArray(f.name, f.data));
|
|
694
|
+
} else if (isFragment(f.data)) {
|
|
695
|
+
rendered.push(
|
|
696
|
+
[
|
|
697
|
+
`[${f.name}]`,
|
|
698
|
+
this.renderFragment(f.data, { depth: 0, path: [f.name] })
|
|
699
|
+
].join("\n")
|
|
700
|
+
);
|
|
701
|
+
} else if (isFragmentObject(f.data)) {
|
|
702
|
+
const entries = this.#renderObjectEntries(f.data, [f.name]);
|
|
703
|
+
rendered.push([`[${f.name}]`, ...entries].join("\n"));
|
|
579
704
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}).join("\n\n");
|
|
705
|
+
}
|
|
706
|
+
return rendered.join("\n\n");
|
|
583
707
|
}
|
|
584
708
|
#renderTopLevelArray(name, items) {
|
|
585
709
|
const fragmentItems = items.filter(isFragment);
|
|
@@ -614,10 +738,12 @@ var TomlRenderer = class extends ContextRenderer {
|
|
|
614
738
|
}
|
|
615
739
|
return `${key} = ${this.#formatValue(value)}`;
|
|
616
740
|
}
|
|
617
|
-
renderPrimitive(key, value,
|
|
741
|
+
renderPrimitive(key, value, ctx) {
|
|
742
|
+
void ctx;
|
|
618
743
|
return `${key} = ${this.#formatValue(value)}`;
|
|
619
744
|
}
|
|
620
|
-
renderArray(key, items,
|
|
745
|
+
renderArray(key, items, ctx) {
|
|
746
|
+
void ctx;
|
|
621
747
|
const values = items.filter((item) => item != null).map((item) => this.#formatValue(item));
|
|
622
748
|
return `${key} = [${values.join(", ")}]`;
|
|
623
749
|
}
|
|
@@ -671,8 +797,11 @@ var TomlRenderer = class extends ContextRenderer {
|
|
|
671
797
|
const values = nonFragmentItems.map((item) => this.#formatValue(item));
|
|
672
798
|
return `${name} = [${values.join(", ")}]`;
|
|
673
799
|
}
|
|
674
|
-
|
|
675
|
-
|
|
800
|
+
if (isFragmentObject(data)) {
|
|
801
|
+
const entries = this.#renderObjectEntries(data, newPath);
|
|
802
|
+
return ["", `[${newPath.join(".")}]`, ...entries].join("\n");
|
|
803
|
+
}
|
|
804
|
+
return "";
|
|
676
805
|
}
|
|
677
806
|
#escape(value) {
|
|
678
807
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
@@ -692,7 +821,8 @@ var TomlRenderer = class extends ContextRenderer {
|
|
|
692
821
|
};
|
|
693
822
|
var ToonRenderer = class extends ContextRenderer {
|
|
694
823
|
render(fragments) {
|
|
695
|
-
|
|
824
|
+
const sanitized = this.sanitizeFragments(fragments);
|
|
825
|
+
return sanitized.map((f) => this.#renderTopLevel(f)).filter(Boolean).join("\n");
|
|
696
826
|
}
|
|
697
827
|
#renderTopLevel(fragment2) {
|
|
698
828
|
const { name, data } = fragment2;
|
|
@@ -741,18 +871,18 @@ ${entries}`;
|
|
|
741
871
|
if (items.length === 0) return false;
|
|
742
872
|
const objects = items.filter(isFragmentObject);
|
|
743
873
|
if (objects.length !== items.length) return false;
|
|
744
|
-
|
|
874
|
+
let intersection = new Set(Object.keys(objects[0]));
|
|
745
875
|
for (const obj of objects) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
}
|
|
876
|
+
const keys = new Set(Object.keys(obj));
|
|
877
|
+
intersection = new Set([...intersection].filter((k) => keys.has(k)));
|
|
749
878
|
for (const value of Object.values(obj)) {
|
|
750
|
-
if (
|
|
879
|
+
if (value == null) continue;
|
|
880
|
+
if (!this.#isPrimitiveValue(value)) {
|
|
751
881
|
return false;
|
|
752
882
|
}
|
|
753
883
|
}
|
|
754
884
|
}
|
|
755
|
-
return
|
|
885
|
+
return intersection.size > 0;
|
|
756
886
|
}
|
|
757
887
|
#renderPrimitiveArray(key, items, depth) {
|
|
758
888
|
const values = items.map((item) => this.#formatValue(item)).join(",");
|
|
@@ -762,10 +892,16 @@ ${entries}`;
|
|
|
762
892
|
if (items.length === 0) {
|
|
763
893
|
return `${this.#pad(depth)}${key}[0]:`;
|
|
764
894
|
}
|
|
765
|
-
const fields =
|
|
895
|
+
const fields = Array.from(
|
|
896
|
+
new Set(items.flatMap((obj) => Object.keys(obj)))
|
|
897
|
+
);
|
|
766
898
|
const header = `${this.#pad(depth)}${key}[${items.length}]{${fields.join(",")}}:`;
|
|
767
899
|
const rows = items.map((obj) => {
|
|
768
|
-
const values = fields.map((f) =>
|
|
900
|
+
const values = fields.map((f) => {
|
|
901
|
+
const value = obj[f];
|
|
902
|
+
if (value == null) return "";
|
|
903
|
+
return this.#formatValue(value);
|
|
904
|
+
});
|
|
769
905
|
return `${this.#pad(depth + 1)}${values.join(",")}`;
|
|
770
906
|
});
|
|
771
907
|
return [header, ...rows].join("\n");
|
|
@@ -913,6 +1049,7 @@ var ContextEngine = class {
|
|
|
913
1049
|
#pendingMessages = [];
|
|
914
1050
|
#store;
|
|
915
1051
|
#chatId;
|
|
1052
|
+
#userId;
|
|
916
1053
|
#branchName;
|
|
917
1054
|
#branch = null;
|
|
918
1055
|
#chatData = null;
|
|
@@ -921,9 +1058,13 @@ var ContextEngine = class {
|
|
|
921
1058
|
if (!options.chatId) {
|
|
922
1059
|
throw new Error("chatId is required");
|
|
923
1060
|
}
|
|
1061
|
+
if (!options.userId) {
|
|
1062
|
+
throw new Error("userId is required");
|
|
1063
|
+
}
|
|
924
1064
|
this.#store = options.store;
|
|
925
1065
|
this.#chatId = options.chatId;
|
|
926
|
-
this.#
|
|
1066
|
+
this.#userId = options.userId;
|
|
1067
|
+
this.#branchName = "main";
|
|
927
1068
|
}
|
|
928
1069
|
/**
|
|
929
1070
|
* Initialize the chat and branch if they don't exist.
|
|
@@ -932,24 +1073,11 @@ var ContextEngine = class {
|
|
|
932
1073
|
if (this.#initialized) {
|
|
933
1074
|
return;
|
|
934
1075
|
}
|
|
935
|
-
this.#chatData = await this.#store.upsertChat({
|
|
936
|
-
|
|
937
|
-
this.#
|
|
938
|
-
|
|
939
|
-
);
|
|
940
|
-
if (existingBranch) {
|
|
941
|
-
this.#branch = existingBranch;
|
|
942
|
-
} else {
|
|
943
|
-
this.#branch = {
|
|
944
|
-
id: crypto.randomUUID(),
|
|
945
|
-
chatId: this.#chatId,
|
|
946
|
-
name: this.#branchName,
|
|
947
|
-
headMessageId: null,
|
|
948
|
-
isActive: true,
|
|
949
|
-
createdAt: Date.now()
|
|
950
|
-
};
|
|
951
|
-
await this.#store.createBranch(this.#branch);
|
|
952
|
-
}
|
|
1076
|
+
this.#chatData = await this.#store.upsertChat({
|
|
1077
|
+
id: this.#chatId,
|
|
1078
|
+
userId: this.#userId
|
|
1079
|
+
});
|
|
1080
|
+
this.#branch = await this.#store.getActiveBranch(this.#chatId);
|
|
953
1081
|
this.#initialized = true;
|
|
954
1082
|
}
|
|
955
1083
|
/**
|
|
@@ -1009,6 +1137,7 @@ var ContextEngine = class {
|
|
|
1009
1137
|
}
|
|
1010
1138
|
return {
|
|
1011
1139
|
id: this.#chatData.id,
|
|
1140
|
+
userId: this.#chatData.userId,
|
|
1012
1141
|
createdAt: this.#chatData.createdAt,
|
|
1013
1142
|
updatedAt: this.#chatData.updatedAt,
|
|
1014
1143
|
title: this.#chatData.title,
|
|
@@ -1051,7 +1180,7 @@ var ContextEngine = class {
|
|
|
1051
1180
|
*
|
|
1052
1181
|
* @example
|
|
1053
1182
|
* ```ts
|
|
1054
|
-
* const context = new ContextEngine({ store, chatId: 'chat-1' })
|
|
1183
|
+
* const context = new ContextEngine({ store, chatId: 'chat-1', userId: 'user-1' })
|
|
1055
1184
|
* .set(role('You are helpful'), user('Hello'));
|
|
1056
1185
|
*
|
|
1057
1186
|
* const { systemPrompt, messages } = await context.resolve();
|
|
@@ -1095,6 +1224,12 @@ var ContextEngine = class {
|
|
|
1095
1224
|
if (this.#pendingMessages.length === 0) {
|
|
1096
1225
|
return;
|
|
1097
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
|
+
}
|
|
1098
1233
|
let parentId = this.#branch.headMessageId;
|
|
1099
1234
|
const now = Date.now();
|
|
1100
1235
|
for (const fragment2 of this.#pendingMessages) {
|
|
@@ -1114,6 +1249,39 @@ var ContextEngine = class {
|
|
|
1114
1249
|
this.#branch.headMessageId = parentId;
|
|
1115
1250
|
this.#pendingMessages = [];
|
|
1116
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
|
+
}
|
|
1117
1285
|
/**
|
|
1118
1286
|
* Estimate token count and cost for the full context.
|
|
1119
1287
|
*
|
|
@@ -1393,9 +1561,38 @@ var ContextEngine = class {
|
|
|
1393
1561
|
consolidate() {
|
|
1394
1562
|
return void 0;
|
|
1395
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
|
+
}
|
|
1396
1593
|
/**
|
|
1397
1594
|
* Inspect the full context state for debugging.
|
|
1398
|
-
* Returns a
|
|
1595
|
+
* Returns a JSON-serializable object with context information.
|
|
1399
1596
|
*
|
|
1400
1597
|
* @param options - Inspection options (modelId and renderer required)
|
|
1401
1598
|
* @returns Complete inspection data including estimates, rendered output, fragments, and graph
|
|
@@ -1547,6 +1744,33 @@ function glossary(entries) {
|
|
|
1547
1744
|
}))
|
|
1548
1745
|
};
|
|
1549
1746
|
}
|
|
1747
|
+
function role(content) {
|
|
1748
|
+
return {
|
|
1749
|
+
name: "role",
|
|
1750
|
+
data: content
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
function principle(input) {
|
|
1754
|
+
return {
|
|
1755
|
+
name: "principle",
|
|
1756
|
+
data: {
|
|
1757
|
+
title: input.title,
|
|
1758
|
+
description: input.description,
|
|
1759
|
+
...input.policies?.length && { policies: input.policies }
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
function policy(input) {
|
|
1764
|
+
return {
|
|
1765
|
+
name: "policy",
|
|
1766
|
+
data: {
|
|
1767
|
+
rule: input.rule,
|
|
1768
|
+
...input.before && { before: input.before },
|
|
1769
|
+
...input.reason && { reason: input.reason },
|
|
1770
|
+
...input.policies?.length && { policies: input.policies }
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1550
1774
|
|
|
1551
1775
|
// packages/context/src/lib/fragments/user.ts
|
|
1552
1776
|
function identity(input) {
|
|
@@ -1563,7 +1787,8 @@ function persona(input) {
|
|
|
1563
1787
|
name: "persona",
|
|
1564
1788
|
data: {
|
|
1565
1789
|
name: input.name,
|
|
1566
|
-
role: input.role,
|
|
1790
|
+
...input.role && { role: input.role },
|
|
1791
|
+
...input.objective && { objective: input.objective },
|
|
1567
1792
|
...input.tone && { tone: input.tone }
|
|
1568
1793
|
}
|
|
1569
1794
|
};
|
|
@@ -1612,11 +1837,79 @@ function runGuardrailChain(part, guardrails, context) {
|
|
|
1612
1837
|
return pass(currentPart);
|
|
1613
1838
|
}
|
|
1614
1839
|
|
|
1840
|
+
// packages/context/src/lib/guardrails/error-recovery.guardrail.ts
|
|
1841
|
+
import chalk from "chalk";
|
|
1842
|
+
var errorRecoveryGuardrail = {
|
|
1843
|
+
id: "error-recovery",
|
|
1844
|
+
name: "API Error Recovery",
|
|
1845
|
+
handle: (part, context) => {
|
|
1846
|
+
if (part.type !== "error") {
|
|
1847
|
+
return pass(part);
|
|
1848
|
+
}
|
|
1849
|
+
const errorText = part.errorText || "";
|
|
1850
|
+
const prefix = chalk.bold.magenta("[ErrorRecovery]");
|
|
1851
|
+
console.log(
|
|
1852
|
+
`${prefix} ${chalk.red("Caught error:")} ${chalk.dim(errorText.slice(0, 150))}`
|
|
1853
|
+
);
|
|
1854
|
+
const logAndFail = (pattern, feedback) => {
|
|
1855
|
+
console.log(
|
|
1856
|
+
`${prefix} ${chalk.yellow("Pattern:")} ${chalk.cyan(pattern)}`
|
|
1857
|
+
);
|
|
1858
|
+
console.log(
|
|
1859
|
+
`${prefix} ${chalk.green("Feedback:")} ${chalk.dim(feedback.slice(0, 80))}...`
|
|
1860
|
+
);
|
|
1861
|
+
return fail(feedback);
|
|
1862
|
+
};
|
|
1863
|
+
if (errorText.includes("Tool choice is none")) {
|
|
1864
|
+
if (context.availableTools.length > 0) {
|
|
1865
|
+
return logAndFail(
|
|
1866
|
+
"Tool choice is none",
|
|
1867
|
+
`I tried to call a tool that doesn't exist. Available tools: ${context.availableTools.join(", ")}. Let me use one of these instead.`
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
return logAndFail(
|
|
1871
|
+
"Tool choice is none (no tools)",
|
|
1872
|
+
"I tried to call a tool, but no tools are available. Let me respond with plain text instead."
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1875
|
+
if (errorText.includes("not in request.tools") || errorText.includes("tool") && errorText.includes("not found")) {
|
|
1876
|
+
const toolMatch = errorText.match(/tool '([^']+)'/);
|
|
1877
|
+
const toolName = toolMatch ? toolMatch[1] : "unknown";
|
|
1878
|
+
if (context.availableTools.length > 0) {
|
|
1879
|
+
return logAndFail(
|
|
1880
|
+
`Unregistered tool: ${toolName}`,
|
|
1881
|
+
`I tried to call "${toolName}" but it doesn't exist. Available tools: ${context.availableTools.join(", ")}. Let me use one of these instead.`
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
return logAndFail(
|
|
1885
|
+
`Unregistered tool: ${toolName} (no tools)`,
|
|
1886
|
+
`I tried to call "${toolName}" but no tools are available. Let me respond with plain text instead.`
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
if (errorText.includes("Failed to parse tool call arguments") || errorText.includes("parse tool call") || errorText.includes("invalid JSON")) {
|
|
1890
|
+
return logAndFail(
|
|
1891
|
+
"Malformed JSON arguments",
|
|
1892
|
+
"I generated malformed JSON for the tool arguments. Let me format my tool call properly with valid JSON."
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
if (errorText.includes("Parsing failed")) {
|
|
1896
|
+
return logAndFail(
|
|
1897
|
+
"Parsing failed",
|
|
1898
|
+
"My response format was invalid. Let me try again with a properly formatted response."
|
|
1899
|
+
);
|
|
1900
|
+
}
|
|
1901
|
+
return logAndFail(
|
|
1902
|
+
"Unknown error",
|
|
1903
|
+
`An error occurred: ${errorText}. Let me try a different approach.`
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
|
|
1615
1908
|
// packages/context/src/lib/sandbox/binary-bridges.ts
|
|
1909
|
+
import { existsSync } from "fs";
|
|
1616
1910
|
import { defineCommand } from "just-bash";
|
|
1617
1911
|
import spawn from "nano-spawn";
|
|
1618
1912
|
import * as path from "path";
|
|
1619
|
-
import { existsSync } from "fs";
|
|
1620
1913
|
function createBinaryBridges(...binaries) {
|
|
1621
1914
|
return binaries.map((input) => {
|
|
1622
1915
|
const config = typeof input === "string" ? { name: input } : input;
|
|
@@ -1662,6 +1955,17 @@ function createBinaryBridges(...binaries) {
|
|
|
1662
1955
|
exitCode: 0
|
|
1663
1956
|
};
|
|
1664
1957
|
} catch (error) {
|
|
1958
|
+
if (error && typeof error === "object") {
|
|
1959
|
+
const err = error;
|
|
1960
|
+
const cause = err.cause;
|
|
1961
|
+
if (cause?.code === "ENOENT") {
|
|
1962
|
+
return {
|
|
1963
|
+
stdout: "",
|
|
1964
|
+
stderr: `${name}: ${binaryPath} not found`,
|
|
1965
|
+
exitCode: 127
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1665
1969
|
if (error && typeof error === "object" && "exitCode" in error) {
|
|
1666
1970
|
const subprocessError = error;
|
|
1667
1971
|
return {
|
|
@@ -2379,7 +2683,9 @@ function parseFrontmatter(content) {
|
|
|
2379
2683
|
throw new Error('Invalid SKILL.md: frontmatter must have a "name" field');
|
|
2380
2684
|
}
|
|
2381
2685
|
if (!frontmatter.description || typeof frontmatter.description !== "string") {
|
|
2382
|
-
throw new Error(
|
|
2686
|
+
throw new Error(
|
|
2687
|
+
'Invalid SKILL.md: frontmatter must have a "description" field'
|
|
2688
|
+
);
|
|
2383
2689
|
}
|
|
2384
2690
|
return {
|
|
2385
2691
|
frontmatter,
|
|
@@ -2420,9 +2726,13 @@ function discoverSkillsInDirectory(directory) {
|
|
|
2420
2726
|
|
|
2421
2727
|
// packages/context/src/lib/skills/fragments.ts
|
|
2422
2728
|
function skills(options) {
|
|
2729
|
+
const pathMapping = /* @__PURE__ */ new Map();
|
|
2730
|
+
for (const { host, sandbox } of options.paths) {
|
|
2731
|
+
pathMapping.set(host, sandbox);
|
|
2732
|
+
}
|
|
2423
2733
|
const skillsMap = /* @__PURE__ */ new Map();
|
|
2424
|
-
for (const
|
|
2425
|
-
const discovered = discoverSkillsInDirectory(
|
|
2734
|
+
for (const { host } of options.paths) {
|
|
2735
|
+
const discovered = discoverSkillsInDirectory(host);
|
|
2426
2736
|
for (const skill of discovered) {
|
|
2427
2737
|
skillsMap.set(skill.name, skill);
|
|
2428
2738
|
}
|
|
@@ -2437,14 +2747,26 @@ function skills(options) {
|
|
|
2437
2747
|
(s) => !options.exclude.includes(s.name)
|
|
2438
2748
|
);
|
|
2439
2749
|
}
|
|
2440
|
-
const skillFragments = filteredSkills.map((skill) =>
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
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
|
+
}
|
|
2446
2759
|
}
|
|
2447
|
-
|
|
2760
|
+
return {
|
|
2761
|
+
name: "skill",
|
|
2762
|
+
data: {
|
|
2763
|
+
name: skill.name,
|
|
2764
|
+
path: sandboxPath,
|
|
2765
|
+
description: skill.description
|
|
2766
|
+
},
|
|
2767
|
+
metadata: { originalPath }
|
|
2768
|
+
};
|
|
2769
|
+
});
|
|
2448
2770
|
return {
|
|
2449
2771
|
name: "available_skills",
|
|
2450
2772
|
data: [
|
|
@@ -2453,7 +2775,11 @@ function skills(options) {
|
|
|
2453
2775
|
data: SKILLS_INSTRUCTIONS
|
|
2454
2776
|
},
|
|
2455
2777
|
...skillFragments
|
|
2456
|
-
]
|
|
2778
|
+
],
|
|
2779
|
+
metadata: {
|
|
2780
|
+
paths: options.paths
|
|
2781
|
+
// Store original path mappings for getSkillMounts()
|
|
2782
|
+
}
|
|
2457
2783
|
};
|
|
2458
2784
|
}
|
|
2459
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.
|
|
@@ -2472,6 +2798,7 @@ var STORE_DDL = `
|
|
|
2472
2798
|
-- createdAt/updatedAt: DEFAULT for insert, inline SET for updates
|
|
2473
2799
|
CREATE TABLE IF NOT EXISTS chats (
|
|
2474
2800
|
id TEXT PRIMARY KEY,
|
|
2801
|
+
userId TEXT NOT NULL,
|
|
2475
2802
|
title TEXT,
|
|
2476
2803
|
metadata TEXT,
|
|
2477
2804
|
createdAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),
|
|
@@ -2479,6 +2806,7 @@ CREATE TABLE IF NOT EXISTS chats (
|
|
|
2479
2806
|
);
|
|
2480
2807
|
|
|
2481
2808
|
CREATE INDEX IF NOT EXISTS idx_chats_updatedAt ON chats(updatedAt);
|
|
2809
|
+
CREATE INDEX IF NOT EXISTS idx_chats_userId ON chats(userId);
|
|
2482
2810
|
|
|
2483
2811
|
-- Messages table (nodes in the DAG)
|
|
2484
2812
|
CREATE TABLE IF NOT EXISTS messages (
|
|
@@ -2544,37 +2872,67 @@ var SqliteContextStore = class extends ContextStore {
|
|
|
2544
2872
|
this.#db.exec("PRAGMA foreign_keys = ON");
|
|
2545
2873
|
this.#db.exec(STORE_DDL);
|
|
2546
2874
|
}
|
|
2875
|
+
/**
|
|
2876
|
+
* Execute a function within a transaction.
|
|
2877
|
+
* Automatically commits on success or rolls back on error.
|
|
2878
|
+
*/
|
|
2879
|
+
#useTransaction(fn) {
|
|
2880
|
+
this.#db.exec("BEGIN TRANSACTION");
|
|
2881
|
+
try {
|
|
2882
|
+
const result = fn();
|
|
2883
|
+
this.#db.exec("COMMIT");
|
|
2884
|
+
return result;
|
|
2885
|
+
} catch (error) {
|
|
2886
|
+
this.#db.exec("ROLLBACK");
|
|
2887
|
+
throw error;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2547
2890
|
// ==========================================================================
|
|
2548
2891
|
// Chat Operations
|
|
2549
2892
|
// ==========================================================================
|
|
2550
2893
|
async createChat(chat) {
|
|
2551
|
-
this.#
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2894
|
+
this.#useTransaction(() => {
|
|
2895
|
+
this.#db.prepare(
|
|
2896
|
+
`INSERT INTO chats (id, userId, title, metadata)
|
|
2897
|
+
VALUES (?, ?, ?, ?)`
|
|
2898
|
+
).run(
|
|
2899
|
+
chat.id,
|
|
2900
|
+
chat.userId,
|
|
2901
|
+
chat.title ?? null,
|
|
2902
|
+
chat.metadata ? JSON.stringify(chat.metadata) : null
|
|
2903
|
+
);
|
|
2904
|
+
this.#db.prepare(
|
|
2905
|
+
`INSERT INTO branches (id, chatId, name, headMessageId, isActive, createdAt)
|
|
2906
|
+
VALUES (?, ?, 'main', NULL, 1, ?)`
|
|
2907
|
+
).run(crypto.randomUUID(), chat.id, Date.now());
|
|
2908
|
+
});
|
|
2559
2909
|
}
|
|
2560
2910
|
async upsertChat(chat) {
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2911
|
+
return this.#useTransaction(() => {
|
|
2912
|
+
const row = this.#db.prepare(
|
|
2913
|
+
`INSERT INTO chats (id, userId, title, metadata)
|
|
2914
|
+
VALUES (?, ?, ?, ?)
|
|
2915
|
+
ON CONFLICT(id) DO UPDATE SET id = excluded.id
|
|
2916
|
+
RETURNING *`
|
|
2917
|
+
).get(
|
|
2918
|
+
chat.id,
|
|
2919
|
+
chat.userId,
|
|
2920
|
+
chat.title ?? null,
|
|
2921
|
+
chat.metadata ? JSON.stringify(chat.metadata) : null
|
|
2922
|
+
);
|
|
2923
|
+
this.#db.prepare(
|
|
2924
|
+
`INSERT OR IGNORE INTO branches (id, chatId, name, headMessageId, isActive, createdAt)
|
|
2925
|
+
VALUES (?, ?, 'main', NULL, 1, ?)`
|
|
2926
|
+
).run(crypto.randomUUID(), chat.id, Date.now());
|
|
2927
|
+
return {
|
|
2928
|
+
id: row.id,
|
|
2929
|
+
userId: row.userId,
|
|
2930
|
+
title: row.title ?? void 0,
|
|
2931
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
|
|
2932
|
+
createdAt: row.createdAt,
|
|
2933
|
+
updatedAt: row.updatedAt
|
|
2934
|
+
};
|
|
2935
|
+
});
|
|
2578
2936
|
}
|
|
2579
2937
|
async getChat(chatId) {
|
|
2580
2938
|
const row = this.#db.prepare("SELECT * FROM chats WHERE id = ?").get(chatId);
|
|
@@ -2583,6 +2941,7 @@ var SqliteContextStore = class extends ContextStore {
|
|
|
2583
2941
|
}
|
|
2584
2942
|
return {
|
|
2585
2943
|
id: row.id,
|
|
2944
|
+
userId: row.userId,
|
|
2586
2945
|
title: row.title ?? void 0,
|
|
2587
2946
|
metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
|
|
2588
2947
|
createdAt: row.createdAt,
|
|
@@ -2606,16 +2965,33 @@ var SqliteContextStore = class extends ContextStore {
|
|
|
2606
2965
|
).get(...params);
|
|
2607
2966
|
return {
|
|
2608
2967
|
id: row.id,
|
|
2968
|
+
userId: row.userId,
|
|
2609
2969
|
title: row.title ?? void 0,
|
|
2610
2970
|
metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
|
|
2611
2971
|
createdAt: row.createdAt,
|
|
2612
2972
|
updatedAt: row.updatedAt
|
|
2613
2973
|
};
|
|
2614
2974
|
}
|
|
2615
|
-
async listChats() {
|
|
2975
|
+
async listChats(options) {
|
|
2976
|
+
const params = [];
|
|
2977
|
+
let whereClause = "";
|
|
2978
|
+
let limitClause = "";
|
|
2979
|
+
if (options?.userId) {
|
|
2980
|
+
whereClause = "WHERE c.userId = ?";
|
|
2981
|
+
params.push(options.userId);
|
|
2982
|
+
}
|
|
2983
|
+
if (options?.limit !== void 0) {
|
|
2984
|
+
limitClause = " LIMIT ?";
|
|
2985
|
+
params.push(options.limit);
|
|
2986
|
+
if (options.offset !== void 0) {
|
|
2987
|
+
limitClause += " OFFSET ?";
|
|
2988
|
+
params.push(options.offset);
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2616
2991
|
const rows = this.#db.prepare(
|
|
2617
2992
|
`SELECT
|
|
2618
2993
|
c.id,
|
|
2994
|
+
c.userId,
|
|
2619
2995
|
c.title,
|
|
2620
2996
|
c.createdAt,
|
|
2621
2997
|
c.updatedAt,
|
|
@@ -2624,11 +3000,13 @@ var SqliteContextStore = class extends ContextStore {
|
|
|
2624
3000
|
FROM chats c
|
|
2625
3001
|
LEFT JOIN messages m ON m.chatId = c.id
|
|
2626
3002
|
LEFT JOIN branches b ON b.chatId = c.id
|
|
3003
|
+
${whereClause}
|
|
2627
3004
|
GROUP BY c.id
|
|
2628
|
-
ORDER BY c.updatedAt DESC`
|
|
2629
|
-
).all();
|
|
3005
|
+
ORDER BY c.updatedAt DESC${limitClause}`
|
|
3006
|
+
).all(...params);
|
|
2630
3007
|
return rows.map((row) => ({
|
|
2631
3008
|
id: row.id,
|
|
3009
|
+
userId: row.userId,
|
|
2632
3010
|
title: row.title ?? void 0,
|
|
2633
3011
|
messageCount: row.messageCount,
|
|
2634
3012
|
branchCount: row.branchCount,
|
|
@@ -2636,22 +3014,42 @@ var SqliteContextStore = class extends ContextStore {
|
|
|
2636
3014
|
updatedAt: row.updatedAt
|
|
2637
3015
|
}));
|
|
2638
3016
|
}
|
|
3017
|
+
async deleteChat(chatId, options) {
|
|
3018
|
+
return this.#useTransaction(() => {
|
|
3019
|
+
const messageIds = this.#db.prepare("SELECT id FROM messages WHERE chatId = ?").all(chatId);
|
|
3020
|
+
let sql = "DELETE FROM chats WHERE id = ?";
|
|
3021
|
+
const params = [chatId];
|
|
3022
|
+
if (options?.userId !== void 0) {
|
|
3023
|
+
sql += " AND userId = ?";
|
|
3024
|
+
params.push(options.userId);
|
|
3025
|
+
}
|
|
3026
|
+
const result = this.#db.prepare(sql).run(...params);
|
|
3027
|
+
if (result.changes > 0 && messageIds.length > 0) {
|
|
3028
|
+
const placeholders = messageIds.map(() => "?").join(", ");
|
|
3029
|
+
this.#db.prepare(
|
|
3030
|
+
`DELETE FROM messages_fts WHERE messageId IN (${placeholders})`
|
|
3031
|
+
).run(...messageIds.map((m) => m.id));
|
|
3032
|
+
}
|
|
3033
|
+
return result.changes > 0;
|
|
3034
|
+
});
|
|
3035
|
+
}
|
|
2639
3036
|
// ==========================================================================
|
|
2640
3037
|
// Message Operations (Graph Nodes)
|
|
2641
3038
|
// ==========================================================================
|
|
2642
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;
|
|
2643
3042
|
this.#db.prepare(
|
|
2644
3043
|
`INSERT INTO messages (id, chatId, parentId, name, type, data, createdAt)
|
|
2645
3044
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2646
3045
|
ON CONFLICT(id) DO UPDATE SET
|
|
2647
|
-
parentId = excluded.parentId,
|
|
2648
3046
|
name = excluded.name,
|
|
2649
3047
|
type = excluded.type,
|
|
2650
3048
|
data = excluded.data`
|
|
2651
3049
|
).run(
|
|
2652
3050
|
message2.id,
|
|
2653
3051
|
message2.chatId,
|
|
2654
|
-
|
|
3052
|
+
parentId,
|
|
2655
3053
|
message2.name,
|
|
2656
3054
|
message2.type ?? null,
|
|
2657
3055
|
JSON.stringify(message2.data),
|
|
@@ -2706,6 +3104,17 @@ var SqliteContextStore = class extends ContextStore {
|
|
|
2706
3104
|
).get(messageId);
|
|
2707
3105
|
return row.hasChildren === 1;
|
|
2708
3106
|
}
|
|
3107
|
+
async getMessages(chatId) {
|
|
3108
|
+
const chat = await this.getChat(chatId);
|
|
3109
|
+
if (!chat) {
|
|
3110
|
+
throw new Error(`Chat "${chatId}" not found`);
|
|
3111
|
+
}
|
|
3112
|
+
const activeBranch = await this.getActiveBranch(chatId);
|
|
3113
|
+
if (!activeBranch?.headMessageId) {
|
|
3114
|
+
return [];
|
|
3115
|
+
}
|
|
3116
|
+
return this.getMessageChain(activeBranch.headMessageId);
|
|
3117
|
+
}
|
|
2709
3118
|
// ==========================================================================
|
|
2710
3119
|
// Branch Operations
|
|
2711
3120
|
// ==========================================================================
|
|
@@ -3003,7 +3412,9 @@ function visualizeGraph(data) {
|
|
|
3003
3412
|
}
|
|
3004
3413
|
|
|
3005
3414
|
// packages/context/src/lib/agent.ts
|
|
3415
|
+
import { groq } from "@ai-sdk/groq";
|
|
3006
3416
|
import {
|
|
3417
|
+
NoSuchToolError,
|
|
3007
3418
|
Output,
|
|
3008
3419
|
convertToModelMessages,
|
|
3009
3420
|
createUIMessageStream,
|
|
@@ -3013,7 +3424,7 @@ import {
|
|
|
3013
3424
|
stepCountIs,
|
|
3014
3425
|
streamText
|
|
3015
3426
|
} from "ai";
|
|
3016
|
-
import
|
|
3427
|
+
import chalk2 from "chalk";
|
|
3017
3428
|
import "zod";
|
|
3018
3429
|
import "@deepagents/agent";
|
|
3019
3430
|
var Agent = class _Agent {
|
|
@@ -3040,16 +3451,17 @@ var Agent = class _Agent {
|
|
|
3040
3451
|
providerOptions: this.#options.providerOptions,
|
|
3041
3452
|
model: this.#options.model,
|
|
3042
3453
|
system: systemPrompt,
|
|
3043
|
-
messages: convertToModelMessages(messages),
|
|
3454
|
+
messages: await convertToModelMessages(messages),
|
|
3044
3455
|
stopWhen: stepCountIs(25),
|
|
3045
3456
|
tools: this.#options.tools,
|
|
3046
3457
|
experimental_context: contextVariables,
|
|
3458
|
+
experimental_repairToolCall: repairToolCall,
|
|
3047
3459
|
toolChoice: this.#options.toolChoice,
|
|
3048
3460
|
onStepFinish: (step) => {
|
|
3049
3461
|
const toolCall = step.toolCalls.at(-1);
|
|
3050
3462
|
if (toolCall) {
|
|
3051
3463
|
console.log(
|
|
3052
|
-
`Debug: ${
|
|
3464
|
+
`Debug: ${chalk2.yellow("ToolCalled")}: ${toolCall.toolName}(${JSON.stringify(toolCall.input)})`
|
|
3053
3465
|
);
|
|
3054
3466
|
}
|
|
3055
3467
|
}
|
|
@@ -3098,8 +3510,9 @@ var Agent = class _Agent {
|
|
|
3098
3510
|
providerOptions: this.#options.providerOptions,
|
|
3099
3511
|
model: this.#options.model,
|
|
3100
3512
|
system: systemPrompt,
|
|
3101
|
-
messages: convertToModelMessages(messages),
|
|
3102
|
-
|
|
3513
|
+
messages: await convertToModelMessages(messages),
|
|
3514
|
+
experimental_repairToolCall: repairToolCall,
|
|
3515
|
+
stopWhen: stepCountIs(50),
|
|
3103
3516
|
experimental_transform: config?.transform ?? smoothStream(),
|
|
3104
3517
|
tools: this.#options.tools,
|
|
3105
3518
|
experimental_context: contextVariables,
|
|
@@ -3108,7 +3521,7 @@ var Agent = class _Agent {
|
|
|
3108
3521
|
const toolCall = step.toolCalls.at(-1);
|
|
3109
3522
|
if (toolCall) {
|
|
3110
3523
|
console.log(
|
|
3111
|
-
`Debug: (${runId}) ${
|
|
3524
|
+
`Debug: (${runId}) ${chalk2.bold.yellow("ToolCalled")}: ${toolCall.toolName}(${JSON.stringify(toolCall.input)})`
|
|
3112
3525
|
);
|
|
3113
3526
|
}
|
|
3114
3527
|
}
|
|
@@ -3155,7 +3568,7 @@ var Agent = class _Agent {
|
|
|
3155
3568
|
guardrailFailed = true;
|
|
3156
3569
|
failureFeedback = checkResult.feedback;
|
|
3157
3570
|
console.log(
|
|
3158
|
-
|
|
3571
|
+
chalk2.yellow(
|
|
3159
3572
|
`[${this.#options.name}] Guardrail triggered (attempt ${attempt}/${maxRetries}): ${failureFeedback.slice(0, 50)}...`
|
|
3160
3573
|
)
|
|
3161
3574
|
);
|
|
@@ -3172,20 +3585,16 @@ var Agent = class _Agent {
|
|
|
3172
3585
|
}
|
|
3173
3586
|
if (attempt >= maxRetries) {
|
|
3174
3587
|
console.error(
|
|
3175
|
-
|
|
3588
|
+
chalk2.red(
|
|
3176
3589
|
`[${this.#options.name}] Guardrail retry limit (${maxRetries}) exceeded.`
|
|
3177
3590
|
)
|
|
3178
3591
|
);
|
|
3179
3592
|
writer.write({ type: "finish" });
|
|
3180
3593
|
return;
|
|
3181
3594
|
}
|
|
3182
|
-
writer
|
|
3183
|
-
type: "text-delta",
|
|
3184
|
-
id: generateId2(),
|
|
3185
|
-
delta: ` ${failureFeedback}`
|
|
3186
|
-
});
|
|
3595
|
+
writeText(writer, failureFeedback);
|
|
3187
3596
|
const selfCorrectionText = accumulatedText + " " + failureFeedback;
|
|
3188
|
-
context.set(
|
|
3597
|
+
context.set(lastAssistantMessage(selfCorrectionText));
|
|
3189
3598
|
await context.save();
|
|
3190
3599
|
currentResult = await this.#createRawStream(
|
|
3191
3600
|
contextVariables,
|
|
@@ -3215,14 +3624,10 @@ function structuredOutput(options) {
|
|
|
3215
3624
|
return {
|
|
3216
3625
|
async generate(contextVariables, config) {
|
|
3217
3626
|
if (!options.context) {
|
|
3218
|
-
throw new Error(
|
|
3219
|
-
`structuredOutput "${options.name}" is missing a context.`
|
|
3220
|
-
);
|
|
3627
|
+
throw new Error(`structuredOutput is missing a context.`);
|
|
3221
3628
|
}
|
|
3222
3629
|
if (!options.model) {
|
|
3223
|
-
throw new Error(
|
|
3224
|
-
`structuredOutput "${options.name}" is missing a model.`
|
|
3225
|
-
);
|
|
3630
|
+
throw new Error(`structuredOutput is missing a model.`);
|
|
3226
3631
|
}
|
|
3227
3632
|
const { messages, systemPrompt } = await options.context.resolve({
|
|
3228
3633
|
renderer: new XmlRenderer()
|
|
@@ -3232,23 +3637,21 @@ function structuredOutput(options) {
|
|
|
3232
3637
|
providerOptions: options.providerOptions,
|
|
3233
3638
|
model: options.model,
|
|
3234
3639
|
system: systemPrompt,
|
|
3235
|
-
messages: convertToModelMessages(messages),
|
|
3640
|
+
messages: await convertToModelMessages(messages),
|
|
3236
3641
|
stopWhen: stepCountIs(25),
|
|
3642
|
+
experimental_repairToolCall: repairToolCall,
|
|
3237
3643
|
experimental_context: contextVariables,
|
|
3238
|
-
|
|
3644
|
+
output: Output.object({ schema: options.schema }),
|
|
3645
|
+
tools: options.tools
|
|
3239
3646
|
});
|
|
3240
|
-
return result.
|
|
3647
|
+
return result.output;
|
|
3241
3648
|
},
|
|
3242
3649
|
async stream(contextVariables, config) {
|
|
3243
3650
|
if (!options.context) {
|
|
3244
|
-
throw new Error(
|
|
3245
|
-
`structuredOutput "${options.name}" is missing a context.`
|
|
3246
|
-
);
|
|
3651
|
+
throw new Error(`structuredOutput is missing a context.`);
|
|
3247
3652
|
}
|
|
3248
3653
|
if (!options.model) {
|
|
3249
|
-
throw new Error(
|
|
3250
|
-
`structuredOutput "${options.name}" is missing a model.`
|
|
3251
|
-
);
|
|
3654
|
+
throw new Error(`structuredOutput is missing a model.`);
|
|
3252
3655
|
}
|
|
3253
3656
|
const { messages, systemPrompt } = await options.context.resolve({
|
|
3254
3657
|
renderer: new XmlRenderer()
|
|
@@ -3258,15 +3661,70 @@ function structuredOutput(options) {
|
|
|
3258
3661
|
providerOptions: options.providerOptions,
|
|
3259
3662
|
model: options.model,
|
|
3260
3663
|
system: systemPrompt,
|
|
3261
|
-
|
|
3262
|
-
|
|
3664
|
+
experimental_repairToolCall: repairToolCall,
|
|
3665
|
+
messages: await convertToModelMessages(messages),
|
|
3666
|
+
stopWhen: stepCountIs(50),
|
|
3263
3667
|
experimental_transform: config?.transform ?? smoothStream(),
|
|
3264
3668
|
experimental_context: contextVariables,
|
|
3265
|
-
|
|
3669
|
+
output: Output.object({ schema: options.schema }),
|
|
3670
|
+
tools: options.tools
|
|
3266
3671
|
});
|
|
3267
3672
|
}
|
|
3268
3673
|
};
|
|
3269
3674
|
}
|
|
3675
|
+
var repairToolCall = async ({
|
|
3676
|
+
toolCall,
|
|
3677
|
+
tools,
|
|
3678
|
+
inputSchema,
|
|
3679
|
+
error
|
|
3680
|
+
}) => {
|
|
3681
|
+
console.log(
|
|
3682
|
+
`Debug: ${chalk2.yellow("RepairingToolCall")}: ${toolCall.toolName}`,
|
|
3683
|
+
error.name
|
|
3684
|
+
);
|
|
3685
|
+
if (NoSuchToolError.isInstance(error)) {
|
|
3686
|
+
return null;
|
|
3687
|
+
}
|
|
3688
|
+
const tool = tools[toolCall.toolName];
|
|
3689
|
+
const { output } = await generateText({
|
|
3690
|
+
model: groq("openai/gpt-oss-20b"),
|
|
3691
|
+
output: Output.object({ schema: tool.inputSchema }),
|
|
3692
|
+
prompt: [
|
|
3693
|
+
`The model tried to call the tool "${toolCall.toolName}" with the following inputs:`,
|
|
3694
|
+
JSON.stringify(toolCall.input),
|
|
3695
|
+
`The tool accepts the following schema:`,
|
|
3696
|
+
JSON.stringify(inputSchema(toolCall)),
|
|
3697
|
+
"Please fix the inputs."
|
|
3698
|
+
].join("\n")
|
|
3699
|
+
});
|
|
3700
|
+
return { ...toolCall, input: JSON.stringify(output) };
|
|
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
|
+
}
|
|
3718
|
+
|
|
3719
|
+
// packages/context/src/lib/render.ts
|
|
3720
|
+
function render(tag, ...fragments) {
|
|
3721
|
+
if (fragments.length === 0) {
|
|
3722
|
+
return "";
|
|
3723
|
+
}
|
|
3724
|
+
const renderer = new XmlRenderer();
|
|
3725
|
+
const wrapped = fragment(tag, ...fragments);
|
|
3726
|
+
return renderer.render([wrapped]);
|
|
3727
|
+
}
|
|
3270
3728
|
export {
|
|
3271
3729
|
BinaryInstallError,
|
|
3272
3730
|
ComposeStartError,
|
|
@@ -3281,6 +3739,7 @@ export {
|
|
|
3281
3739
|
DockerfileBuildError,
|
|
3282
3740
|
DockerfileStrategy,
|
|
3283
3741
|
InMemoryContextStore,
|
|
3742
|
+
LAZY_ID,
|
|
3284
3743
|
MarkdownRenderer,
|
|
3285
3744
|
ModelsRegistry,
|
|
3286
3745
|
MountPathError,
|
|
@@ -3302,6 +3761,7 @@ export {
|
|
|
3302
3761
|
createDockerSandbox,
|
|
3303
3762
|
defaultTokenizer,
|
|
3304
3763
|
discoverSkillsInDirectory,
|
|
3764
|
+
errorRecoveryGuardrail,
|
|
3305
3765
|
estimate,
|
|
3306
3766
|
example,
|
|
3307
3767
|
explain,
|
|
@@ -3316,14 +3776,19 @@ export {
|
|
|
3316
3776
|
isDockerfileOptions,
|
|
3317
3777
|
isFragment,
|
|
3318
3778
|
isFragmentObject,
|
|
3779
|
+
isLazyFragment,
|
|
3319
3780
|
isMessageFragment,
|
|
3781
|
+
lastAssistantMessage,
|
|
3320
3782
|
loadSkillMetadata,
|
|
3321
3783
|
message,
|
|
3322
3784
|
parseFrontmatter,
|
|
3323
3785
|
pass,
|
|
3324
3786
|
persona,
|
|
3787
|
+
policy,
|
|
3325
3788
|
preference,
|
|
3789
|
+
principle,
|
|
3326
3790
|
quirk,
|
|
3791
|
+
render,
|
|
3327
3792
|
role,
|
|
3328
3793
|
runGuardrailChain,
|
|
3329
3794
|
skills,
|