@agent-native/core 0.51.14 → 0.52.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 +3 -3
- package/dist/cli/connect.d.ts +4 -3
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +67 -26
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +20 -13
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +152 -13
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.d.ts +2 -2
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +41 -193
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/plan-local.d.ts +13 -1
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +62 -8
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +1 -1
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +13 -6
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +224 -59
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/agent-engine-key.d.ts +6 -4
- package/dist/client/agent-engine-key.d.ts.map +1 -1
- package/dist/client/agent-engine-key.js +9 -6
- package/dist/client/agent-engine-key.js.map +1 -1
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +7 -14
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/coding-tools/run-code.d.ts +7 -0
- package/dist/coding-tools/run-code.d.ts.map +1 -1
- package/dist/coding-tools/run-code.js +21 -106
- package/dist/coding-tools/run-code.js.map +1 -1
- package/dist/coding-tools/sandbox/adapter.d.ts +79 -0
- package/dist/coding-tools/sandbox/adapter.d.ts.map +1 -0
- package/dist/coding-tools/sandbox/adapter.js +24 -0
- package/dist/coding-tools/sandbox/adapter.js.map +1 -0
- package/dist/coding-tools/sandbox/index.d.ts +51 -0
- package/dist/coding-tools/sandbox/index.d.ts.map +1 -0
- package/dist/coding-tools/sandbox/index.js +79 -0
- package/dist/coding-tools/sandbox/index.js.map +1 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.d.ts +24 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.d.ts.map +1 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.js +141 -0
- package/dist/coding-tools/sandbox/local-child-process-adapter.js.map +1 -0
- package/dist/server/agent-engine-api-key-route.d.ts +37 -0
- package/dist/server/agent-engine-api-key-route.d.ts.map +1 -0
- package/dist/server/agent-engine-api-key-route.js +105 -0
- package/dist/server/agent-engine-api-key-route.js.map +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +10 -6
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/create-server.js +1 -1
- package/dist/server/create-server.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +7 -4
- package/docs/content/plan-plugin.md +5 -4
- package/docs/content/pr-visual-recap.md +1 -1
- package/docs/content/template-plan.md +1 -1
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +7 -4
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox-adapter selection seam.
|
|
3
|
+
*
|
|
4
|
+
* `getSandboxAdapter()` resolves which backend the `run-code` tool executes in.
|
|
5
|
+
* By default it returns the local child-process adapter (preserving today's
|
|
6
|
+
* behavior). The active adapter can be overridden in two ways, both designed so
|
|
7
|
+
* a remote/durable backend can be plugged in later WITHOUT touching the agent
|
|
8
|
+
* loop or `run-code.ts`:
|
|
9
|
+
*
|
|
10
|
+
* 1. Programmatically, via `registerSandboxAdapter(adapter)` — e.g. a host
|
|
11
|
+
* process that wants every `run-code` call to run in a remote container.
|
|
12
|
+
* 2. By env var `AGENT_NATIVE_SANDBOX` for built-in adapters. Currently only
|
|
13
|
+
* `local` (the default) is wired; unknown values fall back to local.
|
|
14
|
+
*
|
|
15
|
+
* Resolution order: an explicitly registered adapter wins; otherwise the env
|
|
16
|
+
* var selects a built-in; otherwise the local adapter is used.
|
|
17
|
+
*
|
|
18
|
+
* // TODO: remote/durable adapter for long jobs. The local child-process
|
|
19
|
+
* // adapter is bounded by the hosting process — on the hosted platform that
|
|
20
|
+
* // means the agent loop's soft execution ceiling (~40s before timeout/
|
|
21
|
+
* // continuation thrash). A remote or durable adapter (Docker, a
|
|
22
|
+
* // Vercel-Sandbox-style runner, or a queued background worker) is the lever
|
|
23
|
+
* // to exceed that ceiling: it would implement `SandboxAdapter.run` against an
|
|
24
|
+
* // out-of-process runtime, tunnel the loopback bridge (or proxy bridge calls
|
|
25
|
+
* // back to the parent), and let large data jobs run to completion
|
|
26
|
+
* // independently of the request lifecycle. Register it here under a new
|
|
27
|
+
* // `AGENT_NATIVE_SANDBOX` value (e.g. `remote`) and via
|
|
28
|
+
* // `registerSandboxAdapter()`.
|
|
29
|
+
*/
|
|
30
|
+
import type { SandboxAdapter } from "./adapter.js";
|
|
31
|
+
export type { SandboxAdapter, SandboxRunRequest, SandboxRunResult, SandboxEnv, } from "./adapter.js";
|
|
32
|
+
export { LocalChildProcessAdapter } from "./local-child-process-adapter.js";
|
|
33
|
+
/**
|
|
34
|
+
* Override the sandbox backend for all subsequent `run-code` invocations.
|
|
35
|
+
* Intended for hosts that want to plug in a Docker/remote/durable adapter. Pass
|
|
36
|
+
* `null` to clear the override and fall back to env-var / default resolution.
|
|
37
|
+
*/
|
|
38
|
+
export declare function registerSandboxAdapter(adapter: SandboxAdapter | null): void;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the active sandbox adapter.
|
|
41
|
+
*
|
|
42
|
+
* Order: explicitly registered adapter → built-in selected by
|
|
43
|
+
* `AGENT_NATIVE_SANDBOX` → local child-process default.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getSandboxAdapter(): SandboxAdapter;
|
|
46
|
+
/**
|
|
47
|
+
* Reset selection state (registered override + cached default). Test-only helper
|
|
48
|
+
* so specs can exercise selection without leaking adapters across cases.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resetSandboxAdapterForTests(): void;
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coding-tools/sandbox/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAa5E;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAelD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox-adapter selection seam.
|
|
3
|
+
*
|
|
4
|
+
* `getSandboxAdapter()` resolves which backend the `run-code` tool executes in.
|
|
5
|
+
* By default it returns the local child-process adapter (preserving today's
|
|
6
|
+
* behavior). The active adapter can be overridden in two ways, both designed so
|
|
7
|
+
* a remote/durable backend can be plugged in later WITHOUT touching the agent
|
|
8
|
+
* loop or `run-code.ts`:
|
|
9
|
+
*
|
|
10
|
+
* 1. Programmatically, via `registerSandboxAdapter(adapter)` — e.g. a host
|
|
11
|
+
* process that wants every `run-code` call to run in a remote container.
|
|
12
|
+
* 2. By env var `AGENT_NATIVE_SANDBOX` for built-in adapters. Currently only
|
|
13
|
+
* `local` (the default) is wired; unknown values fall back to local.
|
|
14
|
+
*
|
|
15
|
+
* Resolution order: an explicitly registered adapter wins; otherwise the env
|
|
16
|
+
* var selects a built-in; otherwise the local adapter is used.
|
|
17
|
+
*
|
|
18
|
+
* // TODO: remote/durable adapter for long jobs. The local child-process
|
|
19
|
+
* // adapter is bounded by the hosting process — on the hosted platform that
|
|
20
|
+
* // means the agent loop's soft execution ceiling (~40s before timeout/
|
|
21
|
+
* // continuation thrash). A remote or durable adapter (Docker, a
|
|
22
|
+
* // Vercel-Sandbox-style runner, or a queued background worker) is the lever
|
|
23
|
+
* // to exceed that ceiling: it would implement `SandboxAdapter.run` against an
|
|
24
|
+
* // out-of-process runtime, tunnel the loopback bridge (or proxy bridge calls
|
|
25
|
+
* // back to the parent), and let large data jobs run to completion
|
|
26
|
+
* // independently of the request lifecycle. Register it here under a new
|
|
27
|
+
* // `AGENT_NATIVE_SANDBOX` value (e.g. `remote`) and via
|
|
28
|
+
* // `registerSandboxAdapter()`.
|
|
29
|
+
*/
|
|
30
|
+
import { LocalChildProcessAdapter } from "./local-child-process-adapter.js";
|
|
31
|
+
export { LocalChildProcessAdapter } from "./local-child-process-adapter.js";
|
|
32
|
+
/** Built-in adapter ids selectable via the `AGENT_NATIVE_SANDBOX` env var. */
|
|
33
|
+
const BUILT_IN_ADAPTERS = {
|
|
34
|
+
local: () => new LocalChildProcessAdapter(),
|
|
35
|
+
};
|
|
36
|
+
/** Lazily-constructed default (local) adapter, shared across calls. */
|
|
37
|
+
let defaultAdapter;
|
|
38
|
+
/** Explicitly registered adapter, if any. Takes precedence over the env var. */
|
|
39
|
+
let registeredAdapter;
|
|
40
|
+
/**
|
|
41
|
+
* Override the sandbox backend for all subsequent `run-code` invocations.
|
|
42
|
+
* Intended for hosts that want to plug in a Docker/remote/durable adapter. Pass
|
|
43
|
+
* `null` to clear the override and fall back to env-var / default resolution.
|
|
44
|
+
*/
|
|
45
|
+
export function registerSandboxAdapter(adapter) {
|
|
46
|
+
registeredAdapter = adapter ?? undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the active sandbox adapter.
|
|
50
|
+
*
|
|
51
|
+
* Order: explicitly registered adapter → built-in selected by
|
|
52
|
+
* `AGENT_NATIVE_SANDBOX` → local child-process default.
|
|
53
|
+
*/
|
|
54
|
+
export function getSandboxAdapter() {
|
|
55
|
+
if (registeredAdapter)
|
|
56
|
+
return registeredAdapter;
|
|
57
|
+
const selected = (process.env.AGENT_NATIVE_SANDBOX ?? "")
|
|
58
|
+
.trim()
|
|
59
|
+
.toLowerCase();
|
|
60
|
+
if (selected && selected !== "local") {
|
|
61
|
+
const factory = BUILT_IN_ADAPTERS[selected];
|
|
62
|
+
if (factory)
|
|
63
|
+
return factory();
|
|
64
|
+
// Unknown value: fall through to the local default rather than failing the
|
|
65
|
+
// run. (A remote adapter is registered programmatically; see the TODO above.)
|
|
66
|
+
}
|
|
67
|
+
if (!defaultAdapter)
|
|
68
|
+
defaultAdapter = new LocalChildProcessAdapter();
|
|
69
|
+
return defaultAdapter;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Reset selection state (registered override + cached default). Test-only helper
|
|
73
|
+
* so specs can exercise selection without leaking adapters across cases.
|
|
74
|
+
*/
|
|
75
|
+
export function resetSandboxAdapterForTests() {
|
|
76
|
+
registeredAdapter = undefined;
|
|
77
|
+
defaultAdapter = undefined;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/coding-tools/sandbox/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAQ5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,8EAA8E;AAC9E,MAAM,iBAAiB,GAAyC;IAC9D,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,wBAAwB,EAAE;CAC5C,CAAC;AAEF,uEAAuE;AACvE,IAAI,cAA0C,CAAC;AAE/C,gFAAgF;AAChF,IAAI,iBAA6C,CAAC;AAElD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAA8B;IACnE,iBAAiB,GAAG,OAAO,IAAI,SAAS,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,iBAAiB;QAAE,OAAO,iBAAiB,CAAC;IAEhD,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;SACtD,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,IAAI,QAAQ,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,OAAO;YAAE,OAAO,OAAO,EAAE,CAAC;QAC9B,2EAA2E;QAC3E,8EAA8E;IAChF,CAAC;IAED,IAAI,CAAC,cAAc;QAAE,cAAc,GAAG,IAAI,wBAAwB,EAAE,CAAC;IACrE,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B;IACzC,iBAAiB,GAAG,SAAS,CAAC;IAC9B,cAAc,GAAG,SAAS,CAAC;AAC7B,CAAC","sourcesContent":["/**\n * Sandbox-adapter selection seam.\n *\n * `getSandboxAdapter()` resolves which backend the `run-code` tool executes in.\n * By default it returns the local child-process adapter (preserving today's\n * behavior). The active adapter can be overridden in two ways, both designed so\n * a remote/durable backend can be plugged in later WITHOUT touching the agent\n * loop or `run-code.ts`:\n *\n * 1. Programmatically, via `registerSandboxAdapter(adapter)` — e.g. a host\n * process that wants every `run-code` call to run in a remote container.\n * 2. By env var `AGENT_NATIVE_SANDBOX` for built-in adapters. Currently only\n * `local` (the default) is wired; unknown values fall back to local.\n *\n * Resolution order: an explicitly registered adapter wins; otherwise the env\n * var selects a built-in; otherwise the local adapter is used.\n *\n * // TODO: remote/durable adapter for long jobs. The local child-process\n * // adapter is bounded by the hosting process — on the hosted platform that\n * // means the agent loop's soft execution ceiling (~40s before timeout/\n * // continuation thrash). A remote or durable adapter (Docker, a\n * // Vercel-Sandbox-style runner, or a queued background worker) is the lever\n * // to exceed that ceiling: it would implement `SandboxAdapter.run` against an\n * // out-of-process runtime, tunnel the loopback bridge (or proxy bridge calls\n * // back to the parent), and let large data jobs run to completion\n * // independently of the request lifecycle. Register it here under a new\n * // `AGENT_NATIVE_SANDBOX` value (e.g. `remote`) and via\n * // `registerSandboxAdapter()`.\n */\n\nimport type { SandboxAdapter } from \"./adapter.js\";\nimport { LocalChildProcessAdapter } from \"./local-child-process-adapter.js\";\n\nexport type {\n SandboxAdapter,\n SandboxRunRequest,\n SandboxRunResult,\n SandboxEnv,\n} from \"./adapter.js\";\nexport { LocalChildProcessAdapter } from \"./local-child-process-adapter.js\";\n\n/** Built-in adapter ids selectable via the `AGENT_NATIVE_SANDBOX` env var. */\nconst BUILT_IN_ADAPTERS: Record<string, () => SandboxAdapter> = {\n local: () => new LocalChildProcessAdapter(),\n};\n\n/** Lazily-constructed default (local) adapter, shared across calls. */\nlet defaultAdapter: SandboxAdapter | undefined;\n\n/** Explicitly registered adapter, if any. Takes precedence over the env var. */\nlet registeredAdapter: SandboxAdapter | undefined;\n\n/**\n * Override the sandbox backend for all subsequent `run-code` invocations.\n * Intended for hosts that want to plug in a Docker/remote/durable adapter. Pass\n * `null` to clear the override and fall back to env-var / default resolution.\n */\nexport function registerSandboxAdapter(adapter: SandboxAdapter | null): void {\n registeredAdapter = adapter ?? undefined;\n}\n\n/**\n * Resolve the active sandbox adapter.\n *\n * Order: explicitly registered adapter → built-in selected by\n * `AGENT_NATIVE_SANDBOX` → local child-process default.\n */\nexport function getSandboxAdapter(): SandboxAdapter {\n if (registeredAdapter) return registeredAdapter;\n\n const selected = (process.env.AGENT_NATIVE_SANDBOX ?? \"\")\n .trim()\n .toLowerCase();\n if (selected && selected !== \"local\") {\n const factory = BUILT_IN_ADAPTERS[selected];\n if (factory) return factory();\n // Unknown value: fall through to the local default rather than failing the\n // run. (A remote adapter is registered programmatically; see the TODO above.)\n }\n\n if (!defaultAdapter) defaultAdapter = new LocalChildProcessAdapter();\n return defaultAdapter;\n}\n\n/**\n * Reset selection state (registered override + cached default). Test-only helper\n * so specs can exercise selection without leaking adapters across cases.\n */\nexport function resetSandboxAdapterForTests(): void {\n registeredAdapter = undefined;\n defaultAdapter = undefined;\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sandbox adapter: a local Node.js child process.
|
|
3
|
+
*
|
|
4
|
+
* This is the historical `run-code` execution path, extracted verbatim so the
|
|
5
|
+
* default runtime behavior is byte-for-byte equivalent to the previous inline
|
|
6
|
+
* implementation in `run-code.ts`:
|
|
7
|
+
* - The prepared module source is written to a fresh temp dir.
|
|
8
|
+
* - The child runs with the scrubbed env supplied by the parent (no secrets).
|
|
9
|
+
* - When the Node permission model is available (`--permission`, or
|
|
10
|
+
* `--experimental-permission` on Node 20), the child is denied filesystem
|
|
11
|
+
* access outside its own temp dir, child processes, workers, and native
|
|
12
|
+
* addons. Outbound network is NOT blocked by the permission model; the env
|
|
13
|
+
* scrub means such requests carry no credentials, and all authenticated calls
|
|
14
|
+
* go through the parent's loopback bridge.
|
|
15
|
+
* - A timeout sends SIGTERM, then SIGKILL after a 2 s grace period.
|
|
16
|
+
* - Temp files are cleaned up best-effort after the run.
|
|
17
|
+
*/
|
|
18
|
+
import type { SandboxAdapter, SandboxRunRequest, SandboxRunResult } from "./adapter.js";
|
|
19
|
+
/** Sandbox adapter that runs code in a locked-down local Node child process. */
|
|
20
|
+
export declare class LocalChildProcessAdapter implements SandboxAdapter {
|
|
21
|
+
readonly id = "local-child-process";
|
|
22
|
+
run(request: SandboxRunRequest): Promise<SandboxRunResult>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=local-child-process-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-child-process-adapter.d.ts","sourceRoot":"","sources":["../../../src/coding-tools/sandbox/local-child-process-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,cAAc,CAAC;AAmDtB,gFAAgF;AAChF,qBAAa,wBAAyB,YAAW,cAAc;IAC7D,QAAQ,CAAC,EAAE,yBAAyB;IAE9B,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA6EjE"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sandbox adapter: a local Node.js child process.
|
|
3
|
+
*
|
|
4
|
+
* This is the historical `run-code` execution path, extracted verbatim so the
|
|
5
|
+
* default runtime behavior is byte-for-byte equivalent to the previous inline
|
|
6
|
+
* implementation in `run-code.ts`:
|
|
7
|
+
* - The prepared module source is written to a fresh temp dir.
|
|
8
|
+
* - The child runs with the scrubbed env supplied by the parent (no secrets).
|
|
9
|
+
* - When the Node permission model is available (`--permission`, or
|
|
10
|
+
* `--experimental-permission` on Node 20), the child is denied filesystem
|
|
11
|
+
* access outside its own temp dir, child processes, workers, and native
|
|
12
|
+
* addons. Outbound network is NOT blocked by the permission model; the env
|
|
13
|
+
* scrub means such requests carry no credentials, and all authenticated calls
|
|
14
|
+
* go through the parent's loopback bridge.
|
|
15
|
+
* - A timeout sends SIGTERM, then SIGKILL after a 2 s grace period.
|
|
16
|
+
* - Temp files are cleaned up best-effort after the run.
|
|
17
|
+
*/
|
|
18
|
+
import fs from "node:fs";
|
|
19
|
+
import os from "node:os";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
22
|
+
/** Grace period between SIGTERM and SIGKILL when a run times out. */
|
|
23
|
+
const SIGKILL_GRACE_MS = 2_000;
|
|
24
|
+
function sandboxReadAllowPaths(tmpDir) {
|
|
25
|
+
const paths = new Set([tmpDir]);
|
|
26
|
+
try {
|
|
27
|
+
paths.add(fs.realpathSync(tmpDir));
|
|
28
|
+
}
|
|
29
|
+
catch { }
|
|
30
|
+
return [...paths];
|
|
31
|
+
}
|
|
32
|
+
function sandboxWriteAllowPaths(tmpDir) {
|
|
33
|
+
const paths = new Set([tmpDir]);
|
|
34
|
+
try {
|
|
35
|
+
paths.add(fs.realpathSync(tmpDir));
|
|
36
|
+
}
|
|
37
|
+
catch { }
|
|
38
|
+
return [...paths];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve the Node permission-model flag supported by the current runtime,
|
|
42
|
+
* probing once and caching. Returns null when the permission model is
|
|
43
|
+
* unavailable (the sandbox then falls back to env-scrub isolation only).
|
|
44
|
+
*/
|
|
45
|
+
let cachedPermissionFlag;
|
|
46
|
+
function resolvePermissionFlag() {
|
|
47
|
+
if (cachedPermissionFlag !== undefined)
|
|
48
|
+
return cachedPermissionFlag;
|
|
49
|
+
for (const flag of ["--permission", "--experimental-permission"]) {
|
|
50
|
+
try {
|
|
51
|
+
const probe = spawnSync(process.execPath, [flag, "-e", "process.exit(0)"], {
|
|
52
|
+
timeout: 10_000,
|
|
53
|
+
stdio: "ignore",
|
|
54
|
+
});
|
|
55
|
+
if (probe.status === 0) {
|
|
56
|
+
cachedPermissionFlag = flag;
|
|
57
|
+
return flag;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Probe failure means the flag is unsupported; try the next one.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
cachedPermissionFlag = null;
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/** Sandbox adapter that runs code in a locked-down local Node child process. */
|
|
68
|
+
export class LocalChildProcessAdapter {
|
|
69
|
+
id = "local-child-process";
|
|
70
|
+
async run(request) {
|
|
71
|
+
let tmpDir;
|
|
72
|
+
let tmpFile;
|
|
73
|
+
try {
|
|
74
|
+
// Write code to a temp ESM file (top-level await needs a module).
|
|
75
|
+
const tmpBaseDir = fs.realpathSync(os.tmpdir());
|
|
76
|
+
tmpDir = fs.mkdtempSync(path.join(tmpBaseDir, "agent-run-code-"));
|
|
77
|
+
tmpFile = path.join(tmpDir, "sandbox.mjs");
|
|
78
|
+
fs.writeFileSync(tmpFile, request.moduleSource, "utf8");
|
|
79
|
+
// The parent supplies an already-scrubbed env (no secrets). Point TMPDIR
|
|
80
|
+
// inside the sandbox dir so in-sandbox temp writes stay within the
|
|
81
|
+
// permission-model allow list.
|
|
82
|
+
const safeEnv = { ...request.env };
|
|
83
|
+
safeEnv.TMPDIR = tmpDir;
|
|
84
|
+
safeEnv.TEMP = tmpDir;
|
|
85
|
+
safeEnv.TMP = tmpDir;
|
|
86
|
+
// Lock the child down with the Node permission model when available:
|
|
87
|
+
// filesystem restricted to the sandbox temp dir, and child processes,
|
|
88
|
+
// workers, and native addons denied entirely.
|
|
89
|
+
const permissionFlag = resolvePermissionFlag();
|
|
90
|
+
const nodeArgs = permissionFlag
|
|
91
|
+
? [
|
|
92
|
+
permissionFlag,
|
|
93
|
+
...sandboxReadAllowPaths(tmpDir).map((allowedPath) => `--allow-fs-read=${allowedPath}`),
|
|
94
|
+
...sandboxWriteAllowPaths(tmpDir).map((allowedPath) => `--allow-fs-write=${allowedPath}`),
|
|
95
|
+
tmpFile,
|
|
96
|
+
]
|
|
97
|
+
: [tmpFile];
|
|
98
|
+
const child = spawn(process.execPath, nodeArgs, {
|
|
99
|
+
cwd: tmpDir,
|
|
100
|
+
env: safeEnv,
|
|
101
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
102
|
+
});
|
|
103
|
+
let stdout = "";
|
|
104
|
+
let stderr = "";
|
|
105
|
+
let timedOut = false;
|
|
106
|
+
const timer = setTimeout(() => {
|
|
107
|
+
timedOut = true;
|
|
108
|
+
child.kill("SIGTERM");
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
try {
|
|
111
|
+
child.kill("SIGKILL");
|
|
112
|
+
}
|
|
113
|
+
catch { }
|
|
114
|
+
}, SIGKILL_GRACE_MS);
|
|
115
|
+
}, request.timeoutMs);
|
|
116
|
+
child.stdout?.on("data", (chunk) => {
|
|
117
|
+
stdout += chunk.toString();
|
|
118
|
+
});
|
|
119
|
+
child.stderr?.on("data", (chunk) => {
|
|
120
|
+
stderr += chunk.toString();
|
|
121
|
+
});
|
|
122
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
123
|
+
child.once("error", reject);
|
|
124
|
+
child.once("exit", resolve);
|
|
125
|
+
});
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
return { stdout, stderr, exitCode, timedOut };
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
// Clean up temp files (best-effort).
|
|
131
|
+
try {
|
|
132
|
+
if (tmpFile)
|
|
133
|
+
fs.rmSync(tmpFile, { force: true });
|
|
134
|
+
if (tmpDir)
|
|
135
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
136
|
+
}
|
|
137
|
+
catch { }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=local-child-process-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-child-process-adapter.js","sourceRoot":"","sources":["../../../src/coding-tools/sandbox/local-child-process-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Default sandbox adapter: a local Node.js child process.\n *\n * This is the historical `run-code` execution path, extracted verbatim so the\n * default runtime behavior is byte-for-byte equivalent to the previous inline\n * implementation in `run-code.ts`:\n * - The prepared module source is written to a fresh temp dir.\n * - The child runs with the scrubbed env supplied by the parent (no secrets).\n * - When the Node permission model is available (`--permission`, or\n * `--experimental-permission` on Node 20), the child is denied filesystem\n * access outside its own temp dir, child processes, workers, and native\n * addons. Outbound network is NOT blocked by the permission model; the env\n * scrub means such requests carry no credentials, and all authenticated calls\n * go through the parent's loopback bridge.\n * - A timeout sends SIGTERM, then SIGKILL after a 2 s grace period.\n * - Temp files are cleaned up best-effort after the run.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { spawn, spawnSync } from \"node:child_process\";\n\nimport type {\n SandboxAdapter,\n SandboxRunRequest,\n SandboxRunResult,\n} from \"./adapter.js\";\n\n/** Grace period between SIGTERM and SIGKILL when a run times out. */\nconst SIGKILL_GRACE_MS = 2_000;\n\nfunction sandboxReadAllowPaths(tmpDir: string): string[] {\n const paths = new Set<string>([tmpDir]);\n try {\n paths.add(fs.realpathSync(tmpDir));\n } catch {}\n return [...paths];\n}\n\nfunction sandboxWriteAllowPaths(tmpDir: string): string[] {\n const paths = new Set<string>([tmpDir]);\n try {\n paths.add(fs.realpathSync(tmpDir));\n } catch {}\n return [...paths];\n}\n\n/**\n * Resolve the Node permission-model flag supported by the current runtime,\n * probing once and caching. Returns null when the permission model is\n * unavailable (the sandbox then falls back to env-scrub isolation only).\n */\nlet cachedPermissionFlag: string | null | undefined;\nfunction resolvePermissionFlag(): string | null {\n if (cachedPermissionFlag !== undefined) return cachedPermissionFlag;\n for (const flag of [\"--permission\", \"--experimental-permission\"]) {\n try {\n const probe = spawnSync(\n process.execPath,\n [flag, \"-e\", \"process.exit(0)\"],\n {\n timeout: 10_000,\n stdio: \"ignore\",\n },\n );\n if (probe.status === 0) {\n cachedPermissionFlag = flag;\n return flag;\n }\n } catch {\n // Probe failure means the flag is unsupported; try the next one.\n }\n }\n cachedPermissionFlag = null;\n return null;\n}\n\n/** Sandbox adapter that runs code in a locked-down local Node child process. */\nexport class LocalChildProcessAdapter implements SandboxAdapter {\n readonly id = \"local-child-process\";\n\n async run(request: SandboxRunRequest): Promise<SandboxRunResult> {\n let tmpDir: string | undefined;\n let tmpFile: string | undefined;\n try {\n // Write code to a temp ESM file (top-level await needs a module).\n const tmpBaseDir = fs.realpathSync(os.tmpdir());\n tmpDir = fs.mkdtempSync(path.join(tmpBaseDir, \"agent-run-code-\"));\n tmpFile = path.join(tmpDir, \"sandbox.mjs\");\n fs.writeFileSync(tmpFile, request.moduleSource, \"utf8\");\n\n // The parent supplies an already-scrubbed env (no secrets). Point TMPDIR\n // inside the sandbox dir so in-sandbox temp writes stay within the\n // permission-model allow list.\n const safeEnv: Record<string, string> = { ...request.env };\n safeEnv.TMPDIR = tmpDir;\n safeEnv.TEMP = tmpDir;\n safeEnv.TMP = tmpDir;\n\n // Lock the child down with the Node permission model when available:\n // filesystem restricted to the sandbox temp dir, and child processes,\n // workers, and native addons denied entirely.\n const permissionFlag = resolvePermissionFlag();\n const nodeArgs = permissionFlag\n ? [\n permissionFlag,\n ...sandboxReadAllowPaths(tmpDir).map(\n (allowedPath) => `--allow-fs-read=${allowedPath}`,\n ),\n ...sandboxWriteAllowPaths(tmpDir).map(\n (allowedPath) => `--allow-fs-write=${allowedPath}`,\n ),\n tmpFile,\n ]\n : [tmpFile];\n\n const child = spawn(process.execPath, nodeArgs, {\n cwd: tmpDir,\n env: safeEnv,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n let timedOut = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n child.kill(\"SIGTERM\");\n setTimeout(() => {\n try {\n child.kill(\"SIGKILL\");\n } catch {}\n }, SIGKILL_GRACE_MS);\n }, request.timeoutMs);\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n\n const exitCode = await new Promise<number | null>((resolve, reject) => {\n child.once(\"error\", reject);\n child.once(\"exit\", resolve);\n });\n clearTimeout(timer);\n\n return { stdout, stderr, exitCode, timedOut };\n } finally {\n // Clean up temp files (best-effort).\n try {\n if (tmpFile) fs.rmSync(tmpFile, { force: true });\n if (tmpDir) fs.rmSync(tmpDir, { recursive: true, force: true });\n } catch {}\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type H3Event } from "h3";
|
|
2
|
+
type AgentEngineApiKeyScope = "user" | "org";
|
|
3
|
+
export interface AgentEngineApiKeyWriteTarget {
|
|
4
|
+
scope: AgentEngineApiKeyScope;
|
|
5
|
+
scopeId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeAgentEngineApiKeyPayload(body: unknown): {
|
|
8
|
+
ok: true;
|
|
9
|
+
key: string;
|
|
10
|
+
value: string;
|
|
11
|
+
scope: AgentEngineApiKeyScope;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
statusCode: number;
|
|
15
|
+
error: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scope: AgentEngineApiKeyScope): Promise<{
|
|
18
|
+
ok: true;
|
|
19
|
+
target: AgentEngineApiKeyWriteTarget;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
statusCode: number;
|
|
23
|
+
error: string;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
26
|
+
error: any;
|
|
27
|
+
ok?: undefined;
|
|
28
|
+
key?: undefined;
|
|
29
|
+
scope?: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
ok: boolean;
|
|
32
|
+
key: string;
|
|
33
|
+
scope: AgentEngineApiKeyScope;
|
|
34
|
+
error?: undefined;
|
|
35
|
+
}>>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=agent-engine-api-key-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-engine-api-key-route.d.ts","sourceRoot":"","sources":["../../src/server/agent-engine-api-key-route.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;AAeZ,KAAK,sBAAsB,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7C,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,sBAAsB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,OAAO,GAC3D;IACE,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;CAC/B,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAgDnD;AAED,wBAAsB,mCAAmC,CACvD,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CACN;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,4BAA4B,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CACnD,CA6BA;AAED,wBAAgB,8BAA8B;;;;;;;;;;IAqC7C"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { defineEventHandler, getMethod, setResponseStatus, } from "h3";
|
|
2
|
+
import { PROVIDER_ENV_META } from "../agent/engine/provider-env-vars.js";
|
|
3
|
+
import { getOrgContext } from "../org/context.js";
|
|
4
|
+
import { writeAppSecret } from "../secrets/storage.js";
|
|
5
|
+
import { getSession } from "./auth.js";
|
|
6
|
+
import { readBody } from "./h3-helpers.js";
|
|
7
|
+
const PROVIDER_TO_ENV_VAR = new Map(Object.entries(PROVIDER_ENV_META).map(([provider, meta]) => [
|
|
8
|
+
provider,
|
|
9
|
+
meta.envVar,
|
|
10
|
+
]));
|
|
11
|
+
const PROVIDER_ENV_VAR_KEYS = new Set(PROVIDER_TO_ENV_VAR.values());
|
|
12
|
+
export function normalizeAgentEngineApiKeyPayload(body) {
|
|
13
|
+
const payload = body && typeof body === "object" ? body : {};
|
|
14
|
+
const raw = payload;
|
|
15
|
+
const key = typeof raw.key === "string"
|
|
16
|
+
? raw.key.trim()
|
|
17
|
+
: typeof raw.provider === "string"
|
|
18
|
+
? (PROVIDER_TO_ENV_VAR.get(raw.provider.trim()) ?? "")
|
|
19
|
+
: "";
|
|
20
|
+
if (!key || !PROVIDER_ENV_VAR_KEYS.has(key)) {
|
|
21
|
+
return {
|
|
22
|
+
ok: false,
|
|
23
|
+
statusCode: 400,
|
|
24
|
+
error: "Unsupported agent engine provider key.",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const value = typeof raw.value === "string"
|
|
28
|
+
? raw.value.trim()
|
|
29
|
+
: typeof raw.apiKey === "string"
|
|
30
|
+
? raw.apiKey.trim()
|
|
31
|
+
: "";
|
|
32
|
+
if (!value) {
|
|
33
|
+
return { ok: false, statusCode: 400, error: "value is required" };
|
|
34
|
+
}
|
|
35
|
+
if (raw.scope != null && raw.scope !== "user" && raw.scope !== "org") {
|
|
36
|
+
return {
|
|
37
|
+
ok: false,
|
|
38
|
+
statusCode: 400,
|
|
39
|
+
error: 'scope must be "user" or "org"',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: true,
|
|
44
|
+
key,
|
|
45
|
+
value,
|
|
46
|
+
scope: raw.scope === "org" ? "org" : "user",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function resolveAgentEngineApiKeyWriteTarget(event, scope) {
|
|
50
|
+
const session = await getSession(event).catch(() => null);
|
|
51
|
+
if (!session?.email) {
|
|
52
|
+
return { ok: false, statusCode: 401, error: "Authentication required" };
|
|
53
|
+
}
|
|
54
|
+
if (scope === "user") {
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
target: { scope: "user", scopeId: session.email },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const ctx = await getOrgContext(event).catch(() => null);
|
|
61
|
+
if (!ctx?.orgId) {
|
|
62
|
+
return { ok: false, statusCode: 400, error: "No active organization" };
|
|
63
|
+
}
|
|
64
|
+
if (ctx.role !== "owner" && ctx.role !== "admin") {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
statusCode: 403,
|
|
68
|
+
error: "Only organization owners and admins can set org-scoped keys",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
ok: true,
|
|
73
|
+
target: { scope: "org", scopeId: ctx.orgId },
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function createAgentEngineApiKeyHandler() {
|
|
77
|
+
return defineEventHandler(async (event) => {
|
|
78
|
+
if (getMethod(event) !== "POST") {
|
|
79
|
+
setResponseStatus(event, 405);
|
|
80
|
+
return { error: "Method not allowed" };
|
|
81
|
+
}
|
|
82
|
+
const payload = normalizeAgentEngineApiKeyPayload(await readBody(event).catch(() => ({})));
|
|
83
|
+
if (!payload.ok) {
|
|
84
|
+
setResponseStatus(event, payload.statusCode);
|
|
85
|
+
return { error: payload.error };
|
|
86
|
+
}
|
|
87
|
+
const resolved = await resolveAgentEngineApiKeyWriteTarget(event, payload.scope);
|
|
88
|
+
if (!resolved.ok) {
|
|
89
|
+
setResponseStatus(event, resolved.statusCode);
|
|
90
|
+
return { error: resolved.error };
|
|
91
|
+
}
|
|
92
|
+
await writeAppSecret({
|
|
93
|
+
key: payload.key,
|
|
94
|
+
value: payload.value,
|
|
95
|
+
scope: resolved.target.scope,
|
|
96
|
+
scopeId: resolved.target.scopeId,
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
ok: true,
|
|
100
|
+
key: payload.key,
|
|
101
|
+
scope: resolved.target.scope,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=agent-engine-api-key-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-engine-api-key-route.js","sourceRoot":"","sources":["../../src/server/agent-engine-api-key-route.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,GAElB,MAAM,IAAI,CAAC;AACZ,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,mBAAmB,GAAG,IAAI,GAAG,CACjC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IAC1D,QAAQ;IACR,IAAI,CAAC,MAAM;CACZ,CAAC,CACH,CAAC;AACF,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAC;AASpE,MAAM,UAAU,iCAAiC,CAAC,IAAa;IAQ7D,MAAM,OAAO,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,MAAM,GAAG,GAAG,OAMX,CAAC;IAEF,MAAM,GAAG,GACP,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ;QACzB,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE;QAChB,CAAC,CAAC,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ;YAChC,CAAC,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YACtD,CAAC,CAAC,EAAE,CAAC;IACX,IAAI,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,OAAO;YACL,EAAE,EAAE,KAAK;YACT,UAAU,EAAE,GAAG;YACf,KAAK,EAAE,wCAAwC;SAChD,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GACT,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ;QAC3B,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;QAClB,CAAC,CAAC,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;YAC9B,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE;YACnB,CAAC,CAAC,EAAE,CAAC;IACX,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;IACpE,CAAC;IAED,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACrE,OAAO;YACL,EAAE,EAAE,KAAK;YACT,UAAU,EAAE,GAAG;YACf,KAAK,EAAE,+BAA+B;SACvC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,GAAG;QACH,KAAK;QACL,KAAK,EAAE,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;KAC5C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,KAAc,EACd,KAA6B;IAK7B,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE;SAClD,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC;QAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC;IACzE,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACjD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,UAAU,EAAE,GAAG;YACf,KAAK,EAAE,6DAA6D;SACrE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE;KAC7C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,OAAO,kBAAkB,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QACjD,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE,CAAC;YAChC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,OAAO,GAAG,iCAAiC,CAC/C,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CACxC,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC7C,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,mCAAmC,CACxD,KAAK,EACL,OAAO,CAAC,KAAK,CACd,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;YAC9C,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnC,CAAC;QAED,MAAM,cAAc,CAAC;YACnB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;YAC5B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;SACjC,CAAC,CAAC;QAEH,OAAO;YACL,EAAE,EAAE,IAAI;YACR,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK;SAC7B,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import {\n defineEventHandler,\n getMethod,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\nimport { PROVIDER_ENV_META } from \"../agent/engine/provider-env-vars.js\";\nimport { getOrgContext } from \"../org/context.js\";\nimport { writeAppSecret } from \"../secrets/storage.js\";\nimport { getSession } from \"./auth.js\";\nimport { readBody } from \"./h3-helpers.js\";\n\nconst PROVIDER_TO_ENV_VAR = new Map(\n Object.entries(PROVIDER_ENV_META).map(([provider, meta]) => [\n provider,\n meta.envVar,\n ]),\n);\nconst PROVIDER_ENV_VAR_KEYS = new Set(PROVIDER_TO_ENV_VAR.values());\n\ntype AgentEngineApiKeyScope = \"user\" | \"org\";\n\nexport interface AgentEngineApiKeyWriteTarget {\n scope: AgentEngineApiKeyScope;\n scopeId: string;\n}\n\nexport function normalizeAgentEngineApiKeyPayload(body: unknown):\n | {\n ok: true;\n key: string;\n value: string;\n scope: AgentEngineApiKeyScope;\n }\n | { ok: false; statusCode: number; error: string } {\n const payload = body && typeof body === \"object\" ? body : {};\n const raw = payload as {\n key?: unknown;\n provider?: unknown;\n value?: unknown;\n apiKey?: unknown;\n scope?: unknown;\n };\n\n const key =\n typeof raw.key === \"string\"\n ? raw.key.trim()\n : typeof raw.provider === \"string\"\n ? (PROVIDER_TO_ENV_VAR.get(raw.provider.trim()) ?? \"\")\n : \"\";\n if (!key || !PROVIDER_ENV_VAR_KEYS.has(key)) {\n return {\n ok: false,\n statusCode: 400,\n error: \"Unsupported agent engine provider key.\",\n };\n }\n\n const value =\n typeof raw.value === \"string\"\n ? raw.value.trim()\n : typeof raw.apiKey === \"string\"\n ? raw.apiKey.trim()\n : \"\";\n if (!value) {\n return { ok: false, statusCode: 400, error: \"value is required\" };\n }\n\n if (raw.scope != null && raw.scope !== \"user\" && raw.scope !== \"org\") {\n return {\n ok: false,\n statusCode: 400,\n error: 'scope must be \"user\" or \"org\"',\n };\n }\n\n return {\n ok: true,\n key,\n value,\n scope: raw.scope === \"org\" ? \"org\" : \"user\",\n };\n}\n\nexport async function resolveAgentEngineApiKeyWriteTarget(\n event: H3Event,\n scope: AgentEngineApiKeyScope,\n): Promise<\n | { ok: true; target: AgentEngineApiKeyWriteTarget }\n | { ok: false; statusCode: number; error: string }\n> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) {\n return { ok: false, statusCode: 401, error: \"Authentication required\" };\n }\n\n if (scope === \"user\") {\n return {\n ok: true,\n target: { scope: \"user\", scopeId: session.email },\n };\n }\n\n const ctx = await getOrgContext(event).catch(() => null);\n if (!ctx?.orgId) {\n return { ok: false, statusCode: 400, error: \"No active organization\" };\n }\n if (ctx.role !== \"owner\" && ctx.role !== \"admin\") {\n return {\n ok: false,\n statusCode: 403,\n error: \"Only organization owners and admins can set org-scoped keys\",\n };\n }\n\n return {\n ok: true,\n target: { scope: \"org\", scopeId: ctx.orgId },\n };\n}\n\nexport function createAgentEngineApiKeyHandler() {\n return defineEventHandler(async (event: H3Event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const payload = normalizeAgentEngineApiKeyPayload(\n await readBody(event).catch(() => ({})),\n );\n if (!payload.ok) {\n setResponseStatus(event, payload.statusCode);\n return { error: payload.error };\n }\n\n const resolved = await resolveAgentEngineApiKeyWriteTarget(\n event,\n payload.scope,\n );\n if (!resolved.ok) {\n setResponseStatus(event, resolved.statusCode);\n return { error: resolved.error };\n }\n\n await writeAppSecret({\n key: payload.key,\n value: payload.value,\n scope: resolved.target.scope,\n scopeId: resolved.target.scopeId,\n });\n\n return {\n ok: true,\n key: payload.key,\n scope: resolved.target.scope,\n };\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-routes-plugin.d.ts","sourceRoot":"","sources":["../../src/server/core-routes-plugin.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAuBlC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA+CvD,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"core-routes-plugin.d.ts","sourceRoot":"","sources":["../../src/server/core-routes-plugin.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAuBlC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA+CvD,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AA6DzD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AACvD,eAAO,MAAM,sBAAsB,0BAAqC,CAAC;AACzE,eAAO,MAAM,6BAA6B,+BAA0C,CAAC;AAErF,wBAAgB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAQrE;AAmBD,eAAO,MAAM,kBAAkB,QAAwC,CAAC;AAsHxE,KAAK,6BAA6B,GAAG,CACnC,KAAK,EAAE,OAAO,KACX,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,wBAAsB,oCAAoC,CACxD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE;IACP,cAAc,CAAC,EAAE,6BAA6B,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACjE,EACN,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAsD9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CASf;AAUD,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;wCACoC;IACpC,eAAe,CAAC,EAAE,OAAO,iBAAiB,EAAE,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;IAChF,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,6BAA6B,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,cAAc,CAkiFhB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAE,cAAyC,CAAC"}
|
|
@@ -40,7 +40,8 @@ import { runWithRequestContext } from "./request-context.js";
|
|
|
40
40
|
import { createVoiceProvidersStatusHandler } from "./voice-providers-status.js";
|
|
41
41
|
import { PROVIDER_ENV_META } from "../agent/engine/provider-env-vars.js";
|
|
42
42
|
import { DEFAULT_MODEL } from "../agent/default-model.js";
|
|
43
|
-
import { canUseDeployCredentialFallbackForRequest } from "./credential-provider.js";
|
|
43
|
+
import { canUseDeployCredentialFallbackForRequest, resolveSecret, } from "./credential-provider.js";
|
|
44
|
+
import { createAgentEngineApiKeyHandler } from "./agent-engine-api-key-route.js";
|
|
44
45
|
import { canUpdateAgentLoopSettings, readAgentLoopSettings, resetAgentLoopSettings, validateMaxIterationsInput, writeAgentLoopSettings, } from "../agent/loop-settings.js";
|
|
45
46
|
import { isAgentEngineSettingConfigured, getAgentEngineEntry, detectEngineFromEnv, detectEngineFromUserSecrets, isAgentEnginePackageInstalled, isStoredEngineUsableForRequest, } from "../agent/engine/registry.js";
|
|
46
47
|
import { registerBuiltinEngines } from "../agent/engine/builtin.js";
|
|
@@ -1410,17 +1411,19 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1410
1411
|
/* org module not present in this template */
|
|
1411
1412
|
}
|
|
1412
1413
|
}
|
|
1413
|
-
|
|
1414
|
-
return envKeys.map((cfg) => {
|
|
1414
|
+
return Promise.all(envKeys.map(async (cfg) => {
|
|
1415
1415
|
const isProviderKey = PROVIDER_ENV_VAR_KEYS.has(cfg.key);
|
|
1416
|
+
const configured = isProviderKey
|
|
1417
|
+
? await runWithRequestContext({ userEmail, orgId }, () => resolveSecret(cfg.key).then(Boolean))
|
|
1418
|
+
: !!process.env[cfg.key];
|
|
1416
1419
|
return {
|
|
1417
1420
|
key: cfg.key,
|
|
1418
1421
|
label: cfg.label,
|
|
1419
1422
|
required: cfg.required ?? false,
|
|
1420
|
-
configured
|
|
1423
|
+
configured,
|
|
1421
1424
|
...(cfg.helpText ? { helpText: cfg.helpText } : {}),
|
|
1422
1425
|
};
|
|
1423
|
-
});
|
|
1426
|
+
}));
|
|
1424
1427
|
}));
|
|
1425
1428
|
getH3App(nitroApp).use(`${P}/env-vars`, defineEventHandler(async (event) => {
|
|
1426
1429
|
if (getMethod(event) !== "POST") {
|
|
@@ -1436,7 +1439,7 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1436
1439
|
if (!isEnvVarWriteAllowed()) {
|
|
1437
1440
|
setResponseStatus(event, 403);
|
|
1438
1441
|
return {
|
|
1439
|
-
error: "env-vars endpoint disabled on multi-tenant deployments. Use
|
|
1442
|
+
error: "env-vars endpoint disabled on multi-tenant deployments. Use scoped secrets or credentials for user/org API keys.",
|
|
1440
1443
|
};
|
|
1441
1444
|
}
|
|
1442
1445
|
const body = await readBody(event);
|
|
@@ -1503,6 +1506,7 @@ export function createCoreRoutesPlugin(options = {}) {
|
|
|
1503
1506
|
return { saved: filtered.map((v) => v.key) };
|
|
1504
1507
|
}));
|
|
1505
1508
|
}
|
|
1509
|
+
getH3App(nitroApp).use(`${P}/agent-engine/api-key`, createAgentEngineApiKeyHandler());
|
|
1506
1510
|
// GET /_agent-native/agent-engine/status — reports whether an engine
|
|
1507
1511
|
// is configured (settings row, settings+env, or auto-detected from env).
|
|
1508
1512
|
// The agent-chat UI uses this to skip the onboarding gate for providers
|