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.
Files changed (281) hide show
  1. package/.env.example +12 -0
  2. package/CHANGELOG.md +825 -0
  3. package/DOCUMENTATION.md +217 -59
  4. package/README.md +42 -1
  5. package/config/agents/examples/harness.yaml +3 -1
  6. package/config/agents/examples/model_zoo.yaml +10 -9
  7. package/config/agents/syndicateSchema.yaml +50 -16
  8. package/config/agents/templates/account_memory.yaml +2 -6
  9. package/config/agents/templates/case_desk.yaml +3 -9
  10. package/config/agents/templates/draft_review.yaml +3 -9
  11. package/config/agents/templates/intake_extractor.yaml +1 -3
  12. package/config/agents/templates/research_brief.yaml +3 -9
  13. package/config/agents/templates/research_desk.yaml +3 -9
  14. package/config/agents/templates/review_panel.yaml +4 -12
  15. package/config/agents/templates/support_triage.yaml +4 -12
  16. package/config/agents/templates/systems_operator.yaml +2 -6
  17. package/db/hardening.sql +7 -1
  18. package/db/migrations/0013_tool_credentials.sql +260 -0
  19. package/dist/lib/a2a/app.d.ts +70 -6
  20. package/dist/lib/a2a/app.js +107 -2
  21. package/dist/lib/a2a/executor.d.ts +20 -3
  22. package/dist/lib/a2a/executor.js +66 -7
  23. package/dist/lib/a2a/remoteAgent.d.ts +24 -9
  24. package/dist/lib/a2a/remoteAgent.js +31 -14
  25. package/dist/lib/compile.d.ts +121 -30
  26. package/dist/lib/compile.js +137 -124
  27. package/dist/lib/compileAdk.d.ts +29 -0
  28. package/dist/lib/compileAdk.js +132 -0
  29. package/dist/lib/compileNative.d.ts +85 -0
  30. package/dist/lib/compileNative.js +222 -0
  31. package/dist/lib/config.d.ts +6 -5
  32. package/dist/lib/config.js +6 -5
  33. package/dist/lib/doctor.js +1 -0
  34. package/dist/lib/index.d.ts +2 -1
  35. package/dist/lib/index.js +2 -1
  36. package/dist/lib/loadSyndicate.d.ts +18 -0
  37. package/dist/lib/memory/erase.d.ts +5 -3
  38. package/dist/lib/memory/erase.js +5 -2
  39. package/dist/lib/memory/namespace.d.ts +8 -1
  40. package/dist/lib/memory/namespace.js +12 -6
  41. package/dist/lib/memory/providers.js +2 -1
  42. package/dist/lib/memory/supabaseMemoryService.d.ts +37 -3
  43. package/dist/lib/memory/supabaseMemoryService.js +42 -2
  44. package/dist/lib/model.d.ts +47 -0
  45. package/dist/lib/model.js +37 -0
  46. package/dist/lib/models/adapterResolver.d.ts +113 -0
  47. package/dist/lib/models/adapterResolver.js +136 -0
  48. package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
  49. package/dist/lib/models/adkGeminiAdapter.js +367 -0
  50. package/dist/lib/models/adkShim.d.ts +111 -0
  51. package/dist/lib/models/adkShim.js +136 -0
  52. package/dist/lib/models/capabilities.d.ts +3 -0
  53. package/dist/lib/models/capabilities.js +20 -13
  54. package/dist/lib/models/chatCompletionsAdapter.d.ts +279 -0
  55. package/dist/lib/models/chatCompletionsAdapter.js +854 -0
  56. package/dist/lib/models/circuitBreaker.d.ts +42 -0
  57. package/dist/lib/models/circuitBreaker.js +70 -0
  58. package/dist/lib/models/claudeAdapter.d.ts +103 -0
  59. package/dist/lib/models/claudeAdapter.js +669 -0
  60. package/dist/lib/models/claudeLlm.d.ts +39 -62
  61. package/dist/lib/models/claudeLlm.js +44 -349
  62. package/dist/lib/models/claudeModels.d.ts +127 -0
  63. package/dist/lib/models/claudeModels.js +237 -0
  64. package/dist/lib/models/contract.d.ts +395 -0
  65. package/dist/lib/models/contract.js +39 -0
  66. package/dist/lib/models/endpoints.js +2 -1
  67. package/dist/lib/models/errorResponse.d.ts +50 -0
  68. package/dist/lib/models/errorResponse.js +48 -0
  69. package/dist/lib/models/fallback.d.ts +17 -10
  70. package/dist/lib/models/fallback.js +53 -42
  71. package/dist/lib/models/fallbackAdapter.d.ts +55 -0
  72. package/dist/lib/models/fallbackAdapter.js +62 -0
  73. package/dist/lib/models/gateway.js +2 -1
  74. package/dist/lib/models/gatewayAdapter.d.ts +51 -0
  75. package/dist/lib/models/gatewayAdapter.js +81 -0
  76. package/dist/lib/models/gatewayLlm.d.ts +12 -33
  77. package/dist/lib/models/gatewayLlm.js +14 -75
  78. package/dist/lib/models/geminiAdapter.d.ts +123 -0
  79. package/dist/lib/models/geminiAdapter.js +831 -0
  80. package/dist/lib/models/geminiState.d.ts +25 -0
  81. package/dist/lib/models/geminiState.js +25 -0
  82. package/dist/lib/models/genaiMapping.d.ts +263 -0
  83. package/dist/lib/models/genaiMapping.js +862 -0
  84. package/dist/lib/models/gptAdapter.d.ts +240 -0
  85. package/dist/lib/models/gptAdapter.js +804 -0
  86. package/dist/lib/models/gptLlm.d.ts +63 -123
  87. package/dist/lib/models/gptLlm.js +88 -602
  88. package/dist/lib/models/grokAdapter.d.ts +86 -0
  89. package/dist/lib/models/grokAdapter.js +142 -0
  90. package/dist/lib/models/grokLlm.d.ts +22 -45
  91. package/dist/lib/models/grokLlm.js +22 -67
  92. package/dist/lib/models/kimiAdapter.d.ts +157 -0
  93. package/dist/lib/models/kimiAdapter.js +203 -0
  94. package/dist/lib/models/kimiLlm.d.ts +15 -107
  95. package/dist/lib/models/kimiLlm.js +17 -153
  96. package/dist/lib/models/ollamaAdapter.d.ts +125 -0
  97. package/dist/lib/models/ollamaAdapter.js +155 -0
  98. package/dist/lib/models/ollamaLlm.d.ts +11 -107
  99. package/dist/lib/models/ollamaLlm.js +13 -151
  100. package/dist/lib/models/openAiCompatibleLlm.d.ts +73 -216
  101. package/dist/lib/models/openAiCompatibleLlm.js +109 -671
  102. package/dist/lib/models/providerState.d.ts +63 -0
  103. package/dist/lib/models/providerState.js +61 -0
  104. package/dist/lib/models/reasoning.d.ts +26 -0
  105. package/dist/lib/models/reasoning.js +59 -0
  106. package/dist/lib/models/registry.d.ts +58 -35
  107. package/dist/lib/models/registry.js +89 -118
  108. package/dist/lib/models/retry.d.ts +2 -1
  109. package/dist/lib/models/retry.js +3 -2
  110. package/dist/lib/models/schemaNormalize.d.ts +98 -0
  111. package/dist/lib/models/schemaNormalize.js +321 -1
  112. package/dist/lib/models/tracedGemini.d.ts +41 -0
  113. package/dist/lib/models/tracedGemini.js +98 -0
  114. package/dist/lib/models/urls.d.ts +11 -0
  115. package/dist/lib/models/urls.js +16 -0
  116. package/dist/lib/net/redirects.d.ts +21 -2
  117. package/dist/lib/net/redirects.js +11 -34
  118. package/dist/lib/observability/audit.d.ts +5 -1
  119. package/dist/lib/observability/lineage.d.ts +14 -0
  120. package/dist/lib/observability/lineage.js +33 -0
  121. package/dist/lib/observability/supabaseSpanExporter.d.ts +10 -4
  122. package/dist/lib/observability/supabaseSpanExporter.js +17 -9
  123. package/dist/lib/observability/tracer.d.ts +26 -8
  124. package/dist/lib/observability/tracer.js +43 -18
  125. package/dist/lib/runtime/adkMemoryBridge.d.ts +46 -0
  126. package/dist/lib/runtime/adkMemoryBridge.js +68 -0
  127. package/dist/lib/runtime/adkSessionBridge.d.ts +78 -0
  128. package/dist/lib/runtime/adkSessionBridge.js +176 -0
  129. package/dist/lib/runtime/credentials.d.ts +59 -0
  130. package/dist/lib/runtime/credentials.js +62 -0
  131. package/dist/lib/runtime/events.d.ts +229 -0
  132. package/dist/lib/runtime/events.js +274 -0
  133. package/dist/lib/runtime/logging.d.ts +32 -0
  134. package/dist/lib/runtime/logging.js +55 -0
  135. package/dist/lib/runtime/memoryService.d.ts +72 -0
  136. package/dist/lib/runtime/memoryService.js +25 -0
  137. package/dist/lib/runtime/native/agentLoop.d.ts +203 -0
  138. package/dist/lib/runtime/native/agentLoop.js +687 -0
  139. package/dist/lib/runtime/native/compaction.d.ts +103 -0
  140. package/dist/lib/runtime/native/compaction.js +191 -0
  141. package/dist/lib/runtime/native/delegate.d.ts +98 -0
  142. package/dist/lib/runtime/native/delegate.js +173 -0
  143. package/dist/lib/runtime/native/history.d.ts +83 -0
  144. package/dist/lib/runtime/native/history.js +312 -0
  145. package/dist/lib/runtime/native/interrupts.d.ts +126 -0
  146. package/dist/lib/runtime/native/interrupts.js +291 -0
  147. package/dist/lib/runtime/native/request.d.ts +215 -0
  148. package/dist/lib/runtime/native/request.js +585 -0
  149. package/dist/lib/runtime/native/selfCorrection.d.ts +106 -0
  150. package/dist/lib/runtime/native/selfCorrection.js +253 -0
  151. package/dist/lib/runtime/native/step.d.ts +148 -0
  152. package/dist/lib/runtime/native/step.js +239 -0
  153. package/dist/lib/runtime/native/taskMode.d.ts +64 -0
  154. package/dist/lib/runtime/native/taskMode.js +126 -0
  155. package/dist/lib/runtime/native/telemetry.d.ts +75 -0
  156. package/dist/lib/runtime/native/telemetry.js +299 -0
  157. package/dist/lib/runtime/native/tempState.d.ts +31 -0
  158. package/dist/lib/runtime/native/tempState.js +56 -0
  159. package/dist/lib/runtime/nativeTurn.d.ts +86 -0
  160. package/dist/lib/runtime/nativeTurn.js +107 -0
  161. package/dist/lib/runtime/questions.d.ts +29 -7
  162. package/dist/lib/runtime/questions.js +47 -32
  163. package/dist/lib/runtime/runtimeFlag.d.ts +30 -0
  164. package/dist/lib/runtime/runtimeFlag.js +50 -0
  165. package/dist/lib/runtime/sessions.d.ts +166 -0
  166. package/dist/lib/runtime/sessions.js +201 -0
  167. package/dist/lib/runtime/syndicateTurn.d.ts +41 -5
  168. package/dist/lib/runtime/syndicateTurn.js +202 -32
  169. package/dist/lib/session/supabaseSessionService.d.ts +64 -17
  170. package/dist/lib/session/supabaseSessionService.js +148 -105
  171. package/dist/lib/session/transcript.d.ts +68 -22
  172. package/dist/lib/session/transcript.js +102 -28
  173. package/dist/lib/skills.js +33 -7
  174. package/dist/lib/storage/postgres/credentialStore.d.ts +20 -0
  175. package/dist/lib/storage/postgres/credentialStore.js +82 -0
  176. package/dist/lib/storage/postgres/index.d.ts +12 -0
  177. package/dist/lib/storage/postgres/index.js +6 -1
  178. package/dist/lib/storage/postgres/sessionService.d.ts +43 -15
  179. package/dist/lib/storage/postgres/sessionService.js +128 -66
  180. package/dist/lib/syndicateSchema.d.ts +47 -0
  181. package/dist/lib/syndicateSchema.js +72 -3
  182. package/dist/lib/toolRegistry.d.ts +15 -2
  183. package/dist/lib/toolRegistry.js +33 -17
  184. package/dist/lib/tools/adkTool.d.ts +81 -0
  185. package/dist/lib/tools/adkTool.js +268 -0
  186. package/dist/lib/tools/auth.d.ts +118 -0
  187. package/dist/lib/tools/auth.js +89 -0
  188. package/dist/lib/tools/collectionsSearchTool.d.ts +7 -6
  189. package/dist/lib/tools/collectionsSearchTool.js +11 -26
  190. package/dist/lib/tools/credentialCipher.d.ts +58 -0
  191. package/dist/lib/tools/credentialCipher.js +116 -0
  192. package/dist/lib/tools/credentialStore.d.ts +77 -0
  193. package/dist/lib/tools/credentialStore.js +246 -0
  194. package/dist/lib/tools/examples.d.ts +43 -0
  195. package/dist/lib/tools/examples.js +62 -0
  196. package/dist/lib/tools/generateImageTool.d.ts +15 -6
  197. package/dist/lib/tools/generateImageTool.js +19 -29
  198. package/dist/lib/tools/inspectImageTool.d.ts +9 -6
  199. package/dist/lib/tools/inspectImageTool.js +13 -17
  200. package/dist/lib/tools/mcpToolFactory.d.ts +42 -1
  201. package/dist/lib/tools/mcpToolFactory.js +46 -47
  202. package/dist/lib/tools/memoryTools.d.ts +61 -0
  203. package/dist/lib/tools/memoryTools.js +119 -0
  204. package/dist/lib/tools/nativeTools.d.ts +38 -0
  205. package/dist/lib/tools/nativeTools.js +43 -0
  206. package/dist/lib/tools/oauthConsent.d.ts +181 -0
  207. package/dist/lib/tools/oauthConsent.js +330 -0
  208. package/dist/lib/tools/openapi/call.d.ts +108 -0
  209. package/dist/lib/tools/openapi/call.js +295 -0
  210. package/dist/lib/tools/openapi/parse.d.ts +147 -0
  211. package/dist/lib/tools/openapi/parse.js +570 -0
  212. package/dist/lib/tools/openapiTools.d.ts +25 -17
  213. package/dist/lib/tools/openapiTools.js +124 -121
  214. package/dist/lib/tools/scienceTools.d.ts +14 -14
  215. package/dist/lib/tools/skillToolset.d.ts +58 -87
  216. package/dist/lib/tools/skillToolset.js +61 -142
  217. package/dist/lib/tools/skills/env.d.ts +58 -0
  218. package/dist/lib/tools/skills/env.js +165 -0
  219. package/dist/lib/tools/skills/executor.d.ts +114 -0
  220. package/dist/lib/tools/skills/executor.js +331 -0
  221. package/dist/lib/tools/skills/frontmatter.d.ts +79 -0
  222. package/dist/lib/tools/skills/frontmatter.js +215 -0
  223. package/dist/lib/tools/skills/loader.d.ts +91 -0
  224. package/dist/lib/tools/skills/loader.js +257 -0
  225. package/dist/lib/tools/skills/tools.d.ts +187 -0
  226. package/dist/lib/tools/skills/tools.js +386 -0
  227. package/dist/lib/tools/taskTools.d.ts +15 -15
  228. package/dist/lib/tools/tool.d.ts +354 -0
  229. package/dist/lib/tools/tool.js +304 -0
  230. package/dist/lib/tools/toolContract.d.ts +89 -33
  231. package/dist/lib/tools/toolContract.js +104 -82
  232. package/dist/lib/tools/urlContextTool.d.ts +3 -0
  233. package/dist/lib/tools/urlContextTool.js +5 -1
  234. package/dist/lib/tools/webExtractTool.d.ts +2 -2
  235. package/dist/lib/tools/webExtractTool.js +2 -1
  236. package/dist/lib/tools/webSearchTool.d.ts +6 -9
  237. package/dist/lib/tools/webSearchTool.js +14 -59
  238. package/dist/lib/tools/wikiTools.d.ts +19 -19
  239. package/dist/lib/tools/wikiTools.js +13 -9
  240. package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
  241. package/dist/lib/tools/xApiSearchTool.js +2 -1
  242. package/dist/lib/tools/xSearchTool.d.ts +7 -9
  243. package/dist/lib/tools/xSearchTool.js +11 -62
  244. package/dist/lib/tools/xaiSearchParams.d.ts +41 -0
  245. package/dist/lib/tools/xaiSearchParams.js +126 -0
  246. package/dist/lib/wiki/agentRun.d.ts +12 -0
  247. package/dist/lib/wiki/agentRun.js +72 -34
  248. package/dist/lib/wiki/entities.d.ts +12 -0
  249. package/dist/lib/wiki/entities.js +45 -3
  250. package/dist/lib/workflow/agentNode.d.ts +136 -0
  251. package/dist/lib/workflow/agentNode.js +274 -0
  252. package/dist/lib/workflow/graph.d.ts +177 -0
  253. package/dist/lib/workflow/graph.js +458 -0
  254. package/dist/lib/workflow/nodeEvents.d.ts +50 -0
  255. package/dist/lib/workflow/nodeEvents.js +101 -0
  256. package/dist/lib/workflow/pause.d.ts +122 -0
  257. package/dist/lib/workflow/pause.js +180 -0
  258. package/dist/lib/workflow/resume.d.ts +165 -0
  259. package/dist/lib/workflow/resume.js +440 -0
  260. package/dist/lib/workflow/route.d.ts +58 -0
  261. package/dist/lib/workflow/route.js +69 -0
  262. package/dist/lib/workflow/scheduler.d.ts +415 -0
  263. package/dist/lib/workflow/scheduler.js +743 -0
  264. package/dist/lib/workflow/toolNode.d.ts +127 -0
  265. package/dist/lib/workflow/toolNode.js +236 -0
  266. package/dist/lib/workflow/turn.d.ts +118 -0
  267. package/dist/lib/workflow/turn.js +216 -0
  268. package/dist/lib/workflowConfig.d.ts +3 -2
  269. package/dist/lib/workflowConfig.js +3 -12
  270. package/dist/scripts/a2a_server.js +4 -3
  271. package/dist/scripts/assistant_worker.d.ts +2 -1
  272. package/dist/scripts/assistant_worker.js +9 -4
  273. package/dist/scripts/syndicate_chat.js +19 -10
  274. package/package.json +4 -1
  275. package/skills/briefs/melchizedek-author.md +3 -2
  276. package/skills/briefs/melchizedek-models.md +13 -9
  277. package/skills/briefs/melchizedek.md +3 -3
  278. package/skills/melchizedek/SKILL.md +2 -1
  279. package/skills/melchizedek-author/SKILL.md +2 -1
  280. package/skills/melchizedek-author/assets/minimal.yaml +2 -0
  281. package/skills/melchizedek-models/SKILL.md +23 -6
