@slashfi/agents-sdk 0.6.0 → 0.8.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/integrations.d.ts +9 -12
- package/dist/agent-definitions/integrations.d.ts.map +1 -1
- package/dist/agent-definitions/integrations.js +21 -36
- package/dist/agent-definitions/integrations.js.map +1 -1
- package/dist/agent-definitions/remote-registry.d.ts +32 -0
- package/dist/agent-definitions/remote-registry.d.ts.map +1 -0
- package/dist/agent-definitions/remote-registry.js +460 -0
- package/dist/agent-definitions/remote-registry.js.map +1 -0
- package/dist/agent-definitions/secrets.d.ts +26 -3
- package/dist/agent-definitions/secrets.d.ts.map +1 -1
- package/dist/agent-definitions/secrets.js +26 -3
- package/dist/agent-definitions/secrets.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +6 -0
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +4 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +49 -12
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent-definitions/integrations.ts +27 -50
- package/src/agent-definitions/remote-registry.ts +621 -0
- package/src/agent-definitions/secrets.ts +61 -6
- package/src/index.ts +5 -1
- package/src/registry.ts +6 -0
- package/src/server.ts +47 -13
- package/src/types.ts +20 -1
|
@@ -20,13 +20,42 @@ import type { AgentDefinition, ToolContext, ToolDefinition } from "../types.js";
|
|
|
20
20
|
* Pluggable secret storage backend.
|
|
21
21
|
* Stores encrypted values, resolves refs.
|
|
22
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* Scope for multi-tenant secret isolation.
|
|
25
|
+
* When provided, secrets are partitioned by tenant/instance.
|
|
26
|
+
*/
|
|
27
|
+
export interface SecretScope {
|
|
28
|
+
tenantId: string;
|
|
29
|
+
instanceKey?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
export interface SecretStore {
|
|
24
33
|
/** Store a secret. Returns the secret ID (without prefix). */
|
|
25
|
-
store(value: string, ownerId: string): Promise<string>;
|
|
34
|
+
store(value: string, ownerId: string, scope?: SecretScope): Promise<string>;
|
|
35
|
+
|
|
26
36
|
/** Resolve a secret ID to its decrypted value. */
|
|
27
|
-
resolve(id: string, ownerId: string): Promise<string | null>;
|
|
37
|
+
resolve(id: string, ownerId: string, scope?: SecretScope): Promise<string | null>;
|
|
38
|
+
|
|
28
39
|
/** Delete a secret. */
|
|
29
|
-
delete(id: string, ownerId: string): Promise<boolean>;
|
|
40
|
+
delete(id: string, ownerId: string, scope?: SecretScope): Promise<boolean>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Store multiple secrets in a single operation.
|
|
44
|
+
* Returns an array of secret IDs in the same order as the input values.
|
|
45
|
+
*/
|
|
46
|
+
storeBatch?(values: string[], ownerId: string, scope?: SecretScope): Promise<string[]>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Associate a secret with an entity (e.g., a provider config, a connection).
|
|
50
|
+
* Enables lookup of secrets by entity rather than by ID.
|
|
51
|
+
*/
|
|
52
|
+
associate?(secretId: string, entityType: string, entityId: string, scope?: SecretScope): Promise<void>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve secrets associated with an entity.
|
|
56
|
+
* Returns all secret IDs linked to the given entity.
|
|
57
|
+
*/
|
|
58
|
+
resolveByEntity?(entityType: string, entityId: string, scope?: SecretScope): Promise<string[]>;
|
|
30
59
|
}
|
|
31
60
|
|
|
32
61
|
// ============================================
|
|
@@ -61,27 +90,53 @@ function randomSecretId(): string {
|
|
|
61
90
|
|
|
62
91
|
export function createInMemorySecretStore(encryptionKey: string): SecretStore {
|
|
63
92
|
const secrets = new Map<string, { encrypted: string; ownerId: string }>();
|
|
93
|
+
const associations = new Map<string, string[]>(); // "entityType:entityId" -> secretIds
|
|
64
94
|
|
|
65
95
|
return {
|
|
66
|
-
async store(value, ownerId) {
|
|
96
|
+
async store(value, ownerId, _scope?) {
|
|
67
97
|
const id = randomSecretId();
|
|
68
98
|
const encrypted = await encryptSecret(value, encryptionKey);
|
|
69
99
|
secrets.set(id, { encrypted, ownerId });
|
|
70
100
|
return id;
|
|
71
101
|
},
|
|
72
102
|
|
|
73
|
-
async resolve(id, ownerId) {
|
|
103
|
+
async resolve(id, ownerId, _scope?) {
|
|
74
104
|
const entry = secrets.get(id);
|
|
75
105
|
if (!entry || entry.ownerId !== ownerId) return null;
|
|
76
106
|
return decryptSecret(entry.encrypted, encryptionKey);
|
|
77
107
|
},
|
|
78
108
|
|
|
79
|
-
async delete(id, ownerId) {
|
|
109
|
+
async delete(id, ownerId, _scope?) {
|
|
80
110
|
const entry = secrets.get(id);
|
|
81
111
|
if (!entry || entry.ownerId !== ownerId) return false;
|
|
82
112
|
secrets.delete(id);
|
|
83
113
|
return true;
|
|
84
114
|
},
|
|
115
|
+
|
|
116
|
+
async storeBatch(values, ownerId, _scope?) {
|
|
117
|
+
const ids: string[] = [];
|
|
118
|
+
for (const value of values) {
|
|
119
|
+
const id = randomSecretId();
|
|
120
|
+
const encrypted = await encryptSecret(value, encryptionKey);
|
|
121
|
+
secrets.set(id, { encrypted, ownerId });
|
|
122
|
+
ids.push(id);
|
|
123
|
+
}
|
|
124
|
+
return ids;
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
async associate(secretId, entityType, entityId, _scope?) {
|
|
128
|
+
const key = `${entityType}:${entityId}`;
|
|
129
|
+
const existing = associations.get(key) ?? [];
|
|
130
|
+
if (!existing.includes(secretId)) {
|
|
131
|
+
existing.push(secretId);
|
|
132
|
+
associations.set(key, existing);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
async resolveByEntity(entityType, entityId, _scope?) {
|
|
137
|
+
const key = `${entityType}:${entityId}`;
|
|
138
|
+
return associations.get(key) ?? [];
|
|
139
|
+
},
|
|
85
140
|
};
|
|
86
141
|
}
|
|
87
142
|
|
package/src/index.ts
CHANGED
|
@@ -125,6 +125,7 @@ export {
|
|
|
125
125
|
processSecretParams,
|
|
126
126
|
} from "./agent-definitions/secrets.js";
|
|
127
127
|
export type {
|
|
128
|
+
SecretScope,
|
|
128
129
|
SecretStore,
|
|
129
130
|
SecretsAgentOptions,
|
|
130
131
|
} from "./agent-definitions/secrets.js";
|
|
@@ -157,13 +158,16 @@ export type {
|
|
|
157
158
|
IntegrationCallInput,
|
|
158
159
|
RestCallInput,
|
|
159
160
|
GraphqlCallInput,
|
|
160
|
-
AgentRegistryCallInput,
|
|
161
161
|
UserConnection,
|
|
162
162
|
ClientAuthMethod,
|
|
163
163
|
TokenContentType,
|
|
164
164
|
TokenExchangeResult,
|
|
165
165
|
} from "./agent-definitions/integrations.js";
|
|
166
166
|
|
|
167
|
+
|
|
168
|
+
// Remote Registry
|
|
169
|
+
export { createRemoteRegistryAgent } from "./agent-definitions/remote-registry.js";
|
|
170
|
+
export type { RemoteRegistryAgentOptions } from "./agent-definitions/remote-registry.js";
|
|
167
171
|
// Users
|
|
168
172
|
export {
|
|
169
173
|
createUsersAgent,
|
package/src/registry.ts
CHANGED
|
@@ -290,6 +290,12 @@ export function createAgentRegistry(
|
|
|
290
290
|
};
|
|
291
291
|
|
|
292
292
|
try {
|
|
293
|
+
if (!tool.execute) {
|
|
294
|
+
return {
|
|
295
|
+
success: false,
|
|
296
|
+
error: `Tool ${request.tool} has no execute function`,
|
|
297
|
+
} as CallAgentErrorResponse;
|
|
298
|
+
}
|
|
293
299
|
const result = await tool.execute(request.params, ctx);
|
|
294
300
|
return {
|
|
295
301
|
success: true,
|
package/src/server.ts
CHANGED
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
* - list_agents → List registered agents and their tools
|
|
15
15
|
*
|
|
16
16
|
* Additional endpoints:
|
|
17
|
-
* - POST /oauth/token
|
|
18
|
-
* - GET
|
|
17
|
+
* - POST /oauth/token → OAuth2 client_credentials (when @auth registered)
|
|
18
|
+
* - GET /oauth/callback → Unified OAuth callback (provider from state)
|
|
19
|
+
* - GET /integrations/callback/* → Legacy OAuth callback (provider from URL path)
|
|
20
|
+
* - GET /health → Health check
|
|
19
21
|
*
|
|
20
22
|
* Auth Integration:
|
|
21
23
|
* When an `@auth` agent is registered, the server automatically:
|
|
@@ -702,13 +704,8 @@ export function createAgentServer(
|
|
|
702
704
|
}
|
|
703
705
|
|
|
704
706
|
|
|
705
|
-
//
|
|
706
|
-
|
|
707
|
-
const provider = path.split("/integrations/callback/")[1]?.split("?")[0];
|
|
708
|
-
if (!provider) {
|
|
709
|
-
return addCors(jsonResponse({ error: "Missing provider" }, 400));
|
|
710
|
-
}
|
|
711
|
-
|
|
707
|
+
// ---- Shared OAuth callback handler ----
|
|
708
|
+
async function handleIntegrationOAuthCallback(provider: string, req: Request): Promise<Response> {
|
|
712
709
|
const url = new URL(req.url);
|
|
713
710
|
const code = url.searchParams.get("code");
|
|
714
711
|
const state = url.searchParams.get("state");
|
|
@@ -726,7 +723,6 @@ export function createAgentServer(
|
|
|
726
723
|
return addCors(jsonResponse({ error: "Missing authorization code" }, 400));
|
|
727
724
|
}
|
|
728
725
|
|
|
729
|
-
// Call handle_oauth_callback tool on @integrations
|
|
730
726
|
try {
|
|
731
727
|
await registry.call({
|
|
732
728
|
action: "execute_tool",
|
|
@@ -741,13 +737,19 @@ export function createAgentServer(
|
|
|
741
737
|
},
|
|
742
738
|
} as any);
|
|
743
739
|
|
|
744
|
-
// Parse redirect URL from state
|
|
740
|
+
// Parse redirect URL from state (base64-encoded JSON)
|
|
745
741
|
let redirectUrl = "/";
|
|
746
742
|
if (state) {
|
|
747
743
|
try {
|
|
748
|
-
const parsed = JSON.parse(state);
|
|
744
|
+
const parsed = JSON.parse(atob(state));
|
|
749
745
|
if (parsed.redirectUrl) redirectUrl = parsed.redirectUrl;
|
|
750
|
-
} catch {
|
|
746
|
+
} catch {
|
|
747
|
+
// Fallback: try raw JSON for backward compat
|
|
748
|
+
try {
|
|
749
|
+
const parsed = JSON.parse(state);
|
|
750
|
+
if (parsed.redirectUrl) redirectUrl = parsed.redirectUrl;
|
|
751
|
+
} catch {}
|
|
752
|
+
}
|
|
751
753
|
}
|
|
752
754
|
|
|
753
755
|
const sep = redirectUrl.includes("?") ? "&" : "?";
|
|
@@ -760,6 +762,38 @@ export function createAgentServer(
|
|
|
760
762
|
}
|
|
761
763
|
}
|
|
762
764
|
|
|
765
|
+
// GET /oauth/callback - Unified OAuth callback (provider from state param)
|
|
766
|
+
if (path === "/oauth/callback" && req.method === "GET") {
|
|
767
|
+
const url = new URL(req.url);
|
|
768
|
+
const state = url.searchParams.get("state");
|
|
769
|
+
let provider: string | undefined;
|
|
770
|
+
if (state) {
|
|
771
|
+
try {
|
|
772
|
+
const parsed = JSON.parse(atob(state));
|
|
773
|
+
provider = parsed.providerId;
|
|
774
|
+
} catch {
|
|
775
|
+
// Fallback: try raw JSON for backward compat
|
|
776
|
+
try {
|
|
777
|
+
const parsed = JSON.parse(state);
|
|
778
|
+
provider = parsed.providerId;
|
|
779
|
+
} catch {}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
if (!provider) {
|
|
783
|
+
return addCors(jsonResponse({ error: "Missing provider in state param" }, 400));
|
|
784
|
+
}
|
|
785
|
+
return handleIntegrationOAuthCallback(provider, req);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// GET /integrations/callback/:provider - Legacy OAuth callback (provider from URL path)
|
|
789
|
+
if (path.startsWith("/integrations/callback/") && req.method === "GET") {
|
|
790
|
+
const provider = path.split("/integrations/callback/")[1]?.split("?")[0];
|
|
791
|
+
if (!provider) {
|
|
792
|
+
return addCors(jsonResponse({ error: "Missing provider" }, 400));
|
|
793
|
+
}
|
|
794
|
+
return handleIntegrationOAuthCallback(provider, req);
|
|
795
|
+
}
|
|
796
|
+
|
|
763
797
|
|
|
764
798
|
// GET /secrets/form/:token - Serve hosted secrets form
|
|
765
799
|
if (path.startsWith("/secrets/form/") && req.method === "GET") {
|
package/src/types.ts
CHANGED
|
@@ -421,8 +421,21 @@ export interface ToolDefinition<
|
|
|
421
421
|
|
|
422
422
|
/**
|
|
423
423
|
* Execute the tool with validated input.
|
|
424
|
+
* Optional — some registries load tool implementations dynamically.
|
|
424
425
|
*/
|
|
425
|
-
execute
|
|
426
|
+
execute?: (input: TInput, ctx: TContext) => Promise<TOutput>;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Path to the tool source file (e.g., '/agents/@clock/timer.tool.ts').
|
|
430
|
+
* Used for tool discovery and prompt composition.
|
|
431
|
+
*/
|
|
432
|
+
path?: string;
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Full documentation content for system prompt composition.
|
|
436
|
+
* When set, rendered directly into the agent's system prompt.
|
|
437
|
+
*/
|
|
438
|
+
doc?: string;
|
|
426
439
|
}
|
|
427
440
|
|
|
428
441
|
/**
|
|
@@ -473,6 +486,12 @@ export interface AgentDefinition<TContext extends ToolContext = ToolContext> {
|
|
|
473
486
|
* by @integrations via standard methods (setup, list, connect, get, update).
|
|
474
487
|
*/
|
|
475
488
|
integrationMethods?: IntegrationMethods;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Lazy loader for lifecycle listeners.
|
|
492
|
+
* Called once to load runtime hooks exported from the agent's entrypoint module.
|
|
493
|
+
*/
|
|
494
|
+
loadListeners?: () => Promise<unknown>;
|
|
476
495
|
}
|
|
477
496
|
|
|
478
497
|
// ============================================
|