melchizedek-agents 1.1.0 → 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 +10 -0
- package/AGENT_SETUP.md +3 -1
- package/CHANGELOG.md +232 -0
- package/DOCUMENTATION.md +91 -16
- package/ONBOARDING.md +339 -0
- package/QUICKSTART.md +15 -2
- package/README.md +5 -2
- package/config/agents/examples/council.yaml +1 -1
- package/config/agents/examples/critic.yaml +8 -8
- package/config/agents/examples/image_production.yaml +4 -3
- package/config/agents/syndicate.schema.json +65 -7
- package/config/agents/syndicateSchema.yaml +18 -6
- package/config/agents/templates/intake_extractor.yaml +3 -2
- package/config/agents/templates/systems_operator.yaml +5 -2
- package/dist/lib/a2a/app.d.ts +12 -0
- package/dist/lib/a2a/app.js +22 -11
- package/dist/lib/a2a/executor.js +14 -6
- package/dist/lib/a2a/oauthSetup.d.ts +16 -0
- package/dist/lib/a2a/oauthSetup.js +57 -3
- package/dist/lib/agentDialect.d.ts +18 -8
- package/dist/lib/agentDialect.js +36 -19
- package/dist/lib/compile.d.ts +38 -7
- package/dist/lib/compile.js +57 -37
- package/dist/lib/compileNative.d.ts +11 -3
- package/dist/lib/compileNative.js +18 -1
- package/dist/lib/doctor.d.ts +76 -0
- package/dist/lib/doctor.js +159 -7
- package/dist/lib/loadSyndicate.d.ts +9 -0
- package/dist/lib/models/capabilities.d.ts +9 -0
- package/dist/lib/models/capabilities.js +24 -0
- 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/onboarding.d.ts +134 -0
- package/dist/lib/onboarding.js +539 -0
- package/dist/lib/runtime/approvals.d.ts +2 -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 +5 -2
- package/dist/lib/runtime/native/agentLoop.js +2 -0
- package/dist/lib/runtime/native/checkpoint.d.ts +12 -5
- package/dist/lib/runtime/native/checkpoint.js +13 -19
- package/dist/lib/runtime/native/delegate.d.ts +82 -1
- package/dist/lib/runtime/native/delegate.js +157 -2
- package/dist/lib/runtime/native/interrupts.d.ts +88 -5
- package/dist/lib/runtime/native/interrupts.js +220 -30
- package/dist/lib/runtime/syndicateTurn.d.ts +4 -2
- package/dist/lib/runtime/syndicateTurn.js +295 -62
- package/dist/lib/runtime/turnControl.d.ts +41 -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 +6 -1
- package/dist/lib/storage/postgres/index.js +1 -1
- package/dist/lib/storage/postgres/taskQueue.d.ts +7 -3
- package/dist/lib/storage/postgres/taskQueue.js +10 -3
- package/dist/lib/syndicateSchema.d.ts +38 -1
- package/dist/lib/syndicateSchema.js +25 -18
- package/dist/lib/tools/auth.d.ts +13 -1
- package/dist/lib/tools/auth.js +10 -2
- package/dist/lib/tools/credentialHosts.d.ts +88 -0
- package/dist/lib/tools/credentialHosts.js +165 -0
- package/dist/lib/tools/credentialUses.d.ts +92 -0
- package/dist/lib/tools/credentialUses.js +112 -0
- package/dist/lib/tools/mcpToolFactory.js +1 -1
- package/dist/lib/tools/oauthConsent.js +8 -1
- package/dist/lib/tools/oauthHosts.d.ts +2 -0
- package/dist/lib/tools/oauthHosts.js +2 -2
- package/dist/lib/tools/oauthTools.d.ts +10 -1
- package/dist/lib/tools/oauthTools.js +29 -3
- package/dist/lib/tools/openapiTools.d.ts +7 -0
- package/dist/lib/tools/openapiTools.js +49 -3
- package/dist/lib/tools/taskTools.d.ts +32 -2
- package/dist/lib/tools/taskTools.js +93 -33
- package/dist/lib/workflow/turn.d.ts +22 -3
- package/dist/lib/workflow/turn.js +151 -31
- package/dist/lib/workflow.d.ts +10 -7
- package/dist/lib/workflow.js +10 -7
- package/dist/scripts/a2a_server.d.ts +2 -2
- package/dist/scripts/a2a_server.js +11 -2
- package/dist/scripts/assistant_worker.d.ts +2 -0
- package/dist/scripts/assistant_worker.js +13 -4
- package/dist/scripts/doctor.d.ts +4 -2
- package/dist/scripts/doctor.js +6 -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 +12 -2
- package/dist/scripts/yaml_codemod.js +115 -33
- package/package.json +4 -1
- package/skills/README.md +11 -2
- package/skills/briefs/_shared.md +1 -1
- package/skills/briefs/melchizedek-models.md +4 -2
- package/skills/briefs/skills-readme.md +3 -1
- package/skills/melchizedek-models/SKILL.md +6 -2
- 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
|
@@ -365,7 +365,7 @@ orchestrator:
|
|
|
365
365
|
|
|
366
366
|
# ── reasoning ─────────────────────────────────────────────
|
|
367
367
|
# [optional] How hard the agent reasons, on any provider (ADR 0047):
|
|
368
|
-
# none | low | medium | high, or { budget_tokens: <int> }.
|
|
368
|
+
# none | low | medium | high | xhigh | max, or { budget_tokens: <int> }.
|
|
369
369
|
# The compiler sends each provider the field it reads:
|
|
370
370
|
# gemini-3 and later → thinkingConfig.thinkingLevel
|
|
371
371
|
# (none = MINIMAL, then LOW, MEDIUM, HIGH)
|
|
@@ -382,6 +382,10 @@ orchestrator:
|
|
|
382
382
|
# A budget is sent as-is to Gemini and to Claude 4.6 and earlier, and as
|
|
383
383
|
# the smallest level that covers it everywhere else. Unset, each provider
|
|
384
384
|
# keeps its default.
|
|
385
|
+
# xhigh and max (ADR 0117) reach the models that take them: both on later
|
|
386
|
+
# claude-*, max on kimi-k3 (xhigh rounds up to it), xhigh on gpt-5.2 and
|
|
387
|
+
# later and grok-4.7. Elsewhere the model's highest setting is sent and
|
|
388
|
+
# the span carries llm.reasoning.weakened; a gateway gets high.
|
|
385
389
|
# Cannot be combined with generateContentConfig.thinkingConfig or
|
|
386
390
|
# generateContentConfig.reasoningEffort, its deprecated v1 spelling.
|
|
387
391
|
reasoning: medium
|
|
@@ -422,6 +426,14 @@ orchestrator:
|
|
|
422
426
|
# answer: { type: string }
|
|
423
427
|
# required: [answer]
|
|
424
428
|
|
|
429
|
+
# ── tool_choice ───────────────────────────────────────────
|
|
430
|
+
# [optional] Which tools the model may call, on any provider (ADR 0117):
|
|
431
|
+
# auto (the default) | none | required (some tool)
|
|
432
|
+
# | { name: <tool> } (that one tool).
|
|
433
|
+
# A provider that rejects forcing a tool gets a weaker choice, and the
|
|
434
|
+
# span carries llm.tool_choice.weakened.
|
|
435
|
+
# tool_choice: auto
|
|
436
|
+
|
|
425
437
|
# ── model_overrides ───────────────────────────────────────
|
|
426
438
|
# [optional] A prompt nuance for one provider (ADR 0115). Keys are the
|
|
427
439
|
# providers a model id routes to: gemini, anthropic, openai, xai,
|
|
@@ -438,11 +450,11 @@ orchestrator:
|
|
|
438
450
|
# The v1 spelling: @google/genai's GenerateContentConfig, with
|
|
439
451
|
# outputSchema beside it. Still loads and behaves as before, with one
|
|
440
452
|
# deprecation line per file; `npx melchizedek-codemod <file>` rewrites
|
|
441
|
-
# it into sampling, output and
|
|
442
|
-
# spelling is a load error. Only
|
|
443
|
-
#
|
|
444
|
-
#
|
|
445
|
-
#
|
|
453
|
+
# it into sampling, output, reasoning and tool_choice. A v2 key beside
|
|
454
|
+
# its v1 spelling is a load error. Only toolConfig's VALIDATED mode and
|
|
455
|
+
# Gemini's dynamic budget (thinkingBudget: -1) have no v2 form. topK,
|
|
456
|
+
# seed, the penalties, candidateCount, safetySettings and
|
|
457
|
+
# includeThoughts reach no provider.
|
|
446
458
|
|
|
447
459
|
# ── Subagents ───────────────────────────────────────────────
|
|
448
460
|
# Each entry is an agent the orchestrator calls as a tool (DELEGATE),
|
|
@@ -23,8 +23,9 @@
|
|
|
23
23
|
#
|
|
24
24
|
# SHAPE: a single agent with an `outputSchema`, so the reply is JSON the
|
|
25
25
|
# schema describes, parseable without a second model call. No subagents and
|
|
26
|
-
# no tools
|
|
27
|
-
#
|
|
26
|
+
# no tools, by choice rather than by rule (an agent that delegates or calls
|
|
27
|
+
# tools may hold a schema too, ADR 0109): the document is the only input,
|
|
28
|
+
# and the extractor may not add anything the document does not say.
|
|
28
29
|
#
|
|
29
30
|
# REDACTION: card numbers, bank details, passwords and government IDs are
|
|
30
31
|
# never copied into the record, not even as a `references` entry; `redacted`
|
|
@@ -24,8 +24,11 @@
|
|
|
24
24
|
# `mcp_auth: { oauth2 }` (ADR 0112): uncomment the block on Systems
|
|
25
25
|
# below. client_credentials gives the server's own token on every
|
|
26
26
|
# request. authorization_code (each person's own token, granted
|
|
27
|
-
# through the consent pause)
|
|
28
|
-
#
|
|
27
|
+
# through the consent pause) works on Systems too: the first call
|
|
28
|
+
# for a person who has not connected pauses the turn with an
|
|
29
|
+
# authorization link, and their next message after the grant
|
|
30
|
+
# resumes Systems' call (ADR 0118). It also needs mcp_tools, the
|
|
31
|
+
# server's tool names, and an operator allowlist (ADR 0114).
|
|
29
32
|
# `npm run doctor` lists every tool that needs a grant.
|
|
30
33
|
# Loopback and private addresses are refused unless
|
|
31
34
|
# ALLOW_PRIVATE_MCP=true (local development).
|
package/dist/lib/a2a/app.d.ts
CHANGED
|
@@ -219,6 +219,18 @@ export interface A2AAppOptions {
|
|
|
219
219
|
* refused when loaded, when compiled, and at each call.
|
|
220
220
|
*/
|
|
221
221
|
oauthHosts?: Record<string, string[]>;
|
|
222
|
+
/**
|
|
223
|
+
* The credential host allowlist (ADR 0122): each static credential
|
|
224
|
+
* variable a YAML may send (`bearer_env`, `api_key.env`,
|
|
225
|
+
* `client_secret_env`) and the hosts its value may go to, e.g.
|
|
226
|
+
* `{ TRACKER_TOKEN: ['api.tracker.example.com'] }`. Wins over
|
|
227
|
+
* MELCHIZEDEK_CREDENTIAL_HOSTS; it is set for this process. With neither,
|
|
228
|
+
* a credential goes to the host the YAML names, as before. With one, it is
|
|
229
|
+
* the whole list: a syndicate that sends a variable it does not bind, or
|
|
230
|
+
* to a host outside that variable's, is refused when loaded, when
|
|
231
|
+
* compiled, and at each call.
|
|
232
|
+
*/
|
|
233
|
+
credentialHosts?: Record<string, string[]>;
|
|
222
234
|
toolCredentials?: ToolCredentials & {
|
|
223
235
|
/** Callback requests per window per client IP. Default 30 per 15 minutes. */
|
|
224
236
|
callbackLimit?: {
|
package/dist/lib/a2a/app.js
CHANGED
|
@@ -64,6 +64,8 @@ import { HEADER_VALUE_PATTERN, SCOPE_KEY_PATTERN } from './identity.js';
|
|
|
64
64
|
import { createMetrics } from '../observability/metrics.js';
|
|
65
65
|
import { ConsentError } from '../tools/oauthConsent.js';
|
|
66
66
|
import { setOAuthHosts } from '../tools/oauthHosts.js';
|
|
67
|
+
import { setCredentialHosts } from '../tools/credentialHosts.js';
|
|
68
|
+
import { syndicateCredentialHostProblems } from '../tools/credentialUses.js';
|
|
67
69
|
import { syndicateOAuthHostProblems } from '../tools/oauthTools.js';
|
|
68
70
|
const SURFACE_HEADERS = [
|
|
69
71
|
['x-surface', 'name'],
|
|
@@ -280,21 +282,30 @@ export async function createA2AApp(options) {
|
|
|
280
282
|
// ── The OAuth host allowlist (ADR 0114) ────────────────────────────────────
|
|
281
283
|
if (options.oauthHosts)
|
|
282
284
|
setOAuthHosts(options.oauthHosts);
|
|
283
|
-
|
|
285
|
+
// ── The credential host allowlist (ADR 0122) ───────────────────────────────
|
|
286
|
+
if (options.credentialHosts)
|
|
287
|
+
setCredentialHosts(options.credentialHosts);
|
|
288
|
+
/**
|
|
289
|
+
* A served syndicate whose OAuth grant names a provider or host outside the
|
|
290
|
+
* OAuth allowlist, or that sends a static credential the credential
|
|
291
|
+
* allowlist does not bind to its host, is refused at load.
|
|
292
|
+
*/
|
|
284
293
|
const checkOAuthHosts = (cfg, label) => {
|
|
285
294
|
const nested = nestedLoader(cfg, (ref) => loadSyndicate(ref, { bindings: bindings() }));
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
});
|
|
295
|
+
const load = (ref) => {
|
|
296
|
+
try {
|
|
297
|
+
return nested(ref);
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return {}; // A nested file that cannot load fails its own compile.
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
const problems = syndicateOAuthHostProblems([cfg], { load });
|
|
296
304
|
if (problems.length)
|
|
297
305
|
throw new Error(`${label}: refusing an OAuth grant the operator's host allowlist does not permit:\n - ${problems.join('\n - ')}`);
|
|
306
|
+
const credentials = syndicateCredentialHostProblems([cfg], { load });
|
|
307
|
+
if (credentials.length)
|
|
308
|
+
throw new Error(`${label}: refusing a credential the operator's credential host allowlist does not permit:\n - ${credentials.join('\n - ')}`);
|
|
298
309
|
return cfg;
|
|
299
310
|
};
|
|
300
311
|
// ── The default syndicate ──────────────────────────────────────────────────
|
package/dist/lib/a2a/executor.js
CHANGED
|
@@ -22,7 +22,7 @@ import { turnLockKey } from './turnLock.js';
|
|
|
22
22
|
import { ingestTurnMemory, runSyndicateTurn } from '../runtime/syndicateTurn.js';
|
|
23
23
|
import { approvalResponsePart, describeApproval, pendingApproval } from '../runtime/approvals.js';
|
|
24
24
|
import { declaresApprovals } from '../compile.js';
|
|
25
|
-
import { delegatedPauses } from '../runtime/native/interrupts.js';
|
|
25
|
+
import { deepestPause, delegatedPauses, routePause } from '../runtime/native/interrupts.js';
|
|
26
26
|
import { isWorkflowSyndicate } from '../workflow.js';
|
|
27
27
|
import { describeInput } from '../runtime/syndicateTurn.js';
|
|
28
28
|
import { describeConsent } from '../runtime/credentials.js';
|
|
@@ -323,7 +323,8 @@ function publishApprovalRequest(eventBus, taskId, contextId, pending) {
|
|
|
323
323
|
* naming the provider, with a data part carrying the authorization URL and
|
|
324
324
|
* its state nonce. The person opens the URL; the server's callback stores
|
|
325
325
|
* the grant; the next message on the conversation resumes the call. The
|
|
326
|
-
* part carries no token, code or verifier.
|
|
326
|
+
* part carries no token, code or verifier. For a call inside a delegated
|
|
327
|
+
* subagent it carries the agent path too (ADR 0118).
|
|
327
328
|
*/
|
|
328
329
|
function publishConsentRequest(eventBus, taskId, contextId, pending) {
|
|
329
330
|
const message = statusMessage(taskId, contextId, `Authorization needed: ${describeConsent(pending)}. Open ${pending.authUri} to authorize, then send any message on this conversation to continue.`);
|
|
@@ -338,6 +339,8 @@ function publishConsentRequest(eventBus, taskId, contextId, pending) {
|
|
|
338
339
|
authorization_url: pending.authUri,
|
|
339
340
|
state: pending.state,
|
|
340
341
|
scopes: pending.scopes,
|
|
342
|
+
// A call paused inside a delegated subagent: the agents from the turn's own down to the one that asked (ADR 0118).
|
|
343
|
+
...(pending.path ? { path: pending.path } : {}),
|
|
341
344
|
},
|
|
342
345
|
},
|
|
343
346
|
metadata: undefined,
|
|
@@ -594,13 +597,18 @@ export class SyndicateExecutor {
|
|
|
594
597
|
// A call gated inside a delegated subagent waits below an open call
|
|
595
598
|
// (ADR 0110), wherever the gate is declared, so a syndicate that
|
|
596
599
|
// delegates is read too.
|
|
597
|
-
|
|
598
|
-
|
|
600
|
+
// A workflow's node that is a nested workflow, and a dispatch route that is one, pause on their walk's gates
|
|
601
|
+
// wherever those are declared (ADR 0119), so every workflow, and every syndicate that delegates or routes, is read.
|
|
602
|
+
const workflow = isWorkflowSyndicate(config);
|
|
603
|
+
const delegates = !workflow && !!config.subagents?.length;
|
|
604
|
+
if (declaresApprovals(config) || delegates || workflow) {
|
|
599
605
|
const session = await this.sessions.get({ appName, userId, sessionId: contextId });
|
|
600
606
|
// The stored Event JSON (ADR 0052), read as TurnEvents.
|
|
601
607
|
const events = session?.events ?? [];
|
|
602
|
-
const
|
|
603
|
-
|
|
608
|
+
const key = { sessions: this.sessions, userId, sessionId: contextId, appName };
|
|
609
|
+
const own = declaresApprovals(config) || workflow ? pendingApproval(events) : undefined;
|
|
610
|
+
const pending = (own && workflow ? await deepestPause(key, own) : own) ??
|
|
611
|
+
(delegates ? ((await routePause(key, events))?.approval ?? (await delegatedPauses(key, events))[0]?.approval) : undefined);
|
|
604
612
|
if (pending) {
|
|
605
613
|
const answer = approvalAnswer(rawParts, pending);
|
|
606
614
|
if (!answer) {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* MELCHIZEDEK_CREDENTIAL_KEY the key that seals each user's tokens (ADR 0072)
|
|
14
14
|
* OAUTH_REDIRECT_URI the consent callback, as registered at every provider (ADR 0085)
|
|
15
15
|
* MELCHIZEDEK_OAUTH_HOSTS which hosts each provider's tokens may go to (ADR 0114)
|
|
16
|
+
* MELCHIZEDEK_CREDENTIAL_HOSTS which hosts each static credential variable may go to (ADR 0122)
|
|
16
17
|
* the client id and secret variables each YAML grant names
|
|
17
18
|
*
|
|
18
19
|
* The consent clients are built from the syndicates the server serves from
|
|
@@ -54,6 +55,19 @@ export declare function grantHostProblems(use: OAuthGrantUse, env?: NodeJS.Proce
|
|
|
54
55
|
* server refuses to start on the ones that would make it unsafe.
|
|
55
56
|
*/
|
|
56
57
|
export declare function oauthEnvProblems(grants: readonly OAuthGrantUse[], env?: NodeJS.ProcessEnv): string[];
|
|
58
|
+
/**
|
|
59
|
+
* The warning for credential variables no allowlist binds (ADR 0122), or
|
|
60
|
+
* null: with no credential host allowlist, each variable in `envs` (the
|
|
61
|
+
* ones the served YAML sends) still goes to whatever host the YAML names.
|
|
62
|
+
* Names only.
|
|
63
|
+
*/
|
|
64
|
+
export declare function unboundCredentialWarning(envs: readonly string[], env?: NodeJS.ProcessEnv): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* What is wrong with the credential host allowlist for these uses, one line
|
|
67
|
+
* each, names and hosts only: a malformed allowlist, or each use it refuses
|
|
68
|
+
* (lib/tools/credentialUses.ts). Empty when none is configured.
|
|
69
|
+
*/
|
|
70
|
+
export declare function credentialHostEnvProblems(configs: readonly SyndicateLike[], env?: NodeJS.ProcessEnv, load?: (ref: string) => SyndicateLike): string[];
|
|
57
71
|
/** The parts of a syndicate config the setup reads. */
|
|
58
72
|
type SyndicateLike = Parameters<typeof oauthClientsFor>[0][number];
|
|
59
73
|
export interface OAuthServerSetupOptions {
|
|
@@ -76,6 +90,8 @@ export interface OAuthServerSetup {
|
|
|
76
90
|
toolCredentials?: ToolCredentials;
|
|
77
91
|
/** One line for the server's banner: key id, row store, consent path, providers, allowlist. No value. */
|
|
78
92
|
summary: string;
|
|
93
|
+
/** One line for the server's banner: the credential host allowlist (ADR 0122), variable names only. */
|
|
94
|
+
credentialSummary: string;
|
|
79
95
|
/** What works less than the YAML asks, names only. */
|
|
80
96
|
warnings: string[];
|
|
81
97
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* MELCHIZEDEK_CREDENTIAL_KEY the key that seals each user's tokens (ADR 0072)
|
|
14
14
|
* OAUTH_REDIRECT_URI the consent callback, as registered at every provider (ADR 0085)
|
|
15
15
|
* MELCHIZEDEK_OAUTH_HOSTS which hosts each provider's tokens may go to (ADR 0114)
|
|
16
|
+
* MELCHIZEDEK_CREDENTIAL_HOSTS which hosts each static credential variable may go to (ADR 0122)
|
|
16
17
|
* the client id and secret variables each YAML grant names
|
|
17
18
|
*
|
|
18
19
|
* The consent clients are built from the syndicates the server serves from
|
|
@@ -27,6 +28,8 @@ import { credentialStore, memoryCredentialRows } from '../tools/credentialStore.
|
|
|
27
28
|
import { oauthConsent } from '../tools/oauthConsent.js';
|
|
28
29
|
import { OAUTH_HOSTS_ENV, oauthHosts } from '../tools/oauthHosts.js';
|
|
29
30
|
import { oauthClientsFor, oauthGrantHostProblems, oauthRefreshProviders, syndicateOAuthGrants, syndicateOAuthHostProblems } from '../tools/oauthTools.js';
|
|
31
|
+
import { CREDENTIAL_HOSTS_ENV, credentialHosts } from '../tools/credentialHosts.js';
|
|
32
|
+
import { syndicateCredentialHostProblems, syndicateCredentialUses, unboundCredentialEnvs } from '../tools/credentialUses.js';
|
|
30
33
|
/** The consent callback's URL, exactly as registered at every provider. */
|
|
31
34
|
export const OAUTH_REDIRECT_URI_ENV = 'OAUTH_REDIRECT_URI';
|
|
32
35
|
/** Who may complete a consent callback: `required` (the browser carries the user's identity) or `state` (the nonce alone). */
|
|
@@ -138,6 +141,42 @@ export function oauthEnvProblems(grants, env = process.env) {
|
|
|
138
141
|
}
|
|
139
142
|
return problems;
|
|
140
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* The warning for credential variables no allowlist binds (ADR 0122), or
|
|
146
|
+
* null: with no credential host allowlist, each variable in `envs` (the
|
|
147
|
+
* ones the served YAML sends) still goes to whatever host the YAML names.
|
|
148
|
+
* Names only.
|
|
149
|
+
*/
|
|
150
|
+
export function unboundCredentialWarning(envs, env = process.env) {
|
|
151
|
+
let allowlist;
|
|
152
|
+
try {
|
|
153
|
+
allowlist = credentialHosts(env);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return null; // A malformed allowlist is a problem, reported as one.
|
|
157
|
+
}
|
|
158
|
+
if (allowlist)
|
|
159
|
+
return null; // Configured: an unbound variable is refused, not warned about.
|
|
160
|
+
const unbound = [...new Set(envs)].sort();
|
|
161
|
+
if (!unbound.length)
|
|
162
|
+
return null;
|
|
163
|
+
return `${unbound.join(', ')} ${unbound.length === 1 ? 'is' : 'are'} sent to whatever host the YAML names: no ${CREDENTIAL_HOSTS_ENV} binds ${unbound.length === 1 ? 'it' : 'them'} to ${unbound.length === 1 ? 'its' : 'their'} hosts`;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* What is wrong with the credential host allowlist for these uses, one line
|
|
167
|
+
* each, names and hosts only: a malformed allowlist, or each use it refuses
|
|
168
|
+
* (lib/tools/credentialUses.ts). Empty when none is configured.
|
|
169
|
+
*/
|
|
170
|
+
export function credentialHostEnvProblems(configs, env = process.env, load) {
|
|
171
|
+
let allowlist;
|
|
172
|
+
try {
|
|
173
|
+
allowlist = credentialHosts(env);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
return [err instanceof Error ? err.message : `${CREDENTIAL_HOSTS_ENV} is malformed`];
|
|
177
|
+
}
|
|
178
|
+
return syndicateCredentialHostProblems(configs, { allowlist: allowlist ?? null, ...(load ? { load } : {}) });
|
|
179
|
+
}
|
|
141
180
|
/**
|
|
142
181
|
* The credential store and consent step from the environment. Throws, naming
|
|
143
182
|
* variables only, when the configuration would be unsafe or cannot work: a
|
|
@@ -163,12 +202,26 @@ export function oauthServerSetup(options) {
|
|
|
163
202
|
const refused = syndicateOAuthHostProblems(options.configs, { ...(options.load ? { load: options.load } : {}), allowlist: allowlist ?? null });
|
|
164
203
|
if (refused.length)
|
|
165
204
|
throw new Error(`refusing an OAuth grant the operator's host allowlist does not permit:\n - ${refused.join('\n - ')}`);
|
|
205
|
+
// The credential host allowlist (ADR 0122): malformed throws here, at boot; a served file it refuses too.
|
|
206
|
+
const credentialList = credentialHosts(env);
|
|
207
|
+
const credentialRefused = syndicateCredentialHostProblems(options.configs, { ...(options.load ? { load: options.load } : {}), allowlist: credentialList ?? null });
|
|
208
|
+
if (credentialRefused.length)
|
|
209
|
+
throw new Error(`refusing a credential the operator's credential host allowlist does not permit:\n - ${credentialRefused.join('\n - ')}`);
|
|
210
|
+
const uses = syndicateCredentialUses(options.configs, options.load);
|
|
211
|
+
const unboundWarning = unboundCredentialWarning(uses.map((u) => u.env), env);
|
|
212
|
+
if (unboundWarning)
|
|
213
|
+
warnings.push(`${unboundWarning.charAt(0).toUpperCase()}${unboundWarning.slice(1)}.`);
|
|
214
|
+
const credentialSummary = credentialList
|
|
215
|
+
? `bound: ${Object.keys(credentialList).join(', ')} (${CREDENTIAL_HOSTS_ENV})`
|
|
216
|
+
: uses.length
|
|
217
|
+
? `no allowlist (${CREDENTIAL_HOSTS_ENV}): ${unboundCredentialEnvs(uses, undefined).join(', ')} unbound`
|
|
218
|
+
: `no allowlist (${CREDENTIAL_HOSTS_ENV}); no served file sends a static credential`;
|
|
166
219
|
if (!cipher) {
|
|
167
220
|
if (redirect)
|
|
168
221
|
throw new Error(`${OAUTH_REDIRECT_URI_ENV} is set but ${CREDENTIAL_KEY_ENV} is not: the consent step has nowhere to keep a grant. Set ${CREDENTIAL_KEY_ENV} (openssl rand -base64 32).`);
|
|
169
222
|
if (authCode.length)
|
|
170
223
|
warnings.push(`authorization_code grants (${authCode.join(', ')}) are declared but ${CREDENTIAL_KEY_ENV} is not set: their tools answer unavailable.`);
|
|
171
|
-
return { summary: `off (${CREDENTIAL_KEY_ENV} unset) · ${hostsLabel}`, warnings };
|
|
224
|
+
return { summary: `off (${CREDENTIAL_KEY_ENV} unset) · ${hostsLabel}`, credentialSummary, warnings };
|
|
172
225
|
}
|
|
173
226
|
const clients = oauthClientsFor(options.configs, { env, ...(options.load ? { load: options.load } : {}), allowlist: allowlist ?? null });
|
|
174
227
|
const providers = Object.keys(clients);
|
|
@@ -184,11 +237,11 @@ export function oauthServerSetup(options) {
|
|
|
184
237
|
if (!redirect) {
|
|
185
238
|
if (providers.length)
|
|
186
239
|
warnings.push(`${OAUTH_REDIRECT_URI_ENV} is not set: a user who has not connected ${providers.join(', ')} cannot be asked to.`);
|
|
187
|
-
return { toolCredentials: { store }, summary: `sealed (key ${cipher.keyId}) in ${where}; no consent step · ${hostsLabel}`, warnings };
|
|
240
|
+
return { toolCredentials: { store }, summary: `sealed (key ${cipher.keyId}) in ${where}; no consent step · ${hostsLabel}`, credentialSummary, warnings };
|
|
188
241
|
}
|
|
189
242
|
if (!providers.length) {
|
|
190
243
|
warnings.push(`${OAUTH_REDIRECT_URI_ENV} is set but no served syndicate declares an authorization_code grant: no consent callback is mounted.`);
|
|
191
|
-
return { toolCredentials: { store }, summary: `sealed (key ${cipher.keyId}) in ${where}; no consent step · ${hostsLabel}`, warnings };
|
|
244
|
+
return { toolCredentials: { store }, summary: `sealed (key ${cipher.keyId}) in ${where}; no consent step · ${hostsLabel}`, credentialSummary, warnings };
|
|
192
245
|
}
|
|
193
246
|
const consent = oauthConsent({
|
|
194
247
|
providers: clients,
|
|
@@ -200,6 +253,7 @@ export function oauthServerSetup(options) {
|
|
|
200
253
|
return {
|
|
201
254
|
toolCredentials: { store, consent },
|
|
202
255
|
summary: `sealed (key ${cipher.keyId}) in ${where}; consent at ${new URL(redirect).pathname} for ${providers.join(', ')} · ${hostsLabel}`,
|
|
256
|
+
credentialSummary,
|
|
203
257
|
warnings,
|
|
204
258
|
};
|
|
205
259
|
}
|
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
* Gemini's dialect (`generateContentConfig.temperature`, `outputSchema`),
|
|
8
8
|
* which is what the engine still reads (lib/runtime/native/request.ts
|
|
9
9
|
* buildModelRequest). YAML v2 spells them provider-neutrally (`sampling`,
|
|
10
|
-
* `output`) and adds per-provider
|
|
10
|
+
* `output`, and `tool_choice` from ADR 0117) and adds per-provider
|
|
11
|
+
* instruction overrides (`model_overrides`).
|
|
11
12
|
* This module is the one place the two spellings meet:
|
|
12
13
|
*
|
|
13
14
|
* - `V2_SPELLINGS`: each v2 key path and the v1 path it replaces. The
|
|
14
15
|
* loader (lib/syndicateSchema.ts crossFieldProblems) refuses a file that
|
|
15
16
|
* sets both; `toEngineAgent` refuses a config built in code that does.
|
|
16
|
-
* - `toEngineAgent`: folds `sampling` and `
|
|
17
|
+
* - `toEngineAgent`: folds `sampling`, `output` and `tool_choice` into
|
|
18
|
+
* the engine form.
|
|
17
19
|
* validateSyndicateConfig applies it to every agent it returns, so every
|
|
18
20
|
* loader hands downstream the engine form; lib/compile.ts applies it
|
|
19
21
|
* again (idempotent) for configs built in code.
|
|
@@ -27,13 +29,21 @@
|
|
|
27
29
|
import type { AgentYamlConfig } from './loadSyndicate.ts';
|
|
28
30
|
/** One v2 key and the v1 (engine) path it replaces. Both paths are relative to the agent. */
|
|
29
31
|
export interface V2Spelling {
|
|
30
|
-
readonly v2: readonly [
|
|
32
|
+
readonly v2: readonly string[];
|
|
31
33
|
readonly v1: readonly string[];
|
|
34
|
+
/** The engine value for the v2 value, when the two are spelled differently. */
|
|
35
|
+
readonly toV1?: (value: unknown) => unknown;
|
|
32
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* `tool_choice` as Gemini's function-calling config, which the engine reads
|
|
39
|
+
* (lib/models/genaiMapping.ts toolChoiceOf): `auto` is AUTO, `none` NONE,
|
|
40
|
+
* `required` ANY, and `{ name }` ANY with that one name allowed (ADR 0117).
|
|
41
|
+
*/
|
|
42
|
+
export declare function functionCallingConfigOf(choice: unknown): Record<string, unknown>;
|
|
33
43
|
/** Every v2 key with a v1 equivalent; the mapper writes the v1 path. */
|
|
34
44
|
export declare const V2_SPELLINGS: readonly V2Spelling[];
|
|
35
45
|
/** The v2 agent keys, which an inline agent alone may carry (not a yaml_reference or a2a_agent_url subagent). */
|
|
36
|
-
export declare const V2_AGENT_KEYS: readonly ['sampling', 'output', 'model_overrides'];
|
|
46
|
+
export declare const V2_AGENT_KEYS: readonly ['sampling', 'output', 'tool_choice', 'model_overrides'];
|
|
37
47
|
/** The v1 spellings ADR 0115 deprecates, as agent keys. */
|
|
38
48
|
export declare const V1_AGENT_KEYS: readonly ['generateContentConfig', 'outputSchema'];
|
|
39
49
|
/** The v2/v1 pairs an agent sets both of: each is a conflict. */
|
|
@@ -41,10 +51,10 @@ export declare function conflictsOf(agent: unknown): V2Spelling[];
|
|
|
41
51
|
/** The loader's message for one conflict, reported against the v2 key path. */
|
|
42
52
|
export declare function conflictMessage(s: V2Spelling): string;
|
|
43
53
|
/**
|
|
44
|
-
* An agent in the engine form: `sampling` and `
|
|
45
|
-
* `generateContentConfig` and `outputSchema` (the table above) and
|
|
46
|
-
* `model_overrides` kept (lib/compile.ts applies it). The same
|
|
47
|
-
* the agent has
|
|
54
|
+
* An agent in the engine form: `sampling`, `output` and `tool_choice` folded
|
|
55
|
+
* into `generateContentConfig` and `outputSchema` (the table above) and
|
|
56
|
+
* removed; `model_overrides` kept (lib/compile.ts applies it). The same
|
|
57
|
+
* object when the agent has none of the three, so it is idempotent. Throws
|
|
48
58
|
* when a v2 key and the v1 key it replaces are both set.
|
|
49
59
|
*/
|
|
50
60
|
export declare function toEngineAgent<T extends object>(agent: T): T;
|
package/dist/lib/agentDialect.js
CHANGED
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
* Gemini's dialect (`generateContentConfig.temperature`, `outputSchema`),
|
|
8
8
|
* which is what the engine still reads (lib/runtime/native/request.ts
|
|
9
9
|
* buildModelRequest). YAML v2 spells them provider-neutrally (`sampling`,
|
|
10
|
-
* `output`) and adds per-provider
|
|
10
|
+
* `output`, and `tool_choice` from ADR 0117) and adds per-provider
|
|
11
|
+
* instruction overrides (`model_overrides`).
|
|
11
12
|
* This module is the one place the two spellings meet:
|
|
12
13
|
*
|
|
13
14
|
* - `V2_SPELLINGS`: each v2 key path and the v1 path it replaces. The
|
|
14
15
|
* loader (lib/syndicateSchema.ts crossFieldProblems) refuses a file that
|
|
15
16
|
* sets both; `toEngineAgent` refuses a config built in code that does.
|
|
16
|
-
* - `toEngineAgent`: folds `sampling` and `
|
|
17
|
+
* - `toEngineAgent`: folds `sampling`, `output` and `tool_choice` into
|
|
18
|
+
* the engine form.
|
|
17
19
|
* validateSyndicateConfig applies it to every agent it returns, so every
|
|
18
20
|
* loader hands downstream the engine form; lib/compile.ts applies it
|
|
19
21
|
* again (idempotent) for configs built in code.
|
|
@@ -26,6 +28,20 @@
|
|
|
26
28
|
*/
|
|
27
29
|
import { providerForModel } from './models/providerMap.js';
|
|
28
30
|
const isObj = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
31
|
+
/**
|
|
32
|
+
* `tool_choice` as Gemini's function-calling config, which the engine reads
|
|
33
|
+
* (lib/models/genaiMapping.ts toolChoiceOf): `auto` is AUTO, `none` NONE,
|
|
34
|
+
* `required` ANY, and `{ name }` ANY with that one name allowed (ADR 0117).
|
|
35
|
+
*/
|
|
36
|
+
export function functionCallingConfigOf(choice) {
|
|
37
|
+
if (choice === 'none')
|
|
38
|
+
return { mode: 'NONE' };
|
|
39
|
+
if (choice === 'required')
|
|
40
|
+
return { mode: 'ANY' };
|
|
41
|
+
if (isObj(choice) && typeof choice.name === 'string')
|
|
42
|
+
return { mode: 'ANY', allowedFunctionNames: [choice.name] };
|
|
43
|
+
return { mode: 'AUTO' };
|
|
44
|
+
}
|
|
29
45
|
/** Every v2 key with a v1 equivalent; the mapper writes the v1 path. */
|
|
30
46
|
export const V2_SPELLINGS = [
|
|
31
47
|
{ v2: ['sampling', 'temperature'], v1: ['generateContentConfig', 'temperature'] },
|
|
@@ -34,9 +50,10 @@ export const V2_SPELLINGS = [
|
|
|
34
50
|
{ v2: ['sampling', 'stop'], v1: ['generateContentConfig', 'stopSequences'] },
|
|
35
51
|
{ v2: ['output', 'schema'], v1: ['outputSchema'] },
|
|
36
52
|
{ v2: ['output', 'mime'], v1: ['generateContentConfig', 'responseMimeType'] },
|
|
53
|
+
{ v2: ['tool_choice'], v1: ['generateContentConfig', 'toolConfig', 'functionCallingConfig'], toV1: functionCallingConfigOf },
|
|
37
54
|
];
|
|
38
55
|
/** The v2 agent keys, which an inline agent alone may carry (not a yaml_reference or a2a_agent_url subagent). */
|
|
39
|
-
export const V2_AGENT_KEYS = ['sampling', 'output', 'model_overrides'];
|
|
56
|
+
export const V2_AGENT_KEYS = ['sampling', 'output', 'tool_choice', 'model_overrides'];
|
|
40
57
|
/** The v1 spellings ADR 0115 deprecates, as agent keys. */
|
|
41
58
|
export const V1_AGENT_KEYS = ['generateContentConfig', 'outputSchema'];
|
|
42
59
|
/** The value at `path` under `root`, or undefined. */
|
|
@@ -58,37 +75,37 @@ export function conflictMessage(s) {
|
|
|
58
75
|
return `cannot be combined with ${s.v1.join('.')}; ${s.v2.join('.')} replaces it, so keep one (ADR 0115)`;
|
|
59
76
|
}
|
|
60
77
|
/**
|
|
61
|
-
* An agent in the engine form: `sampling` and `
|
|
62
|
-
* `generateContentConfig` and `outputSchema` (the table above) and
|
|
63
|
-
* `model_overrides` kept (lib/compile.ts applies it). The same
|
|
64
|
-
* the agent has
|
|
78
|
+
* An agent in the engine form: `sampling`, `output` and `tool_choice` folded
|
|
79
|
+
* into `generateContentConfig` and `outputSchema` (the table above) and
|
|
80
|
+
* removed; `model_overrides` kept (lib/compile.ts applies it). The same
|
|
81
|
+
* object when the agent has none of the three, so it is idempotent. Throws
|
|
65
82
|
* when a v2 key and the v1 key it replaces are both set.
|
|
66
83
|
*/
|
|
67
84
|
export function toEngineAgent(agent) {
|
|
68
85
|
const a = agent;
|
|
69
|
-
if (a.sampling === undefined && a.output === undefined)
|
|
86
|
+
if (a.sampling === undefined && a.output === undefined && a.tool_choice === undefined)
|
|
70
87
|
return agent;
|
|
71
88
|
const clash = conflictsOf(a);
|
|
72
89
|
if (clash.length) {
|
|
73
90
|
const name = typeof a.name === 'string' ? a.name : 'agent';
|
|
74
91
|
throw new Error(`${name}: ${clash.map((s) => `${s.v2.join('.')} cannot be combined with ${s.v1.join('.')}`).join('; ')}; the v2 key replaces it, so keep one (ADR 0115)`);
|
|
75
92
|
}
|
|
76
|
-
const { sampling: _sampling, output: _output, ...rest } = a;
|
|
93
|
+
const { sampling: _sampling, output: _output, tool_choice: _toolChoice, ...rest } = a;
|
|
77
94
|
const out = { ...rest };
|
|
78
|
-
let gcc;
|
|
79
95
|
for (const s of V2_SPELLINGS) {
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
continue;
|
|
83
|
-
if (s.v1.length === 1) {
|
|
84
|
-
out[s.v1[0]] = value;
|
|
96
|
+
const raw = at(a, s.v2);
|
|
97
|
+
if (raw === undefined)
|
|
85
98
|
continue;
|
|
99
|
+
const value = s.toV1 ? s.toV1(raw) : raw;
|
|
100
|
+
// Copy each object on the v1 path, so the caller's config is never written to.
|
|
101
|
+
let parent = out;
|
|
102
|
+
for (const seg of s.v1.slice(0, -1)) {
|
|
103
|
+
const next = { ...(isObj(parent[seg]) ? parent[seg] : {}) };
|
|
104
|
+
parent[seg] = next;
|
|
105
|
+
parent = next;
|
|
86
106
|
}
|
|
87
|
-
|
|
88
|
-
gcc[s.v1[1]] = value;
|
|
107
|
+
parent[s.v1[s.v1.length - 1]] = value;
|
|
89
108
|
}
|
|
90
|
-
if (gcc)
|
|
91
|
-
out.generateContentConfig = gcc;
|
|
92
109
|
return out;
|
|
93
110
|
}
|
|
94
111
|
/**
|
package/dist/lib/compile.d.ts
CHANGED
|
@@ -110,7 +110,30 @@ export type SpecTool = {
|
|
|
110
110
|
} | {
|
|
111
111
|
kind: 'workflow';
|
|
112
112
|
workflow: WorkflowSpec;
|
|
113
|
+
} | {
|
|
114
|
+
kind: 'dispatch';
|
|
115
|
+
dispatch: DispatchSpec;
|
|
113
116
|
};
|
|
117
|
+
/**
|
|
118
|
+
* A nested dispatch (plan-dispatch) syndicate (ADR 0120): it runs as it
|
|
119
|
+
* runs at the top, as a turn of its own on its own conversation (its
|
|
120
|
+
* classifier picks a route, the route answers), so what it compiles to is
|
|
121
|
+
* the file and the options its turn loads its routes with. The turn runner
|
|
122
|
+
* runs it (lib/runtime/syndicateTurn.ts, TurnControl.nestedDispatch), as a
|
|
123
|
+
* delegated call, a dispatch route or a workflow node.
|
|
124
|
+
*/
|
|
125
|
+
export interface DispatchSpec {
|
|
126
|
+
/** The entry's name, under which its caller lists it. */
|
|
127
|
+
name: string;
|
|
128
|
+
/** The entry's description: the tool's, when delegated to. */
|
|
129
|
+
description: string;
|
|
130
|
+
/** The nested syndicate, as loaded. */
|
|
131
|
+
config: SyndicateYamlConfig;
|
|
132
|
+
/** The file it came from. */
|
|
133
|
+
ref: string;
|
|
134
|
+
/** The options its routes compile with: the caller's, its nesting chain extended by `ref`. */
|
|
135
|
+
compile: CompileOptions;
|
|
136
|
+
}
|
|
114
137
|
/**
|
|
115
138
|
* A workflow syndicate, compiled: lib/compileNative.ts builds the walk's
|
|
116
139
|
* graph and agents from it. Nested as a subagent (a `yaml_reference` in
|
|
@@ -138,6 +161,11 @@ export interface WorkflowSpec {
|
|
|
138
161
|
yaml: SubagentYamlConfig;
|
|
139
162
|
workflow: WorkflowSpec;
|
|
140
163
|
}>;
|
|
164
|
+
/** Every node that is a `yaml_reference` to a dispatch syndicate, with its YAML entry: the walk runs it as the node, as its own turn (ADR 0120). */
|
|
165
|
+
dispatches?: Array<{
|
|
166
|
+
yaml: SubagentYamlConfig;
|
|
167
|
+
dispatch: DispatchSpec;
|
|
168
|
+
}>;
|
|
141
169
|
/** The registry entry for a tool node's tool name, or undefined (CompileOptions.onUnknownTool applies). */
|
|
142
170
|
resolveTool: (name: string) => unknown;
|
|
143
171
|
}
|
|
@@ -186,21 +214,23 @@ export interface AgentSpec {
|
|
|
186
214
|
* lookup for its tool nodes. `name` and `description` name a nested one
|
|
187
215
|
* after its subagent entry (ADR 0098); `ref` is the file it came from.
|
|
188
216
|
*
|
|
189
|
-
* A nested workflow
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* by name there.
|
|
217
|
+
* A nested workflow's pauses (an `ask_user` node, a gate) reach the turn
|
|
218
|
+
* wherever it runs (ADR 0111, ADR 0119). `delegated` is accepted for the
|
|
219
|
+
* callers that pass it and no longer changes what compiles.
|
|
193
220
|
*/
|
|
194
221
|
export declare function compileWorkflowSpec(config: SyndicateYamlConfig, opts?: CompileOptions, name?: string, description?: string, ref?: string, delegated?: boolean): Promise<WorkflowSpec>;
|
|
195
222
|
/** Every agent spec a workflow runs, its nested workflow nodes' agents included, for one adapter lookup (nativeAdapterFor). */
|
|
196
223
|
export declare function workflowAgentSpecs(spec: WorkflowSpec): AgentSpec[];
|
|
197
|
-
/** A subagent entry, compiled: one agent,
|
|
224
|
+
/** A subagent entry, compiled: one agent, a nested workflow syndicate's whole graph (ADR 0098, ADR 0106), or a nested dispatch syndicate's own turn (ADR 0120). */
|
|
198
225
|
export type EntrySpec = {
|
|
199
226
|
kind: 'agent';
|
|
200
227
|
spec: AgentSpec;
|
|
201
228
|
} | {
|
|
202
229
|
kind: 'workflow';
|
|
203
230
|
workflow: WorkflowSpec;
|
|
231
|
+
} | {
|
|
232
|
+
kind: 'dispatch';
|
|
233
|
+
dispatch: DispatchSpec;
|
|
204
234
|
};
|
|
205
235
|
/**
|
|
206
236
|
* A subagent entry as what it runs: an inline agent or a nested syndicate's
|
|
@@ -208,8 +238,9 @@ export type EntrySpec = {
|
|
|
208
238
|
* as its whole graph under the entry's name and description. A delegated
|
|
209
239
|
* subagent, a dispatch route and a workflow node all compile through here,
|
|
210
240
|
* so the graph a file describes is the graph that runs (ADR 0106).
|
|
211
|
-
*
|
|
212
|
-
*
|
|
241
|
+
* A nested workflow pauses wherever it runs (ADR 0111, ADR 0119);
|
|
242
|
+
* `delegated` is accepted for the callers that pass it and no longer
|
|
243
|
+
* changes what compiles.
|
|
213
244
|
*/
|
|
214
245
|
export declare function compileEntrySpec(subCfg: SubagentYamlConfig, opts?: CompileOptions, delegated?: boolean): Promise<EntrySpec>;
|
|
215
246
|
/**
|