@slashfi/agents-sdk 0.34.1 → 0.36.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/README.md +2 -1
- package/dist/agent-definitions/auth.d.ts +3 -3
- package/dist/agent-definitions/auth.d.ts.map +1 -1
- package/dist/agent-definitions/auth.js +10 -4
- package/dist/agent-definitions/auth.js.map +1 -1
- package/dist/agent-definitions/config.d.ts.map +1 -1
- package/dist/agent-definitions/config.js.map +1 -1
- package/dist/agent-definitions/integrations.d.ts +12 -3
- package/dist/agent-definitions/integrations.d.ts.map +1 -1
- package/dist/agent-definitions/integrations.js +35 -16
- 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 +17 -22
- package/dist/agent-definitions/remote-registry.js.map +1 -1
- package/dist/agent-definitions/users.d.ts.map +1 -1
- package/dist/agent-definitions/users.js.map +1 -1
- package/dist/auth-governance.js.map +1 -1
- package/dist/call-agent-schema.d.ts.map +1 -1
- package/dist/call-agent-schema.js +1 -2
- package/dist/call-agent-schema.js.map +1 -1
- package/dist/cjs/agent-definitions/auth.js +10 -4
- package/dist/cjs/agent-definitions/auth.js.map +1 -1
- package/dist/cjs/agent-definitions/config.js.map +1 -1
- package/dist/cjs/agent-definitions/integrations.js +35 -16
- package/dist/cjs/agent-definitions/integrations.js.map +1 -1
- package/dist/cjs/agent-definitions/remote-registry.js +17 -22
- package/dist/cjs/agent-definitions/remote-registry.js.map +1 -1
- package/dist/cjs/agent-definitions/users.js.map +1 -1
- package/dist/cjs/auth-governance.js.map +1 -1
- package/dist/cjs/call-agent-schema.js +1 -2
- package/dist/cjs/call-agent-schema.js.map +1 -1
- package/dist/cjs/define.js.map +1 -1
- package/dist/cjs/events.js.map +1 -1
- package/dist/cjs/index.js +6 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/key-manager.js.map +1 -1
- package/dist/cjs/registry-consumer.js +60 -15
- package/dist/cjs/registry-consumer.js.map +1 -1
- package/dist/cjs/registry.js +61 -11
- package/dist/cjs/registry.js.map +1 -1
- package/dist/cjs/server.js +143 -192
- package/dist/cjs/server.js.map +1 -1
- package/dist/cjs/types.js +13 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js.map +1 -1
- package/dist/events.d.ts +85 -9
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/key-manager.d.ts.map +1 -1
- package/dist/key-manager.js +1 -1
- package/dist/key-manager.js.map +1 -1
- package/dist/registry-consumer.d.ts +8 -8
- package/dist/registry-consumer.d.ts.map +1 -1
- package/dist/registry-consumer.js +60 -15
- package/dist/registry-consumer.js.map +1 -1
- package/dist/registry.d.ts +16 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +61 -11
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +136 -185
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-definitions/auth.ts +31 -14
- package/src/agent-definitions/config.ts +4 -4
- package/src/agent-definitions/integrations.ts +119 -63
- package/src/agent-definitions/remote-registry.ts +65 -38
- package/src/agent-definitions/users.ts +36 -3
- package/src/auth-governance.ts +2 -2
- package/src/call-agent-schema.test.ts +4 -1
- package/src/call-agent-schema.ts +4 -3
- package/src/consumer.test.ts +4 -1
- package/src/define.ts +18 -12
- package/src/events.ts +83 -9
- package/src/hooks.test.ts +439 -0
- package/src/index.ts +14 -1
- package/src/key-manager.ts +9 -2
- package/src/registry-consumer.ts +85 -24
- package/src/registry.ts +88 -13
- package/src/server.ts +215 -239
- package/src/types.ts +62 -0
package/src/server.ts
CHANGED
|
@@ -31,9 +31,10 @@ import {
|
|
|
31
31
|
processSecretParams,
|
|
32
32
|
} from "./agent-definitions/secrets.js";
|
|
33
33
|
import { createBM25Index } from "./bm25.js";
|
|
34
|
-
import { verifyJwt } from "./jwt.js";
|
|
35
|
-
import type { SigningKey } from "./jwt.js";
|
|
36
34
|
import {
|
|
35
|
+
verifyJwt,
|
|
36
|
+
type AgentJwtPayload,
|
|
37
|
+
type SigningKey,
|
|
37
38
|
buildJwks,
|
|
38
39
|
exportSigningKey,
|
|
39
40
|
generateSigningKey,
|
|
@@ -44,8 +45,6 @@ import {
|
|
|
44
45
|
} from "./jwt.js";
|
|
45
46
|
import { type OIDCProviderConfig, createOIDCSignIn } from "./oidc-signin.js";
|
|
46
47
|
import type { AgentRegistry } from "./registry.js";
|
|
47
|
-
import type { AgentDefinition, CallAgentRequest } from "./types.js";
|
|
48
|
-
|
|
49
48
|
import {
|
|
50
49
|
callAgentInputSchema,
|
|
51
50
|
callAgentValidationSchema,
|
|
@@ -53,7 +52,33 @@ import {
|
|
|
53
52
|
listAgentsValidationSchema,
|
|
54
53
|
nullTolerant,
|
|
55
54
|
zodToOpenAiJsonSchema,
|
|
55
|
+
type CallAgentExecuteToolRequest,
|
|
56
|
+
type CallerType,
|
|
56
57
|
} from "./call-agent-schema.js";
|
|
58
|
+
import type {
|
|
59
|
+
AgentDefinition,
|
|
60
|
+
AuthClientCredentialsTokenResult,
|
|
61
|
+
CallAgentRequest,
|
|
62
|
+
ExchangeTokenToolResult,
|
|
63
|
+
} from "./types.js";
|
|
64
|
+
import {
|
|
65
|
+
isCallAgentErrorResponse,
|
|
66
|
+
isExchangeTokenLinkedSuccess,
|
|
67
|
+
isExchangeTokenNeedsIdentity,
|
|
68
|
+
} from "./types.js";
|
|
69
|
+
|
|
70
|
+
/** JWT payload claims used for reverse registry registration (jwt_exchange). */
|
|
71
|
+
interface RegistryAssertionPayload {
|
|
72
|
+
type?: string;
|
|
73
|
+
iss?: string;
|
|
74
|
+
name?: string;
|
|
75
|
+
tenantId?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function parseProxyCallerType(raw: string | null): CallerType {
|
|
79
|
+
if (raw === "agent" || raw === "user" || raw === "system") return raw;
|
|
80
|
+
return "agent";
|
|
81
|
+
}
|
|
57
82
|
|
|
58
83
|
// ============================================
|
|
59
84
|
// Server Types
|
|
@@ -231,7 +256,6 @@ export interface AuthConfig {
|
|
|
231
256
|
tokenTtl?: number;
|
|
232
257
|
}
|
|
233
258
|
|
|
234
|
-
|
|
235
259
|
// Auth governance — single source of truth for visibility/access control
|
|
236
260
|
export {
|
|
237
261
|
type ResolvedAuth,
|
|
@@ -539,8 +563,12 @@ export function createAgentServer(
|
|
|
539
563
|
...(options.registry && {
|
|
540
564
|
registry: {
|
|
541
565
|
version: options.registry.version ?? "1.0",
|
|
542
|
-
...(options.registry.features && {
|
|
543
|
-
|
|
566
|
+
...(options.registry.features && {
|
|
567
|
+
features: options.registry.features,
|
|
568
|
+
}),
|
|
569
|
+
...(options.registry.oauthCallbackUrl && {
|
|
570
|
+
oauthCallbackUrl: options.registry.oauthCallbackUrl,
|
|
571
|
+
}),
|
|
544
572
|
},
|
|
545
573
|
}),
|
|
546
574
|
},
|
|
@@ -598,9 +626,11 @@ export function createAgentServer(
|
|
|
598
626
|
case "call_agent": {
|
|
599
627
|
// Validate + strip nulls (OpenAI convention: null = absent)
|
|
600
628
|
const parsed = callAgentValidate.safeParse(args);
|
|
601
|
-
const req = (
|
|
602
|
-
|
|
603
|
-
|
|
629
|
+
const req = (
|
|
630
|
+
parsed.success
|
|
631
|
+
? ((parsed.data as Record<string, unknown>).request ?? parsed.data)
|
|
632
|
+
: (args.request ?? args)
|
|
633
|
+
) as CallAgentRequest;
|
|
604
634
|
|
|
605
635
|
// Inject auth context
|
|
606
636
|
if (auth) {
|
|
@@ -615,18 +645,19 @@ export function createAgentServer(
|
|
|
615
645
|
}
|
|
616
646
|
|
|
617
647
|
// Process secret params: resolve refs, store raw secrets
|
|
618
|
-
if (
|
|
648
|
+
if (req.action === "execute_tool" && req.params && secretStore) {
|
|
649
|
+
const execReq: CallAgentExecuteToolRequest = req;
|
|
619
650
|
const ownerId = auth?.callerId ?? "anonymous";
|
|
620
|
-
const agent = registry.get(
|
|
621
|
-
const tool = agent?.tools.find((t) => t.name ===
|
|
622
|
-
const schema = tool?.inputSchema
|
|
651
|
+
const agent = registry.get(execReq.path);
|
|
652
|
+
const tool = agent?.tools.find((t) => t.name === execReq.tool);
|
|
653
|
+
const schema = tool?.inputSchema;
|
|
623
654
|
const { resolved } = await processSecretParams(
|
|
624
|
-
|
|
625
|
-
schema,
|
|
655
|
+
execReq.params as Record<string, unknown>,
|
|
656
|
+
schema as Parameters<typeof processSecretParams>[1],
|
|
626
657
|
secretStore,
|
|
627
658
|
ownerId,
|
|
628
659
|
);
|
|
629
|
-
|
|
660
|
+
execReq.params = resolved;
|
|
630
661
|
}
|
|
631
662
|
|
|
632
663
|
const result = await registry.call(req);
|
|
@@ -634,102 +665,113 @@ export function createAgentServer(
|
|
|
634
665
|
}
|
|
635
666
|
|
|
636
667
|
case "list_agents": {
|
|
637
|
-
const {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
668
|
+
const {
|
|
669
|
+
query: listQuery,
|
|
670
|
+
limit: listLimit,
|
|
671
|
+
cursor: listCursor,
|
|
672
|
+
} = listAgentsValidate.parse(args);
|
|
673
|
+
|
|
674
|
+
const result = await registry.listAgents(
|
|
675
|
+
{ query: listQuery, limit: listLimit, cursor: listCursor },
|
|
676
|
+
async (allAgents) => {
|
|
677
|
+
let visible = allAgents.filter((agent) => canSeeAgent(agent, auth));
|
|
678
|
+
|
|
679
|
+
// Decode cursor if provided
|
|
680
|
+
const after = listCursor
|
|
681
|
+
? (JSON.parse(Buffer.from(listCursor, "base64url").toString()) as {
|
|
682
|
+
path: string;
|
|
683
|
+
score?: number;
|
|
684
|
+
})
|
|
685
|
+
: undefined;
|
|
686
|
+
|
|
687
|
+
const pageSize = listLimit ?? 20;
|
|
688
|
+
let page: typeof visible;
|
|
689
|
+
let nextCursor: string | undefined;
|
|
690
|
+
|
|
691
|
+
if (listQuery) {
|
|
692
|
+
// BM25 search — ranked by score desc, path asc for tie-breaking
|
|
693
|
+
const docs = visible.map((agent, i) => ({
|
|
694
|
+
id: String(i),
|
|
695
|
+
text: [
|
|
696
|
+
agent.path,
|
|
697
|
+
agent.config?.name ?? "",
|
|
698
|
+
agent.config?.description ?? "",
|
|
699
|
+
...agent.tools
|
|
700
|
+
.filter((t) => canSeeTool(t, auth))
|
|
701
|
+
.map((t) => `${t.name} ${t.description}`),
|
|
702
|
+
].join(" "),
|
|
703
|
+
}));
|
|
704
|
+
const index = createBM25Index(docs);
|
|
705
|
+
const ranked = index.search(listQuery);
|
|
706
|
+
|
|
707
|
+
// Build scored list
|
|
708
|
+
type ScoredAgent = (typeof visible)[number] & { _score: number };
|
|
709
|
+
let scored: ScoredAgent[] = ranked.map((r) => ({
|
|
710
|
+
...visible[Number(r.id)],
|
|
711
|
+
_score: r.score,
|
|
712
|
+
}));
|
|
713
|
+
|
|
714
|
+
// Apply cursor: skip past the after position
|
|
715
|
+
if (after?.score !== undefined) {
|
|
716
|
+
scored = scored.filter(
|
|
717
|
+
(a) =>
|
|
718
|
+
a._score < after.score! ||
|
|
719
|
+
(a._score === after.score! && a.path > after.path),
|
|
720
|
+
);
|
|
721
|
+
}
|
|
675
722
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
(
|
|
682
|
-
|
|
683
|
-
|
|
723
|
+
page = scored.slice(0, pageSize);
|
|
724
|
+
if (scored.length > pageSize) {
|
|
725
|
+
const last = scored[pageSize - 1] as ScoredAgent;
|
|
726
|
+
nextCursor = Buffer.from(
|
|
727
|
+
JSON.stringify({ path: last.path, score: last._score }),
|
|
728
|
+
).toString("base64url");
|
|
729
|
+
}
|
|
730
|
+
} else {
|
|
731
|
+
// Alphabetical listing — sorted by path
|
|
732
|
+
visible.sort((a, b) => a.path.localeCompare(b.path));
|
|
684
733
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
JSON.stringify({ path: last.path, score: last._score }),
|
|
690
|
-
).toString("base64url");
|
|
691
|
-
}
|
|
692
|
-
} else {
|
|
693
|
-
// Alphabetical listing — sorted by path
|
|
694
|
-
visible.sort((a, b) => a.path.localeCompare(b.path));
|
|
734
|
+
// Apply cursor: skip past afterPath
|
|
735
|
+
if (after) {
|
|
736
|
+
visible = visible.filter((a) => a.path > after.path);
|
|
737
|
+
}
|
|
695
738
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
739
|
+
page = visible.slice(0, pageSize);
|
|
740
|
+
if (visible.length > pageSize) {
|
|
741
|
+
const last = page[page.length - 1];
|
|
742
|
+
nextCursor = Buffer.from(
|
|
743
|
+
JSON.stringify({ path: last.path }),
|
|
744
|
+
).toString("base64url");
|
|
745
|
+
}
|
|
746
|
+
}
|
|
700
747
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
748
|
+
return {
|
|
749
|
+
success: true as const,
|
|
750
|
+
total: allAgents.filter((a) => canSeeAgent(a, auth)).length,
|
|
751
|
+
nextCursor,
|
|
752
|
+
agents: page.map((agent) => ({
|
|
753
|
+
path: agent.path,
|
|
754
|
+
name: agent.config?.name,
|
|
755
|
+
description: agent.config?.description,
|
|
756
|
+
supportedActions: agent.config?.supportedActions,
|
|
757
|
+
integration: agent.config?.integration || null,
|
|
758
|
+
security: agent.config?.security
|
|
759
|
+
? { type: agent.config.security.type }
|
|
760
|
+
: undefined,
|
|
761
|
+
resources: agent.config?.resources?.map((r) => ({
|
|
762
|
+
uri: r.uri,
|
|
763
|
+
name: r.name,
|
|
764
|
+
mimeType: r.mimeType,
|
|
765
|
+
})),
|
|
766
|
+
tools: agent.tools
|
|
767
|
+
.filter((t) => canSeeTool(t, auth))
|
|
768
|
+
.map((t) => t.name),
|
|
769
|
+
})),
|
|
770
|
+
};
|
|
771
|
+
},
|
|
772
|
+
);
|
|
709
773
|
|
|
710
|
-
return mcpResult(
|
|
711
|
-
success: true,
|
|
712
|
-
total: agents.filter((a) => canSeeAgent(a, auth)).length,
|
|
713
|
-
nextCursor,
|
|
714
|
-
agents: page.map((agent) => ({
|
|
715
|
-
path: agent.path,
|
|
716
|
-
name: agent.config?.name,
|
|
717
|
-
description: agent.config?.description,
|
|
718
|
-
supportedActions: agent.config?.supportedActions,
|
|
719
|
-
integration: agent.config?.integration || null,
|
|
720
|
-
security: agent.config?.security
|
|
721
|
-
? { type: agent.config.security.type }
|
|
722
|
-
: undefined,
|
|
723
|
-
resources: agent.config?.resources?.map((r) => ({
|
|
724
|
-
uri: r.uri,
|
|
725
|
-
name: r.name,
|
|
726
|
-
mimeType: r.mimeType,
|
|
727
|
-
})),
|
|
728
|
-
tools: agent.tools
|
|
729
|
-
.filter((t) => canSeeTool(t, auth))
|
|
730
|
-
.map((t) => t.name),
|
|
731
|
-
})),
|
|
732
|
-
});
|
|
774
|
+
return mcpResult(result);
|
|
733
775
|
}
|
|
734
776
|
|
|
735
777
|
default:
|
|
@@ -798,27 +840,36 @@ export function createAgentServer(
|
|
|
798
840
|
callerType: "system",
|
|
799
841
|
});
|
|
800
842
|
|
|
801
|
-
|
|
802
|
-
// If the tool call failed, forward the error
|
|
803
|
-
if ((result as any)?.success === false) {
|
|
843
|
+
if (isCallAgentErrorResponse(result)) {
|
|
804
844
|
return jsonResponse(
|
|
805
845
|
{
|
|
806
846
|
error: "server_error",
|
|
807
|
-
error_description:
|
|
808
|
-
(result as any)?.error ?? "Exchange tool failed",
|
|
847
|
+
error_description: result.error ?? "Exchange tool failed",
|
|
809
848
|
raw: JSON.stringify(result)?.slice(0, 300),
|
|
810
849
|
},
|
|
811
850
|
500,
|
|
812
851
|
);
|
|
813
852
|
}
|
|
814
853
|
|
|
854
|
+
if (!("result" in result)) {
|
|
855
|
+
return jsonResponse(
|
|
856
|
+
{
|
|
857
|
+
error: "server_error",
|
|
858
|
+
error_description: `Unexpected exchange response: ${JSON.stringify(result)?.slice(0, 300)}`,
|
|
859
|
+
},
|
|
860
|
+
500,
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const exchangeResult = result.result as ExchangeTokenToolResult;
|
|
865
|
+
|
|
815
866
|
// ── Reverse registration: if caller is an agent-registry, auto-store connection ──
|
|
816
867
|
try {
|
|
817
868
|
const assertionParts = assertion.split(".");
|
|
818
869
|
if (assertionParts.length === 3) {
|
|
819
870
|
const assertionPayload = JSON.parse(
|
|
820
871
|
Buffer.from(assertionParts[1], "base64url").toString(),
|
|
821
|
-
) as
|
|
872
|
+
) as RegistryAssertionPayload;
|
|
822
873
|
if (
|
|
823
874
|
assertionPayload.type === "agent-registry" &&
|
|
824
875
|
assertionPayload.iss
|
|
@@ -844,7 +895,7 @@ export function createAgentServer(
|
|
|
844
895
|
} else {
|
|
845
896
|
console.error(
|
|
846
897
|
"[jwt_exchange] Reverse connection failed:",
|
|
847
|
-
|
|
898
|
+
addResult.error,
|
|
848
899
|
);
|
|
849
900
|
}
|
|
850
901
|
}
|
|
@@ -867,7 +918,7 @@ export function createAgentServer(
|
|
|
867
918
|
}
|
|
868
919
|
|
|
869
920
|
// User not linked yet — needs OAuth identity linking
|
|
870
|
-
if (exchangeResult
|
|
921
|
+
if (isExchangeTokenNeedsIdentity(exchangeResult)) {
|
|
871
922
|
const baseUrl = resolveBaseUrl(req);
|
|
872
923
|
const authorizeUrl = new URL(`${baseUrl}${basePath}/oauth/authorize`);
|
|
873
924
|
authorizeUrl.searchParams.set("token", assertion);
|
|
@@ -890,7 +941,10 @@ export function createAgentServer(
|
|
|
890
941
|
}
|
|
891
942
|
|
|
892
943
|
// User found — sign a local access token
|
|
893
|
-
if (
|
|
944
|
+
if (
|
|
945
|
+
isExchangeTokenLinkedSuccess(exchangeResult) &&
|
|
946
|
+
serverSigningKeys.length > 0
|
|
947
|
+
) {
|
|
894
948
|
const sigKey = serverSigningKeys[0];
|
|
895
949
|
const token = await signJwtES256(
|
|
896
950
|
{
|
|
@@ -951,8 +1005,28 @@ export function createAgentServer(
|
|
|
951
1005
|
callerType: "system",
|
|
952
1006
|
});
|
|
953
1007
|
|
|
954
|
-
|
|
955
|
-
|
|
1008
|
+
if (isCallAgentErrorResponse(result)) {
|
|
1009
|
+
return jsonResponse(
|
|
1010
|
+
{
|
|
1011
|
+
error: "invalid_client",
|
|
1012
|
+
error_description: result.error ?? "Authentication failed",
|
|
1013
|
+
},
|
|
1014
|
+
401,
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
if (!("result" in result)) {
|
|
1019
|
+
return jsonResponse(
|
|
1020
|
+
{
|
|
1021
|
+
error: "invalid_client",
|
|
1022
|
+
error_description: "Authentication failed",
|
|
1023
|
+
},
|
|
1024
|
+
401,
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
const tokenResult = result.result as AuthClientCredentialsTokenResult;
|
|
1029
|
+
if (tokenResult.accessToken == null) {
|
|
956
1030
|
return jsonResponse(
|
|
957
1031
|
{
|
|
958
1032
|
error: "invalid_client",
|
|
@@ -1020,7 +1094,7 @@ export function createAgentServer(
|
|
|
1020
1094
|
if (actorId) {
|
|
1021
1095
|
return {
|
|
1022
1096
|
callerId: actorId,
|
|
1023
|
-
callerType: (actorType
|
|
1097
|
+
callerType: parseProxyCallerType(actorType),
|
|
1024
1098
|
scopes: ["*"],
|
|
1025
1099
|
claims: {},
|
|
1026
1100
|
};
|
|
@@ -1119,12 +1193,12 @@ export function createAgentServer(
|
|
|
1119
1193
|
claims = result as unknown as Record<string, unknown>;
|
|
1120
1194
|
break;
|
|
1121
1195
|
}
|
|
1122
|
-
} catch (e:
|
|
1196
|
+
} catch (e: unknown) {
|
|
1123
1197
|
console.log(
|
|
1124
1198
|
"[oauth/authorize] verify",
|
|
1125
1199
|
issuerUrl,
|
|
1126
1200
|
"-> ERROR:",
|
|
1127
|
-
e.message,
|
|
1201
|
+
e instanceof Error ? e.message : String(e),
|
|
1128
1202
|
);
|
|
1129
1203
|
}
|
|
1130
1204
|
}
|
|
@@ -1190,24 +1264,6 @@ export function createAgentServer(
|
|
|
1190
1264
|
return cors ? addCors(res) : res;
|
|
1191
1265
|
}
|
|
1192
1266
|
|
|
1193
|
-
// ── GET /.well-known/configuration → Server discovery (deprecated, use MCP initialize capabilities) ──
|
|
1194
|
-
if (path === "/.well-known/configuration" && req.method === "GET") {
|
|
1195
|
-
const baseUrl = resolveBaseUrl(req);
|
|
1196
|
-
const res = jsonResponse({
|
|
1197
|
-
issuer: baseUrl,
|
|
1198
|
-
jwks_uri: `${baseUrl}/.well-known/jwks.json`,
|
|
1199
|
-
token_endpoint: `${baseUrl}/oauth/token`,
|
|
1200
|
-
agents_endpoint: `${baseUrl}/list`,
|
|
1201
|
-
call_endpoint: baseUrl,
|
|
1202
|
-
supported_grant_types: ["client_credentials", "jwt_exchange"],
|
|
1203
|
-
authorization_endpoint: `${baseUrl}/oauth/authorize`,
|
|
1204
|
-
...(oidcSignIn
|
|
1205
|
-
? { signin_endpoint: `${baseUrl}/signin/authorize` }
|
|
1206
|
-
: {}),
|
|
1207
|
-
});
|
|
1208
|
-
return cors ? addCors(res) : res;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
1267
|
// ── GET /.well-known/oauth-authorization-server → OAuth Server Metadata (RFC 8414) ──
|
|
1212
1268
|
// Only exposed when the server requires auth (private registries).
|
|
1213
1269
|
// Public registries (e.g. registry.slash.com) skip this entirely.
|
|
@@ -1215,7 +1271,9 @@ export function createAgentServer(
|
|
|
1215
1271
|
path === "/.well-known/oauth-authorization-server" &&
|
|
1216
1272
|
req.method === "GET"
|
|
1217
1273
|
) {
|
|
1218
|
-
if (
|
|
1274
|
+
if (
|
|
1275
|
+
!(options.registry?.oauthCallbackUrl || serverSigningKeys.length > 0)
|
|
1276
|
+
) {
|
|
1219
1277
|
const res = new Response("Not Found", { status: 404 });
|
|
1220
1278
|
return cors ? addCors(res) : res;
|
|
1221
1279
|
}
|
|
@@ -1226,7 +1284,11 @@ export function createAgentServer(
|
|
|
1226
1284
|
token_endpoint: `${baseUrl}/oauth/token`,
|
|
1227
1285
|
jwks_uri: `${baseUrl}/.well-known/jwks.json`,
|
|
1228
1286
|
response_types_supported: ["code"],
|
|
1229
|
-
grant_types_supported: [
|
|
1287
|
+
grant_types_supported: [
|
|
1288
|
+
"authorization_code",
|
|
1289
|
+
"client_credentials",
|
|
1290
|
+
"jwt_exchange",
|
|
1291
|
+
],
|
|
1230
1292
|
code_challenge_methods_supported: ["S256"],
|
|
1231
1293
|
token_endpoint_auth_methods_supported: ["client_secret_post", "none"],
|
|
1232
1294
|
...(options.registry?.oauthCallbackUrl && {
|
|
@@ -1236,98 +1298,6 @@ export function createAgentServer(
|
|
|
1236
1298
|
return cors ? addCors(res) : res;
|
|
1237
1299
|
}
|
|
1238
1300
|
|
|
1239
|
-
// ── GET /list → List agents (──
|
|
1240
|
-
if (path === "/list" && req.method === "GET") {
|
|
1241
|
-
const agents = registry.list();
|
|
1242
|
-
let visible = agents.filter((agent) =>
|
|
1243
|
-
canSeeAgent(agent, effectiveAuth),
|
|
1244
|
-
);
|
|
1245
|
-
|
|
1246
|
-
const searchQuery = url.searchParams.get("q");
|
|
1247
|
-
const searchLimit = url.searchParams.get("limit");
|
|
1248
|
-
const searchCursor = url.searchParams.get("cursor");
|
|
1249
|
-
|
|
1250
|
-
// Decode cursor
|
|
1251
|
-
const httpAfter = searchCursor
|
|
1252
|
-
? (JSON.parse(
|
|
1253
|
-
Buffer.from(searchCursor, "base64url").toString(),
|
|
1254
|
-
) as { path: string; score?: number })
|
|
1255
|
-
: undefined;
|
|
1256
|
-
|
|
1257
|
-
const httpPageSize = searchLimit ? Number(searchLimit) : 20;
|
|
1258
|
-
let httpPage: typeof visible;
|
|
1259
|
-
let httpNextCursor: string | undefined;
|
|
1260
|
-
|
|
1261
|
-
if (searchQuery) {
|
|
1262
|
-
const docs = visible.map((agent, i) => ({
|
|
1263
|
-
id: String(i),
|
|
1264
|
-
text: [
|
|
1265
|
-
agent.path,
|
|
1266
|
-
agent.config?.name ?? "",
|
|
1267
|
-
agent.config?.description ?? "",
|
|
1268
|
-
...agent.tools
|
|
1269
|
-
.filter((t) => canSeeTool(t, effectiveAuth))
|
|
1270
|
-
.map((t) => `${t.name} ${t.description}`),
|
|
1271
|
-
].join(" "),
|
|
1272
|
-
}));
|
|
1273
|
-
const index = createBM25Index(docs);
|
|
1274
|
-
const ranked = index.search(searchQuery);
|
|
1275
|
-
|
|
1276
|
-
type ScoredAgent = (typeof visible)[number] & { _score: number };
|
|
1277
|
-
let scored: ScoredAgent[] = ranked.map((r) => ({
|
|
1278
|
-
...visible[Number(r.id)],
|
|
1279
|
-
_score: r.score,
|
|
1280
|
-
}));
|
|
1281
|
-
|
|
1282
|
-
if (httpAfter?.score !== undefined) {
|
|
1283
|
-
scored = scored.filter(
|
|
1284
|
-
(a) =>
|
|
1285
|
-
a._score < httpAfter.score! ||
|
|
1286
|
-
(a._score === httpAfter.score! && a.path > httpAfter.path),
|
|
1287
|
-
);
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
httpPage = scored.slice(0, httpPageSize);
|
|
1291
|
-
if (scored.length > httpPageSize) {
|
|
1292
|
-
const last = scored[httpPageSize - 1] as ScoredAgent;
|
|
1293
|
-
httpNextCursor = Buffer.from(
|
|
1294
|
-
JSON.stringify({ path: last.path, score: last._score }),
|
|
1295
|
-
).toString("base64url");
|
|
1296
|
-
}
|
|
1297
|
-
} else {
|
|
1298
|
-
visible.sort((a, b) => a.path.localeCompare(b.path));
|
|
1299
|
-
if (httpAfter) {
|
|
1300
|
-
visible = visible.filter((a) => a.path > httpAfter.path);
|
|
1301
|
-
}
|
|
1302
|
-
httpPage = visible.slice(0, httpPageSize);
|
|
1303
|
-
if (visible.length > httpPageSize) {
|
|
1304
|
-
const last = httpPage[httpPage.length - 1];
|
|
1305
|
-
httpNextCursor = Buffer.from(
|
|
1306
|
-
JSON.stringify({ path: last.path }),
|
|
1307
|
-
).toString("base64url");
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
const res = jsonResponse({
|
|
1312
|
-
total: agents.filter((a) => canSeeAgent(a, effectiveAuth)).length,
|
|
1313
|
-
nextCursor: httpNextCursor,
|
|
1314
|
-
agents: httpPage.map((agent) => ({
|
|
1315
|
-
path: agent.path,
|
|
1316
|
-
name: agent.config?.name,
|
|
1317
|
-
description: agent.config?.description,
|
|
1318
|
-
supportedActions: agent.config?.supportedActions,
|
|
1319
|
-
integration: agent.config?.integration || null,
|
|
1320
|
-
tools: agent.tools
|
|
1321
|
-
.filter((t) => canSeeTool(t, effectiveAuth))
|
|
1322
|
-
.map((t) => ({
|
|
1323
|
-
name: t.name,
|
|
1324
|
-
description: t.description,
|
|
1325
|
-
})),
|
|
1326
|
-
})),
|
|
1327
|
-
});
|
|
1328
|
-
return cors ? addCors(res) : res;
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
1301
|
// ── GET /agents → List public agents (discovery endpoint) ──
|
|
1332
1302
|
if (path === "/agents" && req.method === "GET") {
|
|
1333
1303
|
const agents = registry.list();
|
|
@@ -1342,7 +1312,7 @@ export function createAgentServer(
|
|
|
1342
1312
|
name: agent.config?.name,
|
|
1343
1313
|
description:
|
|
1344
1314
|
agent.config?.description ?? agent.entrypoint?.slice(0, 200),
|
|
1345
|
-
mode: agent.mode ??
|
|
1315
|
+
mode: agent.mode ?? "direct",
|
|
1346
1316
|
...(agent.upstream && { upstream: agent.upstream }),
|
|
1347
1317
|
tools: getVisibleTools(agent, effectiveAuth).map((t) => ({
|
|
1348
1318
|
name: t.name,
|
|
@@ -1369,7 +1339,7 @@ export function createAgentServer(
|
|
|
1369
1339
|
name: agent.config?.name,
|
|
1370
1340
|
description:
|
|
1371
1341
|
agent.config?.description ?? agent.entrypoint?.slice(0, 200),
|
|
1372
|
-
mode: agent.mode ??
|
|
1342
|
+
mode: agent.mode ?? "direct",
|
|
1373
1343
|
...(agent.upstream && { upstream: agent.upstream }),
|
|
1374
1344
|
tools: getVisibleTools(agent, effectiveAuth).map((t) => ({
|
|
1375
1345
|
name: t.name,
|
|
@@ -1595,7 +1565,7 @@ export function createAgentServer(
|
|
|
1595
1565
|
hostname,
|
|
1596
1566
|
fetch,
|
|
1597
1567
|
});
|
|
1598
|
-
|
|
1568
|
+
this.url = `http://${hostname}:${port}`;
|
|
1599
1569
|
console.log(
|
|
1600
1570
|
`[agents-sdk] Server listening on http://${hostname}:${port}`,
|
|
1601
1571
|
);
|
|
@@ -1605,7 +1575,7 @@ export function createAgentServer(
|
|
|
1605
1575
|
if (serverInstance) {
|
|
1606
1576
|
serverInstance.stop();
|
|
1607
1577
|
serverInstance = null;
|
|
1608
|
-
|
|
1578
|
+
this.url = null;
|
|
1609
1579
|
}
|
|
1610
1580
|
},
|
|
1611
1581
|
|
|
@@ -1618,8 +1588,14 @@ export function createAgentServer(
|
|
|
1618
1588
|
);
|
|
1619
1589
|
}
|
|
1620
1590
|
const key = serverSigningKeys[0];
|
|
1591
|
+
const payload: Omit<AgentJwtPayload, "iat" | "exp"> = {
|
|
1592
|
+
sub: "system",
|
|
1593
|
+
name: "atlas-os",
|
|
1594
|
+
scopes: ["*"],
|
|
1595
|
+
...(claims as Partial<Omit<AgentJwtPayload, "iat" | "exp">>),
|
|
1596
|
+
};
|
|
1621
1597
|
return signJwtES256(
|
|
1622
|
-
|
|
1598
|
+
payload,
|
|
1623
1599
|
key.privateKey,
|
|
1624
1600
|
key.kid,
|
|
1625
1601
|
options.serverName ?? "agents-sdk",
|