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
package/DOCUMENTATION.md
CHANGED
|
@@ -28,8 +28,10 @@ config/agents/examples/ the starter pack — shipped example syndicates
|
|
|
28
28
|
lib/loadSyndicate.ts YAML → validated config (+ variable binding)
|
|
29
29
|
lib/dispatch.ts plan-dispatch route resolution (§6)
|
|
30
30
|
lib/toolRegistry.ts tool name → live ADK tool instance
|
|
31
|
-
lib/models/
|
|
31
|
+
lib/models/claudeAdapter.ts Claude on the engine's model contract
|
|
32
|
+
lib/models/claudeLlm.ts that adapter behind the ADK shim, in the ADK registry
|
|
32
33
|
lib/models/ollamaLlm.ts open-weight local adapter (Ollama, keyless)
|
|
34
|
+
lib/models/chatCompletionsAdapter.ts the chat-completions wire on the model contract
|
|
33
35
|
lib/tools/mcpToolFactory.ts MCP client: remote tools → live ADK tools
|
|
34
36
|
scripts/demo_mcp_server.ts demo MCP server (library catalog, SSE)
|
|
35
37
|
lib/session/… Supabase-backed session service
|
|
@@ -52,6 +54,21 @@ subagents as `AgentTool`s and tool names through the registry → the ADK
|
|
|
52
54
|
on session end, the memory service distills the transcript into tagged
|
|
53
55
|
facts, embeds them (768-d), and stores them for future recall.
|
|
54
56
|
|
|
57
|
+
The compiler (`lib/compile.ts`) first builds a runtime-neutral `AgentSpec`
|
|
58
|
+
per agent; `lib/compileAdk.ts` turns it into the `LlmAgent`, and
|
|
59
|
+
`lib/compileNative.ts` into the engine's own loop's agent. ADK runs every
|
|
60
|
+
turn by default. `MELCHIZEDEK_RUNTIME=native`, or `runtime: 'native'` on
|
|
61
|
+
`runSyndicateTurn`, runs a single-agent, delegating or plan-dispatch
|
|
62
|
+
syndicate on the native loop with the same result and the same stored
|
|
63
|
+
events, `context:` compaction and `mode: task` included
|
|
64
|
+
([ADR 0078](./wiki/decisions/0078-native-compaction-ports-adk-compactor.md)),
|
|
65
|
+
and a `workflow:` syndicate on the engine's own scheduler, its pause and
|
|
66
|
+
resume included
|
|
67
|
+
([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md));
|
|
68
|
+
what it does not run yet throws `UnsupportedOnRuntimeError` before any
|
|
69
|
+
model call
|
|
70
|
+
([ADR 0073](./wiki/decisions/0073-one-agent-spec-and-a-runtime-flag.md)).
|
|
71
|
+
|
|
55
72
|
## 2. The syndicate YAML
|
|
56
73
|
|
|
57
74
|
Minimal complete example:
|
|
@@ -72,11 +89,9 @@ orchestrator:
|
|
|
72
89
|
You are the Conductor… (persona, objective, workflow contract)
|
|
73
90
|
tools:
|
|
74
91
|
- "google_search" # names resolved via lib/toolRegistry.ts
|
|
92
|
+
reasoning: medium # none | low | medium | high, or { budget_tokens: 4096 }
|
|
75
93
|
generateContentConfig:
|
|
76
94
|
maxOutputTokens: 4096
|
|
77
|
-
thinkingConfig:
|
|
78
|
-
thinkingLevel: "MEDIUM" # or thinkingBudget on older models
|
|
79
|
-
includeThoughts: true
|
|
80
95
|
|
|
81
96
|
subagents:
|
|
82
97
|
- name: "Researcher"
|
|
@@ -104,7 +119,8 @@ Field reference:
|
|
|
104
119
|
| `name` / `model` / `instruction` | agent | The agent triple. Any Gemini id, `claude-*`, or `ollama/*` for open-weight local models (see §5). |
|
|
105
120
|
| `description` | subagent | **The delegation API.** The orchestrator reads this when deciding to hand off — write it like a function signature ("Use this subagent to…, pass it…"). |
|
|
106
121
|
| `tools` | agent | Names resolved by the tool registry (§3). Long-term memory agents add `preload_memory` / `load_memory`. |
|
|
107
|
-
| `
|
|
122
|
+
| `reasoning` | agent | How hard the agent reasons, on any provider: `none`, `low`, `medium`, `high`, or `{ budget_tokens: <int> }`. The compiler sends each provider the field it reads: a thinking level on Gemini 3, a thinking budget on Claude 4.6 and earlier (2,048 / 8,192 / 16,384 tokens for low / medium / high), adaptive thinking with that effort on later Claude models ([ADR 0049](./wiki/decisions/0049-claude-requests-by-model-generation.md)), an effort word on GPT, Grok, Kimi, Ollama and the gateway ([ADR 0047](./wiki/decisions/0047-provider-neutral-reasoning-key.md)). Unset, each adapter keeps its own default. |
|
|
123
|
+
| `generateContentConfig` | agent | Temperature, output caps. Its `thinkingConfig` and `reasoningEffort` are the older, provider-specific spelling of `reasoning`; setting either next to `reasoning` is a load error. |
|
|
108
124
|
| `outputSchema` | agent | Structured-JSON contract. **Constraint:** an agent holding `outputSchema` cannot also hold transfer powers — the ADK deadlocks it. Keep schema-holders as leaf agents (see `critic.yaml`'s header comment for the war story). |
|
|
109
125
|
| `yaml_reference` | subagent | Mount another syndicate file as a nested subagent. |
|
|
110
126
|
| `a2a_agent_url` | subagent | A REMOTE agent over A2A (§6): the orchestrator delegates to it with one `request` argument; in plan-dispatch it can be a route. No `model`/`instruction` — the remote agent has its own. Credentials come from `A2A_AGENT_TOKENS`, never YAML. |
|
|
@@ -117,8 +133,8 @@ Field reference:
|
|
|
117
133
|
| `code_execution` | any Gemini agent | `"gemini"`: the model writes Python and Gemini runs it in Google's server-side sandbox, returning the output to the model; nothing runs on this host. For arithmetic, data and checks a model gets wrong in its head. Gemini models only ([ADR 0033](./wiki/decisions/0033-context-task-code.md)). |
|
|
118
134
|
| `context` | orchestrator | Compacts a long conversation: when the last request's prompt passed `compact_after_tokens`, earlier turns become one summary (written by `summary_model`, default the agent's own) and the last `keep_recent_events` stay verbatim. The full history stays stored; only what the model reads shrinks. The orchestrator of a delegate syndicate only: a dispatch route already reads a bounded projection, a workflow node sees only its input. |
|
|
119
135
|
| `mode` | workflow node | `"task"`: the agent works with its tools until it calls `finish_task`, whose arguments (matching its `outputSchema`) become the node's output. Workflow nodes only. |
|
|
120
|
-
| `examples` | any agent | Few-shot exchanges, `[{ input, output }]` (up to 20), added to every request's instruction
|
|
121
|
-
| `skills` | any agent | Agent Skills (a directory of SKILL.md folders) the agent holds the way a coding harness does: every skill's name and description is appended to its instruction at compile time; `load_skill` reads one in full with the names of its files, `load_skill_resource` reads one file. `scripts: local` adds `run_skill_script`, which runs a skill's own scripts on this machine, each after a person approves (the `require_approval` pause); `tools:` names registry tools a skill's `allowed-tools` may unlock once loaded. Worked example: `examples/harness.yaml`; engine: `lib/tools/skillToolset.ts
|
|
136
|
+
| `examples` | any agent | Few-shot exchanges, `[{ input, output }]` (up to 20), added to every request's instruction as a few-shot block, the one ADK's `ExampleTool` wrote (an Instruction tool, `lib/tools/examples.ts`); the model never calls it. Keeps worked examples out of the prose of `instruction`. |
|
|
137
|
+
| `skills` | any agent | Agent Skills (a directory of SKILL.md folders) the agent holds the way a coding harness does: every skill's name and description is appended to its instruction at compile time; `load_skill` reads one in full with the names of its files, `load_skill_resource` reads one file. `scripts: local` adds `run_skill_script`, which runs a skill's own scripts on this machine, each after a person approves (the `require_approval` pause), with PATH, HOME, the temp directory and the locale but none of the server's keys, plus the variable names listed under `env:` (or `secret_env:` for a secret-shaped name, ADR 0086), and stdout and stderr each cut at 20,000 characters; `tools:` names registry tools a skill's `allowed-tools` may unlock once loaded. Worked example: `examples/harness.yaml`; engine: `lib/tools/skillToolset.ts` over `lib/tools/skills/`, the same on both runtimes. |
|
|
122
138
|
|
|
123
139
|
Validation happens at load: missing names, legacy option blocks, and
|
|
124
140
|
malformed agents fail with pointed errors before any model is called.
|
|
@@ -128,28 +144,37 @@ skipped with a warning at compile time.
|
|
|
128
144
|
## 3. Tools
|
|
129
145
|
|
|
130
146
|
Registered in `lib/toolRegistry.ts` — one map from YAML name to ADK tool
|
|
131
|
-
instance
|
|
147
|
+
instance. A **Contract** is the engine's own Tool (`lib/tools/tool.ts`),
|
|
148
|
+
defined once with `defineTool` and handed to the ADK runtime as a
|
|
149
|
+
`FunctionTool` by `toFunctionTool` (`lib/tools/adkTool.ts`). An
|
|
150
|
+
**Instruction tool** is the engine's own too: it declares no function and
|
|
151
|
+
only writes into each request's instruction, reaching the ADK runtime
|
|
152
|
+
through `toAdkInstructionTool`. A **server-side tool** is an own marker
|
|
153
|
+
(`lib/tools/nativeTools.ts`) that names the provider's tool and declares no
|
|
154
|
+
function; the ADK runtime runs its sentinel (`toAdkNativeTool`), and every
|
|
155
|
+
adapter recognises it by marker ([ADR 0062](./wiki/decisions/0062-server-side-tools-as-markers.md)):
|
|
132
156
|
|
|
133
157
|
| Name | Kind | Does |
|
|
134
158
|
|---|---|---|
|
|
135
159
|
| `web_search` | Provider-agnostic | Live web search via the agent model's NATIVE search: Gemini grounding, Anthropic `web_search` server tool, OpenAI Responses `web_search`, xAI Agent Tools `web_search`. On local `ollama/*` models, and on `kimi-*` (Moonshot's model-side search retires 2026-10-20; its successor is a REST API, not a request field), the tool is omitted with a one-time warning (keyless stays keyless). On grok-* agents, optional server-side domain filters via `XAI_WEB_SEARCH_ALLOWED_DOMAINS` / `_EXCLUDED_DOMAINS` in `.env` (max 5, mutually exclusive; xAI accepts no date bounds — those are `x_search`-only). Prefer this in new YAMLs. |
|
|
136
|
-
| `web_extract` |
|
|
160
|
+
| `web_extract` | Contract | Deterministic page reading: fetches 1–5 agent-chosen URLs and returns clean page text (no LLM summarization). Keyless — works on every provider including local `ollama/*`. Per-page char budget (default 15k, `WEB_EXTRACT_CHAR_LIMIT`); long pages return a head+tail window with an `offset` continuation call served from a 15-minute cache. SSRF-guarded (http(s) only, private/link-local hosts refused, redirects re-checked). Block pages (bot checks, paywall stubs, JS shells) are detected code-side and returned as labeled `Error:` blocks, never as content. Pair with `web_search`: search to find, extract to read past the headline. |
|
|
137
161
|
| `x_search` | xAI-only | Live search over X (Twitter) posts via xAI Agent Tools. Self-gates to `grok-*` agents; a silent no-op on every other provider, so mixed-provider YAMLs stay safe. Optional server-side constraints in `.env`: `XAI_X_SEARCH_FROM_DATE`/`_TO_DATE` (inclusive `YYYY-MM-DD`) and `_ALLOWED_HANDLES`/`_EXCLUDED_HANDLES` (max 20, mutually exclusive — allowlist wins). |
|
|
138
162
|
| `collections_search` | xAI-only | Semantic search over xAI **Collections** — hosted document stores (PDFs/text/CSVs) uploaded at console.x.ai — server-side RAG with `collections://…` citations. Which collections: `XAI_COLLECTION_IDS` in `.env` (optional `XAI_COLLECTIONS_MAX_RESULTS`). Declared with no ids → omitted with a warning; non-xAI providers → silent no-op. |
|
|
139
163
|
| `url_context` | Gemini built-in | Gemini reads the pages at URLs in the conversation, server-side (Google fetches them, not this host). On any other provider it is a no-op the doctor reports as dropped; use `web_extract` there. |
|
|
140
164
|
| `google_search` | ADK built-in | Live web search — Gemini agents only (legacy alias; use `web_search`). |
|
|
141
|
-
| `preload_memory` |
|
|
142
|
-
| `load_memory` |
|
|
143
|
-
| `generate_image` |
|
|
144
|
-
| `inspect_image` |
|
|
145
|
-
| `task_add` / `task_list` / `task_get` / `task_update` |
|
|
146
|
-
| `ask_user` |
|
|
147
|
-
| `task_queue` |
|
|
165
|
+
| `preload_memory` | Instruction tool | Silently injects similarity-matched facts into every request's instruction (ambient recall). The model never calls it. |
|
|
166
|
+
| `load_memory` | Contract | Explicit tool call to search the fact store (deliberate recall). Both memory tools read the caller's own silo only and send the model what ADK's tools of the same names sent ([ADR 0059](./wiki/decisions/0059-memory-on-the-engines-own-interfaces.md)). |
|
|
167
|
+
| `generate_image` | Contract | Calls the Gemini image model directly, saves the result under `outputs/`, returns the path. A function tool because binary `inlineData` cannot survive the AgentTool text boundary. |
|
|
168
|
+
| `inspect_image` | Contract | **Blind visual inventory** of a file under `outputs/`: subjects with exact counts, composition, light, palette, medium cues, artifacts — zero quality judgments. Its signature accepts *only* a file path, so an orchestrator cannot leak expectations into the observation (see `image_production.yaml`). |
|
|
169
|
+
| `task_add` / `task_list` / `task_get` / `task_update` | Contract | A to-do list and job queue. Default: a single-user JSON file (`MELCHIZEDEK_TASKS_FILE`, default `outputs/tasks.json`), so every caller of a shared endpoint shares one list. With `DATABASE_URL` (migration 0009) each caller has its own list, scoped by the caller's scope key, and any number of workers take jobs safely. |
|
|
170
|
+
| `ask_user` | Contract, long-running | Asks the person one question (optionally with `options`) and ends the turn `input-required`; the next message on the conversation is the call's result. Orchestrator or plan-dispatch route only (§6, Questions). |
|
|
171
|
+
| `task_queue` | Contract | Queues a background job (a self-contained instruction). The tool only writes the queue; `npm run assistant:worker` (`melchizedek-worker`) claims each job, runs it through one agent compiled from YAML (default: the Assistant's Worker), and writes the result back for `task_get`. `--once` drains and exits, for cron. |
|
|
148
172
|
|
|
149
173
|
**MCP tools** are the exception to the registry: a subagent with
|
|
150
174
|
`mcp_server_url:` in its YAML gets its tools from a remote MCP server at
|
|
151
175
|
load time. `lib/tools/mcpToolFactory.ts` dials the server over SSE,
|
|
152
|
-
lists its tools, and
|
|
176
|
+
lists its tools, and makes each one an own Tool (`loadMcpTools`), which
|
|
177
|
+
the ADK runtime runs as a `FunctionTool` (`createMcpTools`) — the
|
|
153
178
|
agent's reach is decided by the server, not compiled in.
|
|
154
179
|
`config/agents/examples/librarian.yaml` plus the demo catalog server
|
|
155
180
|
(`npm run mcp:demo`, `scripts/demo_mcp_server.ts`) are the worked
|
|
@@ -160,8 +185,10 @@ treat any remote MCP server as an untrusted tool vendor whose results
|
|
|
160
185
|
are data, never instructions.
|
|
161
186
|
|
|
162
187
|
**OpenAPI tools** turn any HTTP API with an OpenAPI 3 spec into an
|
|
163
|
-
agent's tools, with no tool code (`lib/tools/openapiTools.ts`, on
|
|
164
|
-
|
|
188
|
+
agent's tools, with no tool code (`lib/tools/openapiTools.ts`, on the
|
|
189
|
+
engine's own parser and caller in `lib/tools/openapi/`;
|
|
190
|
+
[ADR 0032](./wiki/decisions/0032-openapi-tools.md),
|
|
191
|
+
[ADR 0067](./wiki/decisions/0067-openapi-calls-on-the-engines-own-caller.md)):
|
|
165
192
|
|
|
166
193
|
```yaml
|
|
167
194
|
orchestrator:
|
|
@@ -190,7 +217,10 @@ may name. A refused or unset variable fails the compile, and a static token is a
|
|
|
190
217
|
never stored in session state. Every server must be http(s) and pass the
|
|
191
218
|
SSRF guard: its literal rules when the agent compiles, the full check with
|
|
192
219
|
DNS before each call; `ALLOW_PRIVATE_OPENAPI=true` permits private hosts for
|
|
193
|
-
local development.
|
|
220
|
+
local development. Redirects are followed one hop at a time, each hop held
|
|
221
|
+
to the guard, and a hop to another origin carries no credential. A
|
|
222
|
+
credential's value never appears in an error the model reads. Only OpenAPI
|
|
223
|
+
3.x specs are read. A response over 20,000 characters is cut and says so; a
|
|
194
224
|
network failure comes back to the model as an error. Specs are files, never
|
|
195
225
|
URLs: save the spec beside the YAML and review it like code (trim it to the
|
|
196
226
|
operations the agent needs, and write each `summary` for the model). Worked
|
|
@@ -311,12 +341,12 @@ accordingly — model optionality is a single YAML line per agent:
|
|
|
311
341
|
| Model id | Provider | Adapter | Key | Native `web_search` |
|
|
312
342
|
|---|---|---|---|---|
|
|
313
343
|
| `gemini-*` | Google Gemini | ADK-native (`TracedGemini`) | `GOOGLE_GENAI_API_KEY` | ✅ grounding |
|
|
314
|
-
| `claude-*` | Anthropic | `lib/models/
|
|
315
|
-
| `gpt-*`, o-series | OpenAI | `lib/models/gptLlm.ts` (Responses API) | `OPENAI_API_KEY` | ✅ web_search tool |
|
|
316
|
-
| `grok-*` | xAI | `lib/models/grokLlm.ts` (Responses API) | `XAI_API_KEY` | ✅ Agent Tools search |
|
|
317
|
-
| `kimi-*` | Moonshot AI (Kimi) | `lib/models/kimiLlm.ts` (chat completions) | `MOONSHOT_API_KEY` | ⚠ omitted + warning |
|
|
318
|
-
| `ollama/*` | Local Ollama | `lib/models/ollamaLlm.ts` | none | ⚠ omitted + warning |
|
|
319
|
-
| *any cloud id whose direct key is absent* | the id's own provider, via a gateway | `lib/models/gatewayLlm.ts` (chat completions) | `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` | ⚠ omitted + reported |
|
|
344
|
+
| `claude-*` | Anthropic | `lib/models/claudeAdapter.ts` (Messages API; `ClaudeLlm` is its ADK shim) | `ANTHROPIC_API_KEY` | ✅ server tool |
|
|
345
|
+
| `gpt-*`, o-series | OpenAI | `lib/models/gptLlm.ts` around `gptAdapter.ts` (Responses API) | `OPENAI_API_KEY` | ✅ web_search tool |
|
|
346
|
+
| `grok-*` | xAI | `lib/models/grokLlm.ts` around `grokAdapter.ts` (Responses API) | `XAI_API_KEY` | ✅ Agent Tools search |
|
|
347
|
+
| `kimi-*` | Moonshot AI (Kimi) | `lib/models/kimiLlm.ts` around `kimiAdapter.ts` (chat completions) | `MOONSHOT_API_KEY` | ⚠ omitted + warning |
|
|
348
|
+
| `ollama/*` | Local Ollama | `lib/models/ollamaLlm.ts` around `ollamaAdapter.ts` (chat completions) | none | ⚠ omitted + warning |
|
|
349
|
+
| *any cloud id whose direct key is absent* | the id's own provider, via a gateway | `lib/models/gatewayLlm.ts` around `gatewayAdapter.ts` (chat completions) | `MODEL_GATEWAY` + `MODEL_GATEWAY_API_KEY` | ⚠ omitted + reported |
|
|
320
350
|
|
|
321
351
|
The xAI adapter carries the deepest capability surface: `grok-4.5`
|
|
322
352
|
requests pin `reasoning.effort: "medium"` (`lib/config.ts`), SSE
|
|
@@ -326,8 +356,9 @@ structured outputs ride `outputSchema` → `text.format`, and two
|
|
|
326
356
|
xAI-only tools — `x_search` and `collections_search` (§3) — turn on
|
|
327
357
|
live X search and hosted-document RAG. All verified live on grok-4.5.
|
|
328
358
|
|
|
329
|
-
**Moonshot AI (Kimi).** `kimi-*` ids route to `lib/models/kimiLlm.ts`,
|
|
330
|
-
|
|
359
|
+
**Moonshot AI (Kimi).** `kimi-*` ids route to `lib/models/kimiLlm.ts`, the
|
|
360
|
+
ADK shim around `KimiAdapter` (`lib/models/kimiAdapter.ts`, on the
|
|
361
|
+
chat-completions base), against `https://api.moonshot.ai/v1`
|
|
331
362
|
(`MOONSHOT_BASE_URL` for a proxy). Get a key at platform.moonshot.ai; the
|
|
332
363
|
`.cn` console serves mainland China. The family (USD per 1M tokens, October
|
|
333
364
|
2026): `kimi-k3`, the flagship — 2.8T-parameter open-weight MoE, 1M context,
|
|
@@ -348,11 +379,12 @@ document it; K2.6 is unstable on `$ref`/`oneOf`), SSE streaming, images as
|
|
|
348
379
|
base64 (Moonshot takes no public image URLs), MCP tools (they are function
|
|
349
380
|
tools to the model), `reasoning_content` surfaced as THINKING. Reasoning:
|
|
350
381
|
K3 takes a top-level `reasoning_effort` (`low` | `high` | `max`); the adapter
|
|
351
|
-
pins `DEFAULT_KIMI_REASONING_EFFORT` (`high`, `lib/config.ts`) unless
|
|
352
|
-
`
|
|
353
|
-
`low` because K3 cannot stop
|
|
354
|
-
|
|
355
|
-
sends `disabled`, and any effort value is dropped from
|
|
382
|
+
pins `DEFAULT_KIMI_REASONING_EFFORT` (`high`, `lib/config.ts`) unless the
|
|
383
|
+
agent's `reasoning:` says otherwise (`medium` is sent as `high`, which K3
|
|
384
|
+
has in its place), and maps `none` to `low` because K3 cannot stop
|
|
385
|
+
thinking. K2.x models take a `thinking: { type }` switch instead:
|
|
386
|
+
`reasoning: none` sends `disabled`, and any effort value is dropped from
|
|
387
|
+
the body. What does
|
|
356
388
|
not: native `web_search` (dropped with a warning; `web_extract` works, and
|
|
357
389
|
Moonshot's standalone `POST /v1/tools/search`, billed per call, could back
|
|
358
390
|
a client-side tool), and thinking carried across a tool loop (Moonshot asks
|
|
@@ -436,13 +468,64 @@ prompt to every available provider, printing input, thinking (qwen3
|
|
|
436
468
|
`<think>` blocks, Claude extended thinking, GPT reasoning summaries,
|
|
437
469
|
Grok reasoning, Kimi reasoning_content), output, and a per-request token/latency trace; add
|
|
438
470
|
`-- --search` to watch four native web searches plus the local
|
|
439
|
-
omission. Providers without keys are skipped, never fatal.
|
|
471
|
+
omission. Providers without keys are skipped, never fatal. Each agent
|
|
472
|
+
runs as a one-agent syndicate through `runSyndicateTurn`, so
|
|
473
|
+
`MELCHIZEDEK_RUNTIME=native npm run demo:models` runs the same demo on
|
|
474
|
+
the engine's own loop.
|
|
440
475
|
|
|
441
476
|
Reasoning/thinking: scratchpads from every provider are surfaced as
|
|
442
|
-
dimmed THINKING output and kept out of session history. On Claude,
|
|
443
|
-
`
|
|
444
|
-
|
|
445
|
-
|
|
477
|
+
dimmed THINKING output and kept out of session history. On Claude, any
|
|
478
|
+
`reasoning:` other than `none` (or the older
|
|
479
|
+
`generateContentConfig.thinkingConfig.thinkingBudget`) enables Anthropic
|
|
480
|
+
extended thinking, tools included: the signed thinking blocks ride on the
|
|
481
|
+
response's parts as `providerState` and are replayed verbatim within the
|
|
482
|
+
turn's tool loop (ADR 0046). GPT's reasoning ids (o-series, `gpt-5*`) and
|
|
483
|
+
`grok-4.5`, `grok-4.6` and `grok-4.7` do the same with their encrypted
|
|
484
|
+
reasoning items.
|
|
485
|
+
Their requests send `store: false`, so the vendor keeps no copy of the
|
|
486
|
+
response (ADR 0050).
|
|
487
|
+
|
|
488
|
+
The engine's own model contract is `lib/models/contract.ts` (ADR 0048),
|
|
489
|
+
importable as `melchizedek-agents/models/contract`. It defines the message
|
|
490
|
+
format, request, response stream and adapter interface of the native
|
|
491
|
+
runtime (ADR 0045), with no `@google/*` in its import graph, and the
|
|
492
|
+
adapters move onto it in stages. `wiki/models/model-contract.md` gives
|
|
493
|
+
each field's purpose and its mapping onto every provider's wire. While ADK
|
|
494
|
+
runs the turn, an adapter on the contract runs behind `AdkShim`
|
|
495
|
+
(`melchizedek-agents/models/adkShim`), an ADK `BaseLlm` that charges each
|
|
496
|
+
call against `max_steps`, passes the turn's abort signal and opens the
|
|
497
|
+
`llm.request` span, as the ADK-path adapters do (ADR 0053).
|
|
498
|
+
GPT and Grok run on the contract already: `GptLlm` and `GrokLlm` are that
|
|
499
|
+
shim around `GptAdapter` (`melchizedek-agents/models/gptAdapter`) and
|
|
500
|
+
`GrokAdapter` (`melchizedek-agents/models/grokAdapter`), and keep the token
|
|
501
|
+
counts and server-side tool record the ledger has always had for them
|
|
502
|
+
(ADR 0056).
|
|
503
|
+
Gemini has two adapters on the contract:
|
|
504
|
+
`melchizedek-agents/models/geminiAdapter` (`GeminiAdapter`, on
|
|
505
|
+
`@google/genai` with no ADK) and, until that one passes its live parity
|
|
506
|
+
run, `melchizedek-agents/models/adkGeminiAdapter` (`AdkGeminiAdapter`,
|
|
507
|
+
a temporary wrapper that runs the request through `TracedGemini`, now in
|
|
508
|
+
`melchizedek-agents/models/tracedGemini`).
|
|
509
|
+
`resolveAdapter(modelId, { apiKey, keyProvider, endpoint, gemini })` in
|
|
510
|
+
`melchizedek-agents/models/registry` returns any id's contract adapter
|
|
511
|
+
from the same prefix table, gateway rule, BYOK scoping and endpoints as
|
|
512
|
+
`resolveModel`, with no ADK registry (ADR 0060). A Gemini id gets
|
|
513
|
+
`AdkGeminiAdapter` unless `GEMINI_ADAPTER=engine` (or `gemini: 'engine'`)
|
|
514
|
+
asks for `GeminiAdapter`. `resolveAdapterWithFallback` wraps an agent's
|
|
515
|
+
model and `fallback_model` in a `FallbackAdapter`.
|
|
516
|
+
|
|
517
|
+
`melchizedek-agents/model` is the model layer on its own, with no
|
|
518
|
+
`@google/adk` in its import graph (ADR 0068): the contract's types,
|
|
519
|
+
`ClaudeAdapter`, `GptAdapter`, `GrokAdapter`, `KimiAdapter`,
|
|
520
|
+
`OllamaAdapter`, `GatewayAdapter`, `GeminiAdapter`, the
|
|
521
|
+
`ChatCompletionsAdapter` base, `resolveAdapter`,
|
|
522
|
+
`resolveAdapterWithFallback`, `FallbackAdapter` and the circuit breaker's
|
|
523
|
+
helpers. A project that only calls models installs the package without ADK
|
|
524
|
+
and imports from there. Its `resolveAdapter` gives a Gemini id
|
|
525
|
+
`GeminiAdapter`; asking it for `adk` (`gemini: 'adk'` or
|
|
526
|
+
`GEMINI_ADAPTER=adk`) throws and names `melchizedek-agents/models/registry`,
|
|
527
|
+
whose `resolveAdapter` keeps the ADK default above. `AdkGeminiAdapter`, the
|
|
528
|
+
ADK shims, `TracedGemini` and `resolveModel` are not in it.
|
|
446
529
|
|
|
447
530
|
Every model request also emits an `llm.request` OpenTelemetry span
|
|
448
531
|
(provider, model, input/output/thinking tokens, latency). Scripts print it
|
|
@@ -461,7 +544,14 @@ full-text `search` column; `adk_telemetry` — one row per `llm.request` /
|
|
|
461
544
|
root span; and `adk_payloads` — full prompts and responses per model call,
|
|
462
545
|
kept by policy (`TELEMETRY_PAYLOADS=off|errors|sample|all`,
|
|
463
546
|
`TELEMETRY_PAYLOAD_SAMPLE`, `TELEMETRY_PAYLOAD_TTL_DAYS`) and expired by
|
|
464
|
-
`melchizedek_prune_telemetry()`.
|
|
547
|
+
`melchizedek_prune_telemetry()`. A row from a failed call's `llm.request`
|
|
548
|
+
span holds the request in the model contract's shape (`model`, `system`,
|
|
549
|
+
`messages`, `tools`, …), whichever adapter made the call; a row from ADK's
|
|
550
|
+
own `call_llm` span holds ADK's request. On the native runtime the loop
|
|
551
|
+
opens `agent.invoke <name>`, `model.call` and `tool.execute <name>` spans
|
|
552
|
+
where ADK opens `invoke_agent`, `call_llm` and `execute_tool`, and the ledger
|
|
553
|
+
reads both (ADR 0076); a clean call's row then comes from `model.call` and
|
|
554
|
+
holds the request and the adapter's response in the contract's shapes. The view `adk_turns_production` excludes
|
|
465
555
|
eval and classifier turns. Operate it with `npm run telemetry:stats`,
|
|
466
556
|
`telemetry:prune` and `telemetry:replay` (the exporter spools failed
|
|
467
557
|
batches to `outputs/telemetry-deadletter.ndjson`).
|
|
@@ -509,7 +599,7 @@ options. `demo/a2a_demo.mjs` is a complete client.
|
|
|
509
599
|
| `POST /a2a/jsonrpc`, `/a2a/rest` | bearer | the default syndicate |
|
|
510
600
|
| `GET /<agentId>/.well-known/agent-card.json` | bearer | another syndicate's card; its URLs point at `/<agentId>/a2a/...` |
|
|
511
601
|
| `POST /<agentId>/a2a/jsonrpc`, `/<agentId>/a2a/rest` | bearer | another syndicate (`A2A_SERVED_AGENTS` restricts which) |
|
|
512
|
-
| `DELETE /memory` | bearer | erase everything stored for the calling scope: facts, sessions (with subagent rows), ledger rows and
|
|
602
|
+
| `DELETE /memory` | bearer | erase everything stored for the calling scope: facts, sessions (with subagent rows), ledger rows, A2A tasks and the third-party tokens held for its tools, including conversations whose sessions have expired, with per-store counts; `?all=1` covers every memory namespace |
|
|
513
603
|
|
|
514
604
|
"bearer" means the credential `A2A_AUTH` asks for (below); with no
|
|
515
605
|
`A2A_SERVER_SECRET` and no authenticator the server binds `127.0.0.1` only.
|
|
@@ -567,8 +657,10 @@ or pass your own `resolveRequest`.
|
|
|
567
657
|
`A2A_LOG_FORMAT=json` prints every server line as JSON, this record included.
|
|
568
658
|
- **The audit trail** (`melchizedek_audit`, `db/migrations/0012_audit_log.sql`;
|
|
569
659
|
option `audit`, supplied by `postgresStorage`): one row per failed
|
|
570
|
-
authentication (`auth.failure`), task outcome (`task.end`)
|
|
571
|
-
(`memory.erase`)
|
|
660
|
+
authentication (`auth.failure`), task outcome (`task.end`), erasure
|
|
661
|
+
(`memory.erase`) and tool credential stored, refreshed, revoked or erased
|
|
662
|
+
(`credential.put`, `.refresh`, `.revoke`, `.erase`, naming the provider and
|
|
663
|
+
app, never a token), with the caller's name, the source address, the agent and
|
|
572
664
|
task ids, and a hash of the scope. Never a scope key and never conversation
|
|
573
665
|
content. A trigger refuses UPDATE and DELETE; rows leave only through
|
|
574
666
|
`SELECT melchizedek_prune_audit(<days>)`, which you schedule (pg_cron, or a
|
|
@@ -600,6 +692,7 @@ names; nothing is kept by the framework anywhere else.
|
|
|
600
692
|
| The ledger: each turn's input, output and tool results (key-shaped secrets redacted) | Your Postgres, `adk_turns`, `adk_telemetry` | **Until you prune it**: schedule `melchizedek_prune_telemetry(<days>)` | `TELEMETRY_REDACT`, the prune's `turn_days` |
|
|
601
693
|
| Sampled full model requests | Your Postgres, `adk_payloads` | 30 days | `TELEMETRY_PAYLOADS`, `TELEMETRY_PAYLOAD_TTL_DAYS` |
|
|
602
694
|
| Traces, when `OTEL_EXPORTER_OTLP_ENDPOINT` is set | Your OTLP collector, conversation content included with key-shaped secrets redacted (`off` drops it) | Your collector's policy | `OTEL_EXPORT_CONTENT` (`redacted`, `off`, `raw`) |
|
|
695
|
+
| Third-party OAuth tokens held for tools, per end user (when `postgresStorage({ credentials })` is used) | Your Postgres, `melchizedek_tool_credentials`, sealed with AES-256-GCM under `MELCHIZEDEK_CREDENTIAL_KEY`, which never reaches the database (migration 0013) | Until revoked or erased | The provider config; the key |
|
|
603
696
|
| The audit trail (no content) | Your Postgres, `melchizedek_audit` | Until `melchizedek_prune_audit(<days>)` | The prune schedule |
|
|
604
697
|
| The task record (no content) | stdout | Your log platform's policy | `A2A_LOG_FORMAT` |
|
|
605
698
|
|
|
@@ -732,6 +825,59 @@ subagent or a workflow node listing it is a load error. In code,
|
|
|
732
825
|
`runSyndicateTurn` returns `status: 'input-required'` with `input`
|
|
733
826
|
(`node`, `message`, `payload`), and the next message's text answers it.
|
|
734
827
|
|
|
828
|
+
#### OAuth consent for tools
|
|
829
|
+
|
|
830
|
+
A tool that acts for the person against a third-party API reads their
|
|
831
|
+
delegated token with `ctx.accessToken(provider)` from the sealed credential
|
|
832
|
+
store ([ADR 0072](./wiki/decisions/0072-tool-credentials-sealed-per-user.md)).
|
|
833
|
+
When they have not granted the provider yet, the turn pauses for their
|
|
834
|
+
consent ([ADR 0085](./wiki/decisions/0085-oauth-consent-pauses-on-adks-credential-request.md)).
|
|
835
|
+
This runs on the native runtime:
|
|
836
|
+
|
|
837
|
+
```ts
|
|
838
|
+
import { createA2AApp } from 'melchizedek-agents/a2a';
|
|
839
|
+
import { oauthConsent } from 'melchizedek-agents/tools/oauthConsent';
|
|
840
|
+
|
|
841
|
+
const consent = oauthConsent({
|
|
842
|
+
providers: {
|
|
843
|
+
github: {
|
|
844
|
+
authorizationUrl: 'https://github.com/login/oauth/authorize',
|
|
845
|
+
tokenUrl: 'https://github.com/login/oauth/access_token',
|
|
846
|
+
clientId: process.env.GITHUB_CLIENT_ID!,
|
|
847
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
|
848
|
+
scopes: ['repo'],
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
redirectUri: 'https://agents.example.com/oauth/callback', // as registered at the provider
|
|
852
|
+
credentials: store, // storage.credentials, or credentialStore(...)
|
|
853
|
+
});
|
|
854
|
+
await createA2AApp({ /* … */ toolCredentials: { store, consent } });
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
1. **The pause.** The task ends `input-required` with the link in its status
|
|
858
|
+
message and a data part `{ type: 'consent_request', consent_id, agent,
|
|
859
|
+
provider, authorization_url, state, scopes }`.
|
|
860
|
+
2. **The grant.** The person opens the link and consents. The provider
|
|
861
|
+
redirects their browser to the callback, which the server mounts at the
|
|
862
|
+
redirect URI's path. The callback exchanges the code with PKCE and stores
|
|
863
|
+
the grant, sealed.
|
|
864
|
+
3. **The resume.** Their next message on the conversation runs the paused
|
|
865
|
+
call again. A message sent before the grant gets the same request back,
|
|
866
|
+
without a model call.
|
|
867
|
+
|
|
868
|
+
The callback refuses these, and stores nothing:
|
|
869
|
+
|
|
870
|
+
- a state that is replayed, tampered with or older than ten minutes;
|
|
871
|
+
- a provider's `error`;
|
|
872
|
+
- a caller who is authenticated as another user.
|
|
873
|
+
|
|
874
|
+
No token, code, client secret or verifier is written to a page, an event, a
|
|
875
|
+
log line or the model's context. The pending flows live in the process: run
|
|
876
|
+
one replica, or route the callback to the instance that paused the call. In
|
|
877
|
+
code, `runSyndicateTurn({ …, toolCredentials })` returns
|
|
878
|
+
`status: 'input-required'` with `consent`. On the ADK runtime an open consent
|
|
879
|
+
request throws `UnsupportedOnRuntimeError`.
|
|
880
|
+
|
|
735
881
|
#### Limits
|
|
736
882
|
|
|
737
883
|
| Setting | Default |
|
|
@@ -1082,18 +1228,25 @@ the deadline cap the whole graph as they cap any turn.
|
|
|
1082
1228
|
and remote `a2a_agent_url` subagents are refused inside a workflow by
|
|
1083
1229
|
the schema, and a workflow cannot be another syndicate's `yaml_reference`
|
|
1084
1230
|
(ADK cannot yet make a `Workflow` a subagent; nested, only its
|
|
1085
|
-
orchestrator runs).
|
|
1086
|
-
|
|
1231
|
+
orchestrator runs). An `ask_user` tool on a node agent is refused too:
|
|
1232
|
+
use an `ask_user` node. The record is [ADR 0030](./wiki/decisions/0030-workflow-graphs.md);
|
|
1233
|
+
the contract is `lib/workflow.ts`, on ADK's `Workflow`, and on the native
|
|
1234
|
+
runtime `lib/workflow/turn.ts`, on the engine's own scheduler
|
|
1235
|
+
([ADR 0095](./wiki/decisions/0095-native-workflow-turn-drains-through-the-adk-reader.md)).
|
|
1236
|
+
On native, a conversation paused inside an agent node or a map item
|
|
1237
|
+
(which only ADK resumes) fails the next turn with `RESUME_UNSUPPORTED`.
|
|
1087
1238
|
|
|
1088
1239
|
## 7. Extending the framework
|
|
1089
1240
|
|
|
1090
|
-
**Call
|
|
1241
|
+
**Call a model directly (no syndicate)**: the YAML layer is a convenience,
|
|
1091
1242
|
never a requirement. `scripts/direct_call.ts` (`npm run demo:direct`) is
|
|
1092
|
-
the canonical minimal block
|
|
1093
|
-
`
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1243
|
+
the canonical minimal block on the engine's model contract:
|
|
1244
|
+
`resolveAdapter(modelId)` from `melchizedek-agents/model`, then
|
|
1245
|
+
`adapter.generate({ model, system, messages, stream })`, reading partial
|
|
1246
|
+
and final responses. The id's prefix picks the provider (`gemini-*`,
|
|
1247
|
+
`claude-*`, `gpt-*`, `grok-*`, `kimi-*`, `ollama/*`), the key comes from
|
|
1248
|
+
the environment, and nothing in that entry loads `@google/adk`. A turn
|
|
1249
|
+
with tools, sessions and telemetry is `runSyndicateTurn`.
|
|
1097
1250
|
|
|
1098
1251
|
**Add a syndicate**: create `config/agents/<name>.yaml` — copy the
|
|
1099
1252
|
closest starter-pack file from `config/agents/examples/` or start from
|
|
@@ -1101,15 +1254,20 @@ closest starter-pack file from `config/agents/examples/` or start from
|
|
|
1101
1254
|
<name>`. No code changes. The loader checks the root first, then
|
|
1102
1255
|
`examples/`, so your syndicate and the starter pack never collide.
|
|
1103
1256
|
|
|
1104
|
-
**Add a tool**:
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1257
|
+
**Add a tool**: write a `defineTool` contract in `lib/tools/` (name,
|
|
1258
|
+
description, zod schema, execute), register the name in
|
|
1259
|
+
`lib/toolRegistry.ts` (or call `registerTool` from your own code),
|
|
1260
|
+
reference it from YAML. The contract runs on either runtime; see
|
|
1261
|
+
`wiki/tools/tool-contracts.md`. The two image tools are the worked
|
|
1262
|
+
examples — including why binary data forces function tools over
|
|
1263
|
+
subagents, and how a tool signature can enforce an epistemic rule (the
|
|
1264
|
+
blind inventory).
|
|
1265
|
+
|
|
1266
|
+
**Add a provider**: follow `claudeAdapter.ts` (SDK-based, key-gated, a
|
|
1267
|
+
`ModelAdapter` on the engine's model contract, run under ADK by its shim
|
|
1268
|
+
`claudeLlm.ts`) or, for a chat-completions API, `ollamaAdapter.ts`
|
|
1269
|
+
(fetch-based, keyless: a `ChatCompletionsAdapter` subclass, run under ADK
|
|
1270
|
+
by its shim `ollamaLlm.ts`), and register it behind a model-id prefix.
|
|
1113
1271
|
|
|
1114
1272
|
**Point an agent at an MCP server**: set `mcp_server_url:` on a
|
|
1115
1273
|
subagent. `scripts/demo_mcp_server.ts` is a complete server to copy —
|
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ const result = await runSyndicateTurn({
|
|
|
101
101
|
console.log(result.status, result.text);
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
`runSyndicateTurn` is the same runtime the server, CLI, and eval harness use. To read syndicates from somewhere else, pass `loadSyndicate(file, { agentsDir })` or set `MELCHIZEDEK_AGENTS_DIR`. To serve inside your own Express app, mount `(await createA2AApp({ defaultSyndicate: 'mine.yaml', serverSecret })).app`.
|
|
104
|
+
`runSyndicateTurn` is the same runtime the server, CLI, and eval harness use. It runs on Google ADK by default; `runtime: 'native'` (or `MELCHIZEDEK_RUNTIME=native`) runs a single-agent, delegating, plan-dispatch or workflow syndicate on the engine's own loop and scheduler instead. To read syndicates from somewhere else, pass `loadSyndicate(file, { agentsDir })` or set `MELCHIZEDEK_AGENTS_DIR`. To serve inside your own Express app, mount `(await createA2AApp({ defaultSyndicate: 'mine.yaml', serverSecret })).app`.
|
|
105
105
|
|
|
106
106
|
The example syndicates ship inside the package at `node_modules/melchizedek-agents/config/agents/examples/`; copy one out as a starting point.
|
|
107
107
|
|
|
@@ -116,6 +116,44 @@ registerTool('myCustomTool', defineTool({ /* ... */ }));
|
|
|
116
116
|
registerGuard(myGuardInstance);
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
### The Model Adapters Alone
|
|
120
|
+
|
|
121
|
+
`melchizedek-agents/model` is the engine's model layer on its own: one message format for every provider, an adapter per provider, `resolveAdapter` over the same model-id prefixes the YAML uses, and `FallbackAdapter`. It loads no `@google/adk`, so a project that only calls models can leave ADK out. npm 7 and later install peer dependencies by default; skip them with:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npm install melchizedek-agents --legacy-peer-deps
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { ClaudeAdapter, OllamaAdapter, resolveAdapter } from 'melchizedek-agents/model';
|
|
129
|
+
import type { ModelAdapter, ModelRequest } from 'melchizedek-agents/model';
|
|
130
|
+
|
|
131
|
+
async function ask(adapter: ModelAdapter, text: string): Promise<string> {
|
|
132
|
+
const request: ModelRequest = {
|
|
133
|
+
model: adapter.model,
|
|
134
|
+
system: 'Answer in one sentence.',
|
|
135
|
+
messages: [{ role: 'user', parts: [{ type: 'text', text }] }],
|
|
136
|
+
};
|
|
137
|
+
for await (const response of adapter.generate(request)) {
|
|
138
|
+
if (response.partial) continue; // deltas while the model writes
|
|
139
|
+
if (response.error) throw new Error(response.error.message);
|
|
140
|
+
return response.parts.map((p) => (p.type === 'text' ? p.text : '')).join('');
|
|
141
|
+
}
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Claude: the key comes from ANTHROPIC_API_KEY in the environment.
|
|
146
|
+
console.log(await ask(new ClaudeAdapter({ model: 'claude-sonnet-4-6' }), 'What is A2A?'));
|
|
147
|
+
|
|
148
|
+
// Ollama: a local model, no key (OLLAMA_BASE_URL, else http://localhost:11434/v1).
|
|
149
|
+
console.log(await ask(new OllamaAdapter({ model: 'ollama/qwen3:8b' }), 'What is A2A?'));
|
|
150
|
+
|
|
151
|
+
// Or by id, with the same routing as a syndicate's `model:` field.
|
|
152
|
+
const adapter = resolveAdapter('ollama/qwen3:8b');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
A Gemini id resolves to the engine's `GeminiAdapter` here. The ADK-backed Gemini adapter, the ADK shims and `resolveModel` stay under `melchizedek-agents/models/*`, which need ADK.
|
|
156
|
+
|
|
119
157
|
### CLI & Server Utilities
|
|
120
158
|
|
|
121
159
|
- `npx melchizedek-chat --syndicate <name>`: Interactive CLI REPL for any syndicate.
|
|
@@ -164,6 +202,9 @@ See `config/agents/syndicateSchema.yaml` for the annotated schema reference.
|
|
|
164
202
|
- [`DOCUMENTATION.md`](./DOCUMENTATION.md) — Full reference: architecture, syndicate YAML, tools, memory, providers, A2A, extending, security.
|
|
165
203
|
- [`AGENT_SETUP.md`](./AGENT_SETUP.md) — A paste-ready prompt that walks your coding agent (Claude Code, Cursor, Codex) through setup.
|
|
166
204
|
- [`skills/README.md`](./skills/README.md) — The bundled `SKILL.md` suite.
|
|
205
|
+
- [`VERSIONING.md`](./VERSIONING.md) — What an upgrade may break, deprecation, and which versions get fixes.
|
|
206
|
+
- [`SUPPORT.md`](./SUPPORT.md) — Where to ask, and what to expect: a single-maintainer project with no SLA.
|
|
207
|
+
- [`SECURITY.md`](./SECURITY.md) and [`CONTRIBUTING.md`](./CONTRIBUTING.md).
|
|
167
208
|
|
|
168
209
|
## License
|
|
169
210
|
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
# tools this file lists under `skills.tools`. Scripts run only with
|
|
43
43
|
# `scripts: local`, only from a skill's scripts/ directory, and only
|
|
44
44
|
# after a person approves each run; the model's own code never
|
|
45
|
-
# executes.
|
|
45
|
+
# executes. A script gets PATH, HOME, the temp directory and the
|
|
46
|
+
# locale, never the server's keys; name anything else it needs under
|
|
47
|
+
# `skills.env` (or `skills.secret_env` for a credential, ADR 0086). Point `dir` only at skills you would let a person follow,
|
|
46
48
|
# and enable scripts only on a machine where you would run them.
|
|
47
49
|
# ============================================================
|
|
48
50
|
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
# Or chat with the zoo: npm run chat:syndicate -- --syndicate model_zoo
|
|
22
22
|
# (the orchestrator delegates your question to a provider you name).
|
|
23
23
|
#
|
|
24
|
+
# ONE KEY FOR REASONING: `reasoning: none | low | medium | high` reads the
|
|
25
|
+
# same on every provider; the compiler sends each one the field it takes
|
|
26
|
+
# (a thinking budget, a thinking level or an effort word; ADR 0047).
|
|
27
|
+
#
|
|
24
28
|
# ONE INSTRUCTION, SIX MODELS: every explainer's `instruction:` is the
|
|
25
29
|
# same `{{explainer}}` variable, so the six prompts are identical by
|
|
26
30
|
# construction and any difference in the answers comes from the model.
|
|
@@ -127,18 +131,16 @@ subagents:
|
|
|
127
131
|
# OLLAMA_MAX_TOKENS. A larger window (Modelfile `PARAMETER num_ctx`; /v1
|
|
128
132
|
# ignores num_ctx) only lets it think past five minutes. "none" is the
|
|
129
133
|
# one value Ollama's /v1 honours here: answers in ~15 s on a laptop.
|
|
130
|
-
|
|
131
|
-
reasoningEffort: "none"
|
|
134
|
+
reasoning: none
|
|
132
135
|
|
|
133
136
|
- name: "claude"
|
|
134
137
|
description: "Claude Sonnet, by Anthropic. Pass the question word for word; returns a plain explanation of at most three paragraphs."
|
|
135
138
|
model: "claude-sonnet-4-6"
|
|
136
139
|
instruction: "{{explainer}}"
|
|
137
|
-
# Extended thinking:
|
|
138
|
-
# thinking parameter and surfaces
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
thinkingBudget: 2048
|
|
140
|
+
# Extended thinking: `low` is a 2,048-token budget on Claude, which the
|
|
141
|
+
# adapter sends as Anthropic's thinking parameter and surfaces as
|
|
142
|
+
# THINKING output (ADR 0047).
|
|
143
|
+
reasoning: low
|
|
142
144
|
|
|
143
145
|
- name: "grok"
|
|
144
146
|
description: "Grok 4.7 (reasoning effort: medium), by xAI. Pass the question word for word; returns a plain explanation of at most three paragraphs."
|
|
@@ -167,5 +169,4 @@ subagents:
|
|
|
167
169
|
# tokens, thinking billed as output), so it is here as the strongest
|
|
168
170
|
# open-weight model, not as the cheap seat: kimi-k2.6 is a quarter of
|
|
169
171
|
# the price if cost matters more; see the table in lib/models/kimiLlm.ts.
|
|
170
|
-
|
|
171
|
-
reasoningEffort: "low"
|
|
172
|
+
reasoning: low
|