melchizedek-agents 0.19.0 → 0.20.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/CHANGELOG.md +252 -76
- package/DOCUMENTATION.md +44 -15
- package/QUICKSTART.md +9 -6
- package/README.md +6 -9
- package/config/agents/syndicateSchema.yaml +3 -0
- package/dist/lib/adkPeer.d.ts +63 -0
- package/dist/lib/adkPeer.js +240 -0
- package/dist/lib/compile.d.ts +40 -2
- package/dist/lib/compile.js +80 -12
- package/dist/lib/compileAdk.d.ts +7 -4
- package/dist/lib/compileAdk.js +22 -12
- package/dist/lib/compileNative.d.ts +28 -2
- package/dist/lib/compileNative.js +60 -4
- package/dist/lib/doctor.d.ts +28 -1
- package/dist/lib/doctor.js +63 -2
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +5 -0
- package/dist/lib/models/adapterResolver.d.ts +13 -11
- package/dist/lib/models/adapterResolver.js +11 -10
- package/dist/lib/models/adkGeminiAdapter.js +2 -0
- package/dist/lib/models/adkShim.d.ts +1 -1
- package/dist/lib/models/adkShim.js +1 -1
- package/dist/lib/models/capabilities.js +13 -10
- package/dist/lib/models/claudeLlm.js +2 -2
- package/dist/lib/models/fallback.d.ts +1 -1
- package/dist/lib/models/fallback.js +1 -1
- package/dist/lib/models/gatewayLlm.js +2 -2
- package/dist/lib/models/geminiAdapter.d.ts +6 -4
- package/dist/lib/models/geminiAdapter.js +28 -5
- package/dist/lib/models/geminiState.d.ts +21 -0
- package/dist/lib/models/geminiState.js +26 -0
- package/dist/lib/models/genaiMapping.d.ts +24 -4
- package/dist/lib/models/genaiMapping.js +109 -6
- package/dist/lib/models/gptLlm.js +2 -2
- package/dist/lib/models/grokLlm.js +2 -2
- package/dist/lib/models/kimiLlm.js +2 -2
- package/dist/lib/models/ollamaLlm.js +2 -2
- package/dist/lib/models/registry.d.ts +5 -1
- package/dist/lib/models/registry.js +17 -12
- package/dist/lib/models/tracedGemini.d.ts +1 -1
- package/dist/lib/models/tracedGemini.js +1 -1
- package/dist/lib/runtime/adkSessionBridge.d.ts +1 -1
- package/dist/lib/runtime/adkSessionBridge.js +1 -1
- package/dist/lib/runtime/approvals.d.ts +5 -0
- package/dist/lib/runtime/approvals.js +39 -8
- package/dist/lib/runtime/credentials.d.ts +3 -1
- package/dist/lib/runtime/credentials.js +6 -1
- package/dist/lib/runtime/native/agentLoop.d.ts +7 -1
- package/dist/lib/runtime/native/agentLoop.js +31 -13
- package/dist/lib/runtime/native/delegate.d.ts +53 -0
- package/dist/lib/runtime/native/delegate.js +91 -8
- package/dist/lib/runtime/native/interrupts.d.ts +6 -3
- package/dist/lib/runtime/native/interrupts.js +23 -4
- package/dist/lib/runtime/native/request.d.ts +1 -1
- package/dist/lib/runtime/native/request.js +1 -1
- package/dist/lib/runtime/native/selfCorrection.d.ts +64 -6
- package/dist/lib/runtime/native/selfCorrection.js +82 -8
- package/dist/lib/runtime/native/step.d.ts +14 -6
- package/dist/lib/runtime/native/step.js +34 -10
- package/dist/lib/runtime/runtimeFlag.d.ts +13 -5
- package/dist/lib/runtime/runtimeFlag.js +14 -6
- package/dist/lib/runtime/syndicateTurn.d.ts +15 -10
- package/dist/lib/runtime/syndicateTurn.js +59 -32
- package/dist/lib/runtime/valueDepth.d.ts +23 -0
- package/dist/lib/runtime/valueDepth.js +41 -0
- package/dist/lib/session/supabaseSessionService.d.ts +1 -1
- package/dist/lib/session/supabaseSessionService.js +1 -1
- package/dist/lib/session/transcript.d.ts +1 -1
- package/dist/lib/session/transcript.js +5 -3
- package/dist/lib/storage/postgres/sessionService.d.ts +1 -1
- package/dist/lib/storage/postgres/sessionService.js +1 -1
- package/dist/lib/syndicateSchema.d.ts +2 -0
- package/dist/lib/syndicateSchema.js +27 -6
- package/dist/lib/toolRegistry.d.ts +12 -1
- package/dist/lib/toolRegistry.js +42 -2
- package/dist/lib/tools/adkTool.d.ts +1 -1
- package/dist/lib/tools/adkTool.js +1 -1
- package/dist/lib/tools/collectionsSearchTool.d.ts +1 -1
- package/dist/lib/tools/collectionsSearchTool.js +1 -1
- package/dist/lib/tools/generateImageTool.d.ts +1 -1
- package/dist/lib/tools/inspectImageTool.d.ts +1 -1
- package/dist/lib/tools/urlContextTool.d.ts +1 -1
- package/dist/lib/tools/urlContextTool.js +1 -1
- package/dist/lib/tools/webExtractTool.d.ts +1 -1
- package/dist/lib/tools/webSearchTool.d.ts +1 -1
- package/dist/lib/tools/webSearchTool.js +1 -1
- package/dist/lib/tools/xApiSearchTool.d.ts +1 -1
- package/dist/lib/tools/xSearchTool.d.ts +1 -1
- package/dist/lib/tools/xSearchTool.js +1 -1
- package/dist/lib/wiki/agentRun.d.ts +1 -1
- package/dist/lib/wiki/agentRun.js +2 -1
- package/dist/lib/workflow/agentNode.d.ts +21 -4
- package/dist/lib/workflow/agentNode.js +96 -5
- package/dist/lib/workflow/graph.d.ts +5 -4
- package/dist/lib/workflow/graph.js +14 -4
- package/dist/lib/workflow/resume.d.ts +10 -9
- package/dist/lib/workflow/resume.js +13 -12
- package/dist/lib/workflow/scheduler.d.ts +10 -7
- package/dist/lib/workflow/scheduler.js +15 -2
- package/dist/lib/workflow.d.ts +33 -11
- package/dist/lib/workflow.js +49 -27
- package/dist/lib/workflowConfig.d.ts +4 -0
- package/dist/lib/workflowConfig.js +4 -0
- package/dist/scripts/doctor.d.ts +3 -1
- package/dist/scripts/doctor.js +4 -2
- package/package.json +6 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/valueDepth.ts — how deeply a JSON value nests, read without
|
|
3
|
+
* recursion (WS5-5, ADR 0101).
|
|
4
|
+
*
|
|
5
|
+
* WHY this file exists:
|
|
6
|
+
* A tool call's arguments come from a model, and a tool's result can come
|
|
7
|
+
* from a remote server (an MCP tool, a fetched API). Both are stored in the
|
|
8
|
+
* session and read again on every later step: cloned for the history,
|
|
9
|
+
* serialized for a durable store and a span. Those readers recurse, so a
|
|
10
|
+
* value nested a few thousand levels deep overflows the stack in each of
|
|
11
|
+
* them, on this turn and on every turn after it: the session stops
|
|
12
|
+
* working. No tool schema the engine knows nests anywhere near
|
|
13
|
+
* MAX_VALUE_DEPTH, so a value past it is malformed, and the runtime keeps
|
|
14
|
+
* a short note in its place (lib/models/genaiMapping.ts contractOutputPart for
|
|
15
|
+
* arguments, lib/runtime/native/agentLoop.ts for results).
|
|
16
|
+
*
|
|
17
|
+
* The check itself walks with an explicit stack, so the value it guards
|
|
18
|
+
* against cannot overflow it.
|
|
19
|
+
*/
|
|
20
|
+
/** The deepest a tool call's arguments or a tool's result may nest, in levels of objects and arrays (the value itself is level 1). */
|
|
21
|
+
export const MAX_VALUE_DEPTH = 64;
|
|
22
|
+
/** True when `value` nests objects or arrays more than `max` levels deep. Iterative; a value seen twice (a cycle) is walked once. */
|
|
23
|
+
export function nestedDeeperThan(value, max = MAX_VALUE_DEPTH) {
|
|
24
|
+
if (typeof value !== 'object' || value === null)
|
|
25
|
+
return false;
|
|
26
|
+
const stack = [{ node: value, level: 1 }];
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
while (stack.length > 0) {
|
|
29
|
+
const { node, level } = stack.pop();
|
|
30
|
+
if (level > max)
|
|
31
|
+
return true;
|
|
32
|
+
if (seen.has(node))
|
|
33
|
+
continue;
|
|
34
|
+
seen.add(node);
|
|
35
|
+
for (const child of Object.values(node)) {
|
|
36
|
+
if (typeof child === 'object' && child !== null)
|
|
37
|
+
stack.push({ node: child, level: level + 1 });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* - lastUpdateTime is the appended event's timestamp, which is the clock
|
|
26
26
|
* of the process that made the event, just before the append.
|
|
27
27
|
*/
|
|
28
|
-
import { BaseSessionService } from '
|
|
28
|
+
import { BaseSessionService } from '../adkPeer.ts';
|
|
29
29
|
import type { CreateSessionRequest as AdkCreateSessionRequest, DeleteSessionRequest as AdkDeleteSessionRequest, Event as AdkEvent, GetSessionRequest as AdkGetSessionRequest, ListSessionsRequest as AdkListSessionsRequest, ListSessionsResponse as AdkListSessionsResponse, Session as AdkSession } from '@google/adk';
|
|
30
30
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
31
31
|
import type { TurnEvent } from '../runtime/events.ts';
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* - lastUpdateTime is the appended event's timestamp, which is the clock
|
|
26
26
|
* of the process that made the event, just before the append.
|
|
27
27
|
*/
|
|
28
|
-
import { BaseSessionService } from '
|
|
28
|
+
import { BaseSessionService } from '../adkPeer.js';
|
|
29
29
|
import { randomUUID } from 'crypto';
|
|
30
30
|
import { applyEvent, listPage, listWindow, selectEvents, withoutTempKeys } from '../runtime/sessions.js';
|
|
31
31
|
import { trimEventForStorage } from './transcript.js';
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
* adapter keeps every event verbatim. Both keep the text whole, which is all
|
|
41
41
|
* long-term memory ingestion reads.
|
|
42
42
|
*/
|
|
43
|
-
import { BaseSessionService } from '
|
|
43
|
+
import { BaseSessionService } from '../adkPeer.ts';
|
|
44
44
|
import type { CreateSessionRequest, GetSessionRequest, ListSessionsRequest, ListSessionsResponse, DeleteSessionRequest, Session, Event } from '@google/adk';
|
|
45
45
|
import type { TurnEvent } from '../runtime/events.ts';
|
|
46
46
|
import type { CreateSessionRequest as EngineCreateSessionRequest, GetSessionOptions, ListSessionsRequest as EngineListSessionsRequest, ListSessionsResult, Session as EngineSession, SessionKey, SessionService } from '../runtime/sessions.ts';
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
* adapter keeps every event verbatim. Both keep the text whole, which is all
|
|
41
41
|
* long-term memory ingestion reads.
|
|
42
42
|
*/
|
|
43
|
-
import { BaseSessionService } from '
|
|
44
|
-
import {
|
|
43
|
+
import { BaseSessionService } from '../adkPeer.js';
|
|
44
|
+
import { asAdkSessionService, asSessionService, isAdkSessionService, isSessionService } from '../runtime/adkSessionBridge.js';
|
|
45
45
|
import { applyEvent } from '../runtime/sessions.js';
|
|
46
46
|
const DEFAULT_MAX_HISTORY_CHARS = 40_000;
|
|
47
47
|
const DEFAULT_MAX_HISTORY_TURNS = 16;
|
|
@@ -313,7 +313,9 @@ export class ProjectedSessionService extends BaseSessionService {
|
|
|
313
313
|
// always was, so the ADK face reaches the same object it did.
|
|
314
314
|
const engineOnly = isSessionService(inner) && !isAdkSessionService(inner);
|
|
315
315
|
this.inner = engineOnly ? asAdkSessionService(inner) : inner;
|
|
316
|
-
|
|
316
|
+
// A bridge is unwrapped to the store it wraps, so the engine face of an
|
|
317
|
+
// engine store never goes through ADK's base service (ADR 0102).
|
|
318
|
+
this.own = asSessionService(inner);
|
|
317
319
|
this.forAgent = forAgent;
|
|
318
320
|
this.options = options;
|
|
319
321
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* '<appName>:<userId>:<sessionId>'), so erase and the session prune cover
|
|
33
33
|
* both. Tables: db/migrations/0001_base.sql and 0003_postgres_storage.sql.
|
|
34
34
|
*/
|
|
35
|
-
import { BaseSessionService } from '
|
|
35
|
+
import { BaseSessionService } from '../../adkPeer.ts';
|
|
36
36
|
import type { CreateSessionRequest as AdkCreateSessionRequest, DeleteSessionRequest as AdkDeleteSessionRequest, Event as AdkEvent, GetSessionRequest as AdkGetSessionRequest, ListSessionsRequest as AdkListSessionsRequest, ListSessionsResponse as AdkListSessionsResponse, Session as AdkSession } from '@google/adk';
|
|
37
37
|
import type { Pool } from 'pg';
|
|
38
38
|
import type { TurnEvent } from '../../runtime/events.ts';
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* both. Tables: db/migrations/0001_base.sql and 0003_postgres_storage.sql.
|
|
34
34
|
*/
|
|
35
35
|
import { randomUUID } from 'node:crypto';
|
|
36
|
-
import { BaseSessionService } from '
|
|
36
|
+
import { BaseSessionService } from '../../adkPeer.js';
|
|
37
37
|
import { applyEvent, listPage, listWindow, withoutTempKeys } from '../../runtime/sessions.js';
|
|
38
38
|
function dbId(appName, userId, sessionId) {
|
|
39
39
|
return `${appName}:${userId}:${sessionId}`;
|
|
@@ -440,6 +440,8 @@ export declare const syndicateSchema: z.ZodObject<{
|
|
|
440
440
|
initial_delay: z.ZodOptional<z.ZodNumber>;
|
|
441
441
|
max_delay: z.ZodOptional<z.ZodNumber>;
|
|
442
442
|
backoff_factor: z.ZodOptional<z.ZodNumber>;
|
|
443
|
+
jitter: z.ZodOptional<z.ZodNumber>;
|
|
444
|
+
exceptions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
443
445
|
}, z.core.$strict>>;
|
|
444
446
|
timeout: z.ZodOptional<z.ZodNumber>;
|
|
445
447
|
}, z.core.$strict>>>;
|
|
@@ -296,12 +296,20 @@ const edgeElement = z.union([
|
|
|
296
296
|
.record(z.string().min(1), edgeTargets)
|
|
297
297
|
.describe('A routing map after a node: `{ <route>: <node or nodes>, default: <node> }`, matched against that node\'s output.'),
|
|
298
298
|
]);
|
|
299
|
+
/** An error class name, as ADK matches `exceptions` against one: an identifier. */
|
|
300
|
+
const ERROR_NAME = /^[A-Za-z_$][\w$]*$/;
|
|
299
301
|
const retrySchema = z
|
|
300
302
|
.strictObject({
|
|
301
303
|
max_attempts: z.number().int().positive().optional().describe('Attempts including the first; 1 = no retry. ADK default 5.'),
|
|
302
304
|
initial_delay: z.number().nonnegative().optional().describe('Seconds before the first retry.'),
|
|
303
305
|
max_delay: z.number().nonnegative().optional(),
|
|
304
306
|
backoff_factor: z.number().positive().optional(),
|
|
307
|
+
jitter: z.number().nonnegative().optional().describe('Randomness of the backoff; 0 = none. ADK default 1.'),
|
|
308
|
+
exceptions: z
|
|
309
|
+
.array(z.string().regex(ERROR_NAME, 'an error name, such as TypeError or NodeTimeoutError'))
|
|
310
|
+
.min(1)
|
|
311
|
+
.optional()
|
|
312
|
+
.describe('Error names to retry on (the error\'s class or its `name`); every error when absent.'),
|
|
305
313
|
})
|
|
306
314
|
.describe('Retry a node on failure (lib/workflow.ts).');
|
|
307
315
|
const workflowNodeSchema = z
|
|
@@ -313,8 +321,8 @@ const workflowNodeSchema = z
|
|
|
313
321
|
max_parallel: z.number().int().positive().optional().describe('Concurrency of map. Default 8.'),
|
|
314
322
|
tool: z.string().min(1).optional().describe('Run this registry tool with the node input as its arguments.'),
|
|
315
323
|
route_key: z.string().min(1).optional().describe('Property of a JSON output holding the route. Default "route".'),
|
|
316
|
-
retry: retrySchema.optional(),
|
|
317
|
-
timeout: z.number().positive().optional().describe('Seconds this node may run before it fails.'),
|
|
324
|
+
retry: retrySchema.optional().describe('Retry this node on failure. Not on a map node: each item runs under its agent\'s own retry.'),
|
|
325
|
+
timeout: z.number().positive().optional().describe('Seconds this node may run before it fails. Not on a map node: each item runs under its agent\'s own timeout.'),
|
|
318
326
|
})
|
|
319
327
|
.describe('A declared node (exactly one of ask_user, join, map, tool) or modifiers for an agent node (retry, timeout, route_key).');
|
|
320
328
|
const workflowSchema = z
|
|
@@ -663,11 +671,14 @@ function crossFieldProblems(raw) {
|
|
|
663
671
|
questionProblems(raw.orchestrator, ['orchestrator'], true);
|
|
664
672
|
}
|
|
665
673
|
const dispatching = isObj(raw.dispatch);
|
|
674
|
+
// A workflow's subagents are its nodes, not delegated tools: a gated call pauses its node, and
|
|
675
|
+
// the walk resumes it (ADR 0098). Skill scripts stay refused inside a workflow (workflowProblems).
|
|
676
|
+
const pausing = dispatching || isObj(raw.workflow);
|
|
666
677
|
subs.forEach((sub, i) => {
|
|
667
678
|
if (!isObj(sub))
|
|
668
679
|
return;
|
|
669
|
-
gateProblems(sub, ['subagents', i],
|
|
670
|
-
skillProblems(sub, ['subagents', i],
|
|
680
|
+
gateProblems(sub, ['subagents', i], pausing);
|
|
681
|
+
skillProblems(sub, ['subagents', i], pausing);
|
|
671
682
|
questionProblems(sub, ['subagents', i], dispatching);
|
|
672
683
|
const hasRef = typeof sub.yaml_reference === 'string';
|
|
673
684
|
const hasRemote = typeof sub.a2a_agent_url === 'string';
|
|
@@ -783,6 +794,15 @@ function workflowProblems(raw, subs) {
|
|
|
783
794
|
if (kind !== 'map' && entry.max_parallel !== undefined) {
|
|
784
795
|
out.push({ path: ['workflow', 'nodes', name, 'max_parallel'], message: 'max_parallel applies to map only' });
|
|
785
796
|
}
|
|
797
|
+
// A map item runs under its agent's own modifiers, as on ADK (ADR 0089, ADR 0103): the map entry's would be applied by neither runtime.
|
|
798
|
+
if (kind === 'map') {
|
|
799
|
+
for (const key of ['retry', 'timeout']) {
|
|
800
|
+
if (entry[key] === undefined)
|
|
801
|
+
continue;
|
|
802
|
+
const target = entry.map;
|
|
803
|
+
out.push({ path: ['workflow', 'nodes', name, key], message: `${key} on a map node is not applied: each item runs under its agent's own ${key}; set it on nodes.${target}` });
|
|
804
|
+
}
|
|
805
|
+
}
|
|
786
806
|
}
|
|
787
807
|
for (const name of agentNames) {
|
|
788
808
|
if (name.endsWith(ROUTE_STEP_SUFFIX))
|
|
@@ -854,8 +874,9 @@ function workflowProblems(raw, subs) {
|
|
|
854
874
|
for (const [path, agent] of agents) {
|
|
855
875
|
if (!isObj(agent))
|
|
856
876
|
continue;
|
|
857
|
-
|
|
858
|
-
|
|
877
|
+
// A map item cannot pause: the walk resumes a paused agent node, not an item of a map (ADR 0094, ADR 0098).
|
|
878
|
+
if (typeof agent.name === 'string' && mapped.has(agent.name) && Array.isArray(agent.require_approval) && agent.require_approval.length) {
|
|
879
|
+
out.push({ path: [...path, 'require_approval'], message: 'approval gates are not supported on an agent a map node runs: a map item cannot pause the walk' });
|
|
859
880
|
}
|
|
860
881
|
if (isObj(agent.skills) && agent.skills.scripts === 'local') {
|
|
861
882
|
out.push({ path: [...path, 'skills', 'scripts'], message: 'skill scripts (an approval pause) are not supported inside a workflow yet' });
|
|
@@ -22,6 +22,15 @@
|
|
|
22
22
|
* callers can log in their own format.
|
|
23
23
|
*/
|
|
24
24
|
export declare function resolveTools(toolNames?: string[], onUnknown?: (name: string) => void): any[];
|
|
25
|
+
/**
|
|
26
|
+
* Names the framework itself declares, calls or reads on the wire: the
|
|
27
|
+
* approval, credential and input interrupts, the reflection tool, delegation,
|
|
28
|
+
* structured output and task mode. A consumer's tool under one of them would
|
|
29
|
+
* be mistaken for the framework's own (a forged approval request, a fake
|
|
30
|
+
* transfer), so registerTool refuses them. `ask_user` is the framework's
|
|
31
|
+
* question tool; only that tool may be registered under it.
|
|
32
|
+
*/
|
|
33
|
+
export declare const RESERVED_TOOL_NAMES: readonly string[];
|
|
25
34
|
/**
|
|
26
35
|
* Make a tool resolvable by name from a syndicate YAML's `tools:` list.
|
|
27
36
|
*
|
|
@@ -34,7 +43,9 @@ export declare function resolveTools(toolNames?: string[], onUnknown?: (name: st
|
|
|
34
43
|
* a ready ADK tool. A contract or Tool reaches the ADK runtime through
|
|
35
44
|
* toFunctionTool, an InstructionTool through toAdkInstructionTool, a
|
|
36
45
|
* NativeToolMarker as its sentinel (toAdkTool, lib/tools/adkTool.ts).
|
|
37
|
-
* Replacing a built-in requires `{ override: true }`.
|
|
46
|
+
* Replacing a built-in requires `{ override: true }`. A reserved framework
|
|
47
|
+
* name (RESERVED_TOOL_NAMES), as the registry name or the tool's own, is
|
|
48
|
+
* refused whatever the options say.
|
|
38
49
|
*/
|
|
39
50
|
export declare function registerTool(name: string, tool: unknown, options?: {
|
|
40
51
|
override?: boolean;
|
package/dist/lib/toolRegistry.js
CHANGED
|
@@ -21,7 +21,7 @@ import { inspectImageTool } from './tools/inspectImageTool.js';
|
|
|
21
21
|
import { toAdkInstructionTool, toAdkTool, toFunctionTool } from './tools/adkTool.js';
|
|
22
22
|
import { loadMemoryTool, preloadMemoryTool } from './tools/memoryTools.js';
|
|
23
23
|
import { COLLECTIONS_SEARCH_MARKER, GOOGLE_SEARCH_MARKER, URL_CONTEXT_MARKER, WEB_SEARCH_MARKER, X_SEARCH_MARKER, } from './tools/nativeTools.js';
|
|
24
|
-
import { isInstructionTool, isNativeToolMarker, isTool } from './tools/tool.js';
|
|
24
|
+
import { isInstructionTool, isNativeToolMarker, isTool, toolOf } from './tools/tool.js';
|
|
25
25
|
import { webExtractTool } from './tools/webExtractTool.js';
|
|
26
26
|
import { WIKI_AGENT_TOOL_CONTRACTS } from './tools/wikiTools.js';
|
|
27
27
|
import { SCIENCE_TOOL_CONTRACTS } from './tools/scienceTools.js';
|
|
@@ -104,6 +104,40 @@ export function resolveTools(toolNames = [], onUnknown) {
|
|
|
104
104
|
})
|
|
105
105
|
.filter(Boolean);
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Names the framework itself declares, calls or reads on the wire: the
|
|
109
|
+
* approval, credential and input interrupts, the reflection tool, delegation,
|
|
110
|
+
* structured output and task mode. A consumer's tool under one of them would
|
|
111
|
+
* be mistaken for the framework's own (a forged approval request, a fake
|
|
112
|
+
* transfer), so registerTool refuses them. `ask_user` is the framework's
|
|
113
|
+
* question tool; only that tool may be registered under it.
|
|
114
|
+
*/
|
|
115
|
+
export const RESERVED_TOOL_NAMES = [
|
|
116
|
+
'adk_request_confirmation',
|
|
117
|
+
'adk_request_credential',
|
|
118
|
+
'adk_request_input',
|
|
119
|
+
'ask_user',
|
|
120
|
+
'adk_handle_model_error',
|
|
121
|
+
'transfer_to_agent',
|
|
122
|
+
'set_model_response',
|
|
123
|
+
'finish_task',
|
|
124
|
+
];
|
|
125
|
+
/** Whether `tool` is the framework's own ask_user (the own Tool, or the registry's wrapper of it). */
|
|
126
|
+
function isFrameworkAskUser(tool) {
|
|
127
|
+
return tool === askUserTool || tool === TOOL_MAP.ask_user || (!!tool && typeof tool === 'object' && toolOf(tool) === askUserTool);
|
|
128
|
+
}
|
|
129
|
+
/** The reserved name `name` or `tool` would take, if any. */
|
|
130
|
+
function reservedNameOf(name, tool) {
|
|
131
|
+
const own = tool && typeof tool === 'object' ? tool.name : undefined;
|
|
132
|
+
for (const candidate of [name, typeof own === 'string' ? own : undefined]) {
|
|
133
|
+
if (!candidate || !RESERVED_TOOL_NAMES.includes(candidate))
|
|
134
|
+
continue;
|
|
135
|
+
if (candidate === 'ask_user' && isFrameworkAskUser(tool))
|
|
136
|
+
continue;
|
|
137
|
+
return candidate;
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
107
141
|
/**
|
|
108
142
|
* Make a tool resolvable by name from a syndicate YAML's `tools:` list.
|
|
109
143
|
*
|
|
@@ -116,12 +150,18 @@ export function resolveTools(toolNames = [], onUnknown) {
|
|
|
116
150
|
* a ready ADK tool. A contract or Tool reaches the ADK runtime through
|
|
117
151
|
* toFunctionTool, an InstructionTool through toAdkInstructionTool, a
|
|
118
152
|
* NativeToolMarker as its sentinel (toAdkTool, lib/tools/adkTool.ts).
|
|
119
|
-
* Replacing a built-in requires `{ override: true }`.
|
|
153
|
+
* Replacing a built-in requires `{ override: true }`. A reserved framework
|
|
154
|
+
* name (RESERVED_TOOL_NAMES), as the registry name or the tool's own, is
|
|
155
|
+
* refused whatever the options say.
|
|
120
156
|
*/
|
|
121
157
|
export function registerTool(name, tool, options = {}) {
|
|
122
158
|
if (!/^[A-Za-z_][A-Za-z0-9_]{0,63}$/.test(name)) {
|
|
123
159
|
throw new Error(`registerTool: '${name}' is not a valid tool name`);
|
|
124
160
|
}
|
|
161
|
+
const reserved = reservedNameOf(name, tool);
|
|
162
|
+
if (reserved) {
|
|
163
|
+
throw new Error(`registerTool: '${reserved}' is reserved by the framework (${RESERVED_TOOL_NAMES.join(', ')}); register the tool under another name`);
|
|
164
|
+
}
|
|
125
165
|
if (Object.prototype.hasOwnProperty.call(TOOL_MAP, name) && !options.override) {
|
|
126
166
|
throw new Error(`registerTool: '${name}' is already registered (pass { override: true } to replace it)`);
|
|
127
167
|
}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*
|
|
39
39
|
* toAdkTool takes any of these and picks the wrapper.
|
|
40
40
|
*/
|
|
41
|
-
import { BaseTool, BaseToolset, FunctionTool } from '
|
|
41
|
+
import { BaseTool, BaseToolset, FunctionTool } from '../adkPeer.ts';
|
|
42
42
|
import type { InstructionTool, NativeToolMarker, Tool, ToolContext, Toolset } from './tool.ts';
|
|
43
43
|
import type { ToolContract } from './toolContract.ts';
|
|
44
44
|
/** The ToolContext for one ADK call; a standalone one outside a run. */
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*
|
|
39
39
|
* toAdkTool takes any of these and picks the wrapper.
|
|
40
40
|
*/
|
|
41
|
-
import { BaseTool, BaseToolset, FunctionTool, GOOGLE_SEARCH } from '
|
|
41
|
+
import { BaseTool, BaseToolset, FunctionTool, GOOGLE_SEARCH } from '../adkPeer.js';
|
|
42
42
|
import { currentTurnSignal } from '../runtime/turnControl.js';
|
|
43
43
|
import { COLLECTIONS_SEARCH } from './collectionsSearchTool.js';
|
|
44
44
|
import { OWN_TOOL, createToolContext, isInstructionTool, isNativeToolMarker, isOwnToolset, nativeToolMarkerOf } from './tool.js';
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* silent no-op everywhere else (same non-throwing routing contract as
|
|
31
31
|
* web_search / x_search).
|
|
32
32
|
*/
|
|
33
|
-
import { BaseTool } from '
|
|
33
|
+
import { BaseTool } from '../adkPeer.ts';
|
|
34
34
|
import type { LlmRequest } from '@google/adk';
|
|
35
35
|
import { NATIVE_TOOL } from './tool.ts';
|
|
36
36
|
export declare const COLLECTIONS_SEARCH_TOOL_NAME = "collections_search";
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* silent no-op everywhere else (same non-throwing routing contract as
|
|
31
31
|
* web_search / x_search).
|
|
32
32
|
*/
|
|
33
|
-
import { BaseTool } from '
|
|
33
|
+
import { BaseTool } from '../adkPeer.js';
|
|
34
34
|
import { providerForModel } from '../models/providerMap.js';
|
|
35
35
|
import { COLLECTIONS_SEARCH_MARKER } from './nativeTools.js';
|
|
36
36
|
import { NATIVE_TOOL, nativeToolMarkerOf } from './tool.js';
|
|
@@ -22,4 +22,4 @@ export declare const generateImageContract: import("./toolContract.ts").DefinedT
|
|
|
22
22
|
color_palette: z.ZodOptional<z.ZodString>;
|
|
23
23
|
}, z.core.$strip>, string>;
|
|
24
24
|
/** ADK surface, ready for the registry. */
|
|
25
|
-
export declare const generateImageTool: import("
|
|
25
|
+
export declare const generateImageTool: import("../adkPeer.ts").FunctionTool;
|
|
@@ -21,4 +21,4 @@ export declare const inspectImageContract: import("./toolContract.ts").DefinedTo
|
|
|
21
21
|
image_path: z.ZodString;
|
|
22
22
|
}, z.core.$strip>, string>;
|
|
23
23
|
/** ADK surface, ready for the registry. */
|
|
24
|
-
export declare const inspectImageTool: import("
|
|
24
|
+
export declare const inspectImageTool: import("../adkPeer.ts").FunctionTool;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* deployment's network is reachable through it. Page text arrives as model
|
|
15
15
|
* input; treat it as data, as any fetched page.
|
|
16
16
|
*/
|
|
17
|
-
import { BaseTool } from '
|
|
17
|
+
import { BaseTool } from '../adkPeer.ts';
|
|
18
18
|
import type { LlmRequest } from '@google/adk';
|
|
19
19
|
import { NATIVE_TOOL } from './tool.ts';
|
|
20
20
|
export declare const URL_CONTEXT_TOOL_NAME = "url_context";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* deployment's network is reachable through it. Page text arrives as model
|
|
15
15
|
* input; treat it as data, as any fetched page.
|
|
16
16
|
*/
|
|
17
|
-
import { BaseTool } from '
|
|
17
|
+
import { BaseTool } from '../adkPeer.js';
|
|
18
18
|
import { providerForModel } from '../models/providerMap.js';
|
|
19
19
|
import { URL_CONTEXT_MARKER } from './nativeTools.js';
|
|
20
20
|
import { NATIVE_TOOL } from './tool.js';
|
|
@@ -70,4 +70,4 @@ export declare const webExtractContract: import("./toolContract.ts").DefinedTool
|
|
|
70
70
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
71
71
|
}, z.core.$strip>, string>;
|
|
72
72
|
/** ADK surface, ready for the registry. */
|
|
73
|
-
export declare const webExtractTool: import("
|
|
73
|
+
export declare const webExtractTool: import("../adkPeer.ts").FunctionTool;
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `google_search` remains available as the Gemini-only ADK tool for
|
|
27
27
|
* backward compatibility; new YAMLs should declare `web_search`.
|
|
28
28
|
*/
|
|
29
|
-
import { BaseTool } from '
|
|
29
|
+
import { BaseTool } from '../adkPeer.ts';
|
|
30
30
|
import type { LlmRequest } from '@google/adk';
|
|
31
31
|
import { NATIVE_TOOL } from './tool.ts';
|
|
32
32
|
export declare const WEB_SEARCH_TOOL_NAME = "web_search";
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `google_search` remains available as the Gemini-only ADK tool for
|
|
27
27
|
* backward compatibility; new YAMLs should declare `web_search`.
|
|
28
28
|
*/
|
|
29
|
-
import { BaseTool } from '
|
|
29
|
+
import { BaseTool } from '../adkPeer.js';
|
|
30
30
|
import { providerForModel } from '../models/providerMap.js';
|
|
31
31
|
import { WEB_SEARCH_MARKER } from './nativeTools.js';
|
|
32
32
|
import { NATIVE_TOOL, nativeToolMarkerOf } from './tool.js';
|
|
@@ -191,4 +191,4 @@ export declare const xApiSearchContract: import("./toolContract.ts").DefinedTool
|
|
|
191
191
|
read_images: z.ZodOptional<z.ZodBoolean>;
|
|
192
192
|
}, z.core.$strip>, string>;
|
|
193
193
|
/** ADK surface, registered under its contract name in lib/toolRegistry.ts. */
|
|
194
|
-
export declare const xApiSearchTool: import("
|
|
194
|
+
export declare const xApiSearchTool: import("../adkPeer.ts").FunctionTool;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* malformed dates are dropped, oversize handle lists truncate, and when
|
|
34
34
|
* both lists are set the allowlist wins.
|
|
35
35
|
*/
|
|
36
|
-
import { BaseTool } from '
|
|
36
|
+
import { BaseTool } from '../adkPeer.ts';
|
|
37
37
|
import type { LlmRequest } from '@google/adk';
|
|
38
38
|
import { NATIVE_TOOL } from './tool.ts';
|
|
39
39
|
export declare const X_SEARCH_TOOL_NAME = "x_search";
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* malformed dates are dropped, oversize handle lists truncate, and when
|
|
34
34
|
* both lists are set the allowlist wins.
|
|
35
35
|
*/
|
|
36
|
-
import { BaseTool } from '
|
|
36
|
+
import { BaseTool } from '../adkPeer.js';
|
|
37
37
|
import { providerForModel } from '../models/providerMap.js';
|
|
38
38
|
import { X_SEARCH_MARKER } from './nativeTools.js';
|
|
39
39
|
import { NATIVE_TOOL, nativeToolMarkerOf } from './tool.js';
|
|
@@ -34,7 +34,7 @@ export interface WikiAgentRun {
|
|
|
34
34
|
tools?: FunctionTool[];
|
|
35
35
|
temperature?: number;
|
|
36
36
|
maxOutputTokens?: number;
|
|
37
|
-
/** The runtime that runs the agent. Default: MELCHIZEDEK_RUNTIME, else
|
|
37
|
+
/** The runtime that runs the agent. Default: MELCHIZEDEK_RUNTIME, else native. */
|
|
38
38
|
runtime?: RuntimeName;
|
|
39
39
|
/** Native runtime only: the leaf adapter for a model id. Default resolveAdapter (lib/models/registry.ts). */
|
|
40
40
|
adapterFor?: (model: string) => ModelAdapter;
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* read the same way.
|
|
24
24
|
*/
|
|
25
25
|
import { randomUUID } from 'node:crypto';
|
|
26
|
-
import {
|
|
26
|
+
import { requireAdk } from '../adkPeer.js';
|
|
27
27
|
import { providerForModel, providerKeyPresent, registerAvailableProviders, resolveAdapter, } from '../models/registry.js';
|
|
28
28
|
import { SelfCorrection } from '../runtime/native/selfCorrection.js';
|
|
29
29
|
import { runNativeAgent } from '../runtime/nativeTurn.js';
|
|
@@ -101,6 +101,7 @@ export async function runWikiAgent(run) {
|
|
|
101
101
|
selfCorrection: new SelfCorrection({ model_errors: 0, tool_errors: 0 }),
|
|
102
102
|
}));
|
|
103
103
|
}
|
|
104
|
+
const { InMemorySessionService, LlmAgent, Runner } = requireAdk('A wiki agent on the adk runtime (MELCHIZEDEK_RUNTIME=adk)');
|
|
104
105
|
registerAvailableProviders();
|
|
105
106
|
const agent = new LlmAgent({
|
|
106
107
|
name: run.name,
|
|
@@ -43,8 +43,25 @@
|
|
|
43
43
|
* error; a run that ends with one and no output returns it as the
|
|
44
44
|
* run's `error`, and the scheduler fails the attempt with
|
|
45
45
|
* NodeReportedError, ADK's message, retried or stopping the walk as
|
|
46
|
-
* ADK's does, and reported once (by the node's own event). A run the turn stopped throws. A run that pauses on
|
|
47
|
-
*
|
|
46
|
+
* ADK's does, and reported once (by the node's own event). A run the turn stopped throws. A run that pauses on
|
|
47
|
+
* an ask_user tool call is refused by name.
|
|
48
|
+
* 8. APPROVALS (ADR 0098). A run that pauses on approval requests (a tool
|
|
49
|
+
* in the agent's `require_approval`) resolves with their ids as the
|
|
50
|
+
* node's interrupts: the node waits and the walk ends paused, as an
|
|
51
|
+
* ask_user node's does. The resumed walk reruns the node with
|
|
52
|
+
* `resumedInterruptIds`: until every request has a decision among the
|
|
53
|
+
* answers (a confirmation, never a plain-text message) it waits again
|
|
54
|
+
* without running, its open requests raised again on one event of the
|
|
55
|
+
* new run (`waitAgain`), so the run after still resumes them; then the
|
|
56
|
+
* agent's run continues instead of starting afresh, unless it already
|
|
57
|
+
* did on an earlier resume, whose stored output is then the node's
|
|
58
|
+
* (`outputAfter`). No input turn is stored, so the person's answer stays the
|
|
59
|
+
* latest user event, and the loop's approval resume
|
|
60
|
+
* (lib/runtime/native/interrupts.ts, ADR 0077) runs or refuses the
|
|
61
|
+
* pinned call before the next model step, which reads the node's turn
|
|
62
|
+
* from its input on. ADK's runLlmAgentAsNode stores the input again and
|
|
63
|
+
* starts the agent afresh, so the pinned call never runs there; ADK
|
|
64
|
+
* turns refuse gates on workflow nodes instead.
|
|
48
65
|
*
|
|
49
66
|
* `agentNodeRuntime` puts it together for the scheduler: a `runNode` for
|
|
50
67
|
* agent nodes and map items, and an `onEvent` that stores the event ADK
|
|
@@ -52,7 +69,7 @@
|
|
|
52
69
|
* (lib/workflow/nodeEvents.ts), so a session the native walk writes holds
|
|
53
70
|
* what ADK's holds, in the same order.
|
|
54
71
|
*
|
|
55
|
-
* NOT HERE:
|
|
72
|
+
* NOT HERE: an ask_user tool call inside a node, a pause inside a map item,
|
|
56
73
|
* tool nodes (lib/workflow/toolNode.ts) and ask_user nodes
|
|
57
74
|
* (lib/workflow/pause.ts). It imports nothing from ADK.
|
|
58
75
|
*/
|
|
@@ -102,7 +119,7 @@ export interface AgentNodeContext {
|
|
|
102
119
|
* one with no output. Throws NodeStoppedError when the turn stopped it, and
|
|
103
120
|
* an Error when it paused on a person.
|
|
104
121
|
*/
|
|
105
|
-
export declare function runAgentNode(agent: NativeAgent, run: Pick<NodeRun, 'input' | 'path' | 'branch' | 'signal'>, ctx: AgentNodeContext): Promise<NodeResult>;
|
|
122
|
+
export declare function runAgentNode(agent: NativeAgent, run: Pick<NodeRun, 'input' | 'path' | 'branch' | 'signal' | 'resumeInputs' | 'resumedInterruptIds'>, ctx: AgentNodeContext): Promise<NodeResult>;
|
|
106
123
|
export interface AgentNodeRuntimeOptions extends Omit<AgentNodeContext, 'appendInput'> {
|
|
107
124
|
/** Every agent of the syndicate, compiled for native, by YAML name. */
|
|
108
125
|
agents: ReadonlyMap<string, NativeAgent>;
|