@slashfi/agents-sdk 0.41.7 → 0.41.9
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/cjs/config-store.js +114 -31
- package/dist/cjs/config-store.js.map +1 -1
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +114 -31
- package/dist/config-store.js.map +1 -1
- package/package.json +1 -1
- package/src/config-store.test.ts +237 -0
- package/src/config-store.ts +134 -28
package/src/config-store.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
RefEntry,
|
|
25
25
|
RegistryEntry,
|
|
26
26
|
ResolvedRef,
|
|
27
|
+
ResolvedRegistry,
|
|
27
28
|
} from "./define-config.js";
|
|
28
29
|
import { normalizeRef } from "./define-config.js";
|
|
29
30
|
import { createRegistryConsumer } from "./registry-consumer.js";
|
|
@@ -211,6 +212,28 @@ function refName(entry: RefEntry): string {
|
|
|
211
212
|
return normalizeRef(entry).name;
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Find a ref by name, trying both with and without `@` prefix.
|
|
217
|
+
* Refs may be stored as `@foo` or `foo` depending on how they were added;
|
|
218
|
+
* this ensures lookups work regardless of which form the caller uses.
|
|
219
|
+
*/
|
|
220
|
+
function findRef(refs: RefEntry[], name: string): RefEntry | undefined {
|
|
221
|
+
const match = refs.find((r) => refName(r) === name);
|
|
222
|
+
if (match) return match;
|
|
223
|
+
const alt = name.startsWith("@") ? name.slice(1) : `@${name}`;
|
|
224
|
+
return refs.find((r) => refName(r) === alt);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Match a ref name with @ normalization (for filter/map operations).
|
|
229
|
+
*/
|
|
230
|
+
function refNameMatches(entry: RefEntry, name: string): boolean {
|
|
231
|
+
const n = refName(entry);
|
|
232
|
+
if (n === name) return true;
|
|
233
|
+
const alt = name.startsWith("@") ? name.slice(1) : `@${name}`;
|
|
234
|
+
return n === alt;
|
|
235
|
+
}
|
|
236
|
+
|
|
214
237
|
function registryDisplayName(r: string | RegistryEntry): string {
|
|
215
238
|
return typeof r === "string" ? r : (r.name ?? r.url);
|
|
216
239
|
}
|
|
@@ -287,7 +310,7 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
287
310
|
|
|
288
311
|
async function readRefSecret(name: string, key: string): Promise<string | null> {
|
|
289
312
|
const config = await readConfig();
|
|
290
|
-
const entry = (config.refs ?? []
|
|
313
|
+
const entry = findRef(config.refs ?? [], name);
|
|
291
314
|
const value = entry?.config?.[key];
|
|
292
315
|
if (typeof value !== "string") return null;
|
|
293
316
|
if (value.startsWith(SECRET_PREFIX) && options.encryptionKey) {
|
|
@@ -481,6 +504,59 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
481
504
|
);
|
|
482
505
|
}
|
|
483
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Build a consumer that includes the ref's sourceRegistry if present.
|
|
509
|
+
* This ensures calls/inspect route to the correct registry endpoint.
|
|
510
|
+
*/
|
|
511
|
+
async function buildConsumerForRef(entry: RefEntry): Promise<RegistryConsumer> {
|
|
512
|
+
const config = await readConfig();
|
|
513
|
+
let registries = config.registries ?? [];
|
|
514
|
+
|
|
515
|
+
// If the ref has a sourceRegistry, ensure it's included in the consumer's registries
|
|
516
|
+
if (entry.sourceRegistry?.url) {
|
|
517
|
+
const sourceUrl = entry.sourceRegistry.url;
|
|
518
|
+
const alreadyIncluded = registries.some((r) =>
|
|
519
|
+
typeof r === "string" ? r === sourceUrl : r.url === sourceUrl,
|
|
520
|
+
);
|
|
521
|
+
if (!alreadyIncluded) {
|
|
522
|
+
registries = [...registries, { url: sourceUrl, name: sourceUrl }];
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const resolved = options.encryptionKey
|
|
527
|
+
? await Promise.all(
|
|
528
|
+
registries.map(async (r) => {
|
|
529
|
+
if (typeof r === "string") return r;
|
|
530
|
+
const decrypted = await decryptConfigSecrets(
|
|
531
|
+
r as unknown as Record<string, unknown>,
|
|
532
|
+
options.encryptionKey!,
|
|
533
|
+
);
|
|
534
|
+
return decrypted as unknown as RegistryEntry;
|
|
535
|
+
}),
|
|
536
|
+
)
|
|
537
|
+
: registries;
|
|
538
|
+
|
|
539
|
+
return createRegistryConsumer(
|
|
540
|
+
{ registries: resolved, refs: config.refs ?? [] },
|
|
541
|
+
{ token: options.token },
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Resolve the correct registry for a ref.
|
|
547
|
+
* If the ref has a sourceRegistry, use that; otherwise fall back to the first registry.
|
|
548
|
+
*/
|
|
549
|
+
function resolveRegistryForRef(consumer: RegistryConsumer, entry: RefEntry): ResolvedRegistry {
|
|
550
|
+
const regs = consumer.registries();
|
|
551
|
+
if (entry.sourceRegistry?.url) {
|
|
552
|
+
const match = regs.find((r) => r.url === entry.sourceRegistry!.url);
|
|
553
|
+
if (match) return match;
|
|
554
|
+
}
|
|
555
|
+
const fallback = regs[0];
|
|
556
|
+
if (!fallback) throw new Error("No registry available");
|
|
557
|
+
return fallback;
|
|
558
|
+
}
|
|
559
|
+
|
|
484
560
|
// ==========================================
|
|
485
561
|
// Registry API
|
|
486
562
|
// ==========================================
|
|
@@ -599,9 +675,38 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
599
675
|
const config = await readConfig();
|
|
600
676
|
const hasRegistries = (config.registries ?? []).length > 0;
|
|
601
677
|
|
|
602
|
-
|
|
678
|
+
// Validate scheme is always specified
|
|
679
|
+
if (!entry.scheme) {
|
|
680
|
+
throw new AdkError({
|
|
681
|
+
code: "REF_INVALID",
|
|
682
|
+
message: `Cannot add ref "${entry.ref}": scheme is required`,
|
|
683
|
+
hint: "Specify scheme: 'registry' (with sourceRegistry), 'mcp' (with url), or 'https' (with url)",
|
|
684
|
+
details: { ref: entry.ref },
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Validate scheme-specific requirements
|
|
689
|
+
if (entry.scheme === "registry" && !entry.sourceRegistry?.url) {
|
|
690
|
+
throw new AdkError({
|
|
691
|
+
code: "REF_INVALID",
|
|
692
|
+
message: `Cannot add ref "${entry.ref}": scheme 'registry' requires sourceRegistry`,
|
|
693
|
+
hint: "Provide sourceRegistry: { url: '...', agentPath: '...' }",
|
|
694
|
+
details: { ref: entry.ref, scheme: entry.scheme },
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if ((entry.scheme === "mcp" || entry.scheme === "https") && !entry.url) {
|
|
699
|
+
throw new AdkError({
|
|
700
|
+
code: "REF_INVALID",
|
|
701
|
+
message: `Cannot add ref "${entry.ref}": scheme '${entry.scheme}' requires url`,
|
|
702
|
+
hint: "Provide the direct agent URL with: url: 'https://...'",
|
|
703
|
+
details: { ref: entry.ref, scheme: entry.scheme },
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (hasRegistries || entry.sourceRegistry?.url) {
|
|
603
708
|
try {
|
|
604
|
-
const consumer = await
|
|
709
|
+
const consumer = await buildConsumerForRef(entry);
|
|
605
710
|
const agentToInspect = entry.sourceRegistry?.agentPath ?? entry.ref;
|
|
606
711
|
const info = await consumer.inspect(agentToInspect);
|
|
607
712
|
|
|
@@ -669,7 +774,7 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
669
774
|
const config = await readConfig();
|
|
670
775
|
if (!config.refs?.length) return false;
|
|
671
776
|
const before = config.refs.length;
|
|
672
|
-
const refs = config.refs.filter((r) =>
|
|
777
|
+
const refs = config.refs.filter((r) => !refNameMatches(r, name));
|
|
673
778
|
if (refs.length === before) return false;
|
|
674
779
|
await writeConfig({ ...config, refs });
|
|
675
780
|
return true;
|
|
@@ -682,7 +787,7 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
682
787
|
|
|
683
788
|
async get(name: string): Promise<RefEntry | null> {
|
|
684
789
|
const config = await readConfig();
|
|
685
|
-
return (config.refs ?? []
|
|
790
|
+
return findRef(config.refs ?? [], name) ?? null;
|
|
686
791
|
},
|
|
687
792
|
|
|
688
793
|
async update(name: string, updates: Partial<RefEntry>): Promise<boolean> {
|
|
@@ -690,7 +795,7 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
690
795
|
if (!config.refs?.length) return false;
|
|
691
796
|
let found = false;
|
|
692
797
|
const refs = config.refs.map((r): RefEntry => {
|
|
693
|
-
if (
|
|
798
|
+
if (!refNameMatches(r, name)) return r;
|
|
694
799
|
found = true;
|
|
695
800
|
const updated = { ...r };
|
|
696
801
|
if (updates.url) updated.url = updates.url;
|
|
@@ -707,16 +812,20 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
707
812
|
|
|
708
813
|
async inspect(name: string, opts?: { full?: boolean }): Promise<AgentListing | null> {
|
|
709
814
|
const config = await readConfig();
|
|
710
|
-
const entry = (config.refs ?? []
|
|
815
|
+
const entry = findRef(config.refs ?? [], name);
|
|
711
816
|
if (!entry) throw new Error(`Ref "${name}" not found`);
|
|
712
817
|
|
|
713
|
-
const consumer = await
|
|
714
|
-
return consumer.inspect(
|
|
818
|
+
const consumer = await buildConsumerForRef(entry);
|
|
819
|
+
return consumer.inspect(
|
|
820
|
+
entry.sourceRegistry?.agentPath ?? entry.ref,
|
|
821
|
+
entry.sourceRegistry?.url,
|
|
822
|
+
opts,
|
|
823
|
+
);
|
|
715
824
|
},
|
|
716
825
|
|
|
717
826
|
async call(name: string, tool: string, params?: Record<string, unknown>): Promise<CallAgentResponse> {
|
|
718
827
|
const config = await readConfig();
|
|
719
|
-
const entry = (config.refs ?? []
|
|
828
|
+
const entry = findRef(config.refs ?? [], name);
|
|
720
829
|
if (!entry) throw new Error(`Ref "${name}" not found`);
|
|
721
830
|
|
|
722
831
|
const accessToken = await readRefSecret(name, "access_token");
|
|
@@ -727,13 +836,12 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
727
836
|
return callMcpDirect(entry.url, tool, params ?? {}, accessToken);
|
|
728
837
|
}
|
|
729
838
|
|
|
730
|
-
const consumer = await
|
|
731
|
-
const reg = consumer
|
|
732
|
-
if (!reg) throw new Error("No registry available");
|
|
839
|
+
const consumer = await buildConsumerForRef(entry);
|
|
840
|
+
const reg = resolveRegistryForRef(consumer, entry);
|
|
733
841
|
|
|
734
842
|
return consumer.callRegistry(reg, {
|
|
735
843
|
action: "execute_tool",
|
|
736
|
-
path: entry.ref,
|
|
844
|
+
path: entry.sourceRegistry?.agentPath ?? entry.ref,
|
|
737
845
|
tool,
|
|
738
846
|
params: params ?? {},
|
|
739
847
|
});
|
|
@@ -741,44 +849,42 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
741
849
|
|
|
742
850
|
async resources(name: string): Promise<CallAgentResponse> {
|
|
743
851
|
const config = await readConfig();
|
|
744
|
-
const entry = (config.refs ?? []
|
|
852
|
+
const entry = findRef(config.refs ?? [], name);
|
|
745
853
|
if (!entry) throw new Error(`Ref "${name}" not found`);
|
|
746
854
|
|
|
747
|
-
const consumer = await
|
|
748
|
-
const reg = consumer
|
|
749
|
-
if (!reg) throw new Error("No registry available");
|
|
855
|
+
const consumer = await buildConsumerForRef(entry);
|
|
856
|
+
const reg = resolveRegistryForRef(consumer, entry);
|
|
750
857
|
|
|
751
858
|
return consumer.callRegistry(reg, {
|
|
752
859
|
action: "list_resources",
|
|
753
|
-
path: entry.ref,
|
|
860
|
+
path: entry.sourceRegistry?.agentPath ?? entry.ref,
|
|
754
861
|
});
|
|
755
862
|
},
|
|
756
863
|
|
|
757
864
|
async read(name: string, uris: string[]): Promise<CallAgentResponse> {
|
|
758
865
|
const config = await readConfig();
|
|
759
|
-
const entry = (config.refs ?? []
|
|
866
|
+
const entry = findRef(config.refs ?? [], name);
|
|
760
867
|
if (!entry) throw new Error(`Ref "${name}" not found`);
|
|
761
868
|
|
|
762
|
-
const consumer = await
|
|
763
|
-
const reg = consumer
|
|
764
|
-
if (!reg) throw new Error("No registry available");
|
|
869
|
+
const consumer = await buildConsumerForRef(entry);
|
|
870
|
+
const reg = resolveRegistryForRef(consumer, entry);
|
|
765
871
|
|
|
766
872
|
return consumer.callRegistry(reg, {
|
|
767
873
|
action: "read_resources",
|
|
768
|
-
path: entry.ref,
|
|
874
|
+
path: entry.sourceRegistry?.agentPath ?? entry.ref,
|
|
769
875
|
uris,
|
|
770
876
|
});
|
|
771
877
|
},
|
|
772
878
|
|
|
773
879
|
async authStatus(name: string): Promise<RefAuthStatus> {
|
|
774
880
|
const config = await readConfig();
|
|
775
|
-
const entry = (config.refs ?? []
|
|
881
|
+
const entry = findRef(config.refs ?? [], name);
|
|
776
882
|
if (!entry) throw new Error(`Ref "${name}" not found`);
|
|
777
883
|
|
|
778
884
|
let security: SecuritySchemeSummary | null = null;
|
|
779
885
|
try {
|
|
780
|
-
const consumer = await
|
|
781
|
-
const info = await consumer.inspect(entry.ref);
|
|
886
|
+
const consumer = await buildConsumerForRef(entry);
|
|
887
|
+
const info = await consumer.inspect(entry.sourceRegistry?.agentPath ?? entry.ref);
|
|
782
888
|
if (info?.security) security = info.security;
|
|
783
889
|
} catch {
|
|
784
890
|
// Can't reach registry
|
|
@@ -863,7 +969,7 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
|
|
|
863
969
|
apiKey?: string;
|
|
864
970
|
}): Promise<AuthStartResult> {
|
|
865
971
|
const config = await readConfig();
|
|
866
|
-
const entry = (config.refs ?? []
|
|
972
|
+
const entry = findRef(config.refs ?? [], name);
|
|
867
973
|
if (!entry) throw new Error(`Ref "${name}" not found`);
|
|
868
974
|
|
|
869
975
|
const status = await ref.authStatus(name);
|