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,312 @@
1
+ /**
2
+ * lib/runtime/native/history.ts — which stored events a native model call
3
+ * sees, and in what form (ADR 0045, ADR 0066).
4
+ *
5
+ * WHY this file exists:
6
+ * A model request's history is the session's events projected for one
7
+ * agent: its own turns as they are, the person's words as they are,
8
+ * another agent's turns retold as context, approvals and credential
9
+ * requests left out, and a tool's late answer moved next to the call it
10
+ * answers. ADK's content processor does this on the ADK runtime
11
+ * (agents/processors/content_processor_utils.js in @google/adk 2.2), and a
12
+ * session one runtime wrote must read the same on the other, so this is
13
+ * that processor, rule for rule, over TurnEvents:
14
+ *
15
+ * - includeContents `default`: every visible event; `none`: from the
16
+ * latest message by the person or by another agent, reaching back to
17
+ * the calls its tool answers answer (getCurrentTurnContents).
18
+ * - Skipped: an event with no role, or whose first part is empty text; an
19
+ * event on another branch (a branch that is not a prefix of this one);
20
+ * an event in another isolation scope; ADK's credential, confirmation
21
+ * and input-request calls and answers.
22
+ * - Another agent's event becomes a user message: "For context:", then
23
+ * `[name] said: …`, `[name] called tool …`, `[name] tool … returned
24
+ * result: …`, any other part copied.
25
+ * - The latest compaction summary stands in for the events it covers, as
26
+ * "[Previous Context Summary]:\n<summary>".
27
+ * - The answer to the latest call is merged and moved next to that call;
28
+ * an earlier call's answers likewise.
29
+ * - ADK's own call ids (`adk-…`) are removed: the provider never sees them.
30
+ * The contents are deep copies, so nothing here changes a stored event.
31
+ *
32
+ * The result is genai-shaped content, as stored. The request builder maps it
33
+ * to the model contract through lib/models/genaiMapping.ts, the same mapping
34
+ * the ADK shim applies, so both runtimes hand an adapter the same messages.
35
+ */
36
+ import { getFunctionCalls, getFunctionResponses } from '../events.js';
37
+ /** ADK prefixes the call ids it makes with this (AF_FUNCTION_CALL_ID_PREFIX). */
38
+ export const ADK_CALL_ID_PREFIX = 'adk-';
39
+ /** ADK's framework calls that a model never sees in its history. */
40
+ export const REQUEST_CONFIRMATION_CALL = 'adk_request_confirmation';
41
+ export const REQUEST_CREDENTIAL_CALL = 'adk_request_credential';
42
+ export const REQUEST_INPUT_CALL = 'adk_request_input';
43
+ const UNSTRINGIFIABLE_VALUE = '<unstringifiable value>';
44
+ export function isCompacted(event) {
45
+ return event.isCompacted === true;
46
+ }
47
+ function isVisible(event, scope) {
48
+ return event.isolationScope === undefined || event.isolationScope === scope;
49
+ }
50
+ /** The latest compaction and what follows it, or every visible event when there is none (ADK's getActiveEvents). */
51
+ export function activeEvents(events, scope) {
52
+ const visible = events.filter((e) => isVisible(e, scope));
53
+ const latest = visible.filter(isCompacted).pop();
54
+ if (!latest)
55
+ return visible;
56
+ return [latest, ...visible.filter((e) => !isCompacted(e) && e.timestamp > latest.endTime)];
57
+ }
58
+ export function isSegmentPrefix(current, target) {
59
+ return !target || target === current || (!!current && current.startsWith(`${target}.`));
60
+ }
61
+ function namesCall(event, name) {
62
+ return (event.content?.parts ?? []).some((p) => p.functionCall?.name === name || p.functionResponse?.name === name);
63
+ }
64
+ function shouldInclude(event, branch, scope) {
65
+ if (!event.content?.role || event.content.parts?.[0]?.text === '')
66
+ return false;
67
+ if (branch && event.branch && !isSegmentPrefix(branch, event.branch))
68
+ return false;
69
+ if (!isVisible(event, scope))
70
+ return false;
71
+ return !namesCall(event, REQUEST_CREDENTIAL_CALL) && !namesCall(event, REQUEST_CONFIRMATION_CALL) && !namesCall(event, REQUEST_INPUT_CALL);
72
+ }
73
+ function fromAnotherAgent(agentName, event) {
74
+ return !!agentName && event.author !== agentName && event.author !== 'user';
75
+ }
76
+ function clone(value) {
77
+ return value === undefined ? value : structuredClone(value);
78
+ }
79
+ function safeStringify(value) {
80
+ if (typeof value === 'string')
81
+ return value;
82
+ try {
83
+ const json = JSON.stringify(value);
84
+ if (typeof json === 'string')
85
+ return json;
86
+ }
87
+ catch {
88
+ // fall through to String()
89
+ }
90
+ try {
91
+ return String(value);
92
+ }
93
+ catch {
94
+ return UNSTRINGIFIABLE_VALUE;
95
+ }
96
+ }
97
+ /** Another agent's event, retold to this one as context in a user message. */
98
+ function retold(event) {
99
+ if (!event.content?.parts?.length)
100
+ return event;
101
+ const parts = [{ text: 'For context:' }];
102
+ for (const part of event.content.parts) {
103
+ if (part.text && !part.thought) {
104
+ parts.push({ text: `[${event.author}] said: ${part.text}` });
105
+ }
106
+ else if (part.functionCall) {
107
+ parts.push({ text: `[${event.author}] called tool \`${part.functionCall.name}\` with parameters: ${safeStringify(part.functionCall.args)}` });
108
+ }
109
+ else if (part.functionResponse) {
110
+ parts.push({ text: `[${event.author}] tool \`${part.functionResponse.name}\` returned result: ${safeStringify(part.functionResponse.response)}` });
111
+ }
112
+ else {
113
+ parts.push(clone(part));
114
+ }
115
+ }
116
+ return { ...event, author: 'user', content: { role: 'user', parts } };
117
+ }
118
+ function summaryOf(event) {
119
+ return { ...event, author: 'user', content: { role: 'user', parts: [{ text: `[Previous Context Summary]:\n${event.compactedContent}` }] } };
120
+ }
121
+ /** Several answer events as one, a later answer to a call replacing an earlier one in place. */
122
+ function mergeResponses(events) {
123
+ if (events.length === 0)
124
+ throw new Error('Cannot merge an empty list of events.');
125
+ const first = events[0];
126
+ const content = clone(first.content);
127
+ const parts = content?.parts;
128
+ if (!parts || parts.length === 0)
129
+ throw new Error('There should be at least one function_response part.');
130
+ const index = new Map();
131
+ parts.forEach((part, i) => {
132
+ if (part.functionResponse?.id)
133
+ index.set(part.functionResponse.id, i);
134
+ });
135
+ for (const event of events.slice(1)) {
136
+ if (!event.content?.parts)
137
+ throw new Error('There should be at least one function_response part.');
138
+ for (const part of event.content.parts) {
139
+ const copy = clone(part);
140
+ const id = copy.functionResponse?.id;
141
+ if (id) {
142
+ const at = index.get(id);
143
+ if (at !== undefined)
144
+ parts[at] = copy;
145
+ else {
146
+ parts.push(copy);
147
+ index.set(id, parts.length - 1);
148
+ }
149
+ }
150
+ else {
151
+ parts.push(copy);
152
+ }
153
+ }
154
+ }
155
+ return { ...first, content };
156
+ }
157
+ /** The latest event answers calls: its answers, merged, sit right after the event that made those calls. */
158
+ function latestAnswerNextToItsCall(events) {
159
+ if (events.length === 0)
160
+ return events;
161
+ const latest = events[events.length - 1];
162
+ const responses = getFunctionResponses(latest);
163
+ if (!responses.length)
164
+ return events;
165
+ const ids = new Set(responses.filter((r) => !!r.id).map((r) => r.id));
166
+ const secondLatest = events.at(-2);
167
+ if (secondLatest && getFunctionCalls(secondLatest).some((c) => c.id && ids.has(c.id)))
168
+ return events;
169
+ let match;
170
+ for (let i = events.length - 2; i >= 0 && !match; i--) {
171
+ const calls = getFunctionCalls(events[i]);
172
+ if (!calls.length)
173
+ continue;
174
+ if (!calls.some((c) => c.id && ids.has(c.id)))
175
+ continue;
176
+ const callIds = new Set(calls.map((c) => c.id).filter((id) => !!id));
177
+ if (![...ids].every((id) => callIds.has(id))) {
178
+ throw new Error(`Last response event should only contain the responses for the function calls in the same function call event. Function call ids found : ${[...callIds].join(', ')}, function response ids provided: ${[...ids].join(', ')}`);
179
+ }
180
+ match = { at: i, ids: callIds };
181
+ }
182
+ if (!match)
183
+ throw new Error(`No function call event found for function responses ids: ${[...ids].join(', ')}`);
184
+ const answers = [];
185
+ for (let i = match.at + 1; i < events.length - 1; i++) {
186
+ const event = events[i];
187
+ if (getFunctionResponses(event).some((r) => r.id && match.ids.has(r.id)))
188
+ answers.push(event);
189
+ }
190
+ answers.push(latest);
191
+ return [...events.slice(0, match.at + 1), mergeResponses(answers)];
192
+ }
193
+ /** Each earlier call's answers, wherever they landed, sit right after the call. */
194
+ function answersNextToTheirCalls(events) {
195
+ const answeredAt = new Map();
196
+ events.forEach((event, i) => {
197
+ for (const r of getFunctionResponses(event))
198
+ if (r.id)
199
+ answeredAt.set(r.id, i);
200
+ });
201
+ const out = [];
202
+ for (const event of events) {
203
+ if (getFunctionResponses(event).length > 0)
204
+ continue;
205
+ const calls = getFunctionCalls(event);
206
+ out.push(event);
207
+ if (!calls.length)
208
+ continue;
209
+ const at = new Set();
210
+ for (const call of calls) {
211
+ const i = call.id ? answeredAt.get(call.id) : undefined;
212
+ if (i !== undefined)
213
+ at.add(i);
214
+ }
215
+ if (at.size === 1)
216
+ out.push(events[[...at][0]]);
217
+ else if (at.size > 1)
218
+ out.push(mergeResponses([...at].sort((a, b) => a - b).map((i) => events[i])));
219
+ }
220
+ return out;
221
+ }
222
+ function stripAdkCallIds(content) {
223
+ for (const part of content?.parts ?? []) {
224
+ if (part.functionCall?.id?.startsWith(ADK_CALL_ID_PREFIX))
225
+ part.functionCall.id = undefined;
226
+ if (part.functionResponse?.id?.startsWith(ADK_CALL_ID_PREFIX))
227
+ part.functionResponse.id = undefined;
228
+ }
229
+ }
230
+ /** The contents of every visible event, projected for `agentName` (ADK's getContents). The compactor's estimate reads it too. */
231
+ export function contentsOf(events, agentName, branch, scope) {
232
+ const kept = [];
233
+ for (const event of events) {
234
+ if (!isVisible(event, scope))
235
+ continue;
236
+ if (isCompacted(event)) {
237
+ kept.push(summaryOf(event));
238
+ continue;
239
+ }
240
+ if (!shouldInclude(event, branch, scope))
241
+ continue;
242
+ kept.push(fromAnotherAgent(agentName, event) ? retold(event) : event);
243
+ }
244
+ const arranged = answersNextToTheirCalls(latestAnswerNextToItsCall(kept));
245
+ return arranged.map((event) => {
246
+ const content = clone(event.content);
247
+ stripAdkCallIds(content);
248
+ return content;
249
+ });
250
+ }
251
+ /** Where the current turn starts: the anchor, or earlier when its answers answer earlier calls. */
252
+ function turnStart(events, anchor) {
253
+ const answered = new Set();
254
+ for (const event of events.slice(anchor)) {
255
+ for (const part of event.content?.parts ?? [])
256
+ if (part.functionResponse?.id)
257
+ answered.add(part.functionResponse.id);
258
+ }
259
+ if (answered.size === 0)
260
+ return anchor;
261
+ let start = anchor;
262
+ for (let i = anchor - 1; i >= 0; i--) {
263
+ const calls = (events[i]?.content?.parts ?? []).flatMap((p) => (p.functionCall ? [p.functionCall] : []));
264
+ if (calls.some((c) => (c.id ? answered.has(c.id) : false)))
265
+ start = i;
266
+ }
267
+ return start;
268
+ }
269
+ /**
270
+ * The genai contents a model request carries for `scope.agentName`, from
271
+ * the session's events (oldest first), as ADK's content processor builds
272
+ * them for the same session.
273
+ */
274
+ export function projectHistory(events, scope) {
275
+ const active = activeEvents(events, scope.isolationScope);
276
+ if ((scope.includeContents ?? 'default') === 'default') {
277
+ return contentsOf(active, scope.agentName, scope.branch, scope.isolationScope);
278
+ }
279
+ for (let i = active.length - 1; i >= 0; i--) {
280
+ const event = active[i];
281
+ if (!shouldInclude(event, scope.branch, scope.isolationScope))
282
+ continue;
283
+ if (event.author === 'user' || fromAnotherAgent(scope.agentName, event)) {
284
+ return contentsOf(active.slice(turnStart(active, i)), scope.agentName, scope.branch, scope.isolationScope);
285
+ }
286
+ }
287
+ return [];
288
+ }
289
+ // ── Gemini code execution in the history ─────────────────────────────────────
290
+ /** ADK's BaseCodeExecutor delimiters: the first code block's, and the result's. */
291
+ const CODE_BLOCK = ['```tool_code\n', '\n```'];
292
+ const EXECUTION_RESULT = ['```tool_output\n', '\n```'];
293
+ /**
294
+ * An agent with `code_execution: gemini`: a content that ends in code
295
+ * becomes that code as a fenced block, and a content that is only a result
296
+ * becomes the result as a user message (ADK's convertCodeExecutionParts,
297
+ * which its code-execution processor applies to every content). In place.
298
+ */
299
+ export function convertCodeExecutionParts(content) {
300
+ const parts = content.parts;
301
+ if (!parts?.length)
302
+ return;
303
+ const last = parts[parts.length - 1];
304
+ if (last.executableCode) {
305
+ parts[parts.length - 1] = { text: CODE_BLOCK[0] + (last.executableCode.code || '') + CODE_BLOCK[1] };
306
+ }
307
+ else if (parts.length === 1 && last.codeExecutionResult) {
308
+ const output = last.codeExecutionResult.output;
309
+ parts[parts.length - 1] = { text: output == null ? '' : EXECUTION_RESULT[0] + output + EXECUTION_RESULT[1] };
310
+ content.role = 'user';
311
+ }
312
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * lib/runtime/native/interrupts.ts — approvals on the native loop: the
3
+ * answer to an `adk_request_confirmation` call runs or refuses the pinned
4
+ * call before the next model step (WS2-7a, ADR 0028, ADR 0077).
5
+ *
6
+ * WHY this file exists:
7
+ * A tool that requires approval does not run when called. The loop
8
+ * (agentLoop.ts) stores ADK's `adk_request_confirmation` call in place of
9
+ * the response, pinning the original call and its arguments, and the run
10
+ * ends paused. The person's answer arrives as the next user message: a
11
+ * function response to that call carrying `{ confirmed }`. On the ADK
12
+ * runtime, LlmAgent's request-confirmation processor reads it before every
13
+ * model step and runs the pinned call with the confirmation. This file is
14
+ * that processor, case for case, so an approval opened on either runtime
15
+ * resumes on the other and both store the same events.
16
+ *
17
+ * BEFORE EACH STEP, AS ADK'S PROCESSOR RUNS IT:
18
+ * 1. The answers: the function responses named `adk_request_confirmation`
19
+ * in the latest user event (events on another branch left out), each
20
+ * read as `{ confirmed, hint, payload }`, or as JSON under `response`.
21
+ * None: nothing happens, and the step goes on as usual.
22
+ * 2. The gates they answer: every `adk_request_confirmation` call whose id
23
+ * an answer names. A request authored by the user is refused
24
+ * (`untrusted_request`); one authored by another agent is skipped; one
25
+ * whose pinned call has no id or name is refused (`malformed_request`);
26
+ * one this agent has already answered the pinned call after is skipped,
27
+ * so a later step never runs the call again.
28
+ * 3. The binding. The pinned call must be one this agent made, by id
29
+ * (`unknown_original_call`); its tool must be the agent's
30
+ * (`unregistered_tool`); the name and the arguments must equal the
31
+ * call's as the model made it (`tool_name_mismatch`,
32
+ * `arguments_mismatch`); and the tool must require approval, or have
33
+ * asked for it (`confirmation_not_required`). A refusal throws ADK's
34
+ * IntentMismatchError text and nothing runs.
35
+ * 4. The bound calls run through the loop's own call path with the
36
+ * confirmation in their context: an approved call runs its tool, a
37
+ * refused one answers ADK's refusal. Their response is stored as its
38
+ * own event before the step builds its request, so the model reads it.
39
+ *
40
+ * Not here: a plain-text "yes" as an answer (ADK's plainTextToolConfirmation,
41
+ * which no surface turns on), and answers delivered by a remote peer (ADK's
42
+ * remoteDelivered, which no surface sets).
43
+ *
44
+ * QUESTIONS (ask_user, WS2-7b, ADR 0079) need no processor here. ADK runs its
45
+ * request-input processor (REQUEST_INPUT_LLM_REQUEST_PROCESSOR) next, before
46
+ * compaction, but it only re-runs a node tool (a workflow run as a tool) that
47
+ * paused on an `adk_request_input` call; for an agent that lists no node tool
48
+ * it returns before doing anything, and no native agent lists one (native
49
+ * refuses workflows). An `ask_user` call is an ordinary long-running call:
50
+ * the turn runner stores the person's next message as its function response
51
+ * (lib/runtime/questions.ts questionAnswerPart), and the step reads the call
52
+ * and the answer side by side from the history (history.ts), as ADK's
53
+ * content processor does. When workflows run natively (WS4), the node-tool
54
+ * resume is ported beside approvedCalls, in the same place in the order.
55
+ *
56
+ * CREDENTIALS (OAuth consent, WS6-3b, ADR 0085) run first, as ADK runs its
57
+ * auth preprocessor (AUTH_PREPROCESSOR) before request-confirmation.
58
+ * grantedCalls is that preprocessor, check for check, with one difference
59
+ * in what the answer carries:
60
+ * 1. The answers: the function responses named `adk_request_credential`
61
+ * in the last event with content, which must be the user's. None:
62
+ * nothing happens.
63
+ * 2. The requests they answer: `adk_request_credential` calls this agent
64
+ * made, by id. An answer naming no such request is ignored, as ADK
65
+ * ignores it.
66
+ * 3. The binding. ADK's answer carries the authorization response (a code
67
+ * or the redirect URL), which ADK exchanges in-process with the client
68
+ * secret its request event stored. Here the server's callback route has
69
+ * already exchanged the code and stored the grant
70
+ * (lib/tools/oauthConsent.ts), so the answer carries no credential:
71
+ * `{ credentialKey, granted: true }`, bound to the request by its
72
+ * credentialKey. An answer that does not bind is ignored.
73
+ * 4. The paused calls the bound requests name (`function_call_id`, ADK's
74
+ * toolset requests aside) run again, from the latest event that made
75
+ * them, through the loop's own call path. The tool now reads its grant
76
+ * through ctx.accessToken. The response is stored before the step
77
+ * builds its request. A later step finds the agent's own events last,
78
+ * so the call runs once.
79
+ *
80
+ * ADK stays out of this file: an ADK tool an agent still lists is asked
81
+ * whether it gates through its own checkRequireConfirmation, by shape.
82
+ */
83
+ import type { ToolConfirmation } from '../../tools/tool.ts';
84
+ import type { TurnFunctionCall } from '../events.ts';
85
+ import type { Session } from '../sessions.ts';
86
+ import type { NativeAgent } from './request.ts';
87
+ /** Why a confirmation does not bind to the call it pins: ADK's IntentMismatchError reasons. */
88
+ export type IntentMismatchReason = 'untrusted_request' | 'malformed_request' | 'unknown_original_call' | 'unregistered_tool' | 'tool_name_mismatch' | 'arguments_mismatch' | 'confirmation_not_required';
89
+ /** A confirmation that does not bind to its pinned call: ADK's IntentMismatchError, by name and text. */
90
+ export declare class IntentMismatchError extends Error {
91
+ readonly reason: IntentMismatchReason;
92
+ readonly functionCallId?: string;
93
+ constructor(reason: IntentMismatchReason, functionCallId?: string);
94
+ }
95
+ /** The pinned calls an answer lets run, each with its confirmation, in the order the gates were stored. */
96
+ export interface ApprovedCalls {
97
+ calls: TurnFunctionCall[];
98
+ confirmations: Map<string, ToolConfirmation>;
99
+ /** The agent's tools by name, as the loop runs calls against them. */
100
+ tools: Map<string, unknown>;
101
+ }
102
+ interface Scope {
103
+ session: Session;
104
+ invocationId: string;
105
+ branch?: string;
106
+ }
107
+ /**
108
+ * The pinned calls the latest user message approves or refuses, bound to
109
+ * the calls this agent made; undefined when it answers no open request.
110
+ * Throws IntentMismatchError when an answer does not bind (nothing runs).
111
+ * `contextFor` makes the context a tool's gate check reads.
112
+ */
113
+ export declare function approvedCalls(agent: NativeAgent, scope: Scope, contextFor: (callId: string) => unknown): Promise<ApprovedCalls | undefined>;
114
+ /** The paused calls a granted consent lets run again, from the event that made them. */
115
+ export interface GrantedCalls {
116
+ calls: TurnFunctionCall[];
117
+ /** The agent's tools by name, as the loop runs calls against them. */
118
+ tools: Map<string, unknown>;
119
+ }
120
+ /**
121
+ * The paused calls the latest user message resumes by answering this
122
+ * agent's credential requests; undefined when it answers none (ADK's
123
+ * AuthPreprocessor, the exchange left to the callback route).
124
+ */
125
+ export declare function grantedCalls(agent: NativeAgent, scope: Scope): Promise<GrantedCalls | undefined>;
126
+ export {};