@slashfi/agents-sdk 0.16.0 → 0.18.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/dist/agent-definitions/auth.d.ts.map +1 -1
- package/dist/agent-definitions/auth.js +44 -11
- package/dist/agent-definitions/auth.js.map +1 -1
- package/dist/agent-definitions/integrations.d.ts.map +1 -1
- package/dist/agent-definitions/integrations.js +106 -45
- package/dist/agent-definitions/integrations.js.map +1 -1
- package/dist/agent-definitions/remote-registry.d.ts.map +1 -1
- package/dist/agent-definitions/remote-registry.js +174 -45
- package/dist/agent-definitions/remote-registry.js.map +1 -1
- package/dist/agent-definitions/secrets.d.ts.map +1 -1
- package/dist/agent-definitions/secrets.js +1 -4
- package/dist/agent-definitions/secrets.js.map +1 -1
- package/dist/agent-definitions/users.d.ts.map +1 -1
- package/dist/agent-definitions/users.js +14 -3
- package/dist/agent-definitions/users.js.map +1 -1
- package/dist/define-config.d.ts +125 -0
- package/dist/define-config.d.ts.map +1 -0
- package/dist/define-config.js +75 -0
- package/dist/define-config.js.map +1 -0
- package/dist/define.d.ts +11 -2
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +57 -26
- package/dist/define.js.map +1 -1
- package/dist/events.d.ts +133 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +57 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +16 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/integration-interface.d.ts +3 -3
- package/dist/integration-interface.d.ts.map +1 -1
- package/dist/integration-interface.js +29 -21
- package/dist/integration-interface.js.map +1 -1
- package/dist/integrations-store.d.ts +2 -2
- package/dist/integrations-store.d.ts.map +1 -1
- package/dist/integrations-store.js +3 -3
- package/dist/integrations-store.js.map +1 -1
- package/dist/jwt.d.ts.map +1 -1
- package/dist/jwt.js +7 -5
- package/dist/jwt.js.map +1 -1
- package/dist/key-manager.d.ts.map +1 -1
- package/dist/key-manager.js +5 -3
- package/dist/key-manager.js.map +1 -1
- package/dist/oidc-signin.d.ts +32 -0
- package/dist/oidc-signin.d.ts.map +1 -0
- package/dist/oidc-signin.js +138 -0
- package/dist/oidc-signin.js.map +1 -0
- package/dist/registry-consumer.d.ts +104 -0
- package/dist/registry-consumer.d.ts.map +1 -0
- package/dist/registry-consumer.js +230 -0
- package/dist/registry-consumer.js.map +1 -0
- package/dist/registry.d.ts +5 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +76 -4
- package/dist/registry.js.map +1 -1
- package/dist/secret-collection.d.ts.map +1 -1
- package/dist/secret-collection.js.map +1 -1
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +222 -27
- package/dist/server.js.map +1 -1
- package/dist/test-utils/mock-oidc-server.d.ts +36 -0
- package/dist/test-utils/mock-oidc-server.d.ts.map +1 -0
- package/dist/test-utils/mock-oidc-server.js +96 -0
- package/dist/test-utils/mock-oidc-server.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/agent-definitions/auth.ts +106 -38
- package/src/agent-definitions/integrations.ts +201 -73
- package/src/agent-definitions/remote-registry.ts +262 -65
- package/src/agent-definitions/secrets.ts +22 -8
- package/src/agent-definitions/users.ts +16 -4
- package/src/cli.ts +293 -0
- package/src/codegen.test.ts +527 -0
- package/src/codegen.ts +1348 -0
- package/src/consumer.test.ts +536 -0
- package/src/define-config.ts +205 -0
- package/src/define.ts +134 -46
- package/src/events.ts +237 -0
- package/src/index.ts +107 -8
- package/src/integration-interface.ts +52 -28
- package/src/integrations-store.ts +9 -5
- package/src/jwt.ts +48 -19
- package/src/key-manager.test.ts +22 -13
- package/src/key-manager.ts +8 -10
- package/src/oidc-signin.ts +223 -0
- package/src/registry-consumer.ts +413 -0
- package/src/registry.ts +115 -9
- package/src/secret-collection.ts +2 -1
- package/src/server.test.ts +304 -238
- package/src/server.ts +371 -69
- package/src/test-utils/mock-oidc-server.ts +123 -0
- package/src/types.ts +172 -18
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OIDC Sign-In Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements the full OIDC authorization code flow for user sign-in.
|
|
5
|
+
* The server acts as an OIDC Relying Party — users authenticate with
|
|
6
|
+
* an external Identity Provider and receive a server-signed JWT.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* GET /signin/authorize → 302 redirect to IdP
|
|
10
|
+
* GET /signin/callback → exchange code → fetch userinfo → sign JWT → return
|
|
11
|
+
*/
|
|
12
|
+
import { signJwtES256 } from "./jwt.js";
|
|
13
|
+
export function createOIDCSignIn(config) {
|
|
14
|
+
let discoveryCache = null;
|
|
15
|
+
const pendingFlows = new Map();
|
|
16
|
+
async function fetchDiscovery() {
|
|
17
|
+
if (discoveryCache)
|
|
18
|
+
return discoveryCache;
|
|
19
|
+
const url = `${config.issuer}/.well-known/openid-configuration`;
|
|
20
|
+
const res = await fetch(url);
|
|
21
|
+
if (!res.ok)
|
|
22
|
+
throw new Error(`OIDC discovery failed: ${res.status}`);
|
|
23
|
+
discoveryCache = (await res.json());
|
|
24
|
+
return discoveryCache;
|
|
25
|
+
}
|
|
26
|
+
function generateState() {
|
|
27
|
+
const bytes = crypto.getRandomValues(new Uint8Array(24));
|
|
28
|
+
return Buffer.from(bytes).toString("base64url");
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
async handleRequest(req, { baseUrl, signingKey, issuerUrl }) {
|
|
32
|
+
const url = new URL(req.url);
|
|
33
|
+
// ── GET /signin/authorize → redirect to IdP ──
|
|
34
|
+
if (url.pathname === "/signin/authorize" && req.method === "GET") {
|
|
35
|
+
const redirectUri = url.searchParams.get("redirect_uri") ?? "";
|
|
36
|
+
if (!redirectUri) {
|
|
37
|
+
return Response.json({
|
|
38
|
+
error: "invalid_request",
|
|
39
|
+
error_description: "Missing redirect_uri",
|
|
40
|
+
}, { status: 400 });
|
|
41
|
+
}
|
|
42
|
+
const discovery = await fetchDiscovery();
|
|
43
|
+
const state = generateState();
|
|
44
|
+
const nonce = generateState();
|
|
45
|
+
pendingFlows.set(state, {
|
|
46
|
+
redirectUri,
|
|
47
|
+
nonce,
|
|
48
|
+
createdAt: Date.now(),
|
|
49
|
+
});
|
|
50
|
+
// Clean up stale flows (> 10 min)
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
for (const [k, v] of pendingFlows) {
|
|
53
|
+
if (now - v.createdAt > 600_000)
|
|
54
|
+
pendingFlows.delete(k);
|
|
55
|
+
}
|
|
56
|
+
const scopes = config.scopes ?? ["openid", "email", "profile"];
|
|
57
|
+
const callbackUrl = `${baseUrl}/signin/callback`;
|
|
58
|
+
const authUrl = new URL(discovery.authorization_endpoint);
|
|
59
|
+
authUrl.searchParams.set("response_type", "code");
|
|
60
|
+
authUrl.searchParams.set("client_id", config.clientId);
|
|
61
|
+
authUrl.searchParams.set("redirect_uri", callbackUrl);
|
|
62
|
+
authUrl.searchParams.set("scope", scopes.join(" "));
|
|
63
|
+
authUrl.searchParams.set("state", state);
|
|
64
|
+
authUrl.searchParams.set("nonce", nonce);
|
|
65
|
+
return Response.redirect(authUrl.toString(), 302);
|
|
66
|
+
}
|
|
67
|
+
// ── GET /signin/callback → exchange code → userinfo → JWT ──
|
|
68
|
+
if (url.pathname === "/signin/callback" && req.method === "GET") {
|
|
69
|
+
const code = url.searchParams.get("code");
|
|
70
|
+
const state = url.searchParams.get("state");
|
|
71
|
+
const error = url.searchParams.get("error");
|
|
72
|
+
if (error) {
|
|
73
|
+
return Response.json({
|
|
74
|
+
error,
|
|
75
|
+
error_description: url.searchParams.get("error_description") ?? "",
|
|
76
|
+
}, { status: 400 });
|
|
77
|
+
}
|
|
78
|
+
if (!code || !state) {
|
|
79
|
+
return Response.json({
|
|
80
|
+
error: "invalid_request",
|
|
81
|
+
error_description: "Missing code or state",
|
|
82
|
+
}, { status: 400 });
|
|
83
|
+
}
|
|
84
|
+
const flow = pendingFlows.get(state);
|
|
85
|
+
if (!flow) {
|
|
86
|
+
return Response.json({
|
|
87
|
+
error: "invalid_state",
|
|
88
|
+
error_description: "Unknown or expired state",
|
|
89
|
+
}, { status: 400 });
|
|
90
|
+
}
|
|
91
|
+
pendingFlows.delete(state);
|
|
92
|
+
const discovery = await fetchDiscovery();
|
|
93
|
+
const callbackUrl = `${baseUrl}/signin/callback`;
|
|
94
|
+
// Exchange code for tokens
|
|
95
|
+
const tokenRes = await fetch(discovery.token_endpoint, {
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
98
|
+
body: new URLSearchParams({
|
|
99
|
+
grant_type: "authorization_code",
|
|
100
|
+
code,
|
|
101
|
+
redirect_uri: callbackUrl,
|
|
102
|
+
client_id: config.clientId,
|
|
103
|
+
client_secret: config.clientSecret,
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
if (!tokenRes.ok) {
|
|
107
|
+
const text = await tokenRes.text();
|
|
108
|
+
return Response.json({ error: "token_exchange_failed", error_description: text }, { status: 502 });
|
|
109
|
+
}
|
|
110
|
+
const tokens = (await tokenRes.json());
|
|
111
|
+
// Fetch userinfo
|
|
112
|
+
const userinfoRes = await fetch(discovery.userinfo_endpoint, {
|
|
113
|
+
headers: { Authorization: `Bearer ${tokens.access_token}` },
|
|
114
|
+
});
|
|
115
|
+
if (!userinfoRes.ok) {
|
|
116
|
+
return Response.json({
|
|
117
|
+
error: "userinfo_failed",
|
|
118
|
+
error_description: `Status ${userinfoRes.status}`,
|
|
119
|
+
}, { status: 502 });
|
|
120
|
+
}
|
|
121
|
+
const userinfo = (await userinfoRes.json());
|
|
122
|
+
// Sign server JWT with user's identity
|
|
123
|
+
const jwt = await signJwtES256({
|
|
124
|
+
sub: userinfo.sub ?? "unknown",
|
|
125
|
+
name: userinfo.name ?? "unknown",
|
|
126
|
+
scopes: ["*"],
|
|
127
|
+
iss: issuerUrl,
|
|
128
|
+
}, signingKey.privateKey, signingKey.kid, issuerUrl, "1h");
|
|
129
|
+
// Redirect back to the caller with the JWT
|
|
130
|
+
const sep = flow.redirectUri.includes("?") ? "&" : "?";
|
|
131
|
+
return Response.redirect(`${flow.redirectUri}${sep}token=${jwt}`, 302);
|
|
132
|
+
}
|
|
133
|
+
// Not a signin route
|
|
134
|
+
return null;
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=oidc-signin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-signin.js","sourceRoot":"","sources":["../src/oidc-signin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry Consumer — Connects to registries and resolves refs.
|
|
3
|
+
*
|
|
4
|
+
* The consumer reads a `ConsumerConfig`, discovers registries via
|
|
5
|
+
* `/.well-known/configuration`, resolves refs to agent definitions,
|
|
6
|
+
* and provides a unified interface for calling tools across all connected agents.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createRegistryConsumer, defineConfig } from '@slashfi/agents-sdk';
|
|
11
|
+
*
|
|
12
|
+
* const config = defineConfig({
|
|
13
|
+
* registries: ['https://registry.slash.com'],
|
|
14
|
+
* refs: ['notion', { ref: 'postgres', as: 'prod-db', config: { url: '...' } }],
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const consumer = await createRegistryConsumer(config);
|
|
18
|
+
*
|
|
19
|
+
* // List all available agents across registries
|
|
20
|
+
* const available = await consumer.list();
|
|
21
|
+
*
|
|
22
|
+
* // List configured refs
|
|
23
|
+
* const refs = consumer.refs();
|
|
24
|
+
*
|
|
25
|
+
* // Call a tool on a ref
|
|
26
|
+
* const result = await consumer.call('notion', 'search', { query: 'meeting notes' });
|
|
27
|
+
*
|
|
28
|
+
* // Resolve secrets in config values
|
|
29
|
+
* const dbUrl = await consumer.resolveSecret('https://twin.slash.com/secrets/crdb-url');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import type { ConsumerConfig, RefConfig, ResolvedConfig, ResolvedRef, ResolvedRegistry } from "./define-config.js";
|
|
33
|
+
/** Registry well-known configuration (from /.well-known/configuration) */
|
|
34
|
+
export interface RegistryConfiguration {
|
|
35
|
+
issuer: string;
|
|
36
|
+
jwks_uri?: string;
|
|
37
|
+
token_endpoint?: string;
|
|
38
|
+
agents_endpoint?: string;
|
|
39
|
+
call_endpoint?: string;
|
|
40
|
+
supported_grant_types?: string[];
|
|
41
|
+
/** @deprecated Use agents_endpoint + GET /list instead */
|
|
42
|
+
agents?: string[];
|
|
43
|
+
}
|
|
44
|
+
/** An agent definition as listed by a registry */
|
|
45
|
+
export interface AgentListing {
|
|
46
|
+
/** Agent path (e.g., '@notion') */
|
|
47
|
+
path: string;
|
|
48
|
+
/** Description */
|
|
49
|
+
description?: string;
|
|
50
|
+
/** Publisher (registry name) */
|
|
51
|
+
publisher: string;
|
|
52
|
+
/** Tools available */
|
|
53
|
+
tools?: Array<{
|
|
54
|
+
name: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
}>;
|
|
57
|
+
/** Whether it requires auth */
|
|
58
|
+
requiresAuth?: boolean;
|
|
59
|
+
/** Integration config if applicable */
|
|
60
|
+
integration?: {
|
|
61
|
+
provider: string;
|
|
62
|
+
displayName: string;
|
|
63
|
+
category?: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export type SecretResolver = (uri: string, auth?: {
|
|
67
|
+
token?: string;
|
|
68
|
+
}) => Promise<string>;
|
|
69
|
+
export interface RegistryConsumerOptions {
|
|
70
|
+
/** Override the secret resolver (default: HTTP GET + JWT) */
|
|
71
|
+
resolveSecret?: SecretResolver;
|
|
72
|
+
/** Bearer token for authenticated registries */
|
|
73
|
+
token?: string;
|
|
74
|
+
/** Custom fetch implementation */
|
|
75
|
+
fetch?: typeof globalThis.fetch;
|
|
76
|
+
}
|
|
77
|
+
export interface RegistryConsumer {
|
|
78
|
+
/** List all available agents across all connected registries */
|
|
79
|
+
list(): Promise<AgentListing[]>;
|
|
80
|
+
/** List configured refs (from the consumer's config) */
|
|
81
|
+
refs(): ResolvedRef[];
|
|
82
|
+
/** Get the resolved registries */
|
|
83
|
+
registries(): ResolvedRegistry[];
|
|
84
|
+
/** Call a tool on a configured ref */
|
|
85
|
+
call(refName: string, tool: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
86
|
+
/** Discover a registry's configuration */
|
|
87
|
+
discover(registryUrl: string): Promise<RegistryConfiguration>;
|
|
88
|
+
/** Resolve a secret URL to its value */
|
|
89
|
+
resolveSecret(url: string): Promise<string>;
|
|
90
|
+
/** Resolve all secret URLs in a config object, returning resolved values */
|
|
91
|
+
resolveConfig(config: RefConfig): Promise<Record<string, string | number | boolean>>;
|
|
92
|
+
/** Produce the indexed/serialized config output */
|
|
93
|
+
index(): ResolvedConfig;
|
|
94
|
+
/** Diff: what's available vs what's configured */
|
|
95
|
+
available(): Promise<AgentListing[]>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Create a registry consumer from a config.
|
|
99
|
+
*
|
|
100
|
+
* The consumer connects to registries, discovers available agents,
|
|
101
|
+
* and provides a unified interface for calling tools.
|
|
102
|
+
*/
|
|
103
|
+
export declare function createRegistryConsumer(config: ConsumerConfig, options?: RegistryConsumerOptions): Promise<RegistryConsumer>;
|
|
104
|
+
//# sourceMappingURL=registry-consumer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-consumer.d.ts","sourceRoot":"","sources":["../src/registry-consumer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,cAAc,EACd,WAAW,EACX,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAW5B,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,+BAA+B;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uCAAuC;IACvC,WAAW,CAAC,EAAE;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AASD,MAAM,MAAM,cAAc,GAAG,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KACtB,OAAO,CAAC,MAAM,CAAC,CAAC;AAoDrB,MAAM,WAAW,uBAAuB;IACtC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,cAAc,CAAC;IAE/B,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAMD,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAEhC,wDAAwD;IACxD,IAAI,IAAI,WAAW,EAAE,CAAC;IAEtB,kCAAkC;IAClC,UAAU,IAAI,gBAAgB,EAAE,CAAC;IAEjC,sCAAsC;IACtC,IAAI,CACF,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,0CAA0C;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAE9D,wCAAwC;IACxC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5C,4EAA4E;IAC5E,aAAa,CACX,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAEtD,mDAAmD;IACnD,KAAK,IAAI,cAAc,CAAC;IAExB,kDAAkD;IAClD,SAAS,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,gBAAgB,CAAC,CAiM3B"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry Consumer — Connects to registries and resolves refs.
|
|
3
|
+
*
|
|
4
|
+
* The consumer reads a `ConsumerConfig`, discovers registries via
|
|
5
|
+
* `/.well-known/configuration`, resolves refs to agent definitions,
|
|
6
|
+
* and provides a unified interface for calling tools across all connected agents.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createRegistryConsumer, defineConfig } from '@slashfi/agents-sdk';
|
|
11
|
+
*
|
|
12
|
+
* const config = defineConfig({
|
|
13
|
+
* registries: ['https://registry.slash.com'],
|
|
14
|
+
* refs: ['notion', { ref: 'postgres', as: 'prod-db', config: { url: '...' } }],
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const consumer = await createRegistryConsumer(config);
|
|
18
|
+
*
|
|
19
|
+
* // List all available agents across registries
|
|
20
|
+
* const available = await consumer.list();
|
|
21
|
+
*
|
|
22
|
+
* // List configured refs
|
|
23
|
+
* const refs = consumer.refs();
|
|
24
|
+
*
|
|
25
|
+
* // Call a tool on a ref
|
|
26
|
+
* const result = await consumer.call('notion', 'search', { query: 'meeting notes' });
|
|
27
|
+
*
|
|
28
|
+
* // Resolve secrets in config values
|
|
29
|
+
* const dbUrl = await consumer.resolveSecret('https://twin.slash.com/secrets/crdb-url');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import { isSecretUrl, normalizeRef, normalizeRegistry, } from "./define-config.js";
|
|
33
|
+
// ============================================
|
|
34
|
+
// Secret Resolver
|
|
35
|
+
// ============================================
|
|
36
|
+
/** Resolves secret URLs to their values */
|
|
37
|
+
import { readFile } from "node:fs/promises";
|
|
38
|
+
/**
|
|
39
|
+
* Default secret resolver — dispatches on URI scheme:
|
|
40
|
+
* file:// → read from filesystem
|
|
41
|
+
* env:// → read from environment variable
|
|
42
|
+
* https:// → HTTP GET with optional bearer token
|
|
43
|
+
* http:// → HTTP GET (dev only)
|
|
44
|
+
*/
|
|
45
|
+
async function defaultSecretResolver(uri, auth) {
|
|
46
|
+
const parsed = new URL(uri);
|
|
47
|
+
switch (parsed.protocol) {
|
|
48
|
+
case "file:": {
|
|
49
|
+
const filePath = parsed.pathname;
|
|
50
|
+
return (await readFile(filePath, "utf-8")).trim();
|
|
51
|
+
}
|
|
52
|
+
case "env:": {
|
|
53
|
+
// env://VAR_NAME or env:///VAR_NAME
|
|
54
|
+
const varName = parsed.hostname || parsed.pathname.replace(/^\//, "");
|
|
55
|
+
const value = process.env[varName];
|
|
56
|
+
if (!value) {
|
|
57
|
+
throw new Error(`Environment variable not set: ${varName}`);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
case "https:":
|
|
62
|
+
case "http:": {
|
|
63
|
+
const headers = {};
|
|
64
|
+
if (auth?.token) {
|
|
65
|
+
headers.Authorization = `Bearer ${auth.token}`;
|
|
66
|
+
}
|
|
67
|
+
const res = await fetch(uri, { headers });
|
|
68
|
+
if (!res.ok) {
|
|
69
|
+
throw new Error(`Failed to resolve secret ${uri}: ${res.status} ${res.statusText}`);
|
|
70
|
+
}
|
|
71
|
+
return res.text();
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
throw new Error(`Unsupported secret URI scheme: ${parsed.protocol}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create a registry consumer from a config.
|
|
79
|
+
*
|
|
80
|
+
* The consumer connects to registries, discovers available agents,
|
|
81
|
+
* and provides a unified interface for calling tools.
|
|
82
|
+
*/
|
|
83
|
+
export async function createRegistryConsumer(config, options = {}) {
|
|
84
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
85
|
+
const resolveSecretFn = options.resolveSecret ?? defaultSecretResolver;
|
|
86
|
+
// Normalize registries
|
|
87
|
+
const resolvedRegistries = (config.registries ?? []).map(normalizeRegistry);
|
|
88
|
+
// Normalize refs
|
|
89
|
+
const resolvedRefs = (config.refs ?? []).map((entry) => {
|
|
90
|
+
const normalized = normalizeRef(entry);
|
|
91
|
+
return {
|
|
92
|
+
ref: normalized.ref,
|
|
93
|
+
name: normalized.name,
|
|
94
|
+
registry: normalized.registry ?? resolvedRegistries[0]?.url ?? "unknown",
|
|
95
|
+
config: normalized.config,
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
// Cache for registry configurations
|
|
99
|
+
const discoveryCache = new Map();
|
|
100
|
+
// Discover a registry
|
|
101
|
+
async function discover(registryUrl) {
|
|
102
|
+
const cached = discoveryCache.get(registryUrl);
|
|
103
|
+
if (cached)
|
|
104
|
+
return cached;
|
|
105
|
+
const url = `${registryUrl.replace(/\/$/, "")}/.well-known/configuration`;
|
|
106
|
+
const res = await fetchFn(url);
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
throw new Error(`Failed to discover registry ${registryUrl}: ${res.status}`);
|
|
109
|
+
}
|
|
110
|
+
const configuration = (await res.json());
|
|
111
|
+
discoveryCache.set(registryUrl, configuration);
|
|
112
|
+
return configuration;
|
|
113
|
+
}
|
|
114
|
+
// List agents from a single registry
|
|
115
|
+
async function listFromRegistry(registry) {
|
|
116
|
+
const configuration = await discover(registry.url);
|
|
117
|
+
const listUrl = configuration.agents_endpoint ??
|
|
118
|
+
`${registry.url.replace(/\/$/, "")}/list`;
|
|
119
|
+
const headers = {};
|
|
120
|
+
if (registry.auth.type === "bearer" && "token" in registry.auth) {
|
|
121
|
+
headers.Authorization = `Bearer ${registry.auth.token}`;
|
|
122
|
+
}
|
|
123
|
+
else if (options.token) {
|
|
124
|
+
headers.Authorization = `Bearer ${options.token}`;
|
|
125
|
+
}
|
|
126
|
+
const res = await fetchFn(listUrl, { headers });
|
|
127
|
+
if (!res.ok) {
|
|
128
|
+
throw new Error(`Failed to list agents from ${registry.url}: ${res.status}`);
|
|
129
|
+
}
|
|
130
|
+
const agents = (await res.json());
|
|
131
|
+
return agents.map((agent) => ({
|
|
132
|
+
...agent,
|
|
133
|
+
publisher: registry.publisher,
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
// Call a tool via a registry
|
|
137
|
+
async function callTool(registry, agentPath, tool, params) {
|
|
138
|
+
const configuration = await discover(registry.url);
|
|
139
|
+
const callUrl = configuration.call_endpoint ?? `${registry.url.replace(/\/$/, "")}/call`;
|
|
140
|
+
const headers = {
|
|
141
|
+
"Content-Type": "application/json",
|
|
142
|
+
};
|
|
143
|
+
if (registry.auth.type === "bearer" && "token" in registry.auth) {
|
|
144
|
+
headers.Authorization = `Bearer ${registry.auth.token}`;
|
|
145
|
+
}
|
|
146
|
+
else if (options.token) {
|
|
147
|
+
headers.Authorization = `Bearer ${options.token}`;
|
|
148
|
+
}
|
|
149
|
+
const res = await fetchFn(callUrl, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers,
|
|
152
|
+
body: JSON.stringify({ path: agentPath, tool, params }),
|
|
153
|
+
});
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
const text = await res.text().catch(() => "unknown error");
|
|
156
|
+
throw new Error(`Tool call failed (${registry.url}/${agentPath}/${tool}): ${res.status} ${text}`);
|
|
157
|
+
}
|
|
158
|
+
return res.json();
|
|
159
|
+
}
|
|
160
|
+
// Build the consumer
|
|
161
|
+
const consumer = {
|
|
162
|
+
async list() {
|
|
163
|
+
const results = await Promise.allSettled(resolvedRegistries.map(listFromRegistry));
|
|
164
|
+
return results.flatMap((r) => (r.status === "fulfilled" ? r.value : []));
|
|
165
|
+
},
|
|
166
|
+
refs() {
|
|
167
|
+
return resolvedRefs;
|
|
168
|
+
},
|
|
169
|
+
registries() {
|
|
170
|
+
return resolvedRegistries;
|
|
171
|
+
},
|
|
172
|
+
async call(refName, tool, params = {}) {
|
|
173
|
+
const ref = resolvedRefs.find((r) => r.name === refName);
|
|
174
|
+
if (!ref) {
|
|
175
|
+
throw new Error(`Ref "${refName}" not found in config. Available: ${resolvedRefs.map((r) => r.name).join(", ")}`);
|
|
176
|
+
}
|
|
177
|
+
const registry = resolvedRegistries.find((r) => r.url === ref.registry);
|
|
178
|
+
if (!registry) {
|
|
179
|
+
throw new Error(`Registry "${ref.registry}" not found for ref "${refName}"`);
|
|
180
|
+
}
|
|
181
|
+
return callTool(registry, ref.ref, tool, params);
|
|
182
|
+
},
|
|
183
|
+
discover,
|
|
184
|
+
async resolveSecret(url) {
|
|
185
|
+
return resolveSecretFn(url, { token: options.token });
|
|
186
|
+
},
|
|
187
|
+
async resolveConfig(config) {
|
|
188
|
+
const resolved = {};
|
|
189
|
+
for (const [key, value] of Object.entries(config)) {
|
|
190
|
+
if (isSecretUrl(value)) {
|
|
191
|
+
resolved[key] = await resolveSecretFn(value, {
|
|
192
|
+
token: options.token,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
resolved[key] = value;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return resolved;
|
|
200
|
+
},
|
|
201
|
+
index() {
|
|
202
|
+
return {
|
|
203
|
+
resolvedAt: new Date().toISOString(),
|
|
204
|
+
sourceHash: simpleHash(JSON.stringify(config)),
|
|
205
|
+
registries: resolvedRegistries,
|
|
206
|
+
refs: resolvedRefs,
|
|
207
|
+
meta: config.meta,
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
async available() {
|
|
211
|
+
const all = await consumer.list();
|
|
212
|
+
const configuredRefs = new Set(resolvedRefs.map((r) => r.ref));
|
|
213
|
+
return all.filter((a) => !configuredRefs.has(a.path));
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
return consumer;
|
|
217
|
+
}
|
|
218
|
+
// ============================================
|
|
219
|
+
// Utilities
|
|
220
|
+
// ============================================
|
|
221
|
+
/** Simple hash for cache invalidation (not cryptographic) */
|
|
222
|
+
function simpleHash(str) {
|
|
223
|
+
let hash = 0;
|
|
224
|
+
for (let i = 0; i < str.length; i++) {
|
|
225
|
+
const char = str.charCodeAt(i);
|
|
226
|
+
hash = ((hash << 5) - hash + char) | 0;
|
|
227
|
+
}
|
|
228
|
+
return Math.abs(hash).toString(36);
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=registry-consumer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-consumer.js","sourceRoot":"","sources":["../src/registry-consumer.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages registered agents and handles callAgent requests.
|
|
5
5
|
*/
|
|
6
|
+
import type { AgentEvent, EventCallback, EventType } from "./events.js";
|
|
6
7
|
import type { AgentDefinition, CallAgentLoadRequest, CallAgentLoadResponse, CallAgentRequest, CallAgentResponse, Visibility } from "./types.js";
|
|
7
8
|
/**
|
|
8
9
|
* Middleware hooks for registry lifecycle actions.
|
|
@@ -43,6 +44,10 @@ export interface AgentRegistry {
|
|
|
43
44
|
listPaths(): string[];
|
|
44
45
|
/** Call an agent (execute action) */
|
|
45
46
|
call(request: CallAgentRequest): Promise<CallAgentResponse>;
|
|
47
|
+
/** Register an event listener (global scope — fires for all agents) */
|
|
48
|
+
on<T extends EventType>(eventType: T, callback: EventCallback<T>): void;
|
|
49
|
+
/** Emit an event to all listeners. Used by the runtime to push lifecycle events. */
|
|
50
|
+
emit(event: AgentEvent): Promise<void>;
|
|
46
51
|
}
|
|
47
52
|
/**
|
|
48
53
|
* Create an agent registry.
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAEV,eAAe,EAMf,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EAIjB,UAAU,EACX,MAAM,YAAY,CAAC;AAapB;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,CACL,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACV,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAEV,eAAe,EAMf,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EAIjB,UAAU,EACX,MAAM,YAAY,CAAC;AAapB;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,CACL,SAAS,EAAE,CACT,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,qBAAqB,CAAC,EACnC,GAAG,EAAE;QACH,KAAK,EAAE,eAAe,CAAC;QACvB,OAAO,EAAE,oBAAoB,CAAC;QAC9B,QAAQ,EAAE,aAAa,CAAC;KACzB,KACE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B,mEAAmE;IACnE,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,iCAAiC;IACjC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wBAAwB;IACxB,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAEvC,2BAA2B;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAE/C,+BAA+B;IAC/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,iCAAiC;IACjC,IAAI,IAAI,eAAe,EAAE,CAAC;IAE1B,sCAAsC;IACtC,SAAS,IAAI,MAAM,EAAE,CAAC;IAEtB,qCAAqC;IACrC,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAE5D,uEAAuE;IACvE,EAAE,CAAC,CAAC,SAAS,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAExE,oFAAoF;IACpF,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAMD;;;;;;;;;;;;;;;GAeG;AACH;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,OAAO,YAAY,EAAE,WAAW,KACtC,OAAO,YAAY,EAAE,WAAW,CAAC;AAEtC,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,oBAAyB,GACjC,aAAa,CAmff"}
|
package/dist/registry.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Manages registered agents and handles callAgent requests.
|
|
5
5
|
*/
|
|
6
6
|
import { dirname, resolve } from "node:path";
|
|
7
|
+
import { createEventBus } from "./events.js";
|
|
7
8
|
/** Default supported actions if not specified */
|
|
8
9
|
const DEFAULT_SUPPORTED_ACTIONS = [
|
|
9
10
|
"execute_tool",
|
|
@@ -13,6 +14,7 @@ const DEFAULT_SUPPORTED_ACTIONS = [
|
|
|
13
14
|
export function createAgentRegistry(options = {}) {
|
|
14
15
|
const { defaultVisibility = "internal" } = options;
|
|
15
16
|
const agents = new Map();
|
|
17
|
+
const eventBus = createEventBus();
|
|
16
18
|
/**
|
|
17
19
|
* Check if agent supports the requested action.
|
|
18
20
|
*/
|
|
@@ -167,6 +169,26 @@ export function createAgentRegistry(options = {}) {
|
|
|
167
169
|
const registry = {
|
|
168
170
|
register(agent) {
|
|
169
171
|
agents.set(agent.path, agent);
|
|
172
|
+
// Collect agent-level listeners into the bus
|
|
173
|
+
if (agent._listeners) {
|
|
174
|
+
for (const entry of agent._listeners) {
|
|
175
|
+
eventBus._onScoped(entry.eventType, entry.callback, {
|
|
176
|
+
agentPath: agent.path,
|
|
177
|
+
toolName: entry.toolScope,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Collect tool-level listeners into the bus
|
|
182
|
+
for (const tool of agent.tools) {
|
|
183
|
+
if (tool._listeners) {
|
|
184
|
+
for (const entry of tool._listeners) {
|
|
185
|
+
eventBus._onScoped(entry.eventType, entry.callback, {
|
|
186
|
+
agentPath: agent.path,
|
|
187
|
+
toolName: tool.name,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
170
192
|
},
|
|
171
193
|
get(path) {
|
|
172
194
|
return agents.get(path);
|
|
@@ -180,6 +202,12 @@ export function createAgentRegistry(options = {}) {
|
|
|
180
202
|
listPaths() {
|
|
181
203
|
return Array.from(agents.keys());
|
|
182
204
|
},
|
|
205
|
+
on(eventType, callback) {
|
|
206
|
+
eventBus.on(eventType, callback);
|
|
207
|
+
},
|
|
208
|
+
async emit(event) {
|
|
209
|
+
await eventBus.emit(event);
|
|
210
|
+
},
|
|
183
211
|
async call(request) {
|
|
184
212
|
const agent = agents.get(request.path);
|
|
185
213
|
if (!agent) {
|
|
@@ -266,16 +294,56 @@ export function createAgentRegistry(options = {}) {
|
|
|
266
294
|
error: `Tool ${request.tool} has no execute function`,
|
|
267
295
|
};
|
|
268
296
|
}
|
|
269
|
-
|
|
297
|
+
// Emit tool/call before execution
|
|
298
|
+
const startMs = Date.now();
|
|
299
|
+
await eventBus.emit({
|
|
300
|
+
type: "tool/call",
|
|
301
|
+
agentPath: agent.path,
|
|
302
|
+
tool: request.tool,
|
|
303
|
+
params: request.params,
|
|
304
|
+
timestamp: startMs,
|
|
305
|
+
});
|
|
306
|
+
let result;
|
|
307
|
+
try {
|
|
308
|
+
result = await tool.execute(request.params, ctx);
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
// Emit tool/error on failure
|
|
312
|
+
await eventBus.emit({
|
|
313
|
+
type: "tool/error",
|
|
314
|
+
agentPath: agent.path,
|
|
315
|
+
tool: request.tool,
|
|
316
|
+
params: request.params,
|
|
317
|
+
error: err,
|
|
318
|
+
durationMs: Date.now() - startMs,
|
|
319
|
+
timestamp: Date.now(),
|
|
320
|
+
}).catch(() => { }); // don't let emit error mask tool error
|
|
321
|
+
return {
|
|
322
|
+
success: false,
|
|
323
|
+
error: err instanceof Error ? err.message : String(err),
|
|
324
|
+
code: "TOOL_EXECUTION_ERROR",
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
// Emit tool/result after success
|
|
328
|
+
await eventBus.emit({
|
|
329
|
+
type: "tool/result",
|
|
330
|
+
agentPath: agent.path,
|
|
331
|
+
tool: request.tool,
|
|
332
|
+
params: request.params,
|
|
333
|
+
result,
|
|
334
|
+
durationMs: Date.now() - startMs,
|
|
335
|
+
timestamp: Date.now(),
|
|
336
|
+
});
|
|
270
337
|
return {
|
|
271
338
|
success: true,
|
|
272
339
|
result,
|
|
273
340
|
};
|
|
274
341
|
}
|
|
275
|
-
catch (
|
|
342
|
+
catch (outerErr) {
|
|
343
|
+
// Catch-all for unexpected errors (e.g., emit failures)
|
|
276
344
|
return {
|
|
277
345
|
success: false,
|
|
278
|
-
error:
|
|
346
|
+
error: outerErr instanceof Error ? outerErr.message : String(outerErr),
|
|
279
347
|
code: "TOOL_EXECUTION_ERROR",
|
|
280
348
|
};
|
|
281
349
|
}
|
|
@@ -297,7 +365,11 @@ export function createAgentRegistry(options = {}) {
|
|
|
297
365
|
}
|
|
298
366
|
case "load": {
|
|
299
367
|
if (options.middleware?.load) {
|
|
300
|
-
return options.middleware.load(defaultLoad, {
|
|
368
|
+
return options.middleware.load(defaultLoad, {
|
|
369
|
+
agent,
|
|
370
|
+
request,
|
|
371
|
+
registry,
|
|
372
|
+
});
|
|
301
373
|
}
|
|
302
374
|
return defaultLoad(agent, request);
|
|
303
375
|
}
|