@crediolabs/policy-synth 0.1.3 → 0.1.5
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/LICENSE +21 -0
- package/README.md +193 -5
- package/dist/adapters/interpreter/adapter.d.ts +38 -0
- package/dist/adapters/interpreter/adapter.js +522 -0
- package/dist/adapters/interpreter/index.d.ts +1 -0
- package/dist/adapters/interpreter/index.js +2 -0
- package/dist/adapters/oz/adapter.js +2 -0
- package/dist/codegen/compile-gate.d.ts +33 -0
- package/dist/codegen/compile-gate.js +119 -0
- package/dist/codegen/index.d.ts +2 -0
- package/dist/codegen/index.js +8 -0
- package/dist/codegen/template.d.ts +18 -0
- package/dist/codegen/template.js +131 -0
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/ir/types.d.ts +13 -2
- package/dist/predicate/encode.d.ts +10 -0
- package/dist/predicate/encode.js +249 -0
- package/dist/predicate/index.d.ts +1 -0
- package/dist/predicate/index.js +2 -0
- package/dist/record/decode.d.ts +6 -3
- package/dist/record/decode.js +13 -3
- package/dist/review-card/builder.d.ts +14 -0
- package/dist/review-card/builder.js +261 -0
- package/dist/review-card/conflict.d.ts +40 -0
- package/dist/review-card/conflict.js +111 -0
- package/dist/review-card/cross-check.d.ts +11 -0
- package/dist/review-card/cross-check.js +148 -0
- package/dist/review-card/index.d.ts +3 -0
- package/dist/review-card/index.js +4 -0
- package/dist/run/index.d.ts +31 -0
- package/dist/run/index.js +164 -0
- package/dist/run/schemas.d.ts +2003 -0
- package/dist/run/schemas.js +215 -0
- package/dist/synth/compose-from-recording.d.ts +35 -7
- package/dist/synth/compose-from-recording.js +225 -34
- package/dist/synth/deny-cases.d.ts +12 -0
- package/dist/synth/deny-cases.js +377 -0
- package/dist/synth/evaluate.d.ts +39 -0
- package/dist/synth/evaluate.js +425 -0
- package/dist/synth/harness.d.ts +16 -0
- package/dist/synth/harness.js +26 -0
- package/dist/synth/index.d.ts +4 -0
- package/dist/synth/index.js +4 -0
- package/dist/synth/minimize.d.ts +4 -0
- package/dist/synth/minimize.js +38 -0
- package/dist/synth/predicate-literals.d.ts +5 -0
- package/dist/synth/predicate-literals.js +25 -0
- package/dist/synth/synthesize-from-recording.d.ts +37 -5
- package/dist/synth/synthesize-from-recording.js +550 -18
- package/dist/types.d.ts +40 -1
- package/dist/types.js +17 -0
- package/dist/verify/envelope.d.ts +15 -0
- package/dist/verify/envelope.js +22 -0
- package/dist/verify/index.d.ts +3 -0
- package/dist/verify/index.js +3 -0
- package/dist/verify/simulate.d.ts +31 -0
- package/dist/verify/simulate.js +258 -0
- package/dist/verify/verify.d.ts +21 -0
- package/dist/verify/verify.js +189 -0
- package/dist-cjs/adapters/interpreter/adapter.d.ts +38 -0
- package/dist-cjs/adapters/interpreter/adapter.js +527 -0
- package/dist-cjs/adapters/interpreter/index.d.ts +1 -0
- package/dist-cjs/adapters/interpreter/index.js +8 -0
- package/dist-cjs/adapters/oz/adapter.d.ts +20 -0
- package/dist-cjs/adapters/oz/adapter.js +289 -0
- package/dist-cjs/adapters/oz/index.d.ts +1 -0
- package/dist-cjs/adapters/oz/index.js +8 -0
- package/dist-cjs/codegen/compile-gate.d.ts +33 -0
- package/dist-cjs/codegen/compile-gate.js +123 -0
- package/dist-cjs/codegen/index.d.ts +2 -0
- package/dist-cjs/codegen/index.js +14 -0
- package/dist-cjs/codegen/template.d.ts +18 -0
- package/dist-cjs/codegen/template.js +134 -0
- package/dist-cjs/errors.d.ts +37 -0
- package/dist-cjs/errors.js +3 -0
- package/dist-cjs/index.d.ts +11 -0
- package/dist-cjs/index.js +27 -0
- package/dist-cjs/ir/index.d.ts +1 -0
- package/dist-cjs/ir/index.js +3 -0
- package/dist-cjs/ir/types.d.ts +108 -0
- package/dist-cjs/ir/types.js +12 -0
- package/dist-cjs/mandate/index.d.ts +2 -0
- package/dist-cjs/mandate/index.js +6 -0
- package/dist-cjs/mandate/to-ir.d.ts +3 -0
- package/dist-cjs/mandate/to-ir.js +63 -0
- package/dist-cjs/mandate/types.d.ts +20 -0
- package/dist-cjs/mandate/types.js +9 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/predicate/encode.d.ts +10 -0
- package/dist-cjs/predicate/encode.js +252 -0
- package/dist-cjs/predicate/index.d.ts +1 -0
- package/dist-cjs/predicate/index.js +6 -0
- package/dist-cjs/record/decode.d.ts +79 -0
- package/dist-cjs/record/decode.js +398 -0
- package/dist-cjs/record/freshness.d.ts +17 -0
- package/dist-cjs/record/freshness.js +55 -0
- package/dist-cjs/record/index.d.ts +21 -0
- package/dist-cjs/record/index.js +166 -0
- package/dist-cjs/record/movements.d.ts +20 -0
- package/dist-cjs/record/movements.js +192 -0
- package/dist-cjs/record/rpc.d.ts +22 -0
- package/dist-cjs/record/rpc.js +74 -0
- package/dist-cjs/record/validate.d.ts +22 -0
- package/dist-cjs/record/validate.js +63 -0
- package/dist-cjs/registry/identify.d.ts +11 -0
- package/dist-cjs/registry/identify.js +87 -0
- package/dist-cjs/registry/index.d.ts +3 -0
- package/dist-cjs/registry/index.js +15 -0
- package/dist-cjs/registry/known-addresses.d.ts +16 -0
- package/dist-cjs/registry/known-addresses.js +53 -0
- package/dist-cjs/registry/protocols.d.ts +38 -0
- package/dist-cjs/registry/protocols.js +153 -0
- package/dist-cjs/review-card/builder.d.ts +14 -0
- package/dist-cjs/review-card/builder.js +264 -0
- package/dist-cjs/review-card/conflict.d.ts +40 -0
- package/dist-cjs/review-card/conflict.js +114 -0
- package/dist-cjs/review-card/cross-check.d.ts +11 -0
- package/dist-cjs/review-card/cross-check.js +151 -0
- package/dist-cjs/review-card/index.d.ts +3 -0
- package/dist-cjs/review-card/index.js +10 -0
- package/dist-cjs/run/index.d.ts +31 -0
- package/dist-cjs/run/index.js +178 -0
- package/dist-cjs/run/schemas.d.ts +2003 -0
- package/dist-cjs/run/schemas.js +218 -0
- package/dist-cjs/seams/index.d.ts +1 -0
- package/dist-cjs/seams/index.js +3 -0
- package/dist-cjs/seams/types.d.ts +66 -0
- package/dist-cjs/seams/types.js +12 -0
- package/dist-cjs/synth/compose-from-recording.d.ts +64 -0
- package/dist-cjs/synth/compose-from-recording.js +356 -0
- package/dist-cjs/synth/deny-cases.d.ts +12 -0
- package/dist-cjs/synth/deny-cases.js +380 -0
- package/dist-cjs/synth/evaluate.d.ts +39 -0
- package/dist-cjs/synth/evaluate.js +428 -0
- package/dist-cjs/synth/harness.d.ts +16 -0
- package/dist-cjs/synth/harness.js +29 -0
- package/dist-cjs/synth/index.d.ts +9 -0
- package/dist-cjs/synth/index.js +23 -0
- package/dist-cjs/synth/lower.d.ts +23 -0
- package/dist-cjs/synth/lower.js +119 -0
- package/dist-cjs/synth/minimize.d.ts +4 -0
- package/dist-cjs/synth/minimize.js +41 -0
- package/dist-cjs/synth/predicate-literals.d.ts +5 -0
- package/dist-cjs/synth/predicate-literals.js +28 -0
- package/dist-cjs/synth/scope.d.ts +26 -0
- package/dist-cjs/synth/scope.js +81 -0
- package/dist-cjs/synth/synthesize-from-mandate.d.ts +5 -0
- package/dist-cjs/synth/synthesize-from-mandate.js +37 -0
- package/dist-cjs/synth/synthesize-from-recording.d.ts +49 -0
- package/dist-cjs/synth/synthesize-from-recording.js +711 -0
- package/dist-cjs/types.d.ts +288 -0
- package/dist-cjs/types.js +55 -0
- package/dist-cjs/verify/envelope.d.ts +15 -0
- package/dist-cjs/verify/envelope.js +23 -0
- package/dist-cjs/verify/index.d.ts +3 -0
- package/dist-cjs/verify/index.js +8 -0
- package/dist-cjs/verify/simulate.d.ts +31 -0
- package/dist-cjs/verify/simulate.js +261 -0
- package/dist-cjs/verify/verify.d.ts +21 -0
- package/dist-cjs/verify/verify.js +192 -0
- package/package.json +43 -3
- package/src/adapters/interpreter/adapter.ts +642 -0
- package/src/adapters/interpreter/index.ts +8 -0
- package/src/adapters/oz/adapter.ts +2 -0
- package/src/codegen/compile-gate.ts +162 -0
- package/src/codegen/index.ts +17 -0
- package/src/codegen/template.ts +148 -0
- package/src/errors.ts +2 -0
- package/src/index.ts +2 -0
- package/src/ir/types.ts +9 -2
- package/src/predicate/encode.ts +307 -0
- package/src/predicate/index.ts +3 -0
- package/src/record/decode.ts +21 -10
- package/src/review-card/builder.ts +303 -0
- package/src/review-card/conflict.ts +143 -0
- package/src/review-card/cross-check.ts +158 -0
- package/src/review-card/index.ts +12 -0
- package/src/run/index.ts +213 -0
- package/src/run/schemas.ts +242 -0
- package/src/synth/compose-from-recording.ts +277 -43
- package/src/synth/deny-cases.ts +466 -0
- package/src/synth/evaluate.ts +493 -0
- package/src/synth/harness.ts +40 -0
- package/src/synth/index.ts +12 -0
- package/src/synth/minimize.ts +44 -0
- package/src/synth/predicate-literals.ts +27 -0
- package/src/synth/synthesize-from-recording.ts +655 -19
- package/src/types.ts +38 -2
- package/src/verify/envelope.ts +28 -0
- package/src/verify/index.ts +5 -0
- package/src/verify/simulate.ts +311 -0
- package/src/verify/verify.ts +243 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/review-card/cross-check.ts - the non-hallucination guard.
|
|
3
|
+
//
|
|
4
|
+
// `summaryCrossCheck` walks EVERY leaf of the predicate and asserts the
|
|
5
|
+
// review-card summary quoted a constraint string for it. Returns
|
|
6
|
+
// `{ ok: false, missingConstraints }` if any leaf was dropped (or rendered
|
|
7
|
+
// into a template shape the cross-check does not recognise). A
|
|
8
|
+
// `PredicateNode = null` is always ok - the policy is OZ-only and the
|
|
9
|
+
// interpreter predicate did not exist.
|
|
10
|
+
//
|
|
11
|
+
// The guard is structural: every leaf the builder is supposed to render has
|
|
12
|
+
// exactly one template shape. The cross-check enumerates those shapes and
|
|
13
|
+
// demands the summary carries the corresponding string. A naive summary
|
|
14
|
+
// that drops a leaf (or fabricates a string not in the predicate) trips the
|
|
15
|
+
// guard.
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.summaryCrossCheck = summaryCrossCheck;
|
|
18
|
+
/** Assert every leaf in the predicate appears as a constraint string in
|
|
19
|
+
* `summary.constraints`. Returns the missing templates (without the leaf
|
|
20
|
+
* values filled in) when any leaf was dropped. */
|
|
21
|
+
function summaryCrossCheck(predicate, summary) {
|
|
22
|
+
if (predicate === null)
|
|
23
|
+
return { ok: true };
|
|
24
|
+
const expected = [];
|
|
25
|
+
collect(predicate, expected);
|
|
26
|
+
if (expected.length === 0)
|
|
27
|
+
return { ok: true };
|
|
28
|
+
const present = new Set(summary.constraints);
|
|
29
|
+
const missing = expected.filter((s) => !present.has(s));
|
|
30
|
+
if (missing.length === 0)
|
|
31
|
+
return { ok: true };
|
|
32
|
+
return { ok: false, missingConstraints: missing };
|
|
33
|
+
}
|
|
34
|
+
/** Walk the predicate and emit the EXACT constraint string the builder is
|
|
35
|
+
* expected to produce for each leaf, in walk order. Strings here MUST
|
|
36
|
+
* match the templates in `builder.ts` byte-for-byte; the cross-check is
|
|
37
|
+
* the structural claim that "every supported leaf shape is rendered". */
|
|
38
|
+
function collect(node, out) {
|
|
39
|
+
switch (node.op) {
|
|
40
|
+
case 'and':
|
|
41
|
+
case 'or':
|
|
42
|
+
for (const child of node.children)
|
|
43
|
+
collect(child, out);
|
|
44
|
+
return;
|
|
45
|
+
case 'not':
|
|
46
|
+
collect(node.child, out);
|
|
47
|
+
return;
|
|
48
|
+
case 'eq':
|
|
49
|
+
case 'lt':
|
|
50
|
+
case 'lte':
|
|
51
|
+
case 'gt':
|
|
52
|
+
case 'gte':
|
|
53
|
+
pushComparison(node.left, node.right, node.op, out);
|
|
54
|
+
return;
|
|
55
|
+
case 'in':
|
|
56
|
+
pushMembership(node.needle, node.haystack, out);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function pushComparison(left, right, op, out) {
|
|
61
|
+
if (left.kind === 'call_contract' && op === 'eq' && right.kind === 'literal_address') {
|
|
62
|
+
out.push(`Contract must be ${right.value}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (left.kind === 'call_fn' && op === 'eq' && right.kind === 'literal_symbol') {
|
|
66
|
+
out.push(`Function must be ${right.value}`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (left.kind === 'call_arg' && op === 'eq' && right.kind === 'literal_vec') {
|
|
70
|
+
out.push(`Path must be exactly [${right.elements.map(renderVecElement).join(', ')}]`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (left.kind === 'invocation_count_in_window' && right.kind === 'literal_u32') {
|
|
74
|
+
out.push(`Invocations <= ${right.value} per ${left.windowSecs} seconds`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (left.kind === 'amount' && right.kind === 'literal_i128') {
|
|
78
|
+
out.push(`Amount <= ${right.value}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (left.kind === 'oracle_price' && right.kind === 'literal_i128') {
|
|
82
|
+
out.push(`Only when oracle_price(${left.asset}) ${comparisonOpText(op)} ${right.value}`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function pushMembership(needle, haystack, out) {
|
|
87
|
+
if (needle.kind !== 'call_arg')
|
|
88
|
+
return;
|
|
89
|
+
const list = haystack.map(renderHaystackElement).join(', ');
|
|
90
|
+
out.push(`Recipient/arg must be one of [${list}]`);
|
|
91
|
+
}
|
|
92
|
+
function renderVecElement(leaf) {
|
|
93
|
+
switch (leaf.kind) {
|
|
94
|
+
case 'literal_address':
|
|
95
|
+
return leaf.value;
|
|
96
|
+
case 'literal_i128':
|
|
97
|
+
return leaf.value;
|
|
98
|
+
case 'literal_symbol':
|
|
99
|
+
return leaf.value;
|
|
100
|
+
case 'literal_u32':
|
|
101
|
+
return String(leaf.value);
|
|
102
|
+
case 'literal_u64':
|
|
103
|
+
return leaf.value;
|
|
104
|
+
case 'literal_bytes':
|
|
105
|
+
return leaf.value;
|
|
106
|
+
case 'literal_vec':
|
|
107
|
+
return `[${leaf.elements.map(renderVecElement).join(', ')}]`;
|
|
108
|
+
case 'call_contract':
|
|
109
|
+
case 'call_fn':
|
|
110
|
+
case 'call_arg':
|
|
111
|
+
case 'amount':
|
|
112
|
+
case 'window_spent':
|
|
113
|
+
case 'now':
|
|
114
|
+
case 'valid_until':
|
|
115
|
+
case 'invocation_count_in_window':
|
|
116
|
+
case 'oracle_price':
|
|
117
|
+
return `<${leaf.kind}>`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function renderHaystackElement(leaf) {
|
|
121
|
+
if (leaf.kind === 'literal_address')
|
|
122
|
+
return leaf.value;
|
|
123
|
+
if (leaf.kind === 'literal_i128')
|
|
124
|
+
return leaf.value;
|
|
125
|
+
if (leaf.kind === 'literal_symbol')
|
|
126
|
+
return leaf.value;
|
|
127
|
+
if (leaf.kind === 'literal_u32')
|
|
128
|
+
return String(leaf.value);
|
|
129
|
+
if (leaf.kind === 'literal_u64')
|
|
130
|
+
return leaf.value;
|
|
131
|
+
if (leaf.kind === 'literal_bytes')
|
|
132
|
+
return leaf.value;
|
|
133
|
+
if (leaf.kind === 'literal_vec') {
|
|
134
|
+
return `[${leaf.elements.map(renderHaystackElement).join(', ')}]`;
|
|
135
|
+
}
|
|
136
|
+
return `<${leaf.kind}>`;
|
|
137
|
+
}
|
|
138
|
+
function comparisonOpText(op) {
|
|
139
|
+
switch (op) {
|
|
140
|
+
case 'lt':
|
|
141
|
+
return '<';
|
|
142
|
+
case 'lte':
|
|
143
|
+
return '<=';
|
|
144
|
+
case 'gt':
|
|
145
|
+
return '>';
|
|
146
|
+
case 'gte':
|
|
147
|
+
return '>=';
|
|
148
|
+
case 'eq':
|
|
149
|
+
return '==';
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/review-card/index.ts - re-export the deterministic review-card surface.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.summaryCrossCheck = exports.classifyConflict = exports.buildReviewCardSummary = void 0;
|
|
5
|
+
var builder_ts_1 = require("./builder.js");
|
|
6
|
+
Object.defineProperty(exports, "buildReviewCardSummary", { enumerable: true, get: function () { return builder_ts_1.buildReviewCardSummary; } });
|
|
7
|
+
var conflict_ts_1 = require("./conflict.js");
|
|
8
|
+
Object.defineProperty(exports, "classifyConflict", { enumerable: true, get: function () { return conflict_ts_1.classifyConflict; } });
|
|
9
|
+
var cross_check_ts_1 = require("./cross-check.js");
|
|
10
|
+
Object.defineProperty(exports, "summaryCrossCheck", { enumerable: true, get: function () { return cross_check_ts_1.summaryCrossCheck; } });
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ProposedPolicy, type RecordedTransaction, type ToolResponse } from '../index.ts';
|
|
2
|
+
import { type RecordTransactionInput, type SynthesizePolicyInput } from './schemas.ts';
|
|
3
|
+
export type { RecordTransactionInput, SynthesizePolicyInput } from './schemas.ts';
|
|
4
|
+
export { ComposeUserResponsesSchema, InterpreterOptionsSchema, MandateSpecSchema, NetworkSchema, OzAdapterConfigSchema, RecordedTransactionSchema, RecordTransactionInputSchema, SynthesizePolicyInputSchema, ToolErrorSchema, } from './schemas.ts';
|
|
5
|
+
export type RunRecordTransactionInput = RecordTransactionInput;
|
|
6
|
+
export type RunSynthesizePolicyInput = SynthesizePolicyInput;
|
|
7
|
+
/** `record_transaction` body - wraps `recordTransaction`. The tool input
|
|
8
|
+
* matches the core RecordInput minus the injected `fetcher` (the transport
|
|
9
|
+
* layer does not own the RPC). Returns the core ToolResponse unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Item 6: a try/catch envelope wraps the core call. The core's own
|
|
12
|
+
* `recordTransaction` already returns `{ok:false, error}` for Zod + decoder
|
|
13
|
+
* failures, but a throw from the SDK (e.g. a malformed hash handed to
|
|
14
|
+
* `@stellar/stellar-sdk`'s StrKey decoder) would otherwise surface as
|
|
15
|
+
* "[object Object]" in the MCP transport. The envelope converts any
|
|
16
|
+
* non-ToolResponse throw into a structured `RECORDING_FAILED` ToolError so
|
|
17
|
+
* the agent always sees a machine-readable error code. */
|
|
18
|
+
export declare function runRecordTransaction(raw: unknown): Promise<ToolResponse<RecordedTransaction>>;
|
|
19
|
+
/** `synthesize_policy` body - discriminated union on `source`:
|
|
20
|
+
* - `mandate` -> synthesizeFromMandate
|
|
21
|
+
* - `recording` -> synthesizeFromRecording
|
|
22
|
+
* Exposing BOTH front-ends through ONE tool keeps the MCP surface tiny while
|
|
23
|
+
* letting the agent pick the deterministic or the inferred path. The CLI
|
|
24
|
+
* routes the same way.
|
|
25
|
+
*
|
|
26
|
+
* Item 6: same try/catch envelope as `runRecordTransaction`. The core
|
|
27
|
+
* `synthesizeFromRecording` already converts ToolError-shaped throws to
|
|
28
|
+
* `{ok:false, error}`, but a raw throw from the SDK (e.g. an unexpected
|
|
29
|
+
* XDR decode error in the adapter) would otherwise surface as
|
|
30
|
+
* "[object Object]" in the MCP transport. */
|
|
31
|
+
export declare function runSynthesizePolicy(raw: unknown): Promise<ToolResponse<ProposedPolicy>>;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// packages/policy-synth/src/run/index.ts
|
|
3
|
+
//
|
|
4
|
+
// Tool-body adapters for the two core front-ends. Reachable as
|
|
5
|
+
// `@crediolabs/policy-synth/run` from both the MCP server (which re-exports
|
|
6
|
+
// for tool-registration glue) and the CLI (which calls them directly). Each
|
|
7
|
+
// body is a THIN adapter over the pure core:
|
|
8
|
+
//
|
|
9
|
+
// 1. Re-validate the parsed input via Zod. This is a defence-in-depth check -
|
|
10
|
+
// the SDK has already parsed it through the registered schema, but we never
|
|
11
|
+
// want a tool body to throw on garbage (the SDK treats uncaught throws as
|
|
12
|
+
// transport errors and the agent loses the machine-readable ToolError).
|
|
13
|
+
// 2. Dispatch to the matching core entry point with the minimum required
|
|
14
|
+
// inputs.
|
|
15
|
+
// 3. Return the core's ToolResponse<T> unchanged. The server layer maps it
|
|
16
|
+
// to the MCP envelope; nothing here knows about MCP.
|
|
17
|
+
//
|
|
18
|
+
// No business logic. No retries. No session state. The same call shape can
|
|
19
|
+
// drive the CLI (which calls into the same core directly without MCP).
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.ToolErrorSchema = exports.SynthesizePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.OzAdapterConfigSchema = exports.NetworkSchema = exports.MandateSpecSchema = exports.InterpreterOptionsSchema = exports.ComposeUserResponsesSchema = void 0;
|
|
22
|
+
exports.runRecordTransaction = runRecordTransaction;
|
|
23
|
+
exports.runSynthesizePolicy = runSynthesizePolicy;
|
|
24
|
+
const index_ts_1 = require("../index.js");
|
|
25
|
+
const schemas_ts_1 = require("./schemas.js");
|
|
26
|
+
// Re-export the underlying Zod schemas so the MCP package (and any other
|
|
27
|
+
// downstream consumer) can import the canonical input shapes from the same
|
|
28
|
+
// module that owns the tool-body glue. The strict schemas are the source of
|
|
29
|
+
// truth - MCP tool shapes are derived from them.
|
|
30
|
+
var schemas_ts_2 = require("./schemas.js");
|
|
31
|
+
Object.defineProperty(exports, "ComposeUserResponsesSchema", { enumerable: true, get: function () { return schemas_ts_2.ComposeUserResponsesSchema; } });
|
|
32
|
+
Object.defineProperty(exports, "InterpreterOptionsSchema", { enumerable: true, get: function () { return schemas_ts_2.InterpreterOptionsSchema; } });
|
|
33
|
+
Object.defineProperty(exports, "MandateSpecSchema", { enumerable: true, get: function () { return schemas_ts_2.MandateSpecSchema; } });
|
|
34
|
+
Object.defineProperty(exports, "NetworkSchema", { enumerable: true, get: function () { return schemas_ts_2.NetworkSchema; } });
|
|
35
|
+
Object.defineProperty(exports, "OzAdapterConfigSchema", { enumerable: true, get: function () { return schemas_ts_2.OzAdapterConfigSchema; } });
|
|
36
|
+
Object.defineProperty(exports, "RecordedTransactionSchema", { enumerable: true, get: function () { return schemas_ts_2.RecordedTransactionSchema; } });
|
|
37
|
+
Object.defineProperty(exports, "RecordTransactionInputSchema", { enumerable: true, get: function () { return schemas_ts_2.RecordTransactionInputSchema; } });
|
|
38
|
+
Object.defineProperty(exports, "SynthesizePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.SynthesizePolicyInputSchema; } });
|
|
39
|
+
Object.defineProperty(exports, "ToolErrorSchema", { enumerable: true, get: function () { return schemas_ts_2.ToolErrorSchema; } });
|
|
40
|
+
/** `record_transaction` body - wraps `recordTransaction`. The tool input
|
|
41
|
+
* matches the core RecordInput minus the injected `fetcher` (the transport
|
|
42
|
+
* layer does not own the RPC). Returns the core ToolResponse unchanged.
|
|
43
|
+
*
|
|
44
|
+
* Item 6: a try/catch envelope wraps the core call. The core's own
|
|
45
|
+
* `recordTransaction` already returns `{ok:false, error}` for Zod + decoder
|
|
46
|
+
* failures, but a throw from the SDK (e.g. a malformed hash handed to
|
|
47
|
+
* `@stellar/stellar-sdk`'s StrKey decoder) would otherwise surface as
|
|
48
|
+
* "[object Object]" in the MCP transport. The envelope converts any
|
|
49
|
+
* non-ToolResponse throw into a structured `RECORDING_FAILED` ToolError so
|
|
50
|
+
* the agent always sees a machine-readable error code. */
|
|
51
|
+
async function runRecordTransaction(raw) {
|
|
52
|
+
const parsed = schemas_ts_1.RecordTransactionInputSchema.safeParse(raw);
|
|
53
|
+
if (!parsed.success) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
error: validationError('record_transaction', parsed.error.issues),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const input = parsed.data;
|
|
60
|
+
// Strip the wire-only `confidenceOverride` and pass the rest straight through.
|
|
61
|
+
const coreInput = {
|
|
62
|
+
network: input.network,
|
|
63
|
+
...(input.hash !== undefined ? { hash: input.hash } : {}),
|
|
64
|
+
...(input.xdr !== undefined ? { xdr: input.xdr } : {}),
|
|
65
|
+
...(input.confidenceOverride !== undefined
|
|
66
|
+
? { confidenceOverride: input.confidenceOverride }
|
|
67
|
+
: {}),
|
|
68
|
+
};
|
|
69
|
+
try {
|
|
70
|
+
return await (0, index_ts_1.recordTransaction)(coreInput);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
error: caughtError('record_transaction', 'RECORDING_FAILED', e),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** `synthesize_policy` body - discriminated union on `source`:
|
|
80
|
+
* - `mandate` -> synthesizeFromMandate
|
|
81
|
+
* - `recording` -> synthesizeFromRecording
|
|
82
|
+
* Exposing BOTH front-ends through ONE tool keeps the MCP surface tiny while
|
|
83
|
+
* letting the agent pick the deterministic or the inferred path. The CLI
|
|
84
|
+
* routes the same way.
|
|
85
|
+
*
|
|
86
|
+
* Item 6: same try/catch envelope as `runRecordTransaction`. The core
|
|
87
|
+
* `synthesizeFromRecording` already converts ToolError-shaped throws to
|
|
88
|
+
* `{ok:false, error}`, but a raw throw from the SDK (e.g. an unexpected
|
|
89
|
+
* XDR decode error in the adapter) would otherwise surface as
|
|
90
|
+
* "[object Object]" in the MCP transport. */
|
|
91
|
+
async function runSynthesizePolicy(raw) {
|
|
92
|
+
const parsed = schemas_ts_1.SynthesizePolicyInputSchema.safeParse(raw);
|
|
93
|
+
if (!parsed.success) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
error: validationError('synthesize_policy', parsed.error.issues),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const input = parsed.data;
|
|
100
|
+
const ozConfig = resolveOzConfig(input);
|
|
101
|
+
try {
|
|
102
|
+
if (input.source === 'mandate') {
|
|
103
|
+
// Zod's optional fields widen to `T | undefined`, which the core's
|
|
104
|
+
// exact-optional MandateSpec rejects; the schema already validated the
|
|
105
|
+
// shape, so assert it (same pattern as the recordedTx cast below).
|
|
106
|
+
return await (0, index_ts_1.synthesizeFromMandate)(input.mandate, ozConfig);
|
|
107
|
+
}
|
|
108
|
+
// recording source
|
|
109
|
+
const recorded = input.recordedTx;
|
|
110
|
+
return await (0, index_ts_1.synthesizeFromRecording)(recorded, {
|
|
111
|
+
network: input.network,
|
|
112
|
+
...(input.userResponses !== undefined ? { userResponses: input.userResponses } : {}),
|
|
113
|
+
...(input.confidenceOverride !== undefined
|
|
114
|
+
? { confidenceOverride: input.confidenceOverride }
|
|
115
|
+
: {}),
|
|
116
|
+
...(input.interpreter !== undefined ? { interpreter: input.interpreter } : {}),
|
|
117
|
+
}, ozConfig);
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
error: caughtError('synthesize_policy', 'SYNTHESIS_ERROR', e),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function resolveOzConfig(input) {
|
|
127
|
+
if (input.ozConfig)
|
|
128
|
+
return input.ozConfig;
|
|
129
|
+
// The mandate path is network-agnostic; fall back to mainnet so the
|
|
130
|
+
// placeholder OZ instance addresses are deterministic.
|
|
131
|
+
return (0, index_ts_1.placeholderOzConfig)('mainnet');
|
|
132
|
+
}
|
|
133
|
+
/** Build a canonical ToolError for a Zod validation failure. The remediation
|
|
134
|
+
* hint points the agent back at the right tool with an empty arg bag - the
|
|
135
|
+
* tool name IS the machine-readable hint. */
|
|
136
|
+
function validationError(toolName, issues) {
|
|
137
|
+
const code = toolName === 'record_transaction' ? 'RECORDING_FAILED' : 'SYNTHESIS_ERROR';
|
|
138
|
+
return {
|
|
139
|
+
code,
|
|
140
|
+
message: `${toolName}: invalid input: ${issues
|
|
141
|
+
.map((i) => `${i.path.join('.') || '<root>'}: ${i.message}`)
|
|
142
|
+
.join('; ')}`,
|
|
143
|
+
severity: 'error',
|
|
144
|
+
retryable: false,
|
|
145
|
+
remediation: {
|
|
146
|
+
toolCall: { name: toolName, args: {} },
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/** Build a canonical ToolError for a thrown exception caught by the tool
|
|
151
|
+
* envelope. We refuse to surface the raw exception's text (the MCP SDK
|
|
152
|
+
* stringifies thrown objects as "[object Object]"), so we extract a
|
|
153
|
+
* string-friendly message and tag the original error in `details` for the
|
|
154
|
+
* agent to inspect. The `code` is the tool's domain code (RECORDING_FAILED
|
|
155
|
+
* for `record_transaction`, SYNTHESIS_ERROR for `synthesize_policy`) so the
|
|
156
|
+
* agent dispatches on the same code the structured ToolError would carry. */
|
|
157
|
+
function caughtError(toolName, code, e) {
|
|
158
|
+
let message;
|
|
159
|
+
if (e instanceof Error) {
|
|
160
|
+
message = e.message || `${toolName}: unknown error`;
|
|
161
|
+
}
|
|
162
|
+
else if (typeof e === 'string') {
|
|
163
|
+
message = e;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
message = `${toolName}: caught non-Error throw of type ${typeof e}`;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
code,
|
|
170
|
+
message: `${toolName}: unhandled throw escaped core envelope: ${message}`,
|
|
171
|
+
severity: 'error',
|
|
172
|
+
retryable: false,
|
|
173
|
+
remediation: {
|
|
174
|
+
toolCall: { name: toolName, args: {} },
|
|
175
|
+
},
|
|
176
|
+
details: { thrown: String(e) },
|
|
177
|
+
};
|
|
178
|
+
}
|