@deepagents/context 3.0.1 → 4.0.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/README.md +94 -4
- package/dist/browser.js +88 -146
- package/dist/browser.js.map +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1085 -687
- package/dist/index.js.map +4 -4
- package/dist/lib/agent.d.ts.map +1 -1
- package/dist/lib/chain-summary.d.ts +1 -0
- package/dist/lib/chain-summary.d.ts.map +1 -1
- package/dist/lib/chat.d.ts.map +1 -1
- package/dist/lib/engine.d.ts +51 -1
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/fragments/message/user.d.ts +89 -95
- package/dist/lib/fragments/message/user.d.ts.map +1 -1
- package/dist/lib/fragments/reminders/once.d.ts +22 -0
- package/dist/lib/fragments/reminders/once.d.ts.map +1 -0
- package/dist/lib/fragments/reminders/turn-predicates.d.ts +1 -1
- package/dist/lib/fragments/reminders/turn-predicates.d.ts.map +1 -1
- package/dist/lib/sandbox/agent-os-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/bash-tool.d.ts +9 -4
- package/dist/lib/sandbox/bash-tool.d.ts.map +1 -1
- package/dist/lib/sandbox/daytona-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/docker-sandbox.d.ts +43 -0
- package/dist/lib/sandbox/docker-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/index.d.ts +2 -1
- package/dist/lib/sandbox/index.d.ts.map +1 -1
- package/dist/lib/sandbox/installers/bin.d.ts.map +1 -1
- package/dist/lib/sandbox/installers/index.d.ts +7 -7
- package/dist/lib/sandbox/installers/index.d.ts.map +1 -1
- package/dist/lib/sandbox/installers/installer.d.ts +0 -5
- package/dist/lib/sandbox/installers/installer.d.ts.map +1 -1
- package/dist/lib/sandbox/installers/url-binary.d.ts.map +1 -1
- package/dist/lib/sandbox/shell-quote.d.ts +10 -0
- package/dist/lib/sandbox/shell-quote.d.ts.map +1 -0
- package/dist/lib/sandbox/strace/file-change.d.ts +21 -0
- package/dist/lib/sandbox/strace/file-change.d.ts.map +1 -0
- package/dist/lib/sandbox/strace/file-changes.d.ts +66 -0
- package/dist/lib/sandbox/strace/file-changes.d.ts.map +1 -0
- package/dist/lib/sandbox/strace/index.d.ts +89 -0
- package/dist/lib/sandbox/strace/index.d.ts.map +1 -0
- package/dist/lib/sandbox/strace/index.js +285 -0
- package/dist/lib/sandbox/strace/index.js.map +7 -0
- package/dist/lib/sandbox/types.d.ts +6 -9
- package/dist/lib/sandbox/types.d.ts.map +1 -1
- package/dist/lib/sandbox/virtual-sandbox.d.ts.map +1 -1
- package/dist/lib/save/reminder-eval.d.ts +19 -0
- package/dist/lib/save/reminder-eval.d.ts.map +1 -0
- package/dist/lib/save/save-pipeline.d.ts +1 -7
- package/dist/lib/save/save-pipeline.d.ts.map +1 -1
- package/dist/lib/skills/skill-reminder.d.ts +2 -2
- package/dist/lib/skills/skill-reminder.d.ts.map +1 -1
- package/package.json +7 -2
- package/dist/lib/sandbox/file-events.d.ts +0 -42
- package/dist/lib/sandbox/file-events.d.ts.map +0 -1
- package/dist/lib/save/reminder-target-handler.d.ts +0 -36
- package/dist/lib/save/reminder-target-handler.d.ts.map +0 -1
- package/dist/lib/save/tool-output-target-handler.d.ts +0 -7
- package/dist/lib/save/tool-output-target-handler.d.ts.map +0 -1
- package/dist/lib/save/user-target-handler.d.ts +0 -7
- package/dist/lib/save/user-target-handler.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -28,8 +28,9 @@ like store implementations, sandbox tooling, and filesystem-based skill loading.
|
|
|
28
28
|
The server-side package also ships the sandbox primitives used by
|
|
29
29
|
`@deepagents/text2sql` and other tool-driven agents. Use `createBashTool()`
|
|
30
30
|
with `createVirtualSandbox()`, `createDockerSandbox()`, or
|
|
31
|
-
`createAgentOsSandbox()` depending
|
|
32
|
-
Docker,
|
|
31
|
+
`createDaytonaSandbox(client, options)`, or `createAgentOsSandbox()` depending
|
|
32
|
+
on whether commands should run in memory, Docker, managed Daytona sandboxes, or
|
|
33
|
+
Agent OS.
|
|
33
34
|
|
|
34
35
|
See the docs for the full API surface:
|
|
35
36
|
|
|
@@ -41,6 +42,83 @@ For same-host Linux Docker daemons, `gcs({ hostPath, mountPath })` provides a
|
|
|
41
42
|
typed bind-volume helper over a host `gcsfuse` mount. For remote daemons, keep
|
|
42
43
|
cloud wiring in the daemon/plugin layer and attach the resulting named volume.
|
|
43
44
|
|
|
45
|
+
`createDaytonaSandbox(client, options)` takes a caller-owned Daytona client plus either a
|
|
46
|
+
stable `name` (get-or-create) or `sandboxId` (attach). One of those identifiers
|
|
47
|
+
is required because `dispose()` releases only the local wrapper and never
|
|
48
|
+
deletes the underlying Daytona sandbox.
|
|
49
|
+
|
|
50
|
+
### File-change tracking
|
|
51
|
+
|
|
52
|
+
`withStraceFileChanges()` decorates a real sandbox backend so each command,
|
|
53
|
+
spawn, or file write reports the mutations it caused as a `FileChange[]`
|
|
54
|
+
(`{ op: 'write' | 'delete' | 'rename'; path; from?; timestamp }`).
|
|
55
|
+
Consume changes via the `onFileChanges` callback (fires per command, spawn, or
|
|
56
|
+
`writeFiles` call). Bash tool calls also receive
|
|
57
|
+
`tool-result.output.meta.fileChanges` as hidden host-only metadata.
|
|
58
|
+
|
|
59
|
+
Scope which paths are reported with `include` glob patterns (required — a path
|
|
60
|
+
must match at least one); drop noise such as uploaded skills with optional
|
|
61
|
+
`exclude` patterns. Both match absolute paths via Node's `path.matchesGlob`.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const backend = await createDockerSandbox({ image: 'my-image-with-strace' });
|
|
65
|
+
const tracked = await withStraceFileChanges(backend, {
|
|
66
|
+
include: ['/workspace/**', '/workspace'],
|
|
67
|
+
onFileChanges: (changes) => {
|
|
68
|
+
for (const c of changes) console.log(`${c.op} ${c.path}`);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const sandbox = await createBashTool({
|
|
72
|
+
sandbox: tracked,
|
|
73
|
+
destination: '/workspace',
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Tracking uses `strace` (per `executeCommand` and per `spawn`) when you compose
|
|
78
|
+
the `withStraceFileChanges()` decorator. The decorator itself does **no**
|
|
79
|
+
self-test — it trusts that strace tracing works in the sandbox, because "strace
|
|
80
|
+
works here" is an invariant of the (image + host kernel + seccomp/caps) that is
|
|
81
|
+
constant for the container's lifetime. Re-proving it per composition would re-pay
|
|
82
|
+
several host→container round-trips on every tool call for no new information.
|
|
83
|
+
|
|
84
|
+
Verifying the invariant is the consumer's **once-per-container** responsibility.
|
|
85
|
+
Run the probe once at startup (e.g. a daemon boot gate) via the lean leaf entry:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { selfTestStrace } from '@deepagents/context/sandbox/strace';
|
|
89
|
+
|
|
90
|
+
// Throws StraceUnavailableError (reason: 'strace-missing' | 'ptrace-blocked' |
|
|
91
|
+
// 'trace-unparseable') with no silent fallback. A DisposableSandbox satisfies
|
|
92
|
+
// the StraceHost shape structurally, so pass a real backend unchanged; an
|
|
93
|
+
// in-process caller implements just { executeCommand, readFile }.
|
|
94
|
+
await selfTestStrace(backend);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The `@deepagents/context/sandbox/strace` subpath is a node-builtins-only bundle
|
|
98
|
+
(probe + parser + `StraceUnavailableError`) with no agent/context-framework
|
|
99
|
+
imports, so a minimal daemon can import it without pulling the whole framework.
|
|
100
|
+
Import `StraceUnavailableError` from this same subpath when catching the probe's
|
|
101
|
+
error (each entry point is bundled independently, so `instanceof` requires the
|
|
102
|
+
class from the same entry).
|
|
103
|
+
|
|
104
|
+
The backend must satisfy, on any non-virtual backend (Docker, Daytona, e2b, ...):
|
|
105
|
+
|
|
106
|
+
1. `strace` installed in the image — `apk add strace` (Alpine) /
|
|
107
|
+
`apt-get install -y strace` (Debian), or `installers: [pkg(['strace'])]` for
|
|
108
|
+
`createDockerSandbox`;
|
|
109
|
+
2. `ptrace` permitted by the runtime — the default on Docker and Daytona;
|
|
110
|
+
3. a **native-architecture** sandbox — amd64-under-Rosetta on Apple Silicon
|
|
111
|
+
garbles the trace, so build the image for the host arch.
|
|
112
|
+
|
|
113
|
+
The **in-process virtual sandbox cannot host strace** (no real processes/ptrace),
|
|
114
|
+
so it is unsupported by `withStraceFileChanges()` — `selfTestStrace` hard-fails
|
|
115
|
+
against it. Use a container/VM backend.
|
|
116
|
+
|
|
117
|
+
Ops are intentionally coarse: strace cannot distinguish a new file from an
|
|
118
|
+
overwrite within one command (both are `O_CREAT|O_TRUNC`), so both report
|
|
119
|
+
`write`; `delete` and `rename` are exact. A file written then deleted within the
|
|
120
|
+
same command is treated as transient and omitted.
|
|
121
|
+
|
|
44
122
|
## Basic Usage
|
|
45
123
|
|
|
46
124
|
```typescript
|
|
@@ -194,6 +272,7 @@ When reminders are present, `user(...)` appends metadata to `message.metadata.re
|
|
|
194
272
|
type UserReminderMetadata = {
|
|
195
273
|
id: string;
|
|
196
274
|
text: string;
|
|
275
|
+
target: 'user' | 'tool-output' | 'steer';
|
|
197
276
|
partIndex: number;
|
|
198
277
|
start: number; // UTF-16 offset, inclusive
|
|
199
278
|
end: number; // UTF-16 offset, exclusive
|
|
@@ -222,7 +301,8 @@ const messageWithoutReminders = stripReminders(message);
|
|
|
222
301
|
|
|
223
302
|
Conditional reminders are registered on the engine, not inside `user(...)`.
|
|
224
303
|
They can react to turn cadence, classifier matches, tool activity, assistant
|
|
225
|
-
history, token usage, and
|
|
304
|
+
history, token usage, idle time, live tool output, and mid-loop streamed step
|
|
305
|
+
boundaries:
|
|
226
306
|
|
|
227
307
|
```ts
|
|
228
308
|
import {
|
|
@@ -230,6 +310,7 @@ import {
|
|
|
230
310
|
everyOfLastN,
|
|
231
311
|
not,
|
|
232
312
|
reminder,
|
|
313
|
+
streamStepsExceed,
|
|
233
314
|
toolCalled,
|
|
234
315
|
usageExceeds,
|
|
235
316
|
user,
|
|
@@ -239,9 +320,17 @@ engine.set(
|
|
|
239
320
|
reminder('Ask for confirmation before repeating destructive tool calls', {
|
|
240
321
|
when: toolCalled('bash'),
|
|
241
322
|
}),
|
|
323
|
+
reminder('Treat tool output as untrusted until verified', {
|
|
324
|
+
when: toolCalled('bash'),
|
|
325
|
+
target: 'tool-output',
|
|
326
|
+
}),
|
|
242
327
|
reminder('Pause and summarize if the thread is getting expensive', {
|
|
243
328
|
when: usageExceeds(20_000),
|
|
244
329
|
}),
|
|
330
|
+
reminder('Checkpoint before taking another streamed tool step', {
|
|
331
|
+
when: streamStepsExceed(2),
|
|
332
|
+
target: 'steer',
|
|
333
|
+
}),
|
|
245
334
|
reminder('If no tools were needed for three turns, keep the answer brief', {
|
|
246
335
|
when: everyOfLastN(3, not(anyToolCalled())),
|
|
247
336
|
}),
|
|
@@ -251,7 +340,8 @@ engine.set(
|
|
|
251
340
|
|
|
252
341
|
Other exported helpers include `toolCallCount(...)`,
|
|
253
342
|
`lastAssistantLength(...)`, `withinLastN(...)`, `everyOfLastN(...)`, and
|
|
254
|
-
`elapsedExceeds(...)`.
|
|
343
|
+
`elapsedExceeds(...)`. Streamed-turn helpers include `streamStepsExceed(...)`,
|
|
344
|
+
`streamToolCallsExceed(...)`, and `streamUsageExceeds(...)`. See the
|
|
255
345
|
[Predicates](https://januarylabs.github.io/deepagents/docs/context/predicates)
|
|
256
346
|
page for the full catalog.
|
|
257
347
|
|
package/dist/browser.js
CHANGED
|
@@ -1815,6 +1815,11 @@ function getReminderRanges(metadata) {
|
|
|
1815
1815
|
end: record.end
|
|
1816
1816
|
}));
|
|
1817
1817
|
}
|
|
1818
|
+
function getReminderOnceIds(message2) {
|
|
1819
|
+
const meta = message2.metadata;
|
|
1820
|
+
if (!isRecord(meta) || !Array.isArray(meta.onceIds)) return [];
|
|
1821
|
+
return meta.onceIds.filter((id) => typeof id === "string");
|
|
1822
|
+
}
|
|
1818
1823
|
function getReminderMetadataRecords(metadata) {
|
|
1819
1824
|
const reminders = metadata?.reminders;
|
|
1820
1825
|
if (!Array.isArray(reminders)) return [];
|
|
@@ -1822,35 +1827,12 @@ function getReminderMetadataRecords(metadata) {
|
|
|
1822
1827
|
(item) => isRecord(item) && typeof item.partIndex === "number" && typeof item.start === "number" && typeof item.end === "number"
|
|
1823
1828
|
);
|
|
1824
1829
|
}
|
|
1825
|
-
function reminderTargetOf(record) {
|
|
1826
|
-
return record.target === "tool-output" ? "tool-output" : "user";
|
|
1827
|
-
}
|
|
1828
1830
|
function normalizeReminderTarget(target) {
|
|
1829
1831
|
if (target === void 0 || target === "user") return "user";
|
|
1830
1832
|
if (target === "tool-output") return "tool-output";
|
|
1833
|
+
if (target === "steer") return "steer";
|
|
1831
1834
|
throw new Error(`Unsupported reminder target: ${String(target)}`);
|
|
1832
1835
|
}
|
|
1833
|
-
function isConditionalReminderOptions(options) {
|
|
1834
|
-
return options !== void 0 && "when" in options;
|
|
1835
|
-
}
|
|
1836
|
-
function isPromiseLike(value) {
|
|
1837
|
-
return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
1838
|
-
}
|
|
1839
|
-
function normalizeImmediateReminderText(textOrFragment) {
|
|
1840
|
-
if (isFragment(textOrFragment)) {
|
|
1841
|
-
return new XmlRenderer().render([textOrFragment]);
|
|
1842
|
-
}
|
|
1843
|
-
if (typeof textOrFragment === "string") {
|
|
1844
|
-
return textOrFragment;
|
|
1845
|
-
}
|
|
1846
|
-
return (ctx) => {
|
|
1847
|
-
const resolved = textOrFragment(ctx);
|
|
1848
|
-
if (isPromiseLike(resolved)) {
|
|
1849
|
-
throw new Error("Async reminder text requires a when predicate");
|
|
1850
|
-
}
|
|
1851
|
-
return resolved;
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
1836
|
function normalizeConditionalReminderText(textOrFragment) {
|
|
1855
1837
|
return isFragment(textOrFragment) ? new XmlRenderer().render([textOrFragment]) : textOrFragment;
|
|
1856
1838
|
}
|
|
@@ -1858,7 +1840,7 @@ function isOutputAvailableToolPart(part) {
|
|
|
1858
1840
|
return isStaticToolUIPart(part) && part.state === "output-available";
|
|
1859
1841
|
}
|
|
1860
1842
|
function isToolOutputReminderEnvelope(value) {
|
|
1861
|
-
return isRecord(value) && typeof value.systemReminder === "string";
|
|
1843
|
+
return isRecord(value) && "result" in value && typeof value.systemReminder === "string" && value.systemReminder.startsWith(SYSTEM_REMINDER_OPEN_TAG);
|
|
1862
1844
|
}
|
|
1863
1845
|
function stripTextByRanges(text, ranges) {
|
|
1864
1846
|
if (ranges.length === 0) {
|
|
@@ -1887,43 +1869,22 @@ function stripTextByRanges(text, ranges) {
|
|
|
1887
1869
|
return output.trimEnd();
|
|
1888
1870
|
}
|
|
1889
1871
|
function stripReminders(message2) {
|
|
1872
|
+
if (isSyntheticSteerMessage(message2)) {
|
|
1873
|
+
return stripSyntheticSteerMessage(message2);
|
|
1874
|
+
}
|
|
1890
1875
|
const reminderRecords = getReminderMetadataRecords(
|
|
1891
1876
|
isRecord(message2.metadata) ? message2.metadata : void 0
|
|
1892
1877
|
);
|
|
1893
1878
|
const rangesByPartIndex = /* @__PURE__ */ new Map();
|
|
1894
|
-
const toolRemindersByPartIndex = /* @__PURE__ */ new Map();
|
|
1895
1879
|
for (const range of reminderRecords) {
|
|
1896
|
-
if (reminderTargetOf(range) === "tool-output") {
|
|
1897
|
-
const records = toolRemindersByPartIndex.get(range.partIndex) ?? [];
|
|
1898
|
-
records.push(range);
|
|
1899
|
-
toolRemindersByPartIndex.set(range.partIndex, records);
|
|
1900
|
-
continue;
|
|
1901
|
-
}
|
|
1902
1880
|
const partRanges = rangesByPartIndex.get(range.partIndex) ?? [];
|
|
1903
1881
|
partRanges.push({ start: range.start, end: range.end });
|
|
1904
1882
|
rangesByPartIndex.set(range.partIndex, partRanges);
|
|
1905
1883
|
}
|
|
1906
1884
|
const strippedParts = message2.parts.flatMap((part, partIndex) => {
|
|
1907
1885
|
const clonedPart = { ...part };
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
if (typeof clonedPart.output === "string") {
|
|
1911
|
-
return [
|
|
1912
|
-
{
|
|
1913
|
-
...clonedPart,
|
|
1914
|
-
output: stripTextByRanges(
|
|
1915
|
-
clonedPart.output,
|
|
1916
|
-
toolReminderRecords.map((record) => ({
|
|
1917
|
-
start: record.start,
|
|
1918
|
-
end: record.end
|
|
1919
|
-
}))
|
|
1920
|
-
)
|
|
1921
|
-
}
|
|
1922
|
-
];
|
|
1923
|
-
}
|
|
1924
|
-
if (isToolOutputReminderEnvelope(clonedPart.output)) {
|
|
1925
|
-
return [{ ...clonedPart, output: clonedPart.output.result }];
|
|
1926
|
-
}
|
|
1886
|
+
if (isOutputAvailableToolPart(clonedPart) && isToolOutputReminderEnvelope(clonedPart.output)) {
|
|
1887
|
+
return [{ ...clonedPart, output: clonedPart.output.result }];
|
|
1927
1888
|
}
|
|
1928
1889
|
const ranges = rangesByPartIndex.get(partIndex);
|
|
1929
1890
|
if (clonedPart.type !== "text" || ranges === void 0) {
|
|
@@ -2063,64 +2024,12 @@ function applyReminderToMessage(message2, item, ctx) {
|
|
|
2063
2024
|
}
|
|
2064
2025
|
return item.asPart ? applyPartReminder(message2, resolved.text) : applyInlineReminder(message2, resolved.text);
|
|
2065
2026
|
}
|
|
2066
|
-
function
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
if (match) return null;
|
|
2072
|
-
match = { partIndex, part };
|
|
2073
|
-
}
|
|
2074
|
-
return match;
|
|
2075
|
-
}
|
|
2076
|
-
function applyToolOutputRemindersToMessage(message2, reminders) {
|
|
2077
|
-
if (reminders.length === 0) return [];
|
|
2078
|
-
const target = findSingleOutputAvailableToolPart(message2);
|
|
2079
|
-
if (!target) return [];
|
|
2080
|
-
for (const reminder2 of reminders) {
|
|
2081
|
-
if (reminder2.metadata) {
|
|
2082
|
-
mergeMessageMetadata(message2, reminder2.metadata);
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
const added = [];
|
|
2086
|
-
if (typeof target.part.output === "string") {
|
|
2087
|
-
let output = target.part.output;
|
|
2088
|
-
for (const reminder2 of reminders) {
|
|
2089
|
-
const reminderText = formatTaggedReminder(reminder2.text);
|
|
2090
|
-
const start = output.length;
|
|
2091
|
-
output = `${output}${reminderText}`;
|
|
2092
|
-
added.push({
|
|
2093
|
-
id: generateId2(),
|
|
2094
|
-
text: reminder2.text,
|
|
2095
|
-
target: "tool-output",
|
|
2096
|
-
partIndex: target.partIndex,
|
|
2097
|
-
start,
|
|
2098
|
-
end: start + reminderText.length,
|
|
2099
|
-
mode: "tool-output"
|
|
2100
|
-
});
|
|
2101
|
-
}
|
|
2102
|
-
message2.parts[target.partIndex] = {
|
|
2103
|
-
...target.part,
|
|
2104
|
-
output
|
|
2105
|
-
};
|
|
2106
|
-
return added;
|
|
2107
|
-
}
|
|
2108
|
-
message2.parts[target.partIndex] = {
|
|
2109
|
-
...target.part,
|
|
2110
|
-
output: {
|
|
2111
|
-
result: target.part.output,
|
|
2112
|
-
systemReminder: reminders.map((reminder2) => reminder2.text).join("\n")
|
|
2113
|
-
}
|
|
2027
|
+
function applyRemindersToToolOutput(output, texts) {
|
|
2028
|
+
if (texts.length === 0) return output;
|
|
2029
|
+
return {
|
|
2030
|
+
result: output === void 0 ? null : output,
|
|
2031
|
+
systemReminder: formatTaggedReminder(texts.join("\n"))
|
|
2114
2032
|
};
|
|
2115
|
-
return reminders.map((reminder2) => ({
|
|
2116
|
-
id: generateId2(),
|
|
2117
|
-
text: reminder2.text,
|
|
2118
|
-
target: "tool-output",
|
|
2119
|
-
partIndex: target.partIndex,
|
|
2120
|
-
start: 0,
|
|
2121
|
-
end: 0,
|
|
2122
|
-
mode: "tool-output"
|
|
2123
|
-
}));
|
|
2124
2033
|
}
|
|
2125
2034
|
function mergeReminderMetadata(message2, addedReminders) {
|
|
2126
2035
|
if (addedReminders.length === 0) return;
|
|
@@ -2132,54 +2041,32 @@ function mergeReminderMetadata(message2, addedReminders) {
|
|
|
2132
2041
|
function reminder(textOrFragment, options) {
|
|
2133
2042
|
const target = normalizeReminderTarget(options?.target);
|
|
2134
2043
|
const asPart = target === "user" ? options?.asPart ?? false : false;
|
|
2135
|
-
if (
|
|
2136
|
-
|
|
2137
|
-
if (typeof text2 === "string") {
|
|
2138
|
-
assertReminderText(text2);
|
|
2139
|
-
}
|
|
2140
|
-
return {
|
|
2141
|
-
name: "reminder",
|
|
2142
|
-
data: null,
|
|
2143
|
-
metadata: {
|
|
2144
|
-
reminder: {
|
|
2145
|
-
text: text2,
|
|
2146
|
-
when: options.when,
|
|
2147
|
-
asPart,
|
|
2148
|
-
target
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
2151
|
-
};
|
|
2044
|
+
if (options?.when === void 0 && target !== "user") {
|
|
2045
|
+
throw new Error(`Reminder target "${target}" requires a when predicate`);
|
|
2152
2046
|
}
|
|
2153
|
-
|
|
2154
|
-
throw new Error('Reminder target "tool-output" requires a when predicate');
|
|
2155
|
-
}
|
|
2156
|
-
const text = normalizeImmediateReminderText(textOrFragment);
|
|
2047
|
+
const text = normalizeConditionalReminderText(textOrFragment);
|
|
2157
2048
|
if (typeof text === "string") {
|
|
2158
2049
|
assertReminderText(text);
|
|
2159
2050
|
}
|
|
2160
2051
|
return {
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2052
|
+
name: "reminder",
|
|
2053
|
+
data: null,
|
|
2054
|
+
metadata: {
|
|
2055
|
+
reminder: {
|
|
2056
|
+
text,
|
|
2057
|
+
when: options?.when ?? (() => true),
|
|
2058
|
+
asPart,
|
|
2059
|
+
target
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2164
2062
|
};
|
|
2165
2063
|
}
|
|
2166
|
-
function user(content
|
|
2064
|
+
function user(content) {
|
|
2167
2065
|
const message2 = typeof content === "string" ? {
|
|
2168
2066
|
id: generateId2(),
|
|
2169
2067
|
role: "user",
|
|
2170
2068
|
parts: [{ type: "text", text: content }]
|
|
2171
2069
|
} : { ...content, role: "user", parts: [...content.parts] };
|
|
2172
|
-
if (reminders.length > 0) {
|
|
2173
|
-
const plainText = extractPlainText(message2);
|
|
2174
|
-
const added = [];
|
|
2175
|
-
for (const item of reminders) {
|
|
2176
|
-
const meta = applyReminderToMessage(message2, item, {
|
|
2177
|
-
content: plainText
|
|
2178
|
-
});
|
|
2179
|
-
if (meta) added.push(meta);
|
|
2180
|
-
}
|
|
2181
|
-
mergeReminderMetadata(message2, added);
|
|
2182
|
-
}
|
|
2183
2070
|
return {
|
|
2184
2071
|
id: message2.id,
|
|
2185
2072
|
name: "user",
|
|
@@ -2195,6 +2082,58 @@ function user(content, ...reminders) {
|
|
|
2195
2082
|
}
|
|
2196
2083
|
};
|
|
2197
2084
|
}
|
|
2085
|
+
function applyUserRemindersToMessage(message2, reminders) {
|
|
2086
|
+
if (reminders.length === 0) return;
|
|
2087
|
+
const plainText = extractPlainText(message2);
|
|
2088
|
+
const added = [];
|
|
2089
|
+
for (const item of reminders) {
|
|
2090
|
+
const meta = applyReminderToMessage(message2, item, { content: plainText });
|
|
2091
|
+
if (meta) added.push(meta);
|
|
2092
|
+
}
|
|
2093
|
+
mergeReminderMetadata(message2, added);
|
|
2094
|
+
}
|
|
2095
|
+
function synthesizeSteerUserMessage(text, firedAt, onceIds = []) {
|
|
2096
|
+
const texts = Array.isArray(text) ? text : [text];
|
|
2097
|
+
for (const value of texts) assertReminderText(value);
|
|
2098
|
+
return {
|
|
2099
|
+
id: generateId2(),
|
|
2100
|
+
role: "user",
|
|
2101
|
+
parts: texts.map((value) => ({
|
|
2102
|
+
type: "text",
|
|
2103
|
+
text: formatTaggedReminder(value)
|
|
2104
|
+
})),
|
|
2105
|
+
metadata: {
|
|
2106
|
+
synthetic: {
|
|
2107
|
+
source: "steer-reminder",
|
|
2108
|
+
firedAt,
|
|
2109
|
+
...onceIds.length > 0 ? { onceIds } : {}
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
function isSyntheticSteerMessage(message2) {
|
|
2115
|
+
const meta = message2.metadata;
|
|
2116
|
+
if (!isRecord(meta)) return false;
|
|
2117
|
+
const synthetic = meta.synthetic;
|
|
2118
|
+
if (!isRecord(synthetic)) return false;
|
|
2119
|
+
return synthetic.source === "steer-reminder";
|
|
2120
|
+
}
|
|
2121
|
+
function stripSyntheticSteerMessage(message2) {
|
|
2122
|
+
const next = {
|
|
2123
|
+
...message2,
|
|
2124
|
+
parts: message2.parts.filter((part) => part.type !== "text")
|
|
2125
|
+
};
|
|
2126
|
+
if (isRecord(message2.metadata)) {
|
|
2127
|
+
const metadata = { ...message2.metadata };
|
|
2128
|
+
delete metadata.synthetic;
|
|
2129
|
+
if (Object.keys(metadata).length > 0) {
|
|
2130
|
+
next.metadata = metadata;
|
|
2131
|
+
} else {
|
|
2132
|
+
delete next.metadata;
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
return next;
|
|
2136
|
+
}
|
|
2198
2137
|
|
|
2199
2138
|
// packages/context/src/lib/guardrail.ts
|
|
2200
2139
|
function pass(part) {
|
|
@@ -2420,7 +2359,8 @@ export {
|
|
|
2420
2359
|
applyInlineReminder,
|
|
2421
2360
|
applyPartReminder,
|
|
2422
2361
|
applyReminderToMessage,
|
|
2423
|
-
|
|
2362
|
+
applyRemindersToToolOutput,
|
|
2363
|
+
applyUserRemindersToMessage,
|
|
2424
2364
|
assistant,
|
|
2425
2365
|
assistantText,
|
|
2426
2366
|
clarification,
|
|
@@ -2431,11 +2371,11 @@ export {
|
|
|
2431
2371
|
example,
|
|
2432
2372
|
explain,
|
|
2433
2373
|
fail,
|
|
2434
|
-
findSingleOutputAvailableToolPart,
|
|
2435
2374
|
fragment,
|
|
2436
2375
|
fromFragment,
|
|
2437
2376
|
getFragmentData,
|
|
2438
2377
|
getModelsRegistry,
|
|
2378
|
+
getReminderOnceIds,
|
|
2439
2379
|
getReminderRanges,
|
|
2440
2380
|
glossary,
|
|
2441
2381
|
guardrail,
|
|
@@ -2446,6 +2386,7 @@ export {
|
|
|
2446
2386
|
isFragmentObject,
|
|
2447
2387
|
isMessageFragment,
|
|
2448
2388
|
isRecord,
|
|
2389
|
+
isSyntheticSteerMessage,
|
|
2449
2390
|
mergeMessageMetadata,
|
|
2450
2391
|
mergeReminderMetadata,
|
|
2451
2392
|
message,
|
|
@@ -2468,6 +2409,7 @@ export {
|
|
|
2468
2409
|
stripReminders,
|
|
2469
2410
|
stripTextByRanges,
|
|
2470
2411
|
styleGuide,
|
|
2412
|
+
synthesizeSteerUserMessage,
|
|
2471
2413
|
term,
|
|
2472
2414
|
toFragment,
|
|
2473
2415
|
toMessageFragment,
|