@guuey/host 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/agent-entry.d.ts +38 -0
- package/dist/agent-entry.d.ts.map +1 -0
- package/dist/agent-entry.js +87 -0
- package/dist/boot-context.d.ts +50 -0
- package/dist/boot-context.d.ts.map +1 -0
- package/dist/boot-context.js +22 -0
- package/dist/creds.d.ts +26 -0
- package/dist/creds.d.ts.map +1 -0
- package/dist/creds.js +45 -0
- package/dist/frameworks/claude-options.d.ts +149 -0
- package/dist/frameworks/claude-options.d.ts.map +1 -0
- package/dist/frameworks/claude-options.js +208 -0
- package/dist/frameworks/claude-runner.d.ts +3 -0
- package/dist/frameworks/claude-runner.d.ts.map +1 -0
- package/dist/frameworks/claude-runner.js +33 -0
- package/dist/frameworks/claude.d.ts +72 -0
- package/dist/frameworks/claude.d.ts.map +1 -0
- package/dist/frameworks/claude.js +80 -0
- package/dist/frameworks/google-adk.d.ts +105 -0
- package/dist/frameworks/google-adk.d.ts.map +1 -0
- package/dist/frameworks/google-adk.js +269 -0
- package/dist/frameworks/openai-runner.d.ts +3 -0
- package/dist/frameworks/openai-runner.d.ts.map +1 -0
- package/dist/frameworks/openai-runner.js +37 -0
- package/dist/frameworks/openai.d.ts +65 -0
- package/dist/frameworks/openai.d.ts.map +1 -0
- package/dist/frameworks/openai.js +207 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +134 -0
- package/dist/options.d.ts +173 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +248 -0
- package/dist/preamble.d.ts +16 -0
- package/dist/preamble.d.ts.map +1 -0
- package/dist/preamble.js +34 -0
- package/dist/run-openai.d.ts +65 -0
- package/dist/run-openai.d.ts.map +1 -0
- package/dist/run-openai.js +207 -0
- package/dist/run.d.ts +72 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +80 -0
- package/dist/sdk-version.d.ts +5 -0
- package/dist/sdk-version.d.ts.map +1 -0
- package/dist/sdk-version.js +56 -0
- package/package.json +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loqu, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @guuey/host
|
|
2
|
+
|
|
3
|
+
The universal agent host for [guuey.com](https://guuey.com) — the injected
|
|
4
|
+
harness that runs declarative (no-code) and graceful code-mode agents on
|
|
5
|
+
Guuey pods, and locally under `guuey dev --serve`.
|
|
6
|
+
|
|
7
|
+
**You usually don't install this directly.** It arrives two ways:
|
|
8
|
+
|
|
9
|
+
- on Guuey pods, baked into the platform image (`/shared`);
|
|
10
|
+
- locally, as a dependency of [`@guuey/cli`](https://www.npmjs.com/package/@guuey/cli),
|
|
11
|
+
which spawns it so your local loop matches production exactly.
|
|
12
|
+
|
|
13
|
+
## What it does
|
|
14
|
+
|
|
15
|
+
Reads the resolved agent snapshot, lazily loads the runner for the agent's
|
|
16
|
+
framework, drives one turn per invoke, and streams the framework's native
|
|
17
|
+
events to the platform (which normalizes them to AgJSON via
|
|
18
|
+
`@silverprotocol/*`). Frameworks are **optional peer dependencies** — the
|
|
19
|
+
host is orchestration; the runtime comes from the installer (on Guuey, the
|
|
20
|
+
platform's pinned versions; in graceful mode, _your_ project's copy wins).
|
|
21
|
+
|
|
22
|
+
| framework | runner | runtime peer |
|
|
23
|
+
| ------------------- | --------------------------------------------------- | -------------------------------- |
|
|
24
|
+
| `claude-agent-sdk` | Claude Agent SDK loop | `@anthropic-ai/claude-agent-sdk` |
|
|
25
|
+
| `openai-agents-sdk` | OpenAI Agents loop | `@openai/agents` |
|
|
26
|
+
| `google-adk` | official Google ADK (`LlmAgent` + `InMemoryRunner`) | `@google/adk` |
|
|
27
|
+
|
|
28
|
+
## Graceful mode
|
|
29
|
+
|
|
30
|
+
If `guuey.json#agent.entry` names a module, the host imports it and runs
|
|
31
|
+
your framework-native agent — plain export or factory:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import type { GuueyContext } from "@guuey/config";
|
|
35
|
+
export default (guuey: GuueyContext) =>
|
|
36
|
+
new LlmAgent({
|
|
37
|
+
model: guuey.model,
|
|
38
|
+
instruction: guuey.instruction,
|
|
39
|
+
tools: [myTool, ...guuey.mcpToolsets],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Scaffold one with `npm create @guuey/agentic-app`.
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
MIT © Loqu, Inc.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { GuueyContext } from "@guuey/config";
|
|
2
|
+
/**
|
|
3
|
+
* Load a module by absolute path with NODE's own resolution — opaque to
|
|
4
|
+
* bundlers/test transformers (vitest's SSR runner rewrites literal `import()`
|
|
5
|
+
* into its own resolver, which cannot load arbitrary runtime paths under
|
|
6
|
+
* /worker). `createRequire` + Node ≥22.12 `require(esm)` handles both CJS and
|
|
7
|
+
* ESM customer modules synchronously; a module using top-level await is the
|
|
8
|
+
* one unsupported shape (pathological for a per-invoke-loaded agent) and
|
|
9
|
+
* surfaces as Node's own ERR_REQUIRE_ASYNC_MODULE.
|
|
10
|
+
*/
|
|
11
|
+
export declare function nativeLoad(modulePath: string): unknown;
|
|
12
|
+
/** Env var carrying the entry path (relative to the worker root). */
|
|
13
|
+
export declare const AGENT_ENTRY_ENV = "GUUEY_AGENT_ENTRY";
|
|
14
|
+
/** Env var overriding the worker root (defaults to the sandbox mount). */
|
|
15
|
+
export declare const WORKER_ROOT_ENV = "GUUEY_WORKER_ROOT";
|
|
16
|
+
/** The sandbox's worker mount — where builder-mode code lives. */
|
|
17
|
+
export declare const DEFAULT_WORKER_ROOT = "/worker";
|
|
18
|
+
/**
|
|
19
|
+
* Resolve `entry` (from guuey.json, customer-controlled) against the worker
|
|
20
|
+
* root, rejecting anything that escapes it. Returns the absolute entry path.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveAgentEntry(entry: string, workerRoot?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Import the entry module and return its default export. A module without a
|
|
25
|
+
* default export is a contract error with an actionable message.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadAgentEntry(entryPath: string): Promise<unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* Materialize the agent from the entry's default export:
|
|
30
|
+
* - a FUNCTION is the factory form — invoked (and awaited) with the
|
|
31
|
+
* {@link GuueyContext};
|
|
32
|
+
* - anything else is the plain-agent form, used as-is. Platform MCP toolsets
|
|
33
|
+
* are NOT silently injected into a dev-constructed agent (no mutation
|
|
34
|
+
* magic) — when servers are configured but the export is plain, `warn` is
|
|
35
|
+
* called once with the factory-form hint.
|
|
36
|
+
*/
|
|
37
|
+
export declare function materializeAgent<TToolset>(exported: unknown, ctx: GuueyContext<TToolset>, warn: (message: string) => void): Promise<object>;
|
|
38
|
+
//# sourceMappingURL=agent-entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-entry.d.ts","sourceRoot":"","sources":["../src/agent-entry.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,qEAAqE;AACrE,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,0EAA0E;AAC1E,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,kEAAkE;AAClE,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,MAA4B,GAAG,MAAM,CAcjG;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASxE;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAC7C,QAAQ,EAAE,OAAO,EACjB,GAAG,EAAE,YAAY,CAAC,QAAQ,CAAC,EAC3B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graceful-mode agent-entry loading: resolve the dev's module STRICTLY under
|
|
3
|
+
* the worker root, import it, and materialize the agent from its default
|
|
4
|
+
* export (plain agent object or `(GuueyContext) => agent` factory).
|
|
5
|
+
*
|
|
6
|
+
* Security posture: `GUUEY_AGENT_ENTRY` originates from customer-controlled
|
|
7
|
+
* `guuey.json#agent.entry`, so the resolved path MUST stay inside the worker
|
|
8
|
+
* root — traversal (`../…`, absolute escapes) is rejected before any import
|
|
9
|
+
* happens. The boundary this protects is tidiness, not secrecy (the sandbox
|
|
10
|
+
* is the real boundary; the host process holds nothing a full worker would
|
|
11
|
+
* not), but containment is cheap and closes the path-injection class.
|
|
12
|
+
*/
|
|
13
|
+
import { createRequire } from "node:module";
|
|
14
|
+
import { isAbsolute, resolve, sep } from "node:path";
|
|
15
|
+
import { pathToFileURL } from "node:url";
|
|
16
|
+
/**
|
|
17
|
+
* Load a module by absolute path with NODE's own resolution — opaque to
|
|
18
|
+
* bundlers/test transformers (vitest's SSR runner rewrites literal `import()`
|
|
19
|
+
* into its own resolver, which cannot load arbitrary runtime paths under
|
|
20
|
+
* /worker). `createRequire` + Node ≥22.12 `require(esm)` handles both CJS and
|
|
21
|
+
* ESM customer modules synchronously; a module using top-level await is the
|
|
22
|
+
* one unsupported shape (pathological for a per-invoke-loaded agent) and
|
|
23
|
+
* surfaces as Node's own ERR_REQUIRE_ASYNC_MODULE.
|
|
24
|
+
*/
|
|
25
|
+
export function nativeLoad(modulePath) {
|
|
26
|
+
return createRequire(pathToFileURL(modulePath).href)(modulePath);
|
|
27
|
+
}
|
|
28
|
+
/** Env var carrying the entry path (relative to the worker root). */
|
|
29
|
+
export const AGENT_ENTRY_ENV = "GUUEY_AGENT_ENTRY";
|
|
30
|
+
/** Env var overriding the worker root (defaults to the sandbox mount). */
|
|
31
|
+
export const WORKER_ROOT_ENV = "GUUEY_WORKER_ROOT";
|
|
32
|
+
/** The sandbox's worker mount — where builder-mode code lives. */
|
|
33
|
+
export const DEFAULT_WORKER_ROOT = "/worker";
|
|
34
|
+
/**
|
|
35
|
+
* Resolve `entry` (from guuey.json, customer-controlled) against the worker
|
|
36
|
+
* root, rejecting anything that escapes it. Returns the absolute entry path.
|
|
37
|
+
*/
|
|
38
|
+
export function resolveAgentEntry(entry, workerRoot = DEFAULT_WORKER_ROOT) {
|
|
39
|
+
if (isAbsolute(entry)) {
|
|
40
|
+
throw new Error(`@guuey/host: agent.entry must be a path relative to the worker root (got absolute "${entry}").`);
|
|
41
|
+
}
|
|
42
|
+
const root = resolve(workerRoot);
|
|
43
|
+
const resolved = resolve(root, entry);
|
|
44
|
+
if (resolved !== root && !resolved.startsWith(root + sep)) {
|
|
45
|
+
throw new Error(`@guuey/host: agent.entry "${entry}" escapes the worker root (${root}) — traversal is not allowed.`);
|
|
46
|
+
}
|
|
47
|
+
return resolved;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Import the entry module and return its default export. A module without a
|
|
51
|
+
* default export is a contract error with an actionable message.
|
|
52
|
+
*/
|
|
53
|
+
export async function loadAgentEntry(entryPath) {
|
|
54
|
+
const mod = nativeLoad(entryPath);
|
|
55
|
+
if (mod.default === undefined) {
|
|
56
|
+
throw new Error(`@guuey/host: the agent entry (${entryPath}) has no default export. ` +
|
|
57
|
+
`Export your framework-native agent object, or a factory (guuey: GuueyContext) => agent.`);
|
|
58
|
+
}
|
|
59
|
+
return mod.default;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Materialize the agent from the entry's default export:
|
|
63
|
+
* - a FUNCTION is the factory form — invoked (and awaited) with the
|
|
64
|
+
* {@link GuueyContext};
|
|
65
|
+
* - anything else is the plain-agent form, used as-is. Platform MCP toolsets
|
|
66
|
+
* are NOT silently injected into a dev-constructed agent (no mutation
|
|
67
|
+
* magic) — when servers are configured but the export is plain, `warn` is
|
|
68
|
+
* called once with the factory-form hint.
|
|
69
|
+
*/
|
|
70
|
+
export async function materializeAgent(exported, ctx, warn) {
|
|
71
|
+
if (typeof exported === "function") {
|
|
72
|
+
const agent = await exported(ctx);
|
|
73
|
+
if (typeof agent !== "object" || agent === null) {
|
|
74
|
+
throw new Error(`@guuey/host: the agent factory returned ${agent === null ? "null" : typeof agent} — expected the framework-native agent object.`);
|
|
75
|
+
}
|
|
76
|
+
return agent;
|
|
77
|
+
}
|
|
78
|
+
if (typeof exported !== "object" || exported === null) {
|
|
79
|
+
throw new Error(`@guuey/host: the agent entry's default export is ${exported === null ? "null" : typeof exported} — ` +
|
|
80
|
+
`expected an agent object or a factory function.`);
|
|
81
|
+
}
|
|
82
|
+
if (ctx.mcpToolsets.length > 0) {
|
|
83
|
+
warn(`@guuey/host: guuey.json declares ${ctx.mcpToolsets.length} MCP server(s), but the agent entry exports a plain agent — ` +
|
|
84
|
+
`platform MCP toolsets are NOT auto-injected. Export a factory ((guuey) => agent) and spread guuey.mcpToolsets into your tools to use them.`);
|
|
85
|
+
}
|
|
86
|
+
return exported;
|
|
87
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure boot-context builder for `@guuey/host`.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `index.ts` so the env-reading logic is unit-testable without
|
|
5
|
+
* importing the worker entrypoint (which calls `main()` as a top-level side
|
|
6
|
+
* effect). `buildHostContext` is pure — no disk access, no I/O.
|
|
7
|
+
*
|
|
8
|
+
* OSS-legal: no guuey-private imports — only Node built-ins.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Parts of the worker boot context derived from the process environment.
|
|
12
|
+
* Resolved once at worker startup by the entrypoint (`index.ts`); per-invoke
|
|
13
|
+
* context lives on `HostInvoke` + `HostRuntime` in `run.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export interface HostBootContext {
|
|
16
|
+
/**
|
|
17
|
+
* OpenAI API key — or the opaque broker token in hosted mode (the Task 8
|
|
18
|
+
* `buildWorkerEnv` injects it as `OPENAI_API_KEY`). Applied globally to the
|
|
19
|
+
* SDK via `setDefaultOpenAIKey` before the first invoke. `undefined` means
|
|
20
|
+
* no OpenAI credentials are available.
|
|
21
|
+
*/
|
|
22
|
+
openaiKey?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Anthropic API key — the local-dev fallback when the managed-LLM broker is
|
|
25
|
+
* NOT configured. Absent in hosted (broker) mode; present for `guuey dev`
|
|
26
|
+
* and local testing.
|
|
27
|
+
*/
|
|
28
|
+
anthropicApiKey?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Loopback proxy base URL — hosted/broker mode. Task 8 injects this as
|
|
31
|
+
* `ANTHROPIC_BASE_URL` into the worker's env via `buildWorkerEnv`. When
|
|
32
|
+
* present together with `anthropicAuthToken`, the Claude CLI subprocess is
|
|
33
|
+
* routed through the managed-LLM broker; the real API key is intentionally
|
|
34
|
+
* absent so it cannot leak to agent code.
|
|
35
|
+
*/
|
|
36
|
+
anthropicBaseUrl?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Opaque session token for the loopback proxy — hosted/broker mode. Task 8
|
|
39
|
+
* injects this as `ANTHROPIC_AUTH_TOKEN`. Required when `anthropicBaseUrl`
|
|
40
|
+
* is set; ignored when only `anthropicApiKey` is present.
|
|
41
|
+
*/
|
|
42
|
+
anthropicAuthToken?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the host boot context from the process environment. Pure — no side
|
|
46
|
+
* effects, no disk access. Takes `env` as a parameter (rather than reading
|
|
47
|
+
* `process.env` directly) so the function is straightforward to unit-test.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildHostContext(env: NodeJS.ProcessEnv): HostBootContext;
|
|
50
|
+
//# sourceMappingURL=boot-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot-context.d.ts","sourceRoot":"","sources":["../src/boot-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAOxE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure boot-context builder for `@guuey/host`.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `index.ts` so the env-reading logic is unit-testable without
|
|
5
|
+
* importing the worker entrypoint (which calls `main()` as a top-level side
|
|
6
|
+
* effect). `buildHostContext` is pure — no disk access, no I/O.
|
|
7
|
+
*
|
|
8
|
+
* OSS-legal: no guuey-private imports — only Node built-ins.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Build the host boot context from the process environment. Pure — no side
|
|
12
|
+
* effects, no disk access. Takes `env` as a parameter (rather than reading
|
|
13
|
+
* `process.env` directly) so the function is straightforward to unit-test.
|
|
14
|
+
*/
|
|
15
|
+
export function buildHostContext(env) {
|
|
16
|
+
return {
|
|
17
|
+
openaiKey: env.OPENAI_API_KEY,
|
|
18
|
+
anthropicApiKey: env.ANTHROPIC_API_KEY,
|
|
19
|
+
anthropicBaseUrl: env.ANTHROPIC_BASE_URL,
|
|
20
|
+
anthropicAuthToken: env.ANTHROPIC_AUTH_TOKEN,
|
|
21
|
+
};
|
|
22
|
+
}
|
package/dist/creds.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Fs } from "@guuey/worker";
|
|
2
|
+
/**
|
|
3
|
+
* One parsed credential file. The shape is the broker's §7.1 contract — the
|
|
4
|
+
* worker consumes it verbatim without consulting the snapshot (the broker
|
|
5
|
+
* owns ALL resolution including transport).
|
|
6
|
+
*/
|
|
7
|
+
export interface CredentialFile {
|
|
8
|
+
/** The resolved MCP URL (may be scoped `<host>/apps/<id>` for federated ggui). */
|
|
9
|
+
url: string;
|
|
10
|
+
/** Transport the broker selected for this server. */
|
|
11
|
+
transport: "http" | "sse";
|
|
12
|
+
/** Headers to forward — typically `{ authorization: 'Bearer <token>' }`. */
|
|
13
|
+
headers: Record<string, string>;
|
|
14
|
+
/** ISO expiry; informational for the worker (the Router refreshes per invoke). */
|
|
15
|
+
expiresAt?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Read all credential files the Router broker wrote for this invoke. Returns
|
|
19
|
+
* one `{ name, cred }` per valid `.json` file — malformed files are silently
|
|
20
|
+
* skipped (never crash the turn). Missing directory → empty array (no MCP).
|
|
21
|
+
*/
|
|
22
|
+
export declare function listCredentials(fs: Fs): () => Array<{
|
|
23
|
+
name: string;
|
|
24
|
+
cred: CredentialFile;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=creds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"creds.d.ts","sourceRoot":"","sources":["../src/creds.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAExC;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1B,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,CA6B3F"}
|
package/dist/creds.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-neutral credential-file reading, shared by every runner.
|
|
3
|
+
*
|
|
4
|
+
* The Router-side credential broker resolves EVERYTHING (default server,
|
|
5
|
+
* federation, minting, env substitution) and writes one JSON file per MCP
|
|
6
|
+
* server to `<sessionDir>/.guuey/credentials/<server>.json` before each
|
|
7
|
+
* worker spawn. Runners only read and shape — no resolution logic here.
|
|
8
|
+
*/
|
|
9
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
/**
|
|
12
|
+
* Read all credential files the Router broker wrote for this invoke. Returns
|
|
13
|
+
* one `{ name, cred }` per valid `.json` file — malformed files are silently
|
|
14
|
+
* skipped (never crash the turn). Missing directory → empty array (no MCP).
|
|
15
|
+
*/
|
|
16
|
+
export function listCredentials(fs) {
|
|
17
|
+
return () => {
|
|
18
|
+
const dir = join(fs.session, ".guuey", "credentials");
|
|
19
|
+
let names;
|
|
20
|
+
try {
|
|
21
|
+
names = readdirSync(dir).filter((n) => n.endsWith(".json"));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return []; // no cred dir this turn → no MCP.
|
|
25
|
+
}
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const file of names) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(readFileSync(join(dir, file), "utf8"));
|
|
30
|
+
if (typeof parsed === "object" &&
|
|
31
|
+
parsed !== null &&
|
|
32
|
+
!Array.isArray(parsed) &&
|
|
33
|
+
typeof parsed.url === "string" &&
|
|
34
|
+
(parsed.transport === "http" ||
|
|
35
|
+
parsed.transport === "sse")) {
|
|
36
|
+
out.push({ name: file.replace(/\.json$/, ""), cred: parsed });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// malformed file → skip (never crash the turn).
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot → Claude Agent SDK `Options` construction. Lifted from
|
|
3
|
+
* `backend/services/nocode-runtime/src/agent-runner.ts` (the pure-logic half),
|
|
4
|
+
* with the B2-mcp amendment: `@guuey/host` is a THIN CRED-DIR READER. All MCP
|
|
5
|
+
* resolution (default, federation, mint, env-substitution) now lives once on the
|
|
6
|
+
* Router-side credential broker. The worker just reads
|
|
7
|
+
* `<sessionDir>/.guuey/credentials/*.json` (via ctx.listCredentials) and shapes
|
|
8
|
+
* each entry into the framework-neutral `SdkMcpServer` map.
|
|
9
|
+
*
|
|
10
|
+
* Two responsibilities:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Snapshot → SDK options mapping.** Translates the agent.json shape
|
|
13
|
+
* (model, allowedTools, maxTurns, GuueyFS binding) and the cred-dir contents
|
|
14
|
+
* into the Claude Agent SDK's `mcpServers` + `allowedTools` + `maxTurns`.
|
|
15
|
+
* 2. **Cred-dir mapping.** `resolveMcpServers(ctx)` globs the cred dir via
|
|
16
|
+
* `ctx.listCredentials()` → one `SdkMcpServer` per file; ALL the old
|
|
17
|
+
* federation/default/isGguiUrl/env-sub logic is DELETED (Router-side now).
|
|
18
|
+
*
|
|
19
|
+
* OSS-legality: this package imports ONLY `@anthropic-ai/claude-agent-sdk`,
|
|
20
|
+
* `@guuey/worker`, `@guuey/config`, and Node built-ins.
|
|
21
|
+
*/
|
|
22
|
+
import type { CanUseTool, Options, SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
23
|
+
import type { Fs, HistoryMessage, JsonValue } from "@guuey/worker";
|
|
24
|
+
import { type GuueyAgent } from "@guuey/config";
|
|
25
|
+
export type { SDKMessage };
|
|
26
|
+
/**
|
|
27
|
+
* Env-var names the Router injects so agent code reaches the home/app layers
|
|
28
|
+
* portably. Host-owned copies of `@guuey/fs`'s `ENV_HOME_DIR`/`ENV_APP_DIR`
|
|
29
|
+
* (trivial string literals — not imported, to keep this package OSS-legal).
|
|
30
|
+
*/
|
|
31
|
+
export declare const ENV_HOME_DIR = "GUUEY_HOME_DIR";
|
|
32
|
+
export declare const ENV_APP_DIR = "GUUEY_APP_DIR";
|
|
33
|
+
export type { CredentialFile } from "../creds.js";
|
|
34
|
+
import type { CredentialFile } from "../creds.js";
|
|
35
|
+
/**
|
|
36
|
+
* SDK's `mcpServers` value shape — recreated structurally rather than imported
|
|
37
|
+
* because the SDK ships it as part of `Options['mcpServers']` (a record-of-union)
|
|
38
|
+
* and pulling out a single arm is awkward in TS.
|
|
39
|
+
*/
|
|
40
|
+
export type SdkMcpServer = {
|
|
41
|
+
type: "http";
|
|
42
|
+
url: string;
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
alwaysLoad?: boolean;
|
|
45
|
+
} | {
|
|
46
|
+
type: "sse";
|
|
47
|
+
url: string;
|
|
48
|
+
headers?: Record<string, string>;
|
|
49
|
+
alwaysLoad?: boolean;
|
|
50
|
+
} | {
|
|
51
|
+
type: "stdio";
|
|
52
|
+
command: string;
|
|
53
|
+
args?: string[];
|
|
54
|
+
alwaysLoad?: boolean;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* One prior memory record fed into the `<thread_memory>` preamble. Host-owned,
|
|
58
|
+
* minimal projection of `@silverprotocol/core`'s `AgMemoryRecord` (the preamble
|
|
59
|
+
* reads only `key`/`value`). Not imported — OSS-legality.
|
|
60
|
+
*/
|
|
61
|
+
export interface PriorMemoryRecord {
|
|
62
|
+
key?: string;
|
|
63
|
+
value: JsonValue;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Per-invoke context `buildOptions` needs beyond the static snapshot. Sourced by
|
|
67
|
+
* the worker loop from the `invoke` control message + boot env.
|
|
68
|
+
*/
|
|
69
|
+
export interface BuildOptionsContext {
|
|
70
|
+
/** The user message — passed to `query({ prompt })` by the caller. */
|
|
71
|
+
input: string;
|
|
72
|
+
/** Router-vouched end-user identity. */
|
|
73
|
+
identity: {
|
|
74
|
+
userId: string;
|
|
75
|
+
authMode: "anonymous" | "authenticated";
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Anthropic API key — used for local-dev / off-sandbox fallback when
|
|
79
|
+
* `baseUrl` + `authToken` are absent. One of (`baseUrl`+`authToken`) or
|
|
80
|
+
* `apiKey` must be provided; `buildOptions` throws if neither is present.
|
|
81
|
+
*/
|
|
82
|
+
apiKey?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Loopback proxy base URL for the managed-LLM broker (`ANTHROPIC_BASE_URL`).
|
|
85
|
+
* When present together with `authToken`, the Claude CLI subprocess is routed
|
|
86
|
+
* through the broker; the real API key is intentionally omitted from
|
|
87
|
+
* `options.env` so it cannot leak to agent code.
|
|
88
|
+
*/
|
|
89
|
+
baseUrl?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Opaque session token for the loopback proxy (`ANTHROPIC_AUTH_TOKEN`).
|
|
92
|
+
* Required when `baseUrl` is set; ignored when only `apiKey` is present.
|
|
93
|
+
*/
|
|
94
|
+
authToken?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Per-session GuueyFS layer mounts (the invoke's `fs`). When present, the
|
|
97
|
+
* invoke binds `cwd`=session, exposes home+app as `additionalDirectories`,
|
|
98
|
+
* enables the file tools, and injects `GUUEY_*` env. Absent → no FS binding.
|
|
99
|
+
*/
|
|
100
|
+
fs?: Fs;
|
|
101
|
+
/** Recent conversation window for the `<conversation_history>` preamble. */
|
|
102
|
+
history?: HistoryMessage[];
|
|
103
|
+
/** Thread-scoped memory for the `<thread_memory>` preamble (the §1.4 push). */
|
|
104
|
+
priorMemory?: PriorMemoryRecord[];
|
|
105
|
+
/** Prior working-state blob for the `<working_state>` preamble. */
|
|
106
|
+
priorState?: JsonValue;
|
|
107
|
+
/**
|
|
108
|
+
* Returns every credential the Router broker wrote to
|
|
109
|
+
* `<sessionDir>/.guuey/credentials/` this invoke — one `{name, cred}` per
|
|
110
|
+
* usable MCP server. `name` is the filename stem (server name); `cred` is the
|
|
111
|
+
* parsed `CredentialFile`. Injected so option-building stays pure (no disk).
|
|
112
|
+
*/
|
|
113
|
+
listCredentials: () => Array<{
|
|
114
|
+
name: string;
|
|
115
|
+
cred: CredentialFile;
|
|
116
|
+
}>;
|
|
117
|
+
/** Cancels the in-flight `query` when the client disconnects. */
|
|
118
|
+
abortController?: AbortController;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Build the Claude Agent SDK `Options` for one invoke. Pure: all disk/env access
|
|
122
|
+
* is injected via {@link BuildOptionsContext}. Throws on an unresolved `{file}`
|
|
123
|
+
* system prompt or a missing API key (the same loud failures the source had).
|
|
124
|
+
*/
|
|
125
|
+
export declare function buildOptions(snapshot: GuueyAgent, ctx: BuildOptionsContext): Options;
|
|
126
|
+
/**
|
|
127
|
+
* Auto-allow permission callback. Installed when fs is bound and the operator
|
|
128
|
+
* did NOT pin `claude.permissions.mode`, so the default no-code agent's `Bash`
|
|
129
|
+
* (and the file tools) run prompt-free. Returns `{ behavior: 'allow' }` for
|
|
130
|
+
* every request, passing the input through unchanged.
|
|
131
|
+
*
|
|
132
|
+
* Safe because the model's tool surface is already locked down BEFORE the
|
|
133
|
+
* callback ever fires — `tools`/`allowedTools` cap which tools exist,
|
|
134
|
+
* `settingSources:[]` blocks filesystem-loaded settings, `strictMcpConfig`
|
|
135
|
+
* pins the MCP catalog — and the real OS isolation is the Router's bubblewrap
|
|
136
|
+
* jail this whole process runs inside. The callback only collapses the SDK's
|
|
137
|
+
* final interactive "ask" stage (which would otherwise hang a headless pod);
|
|
138
|
+
* the earlier hook/deny-rule stages of the permission flow still run.
|
|
139
|
+
*/
|
|
140
|
+
export declare const autoAllowTool: CanUseTool;
|
|
141
|
+
/**
|
|
142
|
+
* Map the Router-resolved cred files to the framework-neutral SdkMcpServer map.
|
|
143
|
+
* The Router (credential-broker) owns ALL resolution — default, federation, mint,
|
|
144
|
+
* env-substitution; this worker just reads `<session>/.guuey/credentials/*.json`
|
|
145
|
+
* (via ctx.listCredentials) and shapes each entry. Keyed by the server name.
|
|
146
|
+
*/
|
|
147
|
+
export declare function resolveMcpServers(ctx: BuildOptionsContext): Record<string, SdkMcpServer>;
|
|
148
|
+
export { withContextPreamble } from "../preamble.js";
|
|
149
|
+
//# sourceMappingURL=claude-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-options.d.ts","sourceRoot":"","sources":["../../src/frameworks/claude-options.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,KAAK,EAAE,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAE9F,YAAY,EAAE,UAAU,EAAE,CAAC;AAa3B;;;;GAIG;AACH,eAAO,MAAM,YAAY,mBAAmB,CAAC;AAC7C,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAoB3C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACrF;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACpF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9E;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,WAAW,GAAG,eAAe,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,EAAE,CAAC,EAAE,EAAE,CAAC;IACR,4EAA4E;IAC5E,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAClC,mEAAmE;IACnE,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;IACrE,iEAAiE;IACjE,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,mBAAmB,GAAG,OAAO,CA6HpF;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa,EAAE,UACiC,CAAC;AAE9D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAgBxF;AA8BD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|