@slashfi/agents-sdk 0.81.0 → 0.83.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/adk.js +3 -28
- package/dist/adk.js.map +1 -1
- package/dist/cjs/config-store.js +6 -205
- package/dist/cjs/config-store.js.map +1 -1
- package/dist/cjs/define-config.js.map +1 -1
- package/dist/cjs/materialize.js +34 -13
- package/dist/cjs/materialize.js.map +1 -1
- package/dist/cjs/registry-consumer.js +0 -8
- package/dist/cjs/registry-consumer.js.map +1 -1
- package/dist/cjs/server.js +0 -8
- package/dist/cjs/server.js.map +1 -1
- package/dist/config-store.d.ts +0 -14
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +6 -205
- package/dist/config-store.js.map +1 -1
- package/dist/define-config.d.ts +0 -29
- package/dist/define-config.d.ts.map +1 -1
- package/dist/define-config.js.map +1 -1
- package/dist/materialize.d.ts.map +1 -1
- package/dist/materialize.js +34 -13
- package/dist/materialize.js.map +1 -1
- package/dist/registry-consumer.d.ts +0 -10
- package/dist/registry-consumer.d.ts.map +1 -1
- package/dist/registry-consumer.js +0 -8
- package/dist/registry-consumer.js.map +1 -1
- package/dist/server.d.ts +0 -11
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +0 -8
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/src/adk.ts +3 -31
- package/src/config-store.test.ts +0 -185
- package/src/config-store.ts +6 -254
- package/src/define-config.ts +0 -31
- package/src/materialize.ts +37 -13
- package/src/registry-consumer.ts +0 -27
- package/src/server.ts +0 -19
package/dist/config-store.js
CHANGED
|
@@ -32,8 +32,6 @@ const SECRET_PREFIX = "secret:";
|
|
|
32
32
|
* we evaluate satisfaction against the entry's current `config`.
|
|
33
33
|
*
|
|
34
34
|
* Behavior:
|
|
35
|
-
* - `mode: 'proxy'` refs → always true. Auth lives server-side; the
|
|
36
|
-
* proxy is the source of truth, no entry-side fields involved.
|
|
37
35
|
* - Cache miss (no `authFields` for this ref yet) → returns `null`,
|
|
38
36
|
* signaling "I don't know — caller should fall back to its own
|
|
39
37
|
* heuristic or call `auth-status` to populate the cache".
|
|
@@ -51,8 +49,6 @@ const SECRET_PREFIX = "secret:";
|
|
|
51
49
|
export function isRefAuthComplete(entry, cacheEntry, opts) {
|
|
52
50
|
if (typeof entry === "string")
|
|
53
51
|
return false;
|
|
54
|
-
if (entry.mode === "proxy")
|
|
55
|
-
return true;
|
|
56
52
|
const authFields = cacheEntry?.authFields;
|
|
57
53
|
if (!authFields)
|
|
58
54
|
return null;
|
|
@@ -624,78 +620,6 @@ export function createAdk(fs, options = {}) {
|
|
|
624
620
|
return fallback;
|
|
625
621
|
}
|
|
626
622
|
// ==========================================
|
|
627
|
-
// Proxy Routing
|
|
628
|
-
// ==========================================
|
|
629
|
-
/**
|
|
630
|
-
* Find the configured RegistryEntry for a ref, consulting `sourceRegistry`
|
|
631
|
-
* first and falling back to the first registry in config. Returns `null` when
|
|
632
|
-
* the ref is sourced from a raw URL (no registry), in which case proxy routing
|
|
633
|
-
* does not apply.
|
|
634
|
-
*/
|
|
635
|
-
async function findRegistryEntryForRef(entry) {
|
|
636
|
-
const sourceUrl = entry.sourceRegistry?.url;
|
|
637
|
-
if (!sourceUrl)
|
|
638
|
-
return null;
|
|
639
|
-
const config = await readConfig();
|
|
640
|
-
const match = (config.registries ?? []).find((r) => {
|
|
641
|
-
if (typeof r === "string")
|
|
642
|
-
return r === sourceUrl;
|
|
643
|
-
return r.url === sourceUrl;
|
|
644
|
-
});
|
|
645
|
-
if (!match || typeof match === "string")
|
|
646
|
-
return null;
|
|
647
|
-
return match;
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Returns the proxy settings for a ref when its source registry has
|
|
651
|
-
* `proxy` configured. `null` means "run locally".
|
|
652
|
-
*
|
|
653
|
-
* Callers pass `{ preferLocal: true }` to opt out of `mode: 'optional'`
|
|
654
|
-
* proxying when they already hold credentials locally. `mode: 'required'`
|
|
655
|
-
* cannot be bypassed — the registry owns auth server-side and there is
|
|
656
|
-
* nothing useful the local SDK can do.
|
|
657
|
-
*/
|
|
658
|
-
async function resolveProxyForRef(entry, opts) {
|
|
659
|
-
const reg = await findRegistryEntryForRef(entry);
|
|
660
|
-
if (!reg?.proxy)
|
|
661
|
-
return null;
|
|
662
|
-
if (reg.proxy.mode === "optional" && opts?.preferLocal)
|
|
663
|
-
return null;
|
|
664
|
-
return { reg, agent: reg.proxy.agent ?? "@config" };
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Forward an `@config ref` operation to the proxy agent on a remote registry.
|
|
668
|
-
*
|
|
669
|
-
* The remote side speaks the standard adk-tools surface, so the call shape is
|
|
670
|
-
* identical to what the local `ref` API would do — the only difference is
|
|
671
|
-
* that tokens and secrets live server-side. `callRegistry` returns the
|
|
672
|
-
* standard CallAgentResponse envelope: `{ success: true, result }` on
|
|
673
|
-
* success or `{ success: false, error }` on failure. We unwrap once and
|
|
674
|
-
* throw on error so callers get a result that matches the local signature.
|
|
675
|
-
*/
|
|
676
|
-
async function forwardRefOpToProxy(reg, agent, operation, params) {
|
|
677
|
-
const consumer = await buildConsumerForRef({
|
|
678
|
-
ref: "",
|
|
679
|
-
name: "",
|
|
680
|
-
sourceRegistry: { url: reg.url, agentPath: agent },
|
|
681
|
-
});
|
|
682
|
-
const resolved = consumer.registries().find((r) => r.url === reg.url);
|
|
683
|
-
if (!resolved)
|
|
684
|
-
throw new Error(`Registry ${reg.url} not resolvable for proxy forwarding`);
|
|
685
|
-
const response = await consumer.callRegistry(resolved, {
|
|
686
|
-
action: "execute_tool",
|
|
687
|
-
path: agent,
|
|
688
|
-
tool: "ref",
|
|
689
|
-
params: { operation, ...params },
|
|
690
|
-
});
|
|
691
|
-
if (!response.success) {
|
|
692
|
-
const errResponse = response;
|
|
693
|
-
const msg = errResponse.error ?? `Proxy ${agent}.ref(${operation}) failed`;
|
|
694
|
-
throw new Error(msg);
|
|
695
|
-
}
|
|
696
|
-
return response.result;
|
|
697
|
-
}
|
|
698
|
-
// ==========================================
|
|
699
623
|
// Registry API
|
|
700
624
|
// ==========================================
|
|
701
625
|
/**
|
|
@@ -708,42 +632,6 @@ export function createAdk(fs, options = {}) {
|
|
|
708
632
|
return value;
|
|
709
633
|
return `${SECRET_PREFIX}${await encryptSecret(value, options.encryptionKey)}`;
|
|
710
634
|
}
|
|
711
|
-
/**
|
|
712
|
-
* Re-probe a registry with the current stored credentials to see whether it
|
|
713
|
-
* advertises `capabilities.registry.proxy` in its MCP `initialize` response,
|
|
714
|
-
* and persist the proxy config when it does. Safe to call after a successful
|
|
715
|
-
* `auth()` / `authLocal()` — on the add path we skip the proxy probe when
|
|
716
|
-
* auth is required, so this is the second chance to back-fill it.
|
|
717
|
-
*
|
|
718
|
-
* Respects explicit user config: if `proxy` is already set, we leave it
|
|
719
|
-
* alone. Any discovery failure is swallowed — proxy is an optimization,
|
|
720
|
-
* not a correctness requirement.
|
|
721
|
-
*/
|
|
722
|
-
async function discoverProxyAfterAuth(nameOrUrl) {
|
|
723
|
-
const config = await readConfig();
|
|
724
|
-
const target = findRegistry(config.registries ?? [], nameOrUrl);
|
|
725
|
-
if (!target || typeof target === "string")
|
|
726
|
-
return;
|
|
727
|
-
if (target.proxy)
|
|
728
|
-
return;
|
|
729
|
-
try {
|
|
730
|
-
const consumer = await buildConsumer(nameOrUrl);
|
|
731
|
-
const discovered = await consumer.discover(target.url);
|
|
732
|
-
if (!discovered.proxy?.mode)
|
|
733
|
-
return;
|
|
734
|
-
await updateRegistryEntry(nameOrUrl, (existing) => {
|
|
735
|
-
if (existing.proxy)
|
|
736
|
-
return;
|
|
737
|
-
existing.proxy = {
|
|
738
|
-
mode: discovered.proxy.mode,
|
|
739
|
-
...(discovered.proxy.agent && { agent: discovered.proxy.agent }),
|
|
740
|
-
};
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
catch {
|
|
744
|
-
// Proxy probe is best-effort — auth itself already succeeded.
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
635
|
/**
|
|
748
636
|
* Atomic read-modify-write on a registry entry by name or URL. Used by
|
|
749
637
|
* `authLocal` to persist both `auth` and `oauth` together, which `auth()`
|
|
@@ -884,14 +772,10 @@ export function createAdk(fs, options = {}) {
|
|
|
884
772
|
const config = await readConfig();
|
|
885
773
|
const alias = entry.name ?? entry.url;
|
|
886
774
|
const registries = (config.registries ?? []).filter((r) => registryDisplayName(r) !== alias);
|
|
887
|
-
// Probe the registry before saving.
|
|
888
|
-
//
|
|
889
|
-
//
|
|
890
|
-
//
|
|
891
|
-
// 2. Proxy capability — the MCP `initialize` response may advertise
|
|
892
|
-
// `capabilities.registry.proxy`, which auto-populates `proxy`.
|
|
893
|
-
// Users who set `proxy` or `auth` explicitly on the entry always win:
|
|
894
|
-
// discovery only fills in blanks.
|
|
775
|
+
// Probe the registry before saving. If it returns 401 with a
|
|
776
|
+
// WWW-Authenticate / RFC 9728 resource metadata pointer, persist
|
|
777
|
+
// that on `authRequirement` so subsequent ops can refuse early
|
|
778
|
+
// with a friendly message.
|
|
895
779
|
let final = entry;
|
|
896
780
|
let authRequirement;
|
|
897
781
|
const hasUsableAuth = entry.auth && entry.auth.type !== "none"
|
|
@@ -906,30 +790,6 @@ export function createAdk(fs, options = {}) {
|
|
|
906
790
|
final = { ...final, authRequirement };
|
|
907
791
|
}
|
|
908
792
|
}
|
|
909
|
-
if (!entry.proxy && !authRequirement) {
|
|
910
|
-
try {
|
|
911
|
-
const probeConsumer = await createRegistryConsumer({ registries: [entry], refs: [] }, { token: options.token, fetch: options.fetch });
|
|
912
|
-
const resolved = probeConsumer.registries()[0];
|
|
913
|
-
if (resolved) {
|
|
914
|
-
const discovered = await probeConsumer.discover(resolved.url);
|
|
915
|
-
if (discovered.proxy?.mode) {
|
|
916
|
-
final = {
|
|
917
|
-
...final,
|
|
918
|
-
proxy: {
|
|
919
|
-
mode: discovered.proxy.mode,
|
|
920
|
-
...(discovered.proxy.agent && {
|
|
921
|
-
agent: discovered.proxy.agent,
|
|
922
|
-
}),
|
|
923
|
-
},
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
catch {
|
|
929
|
-
// Discovery is best-effort — offline, unreachable, or non-adk
|
|
930
|
-
// registries simply skip proxy auto-configuration.
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
793
|
registries.push(final);
|
|
934
794
|
await writeConfig({ ...config, registries });
|
|
935
795
|
return authRequirement ? { authRequirement } : {};
|
|
@@ -975,8 +835,6 @@ export function createAdk(fs, options = {}) {
|
|
|
975
835
|
existing.auth = updates.auth;
|
|
976
836
|
if (updates.headers)
|
|
977
837
|
existing.headers = { ...existing.headers, ...updates.headers };
|
|
978
|
-
if (updates.proxy !== undefined)
|
|
979
|
-
existing.proxy = updates.proxy;
|
|
980
838
|
return existing;
|
|
981
839
|
});
|
|
982
840
|
if (!found)
|
|
@@ -1076,8 +934,6 @@ export function createAdk(fs, options = {}) {
|
|
|
1076
934
|
}
|
|
1077
935
|
delete existing.authRequirement;
|
|
1078
936
|
});
|
|
1079
|
-
if (updated)
|
|
1080
|
-
await discoverProxyAfterAuth(nameOrUrl);
|
|
1081
937
|
return updated;
|
|
1082
938
|
},
|
|
1083
939
|
async authLocal(nameOrUrl, opts) {
|
|
@@ -1224,7 +1080,6 @@ export function createAdk(fs, options = {}) {
|
|
|
1224
1080
|
};
|
|
1225
1081
|
delete existing.authRequirement;
|
|
1226
1082
|
});
|
|
1227
|
-
await discoverProxyAfterAuth(displayName);
|
|
1228
1083
|
resOut.writeHead(200, { "Content-Type": "text/html" });
|
|
1229
1084
|
resOut.end(renderAuthSuccess(displayName));
|
|
1230
1085
|
server.close();
|
|
@@ -1603,12 +1458,6 @@ export function createAdk(fs, options = {}) {
|
|
|
1603
1458
|
const entry = findRef(config.refs ?? [], name);
|
|
1604
1459
|
if (!entry)
|
|
1605
1460
|
throw new Error(`Ref "${name}" not found`);
|
|
1606
|
-
// Registry-proxied refs: ask the remote @config for state (secrets live
|
|
1607
|
-
// server-side so local inspection would always return "missing").
|
|
1608
|
-
const proxy = await resolveProxyForRef(entry);
|
|
1609
|
-
if (proxy) {
|
|
1610
|
-
return forwardRefOpToProxy(proxy.reg, proxy.agent, "auth-status", { name });
|
|
1611
|
-
}
|
|
1612
1461
|
let security = null;
|
|
1613
1462
|
try {
|
|
1614
1463
|
const consumer = await buildConsumerForRef(entry);
|
|
@@ -1730,25 +1579,6 @@ export function createAdk(fs, options = {}) {
|
|
|
1730
1579
|
const entry = findRef(config.refs ?? [], name);
|
|
1731
1580
|
if (!entry)
|
|
1732
1581
|
throw new Error(`Ref "${name}" not found`);
|
|
1733
|
-
// Registry-proxied auth: forward the start-of-flow to the remote @config
|
|
1734
|
-
// agent. The registry owns the client_id/secret and returns an authorize
|
|
1735
|
-
// URL pointing at the registry's OAuth callback domain, so the user
|
|
1736
|
-
// completes the flow against the registry instead of localhost.
|
|
1737
|
-
const proxy = await resolveProxyForRef(entry, {
|
|
1738
|
-
preferLocal: opts?.preferLocal,
|
|
1739
|
-
});
|
|
1740
|
-
if (proxy) {
|
|
1741
|
-
const params = { name };
|
|
1742
|
-
if (opts?.apiKey !== undefined)
|
|
1743
|
-
params.apiKey = opts.apiKey;
|
|
1744
|
-
if (opts?.credentials)
|
|
1745
|
-
params.credentials = opts.credentials;
|
|
1746
|
-
if (opts?.scopes)
|
|
1747
|
-
params.scopes = opts.scopes;
|
|
1748
|
-
if (opts?.stateContext)
|
|
1749
|
-
params.stateContext = opts.stateContext;
|
|
1750
|
-
return forwardRefOpToProxy(proxy.reg, proxy.agent, "auth", params);
|
|
1751
|
-
}
|
|
1752
1582
|
const status = await ref.authStatus(name);
|
|
1753
1583
|
const security = status.security;
|
|
1754
1584
|
const tryResolve = makeTryResolve({ name, entry, security });
|
|
@@ -2002,32 +1832,16 @@ export function createAdk(fs, options = {}) {
|
|
|
2002
1832
|
return { type: security.type, complete: false };
|
|
2003
1833
|
},
|
|
2004
1834
|
async authLocal(name, opts) {
|
|
2005
|
-
// `ref.auth` is already proxy-aware — for proxied refs it returns
|
|
2006
|
-
// the authorizeUrl that the registry minted against its own
|
|
2007
|
-
// callback domain. Everything below is identical for local and
|
|
2008
|
-
// proxied refs except the last step (polling for the callback),
|
|
2009
|
-
// which only makes sense when we own the redirect URI.
|
|
2010
1835
|
const result = await ref.auth(name);
|
|
2011
1836
|
if (result.complete)
|
|
2012
1837
|
return { complete: true };
|
|
2013
|
-
const config = await readConfig();
|
|
2014
|
-
const entry = findRef(config.refs ?? [], name);
|
|
2015
|
-
const proxy = entry ? await resolveProxyForRef(entry) : null;
|
|
2016
1838
|
const port = options.oauthCallbackPort ?? 8919;
|
|
2017
1839
|
const timeout = opts?.timeoutMs ?? 300_000;
|
|
2018
1840
|
const { createServer } = await import("node:http");
|
|
2019
1841
|
// API key / HTTP auth — local credential form.
|
|
2020
|
-
//
|
|
2021
|
-
// We refuse to serve the form for a proxied ref: the registry
|
|
2022
|
-
// owns the credential store, so the user needs to submit via
|
|
2023
|
-
// whatever UI the registry exposes. Supporting this through the
|
|
2024
|
-
// proxy would need a remote form endpoint — out of scope here.
|
|
2025
1842
|
if (result.fields &&
|
|
2026
1843
|
result.fields.length > 0 &&
|
|
2027
1844
|
result.type !== "oauth2") {
|
|
2028
|
-
if (proxy) {
|
|
2029
|
-
throw new Error(`Ref "${name}" is sourced from a proxied registry; submit credentials through ${proxy.agent} instead of a local form.`);
|
|
2030
|
-
}
|
|
2031
1845
|
return new Promise((resolve, reject) => {
|
|
2032
1846
|
const server = createServer(async (req, res) => {
|
|
2033
1847
|
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
@@ -2089,13 +1903,8 @@ export function createAdk(fs, options = {}) {
|
|
|
2089
1903
|
if (opts?.onAuthorizeUrl) {
|
|
2090
1904
|
opts.onAuthorizeUrl(result.authorizeUrl);
|
|
2091
1905
|
}
|
|
2092
|
-
//
|
|
2093
|
-
//
|
|
2094
|
-
// schedule once the user finishes the remote consent screen.
|
|
2095
|
-
if (proxy)
|
|
2096
|
-
return { complete: false };
|
|
2097
|
-
// Local refs: spin up the callback server on oauthCallbackPort and
|
|
2098
|
-
// block until the OAuth provider redirects back.
|
|
1906
|
+
// Spin up the callback server on oauthCallbackPort and block
|
|
1907
|
+
// until the OAuth provider redirects back.
|
|
2099
1908
|
return new Promise((resolve, reject) => {
|
|
2100
1909
|
const server = createServer(async (req, res) => {
|
|
2101
1910
|
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
@@ -2134,14 +1943,6 @@ export function createAdk(fs, options = {}) {
|
|
|
2134
1943
|
});
|
|
2135
1944
|
},
|
|
2136
1945
|
async refreshToken(name) {
|
|
2137
|
-
// Registry-proxied refs: the remote @config holds the refresh_token.
|
|
2138
|
-
const entryForProxy = await ref.get(name);
|
|
2139
|
-
if (entryForProxy) {
|
|
2140
|
-
const proxy = await resolveProxyForRef(entryForProxy);
|
|
2141
|
-
if (proxy) {
|
|
2142
|
-
return forwardRefOpToProxy(proxy.reg, proxy.agent, "refresh-token", { name });
|
|
2143
|
-
}
|
|
2144
|
-
}
|
|
2145
1946
|
// Read stored refresh_token
|
|
2146
1947
|
const refreshToken = await readRefSecret(name, "refresh_token");
|
|
2147
1948
|
if (!refreshToken)
|