@deepagents/context 3.1.0 → 4.1.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 +57 -19
- package/dist/browser.js +48 -64
- package/dist/browser.js.map +3 -3
- package/dist/index.js +2004 -1479
- package/dist/index.js.map +4 -4
- package/dist/lib/agent.d.ts.map +1 -1
- package/dist/lib/chain-summary.d.ts.map +1 -1
- package/dist/lib/engine.d.ts +3 -3
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/fragments/message/user.d.ts +51 -92
- package/dist/lib/fragments/message/user.d.ts.map +1 -1
- package/dist/lib/sandbox/agent-os-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/apple-container-sandbox-errors.d.ts +44 -0
- package/dist/lib/sandbox/apple-container-sandbox-errors.d.ts.map +1 -0
- package/dist/lib/sandbox/apple-container-sandbox.d.ts +122 -0
- package/dist/lib/sandbox/apple-container-sandbox.d.ts.map +1 -0
- package/dist/lib/sandbox/bash-tool.d.ts +9 -28
- package/dist/lib/sandbox/bash-tool.d.ts.map +1 -1
- package/dist/lib/sandbox/cli-process.d.ts +24 -0
- package/dist/lib/sandbox/cli-process.d.ts.map +1 -0
- package/dist/lib/sandbox/container-engine.d.ts +149 -0
- package/dist/lib/sandbox/container-engine.d.ts.map +1 -0
- package/dist/lib/sandbox/container-sandbox-errors.d.ts +10 -0
- package/dist/lib/sandbox/container-sandbox-errors.d.ts.map +1 -0
- package/dist/lib/sandbox/container-sandbox.d.ts +90 -0
- package/dist/lib/sandbox/container-sandbox.d.ts.map +1 -0
- package/dist/lib/sandbox/daytona-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/docker-sandbox-errors.d.ts +2 -2
- package/dist/lib/sandbox/docker-sandbox-errors.d.ts.map +1 -1
- package/dist/lib/sandbox/docker-sandbox.d.ts +122 -189
- package/dist/lib/sandbox/docker-sandbox.d.ts.map +1 -1
- package/dist/lib/sandbox/index.d.ts +6 -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 +74 -0
- package/dist/lib/sandbox/strace/index.d.ts.map +1 -0
- package/dist/lib/sandbox/strace/index.js +296 -0
- package/dist/lib/sandbox/strace/index.js.map +7 -0
- package/dist/lib/sandbox/types.d.ts +9 -4
- 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/save-pipeline.d.ts +1 -13
- 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 +9 -3
- package/dist/lib/sandbox/file-changes.d.ts +0 -83
- package/dist/lib/sandbox/file-changes.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -27,14 +27,15 @@ like store implementations, sandbox tooling, and filesystem-based skill loading.
|
|
|
27
27
|
|
|
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
|
-
with `createVirtualSandbox()`, `createDockerSandbox()`,
|
|
31
|
-
`createDaytonaSandbox(client, options)`, or
|
|
32
|
-
on whether commands should run in memory,
|
|
33
|
-
Agent OS.
|
|
30
|
+
with `createVirtualSandbox()`, `createDockerSandbox()`,
|
|
31
|
+
`createAppleContainerSandbox()`, `createDaytonaSandbox(client, options)`, or
|
|
32
|
+
`createAgentOsSandbox()` depending on whether commands should run in memory,
|
|
33
|
+
Docker, Apple Container lightweight VMs, managed Daytona sandboxes, or Agent OS.
|
|
34
34
|
|
|
35
35
|
See the docs for the full API surface:
|
|
36
36
|
|
|
37
37
|
- [Sandbox](https://januarylabs.github.io/deepagents/docs/context/sandbox)
|
|
38
|
+
- [Apple Container Sandbox](https://januarylabs.github.io/deepagents/docs/context/apple-container-sandbox)
|
|
38
39
|
- [Subcommand Builders](https://januarylabs.github.io/deepagents/docs/context/subcommand)
|
|
39
40
|
- [GCS Cloud Storage Volumes](https://januarylabs.github.io/deepagents/docs/context/recipes/gcs-cloud-storage)
|
|
40
41
|
|
|
@@ -49,37 +50,74 @@ deletes the underlying Daytona sandbox.
|
|
|
49
50
|
|
|
50
51
|
### File-change tracking
|
|
51
52
|
|
|
52
|
-
`
|
|
53
|
+
`withStraceFileChanges()` decorates a real sandbox backend so each command,
|
|
54
|
+
spawn, or file write reports the mutations it caused as a `FileChange[]`
|
|
53
55
|
(`{ op: 'write' | 'delete' | 'rename'; path; from?; timestamp }`).
|
|
54
|
-
Consume
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
Consume changes via the `onFileChanges` callback (fires per command, spawn, or
|
|
57
|
+
`writeFiles` call). Bash tool calls also receive
|
|
58
|
+
`tool-result.output.meta.fileChanges` as hidden host-only metadata.
|
|
59
|
+
|
|
60
|
+
Scope which paths are reported with `include` glob patterns (required — a path
|
|
61
|
+
must match at least one); drop noise such as uploaded skills with optional
|
|
62
|
+
`exclude` patterns. Both match absolute paths via Node's `path.matchesGlob`.
|
|
57
63
|
|
|
58
64
|
```ts
|
|
59
|
-
const
|
|
60
|
-
|
|
65
|
+
const backend = await createDockerSandbox({ image: 'my-image-with-strace' });
|
|
66
|
+
const tracked = await withStraceFileChanges(backend, {
|
|
67
|
+
include: ['/workspace/**', '/workspace'],
|
|
61
68
|
onFileChanges: (changes) => {
|
|
62
69
|
for (const c of changes) console.log(`${c.op} ${c.path}`);
|
|
63
70
|
},
|
|
64
71
|
});
|
|
72
|
+
const sandbox = await createBashTool({
|
|
73
|
+
sandbox: tracked,
|
|
74
|
+
destination: '/workspace',
|
|
75
|
+
});
|
|
65
76
|
```
|
|
66
77
|
|
|
67
|
-
Tracking
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
Tracking uses `strace` (per `executeCommand` and per `spawn`) when you compose
|
|
79
|
+
the `withStraceFileChanges()` decorator. The decorator itself does **no**
|
|
80
|
+
self-test — it trusts that strace tracing works in the sandbox, because "strace
|
|
81
|
+
works here" is an invariant of the (image + host kernel + seccomp/caps) that is
|
|
82
|
+
constant for the container's lifetime. Re-proving it per composition would re-pay
|
|
83
|
+
several host→container round-trips on every tool call for no new information.
|
|
84
|
+
|
|
85
|
+
Verifying the invariant is the consumer's **once-per-container** responsibility.
|
|
86
|
+
Run the probe once inside the sandbox at startup (e.g. a daemon boot gate) via
|
|
87
|
+
the lean leaf entry:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { selfTestStrace } from '@deepagents/context/sandbox/strace';
|
|
91
|
+
|
|
92
|
+
// Throws StraceUnavailableError (reason: 'strace-missing' | 'ptrace-blocked' |
|
|
93
|
+
// 'trace-unparseable') with no silent fallback.
|
|
94
|
+
await selfTestStrace();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The `@deepagents/context/sandbox/strace` subpath is a small Node-runtime leaf
|
|
98
|
+
(probe + parser + `StraceUnavailableError`) with no agent/context-framework
|
|
99
|
+
imports, so a minimal daemon or bundled probe can import it without pulling the
|
|
100
|
+
whole framework. If the host process owns only a remote `DisposableSandbox`,
|
|
101
|
+
bundle this leaf entry with a tiny driver, write it into the sandbox, and run it
|
|
102
|
+
there with `node`.
|
|
103
|
+
Import `StraceUnavailableError` from this same subpath when catching the probe's
|
|
104
|
+
error (each entry point is bundled independently, so `instanceof` requires the
|
|
105
|
+
class from the same entry).
|
|
106
|
+
|
|
107
|
+
The backend must satisfy, on any non-virtual backend (Docker, Apple Container,
|
|
108
|
+
Daytona, e2b, ...):
|
|
72
109
|
|
|
73
110
|
1. `strace` installed in the image — `apk add strace` (Alpine) /
|
|
74
111
|
`apt-get install -y strace` (Debian), or `installers: [pkg(['strace'])]` for
|
|
75
112
|
`createDockerSandbox`;
|
|
76
|
-
2. `ptrace` permitted by the runtime — the default on Docker
|
|
77
|
-
|
|
113
|
+
2. `ptrace` permitted by the runtime — the default on Docker, Apple Container,
|
|
114
|
+
and Daytona;
|
|
115
|
+
3. a **native-architecture** sandbox — amd64-under-Rosetta on Apple silicon
|
|
78
116
|
garbles the trace, so build the image for the host arch.
|
|
79
117
|
|
|
80
118
|
The **in-process virtual sandbox cannot host strace** (no real processes/ptrace),
|
|
81
|
-
so it is unsupported by `
|
|
82
|
-
container/VM backend.
|
|
119
|
+
so it is unsupported by `withStraceFileChanges()` — `selfTestStrace` hard-fails
|
|
120
|
+
against it. Use a container/VM backend.
|
|
83
121
|
|
|
84
122
|
Ops are intentionally coarse: strace cannot distinguish a new file from an
|
|
85
123
|
overwrite within one command (both are `O_CREAT|O_TRUNC`), so both report
|
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 [];
|
|
@@ -1828,27 +1833,6 @@ function normalizeReminderTarget(target) {
|
|
|
1828
1833
|
if (target === "steer") return "steer";
|
|
1829
1834
|
throw new Error(`Unsupported reminder target: ${String(target)}`);
|
|
1830
1835
|
}
|
|
1831
|
-
function isConditionalReminderOptions(options) {
|
|
1832
|
-
return options !== void 0 && "when" in options;
|
|
1833
|
-
}
|
|
1834
|
-
function isPromiseLike(value) {
|
|
1835
|
-
return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
1836
|
-
}
|
|
1837
|
-
function normalizeImmediateReminderText(textOrFragment) {
|
|
1838
|
-
if (isFragment(textOrFragment)) {
|
|
1839
|
-
return new XmlRenderer().render([textOrFragment]);
|
|
1840
|
-
}
|
|
1841
|
-
if (typeof textOrFragment === "string") {
|
|
1842
|
-
return textOrFragment;
|
|
1843
|
-
}
|
|
1844
|
-
return (ctx) => {
|
|
1845
|
-
const resolved = textOrFragment(ctx);
|
|
1846
|
-
if (isPromiseLike(resolved)) {
|
|
1847
|
-
throw new Error("Async reminder text requires a when predicate");
|
|
1848
|
-
}
|
|
1849
|
-
return resolved;
|
|
1850
|
-
};
|
|
1851
|
-
}
|
|
1852
1836
|
function normalizeConditionalReminderText(textOrFragment) {
|
|
1853
1837
|
return isFragment(textOrFragment) ? new XmlRenderer().render([textOrFragment]) : textOrFragment;
|
|
1854
1838
|
}
|
|
@@ -1856,7 +1840,7 @@ function isOutputAvailableToolPart(part) {
|
|
|
1856
1840
|
return isStaticToolUIPart(part) && part.state === "output-available";
|
|
1857
1841
|
}
|
|
1858
1842
|
function isToolOutputReminderEnvelope(value) {
|
|
1859
|
-
return isRecord(value) && "result" in value && typeof value.systemReminder === "string"
|
|
1843
|
+
return isRecord(value) && isRecord(value.meta) && value.meta.reminder === true && "result" in value && typeof value.systemReminder === "string";
|
|
1860
1844
|
}
|
|
1861
1845
|
function stripTextByRanges(text, ranges) {
|
|
1862
1846
|
if (ranges.length === 0) {
|
|
@@ -1979,7 +1963,8 @@ function applyInlineReminder(message2, value) {
|
|
|
1979
1963
|
};
|
|
1980
1964
|
}
|
|
1981
1965
|
function applyPartReminder(message2, value) {
|
|
1982
|
-
const
|
|
1966
|
+
const reminderText = formatTaggedReminder(value);
|
|
1967
|
+
const part = { type: "text", text: reminderText };
|
|
1983
1968
|
message2.parts.push(part);
|
|
1984
1969
|
const partIndex = message2.parts.length - 1;
|
|
1985
1970
|
return {
|
|
@@ -1988,13 +1973,10 @@ function applyPartReminder(message2, value) {
|
|
|
1988
1973
|
target: "user",
|
|
1989
1974
|
partIndex,
|
|
1990
1975
|
start: 0,
|
|
1991
|
-
end:
|
|
1976
|
+
end: reminderText.length,
|
|
1992
1977
|
mode: "part"
|
|
1993
1978
|
};
|
|
1994
1979
|
}
|
|
1995
|
-
function resolveReminderText(item, ctx) {
|
|
1996
|
-
return resolveReminder(item, ctx)?.text ?? "";
|
|
1997
|
-
}
|
|
1998
1980
|
function normalizeReminderResolution(value) {
|
|
1999
1981
|
if (typeof value === "string") {
|
|
2000
1982
|
return value.trim().length === 0 ? null : { text: value };
|
|
@@ -2044,7 +2026,19 @@ function applyRemindersToToolOutput(output, texts) {
|
|
|
2044
2026
|
if (texts.length === 0) return output;
|
|
2045
2027
|
return {
|
|
2046
2028
|
result: output === void 0 ? null : output,
|
|
2047
|
-
systemReminder: formatTaggedReminder(texts.join("\n"))
|
|
2029
|
+
systemReminder: formatTaggedReminder(texts.join("\n")),
|
|
2030
|
+
meta: { reminder: true }
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
function toToolReminderModelOutput(output, projectResult) {
|
|
2034
|
+
if (!isToolOutputReminderEnvelope(output)) return null;
|
|
2035
|
+
const projected = projectResult(output.result);
|
|
2036
|
+
return {
|
|
2037
|
+
type: "json",
|
|
2038
|
+
value: {
|
|
2039
|
+
result: isRecord(projected) ? projected.value : projected,
|
|
2040
|
+
systemReminder: output.systemReminder
|
|
2041
|
+
}
|
|
2048
2042
|
};
|
|
2049
2043
|
}
|
|
2050
2044
|
function mergeReminderMetadata(message2, addedReminders) {
|
|
@@ -2057,54 +2051,32 @@ function mergeReminderMetadata(message2, addedReminders) {
|
|
|
2057
2051
|
function reminder(textOrFragment, options) {
|
|
2058
2052
|
const target = normalizeReminderTarget(options?.target);
|
|
2059
2053
|
const asPart = target === "user" ? options?.asPart ?? false : false;
|
|
2060
|
-
if (
|
|
2061
|
-
const text2 = normalizeConditionalReminderText(textOrFragment);
|
|
2062
|
-
if (typeof text2 === "string") {
|
|
2063
|
-
assertReminderText(text2);
|
|
2064
|
-
}
|
|
2065
|
-
return {
|
|
2066
|
-
name: "reminder",
|
|
2067
|
-
data: null,
|
|
2068
|
-
metadata: {
|
|
2069
|
-
reminder: {
|
|
2070
|
-
text: text2,
|
|
2071
|
-
when: options.when,
|
|
2072
|
-
asPart,
|
|
2073
|
-
target
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
if (target !== "user") {
|
|
2054
|
+
if (options?.when === void 0 && target !== "user") {
|
|
2079
2055
|
throw new Error(`Reminder target "${target}" requires a when predicate`);
|
|
2080
2056
|
}
|
|
2081
|
-
const text =
|
|
2057
|
+
const text = normalizeConditionalReminderText(textOrFragment);
|
|
2082
2058
|
if (typeof text === "string") {
|
|
2083
2059
|
assertReminderText(text);
|
|
2084
2060
|
}
|
|
2085
2061
|
return {
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2062
|
+
name: "reminder",
|
|
2063
|
+
data: null,
|
|
2064
|
+
metadata: {
|
|
2065
|
+
reminder: {
|
|
2066
|
+
text,
|
|
2067
|
+
when: options?.when ?? (() => true),
|
|
2068
|
+
asPart,
|
|
2069
|
+
target
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2089
2072
|
};
|
|
2090
2073
|
}
|
|
2091
|
-
function user(content
|
|
2074
|
+
function user(content) {
|
|
2092
2075
|
const message2 = typeof content === "string" ? {
|
|
2093
2076
|
id: generateId2(),
|
|
2094
2077
|
role: "user",
|
|
2095
2078
|
parts: [{ type: "text", text: content }]
|
|
2096
2079
|
} : { ...content, role: "user", parts: [...content.parts] };
|
|
2097
|
-
if (reminders.length > 0) {
|
|
2098
|
-
const plainText = extractPlainText(message2);
|
|
2099
|
-
const added = [];
|
|
2100
|
-
for (const item of reminders) {
|
|
2101
|
-
const meta = applyReminderToMessage(message2, item, {
|
|
2102
|
-
content: plainText
|
|
2103
|
-
});
|
|
2104
|
-
if (meta) added.push(meta);
|
|
2105
|
-
}
|
|
2106
|
-
mergeReminderMetadata(message2, added);
|
|
2107
|
-
}
|
|
2108
2080
|
return {
|
|
2109
2081
|
id: message2.id,
|
|
2110
2082
|
name: "user",
|
|
@@ -2120,6 +2092,16 @@ function user(content, ...reminders) {
|
|
|
2120
2092
|
}
|
|
2121
2093
|
};
|
|
2122
2094
|
}
|
|
2095
|
+
function applyUserRemindersToMessage(message2, reminders) {
|
|
2096
|
+
if (reminders.length === 0) return;
|
|
2097
|
+
const plainText = extractPlainText(message2);
|
|
2098
|
+
const added = [];
|
|
2099
|
+
for (const item of reminders) {
|
|
2100
|
+
const meta = applyReminderToMessage(message2, item, { content: plainText });
|
|
2101
|
+
if (meta) added.push(meta);
|
|
2102
|
+
}
|
|
2103
|
+
mergeReminderMetadata(message2, added);
|
|
2104
|
+
}
|
|
2123
2105
|
function synthesizeSteerUserMessage(text, firedAt, onceIds = []) {
|
|
2124
2106
|
const texts = Array.isArray(text) ? text : [text];
|
|
2125
2107
|
for (const value of texts) assertReminderText(value);
|
|
@@ -2388,6 +2370,7 @@ export {
|
|
|
2388
2370
|
applyPartReminder,
|
|
2389
2371
|
applyReminderToMessage,
|
|
2390
2372
|
applyRemindersToToolOutput,
|
|
2373
|
+
applyUserRemindersToMessage,
|
|
2391
2374
|
assistant,
|
|
2392
2375
|
assistantText,
|
|
2393
2376
|
clarification,
|
|
@@ -2402,6 +2385,7 @@ export {
|
|
|
2402
2385
|
fromFragment,
|
|
2403
2386
|
getFragmentData,
|
|
2404
2387
|
getModelsRegistry,
|
|
2388
|
+
getReminderOnceIds,
|
|
2405
2389
|
getReminderRanges,
|
|
2406
2390
|
glossary,
|
|
2407
2391
|
guardrail,
|
|
@@ -2427,7 +2411,6 @@ export {
|
|
|
2427
2411
|
render,
|
|
2428
2412
|
resolveReminder,
|
|
2429
2413
|
resolveReminderAsync,
|
|
2430
|
-
resolveReminderText,
|
|
2431
2414
|
role,
|
|
2432
2415
|
runGuardrailChain,
|
|
2433
2416
|
soul,
|
|
@@ -2439,6 +2422,7 @@ export {
|
|
|
2439
2422
|
term,
|
|
2440
2423
|
toFragment,
|
|
2441
2424
|
toMessageFragment,
|
|
2425
|
+
toToolReminderModelOutput,
|
|
2442
2426
|
user,
|
|
2443
2427
|
visualizeGraph,
|
|
2444
2428
|
workflow
|