melchizedek-agents 0.18.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/.env.example +12 -0
- package/CHANGELOG.md +1001 -0
- package/DOCUMENTATION.md +252 -65
- package/QUICKSTART.md +9 -6
- package/README.md +42 -4
- package/config/agents/examples/harness.yaml +3 -1
- package/config/agents/examples/model_zoo.yaml +10 -9
- package/config/agents/syndicateSchema.yaml +53 -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/adkPeer.d.ts +63 -0
- package/dist/lib/adkPeer.js +240 -0
- package/dist/lib/compile.d.ts +159 -30
- package/dist/lib/compile.js +215 -134
- package/dist/lib/compileAdk.d.ts +32 -0
- package/dist/lib/compileAdk.js +142 -0
- package/dist/lib/compileNative.d.ts +111 -0
- package/dist/lib/compileNative.js +278 -0
- package/dist/lib/config.d.ts +6 -5
- package/dist/lib/config.js +6 -5
- package/dist/lib/doctor.d.ts +28 -1
- package/dist/lib/doctor.js +64 -2
- package/dist/lib/index.d.ts +6 -1
- package/dist/lib/index.js +7 -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 +115 -0
- package/dist/lib/models/adapterResolver.js +137 -0
- package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
- package/dist/lib/models/adkGeminiAdapter.js +369 -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 +33 -23
- 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 +45 -350
- 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 +18 -11
- package/dist/lib/models/fallback.js +54 -43
- 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 +16 -77
- package/dist/lib/models/geminiAdapter.d.ts +125 -0
- package/dist/lib/models/geminiAdapter.js +854 -0
- package/dist/lib/models/geminiState.d.ts +46 -0
- package/dist/lib/models/geminiState.js +51 -0
- package/dist/lib/models/genaiMapping.d.ts +283 -0
- package/dist/lib/models/genaiMapping.js +965 -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 +89 -603
- 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 +24 -69
- 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 +19 -155
- 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 +15 -153
- 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 +62 -35
- package/dist/lib/models/registry.js +100 -124
- 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/approvals.d.ts +5 -0
- package/dist/lib/runtime/approvals.js +39 -8
- package/dist/lib/runtime/credentials.d.ts +61 -0
- package/dist/lib/runtime/credentials.js +67 -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 +209 -0
- package/dist/lib/runtime/native/agentLoop.js +705 -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 +151 -0
- package/dist/lib/runtime/native/delegate.js +256 -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 +129 -0
- package/dist/lib/runtime/native/interrupts.js +310 -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 +164 -0
- package/dist/lib/runtime/native/selfCorrection.js +327 -0
- package/dist/lib/runtime/native/step.d.ts +156 -0
- package/dist/lib/runtime/native/step.js +263 -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 +38 -0
- package/dist/lib/runtime/runtimeFlag.js +58 -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 +46 -5
- package/dist/lib/runtime/syndicateTurn.js +233 -36
- package/dist/lib/runtime/valueDepth.d.ts +23 -0
- package/dist/lib/runtime/valueDepth.js +41 -0
- package/dist/lib/session/supabaseSessionService.d.ts +65 -18
- package/dist/lib/session/supabaseSessionService.js +148 -105
- package/dist/lib/session/transcript.d.ts +69 -23
- package/dist/lib/session/transcript.js +105 -29
- 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 +44 -16
- package/dist/lib/storage/postgres/sessionService.js +128 -66
- package/dist/lib/syndicateSchema.d.ts +49 -0
- package/dist/lib/syndicateSchema.js +99 -9
- package/dist/lib/toolRegistry.d.ts +26 -2
- package/dist/lib/toolRegistry.js +73 -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 +8 -7
- package/dist/lib/tools/collectionsSearchTool.js +12 -27
- 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 +4 -1
- package/dist/lib/tools/urlContextTool.js +6 -2
- package/dist/lib/tools/webExtractTool.d.ts +3 -3
- package/dist/lib/tools/webExtractTool.js +2 -1
- package/dist/lib/tools/webSearchTool.d.ts +7 -10
- package/dist/lib/tools/webSearchTool.js +15 -60
- package/dist/lib/tools/wikiTools.d.ts +19 -19
- package/dist/lib/tools/wikiTools.js +13 -9
- package/dist/lib/tools/xApiSearchTool.d.ts +3 -3
- package/dist/lib/tools/xApiSearchTool.js +2 -1
- package/dist/lib/tools/xSearchTool.d.ts +8 -10
- package/dist/lib/tools/xSearchTool.js +12 -63
- 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 +74 -35
- package/dist/lib/wiki/entities.d.ts +12 -0
- package/dist/lib/wiki/entities.js +45 -3
- package/dist/lib/workflow/agentNode.d.ts +153 -0
- package/dist/lib/workflow/agentNode.js +365 -0
- package/dist/lib/workflow/graph.d.ts +178 -0
- package/dist/lib/workflow/graph.js +468 -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 +166 -0
- package/dist/lib/workflow/resume.js +441 -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 +418 -0
- package/dist/lib/workflow/scheduler.js +756 -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/workflow.d.ts +33 -11
- package/dist/lib/workflow.js +49 -27
- package/dist/lib/workflowConfig.d.ts +7 -2
- package/dist/lib/workflowConfig.js +7 -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/doctor.d.ts +3 -1
- package/dist/scripts/doctor.js +4 -2
- package/dist/scripts/syndicate_chat.js +19 -10
- package/package.json +9 -3
- 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,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/native/selfCorrection.ts — self-correction on the native loop:
|
|
3
|
+
* a model error and a tool error retried with reflection, as ADK's
|
|
4
|
+
* reflect-and-retry plugins do it on the ADK runtime (ADR 0034, ADR 0075).
|
|
5
|
+
*
|
|
6
|
+
* WHY this file exists:
|
|
7
|
+
* runSyndicateTurn installs ADK's ReflectAndRetryModelPlugin and
|
|
8
|
+
* ReflectAndRetryToolPlugin on every Runner it builds, retries at their
|
|
9
|
+
* defaults unless the syndicate's `retries:` says otherwise. They change
|
|
10
|
+
* what the model is sent and what the store holds, so the native loop
|
|
11
|
+
* does what they do, word for word, or a session one runtime wrote would
|
|
12
|
+
* read differently on the other:
|
|
13
|
+
*
|
|
14
|
+
* THE MODEL (`retries.model_errors`, default 2; 0 off):
|
|
15
|
+
* - The reflection tool, `adk_handle_model_error`, is one of every step's
|
|
16
|
+
* tools, after the agent's own: the plugin's beforeModelCallback adds it
|
|
17
|
+
* to the request's toolsDict last, and never to its config. Whether the
|
|
18
|
+
* model is told of it depends on the model class ADK hands the request
|
|
19
|
+
* to (ADR 0097): the ADK shim and the engine's own ADK classes declare
|
|
20
|
+
* the toolsDict, so the tool is declared; ADK's own Gemini sends the
|
|
21
|
+
* config alone, so a Gemini model is never told of it. The step asks
|
|
22
|
+
* `declaresReflectionTool` and runs the tool either way.
|
|
23
|
+
* - Each response is checked (afterModelCallback), partials included. A
|
|
24
|
+
* response that calls the reflection tool itself, or whose finish reason
|
|
25
|
+
* is MALFORMED_FUNCTION_CALL, is replaced by a call to the reflection
|
|
26
|
+
* tool: id `adk_handle_model_error_<uuid>`, the error in its arguments,
|
|
27
|
+
* the retry's number counted per agent in the run. The loop runs that
|
|
28
|
+
* call like any other, and the tool answers with reflection guidance.
|
|
29
|
+
* Any other response resets the agent's count.
|
|
30
|
+
* - ON A GEMINI MODEL the stored reflection call is signed (ADR 0103), where
|
|
31
|
+
* ADK's plugin stores it unsigned: it carries the replaced response's
|
|
32
|
+
* thoughtSignature, or on Gemini 3 Gemini's documented placeholder when
|
|
33
|
+
* the response had none (a MALFORMED_FUNCTION_CALL has no parts). Gemini 3
|
|
34
|
+
* rejects the next request with an unsigned current-turn call (400,
|
|
35
|
+
* "missing a thought_signature"); ADK's runtime still does. This is the
|
|
36
|
+
* one place the native loop stores what ADK would not (reflectionSigning).
|
|
37
|
+
* - Past the limit the step ends on ADK's error event for a callback that
|
|
38
|
+
* threw: UNKNOWN_ERROR, and the plugin manager's message.
|
|
39
|
+
*
|
|
40
|
+
* THE TOOLS (`retries.tool_errors`, default 3; 0 off):
|
|
41
|
+
* - A tool that throws an Error, and a call naming no tool, answer with
|
|
42
|
+
* reflection guidance (onToolErrorCallback) in place of the plain error,
|
|
43
|
+
* counted per tool name in the run; past the limit, the "retry limit
|
|
44
|
+
* exceeded" guidance (the plugin is built not to throw).
|
|
45
|
+
* - A call that answered resets its tool's count (afterToolCallback),
|
|
46
|
+
* unless the answer is itself reflection guidance.
|
|
47
|
+
* - ADK runs a step's calls one after another; the native loop runs them
|
|
48
|
+
* in parallel. The counts are kept in call order all the same: each
|
|
49
|
+
* call's count waits for the calls before it (StepCorrection).
|
|
50
|
+
*
|
|
51
|
+
* The texts, the argument names and the counting quirks are ADK 2.2.0's
|
|
52
|
+
* (plugins/reflect_retry_*.js), the reflection tool's "attempt 1" included:
|
|
53
|
+
* it reads `retryCount` where the call carries `retry_count`.
|
|
54
|
+
* tests/selfCorrection.test.ts and tests/nativeLoop.test.ts hold the two
|
|
55
|
+
* runtimes to the same stored events.
|
|
56
|
+
*
|
|
57
|
+
* ADK stays out of this file but for the LlmResponse type the step already
|
|
58
|
+
* reads responses as.
|
|
59
|
+
*/
|
|
60
|
+
import type { LlmResponse } from '@google/adk';
|
|
61
|
+
import type { Tool } from '../../tools/tool.ts';
|
|
62
|
+
/** The syndicate's `retries:` key (lib/syndicateSchema.ts). */
|
|
63
|
+
export interface Retries {
|
|
64
|
+
model_errors?: number;
|
|
65
|
+
tool_errors?: number;
|
|
66
|
+
}
|
|
67
|
+
export declare const DEFAULT_MODEL_ERROR_RETRIES = 2;
|
|
68
|
+
export declare const DEFAULT_TOOL_ERROR_RETRIES = 3;
|
|
69
|
+
export declare const ADK_HANDLE_MODEL_ERROR = "adk_handle_model_error";
|
|
70
|
+
export declare const REFLECT_AND_RETRY_RESPONSE_TYPE = "ERROR_HANDLED_BY_REFLECT_AND_RETRY_PLUGIN";
|
|
71
|
+
/**
|
|
72
|
+
* Marks `adapter` as one the ADK runtime would call through the ADK shim
|
|
73
|
+
* (a resolver's shim or contract adapter, lib/compileNative.ts), not through
|
|
74
|
+
* ADK's own Gemini. Returns it.
|
|
75
|
+
*/
|
|
76
|
+
export declare function servedThroughShim<T extends object>(adapter: T): T;
|
|
77
|
+
/**
|
|
78
|
+
* Whether the ADK runtime would tell this adapter's model of the reflection
|
|
79
|
+
* tool (ADR 0097). The plugin puts the tool in the toolsDict alone. Every
|
|
80
|
+
* model class the engine hands ADK declares the toolsDict, but ADK's own
|
|
81
|
+
* Gemini (and TracedGemini over it) sends only the request's config, which
|
|
82
|
+
* never holds it. A Gemini adapter stands for ADK's Gemini unless a caller
|
|
83
|
+
* handed it over behind the shim (servedThroughShim).
|
|
84
|
+
*/
|
|
85
|
+
export declare function declaresReflectionTool(adapter: {
|
|
86
|
+
readonly provider: string;
|
|
87
|
+
}): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Whether this adapter stands, on the native runtime, for ADK's own Gemini
|
|
90
|
+
* (TracedGemini) on the ADK runtime: a Gemini adapter no caller handed over
|
|
91
|
+
* behind the shim. The step declares no reflection tool to it (ADR 0097) and
|
|
92
|
+
* stores no `turnComplete` on its events, as ADK's Gemini writes none
|
|
93
|
+
* (ADR 0100).
|
|
94
|
+
*/
|
|
95
|
+
export declare function standsForAdkGemini(adapter: {
|
|
96
|
+
readonly provider: string;
|
|
97
|
+
}): boolean;
|
|
98
|
+
/** How the reflection call stored in a model's place is signed. */
|
|
99
|
+
export interface ReflectionSigning {
|
|
100
|
+
/** The signature for a reflection call whose replaced response carried none; absent: left unsigned. */
|
|
101
|
+
placeholder?: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* How self-correction signs the reflection call it stores in place of this
|
|
105
|
+
* adapter's response, or undefined to store it unsigned, as ADK's plugin
|
|
106
|
+
* does. A Gemini adapter's call carries the replaced response's signature;
|
|
107
|
+
* on a Gemini 3 model, whose API rejects an unsigned current-turn call, the
|
|
108
|
+
* placeholder stands in when there was none.
|
|
109
|
+
*/
|
|
110
|
+
export declare function reflectionSigning(adapter: {
|
|
111
|
+
readonly provider: string;
|
|
112
|
+
}, model: string | undefined): ReflectionSigning | undefined;
|
|
113
|
+
/** What afterModel leaves of a response: the response to record, or the error event that ends the step. */
|
|
114
|
+
export type CorrectedResponse = {
|
|
115
|
+
response: LlmResponse;
|
|
116
|
+
replaced: boolean;
|
|
117
|
+
} | {
|
|
118
|
+
failed: {
|
|
119
|
+
code: string;
|
|
120
|
+
message: string;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
/** The model side, for one agent's steps in one run (lib/runtime/native/step.ts). */
|
|
124
|
+
export interface ModelCorrection {
|
|
125
|
+
/** After the agent's own tools: the reflection tool. Declared to the model only where ADK declares it (declaresReflectionTool). */
|
|
126
|
+
readonly tools: readonly Tool[];
|
|
127
|
+
/**
|
|
128
|
+
* ADK's afterModelCallback, on every response the step reads. With
|
|
129
|
+
* `signing` (reflectionSigning), a reflection call put in the response's
|
|
130
|
+
* place is signed.
|
|
131
|
+
*/
|
|
132
|
+
afterModel(response: LlmResponse, signing?: ReflectionSigning): CorrectedResponse;
|
|
133
|
+
}
|
|
134
|
+
/** The tool side, for one call (lib/runtime/native/agentLoop.ts). Each call makes exactly one of these. */
|
|
135
|
+
export interface CallCorrection {
|
|
136
|
+
/**
|
|
137
|
+
* The call threw, or named no tool: the guidance that answers it in place
|
|
138
|
+
* of the error, or undefined to answer the error as it is (a throw that is
|
|
139
|
+
* not an Error, which ADK hands to no plugin).
|
|
140
|
+
*/
|
|
141
|
+
failed(toolName: string, args: Record<string, unknown>, error: unknown): Promise<Record<string, unknown> | undefined>;
|
|
142
|
+
/** The call answered: its tool's count starts again. */
|
|
143
|
+
answered(toolName: string, result: unknown): Promise<void>;
|
|
144
|
+
}
|
|
145
|
+
/** The tool side for one step's calls, counted in call order. `release(i)` when call i is done, whatever it did. */
|
|
146
|
+
export interface StepCorrection {
|
|
147
|
+
call(index: number): CallCorrection;
|
|
148
|
+
release(index: number): void;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Self-correction for a run: ADK's two plugins, with their counters. One per
|
|
152
|
+
* turn, as runSyndicateTurn builds one pair of plugins per Runner; the
|
|
153
|
+
* counters are kept per run (invocation id) within it.
|
|
154
|
+
*/
|
|
155
|
+
export declare class SelfCorrection {
|
|
156
|
+
#private;
|
|
157
|
+
readonly modelErrors: number;
|
|
158
|
+
readonly toolErrors: number;
|
|
159
|
+
constructor(retries?: Retries);
|
|
160
|
+
/** The model side for `agentName`'s steps in run `invocationId`; undefined when model retries are off. */
|
|
161
|
+
forModel(agentName: string, invocationId: string): ModelCorrection | undefined;
|
|
162
|
+
/** The tool side for one step of `count` calls in run `invocationId`; undefined when tool retries are off. */
|
|
163
|
+
forCalls(invocationId: string, count: number): StepCorrection | undefined;
|
|
164
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/native/selfCorrection.ts — self-correction on the native loop:
|
|
3
|
+
* a model error and a tool error retried with reflection, as ADK's
|
|
4
|
+
* reflect-and-retry plugins do it on the ADK runtime (ADR 0034, ADR 0075).
|
|
5
|
+
*
|
|
6
|
+
* WHY this file exists:
|
|
7
|
+
* runSyndicateTurn installs ADK's ReflectAndRetryModelPlugin and
|
|
8
|
+
* ReflectAndRetryToolPlugin on every Runner it builds, retries at their
|
|
9
|
+
* defaults unless the syndicate's `retries:` says otherwise. They change
|
|
10
|
+
* what the model is sent and what the store holds, so the native loop
|
|
11
|
+
* does what they do, word for word, or a session one runtime wrote would
|
|
12
|
+
* read differently on the other:
|
|
13
|
+
*
|
|
14
|
+
* THE MODEL (`retries.model_errors`, default 2; 0 off):
|
|
15
|
+
* - The reflection tool, `adk_handle_model_error`, is one of every step's
|
|
16
|
+
* tools, after the agent's own: the plugin's beforeModelCallback adds it
|
|
17
|
+
* to the request's toolsDict last, and never to its config. Whether the
|
|
18
|
+
* model is told of it depends on the model class ADK hands the request
|
|
19
|
+
* to (ADR 0097): the ADK shim and the engine's own ADK classes declare
|
|
20
|
+
* the toolsDict, so the tool is declared; ADK's own Gemini sends the
|
|
21
|
+
* config alone, so a Gemini model is never told of it. The step asks
|
|
22
|
+
* `declaresReflectionTool` and runs the tool either way.
|
|
23
|
+
* - Each response is checked (afterModelCallback), partials included. A
|
|
24
|
+
* response that calls the reflection tool itself, or whose finish reason
|
|
25
|
+
* is MALFORMED_FUNCTION_CALL, is replaced by a call to the reflection
|
|
26
|
+
* tool: id `adk_handle_model_error_<uuid>`, the error in its arguments,
|
|
27
|
+
* the retry's number counted per agent in the run. The loop runs that
|
|
28
|
+
* call like any other, and the tool answers with reflection guidance.
|
|
29
|
+
* Any other response resets the agent's count.
|
|
30
|
+
* - ON A GEMINI MODEL the stored reflection call is signed (ADR 0103), where
|
|
31
|
+
* ADK's plugin stores it unsigned: it carries the replaced response's
|
|
32
|
+
* thoughtSignature, or on Gemini 3 Gemini's documented placeholder when
|
|
33
|
+
* the response had none (a MALFORMED_FUNCTION_CALL has no parts). Gemini 3
|
|
34
|
+
* rejects the next request with an unsigned current-turn call (400,
|
|
35
|
+
* "missing a thought_signature"); ADK's runtime still does. This is the
|
|
36
|
+
* one place the native loop stores what ADK would not (reflectionSigning).
|
|
37
|
+
* - Past the limit the step ends on ADK's error event for a callback that
|
|
38
|
+
* threw: UNKNOWN_ERROR, and the plugin manager's message.
|
|
39
|
+
*
|
|
40
|
+
* THE TOOLS (`retries.tool_errors`, default 3; 0 off):
|
|
41
|
+
* - A tool that throws an Error, and a call naming no tool, answer with
|
|
42
|
+
* reflection guidance (onToolErrorCallback) in place of the plain error,
|
|
43
|
+
* counted per tool name in the run; past the limit, the "retry limit
|
|
44
|
+
* exceeded" guidance (the plugin is built not to throw).
|
|
45
|
+
* - A call that answered resets its tool's count (afterToolCallback),
|
|
46
|
+
* unless the answer is itself reflection guidance.
|
|
47
|
+
* - ADK runs a step's calls one after another; the native loop runs them
|
|
48
|
+
* in parallel. The counts are kept in call order all the same: each
|
|
49
|
+
* call's count waits for the calls before it (StepCorrection).
|
|
50
|
+
*
|
|
51
|
+
* The texts, the argument names and the counting quirks are ADK 2.2.0's
|
|
52
|
+
* (plugins/reflect_retry_*.js), the reflection tool's "attempt 1" included:
|
|
53
|
+
* it reads `retryCount` where the call carries `retry_count`.
|
|
54
|
+
* tests/selfCorrection.test.ts and tests/nativeLoop.test.ts hold the two
|
|
55
|
+
* runtimes to the same stored events.
|
|
56
|
+
*
|
|
57
|
+
* ADK stays out of this file but for the LlmResponse type the step already
|
|
58
|
+
* reads responses as.
|
|
59
|
+
*/
|
|
60
|
+
import { randomUUID } from 'node:crypto';
|
|
61
|
+
import { GEMINI_PROVIDER, PLACEHOLDER_THOUGHT_SIGNATURE } from '../../models/geminiState.js';
|
|
62
|
+
export const DEFAULT_MODEL_ERROR_RETRIES = 2;
|
|
63
|
+
export const DEFAULT_TOOL_ERROR_RETRIES = 3;
|
|
64
|
+
export const ADK_HANDLE_MODEL_ERROR = 'adk_handle_model_error';
|
|
65
|
+
export const REFLECT_AND_RETRY_RESPONSE_TYPE = 'ERROR_HANDLED_BY_REFLECT_AND_RETRY_PLUGIN';
|
|
66
|
+
const RESERVED_TOOL_CALL = 'RESERVED_TOOL_CALL';
|
|
67
|
+
/** The finish reasons the model plugin retries (its onModelErrors default). */
|
|
68
|
+
const MODEL_ERRORS = ['MALFORMED_FUNCTION_CALL'];
|
|
69
|
+
const MODEL_PLUGIN = 'reflect_retry_model_plugin';
|
|
70
|
+
// ── Where ADK declares the reflection tool ──────────────────────────────────
|
|
71
|
+
/** Gemini adapters a caller handed over as a contract adapter or behind the ADK shim: on ADK the shim declares the toolsDict. */
|
|
72
|
+
const SHIMMED_GEMINI = new WeakSet();
|
|
73
|
+
/**
|
|
74
|
+
* Marks `adapter` as one the ADK runtime would call through the ADK shim
|
|
75
|
+
* (a resolver's shim or contract adapter, lib/compileNative.ts), not through
|
|
76
|
+
* ADK's own Gemini. Returns it.
|
|
77
|
+
*/
|
|
78
|
+
export function servedThroughShim(adapter) {
|
|
79
|
+
SHIMMED_GEMINI.add(adapter);
|
|
80
|
+
return adapter;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether the ADK runtime would tell this adapter's model of the reflection
|
|
84
|
+
* tool (ADR 0097). The plugin puts the tool in the toolsDict alone. Every
|
|
85
|
+
* model class the engine hands ADK declares the toolsDict, but ADK's own
|
|
86
|
+
* Gemini (and TracedGemini over it) sends only the request's config, which
|
|
87
|
+
* never holds it. A Gemini adapter stands for ADK's Gemini unless a caller
|
|
88
|
+
* handed it over behind the shim (servedThroughShim).
|
|
89
|
+
*/
|
|
90
|
+
export function declaresReflectionTool(adapter) {
|
|
91
|
+
return !standsForAdkGemini(adapter);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Whether this adapter stands, on the native runtime, for ADK's own Gemini
|
|
95
|
+
* (TracedGemini) on the ADK runtime: a Gemini adapter no caller handed over
|
|
96
|
+
* behind the shim. The step declares no reflection tool to it (ADR 0097) and
|
|
97
|
+
* stores no `turnComplete` on its events, as ADK's Gemini writes none
|
|
98
|
+
* (ADR 0100).
|
|
99
|
+
*/
|
|
100
|
+
export function standsForAdkGemini(adapter) {
|
|
101
|
+
return adapter.provider === GEMINI_PROVIDER && !SHIMMED_GEMINI.has(adapter);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* How self-correction signs the reflection call it stores in place of this
|
|
105
|
+
* adapter's response, or undefined to store it unsigned, as ADK's plugin
|
|
106
|
+
* does. A Gemini adapter's call carries the replaced response's signature;
|
|
107
|
+
* on a Gemini 3 model, whose API rejects an unsigned current-turn call, the
|
|
108
|
+
* placeholder stands in when there was none.
|
|
109
|
+
*/
|
|
110
|
+
export function reflectionSigning(adapter, model) {
|
|
111
|
+
if (adapter.provider !== GEMINI_PROVIDER)
|
|
112
|
+
return undefined;
|
|
113
|
+
return isGemini3(model) ? { placeholder: PLACEHOLDER_THOUGHT_SIGNATURE } : {};
|
|
114
|
+
}
|
|
115
|
+
/** A Gemini 3 model id, bare or under a resource path (`models/…`, `publishers/google/models/…`). */
|
|
116
|
+
function isGemini3(model) {
|
|
117
|
+
if (!model)
|
|
118
|
+
return false;
|
|
119
|
+
return model.slice(model.lastIndexOf('/') + 1).startsWith('gemini-3');
|
|
120
|
+
}
|
|
121
|
+
/** The signature the replaced response carried: its first call's, else its first signed part's. */
|
|
122
|
+
function signatureOf(response) {
|
|
123
|
+
const parts = response.content?.parts ?? [];
|
|
124
|
+
const signed = (p) => typeof p.thoughtSignature === 'string' && p.thoughtSignature.length > 0;
|
|
125
|
+
return (parts.find((p) => p.functionCall && signed(p)) ?? parts.find(signed))?.thoughtSignature;
|
|
126
|
+
}
|
|
127
|
+
// ── Counting, per run ────────────────────────────────────────────────────────
|
|
128
|
+
/** ADK's ScopedFailureTracker: failures per name, within one run (invocation scope). */
|
|
129
|
+
class FailureTracker {
|
|
130
|
+
#counts = new Map();
|
|
131
|
+
increment(scope, name) {
|
|
132
|
+
let counter = this.#counts.get(scope);
|
|
133
|
+
if (!counter) {
|
|
134
|
+
counter = new Map();
|
|
135
|
+
this.#counts.set(scope, counter);
|
|
136
|
+
}
|
|
137
|
+
const next = (counter.get(name) ?? 0) + 1;
|
|
138
|
+
counter.set(name, next);
|
|
139
|
+
return next;
|
|
140
|
+
}
|
|
141
|
+
reset(scope, name) {
|
|
142
|
+
const counter = this.#counts.get(scope);
|
|
143
|
+
if (!counter)
|
|
144
|
+
return;
|
|
145
|
+
counter.delete(name);
|
|
146
|
+
if (counter.size === 0)
|
|
147
|
+
this.#counts.delete(scope);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Self-correction for a run: ADK's two plugins, with their counters. One per
|
|
152
|
+
* turn, as runSyndicateTurn builds one pair of plugins per Runner; the
|
|
153
|
+
* counters are kept per run (invocation id) within it.
|
|
154
|
+
*/
|
|
155
|
+
export class SelfCorrection {
|
|
156
|
+
modelErrors;
|
|
157
|
+
toolErrors;
|
|
158
|
+
#models = new FailureTracker();
|
|
159
|
+
#tools = new FailureTracker();
|
|
160
|
+
constructor(retries = {}) {
|
|
161
|
+
this.modelErrors = retries.model_errors ?? DEFAULT_MODEL_ERROR_RETRIES;
|
|
162
|
+
this.toolErrors = retries.tool_errors ?? DEFAULT_TOOL_ERROR_RETRIES;
|
|
163
|
+
if (this.modelErrors < 0 || this.toolErrors < 0)
|
|
164
|
+
throw new Error('maxRetries must be a non-negative integer.');
|
|
165
|
+
}
|
|
166
|
+
/** The model side for `agentName`'s steps in run `invocationId`; undefined when model retries are off. */
|
|
167
|
+
forModel(agentName, invocationId) {
|
|
168
|
+
if (this.modelErrors <= 0)
|
|
169
|
+
return undefined;
|
|
170
|
+
const max = this.modelErrors;
|
|
171
|
+
const tracker = this.#models;
|
|
172
|
+
const name = agentName || 'default_model';
|
|
173
|
+
const retry = (errorType, errorDetails, finishReason, signature) => {
|
|
174
|
+
const count = tracker.increment(invocationId, name);
|
|
175
|
+
if (count > max) {
|
|
176
|
+
const thrown = `The model has failed consecutively ${max} times and the retry limit has been exceeded.`;
|
|
177
|
+
return { failed: { code: 'UNKNOWN_ERROR', message: `Error in plugin '${MODEL_PLUGIN}' during 'afterModelCallback' callback: Error: ${thrown}` } };
|
|
178
|
+
}
|
|
179
|
+
const args = { response_type: REFLECT_AND_RETRY_RESPONSE_TYPE, error_type: errorType, error_details: errorDetails, finish_reason: finishReason, retry_count: count };
|
|
180
|
+
const response = {
|
|
181
|
+
content: {
|
|
182
|
+
role: 'model',
|
|
183
|
+
parts: [{ functionCall: { id: `${ADK_HANDLE_MODEL_ERROR}_${randomUUID()}`, name: ADK_HANDLE_MODEL_ERROR, args }, ...(signature ? { thoughtSignature: signature } : {}) }],
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
return { response, replaced: true };
|
|
187
|
+
};
|
|
188
|
+
return {
|
|
189
|
+
tools: [reflectionTool(max)],
|
|
190
|
+
afterModel(response, signing) {
|
|
191
|
+
const signature = () => (signing ? (signatureOf(response) ?? signing.placeholder) : undefined);
|
|
192
|
+
if (response.content?.parts?.some((p) => p.functionCall?.name === ADK_HANDLE_MODEL_ERROR)) {
|
|
193
|
+
return retry(RESERVED_TOOL_CALL, `Model attempted to call reserved tool ${ADK_HANDLE_MODEL_ERROR} directly. This tool is reserved for framework use only. Do not call it.`, 'OTHER', signature());
|
|
194
|
+
}
|
|
195
|
+
if (response.finishReason && MODEL_ERRORS.includes(response.finishReason)) {
|
|
196
|
+
return retry(response.errorCode ?? 'MODEL_ERROR', response.errorMessage ?? 'Model error encountered.', response.finishReason, signature());
|
|
197
|
+
}
|
|
198
|
+
tracker.reset(invocationId, name);
|
|
199
|
+
return { response, replaced: false };
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/** The tool side for one step of `count` calls in run `invocationId`; undefined when tool retries are off. */
|
|
204
|
+
forCalls(invocationId, count) {
|
|
205
|
+
if (this.toolErrors <= 0 || count === 0)
|
|
206
|
+
return undefined;
|
|
207
|
+
const max = this.toolErrors;
|
|
208
|
+
const tracker = this.#tools;
|
|
209
|
+
// Call i's count waits for calls 0..i-1: ADK counts in call order.
|
|
210
|
+
const done = [];
|
|
211
|
+
const settled = Array.from({ length: count }, (_, i) => new Promise((resolve) => (done[i] = resolve)));
|
|
212
|
+
const inTurn = async (index, op) => {
|
|
213
|
+
if (index > 0)
|
|
214
|
+
await settled[index - 1];
|
|
215
|
+
try {
|
|
216
|
+
return op();
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
done[index]?.();
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
return {
|
|
223
|
+
release: (index) => done[index]?.(),
|
|
224
|
+
call: (index) => ({
|
|
225
|
+
failed: (toolName, args, error) => inTurn(index, () => {
|
|
226
|
+
if (!(error instanceof Error)) {
|
|
227
|
+
tracker.reset(invocationId, toolName);
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
const retries = tracker.increment(invocationId, toolName);
|
|
231
|
+
return retries <= max ? toolReflection(toolName, args, error, retries, max) : toolRetryExceeded(toolName, args, error, max);
|
|
232
|
+
}),
|
|
233
|
+
answered: (toolName, result) => inTurn(index, () => {
|
|
234
|
+
const reflected = !!result && typeof result === 'object' && result.response_type === REFLECT_AND_RETRY_RESPONSE_TYPE;
|
|
235
|
+
if (!reflected)
|
|
236
|
+
tracker.reset(invocationId, toolName);
|
|
237
|
+
}),
|
|
238
|
+
}),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// ── The reflection tool and the texts ────────────────────────────────────────
|
|
243
|
+
/** The reflection tool as the model plugin declares it: a FunctionTool with no parameters. */
|
|
244
|
+
function reflectionTool(maxRetries) {
|
|
245
|
+
return {
|
|
246
|
+
name: ADK_HANDLE_MODEL_ERROR,
|
|
247
|
+
declaration: () => ({
|
|
248
|
+
name: ADK_HANDLE_MODEL_ERROR,
|
|
249
|
+
description: 'A tool that triggers reflection. Reserved for internal framework use only. Do not call directly.',
|
|
250
|
+
parameters: { type: 'object', properties: {} },
|
|
251
|
+
}),
|
|
252
|
+
// ADK's adkHandleModelError reads `retryCount`; the call carries `retry_count`, so it says attempt 1.
|
|
253
|
+
execute: async (args) => {
|
|
254
|
+
const attempt = args.retryCount ?? 1;
|
|
255
|
+
return {
|
|
256
|
+
reflection_guidance: `
|
|
257
|
+
The call to the model failed.
|
|
258
|
+
|
|
259
|
+
**Reflection Guidance:**
|
|
260
|
+
- This is retry attempt **${String(attempt)}** of **${maxRetries}**
|
|
261
|
+
- Analyze the error and the arguments you provided. Do not repeat the exact same call.
|
|
262
|
+
|
|
263
|
+
Formulate a new plan based on your analysis and try a corrected or different approach.
|
|
264
|
+
`.trim(),
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const errorDetailsOf = (error) => `${error.name || 'Error'}: ${error.message}`;
|
|
270
|
+
function toolReflection(toolName, args, error, retryCount, maxRetries) {
|
|
271
|
+
const reflectionMessage = `
|
|
272
|
+
The call to tool \`${toolName}\` failed.
|
|
273
|
+
|
|
274
|
+
**Error Details:**
|
|
275
|
+
\`\`\`
|
|
276
|
+
${errorDetailsOf(error)}
|
|
277
|
+
\`\`\`
|
|
278
|
+
|
|
279
|
+
**Tool Arguments Used:**
|
|
280
|
+
\`\`\`json
|
|
281
|
+
${JSON.stringify(args ?? {}, null, 2)}
|
|
282
|
+
\`\`\`
|
|
283
|
+
|
|
284
|
+
**Reflection Guidance:**
|
|
285
|
+
This is retry attempt **${retryCount} of ${maxRetries}**. Analyze the error and the arguments you provided. Do not repeat the exact same call. Consider the following before your next attempt:
|
|
286
|
+
|
|
287
|
+
1. **Invalid Parameters**: Does the error suggest that one or more arguments are incorrect, badly formatted, or missing? Review the tool's schema and your arguments.
|
|
288
|
+
2. **State or Preconditions**: Did a previous step fail or not produce the necessary state/resource for this tool to succeed?
|
|
289
|
+
3. **Alternative Approach**: Is this the right tool for the job? Could another tool or a different sequence of steps achieve the goal?
|
|
290
|
+
4. **Simplify the Task**: Can you break the problem down into smaller, simpler steps?
|
|
291
|
+
5. **Wrong Function Name**: Does the error indicates the tool is not found? Please check again and only use available tools.
|
|
292
|
+
|
|
293
|
+
Formulate a new plan based on your analysis and try a corrected or different approach.
|
|
294
|
+
`.trim();
|
|
295
|
+
return {
|
|
296
|
+
response_type: REFLECT_AND_RETRY_RESPONSE_TYPE,
|
|
297
|
+
error_type: error.name || 'Error',
|
|
298
|
+
error_details: error.message,
|
|
299
|
+
retry_count: retryCount,
|
|
300
|
+
reflection_guidance: reflectionMessage,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function toolRetryExceeded(toolName, args, error, maxRetries) {
|
|
304
|
+
const reflectionMessage = `
|
|
305
|
+
The tool \`${toolName}\` has failed consecutively ${maxRetries} times and the retry limit has been exceeded.
|
|
306
|
+
|
|
307
|
+
**Last Error:**
|
|
308
|
+
\`\`\`
|
|
309
|
+
${errorDetailsOf(error)}
|
|
310
|
+
\`\`\`
|
|
311
|
+
|
|
312
|
+
**Last Arguments Used:**
|
|
313
|
+
\`\`\`json
|
|
314
|
+
${JSON.stringify(args ?? {}, null, 2)}
|
|
315
|
+
\`\`\`
|
|
316
|
+
|
|
317
|
+
**Final Instruction:**
|
|
318
|
+
**Do not attempt to use the \`${toolName}\` tool again for this task.** You must now try a different approach. Acknowledge the failure and devise a new strategy, potentially using other available tools or informing the user that the task cannot be completed.
|
|
319
|
+
`.trim();
|
|
320
|
+
return {
|
|
321
|
+
response_type: REFLECT_AND_RETRY_RESPONSE_TYPE,
|
|
322
|
+
error_type: error.name || 'Error',
|
|
323
|
+
error_details: error.message,
|
|
324
|
+
retry_count: maxRetries,
|
|
325
|
+
reflection_guidance: reflectionMessage,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/native/step.ts — one model step of the native loop: build the
|
|
3
|
+
* request, call the adapter under the turn's controls, and record the
|
|
4
|
+
* model's answer as the event ADK would have stored (ADR 0045, ADR 0066).
|
|
5
|
+
*
|
|
6
|
+
* WHY this file exists:
|
|
7
|
+
* On the ADK runtime one step is LlmAgent.runOneStepAsync: build the
|
|
8
|
+
* request, call the model through the shim (lib/models/adkShim.ts), turn
|
|
9
|
+
* each response into an event, and let the Runner store the ones that are
|
|
10
|
+
* not partial. The native loop does the same with no ADK in the path, and
|
|
11
|
+
* a session either runtime wrote must be one the other can continue, so
|
|
12
|
+
* each piece matches:
|
|
13
|
+
*
|
|
14
|
+
* - THE CALL'S CONTROLS (ADR 0053). The native loop is the adapter's
|
|
15
|
+
* caller, so it charges the turn and opens the llm.request span, through
|
|
16
|
+
* the same traceLlmGeneration call the shim makes, with the adapter's
|
|
17
|
+
* provider, the agent's model id and the request. The step budget, the
|
|
18
|
+
* token charge and the span's attributes are therefore the same on both
|
|
19
|
+
* runtimes. A turn that has stopped (cancel, deadline, the step limit)
|
|
20
|
+
* gets no call and no event: ADK checks the run's signal before the call
|
|
21
|
+
* and after each response and returns without an event, and the turn
|
|
22
|
+
* runner reports the stop from the turn's control. So does this step.
|
|
23
|
+
* - THE EVENT. Each response becomes ADK's event for it: created before
|
|
24
|
+
* the call with the run's id, the agent as author and the branch, and
|
|
25
|
+
* merged with the response as the shim maps it (modelResponseToLlmResponse),
|
|
26
|
+
* a fresh id for every response after the first. For a Gemini adapter
|
|
27
|
+
* that stands for ADK's own Gemini (standsForAdkGemini), the event has no
|
|
28
|
+
* turnComplete, since ADK's Gemini writes none (ADR 0100). A tool call with no id
|
|
29
|
+
* gets ADK's `adk-<uuid>`; a call to a long-running tool is listed in
|
|
30
|
+
* longRunningToolIds; a set_model_response call becomes its arguments as
|
|
31
|
+
* JSON text, ending the step (skipSummarization). An answer with no
|
|
32
|
+
* parts, no error and no usage makes no event.
|
|
33
|
+
* - SELF-CORRECTION (ADR 0075). With the caller's `correction`, the
|
|
34
|
+
* reflection tool is one of the step's tools, after the agent's, and
|
|
35
|
+
* each response passes through it first, as ADK's reflect-and-retry
|
|
36
|
+
* model plugin sees it: a retry may stand in its place, or the step may
|
|
37
|
+
* end on the plugin's UNKNOWN_ERROR event (lib/runtime/native/
|
|
38
|
+
* selfCorrection.ts). The request declares the tool only where ADK's
|
|
39
|
+
* model class would (declaresReflectionTool): never to a Gemini model
|
|
40
|
+
* ADK's own Gemini would serve, which sends no toolsDict (ADR 0097).
|
|
41
|
+
* On a Gemini adapter the reflection call stored in a response's place
|
|
42
|
+
* carries its signature, or Gemini 3's placeholder (reflectionSigning,
|
|
43
|
+
* ADR 0103), where ADK stores it unsigned.
|
|
44
|
+
* - A THROWN FAILURE. The contract forbids an adapter to throw, but a
|
|
45
|
+
* leaf that does (an ADK-era model class) is read as ADK reads it. With
|
|
46
|
+
* a `redirect`, a provider-side failure (errorDecision, lib/models/
|
|
47
|
+
* errorResponse.ts) is handed to it as a retryable failed final, so the
|
|
48
|
+
* fallback answers when nothing was produced yet (FallbackLlm). Any
|
|
49
|
+
* other thrown Error ends the step on ADK's error event for it
|
|
50
|
+
* (runAndHandleError): UNKNOWN_ERROR, or the code a JSON error message
|
|
51
|
+
* names, with the message, key-shaped text scrubbed. A throw that is
|
|
52
|
+
* not an Error, or one while the turn is stopping, is rethrown.
|
|
53
|
+
* - STORAGE. A final event is appended through the SessionService, which
|
|
54
|
+
* applies the store's own rules (trimming, state). A partial event is
|
|
55
|
+
* handed to the caller for streaming and stored nowhere.
|
|
56
|
+
*
|
|
57
|
+
* WHAT IT RETURNS: the request sent, the stored event, and the answer parsed
|
|
58
|
+
* into text, thinking (from the partials: a final never holds thinking) and
|
|
59
|
+
* tool calls with the ids as stored, and the tools the request declared.
|
|
60
|
+
* Running those calls, and looping, is lib/runtime/native/agentLoop.ts.
|
|
61
|
+
*/
|
|
62
|
+
import type { FinalModelResponse, ModelAdapter, ModelError, ModelRequest, ToolCallPart } from '../../models/contract.ts';
|
|
63
|
+
import type { MemoryService } from '../memoryService.ts';
|
|
64
|
+
import type { TurnContent, TurnEvent } from '../events.ts';
|
|
65
|
+
import type { Session, SessionService } from '../sessions.ts';
|
|
66
|
+
import type { NativeAgent, WorkflowInstructionScope } from './request.ts';
|
|
67
|
+
import type { ModelCorrection } from './selfCorrection.ts';
|
|
68
|
+
export interface ModelStepOptions {
|
|
69
|
+
agent: NativeAgent;
|
|
70
|
+
/** The session as it stands, the run's user event already appended. Appending updates it. */
|
|
71
|
+
session: Session;
|
|
72
|
+
sessions: SessionService;
|
|
73
|
+
/** The run's id: every event of the run carries it. */
|
|
74
|
+
invocationId: string;
|
|
75
|
+
/** The message that started the run. */
|
|
76
|
+
userContent?: TurnContent;
|
|
77
|
+
branch?: string;
|
|
78
|
+
isolationScope?: string;
|
|
79
|
+
/** The run's root agent, whose globalInstruction applies. Default: the agent. */
|
|
80
|
+
root?: Pick<NativeAgent, 'globalInstruction'>;
|
|
81
|
+
/** The run's memory, already namespaced. */
|
|
82
|
+
memory?: Pick<MemoryService, 'search'>;
|
|
83
|
+
/** The leaf adapter to call. Default: resolveAdapter(agent.model) (lib/models/registry.ts). */
|
|
84
|
+
adapter?: ModelAdapter;
|
|
85
|
+
/** Stream text and thinking deltas as partial events. Default false. */
|
|
86
|
+
stream?: boolean;
|
|
87
|
+
/** The run's signal. Default: the current turn's (lib/runtime/turnControl.ts). */
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
/** Each partial event, as it arrives. Never stored. */
|
|
90
|
+
onPartial?: (event: TurnEvent) => void;
|
|
91
|
+
/**
|
|
92
|
+
* The model id the request is sent under. Default the agent's. A fallback
|
|
93
|
+
* model answers the request built for the agent's own model, under its own
|
|
94
|
+
* id, as ADK's FallbackLlm sends it (ADR 0044).
|
|
95
|
+
*/
|
|
96
|
+
model?: string;
|
|
97
|
+
/** Called on the final event just before it is stored: the loop saves the agent's outputKey here, as ADK does before its Runner appends. */
|
|
98
|
+
beforeAppend?: (event: TurnEvent) => void;
|
|
99
|
+
/** State laid over the session's when the request is built: the run's `temp:` keys (lib/runtime/native/tempState.ts). */
|
|
100
|
+
stateOverlay?: Readonly<Record<string, unknown>>;
|
|
101
|
+
/**
|
|
102
|
+
* Called on each failed final, with whether the adapter had yielded
|
|
103
|
+
* anything before it. True hands the failure back unstored (`redirected`):
|
|
104
|
+
* a fallback model answers the step instead (ADR 0044, ADR 0053).
|
|
105
|
+
*/
|
|
106
|
+
redirect?: (final: FinalModelResponse, produced: boolean) => boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Self-correction's model side (lib/runtime/native/selfCorrection.ts):
|
|
109
|
+
* its reflection tool is declared after the agent's tools, and every
|
|
110
|
+
* response passes through it before it is recorded, as ADK's
|
|
111
|
+
* reflect-and-retry model plugin sees it.
|
|
112
|
+
*/
|
|
113
|
+
correction?: ModelCorrection;
|
|
114
|
+
/** A workflow agent node's run: fills the instruction's workflow placeholders (request.ts, WorkflowInstructionScope). */
|
|
115
|
+
workflowScope?: WorkflowInstructionScope;
|
|
116
|
+
}
|
|
117
|
+
/** Why a step made no call, or stopped answering: the turn's own stop. */
|
|
118
|
+
export interface StepStop {
|
|
119
|
+
code: string;
|
|
120
|
+
message: string;
|
|
121
|
+
}
|
|
122
|
+
export interface ModelStepResult {
|
|
123
|
+
/** The request sent, or that would have been sent when the turn had stopped. */
|
|
124
|
+
request: ModelRequest;
|
|
125
|
+
/** The final event as the store returned it. Absent when the turn stopped or the answer was empty. */
|
|
126
|
+
event?: TurnEvent;
|
|
127
|
+
/** The adapter's final response. */
|
|
128
|
+
response?: FinalModelResponse;
|
|
129
|
+
/** The answer's text, thinking aside. */
|
|
130
|
+
text: string;
|
|
131
|
+
/** The model's reasoning as the partials showed it. Display only. */
|
|
132
|
+
thinking: string;
|
|
133
|
+
/** The calls the model made, with the ids as stored. */
|
|
134
|
+
toolCalls: ToolCallPart[];
|
|
135
|
+
/** The calls among them that wait for a person. */
|
|
136
|
+
longRunningToolIds: string[];
|
|
137
|
+
/** The call failed: the adapter's error. */
|
|
138
|
+
error?: ModelError;
|
|
139
|
+
/** The turn stopped before or during the call: no event was made for it. */
|
|
140
|
+
stopped?: StepStop;
|
|
141
|
+
/** The failure `redirect` took: nothing was stored for it. */
|
|
142
|
+
redirected?: ModelError;
|
|
143
|
+
/** The client-side tools the request declared, and the reflection tool when it was not declared, by name: what runs the answer's calls. */
|
|
144
|
+
tools: Map<string, unknown>;
|
|
145
|
+
}
|
|
146
|
+
export declare function eitherSignal(...candidates: Array<AbortSignal | undefined>): AbortSignal | undefined;
|
|
147
|
+
/** The turn's stop, as the turn runner reports it; a cancel when the signal aborted outside a turn. */
|
|
148
|
+
/** The turn's stop, as a step reports it. */
|
|
149
|
+
export declare function stopOf(): StepStop;
|
|
150
|
+
/**
|
|
151
|
+
* One model step for `agent`. Never throws for a failed call: the error is
|
|
152
|
+
* on the result and on the stored event, as on the ADK runtime, also when
|
|
153
|
+
* the adapter throws an Error, which the contract forbids. Throws when the
|
|
154
|
+
* request cannot be built (as ADK does).
|
|
155
|
+
*/
|
|
156
|
+
export declare function runModelStep(options: ModelStepOptions): Promise<ModelStepResult>;
|