@slashfi/agents-sdk 0.28.3 → 0.30.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 +2 -6
- package/dist/agent-definitions/auth.d.ts.map +1 -1
- package/dist/agent-definitions/auth.js +5 -5
- 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 +0 -1
- package/dist/agent-definitions/integrations.js.map +1 -1
- package/dist/cjs/agent-definitions/auth.js +5 -5
- package/dist/cjs/agent-definitions/auth.js.map +1 -1
- package/dist/cjs/agent-definitions/integrations.js +0 -1
- package/dist/cjs/agent-definitions/integrations.js.map +1 -1
- package/dist/cjs/define-config.js +1 -5
- package/dist/cjs/define-config.js.map +1 -1
- package/dist/cjs/define.js +2 -0
- package/dist/cjs/define.js.map +1 -1
- package/dist/cjs/index.js +4 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/registry-consumer.js +81 -48
- package/dist/cjs/registry-consumer.js.map +1 -1
- package/dist/cjs/secret-collection.js.map +1 -1
- package/dist/cjs/server.js +20 -27
- package/dist/cjs/server.js.map +1 -1
- package/dist/define-config.d.ts +18 -21
- package/dist/define-config.d.ts.map +1 -1
- package/dist/define-config.js +1 -5
- package/dist/define-config.js.map +1 -1
- package/dist/define.d.ts +11 -0
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +2 -0
- package/dist/define.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/registry-consumer.d.ts +2 -2
- package/dist/registry-consumer.d.ts.map +1 -1
- package/dist/registry-consumer.js +82 -49
- package/dist/registry-consumer.js.map +1 -1
- package/dist/secret-collection.d.ts +0 -1
- package/dist/secret-collection.d.ts.map +1 -1
- package/dist/secret-collection.js.map +1 -1
- package/dist/server.d.ts +3 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +19 -27
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent-definitions/auth.ts +5 -11
- package/src/agent-definitions/integrations.ts +0 -1
- package/src/consumer.test.ts +8 -8
- package/src/define-config.ts +17 -31
- package/src/define.ts +15 -0
- package/src/index.ts +2 -1
- package/src/registry-consumer.ts +104 -56
- package/src/secret-collection.ts +0 -1
- package/src/server.test.ts +3 -3
- package/src/server.ts +20 -31
- package/src/types.ts +13 -0
package/src/registry-consumer.ts
CHANGED
|
@@ -38,7 +38,7 @@ import type {
|
|
|
38
38
|
ResolvedRegistry,
|
|
39
39
|
} from "./define-config.js";
|
|
40
40
|
import {
|
|
41
|
-
|
|
41
|
+
isSecretUri,
|
|
42
42
|
normalizeRef,
|
|
43
43
|
normalizeRegistry,
|
|
44
44
|
} from "./define-config.js";
|
|
@@ -55,6 +55,72 @@ export const REGISTRY_TYPE_HTTPS = "https";
|
|
|
55
55
|
/** Built-in registry types that bypass normal registry resolution */
|
|
56
56
|
const DIRECT_REGISTRY_TYPES = new Set([REGISTRY_TYPE_MCP, REGISTRY_TYPE_HTTPS]);
|
|
57
57
|
|
|
58
|
+
/** Regex for {{secret-uri}} template syntax */
|
|
59
|
+
const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g;
|
|
60
|
+
|
|
61
|
+
/** Check if a string contains {{...}} template expressions */
|
|
62
|
+
function hasTemplates(value: string): boolean {
|
|
63
|
+
return TEMPLATE_REGEX.test(value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve {{secret-uri}} templates in a string.
|
|
68
|
+
* E.g. "Bearer {{file:///.secrets/key}}" → "Bearer actual-key-value"
|
|
69
|
+
*/
|
|
70
|
+
async function resolveTemplateString(
|
|
71
|
+
value: string,
|
|
72
|
+
resolver: SecretResolver,
|
|
73
|
+
auth?: { token?: string },
|
|
74
|
+
): Promise<string> {
|
|
75
|
+
// Reset regex state
|
|
76
|
+
TEMPLATE_REGEX.lastIndex = 0;
|
|
77
|
+
const matches = [...value.matchAll(/\{\{(.+?)\}\}/g)];
|
|
78
|
+
if (matches.length === 0) return value;
|
|
79
|
+
|
|
80
|
+
let result = value;
|
|
81
|
+
for (const match of matches) {
|
|
82
|
+
const uri = match[1]!.trim();
|
|
83
|
+
const resolved = await resolver(uri, auth);
|
|
84
|
+
result = result.replace(match[0], resolved);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Recursively resolve {{secret-uri}} templates in an object.
|
|
91
|
+
* Walks all string values at any depth.
|
|
92
|
+
*/
|
|
93
|
+
async function resolveTemplates<T>(
|
|
94
|
+
obj: T,
|
|
95
|
+
resolver: SecretResolver,
|
|
96
|
+
auth?: { token?: string },
|
|
97
|
+
): Promise<T> {
|
|
98
|
+
if (typeof obj === 'string') {
|
|
99
|
+
// Handle {{secret-uri}} templates
|
|
100
|
+
if (hasTemplates(obj)) {
|
|
101
|
+
return (await resolveTemplateString(obj, resolver, auth)) as T;
|
|
102
|
+
}
|
|
103
|
+
// Handle raw secret URIs (backward compat)
|
|
104
|
+
if (isSecretUri(obj)) {
|
|
105
|
+
return (await resolver(obj, auth)) as T;
|
|
106
|
+
}
|
|
107
|
+
return obj;
|
|
108
|
+
}
|
|
109
|
+
if (Array.isArray(obj)) {
|
|
110
|
+
return (await Promise.all(
|
|
111
|
+
obj.map((item) => resolveTemplates(item, resolver, auth)),
|
|
112
|
+
)) as T;
|
|
113
|
+
}
|
|
114
|
+
if (obj !== null && typeof obj === 'object') {
|
|
115
|
+
const result: Record<string, unknown> = {};
|
|
116
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
117
|
+
result[key] = await resolveTemplates(value, resolver, auth);
|
|
118
|
+
}
|
|
119
|
+
return result as T;
|
|
120
|
+
}
|
|
121
|
+
return obj;
|
|
122
|
+
}
|
|
123
|
+
|
|
58
124
|
// ============================================
|
|
59
125
|
// Registry Discovery Types
|
|
60
126
|
// ============================================
|
|
@@ -378,10 +444,10 @@ export interface RegistryConsumer {
|
|
|
378
444
|
/** Resolve a secret URL to its value */
|
|
379
445
|
resolveSecret(url: string): Promise<string>;
|
|
380
446
|
|
|
381
|
-
/** Resolve
|
|
447
|
+
/** Resolve {{secret-uri}} templates in a config object (recursive) */
|
|
382
448
|
resolveConfig(
|
|
383
449
|
config: RefConfig,
|
|
384
|
-
): Promise<
|
|
450
|
+
): Promise<RefConfig>;
|
|
385
451
|
|
|
386
452
|
/** Produce the indexed/serialized config output */
|
|
387
453
|
index(): ResolvedConfig;
|
|
@@ -408,13 +474,7 @@ export async function createRegistryConsumer(
|
|
|
408
474
|
|
|
409
475
|
// Normalize refs
|
|
410
476
|
const resolvedRefs: ResolvedRef[] = (config.refs ?? []).map((entry) => {
|
|
411
|
-
|
|
412
|
-
return {
|
|
413
|
-
ref: normalized.ref,
|
|
414
|
-
name: normalized.name,
|
|
415
|
-
registry: normalized.registry ?? resolvedRegistries[0]?.url ?? "unknown",
|
|
416
|
-
config: normalized.config,
|
|
417
|
-
};
|
|
477
|
+
return normalizeRef(entry);
|
|
418
478
|
});
|
|
419
479
|
|
|
420
480
|
// Cache for registry configurations
|
|
@@ -526,25 +586,19 @@ export async function createRegistryConsumer(
|
|
|
526
586
|
|
|
527
587
|
// Also collect from direct MCP/HTTPS refs
|
|
528
588
|
for (const ref of resolvedRefs) {
|
|
529
|
-
if (!DIRECT_REGISTRY_TYPES.has(ref.
|
|
530
|
-
|
|
531
|
-
const n = normalizeRef(r);
|
|
532
|
-
return n.name === ref.name;
|
|
533
|
-
});
|
|
534
|
-
const url =
|
|
535
|
-
typeof refEntry === "object" ? refEntry?.url : undefined;
|
|
536
|
-
if (!url) continue;
|
|
589
|
+
if (!ref.scheme || !DIRECT_REGISTRY_TYPES.has(ref.scheme)) continue;
|
|
590
|
+
if (!ref.url) continue;
|
|
537
591
|
|
|
538
592
|
try {
|
|
539
|
-
if (ref.
|
|
593
|
+
if (ref.scheme === REGISTRY_TYPE_MCP) {
|
|
540
594
|
const mcpListings = await listFromMcpServer(
|
|
541
|
-
url,
|
|
595
|
+
ref.url,
|
|
542
596
|
{ token: options.token },
|
|
543
597
|
fetchFn,
|
|
544
598
|
);
|
|
545
599
|
listings.push(...mcpListings);
|
|
546
|
-
} else if (ref.
|
|
547
|
-
listings.push(...listFromHttpsApi(url));
|
|
600
|
+
} else if (ref.scheme === REGISTRY_TYPE_HTTPS) {
|
|
601
|
+
listings.push(...listFromHttpsApi(ref.url));
|
|
548
602
|
}
|
|
549
603
|
} catch {
|
|
550
604
|
// Skip unreachable direct refs during list
|
|
@@ -574,39 +628,43 @@ export async function createRegistryConsumer(
|
|
|
574
628
|
);
|
|
575
629
|
}
|
|
576
630
|
|
|
631
|
+
// Resolve config headers ({{secret-uri}} templates)
|
|
632
|
+
const configHeaders = ref.config?.headers as
|
|
633
|
+
| Record<string, string>
|
|
634
|
+
| undefined;
|
|
635
|
+
const resolvedHeaders = configHeaders
|
|
636
|
+
? await resolveTemplates(configHeaders, resolveSecretFn, {
|
|
637
|
+
token: options.token,
|
|
638
|
+
})
|
|
639
|
+
: undefined;
|
|
640
|
+
const auth = { token: options.token, headers: resolvedHeaders };
|
|
641
|
+
|
|
577
642
|
// Direct MCP ref — bypass registry, call MCP server directly
|
|
578
|
-
if (ref.
|
|
579
|
-
|
|
580
|
-
const n = normalizeRef(r);
|
|
581
|
-
return n.name === ref.name;
|
|
582
|
-
});
|
|
583
|
-
const url = typeof refEntry === "object" ? refEntry?.url : undefined;
|
|
584
|
-
if (!url) {
|
|
643
|
+
if (ref.scheme === REGISTRY_TYPE_MCP) {
|
|
644
|
+
if (!ref.url) {
|
|
585
645
|
throw new Error(`MCP ref "${refName}" has no url`);
|
|
586
646
|
}
|
|
587
|
-
return callMcpTool(url, tool, params,
|
|
647
|
+
return callMcpTool(ref.url, tool, params, auth, fetchFn);
|
|
588
648
|
}
|
|
589
649
|
|
|
590
650
|
// Direct HTTPS ref — bypass registry, call REST API directly
|
|
591
|
-
if (ref.
|
|
592
|
-
|
|
593
|
-
const n = normalizeRef(r);
|
|
594
|
-
return n.name === ref.name;
|
|
595
|
-
});
|
|
596
|
-
const url = typeof refEntry === "object" ? refEntry?.url : undefined;
|
|
597
|
-
if (!url) {
|
|
651
|
+
if (ref.scheme === REGISTRY_TYPE_HTTPS) {
|
|
652
|
+
if (!ref.url) {
|
|
598
653
|
throw new Error(`HTTPS ref "${refName}" has no url`);
|
|
599
654
|
}
|
|
600
|
-
return callHttpsTool(url, tool, params,
|
|
655
|
+
return callHttpsTool(ref.url, tool, params, auth, fetchFn);
|
|
601
656
|
}
|
|
602
657
|
|
|
603
658
|
// Standard registry ref
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
659
|
+
const registryUrl = ref.sourceRegistry?.url;
|
|
660
|
+
const registry = registryUrl
|
|
661
|
+
? resolvedRegistries.find(
|
|
662
|
+
(r) => r.url === registryUrl || r.name === registryUrl,
|
|
663
|
+
)
|
|
664
|
+
: resolvedRegistries[0]; // Default to first registry if no source specified
|
|
607
665
|
if (!registry) {
|
|
608
666
|
throw new Error(
|
|
609
|
-
`Registry
|
|
667
|
+
`Registry not found for ref "${refName}"${registryUrl ? ` (source: ${registryUrl})` : ''}`,
|
|
610
668
|
);
|
|
611
669
|
}
|
|
612
670
|
|
|
@@ -619,20 +677,10 @@ export async function createRegistryConsumer(
|
|
|
619
677
|
return resolveSecretFn(url, { token: options.token });
|
|
620
678
|
},
|
|
621
679
|
|
|
622
|
-
async resolveConfig(
|
|
623
|
-
config
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
for (const [key, value] of Object.entries(config)) {
|
|
627
|
-
if (isSecretUrl(value)) {
|
|
628
|
-
resolved[key] = await resolveSecretFn(value as string, {
|
|
629
|
-
token: options.token,
|
|
630
|
-
});
|
|
631
|
-
} else {
|
|
632
|
-
resolved[key] = value;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
return resolved;
|
|
680
|
+
async resolveConfig(config: RefConfig): Promise<RefConfig> {
|
|
681
|
+
return resolveTemplates(config, resolveSecretFn, {
|
|
682
|
+
token: options.token,
|
|
683
|
+
});
|
|
636
684
|
},
|
|
637
685
|
|
|
638
686
|
index(): ResolvedConfig {
|
package/src/secret-collection.ts
CHANGED
package/src/server.test.ts
CHANGED
|
@@ -241,7 +241,7 @@ describe("atlas ↔ registry E2E", () => {
|
|
|
241
241
|
const consumer = await createRegistryConsumer(
|
|
242
242
|
{
|
|
243
243
|
registries: [REGISTRY_URL],
|
|
244
|
-
refs: ["notion"],
|
|
244
|
+
refs: [{ ref: "notion" }],
|
|
245
245
|
},
|
|
246
246
|
{ token: authToken },
|
|
247
247
|
);
|
|
@@ -256,7 +256,7 @@ describe("atlas ↔ registry E2E", () => {
|
|
|
256
256
|
const consumer = await createRegistryConsumer(
|
|
257
257
|
{
|
|
258
258
|
registries: [REGISTRY_URL],
|
|
259
|
-
refs: ["linear"],
|
|
259
|
+
refs: [{ ref: "linear" }],
|
|
260
260
|
},
|
|
261
261
|
{ token: authToken },
|
|
262
262
|
);
|
|
@@ -269,7 +269,7 @@ describe("atlas ↔ registry E2E", () => {
|
|
|
269
269
|
const consumer = await createRegistryConsumer(
|
|
270
270
|
{
|
|
271
271
|
registries: [REGISTRY_URL],
|
|
272
|
-
refs: ["notion"],
|
|
272
|
+
refs: [{ ref: "notion" }],
|
|
273
273
|
},
|
|
274
274
|
{ token: authToken },
|
|
275
275
|
);
|
package/src/server.ts
CHANGED
|
@@ -180,7 +180,7 @@ interface JsonRpcResponse {
|
|
|
180
180
|
|
|
181
181
|
export interface AuthConfig {
|
|
182
182
|
store?: AuthStore;
|
|
183
|
-
|
|
183
|
+
/** @deprecated Use JWT scopes instead. Will be removed in a future version. */
|
|
184
184
|
tokenTtl?: number;
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -189,11 +189,16 @@ export interface ResolvedAuth {
|
|
|
189
189
|
callerId: string;
|
|
190
190
|
callerType: "agent" | "user" | "system";
|
|
191
191
|
scopes: string[];
|
|
192
|
-
isRoot: boolean;
|
|
193
192
|
/** All JWT claims from the verified token (passthrough) */
|
|
194
193
|
claims: Record<string, unknown>;
|
|
195
194
|
}
|
|
196
195
|
|
|
196
|
+
/** Check if auth has admin-level access (wildcard or admin scope) */
|
|
197
|
+
export function hasAdminScope(auth: ResolvedAuth | null): boolean {
|
|
198
|
+
if (!auth) return false;
|
|
199
|
+
return auth.scopes.includes("*") || auth.scopes.includes("admin");
|
|
200
|
+
}
|
|
201
|
+
|
|
197
202
|
// ============================================
|
|
198
203
|
// HTTP Helpers
|
|
199
204
|
// ============================================
|
|
@@ -265,16 +270,14 @@ export function detectAuth(registry: AgentRegistry): AuthConfig {
|
|
|
265
270
|
const authAgent = registry.get("@auth") as
|
|
266
271
|
| (AgentDefinition & {
|
|
267
272
|
__authStore?: AuthStore;
|
|
268
|
-
__rootKey?: string;
|
|
269
273
|
__tokenTtl?: number;
|
|
270
274
|
})
|
|
271
275
|
| undefined;
|
|
272
276
|
|
|
273
|
-
if (!authAgent?.__authStore
|
|
277
|
+
if (!authAgent?.__authStore) return {};
|
|
274
278
|
|
|
275
279
|
return {
|
|
276
280
|
store: authAgent.__authStore,
|
|
277
|
-
rootKey: authAgent.__rootKey,
|
|
278
281
|
tokenTtl: authAgent.__tokenTtl ?? 3600,
|
|
279
282
|
};
|
|
280
283
|
}
|
|
@@ -293,17 +296,6 @@ export async function resolveAuth(
|
|
|
293
296
|
const [scheme, credential] = authHeader.split(" ", 2);
|
|
294
297
|
if (scheme?.toLowerCase() !== "bearer" || !credential) return null;
|
|
295
298
|
|
|
296
|
-
// Root key check
|
|
297
|
-
if (authConfig.rootKey && credential === authConfig.rootKey) {
|
|
298
|
-
return {
|
|
299
|
-
callerId: "root",
|
|
300
|
-
callerType: "system",
|
|
301
|
-
scopes: ["*"],
|
|
302
|
-
isRoot: true,
|
|
303
|
-
claims: {},
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
299
|
// Try ES256 verification against own signing keys
|
|
308
300
|
const parts = credential.split(".");
|
|
309
301
|
if (parts.length === 3 && jwksOptions?.signingKeys?.length) {
|
|
@@ -315,7 +307,6 @@ export async function resolveAuth(
|
|
|
315
307
|
callerId: verified.sub ?? verified.name ?? "unknown",
|
|
316
308
|
callerType: "agent",
|
|
317
309
|
scopes: verified.scopes ?? ["*"],
|
|
318
|
-
isRoot: false,
|
|
319
310
|
claims: verified as unknown as Record<string, unknown>,
|
|
320
311
|
};
|
|
321
312
|
}
|
|
@@ -347,7 +338,6 @@ export async function resolveAuth(
|
|
|
347
338
|
callerId: verified.sub ?? verified.name ?? "unknown",
|
|
348
339
|
callerType: isSystem ? "system" : "agent",
|
|
349
340
|
scopes,
|
|
350
|
-
isRoot: isSystem,
|
|
351
341
|
claims: verified as unknown as Record<string, unknown>,
|
|
352
342
|
};
|
|
353
343
|
}
|
|
@@ -379,7 +369,6 @@ export async function resolveAuth(
|
|
|
379
369
|
callerId: verified.name || client.name,
|
|
380
370
|
callerType: "agent",
|
|
381
371
|
scopes: verified.scopes,
|
|
382
|
-
isRoot: false,
|
|
383
372
|
claims: verified as unknown as Record<string, unknown>,
|
|
384
373
|
};
|
|
385
374
|
}
|
|
@@ -400,7 +389,6 @@ export async function resolveAuth(
|
|
|
400
389
|
callerId: client?.name ?? token.clientId,
|
|
401
390
|
callerType: "agent",
|
|
402
391
|
scopes: token.scopes,
|
|
403
|
-
isRoot: false,
|
|
404
392
|
claims: {},
|
|
405
393
|
};
|
|
406
394
|
}
|
|
@@ -412,7 +400,7 @@ export function canSeeAgent(
|
|
|
412
400
|
const visibility = ((agent as any).visibility ??
|
|
413
401
|
agent.config?.visibility ??
|
|
414
402
|
"internal") as Visibility;
|
|
415
|
-
if (auth
|
|
403
|
+
if (hasAdminScope(auth)) return true;
|
|
416
404
|
if (visibility === "public") return true;
|
|
417
405
|
if (visibility === "internal" && auth) return true;
|
|
418
406
|
return false;
|
|
@@ -445,10 +433,10 @@ function getVisibleTools(
|
|
|
445
433
|
"internal") as Visibility;
|
|
446
434
|
return agent.tools.filter((t) => {
|
|
447
435
|
const tv = t.visibility;
|
|
448
|
-
if (auth
|
|
436
|
+
if (hasAdminScope(auth)) return true;
|
|
449
437
|
// Tool has explicit visibility — respect it
|
|
450
438
|
if (tv === "public") return true;
|
|
451
|
-
if (tv === "private") return auth
|
|
439
|
+
if (tv === "private") return hasAdminScope(auth) ?? false;
|
|
452
440
|
if (tv === "internal" && auth) return true;
|
|
453
441
|
// No explicit tool visibility — inherit from agent
|
|
454
442
|
if (!tv && agentVisibility === "public") return true;
|
|
@@ -622,10 +610,9 @@ export function createAgentServer(
|
|
|
622
610
|
req.callerType = auth.callerType;
|
|
623
611
|
if (!req.metadata) req.metadata = {};
|
|
624
612
|
req.metadata.scopes = auth.scopes;
|
|
625
|
-
req.metadata.isRoot = auth.isRoot;
|
|
626
613
|
if (auth.issuer) req.metadata.issuer = auth.issuer;
|
|
627
614
|
}
|
|
628
|
-
if (auth
|
|
615
|
+
if (hasAdminScope(auth)) {
|
|
629
616
|
req.callerType = "system";
|
|
630
617
|
}
|
|
631
618
|
|
|
@@ -663,7 +650,7 @@ export function createAgentServer(
|
|
|
663
650
|
tools: agent.tools
|
|
664
651
|
.filter((t) => {
|
|
665
652
|
const tv = t.visibility ?? "internal";
|
|
666
|
-
if (auth
|
|
653
|
+
if (hasAdminScope(auth)) return true;
|
|
667
654
|
if (tv === "public") return true;
|
|
668
655
|
if (
|
|
669
656
|
tv === "authenticated" &&
|
|
@@ -707,7 +694,7 @@ export function createAgentServer(
|
|
|
707
694
|
for (const agent of visible) {
|
|
708
695
|
const visibleTools = agent.tools.filter((t) => {
|
|
709
696
|
const tv = t.visibility ?? "internal";
|
|
710
|
-
if (auth
|
|
697
|
+
if (hasAdminScope(auth)) return true;
|
|
711
698
|
if (tv === "public") return true;
|
|
712
699
|
if (
|
|
713
700
|
tv === "authenticated" &&
|
|
@@ -1053,7 +1040,6 @@ export function createAgentServer(
|
|
|
1053
1040
|
callerId: actorId,
|
|
1054
1041
|
callerType: (actorType as any) ?? "agent",
|
|
1055
1042
|
scopes: ["*"],
|
|
1056
|
-
isRoot: false,
|
|
1057
1043
|
claims: {},
|
|
1058
1044
|
};
|
|
1059
1045
|
}
|
|
@@ -1281,7 +1267,7 @@ export function createAgentServer(
|
|
|
1281
1267
|
tools: agent.tools
|
|
1282
1268
|
.filter((t) => {
|
|
1283
1269
|
const tv = t.visibility ?? "internal";
|
|
1284
|
-
if (effectiveAuth
|
|
1270
|
+
if (hasAdminScope(effectiveAuth)) return true;
|
|
1285
1271
|
if (tv === "public") return true;
|
|
1286
1272
|
if (tv === "internal" && effectiveAuth) return true;
|
|
1287
1273
|
return false;
|
|
@@ -1309,6 +1295,8 @@ export function createAgentServer(
|
|
|
1309
1295
|
name: agent.config?.name,
|
|
1310
1296
|
description:
|
|
1311
1297
|
agent.config?.description ?? agent.entrypoint?.slice(0, 200),
|
|
1298
|
+
mode: agent.mode ?? 'direct',
|
|
1299
|
+
...(agent.upstream && { upstream: agent.upstream }),
|
|
1312
1300
|
tools: getVisibleTools(agent, effectiveAuth).map((t) => ({
|
|
1313
1301
|
name: t.name,
|
|
1314
1302
|
description: t.description,
|
|
@@ -1334,6 +1322,8 @@ export function createAgentServer(
|
|
|
1334
1322
|
name: agent.config?.name,
|
|
1335
1323
|
description:
|
|
1336
1324
|
agent.config?.description ?? agent.entrypoint?.slice(0, 200),
|
|
1325
|
+
mode: agent.mode ?? 'direct',
|
|
1326
|
+
...(agent.upstream && { upstream: agent.upstream }),
|
|
1337
1327
|
tools: getVisibleTools(agent, effectiveAuth).map((t) => ({
|
|
1338
1328
|
name: t.name,
|
|
1339
1329
|
description: t.description,
|
|
@@ -1379,7 +1369,7 @@ export function createAgentServer(
|
|
|
1379
1369
|
callerId: effectiveAuth?.callerId,
|
|
1380
1370
|
callerType: effectiveAuth?.callerType ?? "system",
|
|
1381
1371
|
metadata: effectiveAuth
|
|
1382
|
-
? { scopes: effectiveAuth.scopes
|
|
1372
|
+
? { scopes: effectiveAuth.scopes }
|
|
1383
1373
|
: undefined,
|
|
1384
1374
|
});
|
|
1385
1375
|
const res = jsonResponse({ success: true, result });
|
|
@@ -1464,7 +1454,6 @@ export function createAgentServer(
|
|
|
1464
1454
|
metadata: effectiveAuth
|
|
1465
1455
|
? {
|
|
1466
1456
|
scopes: effectiveAuth.scopes,
|
|
1467
|
-
isRoot: effectiveAuth.isRoot,
|
|
1468
1457
|
...(effectiveAuth.issuer
|
|
1469
1458
|
? { issuer: effectiveAuth.issuer }
|
|
1470
1459
|
: {}),
|
package/src/types.ts
CHANGED
|
@@ -633,6 +633,19 @@ export interface AgentDefinition<TContext extends ToolContext = ToolContext> {
|
|
|
633
633
|
/** Tools provided by this agent */
|
|
634
634
|
tools: ToolDefinition<TContext, unknown, unknown>[];
|
|
635
635
|
|
|
636
|
+
/**
|
|
637
|
+
* Registry hosting mode:
|
|
638
|
+
* - 'direct': registry hosts and serves this agent's tools (default)
|
|
639
|
+
* - 'redirect': registry catalogs this agent but clients connect to `upstream` directly
|
|
640
|
+
*/
|
|
641
|
+
mode?: 'direct' | 'redirect';
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Upstream URL for redirect-mode agents.
|
|
645
|
+
* When mode is 'redirect', clients should connect to this URL instead of the registry.
|
|
646
|
+
*/
|
|
647
|
+
upstream?: string;
|
|
648
|
+
|
|
636
649
|
/**
|
|
637
650
|
* Runtime hooks factory.
|
|
638
651
|
* Called once to create the runtime for this agent.
|