melchizedek-agents 1.0.2 → 1.1.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 +19 -2
- package/CHANGELOG.md +333 -0
- package/DOCUMENTATION.md +99 -39
- package/README.md +1 -0
- 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 +6 -6
- package/config/agents/examples/critic.yaml +16 -16
- package/config/agents/examples/harness.yaml +4 -4
- package/config/agents/examples/image_production.yaml +33 -32
- 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 +1979 -0
- package/config/agents/syndicateSchema.yaml +109 -72
- 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 +61 -60
- 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 +21 -5
- package/db/migrations/0014_durable_runs.sql +31 -0
- package/dist/lib/a2a/app.d.ts +15 -0
- package/dist/lib/a2a/app.js +53 -5
- package/dist/lib/a2a/executor.d.ts +7 -1
- package/dist/lib/a2a/executor.js +34 -4
- package/dist/lib/a2a/oauthSetup.d.ts +90 -0
- package/dist/lib/a2a/oauthSetup.js +205 -0
- package/dist/lib/agentDialect.d.ts +66 -0
- package/dist/lib/agentDialect.js +134 -0
- package/dist/lib/compile.d.ts +10 -5
- package/dist/lib/compile.js +69 -37
- package/dist/lib/compileNative.js +2 -0
- package/dist/lib/dispatch.d.ts +10 -5
- package/dist/lib/dispatch.js +10 -5
- package/dist/lib/doctor.d.ts +34 -1
- package/dist/lib/doctor.js +47 -3
- package/dist/lib/loadSyndicate.d.ts +45 -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 +16 -1
- package/dist/lib/models/capabilities.js +55 -1
- package/dist/lib/observability/tracer.d.ts +8 -1
- package/dist/lib/observability/tracer.js +33 -5
- package/dist/lib/runtime/approvals.d.ts +6 -0
- package/dist/lib/runtime/native/agentLoop.d.ts +18 -1
- package/dist/lib/runtime/native/agentLoop.js +105 -11
- package/dist/lib/runtime/native/checkpoint.d.ts +164 -0
- package/dist/lib/runtime/native/checkpoint.js +365 -0
- package/dist/lib/runtime/native/delegate.d.ts +141 -18
- package/dist/lib/runtime/native/delegate.js +235 -39
- package/dist/lib/runtime/native/interrupts.d.ts +101 -2
- package/dist/lib/runtime/native/interrupts.js +201 -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 +7 -1
- package/dist/lib/runtime/syndicateTurn.js +74 -22
- package/dist/lib/runtime/turnControl.d.ts +15 -0
- package/dist/lib/runtime/turnControl.js +10 -0
- package/dist/lib/storage/postgres/index.d.ts +6 -1
- package/dist/lib/storage/postgres/index.js +7 -2
- package/dist/lib/storage/postgres/taskQueue.d.ts +14 -2
- package/dist/lib/storage/postgres/taskQueue.js +20 -3
- 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 +278 -0
- package/dist/lib/syndicateSchema.js +182 -15
- package/dist/lib/tools/auth.d.ts +7 -5
- package/dist/lib/tools/auth.js +12 -4
- package/dist/lib/tools/credentialEnv.d.ts +28 -0
- package/dist/lib/tools/credentialEnv.js +52 -0
- package/dist/lib/tools/credentialStore.js +9 -2
- package/dist/lib/tools/mcpToolFactory.d.ts +25 -2
- package/dist/lib/tools/mcpToolFactory.js +179 -21
- package/dist/lib/tools/oauthHosts.d.ts +71 -0
- package/dist/lib/tools/oauthHosts.js +154 -0
- package/dist/lib/tools/oauthTools.d.ts +233 -0
- package/dist/lib/tools/oauthTools.js +421 -0
- package/dist/lib/tools/openapiTools.d.ts +4 -6
- package/dist/lib/tools/openapiTools.js +40 -36
- package/dist/lib/tools/taskTools.d.ts +30 -5
- package/dist/lib/tools/taskTools.js +74 -10
- package/dist/lib/workflow.d.ts +8 -4
- package/dist/lib/workflow.js +8 -4
- package/dist/lib/workflowConfig.d.ts +6 -0
- package/dist/scripts/a2a_server.d.ts +36 -0
- package/dist/scripts/a2a_server.js +122 -1
- package/dist/scripts/assistant_worker.d.ts +10 -0
- package/dist/scripts/assistant_worker.js +69 -19
- package/dist/scripts/doctor.d.ts +4 -1
- package/dist/scripts/doctor.js +5 -2
- package/dist/scripts/yaml_codemod.d.ts +52 -0
- package/dist/scripts/yaml_codemod.js +570 -0
- package/package.json +11 -7
- package/skills/briefs/melchizedek-author.md +7 -5
- package/skills/briefs/melchizedek-models.md +4 -3
- package/skills/briefs/melchizedek.md +1 -0
- 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 +6 -3
|
@@ -21,6 +21,16 @@
|
|
|
21
21
|
* instead of abandoning it while it keeps spending. Any syndicate and any
|
|
22
22
|
* subagent in it can serve as the worker.
|
|
23
23
|
*
|
|
24
|
+
* A run is durable (ADR 0113): runDurableTurn (lib/runtime/native/
|
|
25
|
+
* checkpoint.ts) checkpoints the run's sessions at every step boundary
|
|
26
|
+
* beside the job (TaskBackend.saveCheckpoint), and a job claimed again
|
|
27
|
+
* after its worker stopped resumes from its last checkpoint instead of
|
|
28
|
+
* starting over. SIGTERM aborts the step in flight and puts the job back
|
|
29
|
+
* in the queue with its checkpoint; the next worker finishes it. A job
|
|
30
|
+
* cancelled while it runs (task_update) loses its claim: the next lease
|
|
31
|
+
* renewal or checkpoint save sees it, and the run is aborted without
|
|
32
|
+
* writing a result over the cancellation.
|
|
33
|
+
*
|
|
24
34
|
* Usage:
|
|
25
35
|
* npm run assistant:worker poll every 30 s until Ctrl-C
|
|
26
36
|
* npm run assistant:worker -- --once drain the queue, then exit (cron)
|
|
@@ -34,12 +44,11 @@
|
|
|
34
44
|
import { randomUUID } from 'node:crypto';
|
|
35
45
|
import { loadEnv } from '../lib/loadEnv.js';
|
|
36
46
|
import { loadSyndicate } from '../lib/loadSyndicate.js';
|
|
37
|
-
import {
|
|
47
|
+
import { runDurableTurn } from '../lib/runtime/native/checkpoint.js';
|
|
38
48
|
import { runtimeSetting } from '../lib/runtime/runtimeFlag.js';
|
|
39
49
|
import { setLogLevel } from '../lib/runtime/logging.js';
|
|
40
|
-
import { InProcessSessionService } from '../lib/runtime/sessions.js';
|
|
41
50
|
import { PROVIDERS, providerForModel, providerKeyPresent, } from '../lib/models/registry.js';
|
|
42
|
-
import { getTaskBackend, setTaskBackend, taskStorePath } from '../lib/tools/taskTools.js';
|
|
51
|
+
import { applyInterrupted, getTaskBackend, setTaskBackend, taskStorePath } from '../lib/tools/taskTools.js';
|
|
43
52
|
import { postgresStorage } from '../lib/storage/postgres/index.js';
|
|
44
53
|
import { dbSchema } from '../lib/storage/schema.js';
|
|
45
54
|
import { hostname } from 'node:os';
|
|
@@ -105,24 +114,43 @@ const workerConfig = !sub
|
|
|
105
114
|
};
|
|
106
115
|
/** The job in hand, so a signal can cancel it. */
|
|
107
116
|
let current;
|
|
108
|
-
|
|
117
|
+
/** Set by SIGTERM: the job in hand goes back to the queue with its checkpoint. */
|
|
118
|
+
let interrupted = false;
|
|
119
|
+
/** The run lost its claim on the job (cancelled while it ran, or taken by another worker). */
|
|
120
|
+
class ClaimLost extends Error {
|
|
121
|
+
}
|
|
122
|
+
/** SIGTERM stopped the run; the job is re-queued, not failed. */
|
|
123
|
+
class Interrupted extends Error {
|
|
124
|
+
}
|
|
125
|
+
// ── One job = one durable single-turn run (ADR 0113) ────────────────────────
|
|
109
126
|
async function runJob(job) {
|
|
110
|
-
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
current = controller;
|
|
111
129
|
try {
|
|
112
|
-
|
|
130
|
+
// A fresh in-process store per attempt, restored from the job's last
|
|
131
|
+
// checkpoint when an earlier attempt left one (ADR 0080, ADR 0113).
|
|
132
|
+
const result = await runDurableTurn({
|
|
113
133
|
config: workerConfig,
|
|
114
134
|
parts: [{ text: job.instruction ?? job.title }],
|
|
115
135
|
appName: 'assistant-worker',
|
|
116
136
|
userId: 'local-user',
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
137
|
+
runId: `${job.owner}:${job.id}`,
|
|
138
|
+
checkpoints: {
|
|
139
|
+
load: async () => ((await backend.loadCheckpoint?.(job)) ?? null),
|
|
140
|
+
save: async (checkpoint) => (backend.saveCheckpoint ? backend.saveCheckpoint(lease, job, checkpoint) : true),
|
|
141
|
+
},
|
|
142
|
+
onSaveError: (e) => log(`checkpoint not saved: ${e instanceof Error ? e.message : String(e)}`),
|
|
121
143
|
compile: { log, onUnknownTool: (n) => log(`unknown tool '${n}' skipped`) },
|
|
122
|
-
signal:
|
|
144
|
+
signal: controller.signal,
|
|
123
145
|
deadlineMs: JOB_TIMEOUT_MS,
|
|
124
146
|
events: { warn: (m) => log(`⚠ ${m}`) },
|
|
125
147
|
});
|
|
148
|
+
if (result.resumedFromStep > 0)
|
|
149
|
+
log(`${job.id} resumed from step ${result.resumedFromStep}`);
|
|
150
|
+
if (result.lostClaim || controller.signal.reason instanceof ClaimLost)
|
|
151
|
+
throw new ClaimLost('the job was cancelled or claimed elsewhere');
|
|
152
|
+
if (interrupted)
|
|
153
|
+
throw new Interrupted('stopped by SIGTERM');
|
|
126
154
|
if (result.status !== 'completed') {
|
|
127
155
|
throw new Error(`${result.error?.code ?? 'ERROR'}: ${result.error?.message ?? ''}`.trim());
|
|
128
156
|
}
|
|
@@ -142,10 +170,17 @@ async function drain() {
|
|
|
142
170
|
const started = Date.now();
|
|
143
171
|
const label = job.owner ? `${job.id} (${job.owner})` : job.id;
|
|
144
172
|
log(`${label} started: ${job.title}`);
|
|
145
|
-
// Renew the lease while the job runs, so no other worker takes it back
|
|
173
|
+
// Renew the lease while the job runs, so no other worker takes it back;
|
|
174
|
+
// a renewal that finds the claim gone (the job was cancelled) stops the run.
|
|
146
175
|
const held = job;
|
|
147
176
|
const heartbeat = setInterval(() => {
|
|
148
|
-
backend
|
|
177
|
+
backend
|
|
178
|
+
.renew(lease, held)
|
|
179
|
+
.then((kept) => {
|
|
180
|
+
if (kept === false)
|
|
181
|
+
current?.abort(new ClaimLost('claim lost'));
|
|
182
|
+
})
|
|
183
|
+
.catch((e) => log(`lease renewal failed: ${e instanceof Error ? e.message : e}`));
|
|
149
184
|
}, Math.floor(lease.leaseMs / 3));
|
|
150
185
|
try {
|
|
151
186
|
const result = await runJob(job);
|
|
@@ -153,8 +188,22 @@ async function drain() {
|
|
|
153
188
|
log(`${label} done in ${Math.round((Date.now() - started) / 1000)} s`);
|
|
154
189
|
}
|
|
155
190
|
catch (error) {
|
|
156
|
-
|
|
157
|
-
|
|
191
|
+
if (error instanceof ClaimLost) {
|
|
192
|
+
// Cancelled while it ran: the record already says so; nothing is written over it.
|
|
193
|
+
log(`${label} stopped: ${error.message}`);
|
|
194
|
+
}
|
|
195
|
+
else if (error instanceof Interrupted) {
|
|
196
|
+
// Back to the queue with its checkpoint, or failed after MAX_ATTEMPTS interruptions.
|
|
197
|
+
const outcome = await backend.mutate(job.owner, (store) => {
|
|
198
|
+
const t = store.tasks.find((r) => r.id === held.id);
|
|
199
|
+
return t && t.status === 'running' ? applyInterrupted(t) : 'left as is';
|
|
200
|
+
});
|
|
201
|
+
log(`${label} interrupted: ${outcome}`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
await backend.finish(job, { error: String(error?.message ?? error) });
|
|
205
|
+
log(`${label} failed: ${error?.message ?? error}`);
|
|
206
|
+
}
|
|
158
207
|
}
|
|
159
208
|
finally {
|
|
160
209
|
clearInterval(heartbeat);
|
|
@@ -183,12 +232,13 @@ process.on('SIGINT', () => {
|
|
|
183
232
|
stopping = true;
|
|
184
233
|
log('stopping after the current job (Ctrl-C again to quit now)');
|
|
185
234
|
});
|
|
186
|
-
// A container stop:
|
|
187
|
-
//
|
|
235
|
+
// A container stop: abort the step in flight and put the job back in the
|
|
236
|
+
// queue with its checkpoint, so the next worker resumes it (ADR 0113).
|
|
188
237
|
process.on('SIGTERM', () => {
|
|
189
238
|
stopping = true;
|
|
190
|
-
|
|
191
|
-
current
|
|
239
|
+
interrupted = true;
|
|
240
|
+
log('SIGTERM — stopping the current job; it resumes from its last checkpoint');
|
|
241
|
+
current?.abort(new Interrupted('SIGTERM'));
|
|
192
242
|
});
|
|
193
243
|
while (!stopping) {
|
|
194
244
|
await drain();
|
package/dist/scripts/doctor.d.ts
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* gateway stand-in, or local), which declared server-side tools it keeps or
|
|
9
9
|
* drops, and one verdict per syndicate. Says first which runtime a turn runs
|
|
10
10
|
* on (native; a leftover MELCHIZEDEK_RUNTIME=adk is a problem, since 1.0.0
|
|
11
|
-
* removed that runtime).
|
|
11
|
+
* removed that runtime). Lists the tools that need an OAuth grant (an
|
|
12
|
+
* `auth: { oauth2 }` or `mcp_auth`, ADR 0112): each user's consent, or the
|
|
13
|
+
* server's own client credentials and whether their variables are set
|
|
14
|
+
* (names only). Closes with the env vars that would
|
|
12
15
|
* unlock the most, where to get each, and the first command to try.
|
|
13
16
|
*
|
|
14
17
|
* Read-only: never edits .env, never sends a request, never prints a key
|
package/dist/scripts/doctor.js
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* gateway stand-in, or local), which declared server-side tools it keeps or
|
|
9
9
|
* drops, and one verdict per syndicate. Says first which runtime a turn runs
|
|
10
10
|
* on (native; a leftover MELCHIZEDEK_RUNTIME=adk is a problem, since 1.0.0
|
|
11
|
-
* removed that runtime).
|
|
11
|
+
* removed that runtime). Lists the tools that need an OAuth grant (an
|
|
12
|
+
* `auth: { oauth2 }` or `mcp_auth`, ADR 0112): each user's consent, or the
|
|
13
|
+
* server's own client credentials and whether their variables are set
|
|
14
|
+
* (names only). Closes with the env vars that would
|
|
12
15
|
* unlock the most, where to get each, and the first command to try.
|
|
13
16
|
*
|
|
14
17
|
* Read-only: never edits .env, never sends a request, never prints a key
|
|
@@ -88,5 +91,5 @@ if (json) {
|
|
|
88
91
|
else {
|
|
89
92
|
console.log(renderDoctor(result, { color: !noColor }));
|
|
90
93
|
}
|
|
91
|
-
if (check && (result.counts.blocked > 0 || result.runtime.problem))
|
|
94
|
+
if (check && (result.counts.blocked > 0 || result.runtime.problem || result.oauth?.problems.length))
|
|
92
95
|
process.exit(1);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/yaml_codemod.ts — the `melchizedek-codemod` bin and `npm run yaml:codemod`.
|
|
4
|
+
*
|
|
5
|
+
* Rewrites an agent's v1 spellings into the v2 keys (ADR 0115):
|
|
6
|
+
*
|
|
7
|
+
* npm run yaml:codemod -- config/agents/my_syndicate.yaml # rewrite in place
|
|
8
|
+
* npm run yaml:codemod -- config/agents # every *.yaml below it
|
|
9
|
+
* npm run yaml:codemod -- --check config/agents # exit 1 if any file would change
|
|
10
|
+
*
|
|
11
|
+
* Per agent (the orchestrator and every inline subagent):
|
|
12
|
+
*
|
|
13
|
+
* outputSchema → output.schema
|
|
14
|
+
* generateContentConfig.responseMimeType → output.mime (application/json | text/plain)
|
|
15
|
+
* generateContentConfig.temperature → sampling.temperature
|
|
16
|
+
* generateContentConfig.topP → sampling.top_p
|
|
17
|
+
* generateContentConfig.maxOutputTokens → sampling.max_output_tokens
|
|
18
|
+
* generateContentConfig.stopSequences → sampling.stop
|
|
19
|
+
* generateContentConfig.thinkingConfig / reasoningEffort → reasoning:, ONLY
|
|
20
|
+
* when the engine reads the same ReasoningSetting before and after for
|
|
21
|
+
* the agent's model (reasoningOf over the old config equals reasoningOf
|
|
22
|
+
* over what reasoningConfig makes of the new key).
|
|
23
|
+
* generateContentConfig.thinkingConfig.includeThoughts: false → dropped (the default; read by nothing)
|
|
24
|
+
*
|
|
25
|
+
* Anything else stays under generateContentConfig with a note naming its key
|
|
26
|
+
* path (never its value); an emptied generateContentConfig is removed. An
|
|
27
|
+
* agent that already has the v2 key for a concept is left alone for that
|
|
28
|
+
* concept, with a note: the loader refuses an overlap.
|
|
29
|
+
*
|
|
30
|
+
* HOW: the file is parsed with the `yaml` package's Document API, which
|
|
31
|
+
* locates every key and value in the source. The edit splices whole lines:
|
|
32
|
+
* a moved key travels with its own lines (its leading and inline comments,
|
|
33
|
+
* its indentation and quoting); the comments of a key that is converted or
|
|
34
|
+
* dropped are kept as comment lines where the new key goes. Every line the
|
|
35
|
+
* codemod does not move is left byte for byte. The result is parsed again and
|
|
36
|
+
* must read back as the planned data, or the file is refused. Running it
|
|
37
|
+
* twice changes nothing the second time.
|
|
38
|
+
*/
|
|
39
|
+
export interface MigrateResult {
|
|
40
|
+
/** The migrated text; the input itself when nothing changed. */
|
|
41
|
+
text: string;
|
|
42
|
+
changed: boolean;
|
|
43
|
+
/** One line per key left in a v1 spelling, naming its key path (never a value). */
|
|
44
|
+
notes: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Rewrites one YAML text's v1 agent keys into v2 (see the header). Throws on
|
|
48
|
+
* text that is not one YAML document, and on an edit that would not read
|
|
49
|
+
* back as planned (a bug, never a silent change).
|
|
50
|
+
*/
|
|
51
|
+
export declare function migrateYaml(text: string): MigrateResult;
|
|
52
|
+
export declare function main(argv: string[]): number;
|