@agentforge-io/core 0.2.0 → 2.0.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/services/agent-runner.service.d.ts +11 -3
- package/dist/services/agent-runner.service.js +14 -3
- package/dist/services/agent.service.d.ts +12 -0
- package/dist/services/agent.service.js +10 -2
- package/dist/services/connector-registry.service.d.ts +17 -0
- package/dist/services/connector-registry.service.js +26 -0
- package/dist/types/config.types.d.ts +9 -0
- package/package.json +1 -1
|
@@ -26,9 +26,17 @@ export declare class AgentRunnerService {
|
|
|
26
26
|
* - `extras`: a name→definition map so `dispatchTool` can route execution
|
|
27
27
|
* for tools that aren't in the global registry
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* **Connector tools follow the same whitelist as global tools.** An extra
|
|
30
|
+
* is only injected if its name appears in `agent.tools[]`. That keeps
|
|
31
|
+
* "an agent only sees what its definition declares" — a single contract
|
|
32
|
+
* for built-ins, MCP tools, and connector tools alike. Without this
|
|
33
|
+
* filter, any agent run by a user with Gmail/Drive/... connected would
|
|
34
|
+
* silently gain access to those APIs, which is both a security hole and
|
|
35
|
+
* makes curation impossible.
|
|
36
|
+
*
|
|
37
|
+
* Extras with the same name as a global tool shadow the global one —
|
|
38
|
+
* useful when a connector wants to override the built-in `http_request`,
|
|
39
|
+
* for example. The shadowing only lasts for this call.
|
|
32
40
|
*/
|
|
33
41
|
private buildToolList;
|
|
34
42
|
private dispatchTool;
|
|
@@ -193,17 +193,28 @@ class AgentRunnerService {
|
|
|
193
193
|
* - `extras`: a name→definition map so `dispatchTool` can route execution
|
|
194
194
|
* for tools that aren't in the global registry
|
|
195
195
|
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
196
|
+
* **Connector tools follow the same whitelist as global tools.** An extra
|
|
197
|
+
* is only injected if its name appears in `agent.tools[]`. That keeps
|
|
198
|
+
* "an agent only sees what its definition declares" — a single contract
|
|
199
|
+
* for built-ins, MCP tools, and connector tools alike. Without this
|
|
200
|
+
* filter, any agent run by a user with Gmail/Drive/... connected would
|
|
201
|
+
* silently gain access to those APIs, which is both a security hole and
|
|
202
|
+
* makes curation impossible.
|
|
203
|
+
*
|
|
204
|
+
* Extras with the same name as a global tool shadow the global one —
|
|
205
|
+
* useful when a connector wants to override the built-in `http_request`,
|
|
206
|
+
* for example. The shadowing only lasts for this call.
|
|
199
207
|
*/
|
|
200
208
|
buildToolList(agent, overrides) {
|
|
201
209
|
const fromRegistry = agent.tools?.length
|
|
202
210
|
? this.toolRegistry.getToolsForAgent(agent.id, agent.tools)
|
|
203
211
|
: [];
|
|
212
|
+
const allowed = new Set(agent.tools ?? []);
|
|
204
213
|
const extras = new Map();
|
|
205
214
|
const extrasSchema = [];
|
|
206
215
|
for (const t of overrides?.extraTools ?? []) {
|
|
216
|
+
if (!allowed.has(t.name))
|
|
217
|
+
continue;
|
|
207
218
|
extras.set(t.name, t);
|
|
208
219
|
extrasSchema.push({
|
|
209
220
|
name: t.name,
|
|
@@ -29,6 +29,18 @@ export interface AgentRecord {
|
|
|
29
29
|
mcpServers?: McpServerConfig[];
|
|
30
30
|
metadata?: Record<string, unknown>;
|
|
31
31
|
isActive?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* When set, connector tools (Gmail, Drive, ...) are resolved against
|
|
34
|
+
* this user's OAuth authorizations instead of the caller's. Used by
|
|
35
|
+
* public-chat agents — a visitor's browser session can leverage the
|
|
36
|
+
* agent owner's authorized connectors without exposing the owner's
|
|
37
|
+
* identity in the conversation record.
|
|
38
|
+
*
|
|
39
|
+
* Leave undefined for personal agents where the caller owns the
|
|
40
|
+
* connectors themselves; in that case the SDK falls back to the
|
|
41
|
+
* caller's userId, preserving the original behavior.
|
|
42
|
+
*/
|
|
43
|
+
connectorOwnerUserId?: string;
|
|
32
44
|
}
|
|
33
45
|
/**
|
|
34
46
|
* Host-supplied resolver for per-tenant agent configurations. The SDK never
|
|
@@ -157,7 +157,11 @@ class AgentService {
|
|
|
157
157
|
role: 'user',
|
|
158
158
|
content: params.content,
|
|
159
159
|
});
|
|
160
|
-
|
|
160
|
+
// Connector tools follow `agent.connectorOwnerUserId` when the
|
|
161
|
+
// resolved agent declares one (e.g. a public-chat agent reusing the
|
|
162
|
+
// owner's Gmail authorization); otherwise they fall back to the
|
|
163
|
+
// caller's userId, which is the historical personal-agent path.
|
|
164
|
+
const extraTools = await this.resolveExtraTools(agent.connectorOwnerUserId ?? params.userId);
|
|
161
165
|
const response = await this.runner.run(agent, messages, {
|
|
162
166
|
userId: params.userId,
|
|
163
167
|
conversationId: params.conversationId,
|
|
@@ -217,7 +221,10 @@ class AgentService {
|
|
|
217
221
|
});
|
|
218
222
|
let fullContent = '';
|
|
219
223
|
let finalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
220
|
-
|
|
224
|
+
// Same precedence as sendMessage — agent.connectorOwnerUserId takes
|
|
225
|
+
// priority so a public-chat agent always uses the owner's connector
|
|
226
|
+
// toolbelt regardless of which visitor session is streaming.
|
|
227
|
+
const extraTools = await this.resolveExtraTools(agent.connectorOwnerUserId ?? params.userId);
|
|
221
228
|
for await (const chunk of this.runner.stream(agent, messages, {
|
|
222
229
|
userId: params.userId,
|
|
223
230
|
conversationId: params.conversationId,
|
|
@@ -325,5 +332,6 @@ function toAgentDefinition(record) {
|
|
|
325
332
|
tools: record.tools,
|
|
326
333
|
mcpServers: record.mcpServers,
|
|
327
334
|
metadata: record.metadata,
|
|
335
|
+
connectorOwnerUserId: record.connectorOwnerUserId,
|
|
328
336
|
};
|
|
329
337
|
}
|
|
@@ -143,6 +143,23 @@ export declare class ConnectorRegistryService {
|
|
|
143
143
|
}>;
|
|
144
144
|
listForUser(userId: string): Promise<ConnectorStatus[]>;
|
|
145
145
|
disconnect(userId: string, connectorId: string): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Returns the full catalog of tool *definitions* across every registered
|
|
148
|
+
* connector, regardless of whether any user has authorized them. Used by
|
|
149
|
+
* the agent-editor UI so an operator can whitelist connector tools per
|
|
150
|
+
* agent the same way they whitelist built-ins — the runner enforces the
|
|
151
|
+
* whitelist via `agent.tools[]`, so listing here doesn't grant access.
|
|
152
|
+
*
|
|
153
|
+
* No tokens are surfaced and no `execute` is returned: this view is
|
|
154
|
+
* deliberately metadata-only.
|
|
155
|
+
*/
|
|
156
|
+
availableTools(): Array<{
|
|
157
|
+
name: string;
|
|
158
|
+
description: string;
|
|
159
|
+
connectorId: string;
|
|
160
|
+
connectorName: string;
|
|
161
|
+
inputSchema: unknown;
|
|
162
|
+
}>;
|
|
146
163
|
/**
|
|
147
164
|
* Returns the toolbelt for `userId`: one `AgentToolDefinition` per tool
|
|
148
165
|
* of every connector the user has authorized. Each handler is bound to a
|
|
@@ -179,6 +179,32 @@ class ConnectorRegistryService {
|
|
|
179
179
|
throw new ConnectorError('not_connected', 'No active auth row');
|
|
180
180
|
await this.deps.authRepo.delete(a.id);
|
|
181
181
|
}
|
|
182
|
+
// ─── Catalog (no auth) ───────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Returns the full catalog of tool *definitions* across every registered
|
|
185
|
+
* connector, regardless of whether any user has authorized them. Used by
|
|
186
|
+
* the agent-editor UI so an operator can whitelist connector tools per
|
|
187
|
+
* agent the same way they whitelist built-ins — the runner enforces the
|
|
188
|
+
* whitelist via `agent.tools[]`, so listing here doesn't grant access.
|
|
189
|
+
*
|
|
190
|
+
* No tokens are surfaced and no `execute` is returned: this view is
|
|
191
|
+
* deliberately metadata-only.
|
|
192
|
+
*/
|
|
193
|
+
availableTools() {
|
|
194
|
+
const out = [];
|
|
195
|
+
for (const def of this.defs.values()) {
|
|
196
|
+
for (const factory of def.tools) {
|
|
197
|
+
out.push({
|
|
198
|
+
name: factory.definition.name,
|
|
199
|
+
description: factory.definition.description,
|
|
200
|
+
connectorId: def.id,
|
|
201
|
+
connectorName: def.name,
|
|
202
|
+
inputSchema: factory.definition.inputSchema,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
182
208
|
// ─── Per-user tool synthesis ─────────────────────────────────────────────
|
|
183
209
|
/**
|
|
184
210
|
* Returns the toolbelt for `userId`: one `AgentToolDefinition` per tool
|
|
@@ -94,6 +94,15 @@ export interface AgentDefinition {
|
|
|
94
94
|
requiredPlan?: string[];
|
|
95
95
|
/** Custom metadata */
|
|
96
96
|
metadata?: Record<string, unknown>;
|
|
97
|
+
/**
|
|
98
|
+
* When set, connector tools (Gmail, Drive, ...) are resolved against
|
|
99
|
+
* this user's OAuth authorizations instead of the caller's. Lets a
|
|
100
|
+
* public-chat agent reuse the agent owner's authorized connectors
|
|
101
|
+
* while keeping the conversation scoped to the visitor. Leave
|
|
102
|
+
* undefined for personal agents — the SDK falls back to the caller's
|
|
103
|
+
* userId, preserving the original behavior.
|
|
104
|
+
*/
|
|
105
|
+
connectorOwnerUserId?: string;
|
|
97
106
|
}
|
|
98
107
|
/**
|
|
99
108
|
* Configuration for an MCP server the runtime should connect to.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Framework-free AI runtime SDK. Owns: agent loop (Anthropic), conversations, tools, streaming, agent-job queue, SdkHooks. Identity, billing, infra (email/uploads/secrets) live in the host's modules — not here.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|