melchizedek-agents 0.18.0 → 0.19.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/.env.example +12 -0
- package/CHANGELOG.md +825 -0
- package/DOCUMENTATION.md +217 -59
- package/README.md +42 -1
- package/config/agents/examples/harness.yaml +3 -1
- package/config/agents/examples/model_zoo.yaml +10 -9
- package/config/agents/syndicateSchema.yaml +50 -16
- package/config/agents/templates/account_memory.yaml +2 -6
- package/config/agents/templates/case_desk.yaml +3 -9
- package/config/agents/templates/draft_review.yaml +3 -9
- package/config/agents/templates/intake_extractor.yaml +1 -3
- package/config/agents/templates/research_brief.yaml +3 -9
- package/config/agents/templates/research_desk.yaml +3 -9
- package/config/agents/templates/review_panel.yaml +4 -12
- package/config/agents/templates/support_triage.yaml +4 -12
- package/config/agents/templates/systems_operator.yaml +2 -6
- package/db/hardening.sql +7 -1
- package/db/migrations/0013_tool_credentials.sql +260 -0
- package/dist/lib/a2a/app.d.ts +70 -6
- package/dist/lib/a2a/app.js +107 -2
- package/dist/lib/a2a/executor.d.ts +20 -3
- package/dist/lib/a2a/executor.js +66 -7
- package/dist/lib/a2a/remoteAgent.d.ts +24 -9
- package/dist/lib/a2a/remoteAgent.js +31 -14
- package/dist/lib/compile.d.ts +121 -30
- package/dist/lib/compile.js +137 -124
- package/dist/lib/compileAdk.d.ts +29 -0
- package/dist/lib/compileAdk.js +132 -0
- package/dist/lib/compileNative.d.ts +85 -0
- package/dist/lib/compileNative.js +222 -0
- package/dist/lib/config.d.ts +6 -5
- package/dist/lib/config.js +6 -5
- package/dist/lib/doctor.js +1 -0
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/index.js +2 -1
- package/dist/lib/loadSyndicate.d.ts +18 -0
- package/dist/lib/memory/erase.d.ts +5 -3
- package/dist/lib/memory/erase.js +5 -2
- package/dist/lib/memory/namespace.d.ts +8 -1
- package/dist/lib/memory/namespace.js +12 -6
- package/dist/lib/memory/providers.js +2 -1
- package/dist/lib/memory/supabaseMemoryService.d.ts +37 -3
- package/dist/lib/memory/supabaseMemoryService.js +42 -2
- package/dist/lib/model.d.ts +47 -0
- package/dist/lib/model.js +37 -0
- package/dist/lib/models/adapterResolver.d.ts +113 -0
- package/dist/lib/models/adapterResolver.js +136 -0
- package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
- package/dist/lib/models/adkGeminiAdapter.js +367 -0
- package/dist/lib/models/adkShim.d.ts +111 -0
- package/dist/lib/models/adkShim.js +136 -0
- package/dist/lib/models/capabilities.d.ts +3 -0
- package/dist/lib/models/capabilities.js +20 -13
- package/dist/lib/models/chatCompletionsAdapter.d.ts +279 -0
- package/dist/lib/models/chatCompletionsAdapter.js +854 -0
- package/dist/lib/models/circuitBreaker.d.ts +42 -0
- package/dist/lib/models/circuitBreaker.js +70 -0
- package/dist/lib/models/claudeAdapter.d.ts +103 -0
- package/dist/lib/models/claudeAdapter.js +669 -0
- package/dist/lib/models/claudeLlm.d.ts +39 -62
- package/dist/lib/models/claudeLlm.js +44 -349
- package/dist/lib/models/claudeModels.d.ts +127 -0
- package/dist/lib/models/claudeModels.js +237 -0
- package/dist/lib/models/contract.d.ts +395 -0
- package/dist/lib/models/contract.js +39 -0
- package/dist/lib/models/endpoints.js +2 -1
- package/dist/lib/models/errorResponse.d.ts +50 -0
- package/dist/lib/models/errorResponse.js +48 -0
- package/dist/lib/models/fallback.d.ts +17 -10
- package/dist/lib/models/fallback.js +53 -42
- package/dist/lib/models/fallbackAdapter.d.ts +55 -0
- package/dist/lib/models/fallbackAdapter.js +62 -0
- package/dist/lib/models/gateway.js +2 -1
- package/dist/lib/models/gatewayAdapter.d.ts +51 -0
- package/dist/lib/models/gatewayAdapter.js +81 -0
- package/dist/lib/models/gatewayLlm.d.ts +12 -33
- package/dist/lib/models/gatewayLlm.js +14 -75
- package/dist/lib/models/geminiAdapter.d.ts +123 -0
- package/dist/lib/models/geminiAdapter.js +831 -0
- package/dist/lib/models/geminiState.d.ts +25 -0
- package/dist/lib/models/geminiState.js +25 -0
- package/dist/lib/models/genaiMapping.d.ts +263 -0
- package/dist/lib/models/genaiMapping.js +862 -0
- package/dist/lib/models/gptAdapter.d.ts +240 -0
- package/dist/lib/models/gptAdapter.js +804 -0
- package/dist/lib/models/gptLlm.d.ts +63 -123
- package/dist/lib/models/gptLlm.js +88 -602
- package/dist/lib/models/grokAdapter.d.ts +86 -0
- package/dist/lib/models/grokAdapter.js +142 -0
- package/dist/lib/models/grokLlm.d.ts +22 -45
- package/dist/lib/models/grokLlm.js +22 -67
- package/dist/lib/models/kimiAdapter.d.ts +157 -0
- package/dist/lib/models/kimiAdapter.js +203 -0
- package/dist/lib/models/kimiLlm.d.ts +15 -107
- package/dist/lib/models/kimiLlm.js +17 -153
- package/dist/lib/models/ollamaAdapter.d.ts +125 -0
- package/dist/lib/models/ollamaAdapter.js +155 -0
- package/dist/lib/models/ollamaLlm.d.ts +11 -107
- package/dist/lib/models/ollamaLlm.js +13 -151
- package/dist/lib/models/openAiCompatibleLlm.d.ts +73 -216
- package/dist/lib/models/openAiCompatibleLlm.js +109 -671
- package/dist/lib/models/providerState.d.ts +63 -0
- package/dist/lib/models/providerState.js +61 -0
- package/dist/lib/models/reasoning.d.ts +26 -0
- package/dist/lib/models/reasoning.js +59 -0
- package/dist/lib/models/registry.d.ts +58 -35
- package/dist/lib/models/registry.js +89 -118
- package/dist/lib/models/retry.d.ts +2 -1
- package/dist/lib/models/retry.js +3 -2
- package/dist/lib/models/schemaNormalize.d.ts +98 -0
- package/dist/lib/models/schemaNormalize.js +321 -1
- package/dist/lib/models/tracedGemini.d.ts +41 -0
- package/dist/lib/models/tracedGemini.js +98 -0
- package/dist/lib/models/urls.d.ts +11 -0
- package/dist/lib/models/urls.js +16 -0
- package/dist/lib/net/redirects.d.ts +21 -2
- package/dist/lib/net/redirects.js +11 -34
- package/dist/lib/observability/audit.d.ts +5 -1
- package/dist/lib/observability/lineage.d.ts +14 -0
- package/dist/lib/observability/lineage.js +33 -0
- package/dist/lib/observability/supabaseSpanExporter.d.ts +10 -4
- package/dist/lib/observability/supabaseSpanExporter.js +17 -9
- package/dist/lib/observability/tracer.d.ts +26 -8
- package/dist/lib/observability/tracer.js +43 -18
- package/dist/lib/runtime/adkMemoryBridge.d.ts +46 -0
- package/dist/lib/runtime/adkMemoryBridge.js +68 -0
- package/dist/lib/runtime/adkSessionBridge.d.ts +78 -0
- package/dist/lib/runtime/adkSessionBridge.js +176 -0
- package/dist/lib/runtime/credentials.d.ts +59 -0
- package/dist/lib/runtime/credentials.js +62 -0
- package/dist/lib/runtime/events.d.ts +229 -0
- package/dist/lib/runtime/events.js +274 -0
- package/dist/lib/runtime/logging.d.ts +32 -0
- package/dist/lib/runtime/logging.js +55 -0
- package/dist/lib/runtime/memoryService.d.ts +72 -0
- package/dist/lib/runtime/memoryService.js +25 -0
- package/dist/lib/runtime/native/agentLoop.d.ts +203 -0
- package/dist/lib/runtime/native/agentLoop.js +687 -0
- package/dist/lib/runtime/native/compaction.d.ts +103 -0
- package/dist/lib/runtime/native/compaction.js +191 -0
- package/dist/lib/runtime/native/delegate.d.ts +98 -0
- package/dist/lib/runtime/native/delegate.js +173 -0
- package/dist/lib/runtime/native/history.d.ts +83 -0
- package/dist/lib/runtime/native/history.js +312 -0
- package/dist/lib/runtime/native/interrupts.d.ts +126 -0
- package/dist/lib/runtime/native/interrupts.js +291 -0
- package/dist/lib/runtime/native/request.d.ts +215 -0
- package/dist/lib/runtime/native/request.js +585 -0
- package/dist/lib/runtime/native/selfCorrection.d.ts +106 -0
- package/dist/lib/runtime/native/selfCorrection.js +253 -0
- package/dist/lib/runtime/native/step.d.ts +148 -0
- package/dist/lib/runtime/native/step.js +239 -0
- package/dist/lib/runtime/native/taskMode.d.ts +64 -0
- package/dist/lib/runtime/native/taskMode.js +126 -0
- package/dist/lib/runtime/native/telemetry.d.ts +75 -0
- package/dist/lib/runtime/native/telemetry.js +299 -0
- package/dist/lib/runtime/native/tempState.d.ts +31 -0
- package/dist/lib/runtime/native/tempState.js +56 -0
- package/dist/lib/runtime/nativeTurn.d.ts +86 -0
- package/dist/lib/runtime/nativeTurn.js +107 -0
- package/dist/lib/runtime/questions.d.ts +29 -7
- package/dist/lib/runtime/questions.js +47 -32
- package/dist/lib/runtime/runtimeFlag.d.ts +30 -0
- package/dist/lib/runtime/runtimeFlag.js +50 -0
- package/dist/lib/runtime/sessions.d.ts +166 -0
- package/dist/lib/runtime/sessions.js +201 -0
- package/dist/lib/runtime/syndicateTurn.d.ts +41 -5
- package/dist/lib/runtime/syndicateTurn.js +202 -32
- package/dist/lib/session/supabaseSessionService.d.ts +64 -17
- package/dist/lib/session/supabaseSessionService.js +148 -105
- package/dist/lib/session/transcript.d.ts +68 -22
- package/dist/lib/session/transcript.js +102 -28
- package/dist/lib/skills.js +33 -7
- package/dist/lib/storage/postgres/credentialStore.d.ts +20 -0
- package/dist/lib/storage/postgres/credentialStore.js +82 -0
- package/dist/lib/storage/postgres/index.d.ts +12 -0
- package/dist/lib/storage/postgres/index.js +6 -1
- package/dist/lib/storage/postgres/sessionService.d.ts +43 -15
- package/dist/lib/storage/postgres/sessionService.js +128 -66
- package/dist/lib/syndicateSchema.d.ts +47 -0
- package/dist/lib/syndicateSchema.js +72 -3
- package/dist/lib/toolRegistry.d.ts +15 -2
- package/dist/lib/toolRegistry.js +33 -17
- package/dist/lib/tools/adkTool.d.ts +81 -0
- package/dist/lib/tools/adkTool.js +268 -0
- package/dist/lib/tools/auth.d.ts +118 -0
- package/dist/lib/tools/auth.js +89 -0
- package/dist/lib/tools/collectionsSearchTool.d.ts +7 -6
- package/dist/lib/tools/collectionsSearchTool.js +11 -26
- package/dist/lib/tools/credentialCipher.d.ts +58 -0
- package/dist/lib/tools/credentialCipher.js +116 -0
- package/dist/lib/tools/credentialStore.d.ts +77 -0
- package/dist/lib/tools/credentialStore.js +246 -0
- package/dist/lib/tools/examples.d.ts +43 -0
- package/dist/lib/tools/examples.js +62 -0
- package/dist/lib/tools/generateImageTool.d.ts +15 -6
- package/dist/lib/tools/generateImageTool.js +19 -29
- package/dist/lib/tools/inspectImageTool.d.ts +9 -6
- package/dist/lib/tools/inspectImageTool.js +13 -17
- package/dist/lib/tools/mcpToolFactory.d.ts +42 -1
- package/dist/lib/tools/mcpToolFactory.js +46 -47
- package/dist/lib/tools/memoryTools.d.ts +61 -0
- package/dist/lib/tools/memoryTools.js +119 -0
- package/dist/lib/tools/nativeTools.d.ts +38 -0
- package/dist/lib/tools/nativeTools.js +43 -0
- package/dist/lib/tools/oauthConsent.d.ts +181 -0
- package/dist/lib/tools/oauthConsent.js +330 -0
- package/dist/lib/tools/openapi/call.d.ts +108 -0
- package/dist/lib/tools/openapi/call.js +295 -0
- package/dist/lib/tools/openapi/parse.d.ts +147 -0
- package/dist/lib/tools/openapi/parse.js +570 -0
- package/dist/lib/tools/openapiTools.d.ts +25 -17
- package/dist/lib/tools/openapiTools.js +124 -121
- package/dist/lib/tools/scienceTools.d.ts +14 -14
- package/dist/lib/tools/skillToolset.d.ts +58 -87
- package/dist/lib/tools/skillToolset.js +61 -142
- package/dist/lib/tools/skills/env.d.ts +58 -0
- package/dist/lib/tools/skills/env.js +165 -0
- package/dist/lib/tools/skills/executor.d.ts +114 -0
- package/dist/lib/tools/skills/executor.js +331 -0
- package/dist/lib/tools/skills/frontmatter.d.ts +79 -0
- package/dist/lib/tools/skills/frontmatter.js +215 -0
- package/dist/lib/tools/skills/loader.d.ts +91 -0
- package/dist/lib/tools/skills/loader.js +257 -0
- package/dist/lib/tools/skills/tools.d.ts +187 -0
- package/dist/lib/tools/skills/tools.js +386 -0
- package/dist/lib/tools/taskTools.d.ts +15 -15
- package/dist/lib/tools/tool.d.ts +354 -0
- package/dist/lib/tools/tool.js +304 -0
- package/dist/lib/tools/toolContract.d.ts +89 -33
- package/dist/lib/tools/toolContract.js +104 -82
- package/dist/lib/tools/urlContextTool.d.ts +3 -0
- package/dist/lib/tools/urlContextTool.js +5 -1
- package/dist/lib/tools/webExtractTool.d.ts +2 -2
- package/dist/lib/tools/webExtractTool.js +2 -1
- package/dist/lib/tools/webSearchTool.d.ts +6 -9
- package/dist/lib/tools/webSearchTool.js +14 -59
- package/dist/lib/tools/wikiTools.d.ts +19 -19
- package/dist/lib/tools/wikiTools.js +13 -9
- package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
- package/dist/lib/tools/xApiSearchTool.js +2 -1
- package/dist/lib/tools/xSearchTool.d.ts +7 -9
- package/dist/lib/tools/xSearchTool.js +11 -62
- package/dist/lib/tools/xaiSearchParams.d.ts +41 -0
- package/dist/lib/tools/xaiSearchParams.js +126 -0
- package/dist/lib/wiki/agentRun.d.ts +12 -0
- package/dist/lib/wiki/agentRun.js +72 -34
- package/dist/lib/wiki/entities.d.ts +12 -0
- package/dist/lib/wiki/entities.js +45 -3
- package/dist/lib/workflow/agentNode.d.ts +136 -0
- package/dist/lib/workflow/agentNode.js +274 -0
- package/dist/lib/workflow/graph.d.ts +177 -0
- package/dist/lib/workflow/graph.js +458 -0
- package/dist/lib/workflow/nodeEvents.d.ts +50 -0
- package/dist/lib/workflow/nodeEvents.js +101 -0
- package/dist/lib/workflow/pause.d.ts +122 -0
- package/dist/lib/workflow/pause.js +180 -0
- package/dist/lib/workflow/resume.d.ts +165 -0
- package/dist/lib/workflow/resume.js +440 -0
- package/dist/lib/workflow/route.d.ts +58 -0
- package/dist/lib/workflow/route.js +69 -0
- package/dist/lib/workflow/scheduler.d.ts +415 -0
- package/dist/lib/workflow/scheduler.js +743 -0
- package/dist/lib/workflow/toolNode.d.ts +127 -0
- package/dist/lib/workflow/toolNode.js +236 -0
- package/dist/lib/workflow/turn.d.ts +118 -0
- package/dist/lib/workflow/turn.js +216 -0
- package/dist/lib/workflowConfig.d.ts +3 -2
- package/dist/lib/workflowConfig.js +3 -12
- package/dist/scripts/a2a_server.js +4 -3
- package/dist/scripts/assistant_worker.d.ts +2 -1
- package/dist/scripts/assistant_worker.js +9 -4
- package/dist/scripts/syndicate_chat.js +19 -10
- package/package.json +4 -1
- package/skills/briefs/melchizedek-author.md +3 -2
- package/skills/briefs/melchizedek-models.md +13 -9
- package/skills/briefs/melchizedek.md +3 -3
- package/skills/melchizedek/SKILL.md +2 -1
- package/skills/melchizedek-author/SKILL.md +2 -1
- package/skills/melchizedek-author/assets/minimal.yaml +2 -0
- package/skills/melchizedek-models/SKILL.md +23 -6
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/native/telemetry.ts — the native loop's spans: one per agent
|
|
3
|
+
* run, one per model step, one per tool call (ADR 0076).
|
|
4
|
+
*
|
|
5
|
+
* WHY this file exists:
|
|
6
|
+
* The ledger (lib/observability/supabaseSpanExporter.ts) is a projection of
|
|
7
|
+
* a turn's spans. On the ADK runtime, ADK opens `invoke_agent <name>`
|
|
8
|
+
* around an agent's run, `call_llm` around each step's model call and
|
|
9
|
+
* `execute_tool <name>` around each tool call; the tracer reads them to
|
|
10
|
+
* attribute a model call to its agent and to sum tool time, and the
|
|
11
|
+
* exporter reads `call_llm` for the payload tier. A native run writes the
|
|
12
|
+
* same ledger rows because the loop opens the same three spans under the
|
|
13
|
+
* engine's own names and scope:
|
|
14
|
+
*
|
|
15
|
+
* agent.invoke <name> the agent's run (runAgentLoop), parent of the rest
|
|
16
|
+
* model.call one model step, parent of the step's llm.request
|
|
17
|
+
* span(s): two when a fallback model answers
|
|
18
|
+
* tool.execute <name> one tool call; a step's calls run side by side
|
|
19
|
+
*
|
|
20
|
+
* All three are in scope `melchizedek.runtime`, which the console exporter
|
|
21
|
+
* keeps quiet as it keeps ADK's (OTEL_CONSOLE_ALL_SPANS prints them).
|
|
22
|
+
*
|
|
23
|
+
* WHAT A SPAN CARRIES:
|
|
24
|
+
* gen_ai.* attributes as ADK sets them (operation, agent, conversation,
|
|
25
|
+
* tool name and call id, request model, usage, finish reason), and on
|
|
26
|
+
* model.call the provider the answering adapter names (`gen_ai.system`),
|
|
27
|
+
* where ADK's call_llm names its own scope. A model step that did not fail
|
|
28
|
+
* carries its payload as the engine holds it: `llm.payload.request` (the
|
|
29
|
+
* ModelRequest, its signal left out) and `llm.payload.response` (the
|
|
30
|
+
* adapter's final response). A failed step carries none: its llm.request
|
|
31
|
+
* span carries the failed call's payload, as on the ADK runtime, where a
|
|
32
|
+
* failed call_llm never ends. With TELEMETRY_PAYLOADS=off no payload is
|
|
33
|
+
* recorded at all. Tool spans carry no arguments and no results: the root
|
|
34
|
+
* span's ToolCall/ToolResponse events are where the ledger keeps those.
|
|
35
|
+
*
|
|
36
|
+
* The loop calls three hooks (agentLoop.ts): traceAgentInvocation around the
|
|
37
|
+
* whole run, traceModelCall around each step, traceToolCall around each call.
|
|
38
|
+
*/
|
|
39
|
+
import { SpanStatusCode, context, trace } from '@opentelemetry/api';
|
|
40
|
+
import { resolveAdapter } from '../../models/registry.js';
|
|
41
|
+
import { RUNTIME_SPAN_SCOPE } from '../../observability/lineage.js';
|
|
42
|
+
import { payloadPolicyFromEnv } from '../../observability/supabaseSpanExporter.js';
|
|
43
|
+
import { initializeTracing } from '../../observability/tracer.js';
|
|
44
|
+
/** The most a payload attribute holds, as for a failed call's (lib/observability/tracer.ts). */
|
|
45
|
+
const PAYLOAD_MAX_CHARS = 200_000;
|
|
46
|
+
const runtimeTracer = () => trace.getTracer(RUNTIME_SPAN_SCOPE);
|
|
47
|
+
/** JSON that never throws and never exceeds the cap. */
|
|
48
|
+
function payloadJson(value) {
|
|
49
|
+
let json;
|
|
50
|
+
try {
|
|
51
|
+
json = JSON.stringify(value) ?? String(value);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
json = String(value);
|
|
55
|
+
}
|
|
56
|
+
return json.length > PAYLOAD_MAX_CHARS ? json.slice(0, PAYLOAD_MAX_CHARS) : json;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Runs `inner` with `spanContext` active for every step it takes, as ADK's
|
|
60
|
+
* runAsyncGeneratorWithOtelContext does: spans the generator opens are
|
|
61
|
+
* children of the span. A consumer that stops early closes `inner` too, so
|
|
62
|
+
* its own spans end.
|
|
63
|
+
*/
|
|
64
|
+
async function* within(spanContext, inner) {
|
|
65
|
+
let finished = false;
|
|
66
|
+
try {
|
|
67
|
+
for (;;) {
|
|
68
|
+
const next = await context.with(spanContext, () => inner.next());
|
|
69
|
+
if (next.done) {
|
|
70
|
+
finished = true;
|
|
71
|
+
return next.value;
|
|
72
|
+
}
|
|
73
|
+
yield next.value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
if (!finished)
|
|
78
|
+
await context.with(spanContext, () => inner.return(undefined));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function failed(span, error) {
|
|
82
|
+
span.recordException(error instanceof Error ? error : String(error));
|
|
83
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
/** The agent's run as an `agent.invoke <name>` span, opened when the run starts. */
|
|
87
|
+
export async function* traceAgentInvocation(agent, ctx, run) {
|
|
88
|
+
initializeTracing();
|
|
89
|
+
const span = runtimeTracer().startSpan(`agent.invoke ${agent.name}`, {
|
|
90
|
+
attributes: {
|
|
91
|
+
'gen_ai.operation.name': 'invoke_agent',
|
|
92
|
+
'gen_ai.agent.name': agent.name,
|
|
93
|
+
'gen_ai.agent.description': agent.description ?? '',
|
|
94
|
+
'gen_ai.conversation.id': ctx.session.id,
|
|
95
|
+
'adk.invocation_id': ctx.invocationId,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
try {
|
|
99
|
+
const end = yield* within(trace.setSpan(context.active(), span), run());
|
|
100
|
+
span.setAttribute('agent.end_reason', end.reason);
|
|
101
|
+
span.setAttribute('agent.steps', end.steps);
|
|
102
|
+
if (end.stop)
|
|
103
|
+
span.setAttribute('agent.stop_code', end.stop.code);
|
|
104
|
+
return end;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return failed(span, error);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
span.end();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* One model step as a `model.call` span. `step` gets the loop's context with
|
|
115
|
+
* an `adapterFor` that notes the adapter it hands out, so the span names the
|
|
116
|
+
* provider that answered (the fallback's, when a fallback answered).
|
|
117
|
+
*/
|
|
118
|
+
export async function* traceModelCall(agent, ctx, step) {
|
|
119
|
+
initializeTracing();
|
|
120
|
+
const span = runtimeTracer().startSpan('model.call', {
|
|
121
|
+
attributes: {
|
|
122
|
+
'gen_ai.operation.name': 'chat',
|
|
123
|
+
'gen_ai.agent.name': agent.name,
|
|
124
|
+
'llm.agent': agent.name,
|
|
125
|
+
'gen_ai.request.model': agent.model,
|
|
126
|
+
'gen_ai.conversation.id': ctx.session.id,
|
|
127
|
+
'adk.invocation_id': ctx.invocationId,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
let provider;
|
|
131
|
+
const adapterFor = ctx.adapterFor ?? resolveAdapter;
|
|
132
|
+
const traced = {
|
|
133
|
+
...ctx,
|
|
134
|
+
adapterFor: (model) => {
|
|
135
|
+
const adapter = adapterFor(model);
|
|
136
|
+
provider = adapter.provider;
|
|
137
|
+
return adapter;
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
try {
|
|
141
|
+
const result = yield* within(trace.setSpan(context.active(), span), step(traced));
|
|
142
|
+
recordModelCall(span, result, provider);
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
return failed(span, error);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
span.end();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function recordModelCall(span, result, provider) {
|
|
153
|
+
// gen_ai.request.model stays the agent's model, as on ADK's call_llm; the
|
|
154
|
+
// llm.request span (and the payload's request) name the leaf that answered.
|
|
155
|
+
if (provider)
|
|
156
|
+
span.setAttribute('gen_ai.system', provider);
|
|
157
|
+
const response = result.response;
|
|
158
|
+
if (response?.usage) {
|
|
159
|
+
span.setAttribute('gen_ai.usage.input_tokens', response.usage.inputTokens);
|
|
160
|
+
span.setAttribute('gen_ai.usage.output_tokens', response.usage.outputTokens);
|
|
161
|
+
}
|
|
162
|
+
if (response?.finishReason)
|
|
163
|
+
span.setAttribute('gen_ai.response.finish_reasons', [response.finishReason]);
|
|
164
|
+
if (result.stopped) {
|
|
165
|
+
span.setAttribute('model.call.stop_code', result.stopped.code);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (!response)
|
|
169
|
+
return;
|
|
170
|
+
if (response.error) {
|
|
171
|
+
// The failed call's payload is on its llm.request span; the code alone here.
|
|
172
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
173
|
+
span.setAttribute('llm.error_code', String(response.error.code));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (payloadPolicyFromEnv().mode === 'off')
|
|
177
|
+
return;
|
|
178
|
+
const { signal: _signal, ...request } = result.request;
|
|
179
|
+
span.setAttribute('llm.payload.request', payloadJson(request));
|
|
180
|
+
span.setAttribute('llm.payload.response', payloadJson(response));
|
|
181
|
+
}
|
|
182
|
+
/** One tool call as a `tool.execute <name>` span, under the agent's. */
|
|
183
|
+
export async function traceToolCall(call, tool, run) {
|
|
184
|
+
initializeTracing();
|
|
185
|
+
const name = call.name || '<unnamed>';
|
|
186
|
+
const description = tool && typeof tool === 'object' ? tool.description : undefined;
|
|
187
|
+
const span = runtimeTracer().startSpan(`tool.execute ${name}`, {
|
|
188
|
+
attributes: {
|
|
189
|
+
'gen_ai.operation.name': 'execute_tool',
|
|
190
|
+
'gen_ai.tool.name': name,
|
|
191
|
+
'gen_ai.tool.description': typeof description === 'string' ? description : '',
|
|
192
|
+
...(call.id ? { 'gen_ai.tool.call.id': call.id } : {}),
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
try {
|
|
196
|
+
const outcome = await context.with(trace.setSpan(context.active(), span), run);
|
|
197
|
+
const response = outcome?.part?.functionResponse?.response;
|
|
198
|
+
if (!outcome?.part)
|
|
199
|
+
span.setAttribute('tool.pending', true);
|
|
200
|
+
else if (response && Object.hasOwn(response, 'error')) {
|
|
201
|
+
// The error text can quote the person's words; the response event holds it.
|
|
202
|
+
span.setAttribute('tool.error', true);
|
|
203
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
204
|
+
}
|
|
205
|
+
return outcome;
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return failed(span, error);
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
span.end();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// ── A workflow's spans (ADR 0095) ────────────────────────────────────────────
|
|
215
|
+
// ADK opens `invoke_workflow <name>` around a workflow's walk, `execute_node
|
|
216
|
+
// <name>` around each node run (a map item's under its map's), and
|
|
217
|
+
// `execute_tool <name>` around a tool node's call. The native walk opens the
|
|
218
|
+
// same three under the engine's names, `workflow.invoke`, `node.execute` and
|
|
219
|
+
// `tool.execute`, with ADK's attributes. An agent node's own `agent.invoke`
|
|
220
|
+
// (traceAgentInvocation, above) opens inside its node's span, so the ledger
|
|
221
|
+
// attributes each model call to the node's agent, as on ADK.
|
|
222
|
+
/** The walk as a `workflow.invoke <name>` span; every node span opens under it. */
|
|
223
|
+
export async function traceWorkflowInvocation(workflow, ctx, run) {
|
|
224
|
+
initializeTracing();
|
|
225
|
+
const span = runtimeTracer().startSpan(`workflow.invoke ${workflow.name}`, {
|
|
226
|
+
attributes: {
|
|
227
|
+
'gen_ai.operation.name': 'invoke_workflow',
|
|
228
|
+
'gen_ai.conversation.id': ctx.sessionId,
|
|
229
|
+
'adk.workflow.name': workflow.name,
|
|
230
|
+
'adk.node.path': workflow.path,
|
|
231
|
+
'adk.invocation_id': ctx.invocationId,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
try {
|
|
235
|
+
return await context.with(trace.setSpan(context.active(), span), run);
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
return failed(span, error);
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
span.end();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* One node run as a `node.execute <name>` span (the scheduler's traceNode
|
|
246
|
+
* hook): every attempt of the run inside it, ending with ADK's status
|
|
247
|
+
* (`completed`, `waiting` when the run paused on a person, `failed`) and the
|
|
248
|
+
* attempts the run made.
|
|
249
|
+
*/
|
|
250
|
+
export async function traceNodeExecution(node, run) {
|
|
251
|
+
initializeTracing();
|
|
252
|
+
const span = runtimeTracer().startSpan(`node.execute ${node.name}`, {
|
|
253
|
+
attributes: {
|
|
254
|
+
'gen_ai.operation.name': 'execute_node',
|
|
255
|
+
'adk.node.path': node.path,
|
|
256
|
+
'adk.node.run_id': node.runId,
|
|
257
|
+
'adk.node.kind': node.kind,
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
const settle = (status, interrupts) => span.setAttributes({ 'adk.node.attempt': node.attempts.count, 'adk.node.status': status, 'adk.node.interrupt_count': interrupts });
|
|
261
|
+
try {
|
|
262
|
+
const result = await context.with(trace.setSpan(context.active(), span), run);
|
|
263
|
+
const interrupts = result.interruptIds?.length ?? 0;
|
|
264
|
+
settle(interrupts > 0 ? 'waiting' : 'completed', interrupts);
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
settle('failed', 0);
|
|
269
|
+
return failed(span, error);
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
span.end();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** A tool node's call as a `tool.execute <name>` span, under its node's (ToolNodeContext.traceCall). */
|
|
276
|
+
export async function traceToolNodeCall(call, tool, run) {
|
|
277
|
+
initializeTracing();
|
|
278
|
+
const description = tool && typeof tool === 'object' ? tool.description : undefined;
|
|
279
|
+
const span = runtimeTracer().startSpan(`tool.execute ${call.name}`, {
|
|
280
|
+
attributes: {
|
|
281
|
+
'gen_ai.operation.name': 'execute_tool',
|
|
282
|
+
'gen_ai.tool.name': call.name,
|
|
283
|
+
'gen_ai.tool.description': typeof description === 'string' ? description : '',
|
|
284
|
+
'gen_ai.tool.call.id': call.id,
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
try {
|
|
288
|
+
return await context.with(trace.setSpan(context.active(), span), run);
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
// The tool node turns the throw into its { error } response; the span notes the failure, not the message.
|
|
292
|
+
span.setAttribute('tool.error', true);
|
|
293
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
span.end();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/native/tempState.ts — the run's `temp:` state, kept beside
|
|
3
|
+
* the session and never in it (ADR 0071, ADR 0073).
|
|
4
|
+
*
|
|
5
|
+
* WHY this file exists:
|
|
6
|
+
* On the ADK runtime a tool's `state.set('temp:x', …)` writes into the
|
|
7
|
+
* live session object as well as the event's delta, so the next step of
|
|
8
|
+
* the same invocation reads it (an instruction's `{temp:x}`, a tool's
|
|
9
|
+
* `state.get`), and the store drops it when it saves the event. The
|
|
10
|
+
* native loop applies a delta to the session only through the store
|
|
11
|
+
* (SessionService.append), which drops `temp:` keys as every store must.
|
|
12
|
+
* Writing them into the session object instead would reach a store that
|
|
13
|
+
* saves the whole session (the Supabase store does). So the run keeps
|
|
14
|
+
* them here: every event the loop stores is read for its `temp:` keys
|
|
15
|
+
* before the store sees it, and each step reads the session's state with
|
|
16
|
+
* these laid over it.
|
|
17
|
+
*
|
|
18
|
+
* Own keys only, set as own properties, so a key such as `__proto__` is a
|
|
19
|
+
* key and never a prototype.
|
|
20
|
+
*/
|
|
21
|
+
import type { TurnEvent } from '../events.ts';
|
|
22
|
+
/** The `temp:` keys one run has written so far. */
|
|
23
|
+
export interface RunTempState {
|
|
24
|
+
/** Reads `event`'s delta for `temp:` keys. Call it before the event is stored: the store drops them. */
|
|
25
|
+
record(event: TurnEvent): void;
|
|
26
|
+
/** The keys written so far, as a new object. */
|
|
27
|
+
values(): Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
export declare function createRunTempState(): RunTempState;
|
|
30
|
+
/** `state` with `overlay`'s keys laid over it, as a new object; `state` itself when there is nothing to lay. */
|
|
31
|
+
export declare function withStateOverlay(state: Readonly<Record<string, unknown>>, overlay: Readonly<Record<string, unknown>> | undefined): Readonly<Record<string, unknown>>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/native/tempState.ts — the run's `temp:` state, kept beside
|
|
3
|
+
* the session and never in it (ADR 0071, ADR 0073).
|
|
4
|
+
*
|
|
5
|
+
* WHY this file exists:
|
|
6
|
+
* On the ADK runtime a tool's `state.set('temp:x', …)` writes into the
|
|
7
|
+
* live session object as well as the event's delta, so the next step of
|
|
8
|
+
* the same invocation reads it (an instruction's `{temp:x}`, a tool's
|
|
9
|
+
* `state.get`), and the store drops it when it saves the event. The
|
|
10
|
+
* native loop applies a delta to the session only through the store
|
|
11
|
+
* (SessionService.append), which drops `temp:` keys as every store must.
|
|
12
|
+
* Writing them into the session object instead would reach a store that
|
|
13
|
+
* saves the whole session (the Supabase store does). So the run keeps
|
|
14
|
+
* them here: every event the loop stores is read for its `temp:` keys
|
|
15
|
+
* before the store sees it, and each step reads the session's state with
|
|
16
|
+
* these laid over it.
|
|
17
|
+
*
|
|
18
|
+
* Own keys only, set as own properties, so a key such as `__proto__` is a
|
|
19
|
+
* key and never a prototype.
|
|
20
|
+
*/
|
|
21
|
+
import { TEMP_STATE_PREFIX } from '../sessions.js';
|
|
22
|
+
function setOwn(target, key, value) {
|
|
23
|
+
Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
|
|
24
|
+
}
|
|
25
|
+
export function createRunTempState() {
|
|
26
|
+
const held = {};
|
|
27
|
+
return {
|
|
28
|
+
record(event) {
|
|
29
|
+
if (event.partial)
|
|
30
|
+
return;
|
|
31
|
+
const delta = event.actions?.stateDelta;
|
|
32
|
+
if (!delta)
|
|
33
|
+
return;
|
|
34
|
+
for (const [key, value] of Object.entries(delta))
|
|
35
|
+
if (key.startsWith(TEMP_STATE_PREFIX))
|
|
36
|
+
setOwn(held, key, value);
|
|
37
|
+
},
|
|
38
|
+
values() {
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const [key, value] of Object.entries(held))
|
|
41
|
+
setOwn(out, key, value);
|
|
42
|
+
return out;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** `state` with `overlay`'s keys laid over it, as a new object; `state` itself when there is nothing to lay. */
|
|
47
|
+
export function withStateOverlay(state, overlay) {
|
|
48
|
+
if (!overlay || Object.keys(overlay).length === 0)
|
|
49
|
+
return state;
|
|
50
|
+
const out = {};
|
|
51
|
+
for (const [key, value] of Object.entries(state))
|
|
52
|
+
setOwn(out, key, value);
|
|
53
|
+
for (const [key, value] of Object.entries(overlay))
|
|
54
|
+
setOwn(out, key, value);
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/nativeTurn.ts — which runtime runs a turn, and one agent's
|
|
3
|
+
* run on the native runtime (ADR 0045, ADR 0073).
|
|
4
|
+
*
|
|
5
|
+
* The flag itself is lib/runtime/runtimeFlag.ts.
|
|
6
|
+
*
|
|
7
|
+
* WHY this file exists:
|
|
8
|
+
* runSyndicateTurn (lib/runtime/syndicateTurn.ts) runs every turn on ADK
|
|
9
|
+
* by default. MELCHIZEDEK_RUNTIME=native, or the turn's `runtime: 'native'`
|
|
10
|
+
* option, runs it on the engine's own agent loop instead
|
|
11
|
+
* (lib/runtime/native/agentLoop.ts), with the agents lib/compileNative.ts
|
|
12
|
+
* builds from the same AgentSpec. The turn runner keeps its own logic —
|
|
13
|
+
* routing, guards, the relay fallback, approvals and questions read from
|
|
14
|
+
* the stored events — and swaps only what runs one agent: ADK's Runner,
|
|
15
|
+
* or runNativeAgent here. Both store the same events (ADR 0071), and the
|
|
16
|
+
* turn runner drains both with drainAgentStream.
|
|
17
|
+
*
|
|
18
|
+
* WHAT NATIVE REFUSES, before any model call, with a message naming the
|
|
19
|
+
* feature and the runtime (UnsupportedOnRuntimeError): a caller's ADK agent
|
|
20
|
+
* transform, and an `ask_user` tool on a workflow's agent (the schema
|
|
21
|
+
* refuses it on both runtimes; a config that skipped validation is refused
|
|
22
|
+
* here, ADR 0095). A workflow syndicate runs on native through the engine's
|
|
23
|
+
* scheduler (lib/workflow/turn.ts, ADR 0095). An answer to an approval
|
|
24
|
+
* resumes on native (lib/runtime/native/interrupts.ts), an answer to a
|
|
25
|
+
* question resumes the agent that asked (lib/runtime/questions.ts, ADR
|
|
26
|
+
* 0079), `context:` compacts on native (lib/runtime/native/compaction.ts),
|
|
27
|
+
* and `mode: task` runs on native (lib/runtime/native/taskMode.ts).
|
|
28
|
+
*/
|
|
29
|
+
import type { BaseMemoryService, BaseSessionService } from '@google/adk';
|
|
30
|
+
import type { SyndicateYamlConfig } from '../loadSyndicate.ts';
|
|
31
|
+
import type { ModelAdapter } from '../models/contract.ts';
|
|
32
|
+
import type { TurnEvent } from './events.ts';
|
|
33
|
+
import type { MemoryService } from './memoryService.ts';
|
|
34
|
+
import type { AgentLoopEnd } from './native/agentLoop.ts';
|
|
35
|
+
import type { NativeAgent } from './native/request.ts';
|
|
36
|
+
import type { SelfCorrection } from './native/selfCorrection.ts';
|
|
37
|
+
import type { SessionService } from './sessions.ts';
|
|
38
|
+
import type { CredentialStore } from '../tools/auth.ts';
|
|
39
|
+
import type { OAuthConsent } from '../tools/oauthConsent.ts';
|
|
40
|
+
/**
|
|
41
|
+
* Throws UnsupportedOnRuntimeError for a syndicate or a call the native
|
|
42
|
+
* runtime does not run yet.
|
|
43
|
+
*/
|
|
44
|
+
export declare function refuseOnNative(config: SyndicateYamlConfig, call: {
|
|
45
|
+
isWorkflow: boolean;
|
|
46
|
+
transformAgent?: unknown;
|
|
47
|
+
}): void;
|
|
48
|
+
/**
|
|
49
|
+
* The search the native loop's memory tools call: the engine's MemoryService
|
|
50
|
+
* as it is, or an ADK-only service's searchMemory, which takes and returns
|
|
51
|
+
* the same JSON. The caller has already pinned the namespace.
|
|
52
|
+
*/
|
|
53
|
+
export declare function nativeMemory(service: BaseMemoryService | MemoryService | undefined): Pick<MemoryService, 'search'> | undefined;
|
|
54
|
+
export interface NativeRunParams {
|
|
55
|
+
agent: NativeAgent;
|
|
56
|
+
/** The leaf adapter for a model id (lib/compileNative.ts nativeAdapterFor). */
|
|
57
|
+
adapterFor: (model: string) => ModelAdapter;
|
|
58
|
+
/** The store, either face (lib/runtime/adkSessionBridge.ts). */
|
|
59
|
+
sessions: SessionService | BaseSessionService;
|
|
60
|
+
appName: string;
|
|
61
|
+
userId: string;
|
|
62
|
+
sessionId: string;
|
|
63
|
+
/** The message's parts. */
|
|
64
|
+
userParts: unknown[];
|
|
65
|
+
/** The turn's signal. */
|
|
66
|
+
signal?: AbortSignal;
|
|
67
|
+
/** Stream text as partial events. */
|
|
68
|
+
stream?: boolean;
|
|
69
|
+
memory?: Pick<MemoryService, 'search'>;
|
|
70
|
+
log?: (message: string) => void;
|
|
71
|
+
/** The turn's self-correction (ADR 0075), built once per turn from `retries:`. Default: retries at their defaults. */
|
|
72
|
+
selfCorrection?: SelfCorrection;
|
|
73
|
+
/** The run's tool credentials, pinned to its app (ADR 0072). */
|
|
74
|
+
credentials?: Pick<CredentialStore, 'get'>;
|
|
75
|
+
/** The consent step (ADR 0085). */
|
|
76
|
+
consent?: Pick<OAuthConsent, 'has' | 'begin'>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Runs `agent` for one message, as ADK's Runner runs an agent: read the
|
|
80
|
+
* session (it must exist), store the message as the user's event under a
|
|
81
|
+
* new `e-` invocation id, then run the agent loop on it, yielding every
|
|
82
|
+
* event the loop yields. A run whose signal aborted before the message was
|
|
83
|
+
* stored stores nothing, as on ADK. Returns how the loop ended, or
|
|
84
|
+
* undefined when it never started.
|
|
85
|
+
*/
|
|
86
|
+
export declare function runNativeAgent(params: NativeRunParams): AsyncGenerator<TurnEvent, AgentLoopEnd | undefined>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/nativeTurn.ts — which runtime runs a turn, and one agent's
|
|
3
|
+
* run on the native runtime (ADR 0045, ADR 0073).
|
|
4
|
+
*
|
|
5
|
+
* The flag itself is lib/runtime/runtimeFlag.ts.
|
|
6
|
+
*
|
|
7
|
+
* WHY this file exists:
|
|
8
|
+
* runSyndicateTurn (lib/runtime/syndicateTurn.ts) runs every turn on ADK
|
|
9
|
+
* by default. MELCHIZEDEK_RUNTIME=native, or the turn's `runtime: 'native'`
|
|
10
|
+
* option, runs it on the engine's own agent loop instead
|
|
11
|
+
* (lib/runtime/native/agentLoop.ts), with the agents lib/compileNative.ts
|
|
12
|
+
* builds from the same AgentSpec. The turn runner keeps its own logic —
|
|
13
|
+
* routing, guards, the relay fallback, approvals and questions read from
|
|
14
|
+
* the stored events — and swaps only what runs one agent: ADK's Runner,
|
|
15
|
+
* or runNativeAgent here. Both store the same events (ADR 0071), and the
|
|
16
|
+
* turn runner drains both with drainAgentStream.
|
|
17
|
+
*
|
|
18
|
+
* WHAT NATIVE REFUSES, before any model call, with a message naming the
|
|
19
|
+
* feature and the runtime (UnsupportedOnRuntimeError): a caller's ADK agent
|
|
20
|
+
* transform, and an `ask_user` tool on a workflow's agent (the schema
|
|
21
|
+
* refuses it on both runtimes; a config that skipped validation is refused
|
|
22
|
+
* here, ADR 0095). A workflow syndicate runs on native through the engine's
|
|
23
|
+
* scheduler (lib/workflow/turn.ts, ADR 0095). An answer to an approval
|
|
24
|
+
* resumes on native (lib/runtime/native/interrupts.ts), an answer to a
|
|
25
|
+
* question resumes the agent that asked (lib/runtime/questions.ts, ADR
|
|
26
|
+
* 0079), `context:` compacts on native (lib/runtime/native/compaction.ts),
|
|
27
|
+
* and `mode: task` runs on native (lib/runtime/native/taskMode.ts).
|
|
28
|
+
*/
|
|
29
|
+
import { randomUUID } from 'node:crypto';
|
|
30
|
+
import { asSessionService } from './adkSessionBridge.js';
|
|
31
|
+
import { createTurnEvent } from './events.js';
|
|
32
|
+
import { runAgentLoop } from './native/agentLoop.js';
|
|
33
|
+
import { ASK_USER } from './questions.js';
|
|
34
|
+
import { unsupportedOnNative } from './runtimeFlag.js';
|
|
35
|
+
// ── What native refuses before a turn starts ─────────────────────────────────
|
|
36
|
+
/**
|
|
37
|
+
* Throws UnsupportedOnRuntimeError for a syndicate or a call the native
|
|
38
|
+
* runtime does not run yet.
|
|
39
|
+
*/
|
|
40
|
+
export function refuseOnNative(config, call) {
|
|
41
|
+
const where = config.syndicate_name || config.orchestrator?.name || 'syndicate';
|
|
42
|
+
if (call.transformAgent)
|
|
43
|
+
throw unsupportedOnNative('transformAgent (it transforms ADK agents)', where);
|
|
44
|
+
if (call.isWorkflow) {
|
|
45
|
+
// A pause inside an agent node cannot be resumed by the native walk (lib/workflow/resume.ts).
|
|
46
|
+
const asking = [config.orchestrator, ...(config.subagents ?? [])].find((agent) => (agent?.tools ?? []).includes(ASK_USER));
|
|
47
|
+
if (asking)
|
|
48
|
+
throw unsupportedOnNative(`an ${ASK_USER} tool on a workflow node (${asking.name}; use an ask_user node)`, where);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ── Memory ───────────────────────────────────────────────────────────────────
|
|
52
|
+
/**
|
|
53
|
+
* The search the native loop's memory tools call: the engine's MemoryService
|
|
54
|
+
* as it is, or an ADK-only service's searchMemory, which takes and returns
|
|
55
|
+
* the same JSON. The caller has already pinned the namespace.
|
|
56
|
+
*/
|
|
57
|
+
export function nativeMemory(service) {
|
|
58
|
+
if (!service)
|
|
59
|
+
return undefined;
|
|
60
|
+
const engine = service;
|
|
61
|
+
if (typeof engine.search === 'function')
|
|
62
|
+
return { search: (request) => engine.search(request) };
|
|
63
|
+
const adk = service;
|
|
64
|
+
if (typeof adk.searchMemory !== 'function')
|
|
65
|
+
return undefined;
|
|
66
|
+
return {
|
|
67
|
+
search: async (request) => (await adk.searchMemory(request)),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Runs `agent` for one message, as ADK's Runner runs an agent: read the
|
|
72
|
+
* session (it must exist), store the message as the user's event under a
|
|
73
|
+
* new `e-` invocation id, then run the agent loop on it, yielding every
|
|
74
|
+
* event the loop yields. A run whose signal aborted before the message was
|
|
75
|
+
* stored stores nothing, as on ADK. Returns how the loop ended, or
|
|
76
|
+
* undefined when it never started.
|
|
77
|
+
*/
|
|
78
|
+
export async function* runNativeAgent(params) {
|
|
79
|
+
const sessions = asSessionService(params.sessions);
|
|
80
|
+
const { appName, userId, sessionId } = params;
|
|
81
|
+
const session = await sessions.get({ appName, userId, sessionId });
|
|
82
|
+
if (!session)
|
|
83
|
+
throw new Error(`Session not found: ${sessionId} (appName=${appName}, userId=${userId})`);
|
|
84
|
+
if (params.signal?.aborted)
|
|
85
|
+
return undefined;
|
|
86
|
+
if (params.userParts.length === 0)
|
|
87
|
+
throw new Error('No parts in the newMessage.');
|
|
88
|
+
const invocationId = `e-${randomUUID()}`;
|
|
89
|
+
const userContent = { role: 'user', parts: params.userParts };
|
|
90
|
+
await sessions.append(session, createTurnEvent({ invocationId, author: 'user', content: userContent }));
|
|
91
|
+
if (params.signal?.aborted)
|
|
92
|
+
return undefined;
|
|
93
|
+
return yield* runAgentLoop(params.agent, {
|
|
94
|
+
session,
|
|
95
|
+
sessions,
|
|
96
|
+
invocationId,
|
|
97
|
+
userContent,
|
|
98
|
+
stream: params.stream ?? false,
|
|
99
|
+
adapterFor: params.adapterFor,
|
|
100
|
+
...(params.signal ? { signal: params.signal } : {}),
|
|
101
|
+
...(params.memory ? { memory: params.memory } : {}),
|
|
102
|
+
...(params.log ? { log: params.log } : {}),
|
|
103
|
+
...(params.selfCorrection ? { selfCorrection: params.selfCorrection } : {}),
|
|
104
|
+
...(params.credentials ? { credentials: params.credentials } : {}),
|
|
105
|
+
...(params.consent ? { consent: params.consent } : {}),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* these three accounts?", "what is the order number?". Before this, an
|
|
7
7
|
* agent could only end its turn with a question in its text and hope the
|
|
8
8
|
* next message answered it, with nothing in the session saying a question
|
|
9
|
-
* was open. `ask_user` is
|
|
10
|
-
* name: the call is recorded, the run ends without a response to it, the
|
|
9
|
+
* was open. `ask_user` is a long-running tool (lib/tools/tool.ts) under one
|
|
10
|
+
* YAML name: the call is recorded, the run ends without a response to it, the
|
|
11
11
|
* turn ends `input-required` (`result.input`), and the next message on the
|
|
12
12
|
* conversation becomes the call's response, so the agent resumes its own
|
|
13
13
|
* tool loop where it asked, with the question and the answer side by side
|
|
@@ -21,8 +21,15 @@
|
|
|
21
21
|
* plan-dispatch route), as with approval gates: inside a delegated
|
|
22
22
|
* subagent ADK swallows the pause. Not inside a workflow node yet. The
|
|
23
23
|
* schema refuses both.
|
|
24
|
+
*
|
|
25
|
+
* RUNTIMES: the same on ADK and on the native loop (ADR 0079). The answer is
|
|
26
|
+
* an ordinary function response, so either runtime resumes a question either
|
|
27
|
+
* one opened; neither runs a request processor for it.
|
|
28
|
+
*
|
|
29
|
+
* TRUST: a question is an agent's call. One in an event the user authored
|
|
30
|
+
* (a forged call in a message) is ignored, on both runtimes, as approvals
|
|
31
|
+
* refuse a user-authored request (ADR 0077, ADR 0088).
|
|
24
32
|
*/
|
|
25
|
-
import { LongRunningFunctionTool } from '@google/adk';
|
|
26
33
|
import type { Event } from '@google/adk';
|
|
27
34
|
import { z } from 'zod';
|
|
28
35
|
import type { PendingInput } from '../workflowConfig.ts';
|
|
@@ -30,13 +37,15 @@ import type { PendingInput } from '../workflowConfig.ts';
|
|
|
30
37
|
export declare const ASK_USER = "ask_user";
|
|
31
38
|
export declare const MAX_OPTIONS = 10;
|
|
32
39
|
/**
|
|
33
|
-
* The tool
|
|
34
|
-
*
|
|
40
|
+
* The tool, an own Tool marked long-running; the registry hands the ADK
|
|
41
|
+
* runtime its FunctionTool (lib/tools/adkTool.ts). Its execute returns
|
|
42
|
+
* nothing: a long-running call with no result ends the run, and the runtime
|
|
43
|
+
* waits for a function response with the call's id.
|
|
35
44
|
*/
|
|
36
|
-
export declare const askUserTool:
|
|
45
|
+
export declare const askUserTool: import("../tools/toolContract.ts").DefinedTool<z.ZodObject<{
|
|
37
46
|
question: z.ZodString;
|
|
38
47
|
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
39
|
-
}, z.core.$strip
|
|
48
|
+
}, z.core.$strip>, undefined>;
|
|
40
49
|
/** The question an `ask_user` call carries, as the turn result reports it. */
|
|
41
50
|
export declare function questionFrom(author: string | undefined, call: {
|
|
42
51
|
name?: string;
|
|
@@ -47,8 +56,21 @@ export declare function questionFrom(author: string | undefined, call: {
|
|
|
47
56
|
* The question still waiting for an answer in a session, or undefined. A
|
|
48
57
|
* question the person moved past (a text message after it was answered)
|
|
49
58
|
* is not pending; an answered one carries a function response with its id.
|
|
59
|
+
* Only an agent asks: an `ask_user` call in an event the user authored is
|
|
60
|
+
* no question, so the next message never becomes its answer (as approvals
|
|
61
|
+
* refuse a user-authored request, ADR 0077; ADR 0088).
|
|
50
62
|
*/
|
|
51
63
|
export declare function pendingQuestion(events: readonly Event[]): PendingInput | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* The workflow question (`adk_request_input`, an ask_user node's request)
|
|
66
|
+
* still open in a session's events, or undefined. The answer is stored as
|
|
67
|
+
* the person's next text message, not as a function response, so a text
|
|
68
|
+
* message after the question closes it; a function response with its id
|
|
69
|
+
* answers it too. As with pendingQuestion, only a node asks: a request in
|
|
70
|
+
* an event the user authored is none. The resume (lib/workflow/resume.ts)
|
|
71
|
+
* reads the same events to route the answer.
|
|
72
|
+
*/
|
|
73
|
+
export declare function pendingWorkflowInput(events: readonly Event[]): PendingInput | undefined;
|
|
52
74
|
/** The message part that answers question `id` with the person's text. */
|
|
53
75
|
export declare function questionAnswerPart(id: string, answer: string): Record<string, unknown>;
|
|
54
76
|
/** Index of the user message that started the turn holding call `id` (replayed raw on a dispatch resume). */
|