@jungjaehoon/mama-core 4.0.0 → 4.1.1
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/README.md +1 -1
- package/db/migrations/099-commitment-revision-graph.sql +2 -0
- package/dist/api/catalog.js +5 -5
- package/dist/api/dispatch.js +12 -1
- package/dist/db-adapter/node-sqlite-adapter.js +17 -0
- package/dist/knowledge/commitment-revision-migration.d.ts +4 -0
- package/dist/knowledge/commitment-revision-migration.js +50 -0
- package/dist/knowledge/commitments.d.ts +6 -2
- package/dist/knowledge/commitments.js +18 -2
- package/dist/knowledge/judgment-edge.d.ts +6 -0
- package/dist/knowledge/judgment-edge.js +22 -0
- package/dist/knowledge/judgments.js +7 -13
- package/dist/runtime/drivers/claude-cli-wrapper.d.ts +3 -6
- package/dist/runtime/drivers/claude-cli-wrapper.js +2 -19
- package/dist/runtime/drivers/claude-effort.d.ts +4 -0
- package/dist/runtime/drivers/claude-effort.js +16 -0
- package/dist/runtime/drivers/persistent-cli-process.d.ts +3 -2
- package/dist/runtime/drivers/persistent-cli-process.js +2 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The shared engine for storage, records and revisions, evidence links, memory, se
|
|
|
4
4
|
runtime drivers. Consumers supply their own database, principals, source access and product
|
|
5
5
|
vocabulary through public exports. Core does not require the MAMA OS daemon.
|
|
6
6
|
|
|
7
|
-
Version **4.
|
|
7
|
+
Version **4.1.1**; Node.js 22.13+. This README describes the current rebuild checkout.
|
|
8
8
|
See [architecture](../../docs/explanation/architecture.md) and
|
|
9
9
|
[the shared-engine goal](../../INTENT.md).
|
|
10
10
|
|
package/dist/api/catalog.js
CHANGED
|
@@ -55,7 +55,7 @@ const refSchema = {
|
|
|
55
55
|
kind: {
|
|
56
56
|
type: 'string',
|
|
57
57
|
enum: twin_edge_types_js_1.TWIN_REF_KINDS,
|
|
58
|
-
description: 'Referenced graph kind, e.g. "work".',
|
|
58
|
+
description: 'Referenced graph kind, e.g. "memory" (a work item\'s revision record) or "registry".',
|
|
59
59
|
},
|
|
60
60
|
id: {
|
|
61
61
|
type: 'string',
|
|
@@ -145,7 +145,7 @@ const workGraphQuerySchema = {
|
|
|
145
145
|
},
|
|
146
146
|
seeds: {
|
|
147
147
|
type: 'array',
|
|
148
|
-
description: 'Starting graph references, e.g. [{"kind":"
|
|
148
|
+
description: 'Starting graph references, e.g. [{"kind":"memory","id":"judgment_123"}].',
|
|
149
149
|
items: refSchema,
|
|
150
150
|
},
|
|
151
151
|
search: {
|
|
@@ -161,7 +161,7 @@ const workGraphQuerySchema = {
|
|
|
161
161
|
},
|
|
162
162
|
kinds: {
|
|
163
163
|
type: 'array',
|
|
164
|
-
description: 'Kinds to restrict the search, e.g. ["
|
|
164
|
+
description: 'Kinds to restrict the search, e.g. ["registry"].',
|
|
165
165
|
items: { type: 'string', enum: twin_edge_types_js_1.TWIN_REF_KINDS },
|
|
166
166
|
},
|
|
167
167
|
},
|
|
@@ -183,7 +183,7 @@ const workGraphQuerySchema = {
|
|
|
183
183
|
},
|
|
184
184
|
from: {
|
|
185
185
|
...refSchema,
|
|
186
|
-
description: 'Path/timeline start reference, e.g. {"kind":"
|
|
186
|
+
description: 'Path/timeline start reference, e.g. {"kind":"memory","id":"judgment_123"}.',
|
|
187
187
|
},
|
|
188
188
|
to: {
|
|
189
189
|
...refSchema,
|
|
@@ -614,7 +614,7 @@ function coreActionRegistrations(knowledge, adapter, deps) {
|
|
|
614
614
|
{
|
|
615
615
|
contract: {
|
|
616
616
|
name: 'graph.query',
|
|
617
|
-
summary: 'Read the work graph: overview roots, neighbors, paths, timelines, and hydrated details under the caller authority. search resolves a name spelling to its registered node or alias
|
|
617
|
+
summary: 'Read the work graph: overview roots, neighbors, paths, timelines, and hydrated details under the caller authority. Each view takes its own inputs: browse pages every visible edge and accepts only history, relations, asOf, limit and cursor; paths requires from and to; neighbors, timeline and detail need seeds or a search. search resolves a name spelling to its registered node or alias; an empty page with coverage.search_no_match means nothing is registered under that spelling. Ref kinds are memory, case, report, edge, raw, registry and observation; a work item is reached through its memory (revision) records.',
|
|
618
618
|
inputSchema: workGraphQuerySchema,
|
|
619
619
|
examples: [
|
|
620
620
|
{
|
package/dist/api/dispatch.js
CHANGED
|
@@ -272,7 +272,11 @@ function validateInput(schema, value, path) {
|
|
|
272
272
|
if (schema.oneOf !== undefined) {
|
|
273
273
|
const matches = schema.oneOf.filter((sub) => validateInput(sub, value, path) === null).length;
|
|
274
274
|
if (matches !== 1) {
|
|
275
|
-
|
|
275
|
+
// A refusal names what is allowed: "(0 matched)" alone once left a caller dropping the
|
|
276
|
+
// field and the write with it.
|
|
277
|
+
const shapes = schema.oneOf.map(shapeName).join(', ');
|
|
278
|
+
const described = schema.description === undefined ? '' : ` ${schema.description}`;
|
|
279
|
+
return `${path} must match exactly one of: ${shapes} (${matches} matched).${described}`;
|
|
276
280
|
}
|
|
277
281
|
}
|
|
278
282
|
if (typeof value === 'number') {
|
|
@@ -349,6 +353,13 @@ function validateInput(schema, value, path) {
|
|
|
349
353
|
}
|
|
350
354
|
return null;
|
|
351
355
|
}
|
|
356
|
+
function shapeName(schema) {
|
|
357
|
+
if (schema.const !== undefined)
|
|
358
|
+
return JSON.stringify(schema.const);
|
|
359
|
+
if (schema.enum !== undefined)
|
|
360
|
+
return schema.enum.map((value) => JSON.stringify(value)).join(' | ');
|
|
361
|
+
return schema.type ?? 'a described shape';
|
|
362
|
+
}
|
|
352
363
|
function typeMismatch(type, value) {
|
|
353
364
|
switch (type) {
|
|
354
365
|
case 'object':
|
|
@@ -14,6 +14,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
14
14
|
const node_sqlite_statement_js_1 = require("./node-sqlite-statement.js");
|
|
15
15
|
const debug_logger_js_1 = require("../debug-logger.js");
|
|
16
16
|
const embedder_js_1 = require("../embedding/embedder.js");
|
|
17
|
+
const commitment_revision_migration_js_1 = require("../knowledge/commitment-revision-migration.js");
|
|
17
18
|
const SQLITE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
18
19
|
// Migration 071 origin invariant, kept in ONE place so the DDL the rebuild
|
|
19
20
|
// writes and the shape verification that admits a table cannot drift. A row is
|
|
@@ -674,6 +675,22 @@ class NodeSQLiteAdapter {
|
|
|
674
675
|
if (version <= currentVersion) {
|
|
675
676
|
continue;
|
|
676
677
|
}
|
|
678
|
+
if (isCore && version === 99) {
|
|
679
|
+
try {
|
|
680
|
+
this.exec('BEGIN TRANSACTION');
|
|
681
|
+
(0, commitment_revision_migration_js_1.backfillCommitmentRevisionGraph)(this);
|
|
682
|
+
this.exec(fs_1.default.readFileSync(path_1.default.join(migrationsDir, file), 'utf8'));
|
|
683
|
+
this.stampMigration(sourceName, version);
|
|
684
|
+
this.exec('COMMIT');
|
|
685
|
+
(0, debug_logger_js_1.info)(`[node-sqlite-adapter] Migration ${file} applied successfully`);
|
|
686
|
+
}
|
|
687
|
+
catch (err) {
|
|
688
|
+
this.exec('ROLLBACK');
|
|
689
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
690
|
+
throw new Error(`Migration ${file} failed: ${message}`);
|
|
691
|
+
}
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
677
694
|
if (isCore && version === 98) {
|
|
678
695
|
const decisionColumns = this.tableColumns('decisions');
|
|
679
696
|
if (!this.tableExists('decisions_fts') ||
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from '../db-manager.js';
|
|
2
|
+
/** Link every stored commitment revision to the revision it follows. */
|
|
3
|
+
export declare function backfillCommitmentRevisionGraph(adapter: DatabaseAdapter): void;
|
|
4
|
+
//# sourceMappingURL=commitment-revision-migration.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.backfillCommitmentRevisionGraph = backfillCommitmentRevisionGraph;
|
|
4
|
+
const judgment_edge_js_1 = require("./judgment-edge.js");
|
|
5
|
+
/** Link every stored commitment revision to the revision it follows. */
|
|
6
|
+
function backfillCommitmentRevisionGraph(adapter) {
|
|
7
|
+
const assignments = adapter
|
|
8
|
+
.prepare(`SELECT assignment.commitment_id, assignment.revision, assignment.record_id, assignment.operation,
|
|
9
|
+
assignment.agent_id, assignment.model_run_id, assignment.created_at
|
|
10
|
+
FROM commitment_assignments AS assignment
|
|
11
|
+
JOIN commitments AS commitment ON commitment.commitment_id = assignment.commitment_id
|
|
12
|
+
ORDER BY assignment.commitment_id, assignment.revision`)
|
|
13
|
+
.all();
|
|
14
|
+
if (assignments.length === 0)
|
|
15
|
+
return;
|
|
16
|
+
const byCommitment = new Map();
|
|
17
|
+
for (const assignment of assignments) {
|
|
18
|
+
const rows = byCommitment.get(assignment.commitment_id) ?? [];
|
|
19
|
+
rows.push(assignment);
|
|
20
|
+
byCommitment.set(assignment.commitment_id, rows);
|
|
21
|
+
}
|
|
22
|
+
const hasEdge = adapter.prepare(`SELECT 1 FROM twin_edges
|
|
23
|
+
WHERE edge_type = 'builds_on'
|
|
24
|
+
AND subject_kind = 'memory' AND subject_id = ?
|
|
25
|
+
AND object_kind = 'memory' AND object_id = ?`);
|
|
26
|
+
const insertEdge = adapter.prepare(`INSERT OR IGNORE INTO twin_edges (
|
|
27
|
+
edge_id, edge_type, subject_kind, subject_id, object_kind, object_id,
|
|
28
|
+
relation_attrs_json, confidence, source, agent_id, model_run_id, content_hash, created_at
|
|
29
|
+
) VALUES (?, 'builds_on', 'memory', ?, 'memory', ?, '{}', 1.0, 'code', ?, ?, ?, ?)`);
|
|
30
|
+
for (const [commitmentId, revisions] of byCommitment) {
|
|
31
|
+
for (let index = 0; index < revisions.length; index += 1) {
|
|
32
|
+
const current = revisions[index];
|
|
33
|
+
if (current.operation === 'create')
|
|
34
|
+
continue;
|
|
35
|
+
const previous = revisions[index - 1];
|
|
36
|
+
if (!previous) {
|
|
37
|
+
throw new Error(`Commitment ${commitmentId} revision ${current.revision} has no predecessor`);
|
|
38
|
+
}
|
|
39
|
+
if (hasEdge.get(current.record_id, previous.record_id))
|
|
40
|
+
continue;
|
|
41
|
+
const link = {
|
|
42
|
+
relation: 'builds_on',
|
|
43
|
+
target: { kind: 'memory', id: previous.record_id },
|
|
44
|
+
};
|
|
45
|
+
const id = (0, judgment_edge_js_1.judgmentEdgeId)(`migration:099:${commitmentId}:${current.revision}`, 0, link.relation, link.target);
|
|
46
|
+
insertEdge.run(id, current.record_id, previous.record_id, current.agent_id, current.model_run_id, (0, judgment_edge_js_1.judgmentEdgeContentHash)(id, current.record_id, link), current.created_at);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=commitment-revision-migration.js.map
|
|
@@ -102,8 +102,6 @@ export interface WorkCommand {
|
|
|
102
102
|
commandId: string;
|
|
103
103
|
/** Native run that authored this work, when it was written during a model turn. */
|
|
104
104
|
modelRunId?: string | null;
|
|
105
|
-
/** What this commitment is about; becomes the record topic. */
|
|
106
|
-
topic: string;
|
|
107
105
|
/** What the caller is committing to, in its own words. */
|
|
108
106
|
summary: string;
|
|
109
107
|
reasoning?: string;
|
|
@@ -131,6 +129,8 @@ export interface WorkCommand {
|
|
|
131
129
|
event?: JudgmentEventMeta;
|
|
132
130
|
}
|
|
133
131
|
export interface CreateWorkCommand extends WorkCommand {
|
|
132
|
+
/** What this new commitment is about; becomes the record topic. */
|
|
133
|
+
topic: string;
|
|
134
134
|
set: OwnerWorkPatch;
|
|
135
135
|
/**
|
|
136
136
|
* Import vocabulary: the identity this work already had in a predecessor
|
|
@@ -147,12 +147,16 @@ export interface CreateWorkCommand extends WorkCommand {
|
|
|
147
147
|
}
|
|
148
148
|
export interface ReviseWorkCommand extends WorkCommand {
|
|
149
149
|
commitmentId: string;
|
|
150
|
+
/** The revision record's topic; the work item's topic when omitted. */
|
|
151
|
+
topic?: string;
|
|
150
152
|
expectedRevision?: number;
|
|
151
153
|
set?: OwnerWorkPatch;
|
|
152
154
|
clear?: Array<keyof OwnerWorkPatch>;
|
|
153
155
|
}
|
|
154
156
|
export interface WithdrawWorkCommand extends WorkCommand {
|
|
155
157
|
commitmentId: string;
|
|
158
|
+
/** The withdrawal record's topic; the work item's topic when omitted. */
|
|
159
|
+
topic?: string;
|
|
156
160
|
expectedRevision: number;
|
|
157
161
|
}
|
|
158
162
|
export interface WorkWriteResult {
|
|
@@ -331,8 +331,9 @@ async function reviseWork(command, access, options) {
|
|
|
331
331
|
if (readWork(options.adapter, { commitmentId: command.commitmentId }, access).items.length === 0) {
|
|
332
332
|
throw new judgments_js_1.JudgmentError('REFERENCE_NOT_FOUND', `Commitment is unavailable: ${command.commitmentId}`);
|
|
333
333
|
}
|
|
334
|
+
const topic = command.topic ?? workTopic(options.adapter, command.commitmentId);
|
|
334
335
|
const receipt = await (0, judgments_js_1.appendJudgment)({
|
|
335
|
-
...recordFields(command),
|
|
336
|
+
...recordFields({ ...command, topic }),
|
|
336
337
|
work: {
|
|
337
338
|
operation: 'revise',
|
|
338
339
|
commitmentId: command.commitmentId,
|
|
@@ -357,8 +358,9 @@ async function withdrawWork(command, access, options) {
|
|
|
357
358
|
if (readWork(options.adapter, { commitmentId: command.commitmentId }, access).items.length === 0) {
|
|
358
359
|
throw new judgments_js_1.JudgmentError('REFERENCE_NOT_FOUND', `Commitment is unavailable: ${command.commitmentId}`);
|
|
359
360
|
}
|
|
361
|
+
const topic = command.topic ?? workTopic(options.adapter, command.commitmentId);
|
|
360
362
|
const receipt = await (0, judgments_js_1.appendJudgment)({
|
|
361
|
-
...recordFields(command),
|
|
363
|
+
...recordFields({ ...command, topic }),
|
|
362
364
|
work: {
|
|
363
365
|
operation: 'withdraw',
|
|
364
366
|
commitmentId: command.commitmentId,
|
|
@@ -367,4 +369,18 @@ async function withdrawWork(command, access, options) {
|
|
|
367
369
|
}, access, options);
|
|
368
370
|
return requireWorkReceipt(receipt);
|
|
369
371
|
}
|
|
372
|
+
function workTopic(adapter, commitmentId) {
|
|
373
|
+
const row = adapter
|
|
374
|
+
.prepare(`SELECT decision.topic
|
|
375
|
+
FROM commitment_assignments AS assignment
|
|
376
|
+
JOIN decisions AS decision ON decision.id = assignment.record_id
|
|
377
|
+
WHERE assignment.commitment_id = ? AND assignment.operation = 'create'
|
|
378
|
+
ORDER BY assignment.revision
|
|
379
|
+
LIMIT 1`)
|
|
380
|
+
.get(commitmentId);
|
|
381
|
+
if (!row) {
|
|
382
|
+
throw new judgments_js_1.JudgmentError('REFERENCE_NOT_FOUND', `Commitment is unavailable: ${commitmentId}`);
|
|
383
|
+
}
|
|
384
|
+
return row.topic;
|
|
385
|
+
}
|
|
370
386
|
//# sourceMappingURL=commitments.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RecordLink, WorkReference } from '../memory/judgment-types.js';
|
|
2
|
+
/** The stable id of the index-th link a judgment command writes. */
|
|
3
|
+
export declare function judgmentEdgeId(commandId: string, index: number, relation: string, target: WorkReference): string;
|
|
4
|
+
/** The content hash stored on a judgment link's twin edge. */
|
|
5
|
+
export declare function judgmentEdgeContentHash(id: string, recordId: string, link: RecordLink): Buffer;
|
|
6
|
+
//# sourceMappingURL=judgment-edge.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.judgmentEdgeId = judgmentEdgeId;
|
|
7
|
+
exports.judgmentEdgeContentHash = judgmentEdgeContentHash;
|
|
8
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
9
|
+
const canonicalize_js_1 = require("../canonicalize.js");
|
|
10
|
+
/** The stable id of the index-th link a judgment command writes. */
|
|
11
|
+
function judgmentEdgeId(commandId, index, relation, target) {
|
|
12
|
+
return `edge_${node_crypto_1.default
|
|
13
|
+
.createHash('sha256')
|
|
14
|
+
.update((0, canonicalize_js_1.canonicalizeJSON)({ commandId, index, relation, target }))
|
|
15
|
+
.digest('hex')
|
|
16
|
+
.slice(0, 24)}`;
|
|
17
|
+
}
|
|
18
|
+
/** The content hash stored on a judgment link's twin edge. */
|
|
19
|
+
function judgmentEdgeContentHash(id, recordId, link) {
|
|
20
|
+
return node_crypto_1.default.createHash('sha256').update((0, canonicalize_js_1.canonicalizeJSON)({ id, recordId, link })).digest();
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=judgment-edge.js.map
|
|
@@ -16,6 +16,7 @@ exports.listTwinEdgesForRefs = listTwinEdgesForRefs;
|
|
|
16
16
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
17
17
|
const db_manager_js_1 = require("../db-manager.js");
|
|
18
18
|
const canonicalize_js_1 = require("../canonicalize.js");
|
|
19
|
+
const judgment_edge_js_1 = require("./judgment-edge.js");
|
|
19
20
|
const twin_edge_types_js_1 = require("./twin-edge-types.js");
|
|
20
21
|
const event_store_js_1 = require("../memory/event-store.js");
|
|
21
22
|
const record_identity_js_1 = require("../registry/record-identity.js");
|
|
@@ -323,20 +324,10 @@ function assertReplay(adapter, command, access, hash) {
|
|
|
323
324
|
}
|
|
324
325
|
return parseReceipt(row.receipt_json);
|
|
325
326
|
}
|
|
326
|
-
function edgeId(commandId, index, relation, target) {
|
|
327
|
-
return `edge_${node_crypto_1.default
|
|
328
|
-
.createHash('sha256')
|
|
329
|
-
.update((0, canonicalize_js_1.canonicalizeJSON)({ commandId, index, relation, target }))
|
|
330
|
-
.digest('hex')
|
|
331
|
-
.slice(0, 24)}`;
|
|
332
|
-
}
|
|
333
327
|
function insertLink(adapter, command, recordId, link, index, access, now) {
|
|
334
|
-
const id =
|
|
328
|
+
const id = (0, judgment_edge_js_1.judgmentEdgeId)(command.commandId, index, link.relation, link.target);
|
|
335
329
|
const attrs = link.attrs ?? {};
|
|
336
|
-
const contentHash =
|
|
337
|
-
.createHash('sha256')
|
|
338
|
-
.update((0, canonicalize_js_1.canonicalizeJSON)({ id, recordId, link }))
|
|
339
|
-
.digest();
|
|
330
|
+
const contentHash = (0, judgment_edge_js_1.judgmentEdgeContentHash)(id, recordId, link);
|
|
340
331
|
insertTwinEdge(adapter, {
|
|
341
332
|
edge_id: id,
|
|
342
333
|
edge_type: link.relation,
|
|
@@ -537,7 +528,7 @@ async function appendJudgmentOnAdapter(adapter, command, access, embedder) {
|
|
|
537
528
|
}
|
|
538
529
|
else {
|
|
539
530
|
const current = adapter
|
|
540
|
-
.prepare('SELECT current_revision, withdrawn FROM commitments WHERE commitment_id = ?')
|
|
531
|
+
.prepare('SELECT current_revision, head_record_id, withdrawn FROM commitments WHERE commitment_id = ?')
|
|
541
532
|
.get(work.commitmentId);
|
|
542
533
|
if (!current) {
|
|
543
534
|
throw new JudgmentError('REFERENCE_NOT_FOUND', `Commitment is unavailable: ${work.commitmentId}`);
|
|
@@ -556,6 +547,9 @@ async function appendJudgmentOnAdapter(adapter, command, access, embedder) {
|
|
|
556
547
|
(commitment_id, revision, record_id, operation, set_json, clear_json, applies_from, applies_until, created_at, agent_id, model_run_id)
|
|
557
548
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
558
549
|
.run(work.commitmentId, revision, recordId, work.operation, (0, canonicalize_js_1.canonicalizeJSON)(workPatch(work)), (0, canonicalize_js_1.canonicalizeJSON)(work.clear ?? []), command.eventDatetime ?? null, command.appliesUntil ?? null, domainNow, access.agentId, command.modelRunId ?? null);
|
|
550
|
+
edgeIds.push(insertLink(adapter, command, recordId, { relation: 'builds_on', target: { kind: 'memory', id: current.head_record_id } }, command.links?.length ?? 0,
|
|
551
|
+
// The host links a revision to the record it revises; the agent did not judge it.
|
|
552
|
+
{ ...access, edgeSource: 'code' }, now));
|
|
559
553
|
adapter
|
|
560
554
|
.prepare('UPDATE commitments SET current_revision = ?, head_record_id = ?, withdrawn = ?, updated_at = ?, agent_id = ?, model_run_id = ? WHERE commitment_id = ?')
|
|
561
555
|
.run(revision, recordId, work.operation === 'withdraw' ? 1 : 0, domainNow, access.agentId, command.modelRunId ?? null, work.commitmentId);
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* - ⚠️ Tool integration via MCP (future work)
|
|
22
22
|
*/
|
|
23
23
|
import type { PromptCallbacks, PromptResult } from './types.js';
|
|
24
|
+
import { type ThinkingEffort } from './claude-effort.js';
|
|
24
25
|
export interface ClaudeCLIWrapperOptions {
|
|
25
26
|
/** The isolated workspace this CLI runs in; the product states where. */
|
|
26
27
|
/**
|
|
@@ -29,12 +30,8 @@ export interface ClaudeCLIWrapperOptions {
|
|
|
29
30
|
*/
|
|
30
31
|
workspaceDir: string;
|
|
31
32
|
model?: string;
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
* Applies to claude-opus-4-6 and claude-sonnet-4-6
|
|
35
|
-
* 'max' is only available on Opus 4.6
|
|
36
|
-
*/
|
|
37
|
-
effort?: 'low' | 'medium' | 'high' | 'max';
|
|
33
|
+
/** Thinking effort passed as --effort on models that accept it. */
|
|
34
|
+
effort?: ThinkingEffort;
|
|
38
35
|
sessionId?: string;
|
|
39
36
|
systemPrompt?: string;
|
|
40
37
|
mcpConfigPath?: string;
|
|
@@ -66,21 +66,9 @@ const path_1 = __importDefault(require("path"));
|
|
|
66
66
|
const debugLogger = __importStar(require("@jungjaehoon/mama-core/debug-logger"));
|
|
67
67
|
const cli_secret_redaction_js_1 = require("./cli-secret-redaction.js");
|
|
68
68
|
const cli_arg_redaction_js_1 = require("./cli-arg-redaction.js");
|
|
69
|
+
const claude_effort_js_1 = require("./claude-effort.js");
|
|
69
70
|
const { DebugLogger } = debugLogger;
|
|
70
71
|
const logger = new DebugLogger('ClaudeCLI');
|
|
71
|
-
function supportsThinkingEffortModel(model) {
|
|
72
|
-
if (!model) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
// Adaptive thinking effort: Claude 4.6 and every Claude 5 family model accept --effort.
|
|
76
|
-
return /^claude-(opus|sonnet|haiku|fable)-(4-6|5)(\b|-)/.test(model);
|
|
77
|
-
}
|
|
78
|
-
function normalizeThinkingEffort(model, effort) {
|
|
79
|
-
if (effort === 'max' && !(model && /^claude-(opus-4-6|opus-5|fable-5)(\b|-)/.test(model))) {
|
|
80
|
-
return 'high';
|
|
81
|
-
}
|
|
82
|
-
return effort;
|
|
83
|
-
}
|
|
84
72
|
/**
|
|
85
73
|
* ClaudeCLIWrapper - Wraps Claude CLI for programmatic use
|
|
86
74
|
*
|
|
@@ -144,12 +132,7 @@ class ClaudeCLIWrapper {
|
|
|
144
132
|
if (model) {
|
|
145
133
|
args.push('--model', model);
|
|
146
134
|
}
|
|
147
|
-
|
|
148
|
-
if (this.options.effort && supportsThinkingEffortModel(model)) {
|
|
149
|
-
const effort = normalizeThinkingEffort(model, this.options.effort);
|
|
150
|
-
args.push('--effort', effort);
|
|
151
|
-
logger.debug('Effort level:', effort);
|
|
152
|
-
}
|
|
135
|
+
args.push(...(0, claude_effort_js_1.claudeEffortArgs)(model, this.options.effort));
|
|
153
136
|
// System prompt: first turn only (session persistence keeps it across turns)
|
|
154
137
|
if (this.options.systemPrompt && this.turnCount === 0) {
|
|
155
138
|
args.push('--system-prompt', this.options.systemPrompt);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type ThinkingEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
2
|
+
/** The `--effort` arguments for a Claude model; none when the model takes no effort setting. */
|
|
3
|
+
export declare function claudeEffortArgs(model: string | undefined, effort: ThinkingEffort | undefined): string[];
|
|
4
|
+
//# sourceMappingURL=claude-effort.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.claudeEffortArgs = claudeEffortArgs;
|
|
4
|
+
/** The `--effort` arguments for a Claude model; none when the model takes no effort setting. */
|
|
5
|
+
function claudeEffortArgs(model, effort) {
|
|
6
|
+
// --effort: Opus/Sonnet 4.6, Opus 4.7/4.8, and the Claude 5 family (Opus, Sonnet, Fable, Mythos).
|
|
7
|
+
if (!model ||
|
|
8
|
+
!effort ||
|
|
9
|
+
!/^claude-(?:(?:opus|sonnet)-4-6|opus-4-[78]|(?:opus|sonnet|fable|mythos)-5)(?:\b|-)/.test(model)) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
// xhigh arrived with Opus 4.7; the 4.6 models take low through max.
|
|
13
|
+
const accepted = effort === 'xhigh' && /^claude-(?:opus|sonnet)-4-6(?:\b|-)/.test(model) ? 'high' : effort;
|
|
14
|
+
return ['--effort', accepted];
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=claude-effort.js.map
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
import { EventEmitter } from 'events';
|
|
27
27
|
import { type SessionPolicyStatus } from './types.js';
|
|
28
28
|
import { type PromptCallbacks, type PromptResult, type TokenUsageRecord } from './types.js';
|
|
29
|
+
import { type ThinkingEffort } from './claude-effort.js';
|
|
29
30
|
export interface PersistentProcessOptions {
|
|
30
31
|
sessionId: string;
|
|
31
32
|
/**
|
|
@@ -93,8 +94,8 @@ export interface PersistentProcessOptions {
|
|
|
93
94
|
channelKey?: string;
|
|
94
95
|
/** Agent ID for token usage tracking */
|
|
95
96
|
agentId?: string;
|
|
96
|
-
/**
|
|
97
|
-
effort?:
|
|
97
|
+
/** Thinking effort passed as --effort on models that accept it. */
|
|
98
|
+
effort?: ThinkingEffort;
|
|
98
99
|
}
|
|
99
100
|
export interface PersistentProcessAcquireResult {
|
|
100
101
|
process: PersistentClaudeProcess;
|
|
@@ -69,22 +69,10 @@ const types_js_1 = require("./types.js");
|
|
|
69
69
|
const debugLogger = __importStar(require("@jungjaehoon/mama-core/debug-logger"));
|
|
70
70
|
const cli_secret_redaction_js_1 = require("./cli-secret-redaction.js");
|
|
71
71
|
const cli_arg_redaction_js_1 = require("./cli-arg-redaction.js");
|
|
72
|
+
const claude_effort_js_1 = require("./claude-effort.js");
|
|
72
73
|
const { DebugLogger } = debugLogger;
|
|
73
74
|
const persistentLogger = new DebugLogger('PersistentCLI');
|
|
74
75
|
const poolLogger = new DebugLogger('ProcessPool');
|
|
75
|
-
function supportsThinkingEffortModel(model) {
|
|
76
|
-
if (!model) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
// Adaptive thinking effort: Claude 4.6 and every Claude 5 family model accept --effort.
|
|
80
|
-
return /^claude-(opus|sonnet|haiku|fable)-(4-6|5)(\b|-)/.test(model);
|
|
81
|
-
}
|
|
82
|
-
function normalizeThinkingEffort(model, effort) {
|
|
83
|
-
if (effort === 'max' && !(model && /^claude-(opus-4-6|opus-5|fable-5)(\b|-)/.test(model))) {
|
|
84
|
-
return 'high';
|
|
85
|
-
}
|
|
86
|
-
return effort;
|
|
87
|
-
}
|
|
88
76
|
/**
|
|
89
77
|
* Regex to strip lone Unicode surrogates that cause API 400 errors.
|
|
90
78
|
* Matches high surrogates not followed by a low surrogate, and
|
|
@@ -351,9 +339,7 @@ class PersistentClaudeProcess extends events_1.EventEmitter {
|
|
|
351
339
|
if (this.options.useGatewayTools) {
|
|
352
340
|
persistentLogger.info('Gateway Tools mode enabled');
|
|
353
341
|
}
|
|
354
|
-
|
|
355
|
-
args.push('--effort', normalizeThinkingEffort(this.options.model, this.options.effort));
|
|
356
|
-
}
|
|
342
|
+
args.push(...(0, claude_effort_js_1.claudeEffortArgs)(this.options.model, this.options.effort));
|
|
357
343
|
if (this.options.permissionMode) {
|
|
358
344
|
args.push('--permission-mode', this.options.permissionMode);
|
|
359
345
|
}
|