@slashfi/agents-sdk 0.77.2 → 0.78.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-tools.d.ts.map +1 -1
- package/dist/adk-tools.js +104 -253
- package/dist/adk-tools.js.map +1 -1
- package/dist/call-agent-schema.d.ts +12 -12
- package/dist/cjs/adk-tools.js +104 -253
- package/dist/cjs/adk-tools.js.map +1 -1
- package/dist/cjs/config-store.js +333 -94
- package/dist/cjs/config-store.js.map +1 -1
- package/dist/cjs/define-config.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/registry.js +2 -33
- package/dist/cjs/registry.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/config-store.d.ts +34 -4
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +333 -94
- package/dist/config-store.js.map +1 -1
- package/dist/define-config.d.ts +28 -4
- package/dist/define-config.d.ts.map +1 -1
- package/dist/define-config.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +2 -33
- package/dist/registry.js.map +1 -1
- package/dist/types.d.ts +3 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/adk-tools.ts +113 -282
- package/src/config-store.test.ts +345 -28
- package/src/config-store.ts +829 -274
- package/src/define-config.ts +47 -21
- package/src/index.ts +16 -13
- package/src/ref-naming.test.ts +1 -49
- package/src/registry.ts +2 -40
- package/src/types.ts +6 -21
package/src/config-store.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import type { FsStore } from "./agent-definitions/config";
|
|
2
3
|
import {
|
|
3
4
|
createAdk,
|
|
4
5
|
createAdkTools,
|
|
@@ -8,7 +9,6 @@ import {
|
|
|
8
9
|
defineTool,
|
|
9
10
|
} from "./index";
|
|
10
11
|
import type { AgentServer } from "./index";
|
|
11
|
-
import type { FsStore } from "./agent-definitions/config";
|
|
12
12
|
|
|
13
13
|
// ─── Helpers ─────────────────────────────────────────────────────
|
|
14
14
|
|
|
@@ -146,7 +146,8 @@ describe("ADK ref sourceRegistry routing", () => {
|
|
|
146
146
|
// Inspect should find the agent on the source server
|
|
147
147
|
const info = await adk.ref.inspect("@math");
|
|
148
148
|
expect(info).toBeDefined();
|
|
149
|
-
const toolCount =
|
|
149
|
+
const toolCount =
|
|
150
|
+
(info?.tools?.length ?? 0) + (info?.toolSummaries?.length ?? 0);
|
|
150
151
|
expect(toolCount).toBeGreaterThan(0);
|
|
151
152
|
});
|
|
152
153
|
});
|
|
@@ -158,9 +159,9 @@ describe("ADK ref.add validation", () => {
|
|
|
158
159
|
const fs = createMemoryFs();
|
|
159
160
|
const adk = createAdk(fs);
|
|
160
161
|
|
|
161
|
-
await expect(
|
|
162
|
-
|
|
163
|
-
)
|
|
162
|
+
await expect(adk.ref.add({ ref: "@something" })).rejects.toThrow(
|
|
163
|
+
"could not determine connection type",
|
|
164
|
+
);
|
|
164
165
|
});
|
|
165
166
|
|
|
166
167
|
test("throws when scheme is 'registry' without sourceRegistry", async () => {
|
|
@@ -254,7 +255,10 @@ describe("ADK ref.call() auto-refresh on 401", () => {
|
|
|
254
255
|
execute: async () => {
|
|
255
256
|
callCount++;
|
|
256
257
|
if (callCount === 1) {
|
|
257
|
-
return {
|
|
258
|
+
return {
|
|
259
|
+
content: [{ type: "text", text: '{"error":"401 Unauthorized"}' }],
|
|
260
|
+
_httpStatus: 401,
|
|
261
|
+
};
|
|
258
262
|
}
|
|
259
263
|
return { data: "success", callNumber: callCount };
|
|
260
264
|
},
|
|
@@ -352,19 +356,29 @@ describe("ADK ref.call() full auto-refresh flow", () => {
|
|
|
352
356
|
const body = await req.text();
|
|
353
357
|
const params = new URLSearchParams(body);
|
|
354
358
|
if (params.get("grant_type") !== "refresh_token") {
|
|
355
|
-
return new Response(
|
|
359
|
+
return new Response(
|
|
360
|
+
JSON.stringify({ error: "unsupported_grant_type" }),
|
|
361
|
+
{ status: 400 },
|
|
362
|
+
);
|
|
356
363
|
}
|
|
357
364
|
if (params.get("refresh_token") !== "my-refresh-token") {
|
|
358
|
-
return new Response(JSON.stringify({ error: "invalid_grant" }), {
|
|
365
|
+
return new Response(JSON.stringify({ error: "invalid_grant" }), {
|
|
366
|
+
status: 400,
|
|
367
|
+
});
|
|
359
368
|
}
|
|
360
369
|
if (params.get("client_id") !== "my-client-id") {
|
|
361
|
-
return new Response(JSON.stringify({ error: "invalid_client" }), {
|
|
370
|
+
return new Response(JSON.stringify({ error: "invalid_client" }), {
|
|
371
|
+
status: 401,
|
|
372
|
+
});
|
|
362
373
|
}
|
|
363
|
-
return new Response(
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
374
|
+
return new Response(
|
|
375
|
+
JSON.stringify({
|
|
376
|
+
access_token: "refreshed-token",
|
|
377
|
+
token_type: "Bearer",
|
|
378
|
+
expires_in: 3600,
|
|
379
|
+
}),
|
|
380
|
+
{ headers: { "Content-Type": "application/json" } },
|
|
381
|
+
);
|
|
368
382
|
},
|
|
369
383
|
});
|
|
370
384
|
|
|
@@ -377,12 +391,18 @@ describe("ADK ref.call() full auto-refresh flow", () => {
|
|
|
377
391
|
toolCallCount++;
|
|
378
392
|
const token = input?.accessToken;
|
|
379
393
|
if (token === "expired-token" || !token) {
|
|
380
|
-
return {
|
|
394
|
+
return {
|
|
395
|
+
content: [{ type: "text", text: '{"error":"401 Unauthorized"}' }],
|
|
396
|
+
_httpStatus: 401,
|
|
397
|
+
};
|
|
381
398
|
}
|
|
382
399
|
if (token === "refreshed-token") {
|
|
383
400
|
return { message: "success", token };
|
|
384
401
|
}
|
|
385
|
-
return {
|
|
402
|
+
return {
|
|
403
|
+
content: [{ type: "text", text: '{"error":"403 Forbidden"}' }],
|
|
404
|
+
_httpStatus: 403,
|
|
405
|
+
};
|
|
386
406
|
},
|
|
387
407
|
});
|
|
388
408
|
|
|
@@ -420,12 +440,20 @@ describe("ADK ref.call() full auto-refresh flow", () => {
|
|
|
420
440
|
tokenRefreshCount = 0;
|
|
421
441
|
|
|
422
442
|
const fs = createMemoryFs();
|
|
423
|
-
const adk = createAdk(fs, {
|
|
443
|
+
const adk = createAdk(fs, {
|
|
444
|
+
encryptionKey: "test-key-32-chars-long-enough!!",
|
|
445
|
+
});
|
|
424
446
|
|
|
425
|
-
await adk.registry.add({
|
|
447
|
+
await adk.registry.add({
|
|
448
|
+
name: "oauth-reg",
|
|
449
|
+
url: `http://localhost:${REG_PORT}`,
|
|
450
|
+
});
|
|
426
451
|
await adk.ref.add({
|
|
427
452
|
ref: "oauth-api",
|
|
428
|
-
sourceRegistry: {
|
|
453
|
+
sourceRegistry: {
|
|
454
|
+
url: `http://localhost:${REG_PORT}`,
|
|
455
|
+
agentPath: "oauth-api",
|
|
456
|
+
},
|
|
429
457
|
});
|
|
430
458
|
|
|
431
459
|
// Store credentials directly
|
|
@@ -599,7 +627,9 @@ describe("ADK registry proxy routing", () => {
|
|
|
599
627
|
proxy: { mode: "optional", agent: "@custom" },
|
|
600
628
|
});
|
|
601
629
|
|
|
602
|
-
const entry = (await adk.registry.list()).find(
|
|
630
|
+
const entry = (await adk.registry.list()).find(
|
|
631
|
+
(r) => r.name === "cloud-explicit",
|
|
632
|
+
);
|
|
603
633
|
expect(entry?.proxy?.mode).toBe("optional");
|
|
604
634
|
expect(entry?.proxy?.agent).toBe("@custom");
|
|
605
635
|
});
|
|
@@ -694,10 +724,9 @@ describe("ADK registry auth lifecycle", () => {
|
|
|
694
724
|
if (grant === "refresh_token") {
|
|
695
725
|
tokenRefreshCount++;
|
|
696
726
|
if (body.get("refresh_token") !== "refresh-token-v1") {
|
|
697
|
-
return new Response(
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
);
|
|
727
|
+
return new Response(JSON.stringify({ error: "invalid_grant" }), {
|
|
728
|
+
status: 400,
|
|
729
|
+
});
|
|
701
730
|
}
|
|
702
731
|
// Rotate to a new access token so the test can tell refresh ran.
|
|
703
732
|
activeAccessToken = "access-token-v2";
|
|
@@ -716,7 +745,9 @@ describe("ADK registry auth lifecycle", () => {
|
|
|
716
745
|
const expected = `Bearer ${activeAccessToken}`;
|
|
717
746
|
if (auth !== expected) {
|
|
718
747
|
return new Response(
|
|
719
|
-
JSON.stringify({
|
|
748
|
+
JSON.stringify({
|
|
749
|
+
error: { code: "UNAUTHORIZED", message: "No token" },
|
|
750
|
+
}),
|
|
720
751
|
{
|
|
721
752
|
status: 401,
|
|
722
753
|
headers: {
|
|
@@ -744,7 +775,11 @@ describe("ADK registry auth lifecycle", () => {
|
|
|
744
775
|
type: "text",
|
|
745
776
|
text: JSON.stringify({
|
|
746
777
|
agents: [
|
|
747
|
-
{
|
|
778
|
+
{
|
|
779
|
+
path: "@test-agent",
|
|
780
|
+
description: "An agent",
|
|
781
|
+
toolCount: 1,
|
|
782
|
+
},
|
|
748
783
|
],
|
|
749
784
|
}),
|
|
750
785
|
},
|
|
@@ -766,7 +801,9 @@ describe("ADK registry auth lifecycle", () => {
|
|
|
766
801
|
|
|
767
802
|
test("registry.add records auth challenge; browse refuses; auth() unlocks", async () => {
|
|
768
803
|
const fs = createMemoryFs();
|
|
769
|
-
const adk = createAdk(fs, {
|
|
804
|
+
const adk = createAdk(fs, {
|
|
805
|
+
encryptionKey: "test-key-32-chars-long-enough!!",
|
|
806
|
+
});
|
|
770
807
|
|
|
771
808
|
const addResult = await adk.registry.add({ name: "test", url: MCP_URL });
|
|
772
809
|
|
|
@@ -795,7 +832,9 @@ describe("ADK registry auth lifecycle", () => {
|
|
|
795
832
|
|
|
796
833
|
test("browse 401 triggers refresh via stored refresh_token and retries", async () => {
|
|
797
834
|
const fs = createMemoryFs();
|
|
798
|
-
const adk = createAdk(fs, {
|
|
835
|
+
const adk = createAdk(fs, {
|
|
836
|
+
encryptionKey: "test-key-32-chars-long-enough!!",
|
|
837
|
+
});
|
|
799
838
|
|
|
800
839
|
// Reset server-side token so the next refresh rotates predictably.
|
|
801
840
|
activeAccessToken = "access-token-v1";
|
|
@@ -838,3 +877,281 @@ describe("ADK registry auth lifecycle", () => {
|
|
|
838
877
|
expect((stored?.auth as { token: string }).token).toMatch(/^secret:/);
|
|
839
878
|
});
|
|
840
879
|
});
|
|
880
|
+
|
|
881
|
+
// ─── ADK ref registry cache ──────────────────────────────────────
|
|
882
|
+
|
|
883
|
+
describe("ADK ref registry cache", () => {
|
|
884
|
+
let server: AgentServer;
|
|
885
|
+
const PORT = 19940;
|
|
886
|
+
|
|
887
|
+
// Agents configured with descriptions so the registry's describe_tools
|
|
888
|
+
// response carries metadata for the cache to capture.
|
|
889
|
+
const cachedMathAgent = defineAgent({
|
|
890
|
+
path: "@cached-math",
|
|
891
|
+
entrypoint: "Math agent",
|
|
892
|
+
tools: [add],
|
|
893
|
+
visibility: "public",
|
|
894
|
+
config: { description: "Adds numbers together" },
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
const cachedEchoAgent = defineAgent({
|
|
898
|
+
path: "@cached-echo",
|
|
899
|
+
entrypoint: "Echo agent",
|
|
900
|
+
tools: [echo],
|
|
901
|
+
visibility: "public",
|
|
902
|
+
config: { description: "Echoes back the input" },
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
beforeAll(async () => {
|
|
906
|
+
const registry = createAgentRegistry();
|
|
907
|
+
registry.register(cachedMathAgent);
|
|
908
|
+
registry.register(cachedEchoAgent);
|
|
909
|
+
server = createAgentServer(registry, { port: PORT });
|
|
910
|
+
await server.start();
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
afterAll(async () => {
|
|
914
|
+
await server.stop();
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
test("ref.add populates registry-cache.json with description and slim tools", async () => {
|
|
918
|
+
const fs = createMemoryFs();
|
|
919
|
+
const adk = createAdk(fs);
|
|
920
|
+
|
|
921
|
+
await adk.registry.add({
|
|
922
|
+
url: `http://localhost:${PORT}`,
|
|
923
|
+
name: "main",
|
|
924
|
+
});
|
|
925
|
+
await adk.ref.add({
|
|
926
|
+
ref: "@cached-math",
|
|
927
|
+
scheme: "registry",
|
|
928
|
+
sourceRegistry: {
|
|
929
|
+
url: `http://localhost:${PORT}`,
|
|
930
|
+
agentPath: "@cached-math",
|
|
931
|
+
},
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
const cacheRaw = await fs.readFile("registry-cache.json");
|
|
935
|
+
expect(cacheRaw).not.toBeNull();
|
|
936
|
+
const cache = JSON.parse(cacheRaw!);
|
|
937
|
+
const entry = cache.refs["@cached-math"];
|
|
938
|
+
expect(entry).toBeDefined();
|
|
939
|
+
expect(entry.ref).toBe("@cached-math");
|
|
940
|
+
expect(entry.description).toBe("Adds numbers together");
|
|
941
|
+
expect(entry.tools).toBeDefined();
|
|
942
|
+
expect(entry.tools.length).toBeGreaterThan(0);
|
|
943
|
+
expect(entry.tools[0].name).toBe("add");
|
|
944
|
+
expect(entry.tools[0].description).toBe("Add two numbers");
|
|
945
|
+
// inputSchema MUST NOT leak into the cache — that's our whole point.
|
|
946
|
+
expect(entry.tools[0]).not.toHaveProperty("inputSchema");
|
|
947
|
+
expect(typeof entry.fetchedAt).toBe("string");
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
test("ref.list hydrates description and tools from cache", async () => {
|
|
951
|
+
const fs = createMemoryFs();
|
|
952
|
+
const adk = createAdk(fs);
|
|
953
|
+
|
|
954
|
+
await adk.registry.add({
|
|
955
|
+
url: `http://localhost:${PORT}`,
|
|
956
|
+
name: "main",
|
|
957
|
+
});
|
|
958
|
+
await adk.ref.add({
|
|
959
|
+
ref: "@cached-math",
|
|
960
|
+
scheme: "registry",
|
|
961
|
+
sourceRegistry: {
|
|
962
|
+
url: `http://localhost:${PORT}`,
|
|
963
|
+
agentPath: "@cached-math",
|
|
964
|
+
},
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
const refs = await adk.ref.list();
|
|
968
|
+
expect(refs).toHaveLength(1);
|
|
969
|
+
expect(refs[0].name).toBe("@cached-math");
|
|
970
|
+
expect(refs[0].description).toBe("Adds numbers together");
|
|
971
|
+
expect(refs[0].tools).toBeDefined();
|
|
972
|
+
expect(refs[0].tools?.[0].name).toBe("add");
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
test("ref.list returns description undefined when cache is empty", async () => {
|
|
976
|
+
const fs = createMemoryFs();
|
|
977
|
+
// Seed a ref directly into consumer-config without a cache entry — this is
|
|
978
|
+
// the "existing user, fresh cache" case (e.g. before the backfill runs).
|
|
979
|
+
await fs.writeFile(
|
|
980
|
+
"consumer-config.json",
|
|
981
|
+
JSON.stringify({
|
|
982
|
+
refs: [
|
|
983
|
+
{
|
|
984
|
+
ref: "@cached-math",
|
|
985
|
+
name: "@cached-math",
|
|
986
|
+
scheme: "registry",
|
|
987
|
+
sourceRegistry: {
|
|
988
|
+
url: `http://localhost:${PORT}`,
|
|
989
|
+
agentPath: "@cached-math",
|
|
990
|
+
},
|
|
991
|
+
},
|
|
992
|
+
],
|
|
993
|
+
}),
|
|
994
|
+
);
|
|
995
|
+
|
|
996
|
+
const adk = createAdk(fs);
|
|
997
|
+
const refs = await adk.ref.list();
|
|
998
|
+
expect(refs).toHaveLength(1);
|
|
999
|
+
expect(refs[0].description).toBeUndefined();
|
|
1000
|
+
expect(refs[0].tools).toBeUndefined();
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
test("ref.get hydrates a single ref from the cache", async () => {
|
|
1004
|
+
const fs = createMemoryFs();
|
|
1005
|
+
const adk = createAdk(fs);
|
|
1006
|
+
|
|
1007
|
+
await adk.registry.add({
|
|
1008
|
+
url: `http://localhost:${PORT}`,
|
|
1009
|
+
name: "main",
|
|
1010
|
+
});
|
|
1011
|
+
await adk.ref.add({
|
|
1012
|
+
ref: "@cached-math",
|
|
1013
|
+
scheme: "registry",
|
|
1014
|
+
sourceRegistry: {
|
|
1015
|
+
url: `http://localhost:${PORT}`,
|
|
1016
|
+
agentPath: "@cached-math",
|
|
1017
|
+
},
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
const ref = await adk.ref.get("@cached-math");
|
|
1021
|
+
expect(ref).not.toBeNull();
|
|
1022
|
+
expect(ref?.description).toBe("Adds numbers together");
|
|
1023
|
+
expect(ref?.tools?.[0].name).toBe("add");
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
test("ref.inspect refreshes the cache for the inspected ref", async () => {
|
|
1027
|
+
const fs = createMemoryFs();
|
|
1028
|
+
const adk = createAdk(fs);
|
|
1029
|
+
|
|
1030
|
+
await adk.registry.add({
|
|
1031
|
+
url: `http://localhost:${PORT}`,
|
|
1032
|
+
name: "main",
|
|
1033
|
+
});
|
|
1034
|
+
// Seed without registry add-time inspect (use bare config seeding) so the
|
|
1035
|
+
// cache starts empty and we can see ref.inspect populate it.
|
|
1036
|
+
await fs.writeFile(
|
|
1037
|
+
"consumer-config.json",
|
|
1038
|
+
JSON.stringify({
|
|
1039
|
+
registries: [{ url: `http://localhost:${PORT}`, name: "main" }],
|
|
1040
|
+
refs: [
|
|
1041
|
+
{
|
|
1042
|
+
ref: "@cached-math",
|
|
1043
|
+
name: "@cached-math",
|
|
1044
|
+
scheme: "registry",
|
|
1045
|
+
sourceRegistry: {
|
|
1046
|
+
url: `http://localhost:${PORT}`,
|
|
1047
|
+
agentPath: "@cached-math",
|
|
1048
|
+
},
|
|
1049
|
+
},
|
|
1050
|
+
],
|
|
1051
|
+
}),
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
// Cache is empty before inspect.
|
|
1055
|
+
const beforeRefs = await adk.ref.list();
|
|
1056
|
+
expect(beforeRefs[0].description).toBeUndefined();
|
|
1057
|
+
|
|
1058
|
+
// Inspect populates the cache.
|
|
1059
|
+
const info = await adk.ref.inspect("@cached-math");
|
|
1060
|
+
expect(info).toBeDefined();
|
|
1061
|
+
|
|
1062
|
+
const afterRefs = await adk.ref.list();
|
|
1063
|
+
expect(afterRefs[0].description).toBe("Adds numbers together");
|
|
1064
|
+
expect(afterRefs[0].tools?.[0].name).toBe("add");
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
test("ref.inspect with full: true does not leak inputSchema into the cache", async () => {
|
|
1068
|
+
const fs = createMemoryFs();
|
|
1069
|
+
const adk = createAdk(fs);
|
|
1070
|
+
|
|
1071
|
+
await adk.registry.add({
|
|
1072
|
+
url: `http://localhost:${PORT}`,
|
|
1073
|
+
name: "main",
|
|
1074
|
+
});
|
|
1075
|
+
await adk.ref.add({
|
|
1076
|
+
ref: "@cached-math",
|
|
1077
|
+
scheme: "registry",
|
|
1078
|
+
sourceRegistry: {
|
|
1079
|
+
url: `http://localhost:${PORT}`,
|
|
1080
|
+
agentPath: "@cached-math",
|
|
1081
|
+
},
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
// Caller gets the full schema in the response…
|
|
1085
|
+
const full = await adk.ref.inspect("@cached-math", { full: true });
|
|
1086
|
+
expect(full?.tools?.[0]).toHaveProperty("inputSchema");
|
|
1087
|
+
|
|
1088
|
+
// …but the cache stays slim.
|
|
1089
|
+
const cacheRaw = await fs.readFile("registry-cache.json");
|
|
1090
|
+
const cache = JSON.parse(cacheRaw!);
|
|
1091
|
+
const entry = cache.refs["@cached-math"];
|
|
1092
|
+
expect(entry.tools[0]).not.toHaveProperty("inputSchema");
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
test("ref.remove drops the cache entry", async () => {
|
|
1096
|
+
const fs = createMemoryFs();
|
|
1097
|
+
const adk = createAdk(fs);
|
|
1098
|
+
|
|
1099
|
+
await adk.registry.add({
|
|
1100
|
+
url: `http://localhost:${PORT}`,
|
|
1101
|
+
name: "main",
|
|
1102
|
+
});
|
|
1103
|
+
await adk.ref.add({
|
|
1104
|
+
ref: "@cached-math",
|
|
1105
|
+
scheme: "registry",
|
|
1106
|
+
sourceRegistry: {
|
|
1107
|
+
url: `http://localhost:${PORT}`,
|
|
1108
|
+
agentPath: "@cached-math",
|
|
1109
|
+
},
|
|
1110
|
+
});
|
|
1111
|
+
await adk.ref.add({
|
|
1112
|
+
ref: "@cached-echo",
|
|
1113
|
+
scheme: "registry",
|
|
1114
|
+
sourceRegistry: {
|
|
1115
|
+
url: `http://localhost:${PORT}`,
|
|
1116
|
+
agentPath: "@cached-echo",
|
|
1117
|
+
},
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
let cache = JSON.parse((await fs.readFile("registry-cache.json"))!);
|
|
1121
|
+
expect(Object.keys(cache.refs)).toEqual(
|
|
1122
|
+
expect.arrayContaining(["@cached-math", "@cached-echo"]),
|
|
1123
|
+
);
|
|
1124
|
+
|
|
1125
|
+
await adk.ref.remove("@cached-math");
|
|
1126
|
+
|
|
1127
|
+
cache = JSON.parse((await fs.readFile("registry-cache.json"))!);
|
|
1128
|
+
expect(cache.refs["@cached-math"]).toBeUndefined();
|
|
1129
|
+
expect(cache.refs["@cached-echo"]).toBeDefined();
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
test("malformed registry-cache.json is treated as empty (does not break list)", async () => {
|
|
1133
|
+
const fs = createMemoryFs();
|
|
1134
|
+
await fs.writeFile(
|
|
1135
|
+
"consumer-config.json",
|
|
1136
|
+
JSON.stringify({
|
|
1137
|
+
refs: [
|
|
1138
|
+
{
|
|
1139
|
+
ref: "@cached-math",
|
|
1140
|
+
name: "@cached-math",
|
|
1141
|
+
scheme: "registry",
|
|
1142
|
+
sourceRegistry: {
|
|
1143
|
+
url: `http://localhost:${PORT}`,
|
|
1144
|
+
agentPath: "@cached-math",
|
|
1145
|
+
},
|
|
1146
|
+
},
|
|
1147
|
+
],
|
|
1148
|
+
}),
|
|
1149
|
+
);
|
|
1150
|
+
await fs.writeFile("registry-cache.json", "{ this is not json");
|
|
1151
|
+
|
|
1152
|
+
const adk = createAdk(fs);
|
|
1153
|
+
const refs = await adk.ref.list();
|
|
1154
|
+
expect(refs).toHaveLength(1);
|
|
1155
|
+
expect(refs[0].description).toBeUndefined();
|
|
1156
|
+
});
|
|
1157
|
+
});
|