melchizedek-agents 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +12 -0
- package/CHANGELOG.md +1001 -0
- package/DOCUMENTATION.md +252 -65
- package/QUICKSTART.md +9 -6
- package/README.md +42 -4
- package/config/agents/examples/harness.yaml +3 -1
- package/config/agents/examples/model_zoo.yaml +10 -9
- package/config/agents/syndicateSchema.yaml +53 -16
- package/config/agents/templates/account_memory.yaml +2 -6
- package/config/agents/templates/case_desk.yaml +3 -9
- package/config/agents/templates/draft_review.yaml +3 -9
- package/config/agents/templates/intake_extractor.yaml +1 -3
- package/config/agents/templates/research_brief.yaml +3 -9
- package/config/agents/templates/research_desk.yaml +3 -9
- package/config/agents/templates/review_panel.yaml +4 -12
- package/config/agents/templates/support_triage.yaml +4 -12
- package/config/agents/templates/systems_operator.yaml +2 -6
- package/db/hardening.sql +7 -1
- package/db/migrations/0013_tool_credentials.sql +260 -0
- package/dist/lib/a2a/app.d.ts +70 -6
- package/dist/lib/a2a/app.js +107 -2
- package/dist/lib/a2a/executor.d.ts +20 -3
- package/dist/lib/a2a/executor.js +66 -7
- package/dist/lib/a2a/remoteAgent.d.ts +24 -9
- package/dist/lib/a2a/remoteAgent.js +31 -14
- package/dist/lib/adkPeer.d.ts +63 -0
- package/dist/lib/adkPeer.js +240 -0
- package/dist/lib/compile.d.ts +159 -30
- package/dist/lib/compile.js +215 -134
- package/dist/lib/compileAdk.d.ts +32 -0
- package/dist/lib/compileAdk.js +142 -0
- package/dist/lib/compileNative.d.ts +111 -0
- package/dist/lib/compileNative.js +278 -0
- package/dist/lib/config.d.ts +6 -5
- package/dist/lib/config.js +6 -5
- package/dist/lib/doctor.d.ts +28 -1
- package/dist/lib/doctor.js +64 -2
- package/dist/lib/index.d.ts +6 -1
- package/dist/lib/index.js +7 -1
- package/dist/lib/loadSyndicate.d.ts +18 -0
- package/dist/lib/memory/erase.d.ts +5 -3
- package/dist/lib/memory/erase.js +5 -2
- package/dist/lib/memory/namespace.d.ts +8 -1
- package/dist/lib/memory/namespace.js +12 -6
- package/dist/lib/memory/providers.js +2 -1
- package/dist/lib/memory/supabaseMemoryService.d.ts +37 -3
- package/dist/lib/memory/supabaseMemoryService.js +42 -2
- package/dist/lib/model.d.ts +47 -0
- package/dist/lib/model.js +37 -0
- package/dist/lib/models/adapterResolver.d.ts +115 -0
- package/dist/lib/models/adapterResolver.js +137 -0
- package/dist/lib/models/adkGeminiAdapter.d.ts +90 -0
- package/dist/lib/models/adkGeminiAdapter.js +369 -0
- package/dist/lib/models/adkShim.d.ts +111 -0
- package/dist/lib/models/adkShim.js +136 -0
- package/dist/lib/models/capabilities.d.ts +3 -0
- package/dist/lib/models/capabilities.js +33 -23
- package/dist/lib/models/chatCompletionsAdapter.d.ts +279 -0
- package/dist/lib/models/chatCompletionsAdapter.js +854 -0
- package/dist/lib/models/circuitBreaker.d.ts +42 -0
- package/dist/lib/models/circuitBreaker.js +70 -0
- package/dist/lib/models/claudeAdapter.d.ts +103 -0
- package/dist/lib/models/claudeAdapter.js +669 -0
- package/dist/lib/models/claudeLlm.d.ts +39 -62
- package/dist/lib/models/claudeLlm.js +45 -350
- package/dist/lib/models/claudeModels.d.ts +127 -0
- package/dist/lib/models/claudeModels.js +237 -0
- package/dist/lib/models/contract.d.ts +395 -0
- package/dist/lib/models/contract.js +39 -0
- package/dist/lib/models/endpoints.js +2 -1
- package/dist/lib/models/errorResponse.d.ts +50 -0
- package/dist/lib/models/errorResponse.js +48 -0
- package/dist/lib/models/fallback.d.ts +18 -11
- package/dist/lib/models/fallback.js +54 -43
- package/dist/lib/models/fallbackAdapter.d.ts +55 -0
- package/dist/lib/models/fallbackAdapter.js +62 -0
- package/dist/lib/models/gateway.js +2 -1
- package/dist/lib/models/gatewayAdapter.d.ts +51 -0
- package/dist/lib/models/gatewayAdapter.js +81 -0
- package/dist/lib/models/gatewayLlm.d.ts +12 -33
- package/dist/lib/models/gatewayLlm.js +16 -77
- package/dist/lib/models/geminiAdapter.d.ts +125 -0
- package/dist/lib/models/geminiAdapter.js +854 -0
- package/dist/lib/models/geminiState.d.ts +46 -0
- package/dist/lib/models/geminiState.js +51 -0
- package/dist/lib/models/genaiMapping.d.ts +283 -0
- package/dist/lib/models/genaiMapping.js +965 -0
- package/dist/lib/models/gptAdapter.d.ts +240 -0
- package/dist/lib/models/gptAdapter.js +804 -0
- package/dist/lib/models/gptLlm.d.ts +63 -123
- package/dist/lib/models/gptLlm.js +89 -603
- package/dist/lib/models/grokAdapter.d.ts +86 -0
- package/dist/lib/models/grokAdapter.js +142 -0
- package/dist/lib/models/grokLlm.d.ts +22 -45
- package/dist/lib/models/grokLlm.js +24 -69
- package/dist/lib/models/kimiAdapter.d.ts +157 -0
- package/dist/lib/models/kimiAdapter.js +203 -0
- package/dist/lib/models/kimiLlm.d.ts +15 -107
- package/dist/lib/models/kimiLlm.js +19 -155
- package/dist/lib/models/ollamaAdapter.d.ts +125 -0
- package/dist/lib/models/ollamaAdapter.js +155 -0
- package/dist/lib/models/ollamaLlm.d.ts +11 -107
- package/dist/lib/models/ollamaLlm.js +15 -153
- package/dist/lib/models/openAiCompatibleLlm.d.ts +73 -216
- package/dist/lib/models/openAiCompatibleLlm.js +109 -671
- package/dist/lib/models/providerState.d.ts +63 -0
- package/dist/lib/models/providerState.js +61 -0
- package/dist/lib/models/reasoning.d.ts +26 -0
- package/dist/lib/models/reasoning.js +59 -0
- package/dist/lib/models/registry.d.ts +62 -35
- package/dist/lib/models/registry.js +100 -124
- package/dist/lib/models/retry.d.ts +2 -1
- package/dist/lib/models/retry.js +3 -2
- package/dist/lib/models/schemaNormalize.d.ts +98 -0
- package/dist/lib/models/schemaNormalize.js +321 -1
- package/dist/lib/models/tracedGemini.d.ts +41 -0
- package/dist/lib/models/tracedGemini.js +98 -0
- package/dist/lib/models/urls.d.ts +11 -0
- package/dist/lib/models/urls.js +16 -0
- package/dist/lib/net/redirects.d.ts +21 -2
- package/dist/lib/net/redirects.js +11 -34
- package/dist/lib/observability/audit.d.ts +5 -1
- package/dist/lib/observability/lineage.d.ts +14 -0
- package/dist/lib/observability/lineage.js +33 -0
- package/dist/lib/observability/supabaseSpanExporter.d.ts +10 -4
- package/dist/lib/observability/supabaseSpanExporter.js +17 -9
- package/dist/lib/observability/tracer.d.ts +26 -8
- package/dist/lib/observability/tracer.js +43 -18
- package/dist/lib/runtime/adkMemoryBridge.d.ts +46 -0
- package/dist/lib/runtime/adkMemoryBridge.js +68 -0
- package/dist/lib/runtime/adkSessionBridge.d.ts +78 -0
- package/dist/lib/runtime/adkSessionBridge.js +176 -0
- package/dist/lib/runtime/approvals.d.ts +5 -0
- package/dist/lib/runtime/approvals.js +39 -8
- package/dist/lib/runtime/credentials.d.ts +61 -0
- package/dist/lib/runtime/credentials.js +67 -0
- package/dist/lib/runtime/events.d.ts +229 -0
- package/dist/lib/runtime/events.js +274 -0
- package/dist/lib/runtime/logging.d.ts +32 -0
- package/dist/lib/runtime/logging.js +55 -0
- package/dist/lib/runtime/memoryService.d.ts +72 -0
- package/dist/lib/runtime/memoryService.js +25 -0
- package/dist/lib/runtime/native/agentLoop.d.ts +209 -0
- package/dist/lib/runtime/native/agentLoop.js +705 -0
- package/dist/lib/runtime/native/compaction.d.ts +103 -0
- package/dist/lib/runtime/native/compaction.js +191 -0
- package/dist/lib/runtime/native/delegate.d.ts +151 -0
- package/dist/lib/runtime/native/delegate.js +256 -0
- package/dist/lib/runtime/native/history.d.ts +83 -0
- package/dist/lib/runtime/native/history.js +312 -0
- package/dist/lib/runtime/native/interrupts.d.ts +129 -0
- package/dist/lib/runtime/native/interrupts.js +310 -0
- package/dist/lib/runtime/native/request.d.ts +215 -0
- package/dist/lib/runtime/native/request.js +585 -0
- package/dist/lib/runtime/native/selfCorrection.d.ts +164 -0
- package/dist/lib/runtime/native/selfCorrection.js +327 -0
- package/dist/lib/runtime/native/step.d.ts +156 -0
- package/dist/lib/runtime/native/step.js +263 -0
- package/dist/lib/runtime/native/taskMode.d.ts +64 -0
- package/dist/lib/runtime/native/taskMode.js +126 -0
- package/dist/lib/runtime/native/telemetry.d.ts +75 -0
- package/dist/lib/runtime/native/telemetry.js +299 -0
- package/dist/lib/runtime/native/tempState.d.ts +31 -0
- package/dist/lib/runtime/native/tempState.js +56 -0
- package/dist/lib/runtime/nativeTurn.d.ts +86 -0
- package/dist/lib/runtime/nativeTurn.js +107 -0
- package/dist/lib/runtime/questions.d.ts +29 -7
- package/dist/lib/runtime/questions.js +47 -32
- package/dist/lib/runtime/runtimeFlag.d.ts +38 -0
- package/dist/lib/runtime/runtimeFlag.js +58 -0
- package/dist/lib/runtime/sessions.d.ts +166 -0
- package/dist/lib/runtime/sessions.js +201 -0
- package/dist/lib/runtime/syndicateTurn.d.ts +46 -5
- package/dist/lib/runtime/syndicateTurn.js +233 -36
- package/dist/lib/runtime/valueDepth.d.ts +23 -0
- package/dist/lib/runtime/valueDepth.js +41 -0
- package/dist/lib/session/supabaseSessionService.d.ts +65 -18
- package/dist/lib/session/supabaseSessionService.js +148 -105
- package/dist/lib/session/transcript.d.ts +69 -23
- package/dist/lib/session/transcript.js +105 -29
- package/dist/lib/skills.js +33 -7
- package/dist/lib/storage/postgres/credentialStore.d.ts +20 -0
- package/dist/lib/storage/postgres/credentialStore.js +82 -0
- package/dist/lib/storage/postgres/index.d.ts +12 -0
- package/dist/lib/storage/postgres/index.js +6 -1
- package/dist/lib/storage/postgres/sessionService.d.ts +44 -16
- package/dist/lib/storage/postgres/sessionService.js +128 -66
- package/dist/lib/syndicateSchema.d.ts +49 -0
- package/dist/lib/syndicateSchema.js +99 -9
- package/dist/lib/toolRegistry.d.ts +26 -2
- package/dist/lib/toolRegistry.js +73 -17
- package/dist/lib/tools/adkTool.d.ts +81 -0
- package/dist/lib/tools/adkTool.js +268 -0
- package/dist/lib/tools/auth.d.ts +118 -0
- package/dist/lib/tools/auth.js +89 -0
- package/dist/lib/tools/collectionsSearchTool.d.ts +8 -7
- package/dist/lib/tools/collectionsSearchTool.js +12 -27
- package/dist/lib/tools/credentialCipher.d.ts +58 -0
- package/dist/lib/tools/credentialCipher.js +116 -0
- package/dist/lib/tools/credentialStore.d.ts +77 -0
- package/dist/lib/tools/credentialStore.js +246 -0
- package/dist/lib/tools/examples.d.ts +43 -0
- package/dist/lib/tools/examples.js +62 -0
- package/dist/lib/tools/generateImageTool.d.ts +15 -6
- package/dist/lib/tools/generateImageTool.js +19 -29
- package/dist/lib/tools/inspectImageTool.d.ts +9 -6
- package/dist/lib/tools/inspectImageTool.js +13 -17
- package/dist/lib/tools/mcpToolFactory.d.ts +42 -1
- package/dist/lib/tools/mcpToolFactory.js +46 -47
- package/dist/lib/tools/memoryTools.d.ts +61 -0
- package/dist/lib/tools/memoryTools.js +119 -0
- package/dist/lib/tools/nativeTools.d.ts +38 -0
- package/dist/lib/tools/nativeTools.js +43 -0
- package/dist/lib/tools/oauthConsent.d.ts +181 -0
- package/dist/lib/tools/oauthConsent.js +330 -0
- package/dist/lib/tools/openapi/call.d.ts +108 -0
- package/dist/lib/tools/openapi/call.js +295 -0
- package/dist/lib/tools/openapi/parse.d.ts +147 -0
- package/dist/lib/tools/openapi/parse.js +570 -0
- package/dist/lib/tools/openapiTools.d.ts +25 -17
- package/dist/lib/tools/openapiTools.js +124 -121
- package/dist/lib/tools/scienceTools.d.ts +14 -14
- package/dist/lib/tools/skillToolset.d.ts +58 -87
- package/dist/lib/tools/skillToolset.js +61 -142
- package/dist/lib/tools/skills/env.d.ts +58 -0
- package/dist/lib/tools/skills/env.js +165 -0
- package/dist/lib/tools/skills/executor.d.ts +114 -0
- package/dist/lib/tools/skills/executor.js +331 -0
- package/dist/lib/tools/skills/frontmatter.d.ts +79 -0
- package/dist/lib/tools/skills/frontmatter.js +215 -0
- package/dist/lib/tools/skills/loader.d.ts +91 -0
- package/dist/lib/tools/skills/loader.js +257 -0
- package/dist/lib/tools/skills/tools.d.ts +187 -0
- package/dist/lib/tools/skills/tools.js +386 -0
- package/dist/lib/tools/taskTools.d.ts +15 -15
- package/dist/lib/tools/tool.d.ts +354 -0
- package/dist/lib/tools/tool.js +304 -0
- package/dist/lib/tools/toolContract.d.ts +89 -33
- package/dist/lib/tools/toolContract.js +104 -82
- package/dist/lib/tools/urlContextTool.d.ts +4 -1
- package/dist/lib/tools/urlContextTool.js +6 -2
- package/dist/lib/tools/webExtractTool.d.ts +3 -3
- package/dist/lib/tools/webExtractTool.js +2 -1
- package/dist/lib/tools/webSearchTool.d.ts +7 -10
- package/dist/lib/tools/webSearchTool.js +15 -60
- package/dist/lib/tools/wikiTools.d.ts +19 -19
- package/dist/lib/tools/wikiTools.js +13 -9
- package/dist/lib/tools/xApiSearchTool.d.ts +3 -3
- package/dist/lib/tools/xApiSearchTool.js +2 -1
- package/dist/lib/tools/xSearchTool.d.ts +8 -10
- package/dist/lib/tools/xSearchTool.js +12 -63
- package/dist/lib/tools/xaiSearchParams.d.ts +41 -0
- package/dist/lib/tools/xaiSearchParams.js +126 -0
- package/dist/lib/wiki/agentRun.d.ts +12 -0
- package/dist/lib/wiki/agentRun.js +74 -35
- package/dist/lib/wiki/entities.d.ts +12 -0
- package/dist/lib/wiki/entities.js +45 -3
- package/dist/lib/workflow/agentNode.d.ts +153 -0
- package/dist/lib/workflow/agentNode.js +365 -0
- package/dist/lib/workflow/graph.d.ts +178 -0
- package/dist/lib/workflow/graph.js +468 -0
- package/dist/lib/workflow/nodeEvents.d.ts +50 -0
- package/dist/lib/workflow/nodeEvents.js +101 -0
- package/dist/lib/workflow/pause.d.ts +122 -0
- package/dist/lib/workflow/pause.js +180 -0
- package/dist/lib/workflow/resume.d.ts +166 -0
- package/dist/lib/workflow/resume.js +441 -0
- package/dist/lib/workflow/route.d.ts +58 -0
- package/dist/lib/workflow/route.js +69 -0
- package/dist/lib/workflow/scheduler.d.ts +418 -0
- package/dist/lib/workflow/scheduler.js +756 -0
- package/dist/lib/workflow/toolNode.d.ts +127 -0
- package/dist/lib/workflow/toolNode.js +236 -0
- package/dist/lib/workflow/turn.d.ts +118 -0
- package/dist/lib/workflow/turn.js +216 -0
- package/dist/lib/workflow.d.ts +33 -11
- package/dist/lib/workflow.js +49 -27
- package/dist/lib/workflowConfig.d.ts +7 -2
- package/dist/lib/workflowConfig.js +7 -12
- package/dist/scripts/a2a_server.js +4 -3
- package/dist/scripts/assistant_worker.d.ts +2 -1
- package/dist/scripts/assistant_worker.js +9 -4
- package/dist/scripts/doctor.d.ts +3 -1
- package/dist/scripts/doctor.js +4 -2
- package/dist/scripts/syndicate_chat.js +19 -10
- package/package.json +9 -3
- package/skills/briefs/melchizedek-author.md +3 -2
- package/skills/briefs/melchizedek-models.md +13 -9
- package/skills/briefs/melchizedek.md +3 -3
- package/skills/melchizedek/SKILL.md +2 -1
- package/skills/melchizedek-author/SKILL.md +2 -1
- package/skills/melchizedek-author/assets/minimal.yaml +2 -0
- package/skills/melchizedek-models/SKILL.md +23 -6
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/tools/skills/tools.ts — the skill tools and the toolset that holds
|
|
3
|
+
* them, on the engine's own tool base (lib/tools/tool.ts; WS3-3, ADR 0083).
|
|
4
|
+
*
|
|
5
|
+
* WHY this file exists:
|
|
6
|
+
* The skills harness (ADR 0029) was built on ADK's SkillToolset until
|
|
7
|
+
* WS3-3. These are the same tools as own Tools, so the native loop runs
|
|
8
|
+
* them directly and the ADK runtime runs them through the one tool
|
|
9
|
+
* adapter (lib/tools/adkTool.ts, toAdkToolset). A model is sent the same
|
|
10
|
+
* names, descriptions and parameters as before, and reads the same
|
|
11
|
+
* results and error texts, on either runtime:
|
|
12
|
+
* - list_skills: the `<available_skills>` index (ADK's ListSkillsTool).
|
|
13
|
+
* The harness leaves it out, since the index is in the instruction.
|
|
14
|
+
* - load_skill: the procedure, the frontmatter and the NAMES of the files
|
|
15
|
+
* the skill ships (ADR 0029's lean load), and it activates the skill.
|
|
16
|
+
* - load_skill_resource: one of those files (ADK's tool, word for word).
|
|
17
|
+
* A binary file is shown to the model as inline data in the next
|
|
18
|
+
* request, through the Tool's `contents` hook, as ADK's tool did in its
|
|
19
|
+
* processLlmRequest.
|
|
20
|
+
* - run_skill_script: asks a person to approve, then runs one script the
|
|
21
|
+
* skill ships on the local executor (./executor.ts).
|
|
22
|
+
*
|
|
23
|
+
* ACTIVATION: load_skill appends the skill's name to the session state key
|
|
24
|
+
* `_adk_activated_skill_<agent>` (ADK's key, so a session stored by
|
|
25
|
+
* either runtime reads the same). SkillToolset.getTools reads it and adds
|
|
26
|
+
* the tools the activated skills name (`metadata.adk_additional_tools`,
|
|
27
|
+
* filled from `allowed-tools`), but only from the tools the YAML handed
|
|
28
|
+
* it under `skills.tools`: a skill cannot grant itself a tool the YAML
|
|
29
|
+
* withheld.
|
|
30
|
+
*
|
|
31
|
+
* WHY NOT defineTool: a defineTool contract validates its arguments with
|
|
32
|
+
* zod and answers a bad call with its own error string. These tools keep
|
|
33
|
+
* ADK's answers to a bad call (`{ error, error_code }`), so their
|
|
34
|
+
* parameters are written here as JSON Schema and their arguments checked
|
|
35
|
+
* in execute.
|
|
36
|
+
*
|
|
37
|
+
* UNTRUSTED INPUT: every argument is the model's. A skill name and a file
|
|
38
|
+
* path are looked up as own keys of the loaded maps (never on a
|
|
39
|
+
* prototype), so nothing a model sends opens a file the skill did not
|
|
40
|
+
* ship or names a script outside its `scripts/`.
|
|
41
|
+
*/
|
|
42
|
+
import * as fs from 'node:fs/promises';
|
|
43
|
+
import * as os from 'node:os';
|
|
44
|
+
import * as path from 'node:path';
|
|
45
|
+
import { LocalScriptExecutor, guessMimeType, materializeFiles, scriptLanguage, skillResourceFiles, wrapperCode } from './executor.js';
|
|
46
|
+
// ── The index ────────────────────────────────────────────────────────────────
|
|
47
|
+
/** ADK's escapeHtml, as list_skills writes the index. */
|
|
48
|
+
function escapeHtml(unsafe) {
|
|
49
|
+
return unsafe.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
50
|
+
}
|
|
51
|
+
/** The `<available_skills>` index, in the skills' order (ADK's formatSkillsAsXml). */
|
|
52
|
+
export function formatSkillsAsXml(skills) {
|
|
53
|
+
if (skills.length === 0)
|
|
54
|
+
return '<available_skills>\n</available_skills>';
|
|
55
|
+
const lines = ['<available_skills>'];
|
|
56
|
+
for (const skill of skills) {
|
|
57
|
+
lines.push(' <skill>');
|
|
58
|
+
lines.push(` <name>${escapeHtml(skill.frontmatter.name)}</name>`);
|
|
59
|
+
lines.push(` <description>${escapeHtml(skill.frontmatter.description)}</description>`);
|
|
60
|
+
lines.push(' </skill>');
|
|
61
|
+
}
|
|
62
|
+
lines.push('</available_skills>');
|
|
63
|
+
return lines.join('\n');
|
|
64
|
+
}
|
|
65
|
+
// ── The toolset ──────────────────────────────────────────────────────────────
|
|
66
|
+
/** The session state key holding the skills an agent has loaded (ADK's). */
|
|
67
|
+
export function activatedSkillsKey(agentName) {
|
|
68
|
+
return `_adk_activated_skill_${agentName}`;
|
|
69
|
+
}
|
|
70
|
+
/** The names of the tools a SkillToolset holds itself; an unlocked tool never shadows one. */
|
|
71
|
+
const OWN_TOOL_NAMES = new Set([
|
|
72
|
+
'list_skills',
|
|
73
|
+
'load_skill',
|
|
74
|
+
'load_skill_resource',
|
|
75
|
+
'run_skill_script',
|
|
76
|
+
'run_skill_inline_script',
|
|
77
|
+
'search_skills',
|
|
78
|
+
]);
|
|
79
|
+
/** Seconds a skill script may run before the local executor kills it. */
|
|
80
|
+
export const SCRIPT_TIMEOUT_SECONDS = 120;
|
|
81
|
+
function nameOf(tool) {
|
|
82
|
+
const name = tool?.name;
|
|
83
|
+
return typeof name === 'string' ? name : undefined;
|
|
84
|
+
}
|
|
85
|
+
function isToolsetShaped(value) {
|
|
86
|
+
return !!value && typeof value === 'object' && typeof value.getTools === 'function' && typeof value.execute !== 'function' && !('runAsync' in value);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The tools an agent with `skills:` carries: load_skill and
|
|
90
|
+
* load_skill_resource always, run_skill_script with `scripts: local`, and
|
|
91
|
+
* the tools its loaded skills unlock. A toolset by shape (getTools), which
|
|
92
|
+
* the native loop expands and lib/tools/adkTool.ts wraps for ADK.
|
|
93
|
+
*/
|
|
94
|
+
export class SkillToolset {
|
|
95
|
+
name = 'skill_toolset';
|
|
96
|
+
skills;
|
|
97
|
+
executor;
|
|
98
|
+
#tools;
|
|
99
|
+
#additionalTools;
|
|
100
|
+
#scriptOutputDir;
|
|
101
|
+
#tempOutputDir;
|
|
102
|
+
constructor(skills, options = {}) {
|
|
103
|
+
this.skills = skills;
|
|
104
|
+
this.#additionalTools = options.additionalTools ?? [];
|
|
105
|
+
this.#scriptOutputDir = options.scriptOutputDir;
|
|
106
|
+
if (options.scripts === 'local')
|
|
107
|
+
this.executor = options.executor ?? new LocalScriptExecutor({ timeoutSeconds: SCRIPT_TIMEOUT_SECONDS, envNames: options.envNames });
|
|
108
|
+
this.#tools = [new LoadSkillTool(this), new LoadSkillResourceTool(this)];
|
|
109
|
+
if (this.executor)
|
|
110
|
+
this.#tools.push(new RunSkillScriptTool(this));
|
|
111
|
+
}
|
|
112
|
+
/** The skill named `name`, or undefined. Only the toolset's own skills, never a prototype key. */
|
|
113
|
+
getSkill(name) {
|
|
114
|
+
return Object.hasOwn(this.skills, name) ? this.skills[name] : undefined;
|
|
115
|
+
}
|
|
116
|
+
/** The harness tools, then the tools the agent's loaded skills unlock. */
|
|
117
|
+
async getTools(context) {
|
|
118
|
+
return [...this.#tools, ...(await this.#unlocked(context))];
|
|
119
|
+
}
|
|
120
|
+
/** ADK's resolveAdditionalTools: the permitted tools the activated skills name, in the order they name them. */
|
|
121
|
+
async #unlocked(context) {
|
|
122
|
+
if (!context)
|
|
123
|
+
return [];
|
|
124
|
+
const activated = context.state.get(activatedSkillsKey(context.agentName));
|
|
125
|
+
if (!Array.isArray(activated) || activated.length === 0)
|
|
126
|
+
return [];
|
|
127
|
+
const wanted = new Set();
|
|
128
|
+
for (const skillName of activated) {
|
|
129
|
+
const extra = typeof skillName === 'string' ? this.getSkill(skillName)?.frontmatter.metadata?.adk_additional_tools : undefined;
|
|
130
|
+
if (Array.isArray(extra))
|
|
131
|
+
for (const t of extra)
|
|
132
|
+
if (typeof t === 'string')
|
|
133
|
+
wanted.add(t);
|
|
134
|
+
}
|
|
135
|
+
if (wanted.size === 0)
|
|
136
|
+
return [];
|
|
137
|
+
const candidates = new Map();
|
|
138
|
+
for (const union of this.#additionalTools) {
|
|
139
|
+
const listed = isToolsetShaped(union) ? await union.getTools(context) : [union];
|
|
140
|
+
for (const tool of listed) {
|
|
141
|
+
const name = nameOf(tool);
|
|
142
|
+
if (name === undefined)
|
|
143
|
+
continue;
|
|
144
|
+
if (candidates.has(name))
|
|
145
|
+
throw new Error(`Duplicate tool name: ${name}`);
|
|
146
|
+
candidates.set(name, tool);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const out = [];
|
|
150
|
+
const taken = new Set(OWN_TOOL_NAMES);
|
|
151
|
+
for (const name of wanted) {
|
|
152
|
+
const tool = candidates.get(name);
|
|
153
|
+
if (tool !== undefined && !taken.has(name)) {
|
|
154
|
+
out.push(tool);
|
|
155
|
+
taken.add(name);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Where a script's output files are copied: the configured directory, or
|
|
162
|
+
* a private temp directory made once per toolset. Output file names are
|
|
163
|
+
* the script's choice, so they are never resolved against the server's
|
|
164
|
+
* working directory.
|
|
165
|
+
*/
|
|
166
|
+
scriptOutputDir() {
|
|
167
|
+
if (this.#scriptOutputDir) {
|
|
168
|
+
const dir = path.resolve(this.#scriptOutputDir);
|
|
169
|
+
return fs.mkdir(dir, { recursive: true }).then(() => dir);
|
|
170
|
+
}
|
|
171
|
+
return (this.#tempOutputDir ??= fs.mkdtemp(path.join(os.tmpdir(), 'melchizedek_skill_output_')));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// ── The tools ────────────────────────────────────────────────────────────────
|
|
175
|
+
class SkillTool {
|
|
176
|
+
toolset;
|
|
177
|
+
constructor(toolset) {
|
|
178
|
+
this.toolset = toolset;
|
|
179
|
+
}
|
|
180
|
+
declaration() {
|
|
181
|
+
return { name: this.name, description: this.description, parameters: structuredClone(this.parameters) };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** The arguments' string value, or undefined when absent or empty (ADK's `if (!x)`). */
|
|
185
|
+
function stringArg(args, key) {
|
|
186
|
+
return Object.hasOwn(args, key) ? args[key] : undefined;
|
|
187
|
+
}
|
|
188
|
+
/** list_skills: the index of every installed skill. The harness does not carry it (ADR 0029). */
|
|
189
|
+
export class ListSkillsTool extends SkillTool {
|
|
190
|
+
name = 'list_skills';
|
|
191
|
+
description = 'Lists all available skills with their names and descriptions.';
|
|
192
|
+
parameters = { type: 'object', properties: {} };
|
|
193
|
+
async execute() {
|
|
194
|
+
return formatSkillsAsXml(Object.values(this.toolset.skills));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* load_skill, lean (ADR 0029): the procedure, the frontmatter and the names
|
|
199
|
+
* of the files the skill ships, never their contents. Loading activates the
|
|
200
|
+
* skill, which unlocks its permitted `allowed-tools` on the next request.
|
|
201
|
+
*/
|
|
202
|
+
export class LoadSkillTool extends SkillTool {
|
|
203
|
+
name = 'load_skill';
|
|
204
|
+
description = 'Read one installed skill in full: its SKILL.md procedure, its frontmatter, and the names of the files it ships. Read a skill before you follow it.';
|
|
205
|
+
parameters = {
|
|
206
|
+
type: 'object',
|
|
207
|
+
properties: { name: { type: 'string', description: "The skill's name, exactly as the index lists it." } },
|
|
208
|
+
required: ['name'],
|
|
209
|
+
};
|
|
210
|
+
async execute(args, ctx) {
|
|
211
|
+
const raw = stringArg(args, 'name');
|
|
212
|
+
const name = typeof raw === 'string' ? raw.trim() : '';
|
|
213
|
+
if (!name)
|
|
214
|
+
return { error: 'Skill name is required.', error_code: 'MISSING_SKILL_NAME' };
|
|
215
|
+
const skill = this.toolset.getSkill(name);
|
|
216
|
+
if (!skill) {
|
|
217
|
+
return { error: `Skill '${name}' not found. Installed: ${Object.keys(this.toolset.skills).sort().join(', ') || '(none)'}.`, error_code: 'SKILL_NOT_FOUND' };
|
|
218
|
+
}
|
|
219
|
+
const key = activatedSkillsKey(ctx.agentName);
|
|
220
|
+
const current = ctx.state.get(key);
|
|
221
|
+
const activated = Array.isArray(current) ? current : [];
|
|
222
|
+
if (!activated.includes(name))
|
|
223
|
+
ctx.state.set(key, [...activated, name]);
|
|
224
|
+
return { skill_name: name, frontmatter: skill.frontmatter, instructions: skill.instructions, files: resourceNames(skill) };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function resourceNames(skill) {
|
|
228
|
+
const out = [];
|
|
229
|
+
for (const [dir, files] of Object.entries(skill.resources ?? {})) {
|
|
230
|
+
for (const name of Object.keys(files ?? {}))
|
|
231
|
+
out.push(`${dir}/${name}`);
|
|
232
|
+
}
|
|
233
|
+
return out.sort();
|
|
234
|
+
}
|
|
235
|
+
const BINARY_FILE_DETECTED_MSG = 'Binary file detected. The content has been injected into the conversation history for you to analyze.';
|
|
236
|
+
const RESOURCE_KINDS = ['references/', 'assets/', 'scripts/'];
|
|
237
|
+
/** The file at `resourcePath` in `skill`: its content, or undefined. Own keys only. */
|
|
238
|
+
function resourceAt(skill, resourcePath, kinds = RESOURCE_KINDS) {
|
|
239
|
+
const resources = skill.resources ?? {};
|
|
240
|
+
for (const prefix of kinds) {
|
|
241
|
+
if (!resourcePath.startsWith(prefix))
|
|
242
|
+
continue;
|
|
243
|
+
const key = resourcePath.slice(prefix.length);
|
|
244
|
+
if (prefix === 'scripts/') {
|
|
245
|
+
const scripts = resources.scripts ?? {};
|
|
246
|
+
return Object.hasOwn(scripts, key) ? scripts[key]?.src : undefined;
|
|
247
|
+
}
|
|
248
|
+
const files = (prefix === 'references/' ? resources.references : resources.assets) ?? {};
|
|
249
|
+
return Object.hasOwn(files, key) ? files[key] : undefined;
|
|
250
|
+
}
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
/** load_skill_resource: one file a skill ships, by its path (ADK's tool). */
|
|
254
|
+
export class LoadSkillResourceTool extends SkillTool {
|
|
255
|
+
name = 'load_skill_resource';
|
|
256
|
+
description = 'Loads a resource file (from references/, assets/, or scripts/) from within a skill.';
|
|
257
|
+
parameters = {
|
|
258
|
+
type: 'object',
|
|
259
|
+
properties: {
|
|
260
|
+
skill_name: { type: 'string', description: 'The name of the skill.' },
|
|
261
|
+
path: {
|
|
262
|
+
type: 'string',
|
|
263
|
+
description: "The relative path to the resource (e.g., 'references/my_doc.md', 'assets/template.txt', or 'scripts/setup.sh').",
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
required: ['skill_name', 'path'],
|
|
267
|
+
};
|
|
268
|
+
async execute(args) {
|
|
269
|
+
const skillName = stringArg(args, 'skill_name');
|
|
270
|
+
const rawPath = stringArg(args, 'path');
|
|
271
|
+
if (!skillName)
|
|
272
|
+
return { error: 'Skill name is required.', error_code: 'MISSING_SKILL_NAME' };
|
|
273
|
+
if (!rawPath)
|
|
274
|
+
return { error: 'Resource path is required.', error_code: 'MISSING_RESOURCE_PATH' };
|
|
275
|
+
const resourcePath = path.posix.normalize(String(rawPath));
|
|
276
|
+
const skill = this.toolset.getSkill(String(skillName));
|
|
277
|
+
if (!skill)
|
|
278
|
+
return { error: `Skill '${String(skillName)}' not found.`, error_code: 'SKILL_NOT_FOUND' };
|
|
279
|
+
if (!RESOURCE_KINDS.some((prefix) => resourcePath.startsWith(prefix))) {
|
|
280
|
+
return { error: "Path must start with 'references/', 'assets/', or 'scripts/'.", error_code: 'INVALID_RESOURCE_PATH' };
|
|
281
|
+
}
|
|
282
|
+
const content = resourceAt(skill, resourcePath);
|
|
283
|
+
if (content === undefined)
|
|
284
|
+
return { error: `Resource '${resourcePath}' not found in skill '${String(skillName)}'.`, error_code: 'RESOURCE_NOT_FOUND' };
|
|
285
|
+
if (Buffer.isBuffer(content))
|
|
286
|
+
return { skill_name: skillName, path: resourcePath, status: BINARY_FILE_DETECTED_MSG };
|
|
287
|
+
return { skill_name: skillName, path: resourcePath, content };
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* A binary file this tool just answered for is added to the request as
|
|
291
|
+
* inline data, after the history (ADK's processLlmRequest): the latest
|
|
292
|
+
* content, when it is the tools' answer, is searched for this tool's
|
|
293
|
+
* binary notices.
|
|
294
|
+
*/
|
|
295
|
+
async contents(contents) {
|
|
296
|
+
const last = contents.at(-1);
|
|
297
|
+
if (!last || last.role !== 'user' || !last.parts)
|
|
298
|
+
return;
|
|
299
|
+
for (const part of last.parts) {
|
|
300
|
+
const fr = part.functionResponse;
|
|
301
|
+
if (!fr || fr.name !== this.name)
|
|
302
|
+
continue;
|
|
303
|
+
const response = (fr.response ?? {});
|
|
304
|
+
if (response.status !== BINARY_FILE_DETECTED_MSG)
|
|
305
|
+
continue;
|
|
306
|
+
const skill = typeof response.skill_name === 'string' ? this.toolset.getSkill(response.skill_name) : undefined;
|
|
307
|
+
const resourcePath = typeof response.path === 'string' ? response.path : undefined;
|
|
308
|
+
if (!skill || resourcePath === undefined)
|
|
309
|
+
continue;
|
|
310
|
+
const content = resourceAt(skill, resourcePath, ['references/', 'assets/']);
|
|
311
|
+
if (!Buffer.isBuffer(content))
|
|
312
|
+
continue;
|
|
313
|
+
contents.push({
|
|
314
|
+
role: 'user',
|
|
315
|
+
parts: [{ text: `The content of binary file '${resourcePath}' is:` }, { inlineData: { data: content.toString('base64'), mimeType: guessMimeType(resourcePath) } }],
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* run_skill_script behind a person's approval: the first call asks for it
|
|
322
|
+
* (the hint names the skill, the script and the arguments) and returns
|
|
323
|
+
* without running; the call made again with the answer runs only when the
|
|
324
|
+
* answer approved it. The confirmation travels as `adk_request_confirmation`
|
|
325
|
+
* on either runtime, so the turn pauses `input-required` exactly as for
|
|
326
|
+
* `require_approval` (ADR 0028), with this tool's own texts.
|
|
327
|
+
*/
|
|
328
|
+
export class RunSkillScriptTool extends SkillTool {
|
|
329
|
+
name = 'run_skill_script';
|
|
330
|
+
description = "Executes a script from a skill's scripts/ directory.";
|
|
331
|
+
parameters = {
|
|
332
|
+
type: 'object',
|
|
333
|
+
properties: {
|
|
334
|
+
skill_name: { type: 'string', description: 'The name of the skill.' },
|
|
335
|
+
script_path: { type: 'string', description: "The relative path to the script (e.g., 'scripts/setup.js')." },
|
|
336
|
+
args: { type: 'object', description: 'Optional arguments to pass to the script as key-value pairs.' },
|
|
337
|
+
},
|
|
338
|
+
required: ['skill_name', 'script_path'],
|
|
339
|
+
};
|
|
340
|
+
async execute(args, ctx) {
|
|
341
|
+
if (!ctx.confirmation) {
|
|
342
|
+
const summary = `${String(args.skill_name ?? '?')}: ${String(args.script_path ?? '?')}${args.args ? ` ${JSON.stringify(args.args)}` : ''}`;
|
|
343
|
+
ctx.requestConfirmation({
|
|
344
|
+
hint: `Approval is required before a skill script runs on this machine. The agent asks to run ${summary}.`,
|
|
345
|
+
payload: { skill_name: args.skill_name, script_path: args.script_path, args: args.args ?? {} },
|
|
346
|
+
});
|
|
347
|
+
ctx.actions.skipSummarization = true;
|
|
348
|
+
return { error: 'This script run requires approval, please approve or reject.' };
|
|
349
|
+
}
|
|
350
|
+
if (!ctx.confirmation.confirmed)
|
|
351
|
+
return { error: 'This script run was rejected.' };
|
|
352
|
+
return this.#run(args);
|
|
353
|
+
}
|
|
354
|
+
/** ADK's RunSkillScriptTool.runAsync, after the gate. */
|
|
355
|
+
async #run(args) {
|
|
356
|
+
const skillName = stringArg(args, 'skill_name');
|
|
357
|
+
const scriptPath = stringArg(args, 'script_path');
|
|
358
|
+
const scriptArgs = (stringArg(args, 'args') || {});
|
|
359
|
+
if (!skillName)
|
|
360
|
+
return { error: 'Skill name is required.', errorCode: 'MISSING_SKILL_NAME' };
|
|
361
|
+
if (!scriptPath)
|
|
362
|
+
return { error: 'Script path is required.', errorCode: 'MISSING_SCRIPT_PATH' };
|
|
363
|
+
const skill = this.toolset.getSkill(String(skillName));
|
|
364
|
+
if (!skill)
|
|
365
|
+
return { error: `Skill '${String(skillName)}' not found.`, errorCode: 'SKILL_NOT_FOUND' };
|
|
366
|
+
const scriptPathText = String(scriptPath);
|
|
367
|
+
const scripts = skill.resources?.scripts ?? {};
|
|
368
|
+
const relative = scriptPathText.startsWith('scripts/') ? scriptPathText.slice('scripts/'.length) : scriptPathText;
|
|
369
|
+
const script = Object.hasOwn(scripts, relative) ? scripts[relative] : Object.hasOwn(scripts, scriptPathText) ? scripts[scriptPathText] : undefined;
|
|
370
|
+
if (!script)
|
|
371
|
+
return { error: `Script '${scriptPathText}' not found in skill '${String(skillName)}'.`, errorCode: 'SCRIPT_NOT_FOUND' };
|
|
372
|
+
const executor = this.toolset.executor;
|
|
373
|
+
if (!executor)
|
|
374
|
+
return { error: 'No code executor configured.', errorCode: 'NO_CODE_EXECUTOR' };
|
|
375
|
+
try {
|
|
376
|
+
const language = scriptLanguage(path.extname(scriptPathText));
|
|
377
|
+
const result = await executor.run({ code: wrapperCode(scriptPathText, language), inputFiles: skillResourceFiles(skill), language, args: scriptArgs });
|
|
378
|
+
const outputDirectory = await this.toolset.scriptOutputDir();
|
|
379
|
+
result.outputFiles = await materializeFiles(result.outputFiles, outputDirectory);
|
|
380
|
+
return { ...result, outputDirectory };
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
return { error: `Failed to execute script '${scriptPathText}': ${e.message}`, errorCode: 'EXECUTION_ERROR' };
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -134,16 +134,16 @@ export declare const fileTaskBackend: TaskBackend;
|
|
|
134
134
|
/** Plugs in where tasks live (postgresStorage().taskQueue); default the JSON file. */
|
|
135
135
|
export declare function setTaskBackend(backend: TaskBackend): void;
|
|
136
136
|
export declare function getTaskBackend(): TaskBackend;
|
|
137
|
-
export declare const taskAddContract: import("./toolContract.ts").
|
|
137
|
+
export declare const taskAddContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
138
138
|
title: z.ZodString;
|
|
139
139
|
notes: z.ZodOptional<z.ZodString>;
|
|
140
140
|
due: z.ZodOptional<z.ZodString>;
|
|
141
|
-
}, z.core.$strip
|
|
142
|
-
export declare const taskQueueContract: import("./toolContract.ts").
|
|
141
|
+
}, z.core.$strip>, string>;
|
|
142
|
+
export declare const taskQueueContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
143
143
|
title: z.ZodString;
|
|
144
144
|
instruction: z.ZodString;
|
|
145
|
-
}, z.core.$strip
|
|
146
|
-
export declare const taskListContract: import("./toolContract.ts").
|
|
145
|
+
}, z.core.$strip>, string>;
|
|
146
|
+
export declare const taskListContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
147
147
|
status: z.ZodDefault<z.ZodEnum<{
|
|
148
148
|
active: "active";
|
|
149
149
|
all: "all";
|
|
@@ -159,11 +159,11 @@ export declare const taskListContract: import("./toolContract.ts").ToolContract<
|
|
|
159
159
|
background: "background";
|
|
160
160
|
todo: "todo";
|
|
161
161
|
}>>;
|
|
162
|
-
}, z.core.$strip
|
|
163
|
-
export declare const taskGetContract: import("./toolContract.ts").
|
|
162
|
+
}, z.core.$strip>, string>;
|
|
163
|
+
export declare const taskGetContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
164
164
|
id: z.ZodString;
|
|
165
|
-
}, z.core.$strip
|
|
166
|
-
export declare const taskUpdateContract: import("./toolContract.ts").
|
|
165
|
+
}, z.core.$strip>, string>;
|
|
166
|
+
export declare const taskUpdateContract: import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
167
167
|
id: z.ZodString;
|
|
168
168
|
status: z.ZodOptional<z.ZodEnum<{
|
|
169
169
|
cancelled: "cancelled";
|
|
@@ -174,16 +174,16 @@ export declare const taskUpdateContract: import("./toolContract.ts").ToolContrac
|
|
|
174
174
|
title: z.ZodOptional<z.ZodString>;
|
|
175
175
|
notes: z.ZodOptional<z.ZodString>;
|
|
176
176
|
due: z.ZodOptional<z.ZodString>;
|
|
177
|
-
}, z.core.$strip
|
|
177
|
+
}, z.core.$strip>, string>;
|
|
178
178
|
/** Every task contract, in the order an agent's tool list shows them. */
|
|
179
|
-
export declare const TASK_TOOL_CONTRACTS: (import("./toolContract.ts").
|
|
179
|
+
export declare const TASK_TOOL_CONTRACTS: (import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
180
180
|
title: z.ZodString;
|
|
181
181
|
notes: z.ZodOptional<z.ZodString>;
|
|
182
182
|
due: z.ZodOptional<z.ZodString>;
|
|
183
|
-
}, z.core.$strip
|
|
183
|
+
}, z.core.$strip>, string> | import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
184
184
|
title: z.ZodString;
|
|
185
185
|
instruction: z.ZodString;
|
|
186
|
-
}, z.core.$strip
|
|
186
|
+
}, z.core.$strip>, string> | import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
187
187
|
status: z.ZodDefault<z.ZodEnum<{
|
|
188
188
|
active: "active";
|
|
189
189
|
all: "all";
|
|
@@ -199,6 +199,6 @@ export declare const TASK_TOOL_CONTRACTS: (import("./toolContract.ts").ToolContr
|
|
|
199
199
|
background: "background";
|
|
200
200
|
todo: "todo";
|
|
201
201
|
}>>;
|
|
202
|
-
}, z.core.$strip
|
|
202
|
+
}, z.core.$strip>, string> | import("./toolContract.ts").DefinedTool<z.ZodObject<{
|
|
203
203
|
id: z.ZodString;
|
|
204
|
-
}, z.core.$strip
|
|
204
|
+
}, z.core.$strip>, string>)[];
|