melchizedek-agents 1.0.3 → 1.2.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 +29 -2
- package/AGENT_SETUP.md +3 -1
- package/CHANGELOG.md +524 -0
- package/DOCUMENTATION.md +178 -43
- package/ONBOARDING.md +339 -0
- package/QUICKSTART.md +15 -2
- package/README.md +6 -2
- package/config/agents/README.md +2 -2
- package/config/agents/examples/ares.yaml +6 -10
- package/config/agents/examples/assistant.yaml +6 -6
- package/config/agents/examples/augustin.yaml +9 -15
- package/config/agents/examples/cartographers.yaml +6 -6
- package/config/agents/examples/council.yaml +7 -7
- package/config/agents/examples/critic.yaml +24 -24
- package/config/agents/examples/harness.yaml +4 -4
- package/config/agents/examples/image_production.yaml +37 -35
- package/config/agents/examples/librarian.yaml +4 -4
- package/config/agents/examples/patient_advocate.yaml +6 -10
- package/config/agents/examples/pipeline.yaml +20 -19
- package/config/agents/examples/research.yaml +36 -43
- package/config/agents/examples/scribe.yaml +31 -32
- package/config/agents/examples/scriptorium.yaml +6 -6
- package/config/agents/examples/structured_critic.yaml +82 -0
- package/config/agents/examples/style_council.yaml +9 -11
- package/config/agents/examples/syndicate.yaml +3 -5
- package/config/agents/examples/tutor.yaml +2 -2
- package/config/agents/examples/weather.yaml +2 -2
- package/config/agents/syndicate.schema.json +859 -13
- package/config/agents/syndicateSchema.yaml +122 -73
- package/config/agents/templates/README.md +1 -1
- package/config/agents/templates/account_memory.yaml +4 -4
- package/config/agents/templates/case_desk.yaml +6 -6
- package/config/agents/templates/conversational.yaml +2 -2
- package/config/agents/templates/draft_review.yaml +6 -6
- package/config/agents/templates/intake_extractor.yaml +64 -62
- package/config/agents/templates/research_brief.yaml +6 -6
- package/config/agents/templates/research_desk.yaml +6 -6
- package/config/agents/templates/review_panel.yaml +8 -8
- package/config/agents/templates/support_triage.yaml +30 -29
- package/config/agents/templates/systems_operator.yaml +24 -5
- package/db/migrations/0014_durable_runs.sql +31 -0
- package/dist/lib/a2a/app.d.ts +27 -0
- package/dist/lib/a2a/app.js +64 -5
- package/dist/lib/a2a/executor.d.ts +7 -1
- package/dist/lib/a2a/executor.js +43 -5
- package/dist/lib/a2a/oauthSetup.d.ts +106 -0
- package/dist/lib/a2a/oauthSetup.js +259 -0
- package/dist/lib/agentDialect.d.ts +76 -0
- package/dist/lib/agentDialect.js +151 -0
- package/dist/lib/compile.d.ts +42 -6
- package/dist/lib/compile.js +97 -45
- package/dist/lib/compileNative.d.ts +11 -3
- package/dist/lib/compileNative.js +20 -1
- package/dist/lib/dispatch.d.ts +10 -5
- package/dist/lib/dispatch.js +10 -5
- package/dist/lib/doctor.d.ts +110 -1
- package/dist/lib/doctor.js +205 -9
- package/dist/lib/loadSyndicate.d.ts +54 -2
- package/dist/lib/loadSyndicate.js +22 -2
- package/dist/lib/memory/namespace.d.ts +6 -5
- package/dist/lib/memory/namespace.js +6 -5
- package/dist/lib/memory/providers.js +3 -4
- package/dist/lib/models/capabilities.d.ts +25 -1
- package/dist/lib/models/capabilities.js +79 -1
- package/dist/lib/models/chatCompletionsAdapter.d.ts +11 -3
- package/dist/lib/models/chatCompletionsAdapter.js +19 -5
- package/dist/lib/models/claudeAdapter.js +4 -0
- package/dist/lib/models/contract.d.ts +5 -2
- package/dist/lib/models/gateway.d.ts +2 -1
- package/dist/lib/models/gateway.js +4 -2
- package/dist/lib/models/gatewayAdapter.d.ts +7 -1
- package/dist/lib/models/gatewayAdapter.js +8 -0
- package/dist/lib/models/geminiAdapter.js +8 -2
- package/dist/lib/models/genaiMapping.d.ts +8 -4
- package/dist/lib/models/genaiMapping.js +23 -9
- package/dist/lib/models/gptAdapter.d.ts +4 -2
- package/dist/lib/models/gptAdapter.js +11 -4
- package/dist/lib/models/grokAdapter.d.ts +3 -1
- package/dist/lib/models/grokAdapter.js +11 -3
- package/dist/lib/models/kimiAdapter.d.ts +2 -1
- package/dist/lib/models/kimiAdapter.js +3 -3
- package/dist/lib/models/reasoning.d.ts +30 -2
- package/dist/lib/models/reasoning.js +56 -5
- package/dist/lib/observability/tracer.d.ts +8 -1
- package/dist/lib/observability/tracer.js +33 -5
- package/dist/lib/onboarding.d.ts +134 -0
- package/dist/lib/onboarding.js +539 -0
- package/dist/lib/runtime/approvals.d.ts +8 -0
- package/dist/lib/runtime/approvals.js +4 -3
- package/dist/lib/runtime/credentials.d.ts +6 -0
- package/dist/lib/runtime/native/agentLoop.d.ts +23 -3
- package/dist/lib/runtime/native/agentLoop.js +107 -11
- package/dist/lib/runtime/native/checkpoint.d.ts +171 -0
- package/dist/lib/runtime/native/checkpoint.js +359 -0
- package/dist/lib/runtime/native/delegate.d.ts +222 -18
- package/dist/lib/runtime/native/delegate.js +390 -39
- package/dist/lib/runtime/native/interrupts.d.ts +184 -2
- package/dist/lib/runtime/native/interrupts.js +391 -1
- package/dist/lib/runtime/native/request.d.ts +13 -3
- package/dist/lib/runtime/native/request.js +28 -4
- package/dist/lib/runtime/native/telemetry.js +10 -15
- package/dist/lib/runtime/questions.d.ts +7 -4
- package/dist/lib/runtime/sessions.d.ts +1 -1
- package/dist/lib/runtime/syndicateTurn.d.ts +11 -3
- package/dist/lib/runtime/syndicateTurn.js +353 -68
- package/dist/lib/runtime/turnControl.d.ts +56 -0
- package/dist/lib/runtime/turnControl.js +10 -0
- package/dist/lib/session/transcript.d.ts +9 -0
- package/dist/lib/session/transcript.js +20 -1
- package/dist/lib/skills.d.ts +18 -0
- package/dist/lib/skills.js +73 -1
- package/dist/lib/storage/postgres/index.d.ts +12 -2
- package/dist/lib/storage/postgres/index.js +8 -3
- package/dist/lib/storage/postgres/taskQueue.d.ts +20 -4
- package/dist/lib/storage/postgres/taskQueue.js +29 -5
- package/dist/lib/storage/postgres/taskStore.d.ts +26 -2
- package/dist/lib/storage/postgres/taskStore.js +74 -8
- package/dist/lib/syndicateSchema.d.ts +316 -1
- package/dist/lib/syndicateSchema.js +203 -29
- package/dist/lib/tools/auth.d.ts +20 -6
- package/dist/lib/tools/auth.js +21 -5
- package/dist/lib/tools/credentialEnv.d.ts +28 -0
- package/dist/lib/tools/credentialEnv.js +52 -0
- package/dist/lib/tools/credentialHosts.d.ts +88 -0
- package/dist/lib/tools/credentialHosts.js +165 -0
- package/dist/lib/tools/credentialStore.js +9 -2
- package/dist/lib/tools/credentialUses.d.ts +92 -0
- package/dist/lib/tools/credentialUses.js +112 -0
- package/dist/lib/tools/mcpToolFactory.d.ts +25 -2
- package/dist/lib/tools/mcpToolFactory.js +179 -21
- package/dist/lib/tools/oauthConsent.js +8 -1
- package/dist/lib/tools/oauthHosts.d.ts +73 -0
- package/dist/lib/tools/oauthHosts.js +154 -0
- package/dist/lib/tools/oauthTools.d.ts +242 -0
- package/dist/lib/tools/oauthTools.js +447 -0
- package/dist/lib/tools/openapiTools.d.ts +11 -6
- package/dist/lib/tools/openapiTools.js +88 -38
- package/dist/lib/tools/taskTools.d.ts +61 -6
- package/dist/lib/tools/taskTools.js +145 -21
- package/dist/lib/workflow/turn.d.ts +22 -3
- package/dist/lib/workflow/turn.js +151 -31
- package/dist/lib/workflow.d.ts +14 -7
- package/dist/lib/workflow.js +14 -7
- package/dist/lib/workflowConfig.d.ts +6 -0
- package/dist/scripts/a2a_server.d.ts +36 -0
- package/dist/scripts/a2a_server.js +131 -1
- package/dist/scripts/assistant_worker.d.ts +12 -0
- package/dist/scripts/assistant_worker.js +81 -22
- package/dist/scripts/doctor.d.ts +7 -2
- package/dist/scripts/doctor.js +9 -4
- package/dist/scripts/setup.d.ts +23 -0
- package/dist/scripts/setup.js +154 -0
- package/dist/scripts/skills_install.d.ts +3 -1
- package/dist/scripts/skills_install.js +17 -2
- package/dist/scripts/yaml_codemod.d.ts +62 -0
- package/dist/scripts/yaml_codemod.js +652 -0
- package/package.json +8 -2
- package/skills/README.md +11 -2
- package/skills/briefs/_shared.md +1 -1
- package/skills/briefs/melchizedek-author.md +7 -5
- package/skills/briefs/melchizedek-models.md +7 -4
- package/skills/briefs/melchizedek.md +1 -0
- package/skills/briefs/skills-readme.md +3 -1
- package/skills/melchizedek/SKILL.md +1 -0
- package/skills/melchizedek-author/SKILL.md +7 -4
- package/skills/melchizedek-author/assets/minimal.yaml +13 -13
- package/skills/melchizedek-models/SKILL.md +11 -4
- package/skills/melchizedek-onboard/SKILL.md +49 -0
- package/skills/melchizedek-onboard-cloud/SKILL.md +38 -0
- package/skills/melchizedek-onboard-keys/SKILL.md +35 -0
- package/skills/melchizedek-onboard-local/SKILL.md +41 -0
- package/skills/melchizedek-onboard-serve/SKILL.md +43 -0
package/dist/lib/doctor.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* from the YAMLs and the environment: every syndicate the loader can see,
|
|
8
8
|
* every agent's model, the provider that id routes to, whether that path
|
|
9
9
|
* is funded (direct key, gateway, or local), and which declared
|
|
10
|
-
* server-side tools the path will drop
|
|
10
|
+
* server-side tools the path will drop, and which tools need an OAuth
|
|
11
|
+
* grant before they work (ADR 0112). Then it says exactly what to set,
|
|
11
12
|
* grouped by how much each variable unlocks.
|
|
12
13
|
*
|
|
13
14
|
* WHAT IT NEVER DOES:
|
|
@@ -33,6 +34,13 @@ import { credentialSource, endpointFromEnv, endpointLabel, endpointProblems, PLA
|
|
|
33
34
|
import { GATEWAY_ENV, GATEWAY_KEY_ENV, GATEWAYS, gatewayConfig, gatewayProblem, gatewayUsable, } from './models/gateway.js';
|
|
34
35
|
import { PROVIDERS } from './models/providerMap.js';
|
|
35
36
|
import { describeRuntime } from './runtime/runtimeFlag.js';
|
|
37
|
+
import { agentOAuthGrants, oauthEnvNames } from './tools/oauthTools.js';
|
|
38
|
+
import { grantHostProblems, OAUTH_REDIRECT_URI_ENV, oauthEnvProblems } from './a2a/oauthSetup.js';
|
|
39
|
+
import { CREDENTIAL_KEY_ENV } from './tools/credentialCipher.js';
|
|
40
|
+
import { OAUTH_HOSTS_ENV } from './tools/oauthHosts.js';
|
|
41
|
+
import { CREDENTIAL_HOSTS_ENV, credentialHosts } from './tools/credentialHosts.js';
|
|
42
|
+
import { syndicateCredentialUses } from './tools/credentialUses.js';
|
|
43
|
+
import { credentialHostEnvProblems, unboundCredentialWarning } from './a2a/oauthSetup.js';
|
|
36
44
|
function resolvable(module) {
|
|
37
45
|
try {
|
|
38
46
|
createRequire(import.meta.url).resolve(module);
|
|
@@ -95,6 +103,69 @@ export function endpointRows() {
|
|
|
95
103
|
}
|
|
96
104
|
return rows;
|
|
97
105
|
}
|
|
106
|
+
/** One status per provider, probed with an id of its own prefix (the providers line). */
|
|
107
|
+
export function providerPaths() {
|
|
108
|
+
return Object.keys(PROVIDERS).map((p) => {
|
|
109
|
+
const r = describeCapabilities(PROBE_ID[p]);
|
|
110
|
+
return {
|
|
111
|
+
provider: p,
|
|
112
|
+
label: PROVIDERS[p].label,
|
|
113
|
+
funded: r.funded,
|
|
114
|
+
transport: r.transport,
|
|
115
|
+
...(r.gateway ? { gateway: r.gateway } : {}),
|
|
116
|
+
platform: p === 'ollama' ? 'local' : (r.platform ?? 'direct'),
|
|
117
|
+
keyEnv: r.keyEnv,
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/** The serving variables the doctor reports by presence. */
|
|
122
|
+
export const SERVING_ENV = [
|
|
123
|
+
'A2A_AUTH',
|
|
124
|
+
'A2A_SERVER_SECRET',
|
|
125
|
+
'A2A_CALLERS',
|
|
126
|
+
'A2A_JWT_ISSUER',
|
|
127
|
+
'A2A_JWT_AUDIENCE',
|
|
128
|
+
'A2A_JWT_JWKS_URL',
|
|
129
|
+
'A2A_JWT_SECRET',
|
|
130
|
+
'A2A_TRUSTED_USER_HEADER',
|
|
131
|
+
'A2A_KEY_MODE',
|
|
132
|
+
'PUBLIC_URL',
|
|
133
|
+
];
|
|
134
|
+
/**
|
|
135
|
+
* How the A2A server would authenticate callers and who would pay, from the
|
|
136
|
+
* environment; undefined when none of its variables is set. The checks are
|
|
137
|
+
* the ones scripts/a2a_server.ts stops on, reported by name.
|
|
138
|
+
*/
|
|
139
|
+
export function servingReport(env = process.env) {
|
|
140
|
+
const has = (name) => !!env[name]?.trim();
|
|
141
|
+
const set = Object.fromEntries(SERVING_ENV.map((name) => [name, has(name)]));
|
|
142
|
+
if (!Object.values(set).some(Boolean))
|
|
143
|
+
return undefined;
|
|
144
|
+
// A value outside the known modes is reported as `invalid`, never echoed:
|
|
145
|
+
// a secret pasted into the wrong variable must not reach the terminal.
|
|
146
|
+
const rawAuth = (env.A2A_AUTH ?? '').trim().toLowerCase() || 'secret';
|
|
147
|
+
const rawKeyMode = (env.A2A_KEY_MODE ?? '').trim().toLowerCase() || 'server';
|
|
148
|
+
const auth = ['secret', 'callers', 'jwt', 'header'].includes(rawAuth) ? rawAuth : 'invalid';
|
|
149
|
+
const keyMode = rawKeyMode === 'server' || rawKeyMode === 'byok' ? rawKeyMode : 'invalid';
|
|
150
|
+
const problems = [];
|
|
151
|
+
if (auth === 'invalid')
|
|
152
|
+
problems.push('A2A_AUTH must be secret, callers, jwt or header');
|
|
153
|
+
if (auth === 'callers' && !has('A2A_CALLERS'))
|
|
154
|
+
problems.push('A2A_AUTH=callers needs A2A_CALLERS');
|
|
155
|
+
if (auth === 'jwt' && (!has('A2A_JWT_ISSUER') || !has('A2A_JWT_AUDIENCE')))
|
|
156
|
+
problems.push('A2A_AUTH=jwt needs A2A_JWT_ISSUER and A2A_JWT_AUDIENCE');
|
|
157
|
+
if (auth === 'jwt' && !has('A2A_JWT_JWKS_URL') && !has('A2A_JWT_SECRET'))
|
|
158
|
+
problems.push('A2A_AUTH=jwt needs A2A_JWT_JWKS_URL or A2A_JWT_SECRET');
|
|
159
|
+
if (auth === 'header' && (!has('A2A_TRUSTED_USER_HEADER') || !has('A2A_SERVER_SECRET')))
|
|
160
|
+
problems.push('A2A_AUTH=header needs A2A_TRUSTED_USER_HEADER and A2A_SERVER_SECRET');
|
|
161
|
+
if (keyMode !== 'server' && keyMode !== 'byok')
|
|
162
|
+
problems.push("A2A_KEY_MODE must be 'server' or 'byok'");
|
|
163
|
+
if (has('PUBLIC_URL') && !has('A2A_AUTH'))
|
|
164
|
+
problems.push('PUBLIC_URL is set, so A2A_AUTH must be set explicitly (with A2A_SERVED_AGENTS and A2A_TRUST_PROXY)');
|
|
165
|
+
if (auth === 'secret' && !has('A2A_SERVER_SECRET') && keyMode === 'byok')
|
|
166
|
+
problems.push('A2A_KEY_MODE=byok without A2A_SERVER_SECRET (or caller tokens) serves unauthenticated, loopback only');
|
|
167
|
+
return { auth, authDeclared: has('A2A_AUTH'), keyMode, set, problems };
|
|
168
|
+
}
|
|
98
169
|
// ── Where to get a key ───────────────────────────────────────────────────────
|
|
99
170
|
export const CONSOLE_URLS = {
|
|
100
171
|
gemini: 'https://aistudio.google.com',
|
|
@@ -160,6 +231,18 @@ export function tierOf(rows) {
|
|
|
160
231
|
return 'multi-provider';
|
|
161
232
|
return providers[0] === 'ollama' ? 'keyless' : providers[0];
|
|
162
233
|
}
|
|
234
|
+
/** The OAuth grants one agent's tools declare, with the variables not set here. */
|
|
235
|
+
function grantsOf(agent, prefix) {
|
|
236
|
+
return agentOAuthGrants(agent, prefix).map((use) => ({
|
|
237
|
+
agent: use.agent,
|
|
238
|
+
tools: use.tools,
|
|
239
|
+
provider: use.oauth2.provider,
|
|
240
|
+
grant: use.oauth2.grant,
|
|
241
|
+
scopes: [...(use.oauth2.scopes ?? [])],
|
|
242
|
+
missingEnv: oauthEnvNames(use.oauth2).filter((name) => !process.env[name]?.trim()),
|
|
243
|
+
hostProblems: grantHostProblems(use),
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
163
246
|
/** The first problem, without the file prefix the doctor already shows. */
|
|
164
247
|
function firstProblem(err) {
|
|
165
248
|
if (err instanceof SyndicateValidationError)
|
|
@@ -179,6 +262,8 @@ function needsOf(agent, delegates = false) {
|
|
|
179
262
|
function walk(config, prefix, opts, rows) {
|
|
180
263
|
const orch = config.orchestrator;
|
|
181
264
|
const orchModel = orch?.model;
|
|
265
|
+
if (orch)
|
|
266
|
+
opts.grants.push(...grantsOf(orch, prefix));
|
|
182
267
|
if (orch && orchModel) {
|
|
183
268
|
// In DELEGATE mode the orchestrator calls its subagents as tools; under
|
|
184
269
|
// plan-dispatch it is a tool-less classifier and code runs the route; in
|
|
@@ -218,6 +303,7 @@ function walk(config, prefix, opts, rows) {
|
|
|
218
303
|
}
|
|
219
304
|
continue;
|
|
220
305
|
}
|
|
306
|
+
opts.grants.push(...grantsOf(sub, prefix));
|
|
221
307
|
// A subagent without its own model inherits the orchestrator's.
|
|
222
308
|
const model = sub.model ?? orchModel;
|
|
223
309
|
if (!model)
|
|
@@ -283,7 +369,19 @@ export function diagnoseSyndicate(file, agentsDir, scripts) {
|
|
|
283
369
|
const config = load(file);
|
|
284
370
|
const rows = [];
|
|
285
371
|
const nestedErrors = [];
|
|
286
|
-
|
|
372
|
+
const grants = [];
|
|
373
|
+
walk(config, '', { load, seen: new Set([file, path.basename(file)]), nestedErrors, grants }, rows);
|
|
374
|
+
// Static credentials and the credential host allowlist (ADR 0122); a nested file that cannot load is reported above.
|
|
375
|
+
const loadQuiet = (ref) => {
|
|
376
|
+
try {
|
|
377
|
+
return load(ref);
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
return {};
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const credentialEnvs = [...new Set(syndicateCredentialUses([config], loadQuiet).map((u) => u.env))].sort();
|
|
384
|
+
const credentials = credentialEnvs.length ? { envs: credentialEnvs, problems: credentialHostEnvProblems([config], process.env, loadQuiet) } : undefined;
|
|
287
385
|
const memory = config.memory_system === 'long-term'
|
|
288
386
|
? {
|
|
289
387
|
namespace: config.memory_namespace ?? LEGACY_MEMORY_APP_NAME,
|
|
@@ -302,6 +400,8 @@ export function diagnoseSyndicate(file, agentsDir, scripts) {
|
|
|
302
400
|
...(runCommand ? { runCommand } : {}),
|
|
303
401
|
...(nestedErrors.length ? { error: nestedErrors.join('\n') } : {}),
|
|
304
402
|
...(memory ? { memory } : {}),
|
|
403
|
+
...(grants.length ? { grants } : {}),
|
|
404
|
+
...(credentials ? { credentials } : {}),
|
|
305
405
|
};
|
|
306
406
|
}
|
|
307
407
|
catch (err) {
|
|
@@ -383,8 +483,9 @@ export function runDoctor(options = {}) {
|
|
|
383
483
|
const rawGateway = (process.env[GATEWAY_ENV] ?? '').trim();
|
|
384
484
|
const gateway = rawGateway
|
|
385
485
|
? {
|
|
386
|
-
|
|
387
|
-
|
|
486
|
+
// An unrecognised value is never echoed: it may be a key pasted into the wrong variable.
|
|
487
|
+
id: cfg?.gateway.id ?? 'unrecognised',
|
|
488
|
+
label: cfg?.gateway.label ?? 'an unrecognised gateway',
|
|
388
489
|
usable: gatewayUsable(),
|
|
389
490
|
...(gatewayProblem() ? { problem: gatewayProblem() } : {}),
|
|
390
491
|
}
|
|
@@ -398,7 +499,43 @@ export function runDoctor(options = {}) {
|
|
|
398
499
|
for (const s of syndicates)
|
|
399
500
|
counts[s.verdict.state]++;
|
|
400
501
|
flagMemoryNamespaces(syndicates);
|
|
401
|
-
|
|
502
|
+
// The server's OAuth setup (ADR 0114): the key, the redirect URI and the allowlist, names only.
|
|
503
|
+
const grants = syndicates.flatMap((s) => s.grants ?? []).map((g) => ({ agent: g.agent, tools: g.tools, oauth2: { provider: g.provider, grant: g.grant, token_url: '' } }));
|
|
504
|
+
const set = Object.fromEntries([CREDENTIAL_KEY_ENV, OAUTH_REDIRECT_URI_ENV, OAUTH_HOSTS_ENV].map((name) => [name, !!process.env[name]?.trim()]));
|
|
505
|
+
const oauth = grants.length || Object.values(set).some(Boolean) ? { set, problems: oauthEnvProblems(grants) } : undefined;
|
|
506
|
+
// The credential host allowlist (ADR 0122): unbound variables named, refusals listed, names and hosts only.
|
|
507
|
+
const credentialSet = !!process.env[CREDENTIAL_HOSTS_ENV]?.trim();
|
|
508
|
+
const envs = [...new Set(syndicates.flatMap((s) => s.credentials?.envs ?? []))].sort();
|
|
509
|
+
let credentials;
|
|
510
|
+
if (envs.length || credentialSet) {
|
|
511
|
+
const problems = [];
|
|
512
|
+
try {
|
|
513
|
+
credentialHosts();
|
|
514
|
+
}
|
|
515
|
+
catch (err) {
|
|
516
|
+
problems.push(err instanceof Error ? err.message : `${CREDENTIAL_HOSTS_ENV} is malformed`);
|
|
517
|
+
}
|
|
518
|
+
if (!problems.length)
|
|
519
|
+
for (const s of syndicates)
|
|
520
|
+
for (const p of s.credentials?.problems ?? [])
|
|
521
|
+
problems.push(`${s.file}: ${p}`);
|
|
522
|
+
const warning = unboundCredentialWarning(envs);
|
|
523
|
+
credentials = { set: credentialSet, envs, ...(warning ? { warning } : {}), problems };
|
|
524
|
+
}
|
|
525
|
+
const serving = servingReport();
|
|
526
|
+
return {
|
|
527
|
+
agentsDir,
|
|
528
|
+
runtime: runtimeReport(),
|
|
529
|
+
syndicates,
|
|
530
|
+
unlocks,
|
|
531
|
+
gateway,
|
|
532
|
+
endpoints: endpointRows(),
|
|
533
|
+
counts,
|
|
534
|
+
...(oauth ? { oauth } : {}),
|
|
535
|
+
...(credentials ? { credentials } : {}),
|
|
536
|
+
providers: providerPaths(),
|
|
537
|
+
...(serving ? { serving } : {}),
|
|
538
|
+
};
|
|
402
539
|
}
|
|
403
540
|
// ── Rendering ────────────────────────────────────────────────────────────────
|
|
404
541
|
const ANSI = {
|
|
@@ -419,6 +556,29 @@ const PROBE_ID = {
|
|
|
419
556
|
moonshot: 'kimi-x',
|
|
420
557
|
ollama: 'ollama/x',
|
|
421
558
|
};
|
|
559
|
+
/**
|
|
560
|
+
* Why `melchizedek-doctor --check` exits non-zero, one line each; empty when
|
|
561
|
+
* it passes. A blocked syndicate, a runtime problem, the OAuth setup's and
|
|
562
|
+
* the credential allowlist's problems, and each grant whose hosts the OAuth
|
|
563
|
+
* host allowlist refuses (ADR 0114). Names and hosts only, never a value.
|
|
564
|
+
*/
|
|
565
|
+
export function checkProblems(result) {
|
|
566
|
+
const problems = [];
|
|
567
|
+
if (result.counts.blocked > 0)
|
|
568
|
+
problems.push(`${result.counts.blocked} syndicate(s) blocked`);
|
|
569
|
+
if (result.runtime.problem)
|
|
570
|
+
problems.push(result.runtime.problem);
|
|
571
|
+
for (const p of result.oauth?.problems ?? [])
|
|
572
|
+
problems.push(`oauth: ${p}`);
|
|
573
|
+
for (const p of result.credentials?.problems ?? [])
|
|
574
|
+
problems.push(`credentials: ${p}`);
|
|
575
|
+
for (const s of result.syndicates) {
|
|
576
|
+
for (const g of s.grants ?? [])
|
|
577
|
+
for (const p of g.hostProblems ?? [])
|
|
578
|
+
problems.push(`${s.file}: ${g.agent} · ${g.provider}: ${p}`);
|
|
579
|
+
}
|
|
580
|
+
return problems;
|
|
581
|
+
}
|
|
422
582
|
function pad(s, n) {
|
|
423
583
|
return s.length >= n ? s.slice(0, n - 1) + '…' : s.padEnd(n);
|
|
424
584
|
}
|
|
@@ -445,11 +605,10 @@ export function renderDoctor(result, opts = {}) {
|
|
|
445
605
|
// Provider line: what is funded, and how. Each provider is probed with an
|
|
446
606
|
// id of its own prefix, so the line names ITS key (a fallthrough once put
|
|
447
607
|
// xAI's key beside Moonshot).
|
|
448
|
-
const providerBits =
|
|
449
|
-
const r = describeCapabilities(PROBE_ID[p]);
|
|
608
|
+
const providerBits = (result.providers ?? providerPaths()).map((r) => {
|
|
450
609
|
const mark = !r.funded ? `${c.red}✗${c.reset}` : r.transport === 'gateway' ? `${c.yellow}◇${c.reset}` : `${c.green}✓${c.reset}`;
|
|
451
|
-
const how = !r.funded ? `${c.dim}${r.keyEnv} not set${c.reset}` : r.transport === 'gateway' ? `${c.dim}via gateway:${r.gateway}${c.reset}` :
|
|
452
|
-
return `${mark} ${
|
|
610
|
+
const how = !r.funded ? `${c.dim}${r.keyEnv} not set${c.reset}` : r.transport === 'gateway' ? `${c.dim}via gateway:${r.gateway}${c.reset}` : r.platform === 'local' ? `${c.dim}local${c.reset}` : `${c.dim}${r.platform}${c.reset}`;
|
|
611
|
+
return `${mark} ${r.label} ${how}`;
|
|
453
612
|
});
|
|
454
613
|
lines.push('providers ' + providerBits.join(' '));
|
|
455
614
|
for (const e of result.endpoints ?? []) {
|
|
@@ -464,6 +623,33 @@ export function renderDoctor(result, opts = {}) {
|
|
|
464
623
|
? `gateway ${c.red}✗${c.reset} ${result.gateway.problem}`
|
|
465
624
|
: `gateway ${c.yellow}◇${c.reset} ${result.gateway.label} fills in for any provider whose direct key is absent ${c.dim}(native search is lost on that path)${c.reset}`);
|
|
466
625
|
}
|
|
626
|
+
if (result.serving) {
|
|
627
|
+
// Names only: the A2A identity mode, who pays, and what the server would refuse.
|
|
628
|
+
const sv = result.serving;
|
|
629
|
+
const mark = sv.problems.length ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
|
|
630
|
+
const set = Object.entries(sv.set).filter(([, on]) => on).map(([name]) => name).join(', ');
|
|
631
|
+
lines.push(`serving ${mark} A2A_AUTH=${sv.auth}${sv.authDeclared ? '' : ' (default)'} · A2A_KEY_MODE=${sv.keyMode} ${c.dim}· set: ${set || 'none'}${c.reset}`);
|
|
632
|
+
for (const p of sv.problems)
|
|
633
|
+
lines.push(` ${c.red}✗ ${p}${c.reset}`);
|
|
634
|
+
}
|
|
635
|
+
if (result.oauth) {
|
|
636
|
+
// Names only: which variables are set, never their values (ADR 0114).
|
|
637
|
+
const set = Object.entries(result.oauth.set).map(([name, on]) => `${name} ${on ? 'set' : 'unset'}`).join(' · ');
|
|
638
|
+
const mark = result.oauth.problems.length ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
|
|
639
|
+
lines.push(`oauth ${mark} ${c.dim}${set}${c.reset}`);
|
|
640
|
+
for (const p of result.oauth.problems)
|
|
641
|
+
lines.push(` ${c.red}✗ ${p}${c.reset}`);
|
|
642
|
+
}
|
|
643
|
+
if (result.credentials) {
|
|
644
|
+
// Names only: which variables are sent, never their values (ADR 0122).
|
|
645
|
+
const cr = result.credentials;
|
|
646
|
+
const mark = cr.problems.length ? `${c.red}✗${c.reset}` : cr.warning ? `${c.yellow}⚠${c.reset}` : `${c.green}✓${c.reset}`;
|
|
647
|
+
lines.push(`credentials ${mark} ${c.dim}${CREDENTIAL_HOSTS_ENV} ${cr.set ? 'set' : 'unset'}${cr.envs.length ? ` · sent: ${cr.envs.join(', ')}` : ''}${c.reset}`);
|
|
648
|
+
if (cr.warning)
|
|
649
|
+
lines.push(` ${c.yellow}⚠ ${cr.warning}${c.reset}`);
|
|
650
|
+
for (const p of cr.problems)
|
|
651
|
+
lines.push(` ${c.red}✗ ${p}${c.reset}`);
|
|
652
|
+
}
|
|
467
653
|
lines.push('');
|
|
468
654
|
// The table: one line per syndicate (name, verdict, run command), then
|
|
469
655
|
// one indented line per agent.
|
|
@@ -490,6 +676,16 @@ export function renderDoctor(result, opts = {}) {
|
|
|
490
676
|
if (s.memory?.issue) {
|
|
491
677
|
lines.push(` ${c.yellow}⚠ memory: ${s.memory.issue}${c.reset}`);
|
|
492
678
|
}
|
|
679
|
+
for (const g of s.grants ?? []) {
|
|
680
|
+
const scopes = g.scopes.length ? ` ${c.dim}[${g.scopes.join(' ')}]${c.reset}` : '';
|
|
681
|
+
const what = g.grant === 'authorization_code'
|
|
682
|
+
? `needs a grant: each user connects ${g.provider} (consent) before ${g.tools} works for them`
|
|
683
|
+
: `needs a grant: the server's own ${g.provider} token (client_credentials) for ${g.tools}`;
|
|
684
|
+
const missing = g.missingEnv.length ? ` ${c.red}✗ ${g.missingEnv.join(', ')} not set${c.reset}` : '';
|
|
685
|
+
lines.push(` ${c.cyan}⚿ ${g.agent}${c.reset} ${what}${scopes}${missing}`);
|
|
686
|
+
for (const p of g.hostProblems ?? [])
|
|
687
|
+
lines.push(` ${c.red}✗ ${p}${c.reset}`);
|
|
688
|
+
}
|
|
493
689
|
if (s.declaredTier && s.declaredTier !== s.tier) {
|
|
494
690
|
lines.push(` ${c.yellow}⚠ header says "tier: ${s.declaredTier}" but the models say ${s.tier}${c.reset}`);
|
|
495
691
|
}
|
|
@@ -2,6 +2,7 @@ import type { DispatchConfig } from './dispatch.ts';
|
|
|
2
2
|
export type { DispatchConfig } from './dispatch.ts';
|
|
3
3
|
import type { SkillsConfig } from './tools/skillToolset.ts';
|
|
4
4
|
import type { OpenApiConfig } from './tools/openapiTools.ts';
|
|
5
|
+
import type { McpAuthConfig } from './tools/oauthTools.ts';
|
|
5
6
|
import type { ContextConfig, ExampleConfig } from './compile.ts';
|
|
6
7
|
export type { OpenApiConfig } from './tools/openapiTools.ts';
|
|
7
8
|
export type { SkillsConfig } from './tools/skillToolset.ts';
|
|
@@ -91,7 +92,9 @@ export interface AgentYamlConfig {
|
|
|
91
92
|
outputKey?: string;
|
|
92
93
|
/**
|
|
93
94
|
* Model generation config (temperature, topP, safety, thinking, etc.)
|
|
94
|
-
* Maps to LlmAgentConfig.generateContentConfig.
|
|
95
|
+
* Maps to LlmAgentConfig.generateContentConfig. In YAML a v1 spelling,
|
|
96
|
+
* deprecated (ADR 0115): write `sampling`, `output` and `reasoning`. It
|
|
97
|
+
* stays the engine form the loader hands downstream.
|
|
95
98
|
*/
|
|
96
99
|
generateContentConfig?: GenerateContentConfig;
|
|
97
100
|
/**
|
|
@@ -102,12 +105,54 @@ export interface AgentYamlConfig {
|
|
|
102
105
|
reasoning?: ReasoningSetting;
|
|
103
106
|
/**
|
|
104
107
|
* Output schema for structured JSON responses.
|
|
105
|
-
* Maps to LlmAgentConfig.outputSchema.
|
|
108
|
+
* Maps to LlmAgentConfig.outputSchema. In YAML a v1 spelling, deprecated
|
|
109
|
+
* (ADR 0115): write `output.schema`. It stays the engine form.
|
|
106
110
|
*/
|
|
107
111
|
outputSchema?: Record<string, unknown>;
|
|
112
|
+
/**
|
|
113
|
+
* Sampling, provider-neutral (v2): replaces generateContentConfig's
|
|
114
|
+
* temperature, topP, maxOutputTokens and stopSequences. The loader folds it
|
|
115
|
+
* into generateContentConfig (lib/agentDialect.ts toEngineAgent), so a
|
|
116
|
+
* loaded config never carries it. Cannot be combined with the v1 key it replaces.
|
|
117
|
+
*/
|
|
118
|
+
sampling?: {
|
|
119
|
+
temperature?: number;
|
|
120
|
+
top_p?: number;
|
|
121
|
+
max_output_tokens?: number;
|
|
122
|
+
stop?: string[];
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Structured output (v2): `schema` replaces outputSchema, `mime` replaces
|
|
126
|
+
* generateContentConfig.responseMimeType. Folded into those by the loader.
|
|
127
|
+
*/
|
|
128
|
+
output?: {
|
|
129
|
+
schema?: Record<string, unknown>;
|
|
130
|
+
mime?: 'application/json' | 'text/plain';
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Which tools the model may call (v2, ADR 0117): `auto`, `none`,
|
|
134
|
+
* `required`, or `{ name }` for one tool. Replaces
|
|
135
|
+
* generateContentConfig.toolConfig.functionCallingConfig; folded into it
|
|
136
|
+
* by the loader (lib/agentDialect.ts toEngineAgent).
|
|
137
|
+
*/
|
|
138
|
+
tool_choice?: 'auto' | 'none' | 'required' | {
|
|
139
|
+
name: string;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Per-provider instruction (v2), keyed by provider id (lib/models/providerMap.ts):
|
|
143
|
+
* `instruction` replaces the agent's instruction, `instruction_append` is
|
|
144
|
+
* appended after a blank line, for the provider of the model the agent runs
|
|
145
|
+
* on. Applied at compile time, before the skills index; not for fallback_model.
|
|
146
|
+
*/
|
|
147
|
+
model_overrides?: Partial<Record<'gemini' | 'anthropic' | 'openai' | 'xai' | 'moonshot' | 'ollama', {
|
|
148
|
+
instruction?: string;
|
|
149
|
+
instruction_append?: string;
|
|
150
|
+
}>>;
|
|
108
151
|
mcp_server_url?: string;
|
|
109
152
|
/** The MCP server's tools this agent may use; the rest are not exposed. */
|
|
110
153
|
mcp_tools?: string[];
|
|
154
|
+
/** The OAuth grant the MCP server takes (ADR 0112): each user's, or the server's own. */
|
|
155
|
+
mcp_auth?: McpAuthConfig;
|
|
111
156
|
/** Answers when `model` fails provider-side, or its provider's circuit is open (ADR 0044). */
|
|
112
157
|
fallback_model?: string;
|
|
113
158
|
/**
|
|
@@ -216,6 +261,8 @@ export interface SyndicateYamlConfig {
|
|
|
216
261
|
memory_retention_days?: number;
|
|
217
262
|
/** Optional hard limit on the turn's model calls, subagents included (LLM -> Tool cycles). */
|
|
218
263
|
max_steps?: number;
|
|
264
|
+
/** Delegated calls from one model step that run at once (ADR 0116). Default 4. */
|
|
265
|
+
max_concurrency?: number;
|
|
219
266
|
/**
|
|
220
267
|
* The nested `yaml_reference:` syndicates this one reaches, raw, keyed by
|
|
221
268
|
* reference: written by the registry publisher (`bundleReferences`) so a
|
|
@@ -251,6 +298,11 @@ export interface LoadSyndicateOptions {
|
|
|
251
298
|
* with the public example of the same name (ADR 0018).
|
|
252
299
|
*/
|
|
253
300
|
shippedFallback?: boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Where load-time warnings go (the deprecated v1 spellings of ADR 0115).
|
|
303
|
+
* Default console.warn. A warning names the file and key paths, never a value.
|
|
304
|
+
*/
|
|
305
|
+
onWarning?: (message: string) => void;
|
|
254
306
|
}
|
|
255
307
|
/**
|
|
256
308
|
* Parse CLI variable bindings into a VariableMap.
|
|
@@ -4,6 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
import { createClient } from '@supabase/supabase-js';
|
|
5
5
|
import { hasSupabaseCredentials } from './persistence/supabaseProvider.js';
|
|
6
6
|
import { validateSyndicateConfig } from './syndicateSchema.js';
|
|
7
|
+
import { v1SpellingsOf } from './agentDialect.js';
|
|
7
8
|
// ── Variable Injection (private) ──────────────────────────
|
|
8
9
|
const TOKEN_RE = /\{\{(\w+)\}\}/g;
|
|
9
10
|
const FULL_TOKEN_RE = /^\{\{(\w+)\}\}$/;
|
|
@@ -87,6 +88,7 @@ function resolveAndValidate(raw, label, options) {
|
|
|
87
88
|
...bindings,
|
|
88
89
|
};
|
|
89
90
|
const interpolated = isPlainObject(raw) ? interpolateDeep(raw, merged) : raw;
|
|
91
|
+
warnV1Spellings(interpolated, label, options.onWarning);
|
|
90
92
|
const unresolved = findUnresolvedTokens(interpolated);
|
|
91
93
|
if (unresolved.length > 0) {
|
|
92
94
|
console.warn(`⚠ Unresolved template variables: ${unresolved.map((t) => `{{${t}}}`).join(', ')}`);
|
|
@@ -99,6 +101,24 @@ function resolveAndValidate(raw, label, options) {
|
|
|
99
101
|
}
|
|
100
102
|
return config;
|
|
101
103
|
}
|
|
104
|
+
/** Labels already warned about, so a server loading one file per request warns once per process. */
|
|
105
|
+
const warnedV1 = new Set();
|
|
106
|
+
/**
|
|
107
|
+
* One line per label when a file still uses the v1 spellings ADR 0115
|
|
108
|
+
* deprecates. Key paths and the label only: never a value (a prompt, a key).
|
|
109
|
+
*/
|
|
110
|
+
function warnV1Spellings(raw, label, onWarning = console.warn) {
|
|
111
|
+
if (warnedV1.has(label))
|
|
112
|
+
return;
|
|
113
|
+
const paths = v1SpellingsOf(raw);
|
|
114
|
+
if (!paths.length)
|
|
115
|
+
return;
|
|
116
|
+
warnedV1.add(label);
|
|
117
|
+
const fix = label.startsWith('registry:') || label.startsWith('bundled:')
|
|
118
|
+
? 'Run npx melchizedek-codemod on the file it was published from, and republish'
|
|
119
|
+
: `Run npx melchizedek-codemod ${label} to rewrite them`;
|
|
120
|
+
onWarning(`⚠ ${label}: generateContentConfig and outputSchema are v1 spellings, deprecated (ADR 0115): ${paths.join(', ')}. ${fix}.`);
|
|
121
|
+
}
|
|
102
122
|
function applyOverrides(config, overrides) {
|
|
103
123
|
return { ...config, ...overrides };
|
|
104
124
|
}
|
|
@@ -227,9 +247,9 @@ export function collectGuards(config, loadNested = nestedLoader(config), seen =
|
|
|
227
247
|
return [...names];
|
|
228
248
|
}
|
|
229
249
|
export function loadSyndicate(filename, options = {}) {
|
|
230
|
-
const { bindings = {}, overrides } = options;
|
|
250
|
+
const { bindings = {}, overrides, onWarning } = options;
|
|
231
251
|
const { raw, label, filePath } = readSyndicateFile(filename, options);
|
|
232
|
-
return anchorSpecPaths(resolveAndValidate(raw, label, { bindings, overrides }), path.dirname(filePath));
|
|
252
|
+
return anchorSpecPaths(resolveAndValidate(raw, label, { bindings, overrides, onWarning }), path.dirname(filePath));
|
|
233
253
|
}
|
|
234
254
|
/**
|
|
235
255
|
* An `openapi:` spec path is written relative to the syndicate file, so a
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* lib/memory/namespace.ts — memory always resolves to the ROOT syndicate's
|
|
3
3
|
* namespace (ADR 0020 item 3).
|
|
4
4
|
*
|
|
5
|
-
* WHY: a DELEGATE subagent runs on its own session row under
|
|
6
|
-
* `appName = <
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* WHY: a DELEGATE subagent runs on its own session row, filed under its
|
|
6
|
+
* agent path (`appName = <app>/<caller>/<subagent>`, ADR 0111; the
|
|
7
|
+
* subagent's name alone in a conversation stored before), and its memory
|
|
8
|
+
* tools search with the session's app name. Facts are written under the
|
|
9
|
+
* root syndicate's namespace, so a `load_memory` declared on a subagent
|
|
10
|
+
* would search the child's own key, find nothing, and say so without error. Wrapping the
|
|
10
11
|
* service the runtime receives pins every search and ingestion to one
|
|
11
12
|
* namespace, whatever app name the caller carries.
|
|
12
13
|
*
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* lib/memory/namespace.ts — memory always resolves to the ROOT syndicate's
|
|
3
3
|
* namespace (ADR 0020 item 3).
|
|
4
4
|
*
|
|
5
|
-
* WHY: a DELEGATE subagent runs on its own session row under
|
|
6
|
-
* `appName = <
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* WHY: a DELEGATE subagent runs on its own session row, filed under its
|
|
6
|
+
* agent path (`appName = <app>/<caller>/<subagent>`, ADR 0111; the
|
|
7
|
+
* subagent's name alone in a conversation stored before), and its memory
|
|
8
|
+
* tools search with the session's app name. Facts are written under the
|
|
9
|
+
* root syndicate's namespace, so a `load_memory` declared on a subagent
|
|
10
|
+
* would search the child's own key, find nothing, and say so without error. Wrapping the
|
|
10
11
|
* service the runtime receives pins every search and ingestion to one
|
|
11
12
|
* namespace, whatever app name the caller carries.
|
|
12
13
|
*
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { endpointFromEnv } from '../models/endpoints.js';
|
|
32
32
|
import { GoogleGenAI } from '@google/genai';
|
|
33
|
-
import {
|
|
33
|
+
import { SpanStatusCode } from '@opentelemetry/api';
|
|
34
34
|
import { llmRequestToModelRequest, modelResponseToLlmResponse } from '../models/genaiMapping.js';
|
|
35
35
|
import { EMBEDDING_DIMENSIONS, EMBEDDING_MODEL, MEMORY_EXTRACTION_MODEL } from '../config.js';
|
|
36
36
|
import { providerForModel } from '../models/providerMap.js';
|
|
37
37
|
import { resolveModel } from '../models/registry.js';
|
|
38
|
-
import {
|
|
38
|
+
import { startEngineSpan, traceLlmGeneration } from '../observability/tracer.js';
|
|
39
39
|
import { trimTrailingSlashes } from '../models/urls.js';
|
|
40
40
|
/**
|
|
41
41
|
* Extraction on any model id. The key passed here reaches only a model of
|
|
@@ -86,8 +86,7 @@ export function modelExtractor(opts = {}) {
|
|
|
86
86
|
* a reasoning step.
|
|
87
87
|
*/
|
|
88
88
|
async function traced(provider, model, count, fn) {
|
|
89
|
-
|
|
90
|
-
const span = trace.getTracer('melchizedek-tracer').startSpan('llm.request');
|
|
89
|
+
const span = startEngineSpan('melchizedek-tracer', 'llm.request');
|
|
91
90
|
span.setAttribute('llm.provider', provider);
|
|
92
91
|
span.setAttribute('llm.model', model);
|
|
93
92
|
span.setAttribute('llm.purpose', 'memory_embedding');
|
|
@@ -55,7 +55,7 @@ export declare function describeCapabilities(model: string, tools?: readonly str
|
|
|
55
55
|
* a funded direct path with no dropped tool is the quiet default.
|
|
56
56
|
*/
|
|
57
57
|
export declare function capabilitySummary(agentName: string, r: CapabilityReport): string | undefined;
|
|
58
|
-
export declare const CAPABILITIES: readonly ['delegation', 'memory_tools', 'structured_output', 'thinking_with_tools', 'streaming', 'vision', 'native_search'];
|
|
58
|
+
export declare const CAPABILITIES: readonly ['delegation', 'memory_tools', 'structured_output', 'structured_output_with_tools', 'thinking_with_tools', 'streaming', 'vision', 'native_search'];
|
|
59
59
|
export type Capability = (typeof CAPABILITIES)[number];
|
|
60
60
|
export declare const CAPABILITY_LABELS: Record<Capability, string>;
|
|
61
61
|
export type Support = 'supported' | 'degraded' | 'unsupported';
|
|
@@ -74,6 +74,30 @@ export declare function capabilityOf(model: string, capability: Capability, opts
|
|
|
74
74
|
}): CapabilityCell & {
|
|
75
75
|
row: MatrixRow;
|
|
76
76
|
};
|
|
77
|
+
/**
|
|
78
|
+
* The reasoning levels above `high` (ADR 0117), per row: what `reasoning:
|
|
79
|
+
* xhigh` and `reasoning: max` reach the provider as. A level a model lacks
|
|
80
|
+
* goes as its highest setting, and the request's `llm.request` span carries
|
|
81
|
+
* `llm.reasoning.weakened` with the level asked for. Asserted against the
|
|
82
|
+
* request bodies in tests/toolChoiceEffort.test.ts; the direct adapters read
|
|
83
|
+
* lib/models/reasoning.ts effortCeiling.
|
|
84
|
+
*/
|
|
85
|
+
export declare const REASONING_ABOVE_HIGH: Readonly<Record<MatrixRow, string>>;
|
|
86
|
+
/**
|
|
87
|
+
* Whether an outputSchema goes in the same request as the agent's tools, as
|
|
88
|
+
* the provider's own structured-output field, on the path `model` takes
|
|
89
|
+
* (ADR 0109). True only where the `structured_output_with_tools` cell is
|
|
90
|
+
* supported and the model's generation takes it: Claude from Opus 4.8,
|
|
91
|
+
* Sonnet 5 and Haiku 5.5 on (`output_config.format`), every OpenAI id
|
|
92
|
+
* (`text.format`), Gemini 2 and later on Vertex AI (`responseJsonSchema`).
|
|
93
|
+
* Elsewhere the native loop declares set_model_response beside the tools
|
|
94
|
+
* (lib/runtime/native/request.ts), which works on every path. A path that
|
|
95
|
+
* cannot be planned (a malformed gateway setting) answers false, the form
|
|
96
|
+
* that works everywhere.
|
|
97
|
+
*/
|
|
98
|
+
export declare function outputSchemaBesideTools(model: string, opts?: {
|
|
99
|
+
callerKey?: boolean;
|
|
100
|
+
}): boolean;
|
|
77
101
|
/** What one agent's YAML asks of its model. */
|
|
78
102
|
export interface AgentNeedsInput {
|
|
79
103
|
tools?: readonly string[];
|