melchizedek-agents 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +12 -0
- package/CHANGELOG.md +825 -0
- package/DOCUMENTATION.md +217 -59
- package/README.md +42 -1
- package/config/agents/examples/harness.yaml +3 -1
- package/config/agents/examples/model_zoo.yaml +10 -9
- package/config/agents/syndicateSchema.yaml +50 -16
- package/config/agents/templates/account_memory.yaml +2 -6
- package/config/agents/templates/case_desk.yaml +3 -9
- package/config/agents/templates/draft_review.yaml +3 -9
- package/config/agents/templates/intake_extractor.yaml +1 -3
- package/config/agents/templates/research_brief.yaml +3 -9
- package/config/agents/templates/research_desk.yaml +3 -9
- package/config/agents/templates/review_panel.yaml +4 -12
- package/config/agents/templates/support_triage.yaml +4 -12
- package/config/agents/templates/systems_operator.yaml +2 -6
- package/db/hardening.sql +7 -1
- package/db/migrations/0013_tool_credentials.sql +260 -0
- package/dist/lib/a2a/app.d.ts +70 -6
- package/dist/lib/a2a/app.js +107 -2
- package/dist/lib/a2a/executor.d.ts +20 -3
- package/dist/lib/a2a/executor.js +66 -7
- package/dist/lib/a2a/remoteAgent.d.ts +24 -9
- package/dist/lib/a2a/remoteAgent.js +31 -14
- package/dist/lib/compile.d.ts +121 -30
- package/dist/lib/compile.js +137 -124
- package/dist/lib/compileAdk.d.ts +29 -0
- package/dist/lib/compileAdk.js +132 -0
- package/dist/lib/compileNative.d.ts +85 -0
- package/dist/lib/compileNative.js +222 -0
- package/dist/lib/config.d.ts +6 -5
- package/dist/lib/config.js +6 -5
- package/dist/lib/doctor.js +1 -0
- package/dist/lib/index.d.ts +2 -1
- package/dist/lib/index.js +2 -1
- package/dist/lib/loadSyndicate.d.ts +18 -0
- package/dist/lib/memory/erase.d.ts +5 -3
- package/dist/lib/memory/erase.js +5 -2
- package/dist/lib/memory/namespace.d.ts +8 -1
- package/dist/lib/memory/namespace.js +12 -6
- package/dist/lib/memory/providers.js +2 -1
- package/dist/lib/memory/supabaseMemoryService.d.ts +37 -3
- package/dist/lib/memory/supabaseMemoryService.js +42 -2
- package/dist/lib/model.d.ts +47 -0
- package/dist/lib/model.js +37 -0
- package/dist/lib/models/adapterResolver.d.ts +113 -0
- package/dist/lib/models/adapterResolver.js +136 -0
- package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
- package/dist/lib/models/adkGeminiAdapter.js +367 -0
- package/dist/lib/models/adkShim.d.ts +111 -0
- package/dist/lib/models/adkShim.js +136 -0
- package/dist/lib/models/capabilities.d.ts +3 -0
- package/dist/lib/models/capabilities.js +20 -13
- package/dist/lib/models/chatCompletionsAdapter.d.ts +279 -0
- package/dist/lib/models/chatCompletionsAdapter.js +854 -0
- package/dist/lib/models/circuitBreaker.d.ts +42 -0
- package/dist/lib/models/circuitBreaker.js +70 -0
- package/dist/lib/models/claudeAdapter.d.ts +103 -0
- package/dist/lib/models/claudeAdapter.js +669 -0
- package/dist/lib/models/claudeLlm.d.ts +39 -62
- package/dist/lib/models/claudeLlm.js +44 -349
- package/dist/lib/models/claudeModels.d.ts +127 -0
- package/dist/lib/models/claudeModels.js +237 -0
- package/dist/lib/models/contract.d.ts +395 -0
- package/dist/lib/models/contract.js +39 -0
- package/dist/lib/models/endpoints.js +2 -1
- package/dist/lib/models/errorResponse.d.ts +50 -0
- package/dist/lib/models/errorResponse.js +48 -0
- package/dist/lib/models/fallback.d.ts +17 -10
- package/dist/lib/models/fallback.js +53 -42
- package/dist/lib/models/fallbackAdapter.d.ts +55 -0
- package/dist/lib/models/fallbackAdapter.js +62 -0
- package/dist/lib/models/gateway.js +2 -1
- package/dist/lib/models/gatewayAdapter.d.ts +51 -0
- package/dist/lib/models/gatewayAdapter.js +81 -0
- package/dist/lib/models/gatewayLlm.d.ts +12 -33
- package/dist/lib/models/gatewayLlm.js +14 -75
- package/dist/lib/models/geminiAdapter.d.ts +123 -0
- package/dist/lib/models/geminiAdapter.js +831 -0
- package/dist/lib/models/geminiState.d.ts +25 -0
- package/dist/lib/models/geminiState.js +25 -0
- package/dist/lib/models/genaiMapping.d.ts +263 -0
- package/dist/lib/models/genaiMapping.js +862 -0
- package/dist/lib/models/gptAdapter.d.ts +240 -0
- package/dist/lib/models/gptAdapter.js +804 -0
- package/dist/lib/models/gptLlm.d.ts +63 -123
- package/dist/lib/models/gptLlm.js +88 -602
- package/dist/lib/models/grokAdapter.d.ts +86 -0
- package/dist/lib/models/grokAdapter.js +142 -0
- package/dist/lib/models/grokLlm.d.ts +22 -45
- package/dist/lib/models/grokLlm.js +22 -67
- package/dist/lib/models/kimiAdapter.d.ts +157 -0
- package/dist/lib/models/kimiAdapter.js +203 -0
- package/dist/lib/models/kimiLlm.d.ts +15 -107
- package/dist/lib/models/kimiLlm.js +17 -153
- package/dist/lib/models/ollamaAdapter.d.ts +125 -0
- package/dist/lib/models/ollamaAdapter.js +155 -0
- package/dist/lib/models/ollamaLlm.d.ts +11 -107
- package/dist/lib/models/ollamaLlm.js +13 -151
- package/dist/lib/models/openAiCompatibleLlm.d.ts +73 -216
- package/dist/lib/models/openAiCompatibleLlm.js +109 -671
- package/dist/lib/models/providerState.d.ts +63 -0
- package/dist/lib/models/providerState.js +61 -0
- package/dist/lib/models/reasoning.d.ts +26 -0
- package/dist/lib/models/reasoning.js +59 -0
- package/dist/lib/models/registry.d.ts +58 -35
- package/dist/lib/models/registry.js +89 -118
- package/dist/lib/models/retry.d.ts +2 -1
- package/dist/lib/models/retry.js +3 -2
- package/dist/lib/models/schemaNormalize.d.ts +98 -0
- package/dist/lib/models/schemaNormalize.js +321 -1
- package/dist/lib/models/tracedGemini.d.ts +41 -0
- package/dist/lib/models/tracedGemini.js +98 -0
- package/dist/lib/models/urls.d.ts +11 -0
- package/dist/lib/models/urls.js +16 -0
- package/dist/lib/net/redirects.d.ts +21 -2
- package/dist/lib/net/redirects.js +11 -34
- package/dist/lib/observability/audit.d.ts +5 -1
- package/dist/lib/observability/lineage.d.ts +14 -0
- package/dist/lib/observability/lineage.js +33 -0
- package/dist/lib/observability/supabaseSpanExporter.d.ts +10 -4
- package/dist/lib/observability/supabaseSpanExporter.js +17 -9
- package/dist/lib/observability/tracer.d.ts +26 -8
- package/dist/lib/observability/tracer.js +43 -18
- package/dist/lib/runtime/adkMemoryBridge.d.ts +46 -0
- package/dist/lib/runtime/adkMemoryBridge.js +68 -0
- package/dist/lib/runtime/adkSessionBridge.d.ts +78 -0
- package/dist/lib/runtime/adkSessionBridge.js +176 -0
- package/dist/lib/runtime/credentials.d.ts +59 -0
- package/dist/lib/runtime/credentials.js +62 -0
- package/dist/lib/runtime/events.d.ts +229 -0
- package/dist/lib/runtime/events.js +274 -0
- package/dist/lib/runtime/logging.d.ts +32 -0
- package/dist/lib/runtime/logging.js +55 -0
- package/dist/lib/runtime/memoryService.d.ts +72 -0
- package/dist/lib/runtime/memoryService.js +25 -0
- package/dist/lib/runtime/native/agentLoop.d.ts +203 -0
- package/dist/lib/runtime/native/agentLoop.js +687 -0
- package/dist/lib/runtime/native/compaction.d.ts +103 -0
- package/dist/lib/runtime/native/compaction.js +191 -0
- package/dist/lib/runtime/native/delegate.d.ts +98 -0
- package/dist/lib/runtime/native/delegate.js +173 -0
- package/dist/lib/runtime/native/history.d.ts +83 -0
- package/dist/lib/runtime/native/history.js +312 -0
- package/dist/lib/runtime/native/interrupts.d.ts +126 -0
- package/dist/lib/runtime/native/interrupts.js +291 -0
- package/dist/lib/runtime/native/request.d.ts +215 -0
- package/dist/lib/runtime/native/request.js +585 -0
- package/dist/lib/runtime/native/selfCorrection.d.ts +106 -0
- package/dist/lib/runtime/native/selfCorrection.js +253 -0
- package/dist/lib/runtime/native/step.d.ts +148 -0
- package/dist/lib/runtime/native/step.js +239 -0
- package/dist/lib/runtime/native/taskMode.d.ts +64 -0
- package/dist/lib/runtime/native/taskMode.js +126 -0
- package/dist/lib/runtime/native/telemetry.d.ts +75 -0
- package/dist/lib/runtime/native/telemetry.js +299 -0
- package/dist/lib/runtime/native/tempState.d.ts +31 -0
- package/dist/lib/runtime/native/tempState.js +56 -0
- package/dist/lib/runtime/nativeTurn.d.ts +86 -0
- package/dist/lib/runtime/nativeTurn.js +107 -0
- package/dist/lib/runtime/questions.d.ts +29 -7
- package/dist/lib/runtime/questions.js +47 -32
- package/dist/lib/runtime/runtimeFlag.d.ts +30 -0
- package/dist/lib/runtime/runtimeFlag.js +50 -0
- package/dist/lib/runtime/sessions.d.ts +166 -0
- package/dist/lib/runtime/sessions.js +201 -0
- package/dist/lib/runtime/syndicateTurn.d.ts +41 -5
- package/dist/lib/runtime/syndicateTurn.js +202 -32
- package/dist/lib/session/supabaseSessionService.d.ts +64 -17
- package/dist/lib/session/supabaseSessionService.js +148 -105
- package/dist/lib/session/transcript.d.ts +68 -22
- package/dist/lib/session/transcript.js +102 -28
- package/dist/lib/skills.js +33 -7
- package/dist/lib/storage/postgres/credentialStore.d.ts +20 -0
- package/dist/lib/storage/postgres/credentialStore.js +82 -0
- package/dist/lib/storage/postgres/index.d.ts +12 -0
- package/dist/lib/storage/postgres/index.js +6 -1
- package/dist/lib/storage/postgres/sessionService.d.ts +43 -15
- package/dist/lib/storage/postgres/sessionService.js +128 -66
- package/dist/lib/syndicateSchema.d.ts +47 -0
- package/dist/lib/syndicateSchema.js +72 -3
- package/dist/lib/toolRegistry.d.ts +15 -2
- package/dist/lib/toolRegistry.js +33 -17
- package/dist/lib/tools/adkTool.d.ts +81 -0
- package/dist/lib/tools/adkTool.js +268 -0
- package/dist/lib/tools/auth.d.ts +118 -0
- package/dist/lib/tools/auth.js +89 -0
- package/dist/lib/tools/collectionsSearchTool.d.ts +7 -6
- package/dist/lib/tools/collectionsSearchTool.js +11 -26
- package/dist/lib/tools/credentialCipher.d.ts +58 -0
- package/dist/lib/tools/credentialCipher.js +116 -0
- package/dist/lib/tools/credentialStore.d.ts +77 -0
- package/dist/lib/tools/credentialStore.js +246 -0
- package/dist/lib/tools/examples.d.ts +43 -0
- package/dist/lib/tools/examples.js +62 -0
- package/dist/lib/tools/generateImageTool.d.ts +15 -6
- package/dist/lib/tools/generateImageTool.js +19 -29
- package/dist/lib/tools/inspectImageTool.d.ts +9 -6
- package/dist/lib/tools/inspectImageTool.js +13 -17
- package/dist/lib/tools/mcpToolFactory.d.ts +42 -1
- package/dist/lib/tools/mcpToolFactory.js +46 -47
- package/dist/lib/tools/memoryTools.d.ts +61 -0
- package/dist/lib/tools/memoryTools.js +119 -0
- package/dist/lib/tools/nativeTools.d.ts +38 -0
- package/dist/lib/tools/nativeTools.js +43 -0
- package/dist/lib/tools/oauthConsent.d.ts +181 -0
- package/dist/lib/tools/oauthConsent.js +330 -0
- package/dist/lib/tools/openapi/call.d.ts +108 -0
- package/dist/lib/tools/openapi/call.js +295 -0
- package/dist/lib/tools/openapi/parse.d.ts +147 -0
- package/dist/lib/tools/openapi/parse.js +570 -0
- package/dist/lib/tools/openapiTools.d.ts +25 -17
- package/dist/lib/tools/openapiTools.js +124 -121
- package/dist/lib/tools/scienceTools.d.ts +14 -14
- package/dist/lib/tools/skillToolset.d.ts +58 -87
- package/dist/lib/tools/skillToolset.js +61 -142
- package/dist/lib/tools/skills/env.d.ts +58 -0
- package/dist/lib/tools/skills/env.js +165 -0
- package/dist/lib/tools/skills/executor.d.ts +114 -0
- package/dist/lib/tools/skills/executor.js +331 -0
- package/dist/lib/tools/skills/frontmatter.d.ts +79 -0
- package/dist/lib/tools/skills/frontmatter.js +215 -0
- package/dist/lib/tools/skills/loader.d.ts +91 -0
- package/dist/lib/tools/skills/loader.js +257 -0
- package/dist/lib/tools/skills/tools.d.ts +187 -0
- package/dist/lib/tools/skills/tools.js +386 -0
- package/dist/lib/tools/taskTools.d.ts +15 -15
- package/dist/lib/tools/tool.d.ts +354 -0
- package/dist/lib/tools/tool.js +304 -0
- package/dist/lib/tools/toolContract.d.ts +89 -33
- package/dist/lib/tools/toolContract.js +104 -82
- package/dist/lib/tools/urlContextTool.d.ts +3 -0
- package/dist/lib/tools/urlContextTool.js +5 -1
- package/dist/lib/tools/webExtractTool.d.ts +2 -2
- package/dist/lib/tools/webExtractTool.js +2 -1
- package/dist/lib/tools/webSearchTool.d.ts +6 -9
- package/dist/lib/tools/webSearchTool.js +14 -59
- package/dist/lib/tools/wikiTools.d.ts +19 -19
- package/dist/lib/tools/wikiTools.js +13 -9
- package/dist/lib/tools/xApiSearchTool.d.ts +2 -2
- package/dist/lib/tools/xApiSearchTool.js +2 -1
- package/dist/lib/tools/xSearchTool.d.ts +7 -9
- package/dist/lib/tools/xSearchTool.js +11 -62
- package/dist/lib/tools/xaiSearchParams.d.ts +41 -0
- package/dist/lib/tools/xaiSearchParams.js +126 -0
- package/dist/lib/wiki/agentRun.d.ts +12 -0
- package/dist/lib/wiki/agentRun.js +72 -34
- package/dist/lib/wiki/entities.d.ts +12 -0
- package/dist/lib/wiki/entities.js +45 -3
- package/dist/lib/workflow/agentNode.d.ts +136 -0
- package/dist/lib/workflow/agentNode.js +274 -0
- package/dist/lib/workflow/graph.d.ts +177 -0
- package/dist/lib/workflow/graph.js +458 -0
- package/dist/lib/workflow/nodeEvents.d.ts +50 -0
- package/dist/lib/workflow/nodeEvents.js +101 -0
- package/dist/lib/workflow/pause.d.ts +122 -0
- package/dist/lib/workflow/pause.js +180 -0
- package/dist/lib/workflow/resume.d.ts +165 -0
- package/dist/lib/workflow/resume.js +440 -0
- package/dist/lib/workflow/route.d.ts +58 -0
- package/dist/lib/workflow/route.js +69 -0
- package/dist/lib/workflow/scheduler.d.ts +415 -0
- package/dist/lib/workflow/scheduler.js +743 -0
- package/dist/lib/workflow/toolNode.d.ts +127 -0
- package/dist/lib/workflow/toolNode.js +236 -0
- package/dist/lib/workflow/turn.d.ts +118 -0
- package/dist/lib/workflow/turn.js +216 -0
- package/dist/lib/workflowConfig.d.ts +3 -2
- package/dist/lib/workflowConfig.js +3 -12
- package/dist/scripts/a2a_server.js +4 -3
- package/dist/scripts/assistant_worker.d.ts +2 -1
- package/dist/scripts/assistant_worker.js +9 -4
- package/dist/scripts/syndicate_chat.js +19 -10
- package/package.json +4 -1
- package/skills/briefs/melchizedek-author.md +3 -2
- package/skills/briefs/melchizedek-models.md +13 -9
- package/skills/briefs/melchizedek.md +3 -3
- package/skills/melchizedek/SKILL.md +2 -1
- package/skills/melchizedek-author/SKILL.md +2 -1
- package/skills/melchizedek-author/assets/minimal.yaml +2 -0
- package/skills/melchizedek-models/SKILL.md +23 -6
|
@@ -1,42 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/runtime/questions.ts — an agent asks the person a question mid-turn,
|
|
3
|
-
* and the next message is the answer.
|
|
4
|
-
*
|
|
5
|
-
* WHY: A syndicate that is put in front of users needs to ask: "which of
|
|
6
|
-
* these three accounts?", "what is the order number?". Before this, an
|
|
7
|
-
* agent could only end its turn with a question in its text and hope the
|
|
8
|
-
* next message answered it, with nothing in the session saying a question
|
|
9
|
-
* was open. `ask_user` is ADK's long-running tool mechanism under one YAML
|
|
10
|
-
* name: the call is recorded, the run ends without a response to it, the
|
|
11
|
-
* turn ends `input-required` (`result.input`), and the next message on the
|
|
12
|
-
* conversation becomes the call's response, so the agent resumes its own
|
|
13
|
-
* tool loop where it asked, with the question and the answer side by side
|
|
14
|
-
* in its history.
|
|
15
|
-
*
|
|
16
|
-
* The same `input-required` path carries a workflow's `ask_user` node
|
|
17
|
-
* (lib/workflow.ts) and an approval (ADR 0028); a client handles all three
|
|
18
|
-
* by showing `result.input` (or the approval) and sending the next message.
|
|
19
|
-
*
|
|
20
|
-
* WHERE: only on an agent the turn runs directly (the orchestrator, or a
|
|
21
|
-
* plan-dispatch route), as with approval gates: inside a delegated
|
|
22
|
-
* subagent ADK swallows the pause. Not inside a workflow node yet. The
|
|
23
|
-
* schema refuses both.
|
|
24
|
-
*/
|
|
25
|
-
import { LongRunningFunctionTool } from '@google/adk';
|
|
26
1
|
import { z } from 'zod';
|
|
2
|
+
import { defineTool } from '../tools/toolContract.js';
|
|
3
|
+
import { inputRequestFrom } from '../workflowConfig.js';
|
|
27
4
|
/** The registry name, and the function-call name an open question carries. */
|
|
28
5
|
export const ASK_USER = 'ask_user';
|
|
29
6
|
export const MAX_OPTIONS = 10;
|
|
30
7
|
/**
|
|
31
|
-
* The tool
|
|
32
|
-
*
|
|
8
|
+
* The tool, an own Tool marked long-running; the registry hands the ADK
|
|
9
|
+
* runtime its FunctionTool (lib/tools/adkTool.ts). Its execute returns
|
|
10
|
+
* nothing: a long-running call with no result ends the run, and the runtime
|
|
11
|
+
* waits for a function response with the call's id.
|
|
33
12
|
*/
|
|
34
|
-
export const askUserTool =
|
|
13
|
+
export const askUserTool = defineTool({
|
|
35
14
|
name: ASK_USER,
|
|
15
|
+
longRunning: true,
|
|
36
16
|
description: 'Ask the person one question and wait for their answer before you continue: a missing detail you need, or a choice only they can make. ' +
|
|
37
17
|
'Pass `options` when the answer is one of a few choices. The turn ends here; the person\'s next message is the answer, returned to you as this call\'s result. ' +
|
|
38
18
|
'Ask only what you cannot find out or reasonably assume, one question per call.',
|
|
39
|
-
|
|
19
|
+
schema: z.object({
|
|
40
20
|
question: z.string().min(1).max(500).describe('The question, as the person will read it.'),
|
|
41
21
|
options: z
|
|
42
22
|
.array(z.string().min(1).max(120))
|
|
@@ -45,9 +25,8 @@ export const askUserTool = new LongRunningFunctionTool({
|
|
|
45
25
|
.describe('The choices, when the answer is one of a few. Omit for a free answer.'),
|
|
46
26
|
}),
|
|
47
27
|
execute: async (_args, context) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return null;
|
|
28
|
+
context.actions.skipSummarization = true;
|
|
29
|
+
return undefined;
|
|
51
30
|
},
|
|
52
31
|
});
|
|
53
32
|
const partsOf = (e) => (e.content?.parts ?? []);
|
|
@@ -69,6 +48,9 @@ export function questionFrom(author, call) {
|
|
|
69
48
|
* The question still waiting for an answer in a session, or undefined. A
|
|
70
49
|
* question the person moved past (a text message after it was answered)
|
|
71
50
|
* is not pending; an answered one carries a function response with its id.
|
|
51
|
+
* Only an agent asks: an `ask_user` call in an event the user authored is
|
|
52
|
+
* no question, so the next message never becomes its answer (as approvals
|
|
53
|
+
* refuse a user-authored request, ADR 0077; ADR 0088).
|
|
72
54
|
*/
|
|
73
55
|
export function pendingQuestion(events) {
|
|
74
56
|
const answered = new Set();
|
|
@@ -80,6 +62,8 @@ export function pendingQuestion(events) {
|
|
|
80
62
|
if (p.functionResponse?.name === ASK_USER && p.functionResponse.id)
|
|
81
63
|
answered.add(p.functionResponse.id);
|
|
82
64
|
}
|
|
65
|
+
if (e.author === 'user')
|
|
66
|
+
continue;
|
|
83
67
|
for (const p of partsOf(e)) {
|
|
84
68
|
const call = p.functionCall;
|
|
85
69
|
if (call?.name !== ASK_USER || !call.id || answered.has(call.id))
|
|
@@ -89,6 +73,37 @@ export function pendingQuestion(events) {
|
|
|
89
73
|
}
|
|
90
74
|
return undefined;
|
|
91
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* The workflow question (`adk_request_input`, an ask_user node's request)
|
|
78
|
+
* still open in a session's events, or undefined. The answer is stored as
|
|
79
|
+
* the person's next text message, not as a function response, so a text
|
|
80
|
+
* message after the question closes it; a function response with its id
|
|
81
|
+
* answers it too. As with pendingQuestion, only a node asks: a request in
|
|
82
|
+
* an event the user authored is none. The resume (lib/workflow/resume.ts)
|
|
83
|
+
* reads the same events to route the answer.
|
|
84
|
+
*/
|
|
85
|
+
export function pendingWorkflowInput(events) {
|
|
86
|
+
const answered = new Set();
|
|
87
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
88
|
+
const e = events[i];
|
|
89
|
+
if (hasUserText(e))
|
|
90
|
+
return undefined;
|
|
91
|
+
for (const p of partsOf(e))
|
|
92
|
+
if (p.functionResponse?.id)
|
|
93
|
+
answered.add(p.functionResponse.id);
|
|
94
|
+
if (e.author === 'user')
|
|
95
|
+
continue;
|
|
96
|
+
for (const p of partsOf(e)) {
|
|
97
|
+
const call = p.functionCall;
|
|
98
|
+
if (!call || (call.id && answered.has(call.id)))
|
|
99
|
+
continue;
|
|
100
|
+
const input = inputRequestFrom(e.author, call);
|
|
101
|
+
if (input)
|
|
102
|
+
return input;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
92
107
|
/** The message part that answers question `id` with the person's text. */
|
|
93
108
|
export function questionAnswerPart(id, answer) {
|
|
94
109
|
return { functionResponse: { id, name: ASK_USER, response: { result: answer } } };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/runtimeFlag.ts — which runtime runs a turn: MELCHIZEDEK_RUNTIME
|
|
3
|
+
* and the turn's `runtime` option (ADR 0045, ADR 0073).
|
|
4
|
+
*
|
|
5
|
+
* `adk` runs each agent on Google ADK's Runner, `native` on the engine's own
|
|
6
|
+
* agent loop (lib/runtime/native/agentLoop.ts). The default is `adk` until
|
|
7
|
+
* the release that makes native the default (ADR 0045). A feature the native
|
|
8
|
+
* runtime does not run yet fails before any model call with
|
|
9
|
+
* UnsupportedOnRuntimeError, which names the feature and the runtime.
|
|
10
|
+
*
|
|
11
|
+
* A leaf module: it imports nothing, so every caller (the compiler, the
|
|
12
|
+
* turn runner, the wiki agent runner) can read the flag without a cycle.
|
|
13
|
+
*/
|
|
14
|
+
/** The runtime a turn runs on: Google ADK's Runner, or the engine's own loop. */
|
|
15
|
+
export type RuntimeName = 'adk' | 'native';
|
|
16
|
+
export declare const RUNTIMES: readonly RuntimeName[];
|
|
17
|
+
/** The runtime when neither the turn nor MELCHIZEDEK_RUNTIME names one. */
|
|
18
|
+
export declare const DEFAULT_RUNTIME: RuntimeName;
|
|
19
|
+
/** MELCHIZEDEK_RUNTIME as set, or undefined when unset or blank. Any other value is a configuration error. */
|
|
20
|
+
export declare function runtimeSetting(env?: NodeJS.ProcessEnv): RuntimeName | undefined;
|
|
21
|
+
/** The runtime to use: the caller's option, else MELCHIZEDEK_RUNTIME, else adk. */
|
|
22
|
+
export declare function chooseRuntime(option?: string, env?: NodeJS.ProcessEnv): RuntimeName;
|
|
23
|
+
/** A feature the chosen runtime does not run yet. Thrown before any model call. */
|
|
24
|
+
export declare class UnsupportedOnRuntimeError extends Error {
|
|
25
|
+
readonly feature: string;
|
|
26
|
+
readonly runtime: RuntimeName;
|
|
27
|
+
constructor(feature: string, runtime: RuntimeName, where: string);
|
|
28
|
+
}
|
|
29
|
+
/** The error for a feature the native runtime does not run yet; `where` names the agent or syndicate. */
|
|
30
|
+
export declare function unsupportedOnNative(feature: string, where: string): UnsupportedOnRuntimeError;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/runtimeFlag.ts — which runtime runs a turn: MELCHIZEDEK_RUNTIME
|
|
3
|
+
* and the turn's `runtime` option (ADR 0045, ADR 0073).
|
|
4
|
+
*
|
|
5
|
+
* `adk` runs each agent on Google ADK's Runner, `native` on the engine's own
|
|
6
|
+
* agent loop (lib/runtime/native/agentLoop.ts). The default is `adk` until
|
|
7
|
+
* the release that makes native the default (ADR 0045). A feature the native
|
|
8
|
+
* runtime does not run yet fails before any model call with
|
|
9
|
+
* UnsupportedOnRuntimeError, which names the feature and the runtime.
|
|
10
|
+
*
|
|
11
|
+
* A leaf module: it imports nothing, so every caller (the compiler, the
|
|
12
|
+
* turn runner, the wiki agent runner) can read the flag without a cycle.
|
|
13
|
+
*/
|
|
14
|
+
export const RUNTIMES = ['adk', 'native'];
|
|
15
|
+
/** The runtime when neither the turn nor MELCHIZEDEK_RUNTIME names one. */
|
|
16
|
+
export const DEFAULT_RUNTIME = 'adk';
|
|
17
|
+
function asRuntime(raw, source) {
|
|
18
|
+
const value = raw.trim().toLowerCase();
|
|
19
|
+
if (value === 'adk' || value === 'native')
|
|
20
|
+
return value;
|
|
21
|
+
throw new Error(`${source} must be "adk" or "native".`);
|
|
22
|
+
}
|
|
23
|
+
/** MELCHIZEDEK_RUNTIME as set, or undefined when unset or blank. Any other value is a configuration error. */
|
|
24
|
+
export function runtimeSetting(env = process.env) {
|
|
25
|
+
const raw = env.MELCHIZEDEK_RUNTIME;
|
|
26
|
+
if (!raw || !raw.trim())
|
|
27
|
+
return undefined;
|
|
28
|
+
return asRuntime(raw, 'MELCHIZEDEK_RUNTIME');
|
|
29
|
+
}
|
|
30
|
+
/** The runtime to use: the caller's option, else MELCHIZEDEK_RUNTIME, else adk. */
|
|
31
|
+
export function chooseRuntime(option, env = process.env) {
|
|
32
|
+
if (option !== undefined)
|
|
33
|
+
return asRuntime(option, 'The runtime option');
|
|
34
|
+
return runtimeSetting(env) ?? DEFAULT_RUNTIME;
|
|
35
|
+
}
|
|
36
|
+
/** A feature the chosen runtime does not run yet. Thrown before any model call. */
|
|
37
|
+
export class UnsupportedOnRuntimeError extends Error {
|
|
38
|
+
feature;
|
|
39
|
+
runtime;
|
|
40
|
+
constructor(feature, runtime, where) {
|
|
41
|
+
super(`${where}: ${feature} is not supported on the ${runtime} runtime yet. Run it on the ${runtime === 'native' ? 'adk' : 'native'} runtime (MELCHIZEDEK_RUNTIME, or the turn's runtime option).`);
|
|
42
|
+
this.name = 'UnsupportedOnRuntimeError';
|
|
43
|
+
this.feature = feature;
|
|
44
|
+
this.runtime = runtime;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** The error for a feature the native runtime does not run yet; `where` names the agent or syndicate. */
|
|
48
|
+
export function unsupportedOnNative(feature, where) {
|
|
49
|
+
return new UnsupportedOnRuntimeError(feature, 'native', where);
|
|
50
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/sessions.ts — the engine's own session interface, the rules
|
|
3
|
+
* every store applies, and a store that lives in the process (ADR 0045,
|
|
4
|
+
* ADR 0052).
|
|
5
|
+
*
|
|
6
|
+
* WHY this file exists:
|
|
7
|
+
* The native runtime reads and writes sessions without ADK. The durable
|
|
8
|
+
* stores (lib/session/supabaseSessionService.ts, lib/storage/postgres/
|
|
9
|
+
* sessionService.ts) and the transcript projection (lib/session/
|
|
10
|
+
* transcript.ts) implement SessionService beside ADK's BaseSessionService,
|
|
11
|
+
* and lib/runtime/adkSessionBridge.ts gives a store that has only one of
|
|
12
|
+
* the two the other, until ADK leaves at 1.0 (ADR 0058). The shapes are
|
|
13
|
+
* ADK's JSON (a Session holds TurnEvents, lib/runtime/events.ts), so both
|
|
14
|
+
* runtimes read and write the same rows.
|
|
15
|
+
*
|
|
16
|
+
* ONE MEANING ACROSS STORES:
|
|
17
|
+
* Where ADK's own services disagree with the engine's durable stores, the
|
|
18
|
+
* interface takes the durable stores' meaning, because that is what
|
|
19
|
+
* production runs and what a test on this in-process store should see.
|
|
20
|
+
* Where the two durable stores differ, it takes the Postgres store's,
|
|
21
|
+
* which never loses an event:
|
|
22
|
+
* - `afterTimestamp` keeps events strictly after it, and `numRecentEvents`
|
|
23
|
+
* then keeps the newest of those (ADK's in-memory store counts first
|
|
24
|
+
* and keeps an event at the timestamp itself).
|
|
25
|
+
* - Creating a session whose id exists returns it unchanged, events and
|
|
26
|
+
* all, so a second create never resets a conversation (ADK's in-memory
|
|
27
|
+
* store resets it).
|
|
28
|
+
* - Paging reports at least one page (listPage).
|
|
29
|
+
* - `app:` and `user:` state keys stay in the session's own state, as both
|
|
30
|
+
* durable stores keep them; ADK's in-memory store shares them across
|
|
31
|
+
* sessions. No syndicate writes such a key.
|
|
32
|
+
* The method names are not ADK's (create, not createSession), so one class
|
|
33
|
+
* can implement this interface and extend ADK's base during the dual
|
|
34
|
+
* period without either signature constraining the other.
|
|
35
|
+
*
|
|
36
|
+
* NO RUNTIME IMPORTS: every import here is a type, and nothing in this
|
|
37
|
+
* module's import graph names @google/* (tests/events.test.ts asserts it).
|
|
38
|
+
*/
|
|
39
|
+
import type { TurnEvent } from './events.ts';
|
|
40
|
+
/** A conversation's address. Stores key it as `<appName>:<userId>:<sessionId>`. */
|
|
41
|
+
export interface SessionKey {
|
|
42
|
+
/** The syndicate (or, for a DELEGATE subagent's own row, the subagent's name). */
|
|
43
|
+
appName: string;
|
|
44
|
+
userId: string;
|
|
45
|
+
sessionId: string;
|
|
46
|
+
}
|
|
47
|
+
/** A conversation: the same JSON as ADK's `Session`. */
|
|
48
|
+
export interface Session {
|
|
49
|
+
id: string;
|
|
50
|
+
appName: string;
|
|
51
|
+
userId: string;
|
|
52
|
+
/** Written only through events' `stateDelta` (applyEvent). Never holds a `temp:` key. */
|
|
53
|
+
state: Record<string, unknown>;
|
|
54
|
+
/** Oldest first. */
|
|
55
|
+
events: TurnEvent[];
|
|
56
|
+
/** Milliseconds since the epoch: the last appended event's timestamp, or the creation time. */
|
|
57
|
+
lastUpdateTime: number;
|
|
58
|
+
}
|
|
59
|
+
export interface CreateSessionRequest {
|
|
60
|
+
appName: string;
|
|
61
|
+
userId: string;
|
|
62
|
+
/** A new UUID when absent. */
|
|
63
|
+
sessionId?: string;
|
|
64
|
+
/** Initial state; `temp:` keys are dropped. */
|
|
65
|
+
state?: Record<string, unknown>;
|
|
66
|
+
}
|
|
67
|
+
export interface GetSessionOptions {
|
|
68
|
+
/** Keep only the newest N events (after `afterTimestamp`, when both are set). Ignored unless above zero. */
|
|
69
|
+
numRecentEvents?: number;
|
|
70
|
+
/** Keep only events whose timestamp is strictly greater. Ignored when 0 or absent. */
|
|
71
|
+
afterTimestamp?: number;
|
|
72
|
+
}
|
|
73
|
+
export interface ListSessionsRequest {
|
|
74
|
+
appName: string;
|
|
75
|
+
/** Every user's sessions when absent. */
|
|
76
|
+
userId?: string;
|
|
77
|
+
/** Page size. Every session matching, in one page, when absent. */
|
|
78
|
+
limit?: number;
|
|
79
|
+
/** Zero-based index of the first session. Ignored when `page` and `limit` are both set. */
|
|
80
|
+
offset?: number;
|
|
81
|
+
/** One-based page number. Needs `limit`; wins over `offset`. */
|
|
82
|
+
page?: number;
|
|
83
|
+
/** By last update, ties by id. Insertion order when absent. */
|
|
84
|
+
order?: 'asc' | 'desc';
|
|
85
|
+
}
|
|
86
|
+
export interface ListSessionsResult {
|
|
87
|
+
/** The page's sessions, each without its events. */
|
|
88
|
+
sessions: Session[];
|
|
89
|
+
/** One-based. */
|
|
90
|
+
page: number;
|
|
91
|
+
/** The page size, or every matching session's count when no limit was asked for. */
|
|
92
|
+
limit: number;
|
|
93
|
+
/** Sessions matching, across every page. */
|
|
94
|
+
totalItems: number;
|
|
95
|
+
/** At least 1. */
|
|
96
|
+
totalPages: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Where conversations live. Every method fails by throwing, with a message a
|
|
100
|
+
* person can act on; reading a session that does not exist is not a failure.
|
|
101
|
+
*/
|
|
102
|
+
export interface SessionService {
|
|
103
|
+
create(request: CreateSessionRequest): Promise<Session>;
|
|
104
|
+
/** A copy: changing it changes nothing stored. Undefined when there is no such session. */
|
|
105
|
+
get(key: SessionKey, options?: GetSessionOptions): Promise<Session | undefined>;
|
|
106
|
+
list(request: ListSessionsRequest): Promise<ListSessionsResult>;
|
|
107
|
+
/** Deletes the session and its events. Deleting one that does not exist does nothing. */
|
|
108
|
+
delete(key: SessionKey): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* Records `event` in `session` (applyEvent's rules, on the caller's copy)
|
|
111
|
+
* and in the store, and returns the event as stored. A partial event is
|
|
112
|
+
* returned as it is and recorded nowhere. Two copies of one session
|
|
113
|
+
* appending in turn both land: each append adds its own event.
|
|
114
|
+
*/
|
|
115
|
+
append(session: Session, event: TurnEvent): Promise<TurnEvent>;
|
|
116
|
+
}
|
|
117
|
+
/** State keys with this prefix last for one invocation and are never stored. */
|
|
118
|
+
export declare const TEMP_STATE_PREFIX = "temp:";
|
|
119
|
+
/** A copy of `record` without its `temp:` keys, in the same key order. */
|
|
120
|
+
export declare function withoutTempKeys(record: Record<string, unknown>): Record<string, unknown>;
|
|
121
|
+
/**
|
|
122
|
+
* Applies one event to a live session, as ADK's BaseSessionService does,
|
|
123
|
+
* and returns the event as a store keeps it:
|
|
124
|
+
* 1. A partial event is returned as it is, and the session is untouched.
|
|
125
|
+
* 2. The stored event's `stateDelta` loses its `temp:` keys (a copy; the
|
|
126
|
+
* given event is never changed).
|
|
127
|
+
* 3. Each remaining delta key is written into `session.state`.
|
|
128
|
+
* 4. The event replaces the session's event with the same id, or is
|
|
129
|
+
* appended.
|
|
130
|
+
* 5. `session.lastUpdateTime` becomes the event's timestamp.
|
|
131
|
+
*/
|
|
132
|
+
export declare function applyEvent(session: Session, event: TurnEvent): TurnEvent;
|
|
133
|
+
/** The events a read with `options` returns, oldest first (GetSessionOptions). */
|
|
134
|
+
export declare function selectEvents(events: readonly TurnEvent[], options?: GetSessionOptions): TurnEvent[];
|
|
135
|
+
/**
|
|
136
|
+
* The window a list request asks for: a zero-based offset and, when a limit
|
|
137
|
+
* was given, the page size. `page` wins over `offset` only beside a limit.
|
|
138
|
+
*/
|
|
139
|
+
export declare function listWindow(request: Pick<ListSessionsRequest, 'limit' | 'offset' | 'page'>): {
|
|
140
|
+
offset: number;
|
|
141
|
+
limit?: number;
|
|
142
|
+
};
|
|
143
|
+
/** The paging figures a list result reports, given how many sessions matched. */
|
|
144
|
+
export declare function listPage(totalItems: number, request: Pick<ListSessionsRequest, 'limit' | 'offset' | 'page'>): Omit<ListSessionsResult, 'sessions'>;
|
|
145
|
+
export interface InProcessSessionOptions {
|
|
146
|
+
/** The clock for a new session's lastUpdateTime. Default Date.now. */
|
|
147
|
+
now?: () => number;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Sessions held in this process, lost when it exits: the store for a
|
|
151
|
+
* syndicate with no durable one, and for tests. Every read hands out a copy
|
|
152
|
+
* and every append stores a copy, so no caller shares an object with the
|
|
153
|
+
* store. An append to a session the store does not hold (deleted while its
|
|
154
|
+
* turn ran) keeps the caller's session as it stands after the event.
|
|
155
|
+
*/
|
|
156
|
+
export declare class InProcessSessionService implements SessionService {
|
|
157
|
+
private readonly sessions;
|
|
158
|
+
private readonly now;
|
|
159
|
+
constructor(options?: InProcessSessionOptions);
|
|
160
|
+
private static key;
|
|
161
|
+
create(request: CreateSessionRequest): Promise<Session>;
|
|
162
|
+
get(key: SessionKey, options?: GetSessionOptions): Promise<Session | undefined>;
|
|
163
|
+
list(request: ListSessionsRequest): Promise<ListSessionsResult>;
|
|
164
|
+
delete(key: SessionKey): Promise<void>;
|
|
165
|
+
append(session: Session, event: TurnEvent): Promise<TurnEvent>;
|
|
166
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/runtime/sessions.ts — the engine's own session interface, the rules
|
|
3
|
+
* every store applies, and a store that lives in the process (ADR 0045,
|
|
4
|
+
* ADR 0052).
|
|
5
|
+
*
|
|
6
|
+
* WHY this file exists:
|
|
7
|
+
* The native runtime reads and writes sessions without ADK. The durable
|
|
8
|
+
* stores (lib/session/supabaseSessionService.ts, lib/storage/postgres/
|
|
9
|
+
* sessionService.ts) and the transcript projection (lib/session/
|
|
10
|
+
* transcript.ts) implement SessionService beside ADK's BaseSessionService,
|
|
11
|
+
* and lib/runtime/adkSessionBridge.ts gives a store that has only one of
|
|
12
|
+
* the two the other, until ADK leaves at 1.0 (ADR 0058). The shapes are
|
|
13
|
+
* ADK's JSON (a Session holds TurnEvents, lib/runtime/events.ts), so both
|
|
14
|
+
* runtimes read and write the same rows.
|
|
15
|
+
*
|
|
16
|
+
* ONE MEANING ACROSS STORES:
|
|
17
|
+
* Where ADK's own services disagree with the engine's durable stores, the
|
|
18
|
+
* interface takes the durable stores' meaning, because that is what
|
|
19
|
+
* production runs and what a test on this in-process store should see.
|
|
20
|
+
* Where the two durable stores differ, it takes the Postgres store's,
|
|
21
|
+
* which never loses an event:
|
|
22
|
+
* - `afterTimestamp` keeps events strictly after it, and `numRecentEvents`
|
|
23
|
+
* then keeps the newest of those (ADK's in-memory store counts first
|
|
24
|
+
* and keeps an event at the timestamp itself).
|
|
25
|
+
* - Creating a session whose id exists returns it unchanged, events and
|
|
26
|
+
* all, so a second create never resets a conversation (ADK's in-memory
|
|
27
|
+
* store resets it).
|
|
28
|
+
* - Paging reports at least one page (listPage).
|
|
29
|
+
* - `app:` and `user:` state keys stay in the session's own state, as both
|
|
30
|
+
* durable stores keep them; ADK's in-memory store shares them across
|
|
31
|
+
* sessions. No syndicate writes such a key.
|
|
32
|
+
* The method names are not ADK's (create, not createSession), so one class
|
|
33
|
+
* can implement this interface and extend ADK's base during the dual
|
|
34
|
+
* period without either signature constraining the other.
|
|
35
|
+
*
|
|
36
|
+
* NO RUNTIME IMPORTS: every import here is a type, and nothing in this
|
|
37
|
+
* module's import graph names @google/* (tests/events.test.ts asserts it).
|
|
38
|
+
*/
|
|
39
|
+
// ── The rules every store applies ────────────────────────────────────────────
|
|
40
|
+
/** State keys with this prefix last for one invocation and are never stored. */
|
|
41
|
+
export const TEMP_STATE_PREFIX = 'temp:';
|
|
42
|
+
/**
|
|
43
|
+
* Sets an own property even when the key is `__proto__`: JSON.parse makes
|
|
44
|
+
* that an own key, and plain assignment would re-parent the object instead.
|
|
45
|
+
*/
|
|
46
|
+
function setOwn(target, key, value) {
|
|
47
|
+
Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
|
|
48
|
+
}
|
|
49
|
+
/** A copy of `record` without its `temp:` keys, in the same key order. */
|
|
50
|
+
export function withoutTempKeys(record) {
|
|
51
|
+
const out = {};
|
|
52
|
+
for (const [key, value] of Object.entries(record))
|
|
53
|
+
if (!key.startsWith(TEMP_STATE_PREFIX))
|
|
54
|
+
setOwn(out, key, value);
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Applies one event to a live session, as ADK's BaseSessionService does,
|
|
59
|
+
* and returns the event as a store keeps it:
|
|
60
|
+
* 1. A partial event is returned as it is, and the session is untouched.
|
|
61
|
+
* 2. The stored event's `stateDelta` loses its `temp:` keys (a copy; the
|
|
62
|
+
* given event is never changed).
|
|
63
|
+
* 3. Each remaining delta key is written into `session.state`.
|
|
64
|
+
* 4. The event replaces the session's event with the same id, or is
|
|
65
|
+
* appended.
|
|
66
|
+
* 5. `session.lastUpdateTime` becomes the event's timestamp.
|
|
67
|
+
*/
|
|
68
|
+
export function applyEvent(session, event) {
|
|
69
|
+
if (event.partial)
|
|
70
|
+
return event;
|
|
71
|
+
let stored = event;
|
|
72
|
+
const delta = event.actions?.stateDelta;
|
|
73
|
+
if (delta) {
|
|
74
|
+
const kept = withoutTempKeys(delta);
|
|
75
|
+
if (Object.keys(kept).length !== Object.keys(delta).length) {
|
|
76
|
+
stored = { ...event, actions: { ...event.actions, stateDelta: kept } };
|
|
77
|
+
}
|
|
78
|
+
for (const [key, value] of Object.entries(kept))
|
|
79
|
+
setOwn(session.state, key, value);
|
|
80
|
+
}
|
|
81
|
+
const at = session.events.findIndex((e) => e.id === stored.id);
|
|
82
|
+
if (at >= 0)
|
|
83
|
+
session.events[at] = stored;
|
|
84
|
+
else
|
|
85
|
+
session.events.push(stored);
|
|
86
|
+
session.lastUpdateTime = stored.timestamp;
|
|
87
|
+
return stored;
|
|
88
|
+
}
|
|
89
|
+
/** A finite number, rounded down; undefined otherwise. */
|
|
90
|
+
function whole(n) {
|
|
91
|
+
return typeof n === 'number' && Number.isFinite(n) ? Math.floor(n) : undefined;
|
|
92
|
+
}
|
|
93
|
+
/** The events a read with `options` returns, oldest first (GetSessionOptions). */
|
|
94
|
+
export function selectEvents(events, options = {}) {
|
|
95
|
+
let out = [...events];
|
|
96
|
+
const after = options.afterTimestamp;
|
|
97
|
+
if (after)
|
|
98
|
+
out = out.filter((e) => e.timestamp > after);
|
|
99
|
+
const n = whole(options.numRecentEvents);
|
|
100
|
+
if (n !== undefined && n > 0)
|
|
101
|
+
out = out.slice(-n);
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The window a list request asks for: a zero-based offset and, when a limit
|
|
106
|
+
* was given, the page size. `page` wins over `offset` only beside a limit.
|
|
107
|
+
*/
|
|
108
|
+
export function listWindow(request) {
|
|
109
|
+
const limitRaw = whole(request.limit);
|
|
110
|
+
const limit = limitRaw === undefined ? undefined : Math.max(0, limitRaw);
|
|
111
|
+
const page = whole(request.page);
|
|
112
|
+
const offset = limit !== undefined && page !== undefined ? (Math.max(1, page) - 1) * limit : Math.max(0, whole(request.offset) ?? 0);
|
|
113
|
+
return limit === undefined ? { offset } : { offset, limit };
|
|
114
|
+
}
|
|
115
|
+
/** The paging figures a list result reports, given how many sessions matched. */
|
|
116
|
+
export function listPage(totalItems, request) {
|
|
117
|
+
const { offset, limit } = listWindow(request);
|
|
118
|
+
return {
|
|
119
|
+
page: limit ? Math.floor(offset / limit) + 1 : 1,
|
|
120
|
+
limit: limit ?? totalItems,
|
|
121
|
+
totalItems,
|
|
122
|
+
totalPages: limit ? Math.max(1, Math.ceil(totalItems / limit)) : 1,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Sessions held in this process, lost when it exits: the store for a
|
|
127
|
+
* syndicate with no durable one, and for tests. Every read hands out a copy
|
|
128
|
+
* and every append stores a copy, so no caller shares an object with the
|
|
129
|
+
* store. An append to a session the store does not hold (deleted while its
|
|
130
|
+
* turn ran) keeps the caller's session as it stands after the event.
|
|
131
|
+
*/
|
|
132
|
+
export class InProcessSessionService {
|
|
133
|
+
sessions = new Map();
|
|
134
|
+
now;
|
|
135
|
+
constructor(options = {}) {
|
|
136
|
+
this.now = options.now ?? Date.now;
|
|
137
|
+
}
|
|
138
|
+
static key(appName, userId, sessionId) {
|
|
139
|
+
return JSON.stringify([appName, userId, sessionId]);
|
|
140
|
+
}
|
|
141
|
+
async create(request) {
|
|
142
|
+
const id = request.sessionId || globalThis.crypto.randomUUID();
|
|
143
|
+
const key = InProcessSessionService.key(request.appName, request.userId, id);
|
|
144
|
+
const existing = this.sessions.get(key);
|
|
145
|
+
if (existing)
|
|
146
|
+
return structuredClone(existing);
|
|
147
|
+
const session = {
|
|
148
|
+
id,
|
|
149
|
+
appName: request.appName,
|
|
150
|
+
userId: request.userId,
|
|
151
|
+
state: withoutTempKeys(structuredClone(request.state ?? {})),
|
|
152
|
+
events: [],
|
|
153
|
+
lastUpdateTime: this.now(),
|
|
154
|
+
};
|
|
155
|
+
this.sessions.set(key, session);
|
|
156
|
+
return structuredClone(session);
|
|
157
|
+
}
|
|
158
|
+
async get(key, options) {
|
|
159
|
+
const held = this.sessions.get(InProcessSessionService.key(key.appName, key.userId, key.sessionId));
|
|
160
|
+
if (!held)
|
|
161
|
+
return undefined;
|
|
162
|
+
const copy = structuredClone(held);
|
|
163
|
+
copy.events = selectEvents(copy.events, options);
|
|
164
|
+
return copy;
|
|
165
|
+
}
|
|
166
|
+
async list(request) {
|
|
167
|
+
const matching = [...this.sessions.values()].filter((s) => s.appName === request.appName && (request.userId === undefined || s.userId === request.userId));
|
|
168
|
+
if (request.order) {
|
|
169
|
+
const sign = request.order === 'asc' ? 1 : -1;
|
|
170
|
+
matching.sort((a, b) => sign * (a.lastUpdateTime - b.lastUpdateTime) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
171
|
+
}
|
|
172
|
+
const { offset, limit } = listWindow(request);
|
|
173
|
+
const window = matching.slice(offset, limit === undefined ? undefined : offset + limit);
|
|
174
|
+
return {
|
|
175
|
+
sessions: window.map((s) => ({
|
|
176
|
+
id: s.id,
|
|
177
|
+
appName: s.appName,
|
|
178
|
+
userId: s.userId,
|
|
179
|
+
state: structuredClone(s.state),
|
|
180
|
+
events: [],
|
|
181
|
+
lastUpdateTime: s.lastUpdateTime,
|
|
182
|
+
})),
|
|
183
|
+
...listPage(matching.length, request),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async delete(key) {
|
|
187
|
+
this.sessions.delete(InProcessSessionService.key(key.appName, key.userId, key.sessionId));
|
|
188
|
+
}
|
|
189
|
+
async append(session, event) {
|
|
190
|
+
if (event.partial)
|
|
191
|
+
return event;
|
|
192
|
+
const stored = applyEvent(session, event);
|
|
193
|
+
const key = InProcessSessionService.key(session.appName, session.userId, session.id);
|
|
194
|
+
const held = this.sessions.get(key);
|
|
195
|
+
if (held)
|
|
196
|
+
applyEvent(held, structuredClone(stored));
|
|
197
|
+
else
|
|
198
|
+
this.sessions.set(key, structuredClone(session));
|
|
199
|
+
return stored;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -25,9 +25,25 @@
|
|
|
25
25
|
* subagents, nested syndicates), an optional deadline bounds wall-clock
|
|
26
26
|
* time, and an outer AbortSignal cancels it. All three abort the provider
|
|
27
27
|
* request in flight, not just the loop around it.
|
|
28
|
+
*
|
|
29
|
+
* ── Runtimes (ADR 0045, ADR 0073) ─────────────────────────────────────────
|
|
30
|
+
* Each agent of a turn runs on ADK's Runner (the default) or on the
|
|
31
|
+
* engine's own agent loop: the turn's `runtime` option, else
|
|
32
|
+
* MELCHIZEDEK_RUNTIME. Both compile the same AgentSpec (lib/compile.ts),
|
|
33
|
+
* store the same events and drain through drainAgentStream, so everything
|
|
34
|
+
* else here is shared. What native does not run yet fails before any model
|
|
35
|
+
* call, naming the feature (lib/runtime/nativeTurn.ts).
|
|
28
36
|
*/
|
|
29
37
|
import type { BasePlugin } from '@google/adk';
|
|
30
38
|
import type { BaseMemoryService, BaseSessionService, Event, LlmAgent } from '@google/adk';
|
|
39
|
+
import type { RuntimeName } from './runtimeFlag.ts';
|
|
40
|
+
import type { ToolCredentials } from '../tools/oauthConsent.ts';
|
|
41
|
+
import type { PendingConsent } from './credentials.ts';
|
|
42
|
+
export { CREDENTIAL_REQUEST, credentialResponsePart, describeConsent, pendingConsent } from './credentials.ts';
|
|
43
|
+
export type { PendingConsent } from './credentials.ts';
|
|
44
|
+
export type { ToolCredentials } from '../tools/oauthConsent.ts';
|
|
45
|
+
export { chooseRuntime, runtimeSetting, DEFAULT_RUNTIME, RUNTIMES, UnsupportedOnRuntimeError } from './runtimeFlag.ts';
|
|
46
|
+
export type { RuntimeName } from './runtimeFlag.ts';
|
|
31
47
|
import type { PendingInput } from '../workflow.ts';
|
|
32
48
|
export { describeInput } from '../workflow.ts';
|
|
33
49
|
export type { PendingInput } from '../workflow.ts';
|
|
@@ -93,8 +109,15 @@ export interface SyndicateTurnOptions {
|
|
|
93
109
|
memoryService?: BaseMemoryService;
|
|
94
110
|
/** Model resolution, unknown-tool handling, nested loading. */
|
|
95
111
|
compile?: CompileOptions;
|
|
96
|
-
/** Applied to every compiled agent before it runs (eval tool replay). */
|
|
112
|
+
/** Applied to every compiled agent before it runs (eval tool replay). ADK runtime only. */
|
|
97
113
|
transformAgent?: (agent: LlmAgent) => LlmAgent;
|
|
114
|
+
/**
|
|
115
|
+
* The runtime that runs the turn's agents: `adk` (Google ADK's Runner) or
|
|
116
|
+
* `native` (the engine's own loop). Default: MELCHIZEDEK_RUNTIME, else
|
|
117
|
+
* `adk`. A feature native does not run yet throws UnsupportedOnRuntimeError
|
|
118
|
+
* before any model call.
|
|
119
|
+
*/
|
|
120
|
+
runtime?: RuntimeName;
|
|
98
121
|
/** Plan-dispatch only: skip the classifier and run this route. Overrides
|
|
99
122
|
* in the YAML still win, as they do in production. */
|
|
100
123
|
forceRoute?: string;
|
|
@@ -109,6 +132,15 @@ export interface SyndicateTurnOptions {
|
|
|
109
132
|
/** Root-span metadata; `false` disables tracing for the turn. */
|
|
110
133
|
trace?: TraceOptions | false;
|
|
111
134
|
events?: TurnEvents;
|
|
135
|
+
/**
|
|
136
|
+
* The turn's tool credentials (ADR 0072) and consent step (ADR 0085), on
|
|
137
|
+
* the native runtime. The store is pinned to `appName`; a tool reads the
|
|
138
|
+
* grant of `userId` only. With `consent`, a call whose provider the user
|
|
139
|
+
* has not granted pauses the turn input-required (`result.consent`), and
|
|
140
|
+
* the next message after the grant resumes it. Omitted: tools have no
|
|
141
|
+
* `accessToken`, as before.
|
|
142
|
+
*/
|
|
143
|
+
toolCredentials?: ToolCredentials;
|
|
112
144
|
}
|
|
113
145
|
/** What one agent's event stream amounted to. */
|
|
114
146
|
export interface DrainedRun {
|
|
@@ -159,8 +191,9 @@ export interface DrainedRun {
|
|
|
159
191
|
export type TurnStage = 'classify' | 'dispatch' | 'delegate' | 'workflow';
|
|
160
192
|
export interface RouteDecision extends RouteResolution {
|
|
161
193
|
/** `approval`: the turn resumed the route that asked for an approval (ADR 0028).
|
|
162
|
-
* `answer`: the message answered the route's open `ask_user` question.
|
|
163
|
-
|
|
194
|
+
* `answer`: the message answered the route's open `ask_user` question.
|
|
195
|
+
* `consent`: the turn resumed the route whose call waited for an OAuth grant (ADR 0085). */
|
|
196
|
+
decidedBy: 'override' | 'forced' | 'classifier' | 'approval' | 'answer' | 'consent';
|
|
164
197
|
}
|
|
165
198
|
export interface SyndicateTurnResult {
|
|
166
199
|
/** completed: an answer was produced. failed: an error, a deadline or the
|
|
@@ -173,6 +206,10 @@ export interface SyndicateTurnResult {
|
|
|
173
206
|
/** The question a workflow's `ask_user` node asked, when status is
|
|
174
207
|
* input-required. The next message on the conversation is the answer. */
|
|
175
208
|
input?: PendingInput;
|
|
209
|
+
/** The OAuth grant a paused call waits for, when status is input-required
|
|
210
|
+
* (ADR 0085): the person opens `consent.authUri`; their next message after
|
|
211
|
+
* the grant is stored resumes the call. */
|
|
212
|
+
consent?: PendingConsent;
|
|
176
213
|
/** The text the user receives (relay fallback and guards applied). */
|
|
177
214
|
text: string;
|
|
178
215
|
error?: {
|
|
@@ -207,8 +244,7 @@ export interface TurnUsage {
|
|
|
207
244
|
outputTokens: number;
|
|
208
245
|
thinkingTokens: number;
|
|
209
246
|
}
|
|
210
|
-
export
|
|
211
|
-
export declare const DEFAULT_TOOL_ERROR_RETRIES = 3;
|
|
247
|
+
export { DEFAULT_MODEL_ERROR_RETRIES, DEFAULT_TOOL_ERROR_RETRIES } from './native/selfCorrection.ts';
|
|
212
248
|
/**
|
|
213
249
|
* ADK's reflect-and-retry plugins, on by default. The model plugin turns a
|
|
214
250
|
* reply ADK marks malformed (MALFORMED_FUNCTION_CALL) into a retry with
|