@@ -0,0 +1,585 @@
1
+ /**
2
+ * lib/runtime/native/request.ts — one model request of the native loop,
3
+ * built from an agent and its session (ADR 0045, ADR 0066).
4
+ *
5
+ * WHY this file exists:
6
+ * The native runtime calls a ModelAdapter (lib/models/contract.ts) with a
7
+ * ModelRequest it builds itself, with no LlmRequest in between. A session
8
+ * moves between the runtimes and an agent must behave the same on either,
9
+ * so the request is the one the ADK runtime hands the same adapter for
10
+ * the same agent and session: what ADK's LlmAgent request processors and
11
+ * tools build, read through the shim's mapping (llmRequestToModelRequest,
12
+ * lib/models/genaiMapping.ts). tests/nativeStep.test.ts asserts that on
13
+ * whole syndicates.
14
+ *
15
+ * THE REQUEST, in the order ADK builds it:
16
+ * 1. The agent's generateContentConfig, and its output schema when it has
17
+ * no tools (or the model takes a schema beside tools: Gemini 2 and
18
+ * later on Vertex AI).
19
+ * 2. The system prompt, each piece joined to the last by a blank line:
20
+ * - the identity lines ("You are an agent. Your internal name is …"),
21
+ * unless the agent may transfer to no one (an output schema rules
22
+ * transfer out);
23
+ * - the root agent's globalInstruction, then the agent's instruction,
24
+ * each with `{state_key}` placeholders filled from session state,
25
+ * and, in a workflow node's run, `{input.field}` and
26
+ * `<input.field from Node>` filled from its workflow scope;
27
+ * - with an output schema beside tools on a model that cannot take
28
+ * both, the line asking for set_model_response;
29
+ * - then, at each tool's place in the agent's list, the text its
30
+ * `instruction(ctx)` writes: few-shot examples, preload_memory, an
31
+ * own Tool's note (ADR 0059, ADR 0062). The skills index is part of
32
+ * the instruction itself (lib/compile.ts appends it).
33
+ * A Tool's `contents` hook then adds to the history, after it is
34
+ * projected (load_skill_resource's binary file, ADR 0083).
35
+ * 3. The history: the session's events projected by includeContents
36
+ * (lib/runtime/native/history.ts), with Gemini code execution's parts
37
+ * as text when the agent runs code.
38
+ * 4. The tools, in the agent's order, a toolset expanded to its tools:
39
+ * each client-side tool's declaration (contractToolDeclaration), at
40
+ * most one per name, the later one winning; each server-side tool
41
+ * where the ADK runtime sends it (web_search everywhere, url_context
42
+ * and google_search on Gemini, x_search and collections_search on
43
+ * xAI); `code_execution` first among Gemini's own tools; and the
44
+ * set_model_response tool when (2) asked for it, then the caller's
45
+ * `extraTools` (self-correction's reflection tool, as ADK's plugin adds
46
+ * it to the toolsDict last). In `mode: task`, finish_task takes
47
+ * set_model_response's place and the output schema is never the
48
+ * response schema (lib/runtime/native/taskMode.ts).
49
+ * 5. Tool choice, the output schema or JSON mode, reasoning and sampling,
50
+ * read from the config by the mapping's own readers.
51
+ *
52
+ * WHAT IT DOES NOT DO (later tickets): resume an approval or an input
53
+ * request (ADK's confirmation and input processors run tools before the
54
+ * request; WS2-7), add transfer_to_agent
55
+ * (compiled syndicates never set subAgents; they delegate through subagent tools, delegate.ts),
56
+ * artifacts in an
57
+ * instruction (no runtime has an artifact service), and an ADK tool's own
58
+ * processLlmRequest side effects beyond its declaration (an own Tool says
59
+ * what it writes through `instruction`).
60
+ *
61
+ * ADK STAYS OUT OF THIS FILE'S OWN LOGIC: it reads tools by marker and by
62
+ * the own-tool symbols (lib/tools/tool.ts), and only lib/models/
63
+ * genaiMapping.ts, which stored history needs anyway (ADR 0048 item 8),
64
+ * names @google/*. An ADK tool or toolset an agent still carries (an
65
+ * AgentTool, an MCP or OpenAPI tool) is read through its declaration and
66
+ * `getTools`, by shape, as is the engine's own skills toolset.
67
+ */
68
+ import { contentsToMessages, reasoningOf, samplingOf, systemText, toolChoiceOf } from '../../models/genaiMapping.js';
69
+ import { providerForModel } from '../../models/providerMap.js';
70
+ import { contractToolDeclaration, nativeToolOf, toContractJsonSchema } from '../../models/schemaNormalize.js';
71
+ import { createToolContext, instructionToolOf, isTool, toolOf } from '../../tools/tool.js';
72
+ import { convertCodeExecutionParts, projectHistory } from './history.js';
73
+ import { finishTaskTool } from './taskMode.js';
74
+ import { withStateOverlay } from './tempState.js';
75
+ // ── set_model_response (ADK's output schema beside tools) ────────────────────
76
+ /** The tool ADK adds when an agent has an output schema and tools a model cannot take together. */
77
+ export const SET_MODEL_RESPONSE = 'set_model_response';
78
+ const SET_MODEL_RESPONSE_DESCRIPTION = 'Call this tool to submit your final response conforming to the output schema. Use this tool only when you have collected all the information and are ready to return the final answer.';
79
+ const SET_MODEL_RESPONSE_INSTRUCTION = 'To output the final result, you must call the "set_model_response" function with the appropriate values. Do not output anything else.';
80
+ /** set_model_response as an own Tool: its answer is the arguments, as JSON text, and it ends the step. */
81
+ export function setModelResponseTool(outputSchema) {
82
+ return {
83
+ name: SET_MODEL_RESPONSE,
84
+ declaration: () => ({
85
+ name: SET_MODEL_RESPONSE,
86
+ description: SET_MODEL_RESPONSE_DESCRIPTION,
87
+ parameters: toContractJsonSchema(outputSchema),
88
+ }),
89
+ execute: async (args, ctx) => {
90
+ ctx.actions.skipSummarization = true;
91
+ return JSON.stringify(args);
92
+ },
93
+ };
94
+ }
95
+ // ── Model names (ADK's utils/model_name.js and output_schema_utils.js) ───────
96
+ /** A Vertex AI resource name's model id, else the id itself. Split, never a backtracking pattern. */
97
+ function modelName(model) {
98
+ const parts = model.split('/');
99
+ const isResource = parts.length >= 8 &&
100
+ parts[0] === 'projects' &&
101
+ parts[2] === 'locations' &&
102
+ parts[4] === 'publishers' &&
103
+ parts[6] === 'models' &&
104
+ [1, 3, 5].every((i) => (parts[i] ?? '') !== '');
105
+ if (!isResource)
106
+ return model;
107
+ const rest = parts.slice(7).join('/');
108
+ return rest === '' ? model : rest;
109
+ }
110
+ function isGeminiModel(model) {
111
+ return modelName(model).startsWith('gemini-');
112
+ }
113
+ function isGemini1Model(model) {
114
+ return modelName(model).startsWith('gemini-1');
115
+ }
116
+ function isGemini2OrAbove(model) {
117
+ const name = modelName(model);
118
+ if (!name.startsWith('gemini-'))
119
+ return false;
120
+ const version = name.slice('gemini-'.length).split('-', 1)[0] ?? '';
121
+ if (!/^\d+(\.\d+)*$/.test(version))
122
+ return false;
123
+ return Number.parseInt(version, 10) >= 2;
124
+ }
125
+ function envFlag(name) {
126
+ return ['true', '1'].includes((process.env[name] || '').toLowerCase());
127
+ }
128
+ /** ADK's enterprise switch: GOOGLE_GENAI_USE_ENTERPRISE, else the deprecated GOOGLE_GENAI_USE_VERTEXAI. */
129
+ function vertexAi() {
130
+ if (process.env.GOOGLE_GENAI_USE_ENTERPRISE !== undefined)
131
+ return envFlag('GOOGLE_GENAI_USE_ENTERPRISE');
132
+ return envFlag('GOOGLE_GENAI_USE_VERTEXAI');
133
+ }
134
+ /** Whether the model takes an output schema beside tools in one request (ADK: Vertex AI, Gemini 2 and later). */
135
+ export function outputSchemaWithTools(model) {
136
+ return vertexAi() && isGemini2OrAbove(model);
137
+ }
138
+ // ── Session state in an instruction (ADK's injectSessionState) ───────────────
139
+ const STATE_PREFIXES = ['app:', 'user:', 'temp:'];
140
+ const ARTIFACT_PREFIX = 'artifact.';
141
+ function isIdentifier(s) {
142
+ return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(s);
143
+ }
144
+ function isStateName(name) {
145
+ const parts = name.split(':');
146
+ if (parts.length === 1)
147
+ return isIdentifier(name);
148
+ if (parts.length !== 2)
149
+ return false;
150
+ return STATE_PREFIXES.includes(`${parts[0]}:`) && isIdentifier(parts[1]);
151
+ }
152
+ /**
153
+ * Every `{…}` placeholder in a template, as ADK's `/\{+[^{}]*}+/g` finds
154
+ * them, by one linear scan (the regular expression backtracks on a long run
155
+ * of braces): a run of `{`, then no brace, then a run of `}`.
156
+ */
157
+ function placeholders(template) {
158
+ const found = [];
159
+ let i = 0;
160
+ while (i < template.length) {
161
+ const open = template.indexOf('{', i);
162
+ if (open < 0)
163
+ break;
164
+ let j = open;
165
+ while (template[j] === '{')
166
+ j++;
167
+ let k = j;
168
+ while (k < template.length && template[k] !== '{' && template[k] !== '}')
169
+ k++;
170
+ if (template[k] !== '}') {
171
+ i = k;
172
+ continue;
173
+ }
174
+ let end = k;
175
+ while (template[end] === '}')
176
+ end++;
177
+ found.push({ raw: template.slice(open, end), index: open });
178
+ i = end;
179
+ }
180
+ return found;
181
+ }
182
+ const isWordChar = (c) => c !== undefined && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_');
183
+ const isIdentStart = (c) => c !== undefined && c !== '' && isWordChar(c) && !(c >= '0' && c <= '9');
184
+ const isSpace = (c) => c !== undefined && c !== '' && /\s/.test(c);
185
+ /** ADK's WORKFLOW_FIELD_KEY, `^[A-Za-z_]\w*\.[A-Za-z_]\w*$`, without a pattern: two identifiers joined by one dot. */
186
+ function isWorkflowFieldKey(key) {
187
+ const dot = key.indexOf('.');
188
+ return dot > 0 && isIdentifier(key.slice(0, dot)) && isIdentifier(key.slice(dot + 1));
189
+ }
190
+ /** The identifier `[A-Za-z_]\w*` starting at `i`, and where it ends; undefined when none starts there. */
191
+ function identAt(s, i) {
192
+ if (!isIdentStart(s[i]))
193
+ return undefined;
194
+ let end = i + 1;
195
+ while (isWordChar(s[end]))
196
+ end++;
197
+ return { name: s.slice(i, end), end };
198
+ }
199
+ function skipSpaces(s, i) {
200
+ while (isSpace(s[i]))
201
+ i++;
202
+ return i;
203
+ }
204
+ /**
205
+ * Every `<x.field from Node>` placeholder, as ADK's SOURCE_NODE_PLACEHOLDER,
206
+ * `/<\s*[A-Za-z_]\w*\.([A-Za-z_]\w*)\s+from\s+([A-Za-z_]\w*)\s*>/g`, finds
207
+ * them. Each token of that pattern is determined by the next character, so
208
+ * a hand parser takes the same matches; an attempt from a `<` cannot pass
209
+ * the next `<`, so the scan is linear.
210
+ */
211
+ function sourcePlaceholders(template) {
212
+ const found = [];
213
+ let open = template.indexOf('<');
214
+ while (open >= 0) {
215
+ const match = sourcePlaceholderAt(template, open);
216
+ if (match)
217
+ found.push(match);
218
+ open = template.indexOf('<', match ? match.index + match.raw.length : open + 1);
219
+ }
220
+ return found;
221
+ }
222
+ function sourcePlaceholderAt(s, open) {
223
+ const head = identAt(s, skipSpaces(s, open + 1));
224
+ if (!head || s[head.end] !== '.')
225
+ return undefined;
226
+ const field = identAt(s, head.end + 1);
227
+ if (!field || !isSpace(s[field.end]))
228
+ return undefined;
229
+ const from = skipSpaces(s, field.end);
230
+ if (s.slice(from, from + 4) !== 'from' || !isSpace(s[from + 4]))
231
+ return undefined;
232
+ const node = identAt(s, skipSpaces(s, from + 4));
233
+ if (!node)
234
+ return undefined;
235
+ const close = skipSpaces(s, node.end);
236
+ if (s[close] !== '>')
237
+ return undefined;
238
+ return { raw: s.slice(open, close + 1), index: open, field: field.name, node: node.name };
239
+ }
240
+ /** ADK's resolveSourceNode: the field of the named node's object output, else the placeholder as written. */
241
+ function resolveSourceNode(raw, field, node, scope) {
242
+ const out = scope.outputsByNode[node];
243
+ if (out && typeof out === 'object' && field in out)
244
+ return formatValue(out[field]);
245
+ return raw;
246
+ }
247
+ /**
248
+ * ADK's collectPredecessorOutputs: the output every event of the invocation
249
+ * carries, keyed by the last segment of its node path without the run
250
+ * suffix (`Graph.Fan.Agent@2` is `Agent`), the later event winning.
251
+ */
252
+ export function predecessorOutputs(events, invocationId) {
253
+ const outputs = {};
254
+ for (const event of events) {
255
+ if (event.invocationId !== invocationId || event.output === undefined)
256
+ continue;
257
+ const path = event.nodeInfo?.path;
258
+ if (!path)
259
+ continue;
260
+ const leaf = path.slice(path.lastIndexOf('.') + 1);
261
+ const at = leaf.indexOf('@');
262
+ outputs[at >= 0 ? leaf.slice(0, at) : leaf] = event.output;
263
+ }
264
+ return outputs;
265
+ }
266
+ function stripBraces(raw) {
267
+ let start = 0;
268
+ let end = raw.length;
269
+ while (start < end && raw[start] === '{')
270
+ start++;
271
+ while (end > start && raw[end - 1] === '}')
272
+ end--;
273
+ return raw.slice(start, end).trim();
274
+ }
275
+ function formatValue(value) {
276
+ if (typeof value === 'string')
277
+ return value;
278
+ if (typeof value === 'object' && value !== null) {
279
+ try {
280
+ const json = JSON.stringify(value);
281
+ if (json !== undefined)
282
+ return json;
283
+ }
284
+ catch (e) {
285
+ throw new Error(`Failed to serialize value for instruction template: ${e instanceof Error ? e.message : String(e)}`);
286
+ }
287
+ }
288
+ return String(value);
289
+ }
290
+ /**
291
+ * `template` with each `{key}` naming a state key replaced by the value in
292
+ * `state` (a string as it is, anything else as JSON). `{key?}` is optional
293
+ * and becomes empty when the key is absent; a required key that is absent
294
+ * fails, as on the ADK runtime. A placeholder that names no state key
295
+ * (`{ "a": 1 }` in an example) stays as it is. `{artifact.x}` fails: no
296
+ * runtime of this engine has an artifact service. Own keys only: a key such
297
+ * as `constructor` is absent unless the state holds it.
298
+ *
299
+ * With a workflow `scope` (a workflow agent node's run), ADK 2.2's two
300
+ * workflow placeholders are filled too, as its injectSessionState fills
301
+ * them: `{x.field}` (any identifier before the dot) from the node's input
302
+ * when it is an object holding `field`, `''` when optional and absent, else
303
+ * left as written (the key's first spelling); and `<x.field from Node>`
304
+ * from that node's stored object output, else left as written.
305
+ */
306
+ export function injectSessionState(template, state, scope) {
307
+ const sources = scope ? sourcePlaceholders(template).map((m) => ({ raw: m.raw, index: m.index, text: resolveSourceNode(m.raw, m.field, m.node, scope) })) : [];
308
+ const matches = placeholders(template);
309
+ if (matches.length === 0 && sources.length === 0)
310
+ return template;
311
+ const parsed = matches.map((m) => {
312
+ let key = stripBraces(m.raw);
313
+ const optional = key.endsWith('?');
314
+ if (optional)
315
+ key = key.slice(0, -1);
316
+ return { ...m, key, optional, valid: key.startsWith(ARTIFACT_PREFIX) || isStateName(key) || (!!scope && isWorkflowFieldKey(key)) };
317
+ });
318
+ const unique = new Map();
319
+ for (const p of parsed) {
320
+ if (!p.valid)
321
+ continue;
322
+ const seen = unique.get(p.key);
323
+ if (seen)
324
+ seen.required ||= !p.optional;
325
+ else
326
+ unique.set(p.key, { required: !p.optional, raw: p.raw });
327
+ }
328
+ const values = new Map();
329
+ for (const [key, { required, raw }] of unique)
330
+ values.set(key, resolveKey(key, required, raw, state, scope));
331
+ // ADK's merge: both kinds in template order, each replaced in turn.
332
+ const all = [...parsed.map((p) => ({ raw: p.raw, index: p.index, text: p.valid ? values.get(p.key) : p.raw })), ...sources].sort((a, b) => a.index - b.index);
333
+ let out = '';
334
+ let last = 0;
335
+ for (const p of all) {
336
+ out += template.slice(last, p.index) + p.text;
337
+ last = p.index + p.raw.length;
338
+ }
339
+ return out + template.slice(last);
340
+ }
341
+ /** ADK's resolveKey for one placeholder key: an artifact (refused), a state key, or a workflow field. */
342
+ function resolveKey(key, required, raw, state, scope) {
343
+ if (key.startsWith(ARTIFACT_PREFIX))
344
+ throw new Error('Artifact service is not initialized.');
345
+ if (isStateName(key)) {
346
+ if (Object.hasOwn(state, key))
347
+ return formatValue(state[key]);
348
+ if (!required)
349
+ return '';
350
+ throw new Error(`Context variable not found: \`${key}\`.`);
351
+ }
352
+ if (scope && isWorkflowFieldKey(key)) {
353
+ const field = key.slice(key.indexOf('.') + 1);
354
+ const input = scope.input;
355
+ if (input && typeof input === 'object' && field in input)
356
+ return formatValue(input[field]);
357
+ if (!required)
358
+ return '';
359
+ }
360
+ return raw;
361
+ }
362
+ function isObject(value) {
363
+ return !!value && typeof value === 'object' && !Array.isArray(value);
364
+ }
365
+ /** ADK's appendInstructions: the texts joined by a blank line, after a blank line when there is text already. */
366
+ function appendInstructions(system, texts) {
367
+ const added = texts.join('\n\n');
368
+ return system ? `${system}\n\n${added}` : added;
369
+ }
370
+ async function resolveInstruction(instruction, ctx, scope) {
371
+ if (typeof instruction === 'function')
372
+ return instruction(ctx);
373
+ return injectSessionState(instruction ?? '', ctx.state, scope);
374
+ }
375
+ /** A toolset (the skills harness, an MCP toolset): something that yields tools, and is not one. */
376
+ export function isToolset(value) {
377
+ if (!isObject(value))
378
+ return false;
379
+ if (typeof value.getTools !== 'function')
380
+ return false;
381
+ return !('runAsync' in value) && !isTool(value) && typeof value._getDeclaration !== 'function';
382
+ }
383
+ /**
384
+ * `configTools`: how many entries Gemini's own tool list holds so far (its
385
+ * native tools, and one function-declarations entry per declared tool),
386
+ * which Gemini 1's search refuses to share.
387
+ */
388
+ function placementOf(native, model, configTools) {
389
+ const provider = providerForModel(model);
390
+ switch (native) {
391
+ case 'web_search':
392
+ return provider === 'gemini' ? { in: 'config', as: 'web_search' } : { in: 'dict' };
393
+ case 'x_search':
394
+ case 'collections_search':
395
+ return provider === 'xai' ? { in: 'dict' } : { in: 'none' };
396
+ case 'url_context':
397
+ return provider === 'gemini' ? { in: 'config', as: 'url_context' } : { in: 'none' };
398
+ case 'google_search':
399
+ // ADK's own GoogleSearchTool: Gemini only, and alone on Gemini 1.
400
+ if (isGemini1Model(model)) {
401
+ if (configTools > 0)
402
+ throw new Error('Google search tool can not be used with other tools in Gemini 1.x.');
403
+ return { in: 'config', as: 'web_search' };
404
+ }
405
+ if (isGeminiModel(model))
406
+ return { in: 'config', as: 'web_search' };
407
+ throw new Error(`Google search tool is not supported for model ${model}`);
408
+ case 'code_execution':
409
+ // The agent's code_execution: gemini, never a listed tool.
410
+ return { in: 'none' };
411
+ }
412
+ }
413
+ /**
414
+ * The ModelRequest the native loop sends for `agent` now, with the
415
+ * client-side tools it declares. Throws where the ADK runtime throws
416
+ * building the same request: a required state key that is absent, a
417
+ * Gemini-only tool on another model, a config field LlmAgent refuses.
418
+ */
419
+ export async function buildModelRequest(agent, ctx) {
420
+ const model = agent.model;
421
+ const cfg = { ...(agent.generateContentConfig ?? {}) };
422
+ // LlmAgent's own refusals, so a config that cannot run under ADK cannot run here.
423
+ if (cfg.tools)
424
+ throw new Error('All tools must be set via LlmAgent.tools.');
425
+ if (cfg.systemInstruction)
426
+ throw new Error('System instruction must be set via LlmAgent.instruction.');
427
+ if (cfg.responseSchema)
428
+ throw new Error('Response schema must be set via LlmAgent.output_schema.');
429
+ const listed = agent.tools ?? [];
430
+ const taskMode = agent.mode === 'task';
431
+ const schemaWithTools = !!agent.outputSchema && listed.length > 0 && !outputSchemaWithTools(model);
432
+ // 1. Basic: the config, and the output schema where the model takes it (never in task mode: finish_task carries it).
433
+ if (agent.outputSchema && !schemaWithTools && !taskMode) {
434
+ cfg.responseSchema = agent.outputSchema;
435
+ cfg.responseMimeType = 'application/json';
436
+ }
437
+ const state = withStateOverlay(ctx.session.state, ctx.stateOverlay);
438
+ const instructionCtx = {
439
+ agentName: agent.name,
440
+ invocationId: ctx.invocationId,
441
+ state,
442
+ ...(ctx.userContent ? { userContent: ctx.userContent } : {}),
443
+ };
444
+ // 2. Identity, then the root's global instruction, then the agent's own.
445
+ let system;
446
+ const transferDisabled = !!agent.outputSchema || (agent.disallowTransferToParent === true && agent.disallowTransferToPeers === true);
447
+ if (!transferDisabled) {
448
+ const identity = [`You are an agent. Your internal name is "${agent.name}".`];
449
+ if (agent.description)
450
+ identity.push(`The description about you is "${agent.description}"`);
451
+ system = appendInstructions(system, identity);
452
+ }
453
+ const globalInstruction = (ctx.root ?? agent).globalInstruction;
454
+ if (globalInstruction)
455
+ system = appendInstructions(system, [await resolveInstruction(globalInstruction, instructionCtx, ctx.workflowScope)]);
456
+ if (agent.instruction)
457
+ system = appendInstructions(system, [await resolveInstruction(agent.instruction, instructionCtx, ctx.workflowScope)]);
458
+ if (schemaWithTools)
459
+ system = appendInstructions(system, [SET_MODEL_RESPONSE_INSTRUCTION]);
460
+ // 3. The history, and Gemini code execution's parts in it.
461
+ const contents = projectHistory(ctx.session.events, {
462
+ agentName: agent.name,
463
+ includeContents: agent.includeContents ?? 'default',
464
+ branch: ctx.branch,
465
+ isolationScope: ctx.isolationScope,
466
+ });
467
+ const configNatives = [];
468
+ if (agent.codeExecution === 'gemini') {
469
+ if (!isGemini2OrAbove(model))
470
+ throw new Error(`Gemini code execution tool is not supported for model ${model}`);
471
+ configNatives.push('code_execution');
472
+ for (const content of contents)
473
+ convertCodeExecutionParts(content);
474
+ }
475
+ // 4. The tools, in the agent's order.
476
+ const toolContext = createToolContext({
477
+ invocationId: ctx.invocationId,
478
+ agentName: agent.name,
479
+ userId: ctx.session.userId,
480
+ appName: ctx.session.appName,
481
+ sessionId: ctx.session.id,
482
+ state,
483
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
484
+ ...(ctx.userContent ? { userContent: ctx.userContent } : {}),
485
+ ...(ctx.memory ? { memory: ctx.memory } : {}),
486
+ });
487
+ // What a toolset reads to list its tools (ADK's ReadonlyContext, by shape).
488
+ const toolsetContext = {
489
+ agentName: agent.name,
490
+ invocationId: ctx.invocationId,
491
+ state: { get: (key) => state[key], has: (key) => Object.hasOwn(state, key) },
492
+ };
493
+ const all = [...listed];
494
+ // Task mode (lib/runtime/native/taskMode.ts): finish_task in set_model_response's place. ADK's
495
+ // instruction processor still writes the set_model_response line above; LlmAgent adds no such tool.
496
+ if (taskMode)
497
+ all.push(finishTaskTool(agent.outputSchema));
498
+ else if (schemaWithTools)
499
+ all.push(setModelResponseTool(agent.outputSchema));
500
+ if (ctx.extraTools)
501
+ all.push(...ctx.extraTools);
502
+ // One entry per name, in first-listed order, the later object winning (ADK's toolsDict).
503
+ const dict = new Map();
504
+ const instructionTexts = [];
505
+ const contentWriters = [];
506
+ for (const union of all) {
507
+ const expanded = isToolset(union) ? await union.getTools(toolsetContext) : [union];
508
+ for (const listedTool of expanded) {
509
+ const native = nativeToolOf(listedTool);
510
+ if (native) {
511
+ const declaredSoFar = [...dict.values()].filter((e) => e.declaration).length;
512
+ const placement = placementOf(native, model, configNatives.length + declaredSoFar);
513
+ if (placement.in === 'config')
514
+ configNatives.push(placement.as);
515
+ else if (placement.in === 'dict')
516
+ dict.set(listedTool.name, { tool: listedTool, native });
517
+ continue;
518
+ }
519
+ const writer = instructionToolOf(listedTool);
520
+ if (writer) {
521
+ instructionTexts.push(() => writer.instruction(toolContext));
522
+ continue;
523
+ }
524
+ const own = toolOf(listedTool);
525
+ const declaration = contractToolDeclaration(own ?? listedTool);
526
+ if (declaration) {
527
+ const key = typeof listedTool.name === 'string' ? listedTool.name : declaration.name;
528
+ dict.set(key, { tool: own ?? listedTool, declaration });
529
+ }
530
+ if (own?.instruction) {
531
+ const write = own.instruction.bind(own);
532
+ instructionTexts.push(() => write(toolContext));
533
+ }
534
+ if (own?.contents) {
535
+ const add = own.contents.bind(own);
536
+ contentWriters.push(() => add(contents, toolContext));
537
+ }
538
+ }
539
+ }
540
+ // ADK runs each tool's processLlmRequest in turn; its instruction lands in that order.
541
+ for (const text of instructionTexts) {
542
+ const written = await text();
543
+ if (written)
544
+ system = appendInstructions(system, [written]);
545
+ }
546
+ // ...and what it adds to the history (load_skill_resource's binary file, ADR 0083), after the history.
547
+ for (const write of contentWriters)
548
+ await write();
549
+ // 5. Everything the config says, read as the shim's mapping reads it.
550
+ const { toolChoice, strict } = toolChoiceOf(cfg);
551
+ const tools = [];
552
+ const declared = new Map();
553
+ const nativeTools = new Set();
554
+ for (const [name, entry] of dict) {
555
+ if (entry.native)
556
+ nativeTools.add(entry.native);
557
+ if (entry.declaration) {
558
+ tools.push(strict ? { ...entry.declaration, strict } : entry.declaration);
559
+ declared.set(name, entry.tool);
560
+ }
561
+ }
562
+ for (const native of configNatives)
563
+ nativeTools.add(native);
564
+ const schema = cfg.responseJsonSchema ?? cfg.responseSchema;
565
+ const jsonMode = !isObject(schema) && cfg.responseMimeType === 'application/json';
566
+ const reasoning = reasoningOf(cfg);
567
+ const sampling = samplingOf(cfg);
568
+ const systemPrompt = systemText(system);
569
+ const messages = contentsToMessages(contents).messages;
570
+ const request = {
571
+ model,
572
+ ...(systemPrompt !== undefined ? { system: systemPrompt } : {}),
573
+ messages,
574
+ ...(tools.length > 0 ? { tools } : {}),
575
+ ...(nativeTools.size > 0 ? { nativeTools: [...nativeTools] } : {}),
576
+ ...(toolChoice !== undefined ? { toolChoice } : {}),
577
+ ...(isObject(schema) ? { outputSchema: toContractJsonSchema(schema) } : {}),
578
+ ...(jsonMode ? { outputFormat: 'json' } : {}),
579
+ ...(reasoning !== undefined ? { reasoning } : {}),
580
+ ...(sampling ? { sampling } : {}),
581
+ stream: ctx.stream ?? false,
582
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
583
+ };
584
+ return { request, tools: declared };
585
+ }