@agentforge-io/core 2.0.3 → 2.0.5
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/builtins/current-time.tool.d.ts +21 -0
- package/dist/builtins/current-time.tool.js +135 -0
- package/dist/builtins/index.d.ts +1 -0
- package/dist/builtins/index.js +10 -0
- package/dist/services/agent-runner.service.js +4 -3
- package/dist/services/agent.service.d.ts +7 -0
- package/dist/services/agent.service.js +3 -0
- package/dist/services/mcp-client.service.js +4 -0
- package/dist/services/mcp-server.service.js +4 -0
- package/dist/services/tool-registry.service.d.ts +16 -1
- package/dist/services/tool-registry.service.js +39 -3
- package/dist/types/agent.types.d.ts +22 -0
- package/dist/types/config.types.d.ts +13 -0
- package/package.json +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AgentToolDefinition } from '../types/agent.types';
|
|
2
|
+
/**
|
|
3
|
+
* `current_time` — built-in tool every agent gets for free.
|
|
4
|
+
*
|
|
5
|
+
* Models can't read the system clock. Without this, "what's today's
|
|
6
|
+
* date?" / "what time is it in Bogotá?" answers drift to either the
|
|
7
|
+
* training cutoff (months off) or the host server's UTC, neither of
|
|
8
|
+
* which match the user's expectations. This tool anchors every time
|
|
9
|
+
* question to the agent's configured IANA timezone.
|
|
10
|
+
*
|
|
11
|
+
* Input is optional: when no `timezone` argument is supplied we fall
|
|
12
|
+
* back to `context.agent.timezone` (set by the runner from the
|
|
13
|
+
* AgentDefinition), and finally to `"UTC"` so the call still succeeds
|
|
14
|
+
* on agents with no tz configured.
|
|
15
|
+
*
|
|
16
|
+
* Output is a compact JSON object — easier for the model to quote
|
|
17
|
+
* specific pieces (just the weekday, just the ISO) than a natural-
|
|
18
|
+
* language string would be.
|
|
19
|
+
*/
|
|
20
|
+
export declare const CURRENT_TIME_TOOL_NAME = "current_time";
|
|
21
|
+
export declare function currentTimeTool(): AgentToolDefinition;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CURRENT_TIME_TOOL_NAME = void 0;
|
|
4
|
+
exports.currentTimeTool = currentTimeTool;
|
|
5
|
+
/**
|
|
6
|
+
* `current_time` — built-in tool every agent gets for free.
|
|
7
|
+
*
|
|
8
|
+
* Models can't read the system clock. Without this, "what's today's
|
|
9
|
+
* date?" / "what time is it in Bogotá?" answers drift to either the
|
|
10
|
+
* training cutoff (months off) or the host server's UTC, neither of
|
|
11
|
+
* which match the user's expectations. This tool anchors every time
|
|
12
|
+
* question to the agent's configured IANA timezone.
|
|
13
|
+
*
|
|
14
|
+
* Input is optional: when no `timezone` argument is supplied we fall
|
|
15
|
+
* back to `context.agent.timezone` (set by the runner from the
|
|
16
|
+
* AgentDefinition), and finally to `"UTC"` so the call still succeeds
|
|
17
|
+
* on agents with no tz configured.
|
|
18
|
+
*
|
|
19
|
+
* Output is a compact JSON object — easier for the model to quote
|
|
20
|
+
* specific pieces (just the weekday, just the ISO) than a natural-
|
|
21
|
+
* language string would be.
|
|
22
|
+
*/
|
|
23
|
+
exports.CURRENT_TIME_TOOL_NAME = 'current_time';
|
|
24
|
+
function currentTimeTool() {
|
|
25
|
+
return {
|
|
26
|
+
name: exports.CURRENT_TIME_TOOL_NAME,
|
|
27
|
+
alwaysOn: true,
|
|
28
|
+
description: "Get the current date and time. Use this any time the user asks " +
|
|
29
|
+
'about "now", "today", "the current date", a deadline relative to ' +
|
|
30
|
+
"today, or anything else that depends on knowing the real-world " +
|
|
31
|
+
"wall-clock. The result is anchored to the agent's configured " +
|
|
32
|
+
'timezone unless the caller passes an explicit `timezone` argument.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
timezone: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'Optional IANA timezone (e.g. "America/Bogota", "Europe/Madrid", ' +
|
|
39
|
+
'"Asia/Tokyo"). Defaults to the agent\'s configured timezone.',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
},
|
|
44
|
+
execute: async (input, context) => {
|
|
45
|
+
const requested = typeof input.timezone === 'string' && input.timezone.trim()
|
|
46
|
+
? input.timezone.trim()
|
|
47
|
+
: undefined;
|
|
48
|
+
const fallback = context.agent?.timezone || 'UTC';
|
|
49
|
+
const tz = requested ?? fallback;
|
|
50
|
+
const now = new Date();
|
|
51
|
+
let iso;
|
|
52
|
+
let weekday;
|
|
53
|
+
let resolvedTz = tz;
|
|
54
|
+
try {
|
|
55
|
+
// Use Intl to format the offset in the target tz, then assemble an
|
|
56
|
+
// ISO 8601 string that includes the offset. `toISOString()` is UTC
|
|
57
|
+
// only, which would defeat the purpose.
|
|
58
|
+
iso = formatIsoInTimezone(now, tz);
|
|
59
|
+
weekday = new Intl.DateTimeFormat('en-US', {
|
|
60
|
+
weekday: 'long',
|
|
61
|
+
timeZone: tz,
|
|
62
|
+
}).format(now);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Invalid IANA string — fall back to UTC rather than failing the
|
|
66
|
+
// tool call (which would surface as a confusing model error).
|
|
67
|
+
resolvedTz = 'UTC';
|
|
68
|
+
iso = now.toISOString();
|
|
69
|
+
weekday = new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(now);
|
|
70
|
+
}
|
|
71
|
+
return JSON.stringify({
|
|
72
|
+
iso,
|
|
73
|
+
timezone: resolvedTz,
|
|
74
|
+
weekday,
|
|
75
|
+
epochMs: now.getTime(),
|
|
76
|
+
...(requested && requested !== resolvedTz
|
|
77
|
+
? { requestedTimezone: requested, note: 'invalid_timezone_fell_back_to_utc' }
|
|
78
|
+
: {}),
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build an ISO 8601 string that reflects the local wall-clock in `tz`.
|
|
85
|
+
*
|
|
86
|
+
* `Date#toISOString()` always emits UTC ("…Z"), so we hand-compose the
|
|
87
|
+
* parts via Intl. The shape is `YYYY-MM-DDTHH:mm:ss±HH:MM`, the form the
|
|
88
|
+
* model is most likely to have seen in training data.
|
|
89
|
+
*/
|
|
90
|
+
function formatIsoInTimezone(date, tz) {
|
|
91
|
+
// Throws on invalid tz — surfaced as a try/catch in the caller.
|
|
92
|
+
const dtf = new Intl.DateTimeFormat('en-US', {
|
|
93
|
+
timeZone: tz,
|
|
94
|
+
year: 'numeric',
|
|
95
|
+
month: '2-digit',
|
|
96
|
+
day: '2-digit',
|
|
97
|
+
hour: '2-digit',
|
|
98
|
+
minute: '2-digit',
|
|
99
|
+
second: '2-digit',
|
|
100
|
+
hour12: false,
|
|
101
|
+
});
|
|
102
|
+
const parts = Object.fromEntries(dtf.formatToParts(date).map((p) => [p.type, p.value]));
|
|
103
|
+
const offset = formatOffset(date, tz);
|
|
104
|
+
// `hour` reports "24" at midnight on some engines — normalize.
|
|
105
|
+
const hour = parts.hour === '24' ? '00' : parts.hour;
|
|
106
|
+
return `${parts.year}-${parts.month}-${parts.day}T${hour}:${parts.minute}:${parts.second}${offset}`;
|
|
107
|
+
}
|
|
108
|
+
function formatOffset(date, tz) {
|
|
109
|
+
// Compute the offset by formatting the same instant in UTC vs target tz
|
|
110
|
+
// and taking the delta. Cheaper than parsing Intl's `shortOffset` token,
|
|
111
|
+
// and avoids engine-specific formatting quirks.
|
|
112
|
+
const tzParts = partsToUtcMs(date, tz);
|
|
113
|
+
const utcParts = partsToUtcMs(date, 'UTC');
|
|
114
|
+
const diffMin = Math.round((tzParts - utcParts) / 60000);
|
|
115
|
+
const sign = diffMin >= 0 ? '+' : '-';
|
|
116
|
+
const abs = Math.abs(diffMin);
|
|
117
|
+
const hh = String(Math.floor(abs / 60)).padStart(2, '0');
|
|
118
|
+
const mm = String(abs % 60).padStart(2, '0');
|
|
119
|
+
return `${sign}${hh}:${mm}`;
|
|
120
|
+
}
|
|
121
|
+
function partsToUtcMs(date, tz) {
|
|
122
|
+
const dtf = new Intl.DateTimeFormat('en-US', {
|
|
123
|
+
timeZone: tz,
|
|
124
|
+
year: 'numeric',
|
|
125
|
+
month: '2-digit',
|
|
126
|
+
day: '2-digit',
|
|
127
|
+
hour: '2-digit',
|
|
128
|
+
minute: '2-digit',
|
|
129
|
+
second: '2-digit',
|
|
130
|
+
hour12: false,
|
|
131
|
+
});
|
|
132
|
+
const p = Object.fromEntries(dtf.formatToParts(date).map((pp) => [pp.type, pp.value]));
|
|
133
|
+
const hour = p.hour === '24' ? '00' : p.hour;
|
|
134
|
+
return Date.UTC(Number(p.year), Number(p.month) - 1, Number(p.day), Number(hour), Number(p.minute), Number(p.second));
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { currentTimeTool, CURRENT_TIME_TOOL_NAME } from './current-time.tool';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Built-in tools — always available to every agent regardless of the
|
|
3
|
+
// `agent.tools[]` whitelist. The runner registers these alongside the
|
|
4
|
+
// host-supplied catalog at boot time. UIs can still show them in the
|
|
5
|
+
// picker (read-only) so users understand the agent can call them.
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CURRENT_TIME_TOOL_NAME = exports.currentTimeTool = void 0;
|
|
8
|
+
var current_time_tool_1 = require("./current-time.tool");
|
|
9
|
+
Object.defineProperty(exports, "currentTimeTool", { enumerable: true, get: function () { return current_time_tool_1.currentTimeTool; } });
|
|
10
|
+
Object.defineProperty(exports, "CURRENT_TIME_TOOL_NAME", { enumerable: true, get: function () { return current_time_tool_1.CURRENT_TIME_TOOL_NAME; } });
|
|
@@ -206,9 +206,10 @@ class AgentRunnerService {
|
|
|
206
206
|
* for example. The shadowing only lasts for this call.
|
|
207
207
|
*/
|
|
208
208
|
buildToolList(agent, overrides) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
// Always invoke the registry — even when the agent has no whitelist —
|
|
210
|
+
// because alwaysOn tools (e.g. `current_time`) get folded in there and
|
|
211
|
+
// need to reach an agent whose `tools[]` is empty.
|
|
212
|
+
const fromRegistry = this.toolRegistry.getToolsForAgent(agent.id, agent.tools ?? []);
|
|
212
213
|
const allowed = new Set(agent.tools ?? []);
|
|
213
214
|
const extras = new Map();
|
|
214
215
|
const extrasSchema = [];
|
|
@@ -41,6 +41,13 @@ export interface AgentRecord {
|
|
|
41
41
|
* caller's userId, preserving the original behavior.
|
|
42
42
|
*/
|
|
43
43
|
connectorOwnerUserId?: string;
|
|
44
|
+
/**
|
|
45
|
+
* IANA timezone (e.g. `"America/Bogota"`, `"Europe/Madrid"`). The
|
|
46
|
+
* built-in `current_time` tool reads this to anchor "what time is it"
|
|
47
|
+
* answers to the agent owner's locale instead of the host server's UTC.
|
|
48
|
+
* Defaults to `"UTC"` when unset.
|
|
49
|
+
*/
|
|
50
|
+
timezone?: string;
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
46
53
|
* Host-supplied resolver for per-tenant agent configurations. The SDK never
|
|
@@ -167,6 +167,7 @@ class AgentService {
|
|
|
167
167
|
conversationId: params.conversationId,
|
|
168
168
|
agentId: conv.agentId,
|
|
169
169
|
messageId: 'sync',
|
|
170
|
+
agent: { timezone: agent.timezone },
|
|
170
171
|
}, { ...(params.overrides ?? {}), extraTools });
|
|
171
172
|
await this.conversations.addMessage({
|
|
172
173
|
conversationId: params.conversationId,
|
|
@@ -230,6 +231,7 @@ class AgentService {
|
|
|
230
231
|
conversationId: params.conversationId,
|
|
231
232
|
agentId: conv.agentId,
|
|
232
233
|
messageId: 'streaming',
|
|
234
|
+
agent: { timezone: agent.timezone },
|
|
233
235
|
}, { ...(params.overrides ?? {}), extraTools })) {
|
|
234
236
|
if (chunk.type === 'text_delta')
|
|
235
237
|
fullContent += chunk.delta;
|
|
@@ -338,6 +340,7 @@ function toAgentDefinition(record) {
|
|
|
338
340
|
mcpServers: record.mcpServers,
|
|
339
341
|
metadata: record.metadata,
|
|
340
342
|
connectorOwnerUserId: record.connectorOwnerUserId,
|
|
343
|
+
timezone: record.timezone,
|
|
341
344
|
...(record.slug !== undefined ? { slug: record.slug } : {}),
|
|
342
345
|
...(extra.appearance !== undefined ? { appearance: extra.appearance } : {}),
|
|
343
346
|
};
|
|
@@ -71,6 +71,10 @@ class McpClientService {
|
|
|
71
71
|
// Carry the MCP origin through to the registry so /tools can label
|
|
72
72
|
// and group these distinctly from built-ins / connector tools.
|
|
73
73
|
mcpServerName: config.name,
|
|
74
|
+
// Propagate the owning tenant when the host wired one; lets the
|
|
75
|
+
// catalog endpoint scope MCP rows per workspace so deepwiki@tenantA
|
|
76
|
+
// doesn't leak into tenantB's tools picker.
|
|
77
|
+
...(config.tenantId ? { tenantId: config.tenantId } : {}),
|
|
74
78
|
};
|
|
75
79
|
this.registry.register(wrapped);
|
|
76
80
|
handles.push({
|
|
@@ -158,5 +158,9 @@ function toClientConfig(r) {
|
|
|
158
158
|
transport: r.transport,
|
|
159
159
|
url: r.url,
|
|
160
160
|
headers: r.headers,
|
|
161
|
+
// Propagate the owning tenant so the registry can scope `/tools` by
|
|
162
|
+
// workspace; harmless on single-tenant deployments where it stays
|
|
163
|
+
// undefined.
|
|
164
|
+
tenantId: r.tenantId,
|
|
161
165
|
};
|
|
162
166
|
}
|
|
@@ -32,7 +32,15 @@ export declare class ToolRegistryService {
|
|
|
32
32
|
* `execute` function (not serializable) and surfaces the per-tool agent
|
|
33
33
|
* allowlist so a UI can show "this tool is only usable by agent X".
|
|
34
34
|
*/
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Public catalog. Pass `tenantId` to scope tenant-tagged tools (MCP rows
|
|
37
|
+
* registered per-tenant) to that tenant; built-ins and untagged tools are
|
|
38
|
+
* always returned. Omit `tenantId` to keep the legacy behavior of
|
|
39
|
+
* returning everything (used by tests and single-tenant deployments).
|
|
40
|
+
*/
|
|
41
|
+
describe(opts?: {
|
|
42
|
+
tenantId?: string;
|
|
43
|
+
}): ToolDescription[];
|
|
36
44
|
}
|
|
37
45
|
export interface ToolDescription {
|
|
38
46
|
name: string;
|
|
@@ -55,4 +63,11 @@ export interface ToolDescription {
|
|
|
55
63
|
* from built-ins / connector tools.
|
|
56
64
|
*/
|
|
57
65
|
mcpServerName?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Owning tenant for tenant-scoped tools (MCP servers registered per
|
|
68
|
+
* tenant). When the catalog endpoint is called with a tenant the
|
|
69
|
+
* registry filters by this field so workspaces don't see each other's
|
|
70
|
+
* MCP rows. Built-ins and untagged tools omit it.
|
|
71
|
+
*/
|
|
72
|
+
tenantId?: string;
|
|
58
73
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ToolRegistryService = void 0;
|
|
4
|
+
const current_time_tool_1 = require("../builtins/current-time.tool");
|
|
4
5
|
const noopLogger = {
|
|
5
6
|
log: () => { },
|
|
6
7
|
warn: () => { },
|
|
@@ -16,6 +17,10 @@ class ToolRegistryService {
|
|
|
16
17
|
constructor(opts = {}) {
|
|
17
18
|
this.tools = new Map();
|
|
18
19
|
this.logger = opts.logger ?? noopLogger;
|
|
20
|
+
// Built-in essentials registered before host tools so a host can still
|
|
21
|
+
// override by registering the same name (rare — but the explicit Map
|
|
22
|
+
// overwrite warning makes the swap visible).
|
|
23
|
+
this.register((0, current_time_tool_1.currentTimeTool)());
|
|
19
24
|
if (opts.initialTools)
|
|
20
25
|
this.registerMany(opts.initialTools);
|
|
21
26
|
}
|
|
@@ -39,7 +44,18 @@ class ToolRegistryService {
|
|
|
39
44
|
return existed;
|
|
40
45
|
}
|
|
41
46
|
getToolsForAgent(agentId, toolNames) {
|
|
42
|
-
|
|
47
|
+
// Always-on tools (e.g. `current_time`) are offered to every agent
|
|
48
|
+
// regardless of the whitelist — they're runtime essentials the model
|
|
49
|
+
// needs to answer correctly. Per-agent allowlists still apply.
|
|
50
|
+
const requested = new Set(toolNames);
|
|
51
|
+
for (const t of this.tools.values()) {
|
|
52
|
+
if (!t.alwaysOn)
|
|
53
|
+
continue;
|
|
54
|
+
if (t.agents && t.agents.length > 0 && !t.agents.includes(agentId))
|
|
55
|
+
continue;
|
|
56
|
+
requested.add(t.name);
|
|
57
|
+
}
|
|
58
|
+
return Array.from(requested)
|
|
43
59
|
.filter((name) => {
|
|
44
60
|
const tool = this.tools.get(name);
|
|
45
61
|
if (!tool) {
|
|
@@ -89,8 +105,27 @@ class ToolRegistryService {
|
|
|
89
105
|
* `execute` function (not serializable) and surfaces the per-tool agent
|
|
90
106
|
* allowlist so a UI can show "this tool is only usable by agent X".
|
|
91
107
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Public catalog. Pass `tenantId` to scope tenant-tagged tools (MCP rows
|
|
110
|
+
* registered per-tenant) to that tenant; built-ins and untagged tools are
|
|
111
|
+
* always returned. Omit `tenantId` to keep the legacy behavior of
|
|
112
|
+
* returning everything (used by tests and single-tenant deployments).
|
|
113
|
+
*/
|
|
114
|
+
describe(opts) {
|
|
115
|
+
const callerTenant = opts?.tenantId;
|
|
116
|
+
return Array.from(this.tools.values())
|
|
117
|
+
.filter((t) => {
|
|
118
|
+
// Tools without a tenant tag are global (built-ins, untagged MCPs
|
|
119
|
+
// from older callers). Tools with a tenant tag only appear for the
|
|
120
|
+
// matching tenant; when no caller tenant was supplied we surface
|
|
121
|
+
// them all (backwards-compat).
|
|
122
|
+
if (!t.tenantId)
|
|
123
|
+
return true;
|
|
124
|
+
if (!callerTenant)
|
|
125
|
+
return true;
|
|
126
|
+
return t.tenantId === callerTenant;
|
|
127
|
+
})
|
|
128
|
+
.map((t) => ({
|
|
94
129
|
name: t.name,
|
|
95
130
|
description: t.description,
|
|
96
131
|
inputSchema: t.inputSchema,
|
|
@@ -98,6 +133,7 @@ class ToolRegistryService {
|
|
|
98
133
|
...(t.connectorId ? { connectorId: t.connectorId } : {}),
|
|
99
134
|
...(t.connectorName ? { connectorName: t.connectorName } : {}),
|
|
100
135
|
...(t.mcpServerName ? { mcpServerName: t.mcpServerName } : {}),
|
|
136
|
+
...(t.tenantId ? { tenantId: t.tenantId } : {}),
|
|
101
137
|
}));
|
|
102
138
|
}
|
|
103
139
|
}
|
|
@@ -97,12 +97,34 @@ export interface AgentToolDefinition {
|
|
|
97
97
|
/** MCP server this tool was discovered from. Set by McpClientService when
|
|
98
98
|
* wrapping a remote tool; left undefined for built-ins and connector tools. */
|
|
99
99
|
mcpServerName?: string;
|
|
100
|
+
/**
|
|
101
|
+
* When true, the tool is offered to every agent regardless of whether the
|
|
102
|
+
* agent's `tools[]` whitelist mentions it. Used for runtime essentials
|
|
103
|
+
* like `current_time` that should never silently be off — the model
|
|
104
|
+
* needs them to answer correctly. UIs can still surface them in the
|
|
105
|
+
* picker as informational rows.
|
|
106
|
+
*/
|
|
107
|
+
alwaysOn?: boolean;
|
|
108
|
+
/** Owning tenantId for tenant-scoped tools (MCP servers registered per
|
|
109
|
+
* tenant). Used by `/tools` to filter results to the caller's tenant so
|
|
110
|
+
* the catalog doesn't leak another workspace's rows. Built-ins leave
|
|
111
|
+
* this unset and remain globally visible. */
|
|
112
|
+
tenantId?: string;
|
|
100
113
|
}
|
|
101
114
|
export interface ToolExecutionContext {
|
|
102
115
|
userId: string;
|
|
103
116
|
conversationId: string;
|
|
104
117
|
agentId: string;
|
|
105
118
|
messageId: string;
|
|
119
|
+
/**
|
|
120
|
+
* Agent-level configuration the tool may consult — e.g. `current_time`
|
|
121
|
+
* reads `timezone` to anchor results to the agent owner's locale. Set
|
|
122
|
+
* by the runner when it dispatches; tools should treat any field as
|
|
123
|
+
* optional and fall back to sensible defaults.
|
|
124
|
+
*/
|
|
125
|
+
agent?: {
|
|
126
|
+
timezone?: string;
|
|
127
|
+
};
|
|
106
128
|
}
|
|
107
129
|
export type AnthropicMessage = Anthropic.MessageParam;
|
|
108
130
|
export type AnthropicTool = Anthropic.Tool;
|
|
@@ -103,6 +103,12 @@ export interface AgentDefinition {
|
|
|
103
103
|
* userId, preserving the original behavior.
|
|
104
104
|
*/
|
|
105
105
|
connectorOwnerUserId?: string;
|
|
106
|
+
/**
|
|
107
|
+
* IANA timezone string (e.g. `"America/Bogota"`). The built-in
|
|
108
|
+
* `current_time` tool reads this so date/time questions resolve to the
|
|
109
|
+
* agent owner's locale instead of UTC. Defaults to `"UTC"` when unset.
|
|
110
|
+
*/
|
|
111
|
+
timezone?: string;
|
|
106
112
|
}
|
|
107
113
|
/**
|
|
108
114
|
* Configuration for an MCP server the runtime should connect to.
|
|
@@ -133,4 +139,11 @@ export interface McpServerConfig {
|
|
|
133
139
|
* secrets via the host's SecretsService before passing them here.
|
|
134
140
|
*/
|
|
135
141
|
headers?: Record<string, string>;
|
|
142
|
+
/**
|
|
143
|
+
* When the host stores MCP server records per-tenant, pass the owning
|
|
144
|
+
* tenantId here so the registry can scope `/tools` results to the caller
|
|
145
|
+
* and avoid leaking another workspace's catalog rows. Optional — leave
|
|
146
|
+
* unset for hosts with a single global MCP catalog.
|
|
147
|
+
*/
|
|
148
|
+
tenantId?: string;
|
|
136
149
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
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",
|