@zvada/agent-server 0.3.0 → 0.3.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zvada/agent-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Harness-agnostic agent execution engine: run Claude Code, Codex (SDK/CLI + app-server), and any ACP agent behind one interface with a normalized event stream, multi-turn sessions, and resume. Root export is the wire contract; /core, /server, /client are the seats.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -4,6 +4,26 @@ import { type ApiKeyStore, apiKeyStore } from "./api-key-store.ts";
|
|
|
4
4
|
/** Placeholder key handed to the agent subprocess; swapped for the real one here. */
|
|
5
5
|
export const PROXY_PLACEHOLDER_KEY = "sk-proxy-managed";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* The `anthropic-beta` capability that must accompany OAuth bearer traffic.
|
|
9
|
+
* Anthropic's gateway guidance: proxies carrying subscription-OAuth requests
|
|
10
|
+
* must advertise this capability or the upstream rejects the bearer token.
|
|
11
|
+
*/
|
|
12
|
+
export const ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
13
|
+
|
|
14
|
+
/** Append a capability to `anthropic-beta` without clobbering existing ones. */
|
|
15
|
+
function appendAnthropicBeta(headers: Headers, capability: string): void {
|
|
16
|
+
const existing = headers.get("anthropic-beta");
|
|
17
|
+
const values = existing
|
|
18
|
+
? existing
|
|
19
|
+
.split(",")
|
|
20
|
+
.map((value) => value.trim())
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
: [];
|
|
23
|
+
if (!values.includes(capability)) values.push(capability);
|
|
24
|
+
headers.set("anthropic-beta", values.join(","));
|
|
25
|
+
}
|
|
26
|
+
|
|
7
27
|
/** Minimal fetch shape (`globalThis.fetch` qualifies; injectable for tests/platforms). */
|
|
8
28
|
export type FetchLike = (
|
|
9
29
|
input: string | URL | Request,
|
|
@@ -68,10 +88,19 @@ export function createAnthropicProxy(
|
|
|
68
88
|
}
|
|
69
89
|
|
|
70
90
|
const headers = new Headers(request.headers);
|
|
71
|
-
headers.set("x-api-key", entry.apiKey);
|
|
72
|
-
headers.delete("authorization");
|
|
73
91
|
headers.delete("host");
|
|
74
92
|
headers.delete("content-length");
|
|
93
|
+
if (entry.kind === "oauth") {
|
|
94
|
+
// Subscription token: bearer auth + the OAuth capability. The
|
|
95
|
+
// x-api-key the CLI sent carries only the placeholder — it must go,
|
|
96
|
+
// or the upstream sees two conflicting credentials.
|
|
97
|
+
headers.delete("x-api-key");
|
|
98
|
+
headers.set("authorization", `Bearer ${entry.apiKey}`);
|
|
99
|
+
appendAnthropicBeta(headers, ANTHROPIC_OAUTH_BETA);
|
|
100
|
+
} else {
|
|
101
|
+
headers.set("x-api-key", entry.apiKey);
|
|
102
|
+
headers.delete("authorization");
|
|
103
|
+
}
|
|
75
104
|
|
|
76
105
|
const init: RequestInit & { duplex?: "half" } = {
|
|
77
106
|
method: request.method,
|
|
@@ -1,20 +1,52 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** How a stored credential is presented to the upstream API. */
|
|
2
|
+
export type ApiCredentialKind = "api_key" | "oauth";
|
|
3
|
+
|
|
4
|
+
/** A real upstream credential + base URL, keyed by an opaque proxy session id. */
|
|
2
5
|
export interface ApiKeyEntry {
|
|
3
6
|
apiKey: string;
|
|
4
7
|
upstreamBaseUrl: string;
|
|
8
|
+
/**
|
|
9
|
+
* `api_key` → sent as `x-api-key` (Anthropic API keys).
|
|
10
|
+
* `oauth` → sent as `Authorization: Bearer` with the OAuth capability
|
|
11
|
+
* advertised in `anthropic-beta` (Claude subscription tokens from
|
|
12
|
+
* `claude setup-token`, `sk-ant-oat01-…`).
|
|
13
|
+
*/
|
|
14
|
+
kind: ApiCredentialKind;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ApiKeyStoreSetOptions {
|
|
18
|
+
upstreamBaseUrl?: string;
|
|
19
|
+
kind?: ApiCredentialKind;
|
|
5
20
|
}
|
|
6
21
|
|
|
7
22
|
/**
|
|
8
23
|
* In-memory map of proxy-session → real credentials. The agent subprocess is
|
|
9
24
|
* given a placeholder key and pointed at the local proxy; the proxy swaps in the
|
|
10
|
-
* real
|
|
11
|
-
* the subprocess environment. (BYOK pattern from the echo/agnt sidecars.)
|
|
25
|
+
* real credential from this store before forwarding upstream, so it never lives
|
|
26
|
+
* in the subprocess environment. (BYOK pattern from the echo/agnt sidecars.)
|
|
27
|
+
* That no-exfiltration property is exactly why subscription OAuth tokens ride
|
|
28
|
+
* the same store instead of the child env: the child keeps the placeholder
|
|
29
|
+
* either way, only the upstream header shape differs.
|
|
12
30
|
*/
|
|
13
31
|
export class ApiKeyStore {
|
|
14
32
|
private readonly entries = new Map<string, ApiKeyEntry>();
|
|
15
33
|
|
|
16
|
-
set(
|
|
17
|
-
|
|
34
|
+
set(
|
|
35
|
+
sessionId: string,
|
|
36
|
+
apiKey: string,
|
|
37
|
+
// A plain string third argument (the base URL) remains supported: the
|
|
38
|
+
// pre-kind signature every existing sidecar call site uses.
|
|
39
|
+
optionsOrBaseUrl: string | ApiKeyStoreSetOptions = {},
|
|
40
|
+
): void {
|
|
41
|
+
const options =
|
|
42
|
+
typeof optionsOrBaseUrl === "string"
|
|
43
|
+
? { upstreamBaseUrl: optionsOrBaseUrl }
|
|
44
|
+
: optionsOrBaseUrl;
|
|
45
|
+
this.entries.set(sessionId, {
|
|
46
|
+
apiKey,
|
|
47
|
+
upstreamBaseUrl: options.upstreamBaseUrl ?? "https://api.anthropic.com",
|
|
48
|
+
kind: options.kind ?? "api_key",
|
|
49
|
+
});
|
|
18
50
|
}
|
|
19
51
|
|
|
20
52
|
get(sessionId: string): ApiKeyEntry | undefined {
|
package/src/core/proxy/index.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// @zvada/agent-server/core/proxy — optional BYOK Anthropic proxy building block.
|
|
2
|
-
export { type ApiKeyEntry, ApiKeyStore, apiKeyStore } from "./api-key-store.ts";
|
|
3
2
|
export {
|
|
3
|
+
type ApiCredentialKind,
|
|
4
|
+
type ApiKeyEntry,
|
|
5
|
+
ApiKeyStore,
|
|
6
|
+
type ApiKeyStoreSetOptions,
|
|
7
|
+
apiKeyStore,
|
|
8
|
+
} from "./api-key-store.ts";
|
|
9
|
+
export {
|
|
10
|
+
ANTHROPIC_OAUTH_BETA,
|
|
4
11
|
type AnthropicProxyOptions,
|
|
5
12
|
createAnthropicProxy,
|
|
6
13
|
PROXY_PLACEHOLDER_KEY,
|