nexus-ai-pro 2.2.0 → 2.4.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/API_STABILITY.md +225 -0
- package/CHANGELOG.md +325 -1
- package/README.md +20 -6
- package/SECURITY.md +140 -0
- package/dist/adapter-kit/contracts.d.ts +87 -0
- package/dist/adapter-kit/contracts.js +237 -0
- package/dist/adapter-kit/errors.d.ts +39 -0
- package/dist/adapter-kit/errors.js +52 -0
- package/dist/adapter-kit/index.d.ts +144 -0
- package/dist/adapter-kit/index.js +178 -0
- package/dist/adapter-kit/semver.d.ts +12 -0
- package/dist/adapter-kit/semver.js +55 -0
- package/dist/agent/capabilities.d.ts +39 -0
- package/dist/agent/capabilities.js +36 -0
- package/dist/agent/create-agent.d.ts +61 -11
- package/dist/agent/create-agent.js +136 -22
- package/dist/agent/index.d.ts +3 -2
- package/dist/agent/index.js +1 -1
- package/dist/agent/middleware/approval.d.ts +26 -0
- package/dist/agent/middleware/approval.js +23 -0
- package/dist/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
- package/dist/agent/{middleware.js → middleware/basic.js} +3 -5
- package/dist/agent/middleware/context-editor.d.ts +52 -0
- package/dist/agent/middleware/context-editor.js +66 -0
- package/dist/agent/middleware/filesystem.d.ts +44 -0
- package/dist/agent/middleware/filesystem.js +83 -0
- package/dist/agent/middleware/index.d.ts +19 -0
- package/dist/agent/middleware/index.js +9 -0
- package/dist/agent/middleware/limits.d.ts +42 -0
- package/dist/agent/middleware/limits.js +52 -0
- package/dist/agent/middleware/models.d.ts +48 -0
- package/dist/agent/middleware/models.js +44 -0
- package/dist/agent/middleware/pii.d.ts +67 -0
- package/dist/agent/middleware/pii.js +142 -0
- package/dist/agent/middleware/retry.d.ts +66 -0
- package/dist/agent/middleware/retry.js +59 -0
- package/dist/agent/middleware/shared.d.ts +41 -0
- package/dist/agent/middleware/shared.js +73 -0
- package/dist/agent/middleware/tool-selector.d.ts +64 -0
- package/dist/agent/middleware/tool-selector.js +106 -0
- package/dist/agent/permissions.d.ts +113 -0
- package/dist/agent/permissions.js +180 -0
- package/dist/agent/sandbox.d.ts +151 -0
- package/dist/agent/sandbox.js +257 -0
- package/dist/agent/tool.d.ts +8 -3
- package/dist/agent/tool.js +14 -3
- package/dist/core/secure-stream.js +4 -3
- package/dist/deep-agent/index.d.ts +109 -0
- package/dist/deep-agent/index.js +216 -0
- package/dist/embeddings/adapters.js +2 -1
- package/dist/evals/judge.js +2 -5
- package/dist/evaluate/cache.d.ts +0 -14
- package/dist/evaluate/cache.js +0 -30
- package/dist/evaluate/file-cache.d.ts +15 -0
- package/dist/evaluate/file-cache.js +30 -0
- package/dist/evaluate/index.d.ts +2 -1
- package/dist/evaluate/index.js +2 -1
- package/dist/evaluate/review.js +2 -2
- package/dist/evaluate/run.js +2 -2
- package/dist/evaluate/version.js +3 -3
- package/dist/graph/functional.d.ts +9 -0
- package/dist/graph/functional.js +20 -3
- package/dist/graph/graph.js +27 -6
- package/dist/graph/lint.d.ts +4 -1
- package/dist/graph/lint.js +35 -0
- package/dist/graph/node-cache.js +3 -3
- package/dist/hallucination/rag.d.ts +4 -1
- package/dist/hallucination/rag.js +6 -1
- package/dist/images/asset-stores.js +2 -3
- package/dist/images/asset-support.js +2 -2
- package/dist/images/assets.js +1 -2
- package/dist/images/evals.js +4 -4
- package/dist/insights/proposals.js +1 -2
- package/dist/insights/regressions.d.ts +26 -2
- package/dist/insights/regressions.js +129 -3
- package/dist/loaders/git.js +8 -1
- package/dist/loaders/web.js +7 -1
- package/dist/mcp/client.d.ts +14 -0
- package/dist/mcp/client.js +59 -1
- package/dist/mcp/registry.d.ts +6 -0
- package/dist/mcp/registry.js +7 -0
- package/dist/postgres/fulltext.d.ts +67 -0
- package/dist/postgres/fulltext.js +91 -0
- package/dist/prompts/file.js +28 -11
- package/dist/protocols/a2a.d.ts +235 -0
- package/dist/protocols/a2a.js +386 -0
- package/dist/protocols/acp.d.ts +87 -0
- package/dist/protocols/acp.js +322 -0
- package/dist/protocols/ag-ui.d.ts +120 -0
- package/dist/protocols/ag-ui.js +180 -0
- package/dist/protocols/shared.d.ts +80 -0
- package/dist/protocols/shared.js +49 -0
- package/dist/providers/anthropic.js +1 -0
- package/dist/providers/cohere.js +2 -2
- package/dist/providers/google.js +2 -11
- package/dist/providers/openai.js +1 -0
- package/dist/rag/elasticsearch.d.ts +71 -0
- package/dist/rag/elasticsearch.js +130 -0
- package/dist/rag/file-ingestion.js +15 -9
- package/dist/rag/pipeline.d.ts +140 -0
- package/dist/rag/pipeline.js +187 -0
- package/dist/rag/rerankers.d.ts +92 -0
- package/dist/rag/rerankers.js +97 -0
- package/dist/rag/retrievers.d.ts +12 -1
- package/dist/runtime/detect.d.ts +17 -0
- package/dist/runtime/detect.js +16 -0
- package/dist/runtime/index.d.ts +19 -0
- package/dist/runtime/index.js +7 -0
- package/dist/security/injection-detector.d.ts +2 -0
- package/dist/security/injection-detector.js +7 -1
- package/dist/security/input-guard.js +5 -2
- package/dist/security/output-guard.js +8 -4
- package/dist/security/pii-detector.js +22 -6
- package/dist/security/prompt-hardening.js +6 -2
- package/dist/security/semantic-injection-classifier.d.ts +2 -1
- package/dist/security/semantic-injection-classifier.js +31 -35
- package/dist/security/upload-scanner.d.ts +8 -0
- package/dist/security/upload-scanner.js +51 -9
- package/dist/server/assistant.d.ts +5 -1
- package/dist/server/assistant.js +4 -2
- package/dist/server/auth.d.ts +250 -0
- package/dist/server/auth.js +392 -0
- package/dist/server/deployments.d.ts +63 -1
- package/dist/server/deployments.js +75 -2
- package/dist/server/runs.d.ts +9 -0
- package/dist/server/runs.js +20 -0
- package/dist/server/server.js +5 -0
- package/dist/store/memory.d.ts +10 -0
- package/dist/store/memory.js +10 -0
- package/dist/testing/record.js +2 -2
- package/dist/tracing/stores.js +2 -1
- package/dist/tracing/tracer.js +2 -2
- package/dist/types/config.d.ts +20 -0
- package/dist/types/graph.d.ts +38 -0
- package/dist/types/messages.d.ts +36 -2
- package/dist/types/principal.d.ts +21 -0
- package/dist/types/principal.js +1 -0
- package/dist/types/server.d.ts +8 -9
- package/dist/utils/base64.d.ts +4 -0
- package/dist/utils/base64.js +21 -0
- package/dist/utils/checksums.d.ts +22 -0
- package/dist/utils/checksums.js +39 -0
- package/dist/utils/ids.d.ts +8 -0
- package/dist/utils/ids.js +26 -2
- package/dist/utils/sha256.d.ts +22 -0
- package/dist/utils/sha256.js +120 -0
- package/dist/utils/tenant.d.ts +11 -0
- package/dist/utils/tenant.js +14 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist-cjs/adapter-kit/contracts.d.ts +87 -0
- package/dist-cjs/adapter-kit/contracts.js +243 -0
- package/dist-cjs/adapter-kit/errors.d.ts +39 -0
- package/dist-cjs/adapter-kit/errors.js +57 -0
- package/dist-cjs/adapter-kit/index.d.ts +144 -0
- package/dist-cjs/adapter-kit/index.js +194 -0
- package/dist-cjs/adapter-kit/semver.d.ts +12 -0
- package/dist-cjs/adapter-kit/semver.js +59 -0
- package/dist-cjs/agent/capabilities.d.ts +39 -0
- package/dist-cjs/agent/capabilities.js +41 -0
- package/dist-cjs/agent/create-agent.d.ts +61 -11
- package/dist-cjs/agent/create-agent.js +136 -22
- package/dist-cjs/agent/index.d.ts +3 -2
- package/dist-cjs/agent/index.js +4 -4
- package/dist-cjs/agent/middleware/approval.d.ts +26 -0
- package/dist-cjs/agent/middleware/approval.js +26 -0
- package/dist-cjs/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
- package/dist-cjs/agent/{middleware.js → middleware/basic.js} +3 -5
- package/dist-cjs/agent/middleware/context-editor.d.ts +52 -0
- package/dist-cjs/agent/middleware/context-editor.js +70 -0
- package/dist-cjs/agent/middleware/filesystem.d.ts +44 -0
- package/dist-cjs/agent/middleware/filesystem.js +86 -0
- package/dist-cjs/agent/middleware/index.d.ts +19 -0
- package/dist-cjs/agent/middleware/index.js +28 -0
- package/dist-cjs/agent/middleware/limits.d.ts +42 -0
- package/dist-cjs/agent/middleware/limits.js +57 -0
- package/dist-cjs/agent/middleware/models.d.ts +48 -0
- package/dist-cjs/agent/middleware/models.js +48 -0
- package/dist-cjs/agent/middleware/pii.d.ts +67 -0
- package/dist-cjs/agent/middleware/pii.js +147 -0
- package/dist-cjs/agent/middleware/retry.d.ts +66 -0
- package/dist-cjs/agent/middleware/retry.js +63 -0
- package/dist-cjs/agent/middleware/shared.d.ts +41 -0
- package/dist-cjs/agent/middleware/shared.js +83 -0
- package/dist-cjs/agent/middleware/tool-selector.d.ts +64 -0
- package/dist-cjs/agent/middleware/tool-selector.js +109 -0
- package/dist-cjs/agent/permissions.d.ts +113 -0
- package/dist-cjs/agent/permissions.js +189 -0
- package/dist-cjs/agent/sandbox.d.ts +151 -0
- package/dist-cjs/agent/sandbox.js +297 -0
- package/dist-cjs/agent/tool.d.ts +8 -3
- package/dist-cjs/agent/tool.js +14 -3
- package/dist-cjs/core/secure-stream.js +4 -3
- package/dist-cjs/deep-agent/index.d.ts +109 -0
- package/dist-cjs/deep-agent/index.js +219 -0
- package/dist-cjs/embeddings/adapters.js +2 -1
- package/dist-cjs/evals/judge.js +2 -5
- package/dist-cjs/evaluate/cache.d.ts +0 -14
- package/dist-cjs/evaluate/cache.js +1 -65
- package/dist-cjs/evaluate/file-cache.d.ts +15 -0
- package/dist-cjs/evaluate/file-cache.js +67 -0
- package/dist-cjs/evaluate/index.d.ts +2 -1
- package/dist-cjs/evaluate/index.js +3 -2
- package/dist-cjs/evaluate/review.js +2 -2
- package/dist-cjs/evaluate/run.js +2 -2
- package/dist-cjs/evaluate/version.js +3 -3
- package/dist-cjs/graph/functional.d.ts +9 -0
- package/dist-cjs/graph/functional.js +20 -3
- package/dist-cjs/graph/graph.js +27 -6
- package/dist-cjs/graph/lint.d.ts +4 -1
- package/dist-cjs/graph/lint.js +35 -0
- package/dist-cjs/graph/node-cache.js +3 -3
- package/dist-cjs/hallucination/rag.d.ts +4 -1
- package/dist-cjs/hallucination/rag.js +6 -1
- package/dist-cjs/images/asset-stores.js +2 -3
- package/dist-cjs/images/asset-support.js +2 -2
- package/dist-cjs/images/assets.js +1 -2
- package/dist-cjs/images/evals.js +4 -4
- package/dist-cjs/insights/proposals.js +1 -2
- package/dist-cjs/insights/regressions.d.ts +26 -2
- package/dist-cjs/insights/regressions.js +129 -3
- package/dist-cjs/loaders/git.js +8 -1
- package/dist-cjs/loaders/web.js +7 -1
- package/dist-cjs/mcp/client.d.ts +14 -0
- package/dist-cjs/mcp/client.js +60 -1
- package/dist-cjs/mcp/registry.d.ts +6 -0
- package/dist-cjs/mcp/registry.js +7 -0
- package/dist-cjs/postgres/fulltext.d.ts +67 -0
- package/dist-cjs/postgres/fulltext.js +129 -0
- package/dist-cjs/prompts/file.js +28 -11
- package/dist-cjs/protocols/a2a.d.ts +235 -0
- package/dist-cjs/protocols/a2a.js +393 -0
- package/dist-cjs/protocols/acp.d.ts +87 -0
- package/dist-cjs/protocols/acp.js +326 -0
- package/dist-cjs/protocols/ag-ui.d.ts +120 -0
- package/dist-cjs/protocols/ag-ui.js +186 -0
- package/dist-cjs/protocols/shared.d.ts +80 -0
- package/dist-cjs/protocols/shared.js +59 -0
- package/dist-cjs/providers/anthropic.js +1 -0
- package/dist-cjs/providers/cohere.js +2 -2
- package/dist-cjs/providers/google.js +3 -12
- package/dist-cjs/providers/openai.js +1 -0
- package/dist-cjs/rag/elasticsearch.d.ts +71 -0
- package/dist-cjs/rag/elasticsearch.js +135 -0
- package/dist-cjs/rag/file-ingestion.js +14 -8
- package/dist-cjs/rag/pipeline.d.ts +140 -0
- package/dist-cjs/rag/pipeline.js +191 -0
- package/dist-cjs/rag/rerankers.d.ts +92 -0
- package/dist-cjs/rag/rerankers.js +107 -0
- package/dist-cjs/rag/retrievers.d.ts +12 -1
- package/dist-cjs/runtime/detect.d.ts +17 -0
- package/dist-cjs/runtime/detect.js +19 -0
- package/dist-cjs/runtime/index.d.ts +19 -0
- package/dist-cjs/runtime/index.js +31 -0
- package/dist-cjs/security/injection-detector.d.ts +2 -0
- package/dist-cjs/security/injection-detector.js +7 -1
- package/dist-cjs/security/input-guard.js +5 -2
- package/dist-cjs/security/output-guard.js +8 -4
- package/dist-cjs/security/pii-detector.js +22 -6
- package/dist-cjs/security/prompt-hardening.js +6 -2
- package/dist-cjs/security/semantic-injection-classifier.d.ts +2 -1
- package/dist-cjs/security/semantic-injection-classifier.js +31 -35
- package/dist-cjs/security/upload-scanner.d.ts +8 -0
- package/dist-cjs/security/upload-scanner.js +53 -9
- package/dist-cjs/server/assistant.d.ts +5 -1
- package/dist-cjs/server/assistant.js +4 -2
- package/dist-cjs/server/auth.d.ts +250 -0
- package/dist-cjs/server/auth.js +402 -0
- package/dist-cjs/server/deployments.d.ts +63 -1
- package/dist-cjs/server/deployments.js +75 -2
- package/dist-cjs/server/runs.d.ts +9 -0
- package/dist-cjs/server/runs.js +20 -0
- package/dist-cjs/server/server.js +5 -0
- package/dist-cjs/store/memory.d.ts +10 -0
- package/dist-cjs/store/memory.js +10 -0
- package/dist-cjs/testing/record.js +2 -2
- package/dist-cjs/tracing/stores.js +2 -1
- package/dist-cjs/tracing/tracer.js +2 -2
- package/dist-cjs/types/config.d.ts +20 -0
- package/dist-cjs/types/graph.d.ts +38 -0
- package/dist-cjs/types/messages.d.ts +36 -2
- package/dist-cjs/types/principal.d.ts +21 -0
- package/dist-cjs/types/principal.js +2 -0
- package/dist-cjs/types/server.d.ts +8 -9
- package/dist-cjs/utils/base64.d.ts +4 -0
- package/dist-cjs/utils/base64.js +25 -0
- package/dist-cjs/utils/checksums.d.ts +22 -0
- package/dist-cjs/utils/checksums.js +46 -0
- package/dist-cjs/utils/ids.d.ts +8 -0
- package/dist-cjs/utils/ids.js +28 -2
- package/dist-cjs/utils/sha256.d.ts +22 -0
- package/dist-cjs/utils/sha256.js +125 -0
- package/dist-cjs/utils/tenant.d.ts +11 -0
- package/dist-cjs/utils/tenant.js +15 -0
- package/dist-cjs/version.d.ts +1 -1
- package/dist-cjs/version.js +1 -1
- package/llms.txt +7 -3
- package/package.json +193 -6
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sandbox contract: where an agent's commands and code run, and where its files live.
|
|
3
|
+
*
|
|
4
|
+
* The package ships the contract and a conformance suite, not the isolation: a container, a VM, a
|
|
5
|
+
* remote interpreter, or a hosted sandbox fills the `Sandbox` interface. `processSandbox()` is a
|
|
6
|
+
* reference for development, which runs commands as ordinary processes; it says so in its
|
|
7
|
+
* `isolation`, and is never a security boundary.
|
|
8
|
+
*/
|
|
9
|
+
import type { ToolDefinition } from '../types/messages.js';
|
|
10
|
+
/** Options for one command. */
|
|
11
|
+
export interface SandboxExecOptions {
|
|
12
|
+
/** The working directory, inside the sandbox. Defaults to its root. */
|
|
13
|
+
cwd?: string;
|
|
14
|
+
/** Environment variables for the command. The host's own are never passed through. */
|
|
15
|
+
env?: Record<string, string>;
|
|
16
|
+
/** Sent to the command's standard input. */
|
|
17
|
+
stdin?: string;
|
|
18
|
+
/** Stops the command after this many milliseconds. */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
/** Stops the command when aborted. */
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
/** What a command did. */
|
|
24
|
+
export interface SandboxExecResult {
|
|
25
|
+
/** Its exit code, or `null` when it was stopped. */
|
|
26
|
+
exitCode: number | null;
|
|
27
|
+
/** What it wrote to standard output. */
|
|
28
|
+
stdout: string;
|
|
29
|
+
/** What it wrote to standard error. */
|
|
30
|
+
stderr: string;
|
|
31
|
+
/** True when it was stopped by its timeout. */
|
|
32
|
+
timedOut: boolean;
|
|
33
|
+
/** How long it ran, in milliseconds. */
|
|
34
|
+
durationMs: number;
|
|
35
|
+
}
|
|
36
|
+
/** What a sandbox claims to isolate. The conformance suite checks the claims it can observe. */
|
|
37
|
+
export interface SandboxIsolation {
|
|
38
|
+
/** Commands cannot read or write the host's files. */
|
|
39
|
+
filesystem: boolean;
|
|
40
|
+
/** Commands cannot reach the network, or only what the sandbox allows. */
|
|
41
|
+
network: boolean;
|
|
42
|
+
/** Commands cannot see or signal the host's processes. */
|
|
43
|
+
processes: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Where an agent's commands, code, and files go. The application provides one. */
|
|
46
|
+
export interface Sandbox {
|
|
47
|
+
/** Names the sandbox in reports. */
|
|
48
|
+
readonly name: string;
|
|
49
|
+
/** What it isolates. */
|
|
50
|
+
readonly isolation: SandboxIsolation;
|
|
51
|
+
/** Runs a command line in the sandbox. */
|
|
52
|
+
exec(command: string, options?: SandboxExecOptions): Promise<SandboxExecResult>;
|
|
53
|
+
/** Reads a file, by a path inside the sandbox. */
|
|
54
|
+
readFile(file: string): Promise<string>;
|
|
55
|
+
/** Writes a file, creating its directory. */
|
|
56
|
+
writeFile(file: string, content: string): Promise<void>;
|
|
57
|
+
/** Lists a directory's entries. */
|
|
58
|
+
listFiles?(directory?: string): Promise<string[]>;
|
|
59
|
+
/** Removes a file or directory. */
|
|
60
|
+
removeFile?(file: string): Promise<void>;
|
|
61
|
+
/** Releases the sandbox. */
|
|
62
|
+
dispose?(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/** Raised when a path would leave the sandbox. */
|
|
65
|
+
export declare class SandboxPathError extends Error {
|
|
66
|
+
/** The path that was refused. */
|
|
67
|
+
readonly path: string;
|
|
68
|
+
/** Always `SANDBOX_PATH`. */
|
|
69
|
+
readonly code = "SANDBOX_PATH";
|
|
70
|
+
constructor(
|
|
71
|
+
/** The path that was refused. */
|
|
72
|
+
path: string);
|
|
73
|
+
}
|
|
74
|
+
/** Options for `processSandbox()`. */
|
|
75
|
+
export interface ProcessSandboxOptions {
|
|
76
|
+
/** The directory commands run in and files live under. Created when missing. */
|
|
77
|
+
root: string;
|
|
78
|
+
/** Environment variables every command gets, on top of a minimal `PATH`. */
|
|
79
|
+
env?: Record<string, string>;
|
|
80
|
+
/** Timeout for a command that sets none. Defaults to 30 seconds. */
|
|
81
|
+
timeoutMs?: number;
|
|
82
|
+
/** Output kept per stream, in bytes. Defaults to 1 MB. */
|
|
83
|
+
maxOutputBytes?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A sandbox that runs commands as ordinary processes in a directory, for development and tests only.
|
|
87
|
+
*
|
|
88
|
+
* Its file methods refuse any path outside `root`, and commands get only `PATH` and the variables
|
|
89
|
+
* given, never the host's environment. But a command it runs can read and write anything the user
|
|
90
|
+
* can, and reach any host: `isolation` says so. Use a container or a VM in production.
|
|
91
|
+
*/
|
|
92
|
+
export declare function processSandbox(options: ProcessSandboxOptions): Sandbox;
|
|
93
|
+
/** Options for `sandboxTools()`. */
|
|
94
|
+
export interface SandboxToolsOptions {
|
|
95
|
+
/** Offer `run_command`. Defaults to true. */
|
|
96
|
+
shell?: boolean;
|
|
97
|
+
/** Offer `read_file`, `write_file`, and `list_files`. Defaults to true. */
|
|
98
|
+
files?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* The path a permission policy sees the sandbox's files under. Defaults to `/workspace`, so a
|
|
101
|
+
* policy granting `/workspace/**` grants the sandbox.
|
|
102
|
+
*/
|
|
103
|
+
mount?: string;
|
|
104
|
+
/** Timeout for each command. */
|
|
105
|
+
timeoutMs?: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Tools that act through a sandbox, each declaring exactly what one call does: `run_command`
|
|
109
|
+
* declares `shell:<the command>`, and the file tools declare `filesystem:read` or
|
|
110
|
+
* `filesystem:write` with the path under `mount`. A permission policy can therefore grant a
|
|
111
|
+
* workspace, a few commands, and nothing else.
|
|
112
|
+
*/
|
|
113
|
+
export declare function sandboxTools(sandbox: Sandbox, options?: SandboxToolsOptions): ToolDefinition[];
|
|
114
|
+
/** One conformance check's result. */
|
|
115
|
+
export interface SandboxConformanceCheck {
|
|
116
|
+
/** What was checked. */
|
|
117
|
+
name: string;
|
|
118
|
+
/** Whether it held. */
|
|
119
|
+
ok: boolean;
|
|
120
|
+
/** What went wrong, when it did not. */
|
|
121
|
+
detail?: string;
|
|
122
|
+
}
|
|
123
|
+
/** What `runSandboxConformance()` found. */
|
|
124
|
+
export interface SandboxConformanceReport {
|
|
125
|
+
/** The sandbox's name. */
|
|
126
|
+
sandbox: string;
|
|
127
|
+
/** True when every check held. */
|
|
128
|
+
passed: boolean;
|
|
129
|
+
/** Every check, in order. */
|
|
130
|
+
checks: SandboxConformanceCheck[];
|
|
131
|
+
}
|
|
132
|
+
/** Options for `runSandboxConformance()`. */
|
|
133
|
+
export interface SandboxConformanceOptions {
|
|
134
|
+
/** The command that runs JavaScript inside the sandbox. Defaults to `node`. */
|
|
135
|
+
node?: string;
|
|
136
|
+
/** The timeout the timeout check sets, in milliseconds. Defaults to 300. */
|
|
137
|
+
timeoutMs?: number;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Checks a sandbox against the contract, without a test framework, so any sandbox — a container
|
|
141
|
+
* runner, a VM, a hosted service — can prove itself the same way:
|
|
142
|
+
*
|
|
143
|
+
* - commands report their output, errors, and exit code, take standard input and the variables
|
|
144
|
+
* given, and never see the host's environment;
|
|
145
|
+
* - a command past its timeout is stopped and reported as timed out;
|
|
146
|
+
* - commands run where the files are, and files round-trip;
|
|
147
|
+
* - a path outside the sandbox is refused.
|
|
148
|
+
*
|
|
149
|
+
* Every check runs on a fresh sandbox from `create`, which is disposed afterwards.
|
|
150
|
+
*/
|
|
151
|
+
export declare function runSandboxConformance(create: () => Sandbox | Promise<Sandbox>, options?: SandboxConformanceOptions): Promise<SandboxConformanceReport>;
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SandboxPathError = void 0;
|
|
37
|
+
exports.processSandbox = processSandbox;
|
|
38
|
+
exports.sandboxTools = sandboxTools;
|
|
39
|
+
exports.runSandboxConformance = runSandboxConformance;
|
|
40
|
+
class SandboxPathError extends Error {
|
|
41
|
+
path;
|
|
42
|
+
code = 'SANDBOX_PATH';
|
|
43
|
+
constructor(path) {
|
|
44
|
+
super(`"${path}" is outside the sandbox`);
|
|
45
|
+
this.path = path;
|
|
46
|
+
this.name = 'SandboxPathError';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.SandboxPathError = SandboxPathError;
|
|
50
|
+
function processSandbox(options) {
|
|
51
|
+
const ready = (async () => {
|
|
52
|
+
const [{ spawn }, fs, { dirname, isAbsolute, relative, resolve }] = await Promise.all([
|
|
53
|
+
Promise.resolve().then(() => __importStar(require('node:child_process'))),
|
|
54
|
+
Promise.resolve().then(() => __importStar(require('node:fs/promises'))),
|
|
55
|
+
Promise.resolve().then(() => __importStar(require('node:path'))),
|
|
56
|
+
]);
|
|
57
|
+
const root = resolve(options.root);
|
|
58
|
+
await fs.mkdir(root, { recursive: true });
|
|
59
|
+
const inside = (file) => {
|
|
60
|
+
const resolved = resolve(root, file);
|
|
61
|
+
const fromRoot = relative(root, resolved);
|
|
62
|
+
if (fromRoot.startsWith('..') || isAbsolute(fromRoot))
|
|
63
|
+
throw new SandboxPathError(file);
|
|
64
|
+
return resolved;
|
|
65
|
+
};
|
|
66
|
+
return { spawn, fs, dirname, root, inside };
|
|
67
|
+
})();
|
|
68
|
+
ready.catch(() => undefined);
|
|
69
|
+
const maxOutput = options.maxOutputBytes ?? 1_048_576;
|
|
70
|
+
return {
|
|
71
|
+
name: 'process (development only)',
|
|
72
|
+
isolation: { filesystem: false, network: false, processes: false },
|
|
73
|
+
async exec(command, execOptions = {}) {
|
|
74
|
+
const { spawn, root, inside } = await ready;
|
|
75
|
+
const started = Date.now();
|
|
76
|
+
const cwd = inside(execOptions.cwd ?? '.');
|
|
77
|
+
const env = {
|
|
78
|
+
PATH: process.env.PATH ?? '',
|
|
79
|
+
...(process.platform === 'win32' && process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {}),
|
|
80
|
+
HOME: root,
|
|
81
|
+
...options.env,
|
|
82
|
+
...execOptions.env,
|
|
83
|
+
};
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
const child = spawn(command, {
|
|
86
|
+
cwd,
|
|
87
|
+
env,
|
|
88
|
+
shell: true,
|
|
89
|
+
windowsHide: true,
|
|
90
|
+
detached: process.platform !== 'win32',
|
|
91
|
+
});
|
|
92
|
+
let stdout = '';
|
|
93
|
+
let stderr = '';
|
|
94
|
+
let timedOut = false;
|
|
95
|
+
let settled = false;
|
|
96
|
+
const keep = (current, chunk) => current.length >= maxOutput ? current : (current + chunk.toString('utf8')).slice(0, maxOutput);
|
|
97
|
+
child.stdout?.on('data', (chunk) => {
|
|
98
|
+
stdout = keep(stdout, chunk);
|
|
99
|
+
});
|
|
100
|
+
child.stderr?.on('data', (chunk) => {
|
|
101
|
+
stderr = keep(stderr, chunk);
|
|
102
|
+
});
|
|
103
|
+
const stop = () => killTree(spawn, child.pid);
|
|
104
|
+
const limit = execOptions.timeoutMs ?? options.timeoutMs ?? 30_000;
|
|
105
|
+
const timer = setTimeout(() => {
|
|
106
|
+
timedOut = true;
|
|
107
|
+
stop();
|
|
108
|
+
}, limit);
|
|
109
|
+
const onAbort = () => stop();
|
|
110
|
+
execOptions.signal?.addEventListener('abort', onAbort, { once: true });
|
|
111
|
+
const finish = (exitCode) => {
|
|
112
|
+
if (settled)
|
|
113
|
+
return;
|
|
114
|
+
settled = true;
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
execOptions.signal?.removeEventListener('abort', onAbort);
|
|
117
|
+
resolve({ exitCode: timedOut ? null : exitCode, stdout, stderr, timedOut, durationMs: Date.now() - started });
|
|
118
|
+
};
|
|
119
|
+
child.on('error', (error) => {
|
|
120
|
+
stderr += error.message;
|
|
121
|
+
finish(null);
|
|
122
|
+
});
|
|
123
|
+
child.on('close', (code) => finish(code));
|
|
124
|
+
if (execOptions.stdin !== undefined)
|
|
125
|
+
child.stdin?.end(execOptions.stdin);
|
|
126
|
+
else
|
|
127
|
+
child.stdin?.end();
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
async readFile(file) {
|
|
131
|
+
const { fs, inside } = await ready;
|
|
132
|
+
return fs.readFile(inside(file), 'utf8');
|
|
133
|
+
},
|
|
134
|
+
async writeFile(file, content) {
|
|
135
|
+
const { fs, dirname, inside } = await ready;
|
|
136
|
+
const target = inside(file);
|
|
137
|
+
await fs.mkdir(dirname(target), { recursive: true });
|
|
138
|
+
await fs.writeFile(target, content, 'utf8');
|
|
139
|
+
},
|
|
140
|
+
async listFiles(directory = '.') {
|
|
141
|
+
const { fs, inside } = await ready;
|
|
142
|
+
return (await fs.readdir(inside(directory))).sort();
|
|
143
|
+
},
|
|
144
|
+
async removeFile(file) {
|
|
145
|
+
const { fs, root, inside } = await ready;
|
|
146
|
+
const target = inside(file);
|
|
147
|
+
if (target === root)
|
|
148
|
+
throw new SandboxPathError(file);
|
|
149
|
+
await fs.rm(target, { recursive: true, force: true });
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function killTree(spawn, pid) {
|
|
154
|
+
if (pid === undefined)
|
|
155
|
+
return;
|
|
156
|
+
try {
|
|
157
|
+
if (process.platform === 'win32') {
|
|
158
|
+
spawn('taskkill', ['/pid', String(pid), '/T', '/F'], { windowsHide: true, stdio: 'ignore' });
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
process.kill(-pid, 'SIGKILL');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function sandboxTools(sandbox, options = {}) {
|
|
168
|
+
const mount = (options.mount ?? '/workspace').replace(/\/+$/, '');
|
|
169
|
+
const local = (file) => {
|
|
170
|
+
const unified = String(file ?? '.').replace(/\\/g, '/');
|
|
171
|
+
const relative = unified === mount ? '.' : unified.startsWith(`${mount}/`) ? unified.slice(mount.length + 1) : unified;
|
|
172
|
+
return relative.replace(/^\/+/, '') || '.';
|
|
173
|
+
};
|
|
174
|
+
const mounted = (file) => `${mount}/${local(file)}`;
|
|
175
|
+
const tools = [];
|
|
176
|
+
if (options.shell !== false) {
|
|
177
|
+
tools.push({
|
|
178
|
+
name: 'run_command',
|
|
179
|
+
description: 'Runs a shell command in the sandbox and returns its exit code and output.',
|
|
180
|
+
parameters: {
|
|
181
|
+
type: 'object',
|
|
182
|
+
properties: { command: { type: 'string', description: 'The command line to run' } },
|
|
183
|
+
required: ['command'],
|
|
184
|
+
},
|
|
185
|
+
capabilities: (args) => [`shell:${String(args.command ?? '')}`],
|
|
186
|
+
execute: async (args) => {
|
|
187
|
+
const result = await sandbox.exec(String(args.command ?? ''), {
|
|
188
|
+
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
189
|
+
});
|
|
190
|
+
return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr, timedOut: result.timedOut };
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (options.files !== false) {
|
|
195
|
+
tools.push({
|
|
196
|
+
name: 'read_file',
|
|
197
|
+
description: `Reads a text file in the sandbox. Paths are relative to ${mount}.`,
|
|
198
|
+
parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] },
|
|
199
|
+
capabilities: (args) => [`filesystem:read:${mounted(args.path)}`],
|
|
200
|
+
execute: async (args) => sandbox.readFile(local(args.path)),
|
|
201
|
+
}, {
|
|
202
|
+
name: 'write_file',
|
|
203
|
+
description: `Writes a text file in the sandbox, creating its directory. Paths are relative to ${mount}.`,
|
|
204
|
+
parameters: {
|
|
205
|
+
type: 'object',
|
|
206
|
+
properties: { path: { type: 'string' }, content: { type: 'string' } },
|
|
207
|
+
required: ['path', 'content'],
|
|
208
|
+
},
|
|
209
|
+
capabilities: (args) => [`filesystem:write:${mounted(args.path)}`],
|
|
210
|
+
execute: async (args) => {
|
|
211
|
+
await sandbox.writeFile(local(args.path), String(args.content ?? ''));
|
|
212
|
+
return { written: local(args.path) };
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
if (sandbox.listFiles) {
|
|
216
|
+
const list = sandbox.listFiles.bind(sandbox);
|
|
217
|
+
tools.push({
|
|
218
|
+
name: 'list_files',
|
|
219
|
+
description: 'Lists the entries of a directory in the sandbox.',
|
|
220
|
+
parameters: { type: 'object', properties: { path: { type: 'string' } } },
|
|
221
|
+
capabilities: (args) => [`filesystem:read:${mounted(args.path)}`],
|
|
222
|
+
execute: async (args) => list(local(args.path)),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return tools;
|
|
227
|
+
}
|
|
228
|
+
async function runSandboxConformance(create, options = {}) {
|
|
229
|
+
const node = options.node ?? 'node';
|
|
230
|
+
const js = (code) => `${node} -e "${code}"`;
|
|
231
|
+
const checks = [];
|
|
232
|
+
let name = 'sandbox';
|
|
233
|
+
const check = async (label, run) => {
|
|
234
|
+
const sandbox = await create();
|
|
235
|
+
name = sandbox.name;
|
|
236
|
+
try {
|
|
237
|
+
const problem = await run(sandbox);
|
|
238
|
+
checks.push(problem ? { name: label, ok: false, detail: problem } : { name: label, ok: true });
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
checks.push({ name: label, ok: false, detail: error instanceof Error ? error.message : String(error) });
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
await sandbox.dispose?.();
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const expect = (actual, expected, what) => actual === expected ? undefined : `${what}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`;
|
|
248
|
+
await check('a command reports its output and a zero exit code', async (sandbox) => {
|
|
249
|
+
const result = await sandbox.exec(js("process.stdout.write('ok')"));
|
|
250
|
+
return expect(result.stdout, 'ok', 'stdout') ?? expect(result.exitCode, 0, 'exit code');
|
|
251
|
+
});
|
|
252
|
+
await check('a failing command reports its exit code and its errors', async (sandbox) => {
|
|
253
|
+
const result = await sandbox.exec(js("process.stderr.write('bad'); process.exit(3)"));
|
|
254
|
+
return expect(result.exitCode, 3, 'exit code') ?? expect(result.stderr, 'bad', 'stderr');
|
|
255
|
+
});
|
|
256
|
+
await check('a command reads its standard input', async (sandbox) => {
|
|
257
|
+
const result = await sandbox.exec(js('process.stdin.pipe(process.stdout)'), { stdin: 'piped' });
|
|
258
|
+
return expect(result.stdout, 'piped', 'stdout');
|
|
259
|
+
});
|
|
260
|
+
await check('a command gets the variables it is given, and none of the host', async (sandbox) => {
|
|
261
|
+
process.env.NEXUS_SANDBOX_HOST_SECRET = 'host-only';
|
|
262
|
+
try {
|
|
263
|
+
const result = await sandbox.exec(js("process.stdout.write((process.env.NEXUS_SANDBOX_GIVEN || '') + '|' + (process.env.NEXUS_SANDBOX_HOST_SECRET || ''))"), { env: { NEXUS_SANDBOX_GIVEN: 'given' } });
|
|
264
|
+
return expect(result.stdout, 'given|', 'environment');
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
delete process.env.NEXUS_SANDBOX_HOST_SECRET;
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
await check('a command past its timeout is stopped', async (sandbox) => {
|
|
271
|
+
const limit = options.timeoutMs ?? 300;
|
|
272
|
+
const result = await sandbox.exec(js('setTimeout(() => {}, 20000)'), { timeoutMs: limit });
|
|
273
|
+
if (!result.timedOut)
|
|
274
|
+
return 'the command was not reported as timed out';
|
|
275
|
+
if (result.durationMs > limit + 5_000)
|
|
276
|
+
return `the command ran ${result.durationMs} ms past a ${limit} ms timeout`;
|
|
277
|
+
return undefined;
|
|
278
|
+
});
|
|
279
|
+
await check('files round-trip, and commands run where they are', async (sandbox) => {
|
|
280
|
+
await sandbox.writeFile('conformance/note.txt', 'here');
|
|
281
|
+
const read = await sandbox.readFile('conformance/note.txt');
|
|
282
|
+
const seen = await sandbox.exec(js("process.stdout.write(require('fs').readFileSync('conformance/note.txt', 'utf8'))"));
|
|
283
|
+
const listed = sandbox.listFiles ? await sandbox.listFiles('conformance') : ['note.txt'];
|
|
284
|
+
return (expect(read, 'here', 'readFile') ??
|
|
285
|
+
expect(seen.stdout, 'here', 'a command reading the file') ??
|
|
286
|
+
(listed.includes('note.txt') ? undefined : `listFiles did not list note.txt: ${JSON.stringify(listed)}`));
|
|
287
|
+
});
|
|
288
|
+
await check('a path outside the sandbox is refused', async (sandbox) => {
|
|
289
|
+
for (const attempt of ['../outside.txt', 'conformance/../../outside.txt']) {
|
|
290
|
+
const refused = await sandbox.writeFile(attempt, 'escaped').then(() => false, () => true);
|
|
291
|
+
if (!refused)
|
|
292
|
+
return `writeFile("${attempt}") was allowed`;
|
|
293
|
+
}
|
|
294
|
+
return undefined;
|
|
295
|
+
});
|
|
296
|
+
return { sandbox: name, passed: checks.every((item) => item.ok), checks };
|
|
297
|
+
}
|
package/dist-cjs/agent/tool.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import type { ContentPart, Message, ToolDefinition, ToolOutput } from '../types/messages.js';
|
|
1
|
+
import type { ContentPart, Message, ToolContext, ToolDefinition, ToolOutput } from '../types/messages.js';
|
|
2
2
|
import type { ToolExecutionResult } from '../types/agent.js';
|
|
3
3
|
/** Defines a tool the model can call, typing its arguments. */
|
|
4
4
|
export declare function tool<TArgs extends Record<string, unknown> = Record<string, unknown>>(definition: {
|
|
5
5
|
name: string;
|
|
6
6
|
description: string;
|
|
7
7
|
parameters: Record<string, unknown>;
|
|
8
|
-
|
|
8
|
+
/** Runs the tool. In an agent, `context` says who the run is for and carries its signal and store. */
|
|
9
|
+
execute: (args: TArgs, context: ToolContext) => Promise<unknown> | unknown;
|
|
10
|
+
/** What the tool does to the world, for a permission policy; see `ToolDefinition.capabilities`. */
|
|
11
|
+
capabilities?: readonly string[] | ((args: TArgs) => readonly string[]);
|
|
9
12
|
}): ToolDefinition;
|
|
10
13
|
/**
|
|
11
14
|
* Builds a tool's result as content: text, images, and asset references, in order. A string becomes
|
|
@@ -28,8 +31,10 @@ export declare class ToolExecutor {
|
|
|
28
31
|
register(toolDefinition: ToolDefinition): this;
|
|
29
32
|
/** Whether a tool is registered. */
|
|
30
33
|
has(name: string): boolean;
|
|
34
|
+
/** A registered tool, or `undefined`. */
|
|
35
|
+
get(name: string): ToolDefinition | undefined;
|
|
31
36
|
/** Every registered tool. */
|
|
32
37
|
list(): ToolDefinition[];
|
|
33
38
|
/** Runs a tool. An unknown name or a thrown error comes back as a failed result. */
|
|
34
|
-
execute(name: string, args: Record<string, unknown
|
|
39
|
+
execute(name: string, args: Record<string, unknown>, context?: ToolContext): Promise<ToolExecutionResult>;
|
|
35
40
|
}
|
package/dist-cjs/agent/tool.js
CHANGED
|
@@ -6,11 +6,19 @@ exports.toolOutput = toolOutput;
|
|
|
6
6
|
exports.isToolOutput = isToolOutput;
|
|
7
7
|
exports.toolMessageContent = toolMessageContent;
|
|
8
8
|
function tool(definition) {
|
|
9
|
+
const capabilities = definition.capabilities;
|
|
9
10
|
return {
|
|
10
11
|
name: definition.name,
|
|
11
12
|
description: definition.description,
|
|
12
13
|
parameters: definition.parameters,
|
|
13
|
-
execute: async (args) => definition.execute(args),
|
|
14
|
+
execute: async (args, context) => definition.execute(args, context ?? {}),
|
|
15
|
+
...(capabilities === undefined
|
|
16
|
+
? {}
|
|
17
|
+
: {
|
|
18
|
+
capabilities: typeof capabilities === 'function'
|
|
19
|
+
? (args) => capabilities(args)
|
|
20
|
+
: capabilities,
|
|
21
|
+
}),
|
|
14
22
|
};
|
|
15
23
|
}
|
|
16
24
|
function toolOutput(...content) {
|
|
@@ -44,10 +52,13 @@ class ToolExecutor {
|
|
|
44
52
|
has(name) {
|
|
45
53
|
return this.tools.has(name);
|
|
46
54
|
}
|
|
55
|
+
get(name) {
|
|
56
|
+
return this.tools.get(name);
|
|
57
|
+
}
|
|
47
58
|
list() {
|
|
48
59
|
return [...this.tools.values()];
|
|
49
60
|
}
|
|
50
|
-
async execute(name, args) {
|
|
61
|
+
async execute(name, args, context) {
|
|
51
62
|
const toolDefinition = this.tools.get(name);
|
|
52
63
|
if (!toolDefinition) {
|
|
53
64
|
return { ok: false, error: `Tool "${name}" is not registered` };
|
|
@@ -56,7 +67,7 @@ class ToolExecutor {
|
|
|
56
67
|
return { ok: false, error: `Tool "${name}" does not have an execute function` };
|
|
57
68
|
}
|
|
58
69
|
try {
|
|
59
|
-
const result = await toolDefinition.execute(args);
|
|
70
|
+
const result = await toolDefinition.execute(args, context);
|
|
60
71
|
return { ok: true, result };
|
|
61
72
|
}
|
|
62
73
|
catch (err) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.protectStreamOutput = protectStreamOutput;
|
|
4
|
+
const ids_js_1 = require("../utils/ids.js");
|
|
4
5
|
const output_guard_js_1 = require("../security/output-guard.js");
|
|
5
6
|
const MAX_BUFFERED_STREAM_BYTES = 1_048_576;
|
|
6
7
|
const MAX_BUFFERED_STREAM_CHUNKS = 100_000;
|
|
@@ -24,13 +25,13 @@ function protectStreamOutput(stream, security, requestSignal) {
|
|
|
24
25
|
}
|
|
25
26
|
if (chunk.type === 'text' && chunk.content) {
|
|
26
27
|
bufferedText += chunk.content;
|
|
27
|
-
bufferedBytes +=
|
|
28
|
+
bufferedBytes += (0, ids_js_1.utf8Length)(chunk.content);
|
|
28
29
|
}
|
|
29
30
|
else if (chunk.type === 'error' && chunk.error) {
|
|
30
|
-
bufferedBytes +=
|
|
31
|
+
bufferedBytes += (0, ids_js_1.utf8Length)(chunk.error);
|
|
31
32
|
}
|
|
32
33
|
else if (chunk.type === 'tool_call' && chunk.toolCall) {
|
|
33
|
-
bufferedBytes +=
|
|
34
|
+
bufferedBytes += (0, ids_js_1.utf8Length)(chunk.toolCall.function.arguments);
|
|
34
35
|
bufferedToolCalls.push(chunk.toolCall);
|
|
35
36
|
}
|
|
36
37
|
if (bufferedBytes > MAX_BUFFERED_STREAM_BYTES) {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep agents: agents for long, multi-step work — a plan, a workspace, helpers to delegate to, skills
|
|
3
|
+
* to load when needed, and a context that stays small however long the work runs.
|
|
4
|
+
*
|
|
5
|
+
* A preset, not an engine: `createDeepAgent()` composes `createAgent()` with its tools and middleware,
|
|
6
|
+
* and returns the same compiled graph, with the same checkpoints, approvals, events, and server
|
|
7
|
+
* support as any agent.
|
|
8
|
+
*/
|
|
9
|
+
import { type AgentGraph, type AgentMiddleware, type CreateAgentOptions } from '../agent/create-agent.js';
|
|
10
|
+
import { type ContextEditorOptions } from '../agent/middleware/context-editor.js';
|
|
11
|
+
import { type ContextOffloadOptions } from '../agent/middleware/filesystem.js';
|
|
12
|
+
import { type ToolSelectorOptions } from '../agent/middleware/tool-selector.js';
|
|
13
|
+
import { type PermissionPolicyLike } from '../agent/permissions.js';
|
|
14
|
+
import { type Sandbox } from '../agent/sandbox.js';
|
|
15
|
+
/** A helper the deep agent can hand a self-contained piece of work to, with a fresh context. */
|
|
16
|
+
export interface DeepSubagent {
|
|
17
|
+
/** Its name, as the agent delegates to it. */
|
|
18
|
+
name: string;
|
|
19
|
+
/** What it is for, written for the model that decides when to delegate. */
|
|
20
|
+
description: string;
|
|
21
|
+
/** Its own instructions. */
|
|
22
|
+
instructions: string;
|
|
23
|
+
/**
|
|
24
|
+
* The tools it may use, by name, from the deep agent's own. Defaults to all of them except
|
|
25
|
+
* `delegate`, so a helper cannot delegate in turn. A tool named in `interruptOn` is never a
|
|
26
|
+
* helper's: a helper keeps no checkpoints, so it could not pause for the approval.
|
|
27
|
+
*/
|
|
28
|
+
tools?: readonly string[];
|
|
29
|
+
/** Its model. Defaults to the deep agent's. */
|
|
30
|
+
model?: string;
|
|
31
|
+
/** Model calls it may make. Defaults to 20. */
|
|
32
|
+
maxIterations?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Instructions the agent loads only when a task needs them: a procedure, a checklist, a house style. */
|
|
35
|
+
export interface DeepSkill {
|
|
36
|
+
/** Its name, as the agent asks for it. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** When it applies, written for the model. Only this is in the agent's context until it is loaded. */
|
|
39
|
+
description: string;
|
|
40
|
+
/** The instructions themselves. */
|
|
41
|
+
instructions?: string;
|
|
42
|
+
/** A file in the sandbox that holds them, read when the skill is loaded, instead of `instructions`. */
|
|
43
|
+
file?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Options for `createDeepAgent()`. Everything `createAgent()` takes, and the parts of a deep agent. */
|
|
46
|
+
export interface DeepAgentOptions extends Omit<CreateAgentOptions, 'systemPrompt' | 'permissions'> {
|
|
47
|
+
/** What this agent is for. Placed before the deep agent's own working instructions. */
|
|
48
|
+
instructions?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The workspace the agent reads, writes, and runs commands in, through `sandboxTools()`, mounted
|
|
51
|
+
* at `/workspace`. Without one, the agent has no filesystem and no offloading.
|
|
52
|
+
*/
|
|
53
|
+
sandbox?: Sandbox;
|
|
54
|
+
/**
|
|
55
|
+
* Commands the agent may run in the sandbox, as prefixes a permission policy grants: `node`,
|
|
56
|
+
* `npm test`, `git status`. Without any, there is no `run_command` tool.
|
|
57
|
+
*/
|
|
58
|
+
commands?: readonly string[];
|
|
59
|
+
/** Records a plan with `write_todos` and keeps it current. Defaults to true. */
|
|
60
|
+
planning?: boolean;
|
|
61
|
+
/** Helpers the agent can delegate to through one `delegate` tool. */
|
|
62
|
+
subagents?: readonly DeepSubagent[];
|
|
63
|
+
/** Skills the agent can load through `load_skill`. */
|
|
64
|
+
skills?: readonly DeepSkill[];
|
|
65
|
+
/** Instruction files from the sandbox the model sees on every call. Defaults to `AGENTS.md`. */
|
|
66
|
+
include?: readonly string[];
|
|
67
|
+
/**
|
|
68
|
+
* Writes tool results longer than the limit to `.context/` in the sandbox, leaving a preview and the
|
|
69
|
+
* path. Defaults to results over 20,000 characters; `false` keeps them whole.
|
|
70
|
+
*/
|
|
71
|
+
offload?: ContextOffloadOptions | false;
|
|
72
|
+
/**
|
|
73
|
+
* Clears old tool results from what the model is sent once the request grows. Defaults to past
|
|
74
|
+
* 60,000 estimated tokens, never clearing the plan; `false` turns it off.
|
|
75
|
+
*/
|
|
76
|
+
contextEditing?: ContextEditorOptions | false;
|
|
77
|
+
/**
|
|
78
|
+
* Sends the model only the tools relevant to the turn, for an agent with many. The deep agent's own
|
|
79
|
+
* tools are always sent. Off unless given.
|
|
80
|
+
*/
|
|
81
|
+
toolSelection?: ToolSelectorOptions;
|
|
82
|
+
/**
|
|
83
|
+
* Decides every tool call. Defaults to a policy that grants the workspace, the `commands`, the plan,
|
|
84
|
+
* delegation, and skills, and denies everything else, so a tool of your own needs a grant here or
|
|
85
|
+
* its own policy. `false` runs every call.
|
|
86
|
+
*/
|
|
87
|
+
permissions?: PermissionPolicyLike | false;
|
|
88
|
+
/** Middleware run after the deep agent's own. */
|
|
89
|
+
middleware?: AgentMiddleware[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Builds a deep agent: `createAgent()` with a plan, a sandboxed workspace, subagents, skills, context
|
|
93
|
+
* offloading, optional tool selection, and a permission policy.
|
|
94
|
+
*
|
|
95
|
+
* ```ts
|
|
96
|
+
* const agent = createDeepAgent({
|
|
97
|
+
* client: ai,
|
|
98
|
+
* model: 'claude-sonnet-5-5',
|
|
99
|
+
* instructions: 'You maintain this repository.',
|
|
100
|
+
* sandbox,
|
|
101
|
+
* commands: ['node', 'npm test', 'git diff'],
|
|
102
|
+
* subagents: [{ name: 'reviewer', description: 'Reviews a change', instructions: 'Review the diff for bugs.' }],
|
|
103
|
+
* skills: [{ name: 'release-notes', description: 'Writing release notes', file: 'skills/release-notes.md' }],
|
|
104
|
+
* checkpointer,
|
|
105
|
+
* });
|
|
106
|
+
* const run = await agent.invoke(agentInput('Fix the failing test'), { threadId });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export declare function createDeepAgent(options: DeepAgentOptions): AgentGraph;
|