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
|
@@ -340,6 +340,15 @@ export class ProjectedSessionService {
|
|
|
340
340
|
* The event lands in the projected session the runtime holds and, through
|
|
341
341
|
* the store, in the real one `get` read. A session `get` did not hand out
|
|
342
342
|
* is the real one, and the store alone applies the event to it.
|
|
343
|
+
*
|
|
344
|
+
* A store may answer an append with events of its own: a durable run's
|
|
345
|
+
* store restoring a checkpoint (lib/runtime/native/checkpoint.ts, ADR 0113)
|
|
346
|
+
* answers the opening message with the run's stored events, the stored
|
|
347
|
+
* opening returned in place of the one given. The projected session then
|
|
348
|
+
* takes, in place of the event given, every event the real session gained,
|
|
349
|
+
* unprojected: they are the current turn, which is never projected. The
|
|
350
|
+
* agent loop thereby reads the restored steps, as it would on the store's
|
|
351
|
+
* own session.
|
|
343
352
|
*/
|
|
344
353
|
async append(session, event) {
|
|
345
354
|
if (event.partial)
|
|
@@ -347,7 +356,17 @@ export class ProjectedSessionService {
|
|
|
347
356
|
const real = this.stored.get(this.key(session.appName, session.userId, session.id));
|
|
348
357
|
if (!real || real === session)
|
|
349
358
|
return this.own.append(session, event);
|
|
359
|
+
const before = real.events.length;
|
|
360
|
+
const at = session.events.length;
|
|
350
361
|
applyEvent(session, event);
|
|
351
|
-
|
|
362
|
+
const stored = await this.own.append(real, event);
|
|
363
|
+
if (stored.id !== event.id) {
|
|
364
|
+
// The store answered with its own events: they replace the one applied above.
|
|
365
|
+
if (session.events[at]?.id === event.id)
|
|
366
|
+
session.events.splice(at, 1);
|
|
367
|
+
for (const gained of real.events.slice(before))
|
|
368
|
+
applyEvent(session, gained);
|
|
369
|
+
}
|
|
370
|
+
return stored;
|
|
352
371
|
}
|
|
353
372
|
}
|
package/dist/lib/skills.d.ts
CHANGED
|
@@ -48,3 +48,21 @@ export interface InstallResult {
|
|
|
48
48
|
export declare function destinationsFor(opts: InstallOptions): string[];
|
|
49
49
|
/** Copy the suite into every destination. Returns one result per destination. */
|
|
50
50
|
export declare function installSkills(opts?: InstallOptions): InstallResult[];
|
|
51
|
+
/** The markers that delimit the block this installer owns inside AGENTS.md. */
|
|
52
|
+
export declare const AGENTS_MD_BEGIN = "<!-- melchizedek-skills:begin -->";
|
|
53
|
+
export declare const AGENTS_MD_END = "<!-- melchizedek-skills:end -->";
|
|
54
|
+
/** The pointer: where the skills are, and the onboarding entry point. */
|
|
55
|
+
export declare function agentsMdBlock(destinations: string[], projectRoot: string): string;
|
|
56
|
+
export interface AgentsMdResult {
|
|
57
|
+
path: string;
|
|
58
|
+
status: 'created' | 'appended' | 'updated' | 'unchanged';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Write the pointer into `<projectRoot>/AGENTS.md`, the instructions file
|
|
62
|
+
* Codex and other agents read: create the file when absent, append the block
|
|
63
|
+
* when the file has none, or replace only the block between the markers.
|
|
64
|
+
* Nothing outside the markers is ever changed.
|
|
65
|
+
*/
|
|
66
|
+
export declare function writeAgentsMdPointer(projectRoot: string, destinations: string[], opts?: {
|
|
67
|
+
dryRun?: boolean;
|
|
68
|
+
}): AgentsMdResult;
|
package/dist/lib/skills.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* A SKILL.md's frontmatter is read by the skills harness's own parser
|
|
16
16
|
* (lib/tools/skills/frontmatter.ts), the one an agent's `skills:` uses.
|
|
17
17
|
*/
|
|
18
|
-
import { closeSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
18
|
+
import { closeSync, constants as fsConstants, existsSync, fstatSync, ftruncateSync, lstatSync, mkdirSync, openSync, readSync, readdirSync, readFileSync, statSync, writeFileSync, writeSync } from 'node:fs';
|
|
19
19
|
import { homedir } from 'node:os';
|
|
20
20
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
21
21
|
import { fileURLToPath } from 'node:url';
|
|
@@ -162,3 +162,75 @@ export function installSkills(opts = {}) {
|
|
|
162
162
|
}
|
|
163
163
|
return results;
|
|
164
164
|
}
|
|
165
|
+
// ── The AGENTS.md pointer ────────────────────────────────────────────────────
|
|
166
|
+
/** The markers that delimit the block this installer owns inside AGENTS.md. */
|
|
167
|
+
export const AGENTS_MD_BEGIN = '<!-- melchizedek-skills:begin -->';
|
|
168
|
+
export const AGENTS_MD_END = '<!-- melchizedek-skills:end -->';
|
|
169
|
+
/** The pointer: where the skills are, and the onboarding entry point. */
|
|
170
|
+
export function agentsMdBlock(destinations, projectRoot) {
|
|
171
|
+
const where = destinations.map((d) => `\`${relative(projectRoot, d) || '.'}/\``).join(' and ');
|
|
172
|
+
return [
|
|
173
|
+
AGENTS_MD_BEGIN,
|
|
174
|
+
'## Melchizedek agent skills',
|
|
175
|
+
'',
|
|
176
|
+
`The melchizedek-agents skills are installed in ${where}, one directory per skill with a SKILL.md.`,
|
|
177
|
+
'To onboard someone, start with `melchizedek-onboard/SKILL.md`, or run `npx melchizedek-setup --auto`.',
|
|
178
|
+
'Never ask for an API key in chat and never print a value from `.env`: the person types keys into `.env` themselves.',
|
|
179
|
+
AGENTS_MD_END,
|
|
180
|
+
].join('\n');
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Write the pointer into `<projectRoot>/AGENTS.md`, the instructions file
|
|
184
|
+
* Codex and other agents read: create the file when absent, append the block
|
|
185
|
+
* when the file has none, or replace only the block between the markers.
|
|
186
|
+
* Nothing outside the markers is ever changed.
|
|
187
|
+
*/
|
|
188
|
+
export function writeAgentsMdPointer(projectRoot, destinations, opts = {}) {
|
|
189
|
+
const path = join(resolve(projectRoot), 'AGENTS.md');
|
|
190
|
+
const block = agentsMdBlock(destinations, resolve(projectRoot));
|
|
191
|
+
const plan = (text) => {
|
|
192
|
+
if (text === undefined)
|
|
193
|
+
return { status: 'created', next: `# AGENTS.md\n\n${block}\n` };
|
|
194
|
+
const start = text.indexOf(AGENTS_MD_BEGIN);
|
|
195
|
+
const end = text.indexOf(AGENTS_MD_END);
|
|
196
|
+
if (start !== -1 && end > start) {
|
|
197
|
+
const next = text.slice(0, start) + block + text.slice(end + AGENTS_MD_END.length);
|
|
198
|
+
return { status: next === text ? 'unchanged' : 'updated', next };
|
|
199
|
+
}
|
|
200
|
+
return { status: 'appended', next: `${text}${text.endsWith('\n') ? '' : '\n'}\n${block}\n` };
|
|
201
|
+
};
|
|
202
|
+
if (opts.dryRun) {
|
|
203
|
+
// Nothing is written, so a path check is enough to report what would happen.
|
|
204
|
+
if (existsSync(path) && lstatSync(path).isSymbolicLink())
|
|
205
|
+
throw new Error(`refusing to write through a symlink: ${path}`);
|
|
206
|
+
return { path, status: plan(existsSync(path) ? readFileSync(path, 'utf-8') : undefined).status };
|
|
207
|
+
}
|
|
208
|
+
// One handle for the read and the write, so the file read is the file written:
|
|
209
|
+
// created if absent, never followed through a symlink (O_NOFOLLOW).
|
|
210
|
+
let fd;
|
|
211
|
+
try {
|
|
212
|
+
fd = openSync(path, fsConstants.O_RDWR | fsConstants.O_CREAT | (fsConstants.O_NOFOLLOW ?? 0), 0o644);
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
if (err.code === 'ELOOP')
|
|
216
|
+
throw new Error(`refusing to write through a symlink: ${path}`);
|
|
217
|
+
throw err;
|
|
218
|
+
}
|
|
219
|
+
let status;
|
|
220
|
+
try {
|
|
221
|
+
const stat = fstatSync(fd);
|
|
222
|
+
if (!stat.isFile())
|
|
223
|
+
throw new Error(`not a regular file: ${path}`);
|
|
224
|
+
const existing = stat.size > 0 ? readFileSync(fd, 'utf-8') : undefined;
|
|
225
|
+
const result = plan(existing);
|
|
226
|
+
status = result.status;
|
|
227
|
+
if (status !== 'unchanged') {
|
|
228
|
+
ftruncateSync(fd, 0);
|
|
229
|
+
writeSync(fd, result.next, 0);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
closeSync(fd);
|
|
234
|
+
}
|
|
235
|
+
return { path, status };
|
|
236
|
+
}
|
|
@@ -21,7 +21,7 @@ import type { CredentialStoreOptions } from '../../tools/credentialStore.ts';
|
|
|
21
21
|
import type { CredentialStore } from '../../tools/auth.ts';
|
|
22
22
|
import type { AuditSink } from '../../observability/audit.ts';
|
|
23
23
|
import type { RlsHardeningStatus } from '../rlsStatus.ts';
|
|
24
|
-
import type { TaskBackend } from '../../tools/taskTools.ts';
|
|
24
|
+
import type { TaskBackend, TaskBackendOptions } from '../../tools/taskTools.ts';
|
|
25
25
|
import type { TurnLock } from '../../a2a/turnLock.ts';
|
|
26
26
|
import type { PostgresTaskStoreOptions } from './taskStore.ts';
|
|
27
27
|
export { PostgresSessionService } from './sessionService.ts';
|
|
@@ -73,6 +73,11 @@ export interface PostgresStorageOptions {
|
|
|
73
73
|
* go to this storage's audit trail.
|
|
74
74
|
*/
|
|
75
75
|
credentials?: Omit<CredentialStoreOptions, 'rows' | 'audit'>;
|
|
76
|
+
/**
|
|
77
|
+
* The job queue's checkpoints (ADR 0113): the largest one stored, in bytes
|
|
78
|
+
* of JSON (default 5 MiB), and where a skipped save is logged.
|
|
79
|
+
*/
|
|
80
|
+
taskQueue?: TaskBackendOptions;
|
|
76
81
|
}
|
|
77
82
|
export interface PostgresStorage {
|
|
78
83
|
pool: Pool;
|
|
@@ -120,7 +120,7 @@ export function postgresStorage(options) {
|
|
|
120
120
|
reap: () => reapExpiredTasks(pool),
|
|
121
121
|
cancelRequested: () => cancelRequestedTasks(pool, lease),
|
|
122
122
|
},
|
|
123
|
-
taskQueue: postgresTaskBackend(pool),
|
|
123
|
+
taskQueue: postgresTaskBackend(pool, options.taskQueue),
|
|
124
124
|
async schemaVersion() {
|
|
125
125
|
try {
|
|
126
126
|
const r = await pool.query('SELECT max(version) AS v FROM melchizedek_schema_version');
|
|
@@ -27,8 +27,12 @@
|
|
|
27
27
|
* survives while the job is running or queued: recover's requeue keeps it,
|
|
28
28
|
* so the next claim resumes from it, and claimNext leaves it; a mutate that
|
|
29
29
|
* moves the job to any other status, or recover failing it, clears it; a
|
|
30
|
-
* deleted row takes it along.
|
|
30
|
+
* deleted row takes it along. A checkpoint whose JSON is above the cap
|
|
31
|
+
* (TaskBackendOptions.checkpointMaxBytes, default 5 MiB) is not written:
|
|
32
|
+
* the column keeps the previous one, the save still reports the claim, and
|
|
33
|
+
* one line names the job id and the sizes.
|
|
31
34
|
*/
|
|
32
35
|
import type { Pool } from 'pg';
|
|
33
|
-
import type { TaskBackend } from '../../tools/taskTools.ts';
|
|
34
|
-
|
|
36
|
+
import type { TaskBackend, TaskBackendOptions } from '../../tools/taskTools.ts';
|
|
37
|
+
/** The task backend on `pool`; `options` caps the checkpoint a save stores (TaskBackendOptions). */
|
|
38
|
+
export declare function postgresTaskBackend(pool: Pool, options?: TaskBackendOptions): TaskBackend;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyFinish, applyInterrupted } from '../../tools/taskTools.js';
|
|
1
|
+
import { applyFinish, applyInterrupted, checkpointJson } from '../../tools/taskTools.js';
|
|
2
2
|
const seqOf = (id) => Number(id.slice(1)) || 0;
|
|
3
3
|
async function loadOwner(db, owner, lock) {
|
|
4
4
|
const head = await db.query(`SELECT next_id FROM melchizedek_task_owners WHERE owner = $1${lock ? ' FOR UPDATE' : ''}`, [owner]);
|
|
@@ -21,7 +21,8 @@ async function inTransaction(pool, run) {
|
|
|
21
21
|
client.release();
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
/** The task backend on `pool`; `options` caps the checkpoint a save stores (TaskBackendOptions). */
|
|
25
|
+
export function postgresTaskBackend(pool, options = {}) {
|
|
25
26
|
return {
|
|
26
27
|
read: (owner) => loadOwner(pool, owner, false),
|
|
27
28
|
async mutate(owner, change) {
|
|
@@ -82,8 +83,14 @@ export function postgresTaskBackend(pool) {
|
|
|
82
83
|
return (r.rowCount ?? 0) > 0;
|
|
83
84
|
},
|
|
84
85
|
async saveCheckpoint(worker, job, checkpoint) {
|
|
86
|
+
const json = checkpointJson(job, checkpoint, options);
|
|
87
|
+
if (json === null) {
|
|
88
|
+
// Over the cap: the previous checkpoint is kept; the answer is still whether the claim holds.
|
|
89
|
+
const held = await pool.query(`SELECT 1 FROM melchizedek_tasks WHERE owner = $1 AND id = $2 AND lease_owner = $3 AND status = 'running'`, [job.owner, job.id, worker.workerId]);
|
|
90
|
+
return (held.rowCount ?? 0) > 0;
|
|
91
|
+
}
|
|
85
92
|
const r = await pool.query(`UPDATE melchizedek_tasks SET checkpoint = $4::jsonb, checkpoint_at = NOW()
|
|
86
|
-
WHERE owner = $1 AND id = $2 AND lease_owner = $3 AND status = 'running'`, [job.owner, job.id, worker.workerId,
|
|
93
|
+
WHERE owner = $1 AND id = $2 AND lease_owner = $3 AND status = 'running'`, [job.owner, job.id, worker.workerId, json]);
|
|
87
94
|
return (r.rowCount ?? 0) > 0;
|
|
88
95
|
},
|
|
89
96
|
async loadCheckpoint(job) {
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
import { z } from 'zod';
|
|
25
25
|
import type { SyndicateYamlConfig } from './loadSyndicate.ts';
|
|
26
26
|
export declare const MEMORY_SYSTEMS: readonly ['internal-only', 'session-only', 'long-term'];
|
|
27
|
-
export declare const REASONING_LEVELS: readonly ['none', 'low', 'medium', 'high'];
|
|
27
|
+
export declare const REASONING_LEVELS: readonly ['none', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
28
28
|
export declare const OUTPUT_MIMES: readonly ['application/json', 'text/plain'];
|
|
29
|
+
export declare const TOOL_CHOICE_MODES: readonly ['auto', 'none', 'required'];
|
|
29
30
|
export declare const SKILL_SCRIPT_MODES: readonly ['none', 'local'];
|
|
30
31
|
export declare const agentSchema: z.ZodObject<{
|
|
31
32
|
name: z.ZodString;
|
|
@@ -67,8 +68,10 @@ export declare const agentSchema: z.ZodObject<{
|
|
|
67
68
|
reasoning: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
68
69
|
high: "high";
|
|
69
70
|
low: "low";
|
|
71
|
+
max: "max";
|
|
70
72
|
medium: "medium";
|
|
71
73
|
none: "none";
|
|
74
|
+
xhigh: "xhigh";
|
|
72
75
|
}>, z.ZodObject<{
|
|
73
76
|
budget_tokens: z.ZodNumber;
|
|
74
77
|
}, z.core.$strict>]>>;
|
|
@@ -85,6 +88,13 @@ export declare const agentSchema: z.ZodObject<{
|
|
|
85
88
|
"text/plain": "text/plain";
|
|
86
89
|
}>>;
|
|
87
90
|
}, z.core.$strict>>;
|
|
91
|
+
tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
92
|
+
auto: "auto";
|
|
93
|
+
none: "none";
|
|
94
|
+
required: "required";
|
|
95
|
+
}>, z.ZodObject<{
|
|
96
|
+
name: z.ZodString;
|
|
97
|
+
}, z.core.$strict>]>>;
|
|
88
98
|
model_overrides: z.ZodOptional<z.ZodObject<{
|
|
89
99
|
gemini: z.ZodOptional<z.ZodObject<{
|
|
90
100
|
instruction: z.ZodOptional<z.ZodString>;
|
|
@@ -233,8 +243,10 @@ export declare const subagentSchema: z.ZodObject<{
|
|
|
233
243
|
reasoning: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
234
244
|
high: "high";
|
|
235
245
|
low: "low";
|
|
246
|
+
max: "max";
|
|
236
247
|
medium: "medium";
|
|
237
248
|
none: "none";
|
|
249
|
+
xhigh: "xhigh";
|
|
238
250
|
}>, z.ZodObject<{
|
|
239
251
|
budget_tokens: z.ZodNumber;
|
|
240
252
|
}, z.core.$strict>]>>;
|
|
@@ -251,6 +263,13 @@ export declare const subagentSchema: z.ZodObject<{
|
|
|
251
263
|
"text/plain": "text/plain";
|
|
252
264
|
}>>;
|
|
253
265
|
}, z.core.$strict>>;
|
|
266
|
+
tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
267
|
+
auto: "auto";
|
|
268
|
+
none: "none";
|
|
269
|
+
required: "required";
|
|
270
|
+
}>, z.ZodObject<{
|
|
271
|
+
name: z.ZodString;
|
|
272
|
+
}, z.core.$strict>]>>;
|
|
254
273
|
model_overrides: z.ZodOptional<z.ZodObject<{
|
|
255
274
|
gemini: z.ZodOptional<z.ZodObject<{
|
|
256
275
|
instruction: z.ZodOptional<z.ZodString>;
|
|
@@ -403,8 +422,10 @@ export declare const syndicateSchema: z.ZodObject<{
|
|
|
403
422
|
reasoning: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
404
423
|
high: "high";
|
|
405
424
|
low: "low";
|
|
425
|
+
max: "max";
|
|
406
426
|
medium: "medium";
|
|
407
427
|
none: "none";
|
|
428
|
+
xhigh: "xhigh";
|
|
408
429
|
}>, z.ZodObject<{
|
|
409
430
|
budget_tokens: z.ZodNumber;
|
|
410
431
|
}, z.core.$strict>]>>;
|
|
@@ -421,6 +442,13 @@ export declare const syndicateSchema: z.ZodObject<{
|
|
|
421
442
|
"text/plain": "text/plain";
|
|
422
443
|
}>>;
|
|
423
444
|
}, z.core.$strict>>;
|
|
445
|
+
tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
446
|
+
auto: "auto";
|
|
447
|
+
none: "none";
|
|
448
|
+
required: "required";
|
|
449
|
+
}>, z.ZodObject<{
|
|
450
|
+
name: z.ZodString;
|
|
451
|
+
}, z.core.$strict>]>>;
|
|
424
452
|
model_overrides: z.ZodOptional<z.ZodObject<{
|
|
425
453
|
gemini: z.ZodOptional<z.ZodObject<{
|
|
426
454
|
instruction: z.ZodOptional<z.ZodString>;
|
|
@@ -563,8 +591,10 @@ export declare const syndicateSchema: z.ZodObject<{
|
|
|
563
591
|
reasoning: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
564
592
|
high: "high";
|
|
565
593
|
low: "low";
|
|
594
|
+
max: "max";
|
|
566
595
|
medium: "medium";
|
|
567
596
|
none: "none";
|
|
597
|
+
xhigh: "xhigh";
|
|
568
598
|
}>, z.ZodObject<{
|
|
569
599
|
budget_tokens: z.ZodNumber;
|
|
570
600
|
}, z.core.$strict>]>>;
|
|
@@ -581,6 +611,13 @@ export declare const syndicateSchema: z.ZodObject<{
|
|
|
581
611
|
"text/plain": "text/plain";
|
|
582
612
|
}>>;
|
|
583
613
|
}, z.core.$strict>>;
|
|
614
|
+
tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
615
|
+
auto: "auto";
|
|
616
|
+
none: "none";
|
|
617
|
+
required: "required";
|
|
618
|
+
}>, z.ZodObject<{
|
|
619
|
+
name: z.ZodString;
|
|
620
|
+
}, z.core.$strict>]>>;
|
|
584
621
|
model_overrides: z.ZodOptional<z.ZodObject<{
|
|
585
622
|
gemini: z.ZodOptional<z.ZodObject<{
|
|
586
623
|
instruction: z.ZodOptional<z.ZodString>;
|
|
@@ -45,7 +45,7 @@ const thinkingConfig = z
|
|
|
45
45
|
includeThoughts: z.boolean().optional().describe('Stream the thinking trace in the response.'),
|
|
46
46
|
})
|
|
47
47
|
.describe('Older spelling of `reasoning` for Gemini and Claude (thinkingLevel or thinkingBudget). Cannot be combined with `reasoning`.');
|
|
48
|
-
export const REASONING_LEVELS = ['none', 'low', 'medium', 'high'];
|
|
48
|
+
export const REASONING_LEVELS = ['none', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
49
49
|
/**
|
|
50
50
|
* The provider-neutral reasoning key (ADR 0047): a level, or a token budget.
|
|
51
51
|
* The compiler maps it per provider (lib/compile.ts reasoningConfig).
|
|
@@ -62,7 +62,7 @@ const reasoningSchema = z
|
|
|
62
62
|
return `must be one of ${REASONING_LEVELS.join(' | ')}, or { budget_tokens: <integer ≥ 0> } (got ${describeValue(iss.input)}${hint ? ` — did you mean "${hint}"?` : ''})`;
|
|
63
63
|
},
|
|
64
64
|
})
|
|
65
|
-
.describe('How hard this agent reasons, on any provider: none | low | medium | high, or { budget_tokens: <int> }. Replaces generateContentConfig.thinkingConfig and reasoningEffort (ADR 0047).');
|
|
65
|
+
.describe('How hard this agent reasons, on any provider: none | low | medium | high | xhigh | max, or { budget_tokens: <int> }. xhigh and max reach the models that take them; elsewhere they go as the model\'s highest setting (ADR 0117). Replaces generateContentConfig.thinkingConfig and reasoningEffort (ADR 0047).');
|
|
66
66
|
/**
|
|
67
67
|
* Loose on purpose: provider-specific fields (e.g. `toolConfig`) pass through
|
|
68
68
|
* to the SDK. Only the documented fields are typed, so `temperature: hot`
|
|
@@ -89,7 +89,7 @@ const generateContentConfig = z
|
|
|
89
89
|
.optional()
|
|
90
90
|
.describe('Older spelling of `reasoning` for the chat-completions and Responses providers. Cannot be combined with `reasoning`.'),
|
|
91
91
|
})
|
|
92
|
-
.describe('Deprecated v1 spelling (ADR 0115): write `sampling` (temperature, top_p, max_output_tokens, stop), `output.mime` (responseMimeType)
|
|
92
|
+
.describe('Deprecated v1 spelling (ADR 0115): write `sampling` (temperature, top_p, max_output_tokens, stop), `output.mime` (responseMimeType), `reasoning` (thinkingConfig, reasoningEffort) and `tool_choice` (toolConfig.functionCallingConfig) instead; npx melchizedek-codemod rewrites a file. Still read: the Gemini GenerateContentConfig shape the engine takes. Do not set tools here.')
|
|
93
93
|
.meta({ deprecated: true });
|
|
94
94
|
// ── YAML v2 agent keys (ADR 0115) ────────────────────────────────────────────
|
|
95
95
|
/** `sampling` and `output` must say something: an empty block is a leftover. */
|
|
@@ -116,6 +116,20 @@ const outputSchemaV2 = z
|
|
|
116
116
|
})
|
|
117
117
|
.refine(nonEmpty, { message: 'must set schema or mime', when: quiet })
|
|
118
118
|
.describe('What this agent\'s final reply is (ADR 0115). Replaces outputSchema and generateContentConfig.responseMimeType; cannot be combined with them.');
|
|
119
|
+
export const TOOL_CHOICE_MODES = ['auto', 'none', 'required'];
|
|
120
|
+
const toolChoiceSchema = z
|
|
121
|
+
.union([
|
|
122
|
+
z.enum(TOOL_CHOICE_MODES),
|
|
123
|
+
z.strictObject({
|
|
124
|
+
name: z.string().min(1).describe('The one tool the model must call: a name from this agent\'s tools, subagents or MCP tools.'),
|
|
125
|
+
}),
|
|
126
|
+
], {
|
|
127
|
+
error: (iss) => {
|
|
128
|
+
const hint = typeof iss.input === 'string' ? suggest(iss.input, TOOL_CHOICE_MODES) : undefined;
|
|
129
|
+
return `must be one of ${TOOL_CHOICE_MODES.join(' | ')}, or { name: <tool> } (got ${describeValue(iss.input)}${hint ? ` — did you mean "${hint}"?` : ''})`;
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
.describe('Which tools the model may call, on any provider (ADR 0117): auto (the default), none, required (some tool), or { name: <tool> } (that tool). A provider that rejects forcing sends a weaker choice and marks the span llm.tool_choice.weakened. Replaces generateContentConfig.toolConfig.functionCallingConfig; cannot be combined with it.');
|
|
119
133
|
const modelOverrideEntry = z
|
|
120
134
|
.strictObject({
|
|
121
135
|
instruction: z.string().min(1).optional().describe('Replaces the agent\'s instruction on this provider.'),
|
|
@@ -302,6 +316,7 @@ const agentFields = {
|
|
|
302
316
|
reasoning: reasoningSchema.optional(),
|
|
303
317
|
sampling: samplingSchema.optional(),
|
|
304
318
|
output: outputSchemaV2.optional(),
|
|
319
|
+
tool_choice: toolChoiceSchema.optional(),
|
|
305
320
|
model_overrides: modelOverridesSchema.optional(),
|
|
306
321
|
outputSchema: z
|
|
307
322
|
.record(z.string(), z.unknown())
|
|
@@ -374,7 +389,7 @@ export const subagentSchema = z
|
|
|
374
389
|
.string()
|
|
375
390
|
.min(1)
|
|
376
391
|
.optional()
|
|
377
|
-
.describe('A whole nested syndicate (filename under the agents dir) used as this subagent. An approval request or ask_user question raised inside it pauses the turn with the agent path (ADR 0110, ADR 0111): a delegate syndicate\'s gates anywhere, a dispatch syndicate\'s on its
|
|
392
|
+
.describe('A whole nested syndicate (filename under the agents dir) used as this subagent. An approval request or ask_user question raised inside it pauses the turn with the agent path (ADR 0110, ADR 0111): a delegate syndicate\'s gates anywhere, a dispatch syndicate\'s on its routes, which it classifies and runs as at the top, its route\'s answer being its own (ADR 0120), and a workflow\'s ask_user nodes and gates, wherever each runs: delegated to as a subagent, as a dispatch route or as a workflow node (ADR 0119).'),
|
|
378
393
|
a2a_agent_url: z
|
|
379
394
|
.string()
|
|
380
395
|
.min(1)
|
|
@@ -706,17 +721,11 @@ function crossFieldProblems(raw) {
|
|
|
706
721
|
});
|
|
707
722
|
};
|
|
708
723
|
// A skill script run pauses for approval the same way, so it is allowed in
|
|
709
|
-
// the same places; `skills.tools`
|
|
710
|
-
// already carry outright.
|
|
711
|
-
const skillProblems = (agent, path
|
|
724
|
+
// the same places, a delegated subagent included (ADR 0118); `skills.tools`
|
|
725
|
+
// may only unlock tools the agent does not already carry outright.
|
|
726
|
+
const skillProblems = (agent, path) => {
|
|
712
727
|
if (!isObj(agent.skills))
|
|
713
728
|
return;
|
|
714
|
-
if (agent.skills.scripts === 'local' && !allowed) {
|
|
715
|
-
out.push({
|
|
716
|
-
path: [...path, 'skills', 'scripts'],
|
|
717
|
-
message: 'skill scripts on a delegated subagent are not supported yet; run them on the orchestrator or a plan-dispatch route (ADR 0110)',
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
729
|
const tools = Array.isArray(agent.tools) ? agent.tools : [];
|
|
721
730
|
(Array.isArray(agent.skills.tools) ? agent.skills.tools : []).forEach((name, j) => {
|
|
722
731
|
if (typeof name === 'string' && tools.includes(name)) {
|
|
@@ -823,19 +832,17 @@ function crossFieldProblems(raw) {
|
|
|
823
832
|
v2Problems(sub, ['subagents', i]);
|
|
824
833
|
if (isObj(raw.orchestrator)) {
|
|
825
834
|
gateProblems(raw.orchestrator, ['orchestrator'], true);
|
|
826
|
-
skillProblems(raw.orchestrator, ['orchestrator']
|
|
835
|
+
skillProblems(raw.orchestrator, ['orchestrator']);
|
|
827
836
|
questionProblems(raw.orchestrator, ['orchestrator'], true);
|
|
828
837
|
}
|
|
829
|
-
const dispatching = isObj(raw.dispatch);
|
|
830
838
|
// A workflow's subagents are its nodes, not delegated tools: a gated call pauses its node, and
|
|
831
839
|
// the walk resumes it (ADR 0098); a skill script run pauses on the same approval (ADR 0106). A map item cannot (workflowProblems).
|
|
832
|
-
const pausing = dispatching || isObj(raw.workflow);
|
|
833
840
|
subs.forEach((sub, i) => {
|
|
834
841
|
if (!isObj(sub))
|
|
835
842
|
return;
|
|
836
|
-
// A delegated subagent's gate and
|
|
843
|
+
// A delegated subagent's gate, question and skill script run pause the turn through the open call (ADR 0110, ADR 0118).
|
|
837
844
|
gateProblems(sub, ['subagents', i], true);
|
|
838
|
-
skillProblems(sub, ['subagents', i]
|
|
845
|
+
skillProblems(sub, ['subagents', i]);
|
|
839
846
|
questionProblems(sub, ['subagents', i], true);
|
|
840
847
|
const hasRef = typeof sub.yaml_reference === 'string';
|
|
841
848
|
const hasRemote = typeof sub.a2a_agent_url === 'string';
|
package/dist/lib/tools/auth.d.ts
CHANGED
|
@@ -93,14 +93,26 @@ export interface CredentialStore {
|
|
|
93
93
|
/** What the ToolContext member gives a tool: a valid access token for a provider, for this run's user only. */
|
|
94
94
|
export type ToolAccessToken = (provider: string) => Promise<string>;
|
|
95
95
|
export type ToolCredentialErrorCode = 'not_connected' | 'expired' | 'refresh_failed' | 'unreadable' | 'no_user' | 'invalid' | 'unavailable' | 'grant_failed' | 'host_refused';
|
|
96
|
+
/**
|
|
97
|
+
* Which operator allowlist refused a `host_refused` call: the OAuth host
|
|
98
|
+
* allowlist, which binds a provider's tokens to its hosts
|
|
99
|
+
* (`MELCHIZEDEK_OAUTH_HOSTS`, ADR 0114), or the credential host allowlist,
|
|
100
|
+
* which binds a static credential variable such as a client secret to its
|
|
101
|
+
* hosts (`MELCHIZEDEK_CREDENTIAL_HOSTS`, ADR 0122).
|
|
102
|
+
*/
|
|
103
|
+
export type HostAllowlist = 'oauth' | 'credential';
|
|
96
104
|
/**
|
|
97
105
|
* A credential that cannot be used. The message names the provider and what
|
|
98
106
|
* to do, never a token, a user or a key, so a tool may return it to the model.
|
|
107
|
+
* A `host_refused` error names the allowlist that refused (`allowlist`,
|
|
108
|
+
* `'oauth'` when not given).
|
|
99
109
|
*/
|
|
100
110
|
export declare class ToolCredentialError extends Error {
|
|
101
111
|
readonly code: ToolCredentialErrorCode;
|
|
102
112
|
readonly provider?: string;
|
|
103
|
-
|
|
113
|
+
/** For `host_refused`: the allowlist that refused the host. */
|
|
114
|
+
readonly allowlist?: HostAllowlist;
|
|
115
|
+
constructor(code: ToolCredentialErrorCode, provider?: string, allowlist?: HostAllowlist);
|
|
104
116
|
}
|
|
105
117
|
/** A provider name: lowercase letters, digits, and . _ - inside; at most 64 characters. */
|
|
106
118
|
export declare const PROVIDER_NAME: RegExp;
|
package/dist/lib/tools/auth.js
CHANGED
|
@@ -32,11 +32,15 @@
|
|
|
32
32
|
/**
|
|
33
33
|
* A credential that cannot be used. The message names the provider and what
|
|
34
34
|
* to do, never a token, a user or a key, so a tool may return it to the model.
|
|
35
|
+
* A `host_refused` error names the allowlist that refused (`allowlist`,
|
|
36
|
+
* `'oauth'` when not given).
|
|
35
37
|
*/
|
|
36
38
|
export class ToolCredentialError extends Error {
|
|
37
39
|
code;
|
|
38
40
|
provider;
|
|
39
|
-
|
|
41
|
+
/** For `host_refused`: the allowlist that refused the host. */
|
|
42
|
+
allowlist;
|
|
43
|
+
constructor(code, provider, allowlist) {
|
|
40
44
|
const p = provider ? `"${provider}"` : 'this provider';
|
|
41
45
|
super(code === 'not_connected'
|
|
42
46
|
? `No ${p} account is connected for this user; ask them to connect it.`
|
|
@@ -53,11 +57,15 @@ export class ToolCredentialError extends Error {
|
|
|
53
57
|
: code === 'grant_failed'
|
|
54
58
|
? `The server's own ${p} authorization could not be obtained from the provider's token endpoint.`
|
|
55
59
|
: code === 'host_refused'
|
|
56
|
-
?
|
|
60
|
+
? allowlist === 'credential'
|
|
61
|
+
? `The ${p} client secret may not be sent to this host: the operator's credential host allowlist (MELCHIZEDEK_CREDENTIAL_HOSTS) does not bind it there.`
|
|
62
|
+
: `The ${p} authorization may not be sent to this host: the operator's OAuth host allowlist (MELCHIZEDEK_OAUTH_HOSTS) does not include it.`
|
|
57
63
|
: `Invalid credential request for ${p}.`);
|
|
58
64
|
this.name = 'ToolCredentialError';
|
|
59
65
|
this.code = code;
|
|
60
66
|
this.provider = provider;
|
|
67
|
+
if (code === 'host_refused')
|
|
68
|
+
this.allowlist = allowlist ?? 'oauth';
|
|
61
69
|
}
|
|
62
70
|
}
|
|
63
71
|
/** A provider name: lowercase letters, digits, and . _ - inside; at most 64 characters. */
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/tools/credentialHosts.ts — the operator's credential host allowlist:
|
|
3
|
+
* which hosts the value of each static credential variable may be sent to
|
|
4
|
+
* (ADR 0122).
|
|
5
|
+
*
|
|
6
|
+
* WHY this file exists:
|
|
7
|
+
* A syndicate YAML (possibly registry-stored) names a credential variable
|
|
8
|
+
* and, beside it, the host its value goes to: an OpenAPI `auth` sends
|
|
9
|
+
* `bearer_env` or `api_key.env` to the spec's server (or `base_url`), and
|
|
10
|
+
* an `oauth2` block sends `client_secret_env` to its `token_url`.
|
|
11
|
+
* credentialEnvProblem (lib/tools/credentialEnv.ts) keeps the framework's
|
|
12
|
+
* own secrets out of reach, and the OAuth host allowlist (ADR 0114) binds
|
|
13
|
+
* a provider's tokens, but nothing bound a static secret to its API: a
|
|
14
|
+
* YAML that names TRACKER_TOKEN could aim it at a host of its own. The
|
|
15
|
+
* binding is the operator's, never the YAML's: an environment variable or
|
|
16
|
+
* `createA2AApp({ credentialHosts })`.
|
|
17
|
+
*
|
|
18
|
+
* THE RULE (ADR 0122):
|
|
19
|
+
* - With no allowlist configured, nothing changes: a credential goes to
|
|
20
|
+
* the host the YAML names, as before. The doctor and the server binary
|
|
21
|
+
* name every credential variable a served YAML sends, as unbound.
|
|
22
|
+
* - With an allowlist configured, it is the whole list: every credential
|
|
23
|
+
* variable a YAML sends must be on it, and every host its value goes to
|
|
24
|
+
* must be one of that variable's hosts.
|
|
25
|
+
* - The check runs when a syndicate is loaded to be served, when its tools
|
|
26
|
+
* are compiled, and again before each call sends the value.
|
|
27
|
+
*
|
|
28
|
+
* WHAT IT COVERS: `bearer_env`, `api_key.env` and `client_secret_env` (both
|
|
29
|
+
* grants: the client-credentials token request, the consent step's code
|
|
30
|
+
* exchange and its refresh). Not `client_id_env`: a client id is not a
|
|
31
|
+
* secret. Not MCP_BEARER_TOKENS: it maps each token to its host already,
|
|
32
|
+
* and the operator writes both.
|
|
33
|
+
*
|
|
34
|
+
* THE FORMAT: `MELCHIZEDEK_CREDENTIAL_HOSTS="TRACKER_TOKEN=api.tracker.example.com;WEATHER_KEY=api.weather.example.com,*.weather.example.com"`.
|
|
35
|
+
* Entries are separated by `;` (or a newline), a variable from its hosts by
|
|
36
|
+
* `=`, hosts by `,`. A host is what the OAuth host allowlist takes
|
|
37
|
+
* (lib/tools/oauthHosts.ts): a hostname, `*.example.com`, IPv4 or
|
|
38
|
+
* `[IPv6]`, with no scheme, port or path.
|
|
39
|
+
*
|
|
40
|
+
* Nothing here reads or prints a credential's value: variable names and
|
|
41
|
+
* hosts only. No regular expression here can backtrack: the separators are
|
|
42
|
+
* single characters, and a variable name is one bounded character class.
|
|
43
|
+
*/
|
|
44
|
+
/** The environment variable the allowlist is read from when no option sets it. */
|
|
45
|
+
export declare const CREDENTIAL_HOSTS_ENV = "MELCHIZEDEK_CREDENTIAL_HOSTS";
|
|
46
|
+
/** Credential variable name → the hosts its value may be sent to. */
|
|
47
|
+
export type CredentialHostAllowlist = Readonly<Record<string, readonly string[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* The allowlist, checked and normalized (hosts lowercased, duplicates
|
|
50
|
+
* dropped). Throws, naming the variable and the host, on anything malformed.
|
|
51
|
+
*/
|
|
52
|
+
export declare function checkCredentialHosts(allowlist: Record<string, readonly string[]>, source?: string): Record<string, string[]>;
|
|
53
|
+
/** The allowlist from its text form (MELCHIZEDEK_CREDENTIAL_HOSTS). Throws on a malformed entry. */
|
|
54
|
+
export declare function parseCredentialHosts(text: string): Record<string, string[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Sets this process's allowlist (createA2AApp's `credentialHosts` does),
|
|
57
|
+
* which wins over the environment variable. `undefined` returns to the
|
|
58
|
+
* variable.
|
|
59
|
+
*/
|
|
60
|
+
export declare function setCredentialHosts(allowlist: Record<string, readonly string[]> | undefined): void;
|
|
61
|
+
/**
|
|
62
|
+
* The allowlist in force: the one set by `setCredentialHosts`, else the
|
|
63
|
+
* environment variable's, else undefined (not configured). A malformed
|
|
64
|
+
* variable throws, so the first check refuses rather than allowing.
|
|
65
|
+
*/
|
|
66
|
+
export declare function credentialHosts(env?: NodeJS.ProcessEnv): CredentialHostAllowlist | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Why the value of credential variable `name` may not be sent to `url`, or
|
|
69
|
+
* null. `role` names the URL in the message (`server`, `token_url`).
|
|
70
|
+
* `allowlist` defaults to the one in force; `null` means none is
|
|
71
|
+
* configured, which allows (the behaviour before ADR 0122).
|
|
72
|
+
*/
|
|
73
|
+
export declare function credentialHostProblem(name: string, url: string, role?: string, allowlist?: CredentialHostAllowlist | null | undefined): string | null;
|
|
74
|
+
/**
|
|
75
|
+
* The call-time check: why the value of `name` may not be sent to
|
|
76
|
+
* `destination` now, or null. A malformed allowlist refuses.
|
|
77
|
+
*/
|
|
78
|
+
export declare function credentialCallProblem(name: string, destination: string): string | null;
|
|
79
|
+
/**
|
|
80
|
+
* Marks an OAuth client config (lib/tools/oauthConsent.ts) with the
|
|
81
|
+
* variable its client secret came from, so the consent step's code exchange
|
|
82
|
+
* and the refresh hook can check the token endpoint at call time. Set by
|
|
83
|
+
* oauthClientsFor (lib/tools/oauthTools.ts); a client built by hand carries
|
|
84
|
+
* none and is not checked.
|
|
85
|
+
*/
|
|
86
|
+
export declare const CLIENT_SECRET_ENV: unique symbol;
|
|
87
|
+
/** The variable a client config's secret came from, when oauthClientsFor marked it. */
|
|
88
|
+
export declare function clientSecretEnvOf(client: object): string | undefined;
|