@martinloop/mcp 0.3.6 → 0.3.8
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 +216 -0
- package/README.md +105 -97
- package/dist/discovery-metadata.d.ts +1 -1
- package/dist/discovery-metadata.js +1 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resources.d.ts +2 -1
- package/dist/resources.js +251 -197
- package/dist/server-validation.d.ts +1 -1
- package/dist/server-validation.js +11 -16
- package/dist/server.d.ts +0 -23
- package/dist/server.js +7 -152
- package/dist/tools/preflight.d.ts +2 -0
- package/dist/tools/preflight.js +42 -2
- package/dist/tools/run-loop.d.ts +2 -1
- package/dist/tools/run-loop.js +5 -1
- package/dist/tools/tool-support.js +12 -1
- package/dist/vendor/adapters/adapters/src/claude-cli.d.ts +146 -0
- package/dist/vendor/adapters/adapters/src/claude-cli.js +1100 -0
- package/dist/vendor/adapters/adapters/src/cli-bridge.d.ts +103 -0
- package/dist/vendor/adapters/adapters/src/cli-bridge.js +569 -0
- package/dist/vendor/adapters/adapters/src/codex-launcher.d.ts +78 -0
- package/dist/vendor/adapters/adapters/src/codex-launcher.js +663 -0
- package/dist/vendor/adapters/adapters/src/direct-provider.d.ts +10 -0
- package/dist/vendor/adapters/adapters/src/direct-provider.js +40 -0
- package/dist/vendor/adapters/adapters/src/index.d.ts +8 -0
- package/dist/vendor/adapters/adapters/src/index.js +8 -0
- package/dist/vendor/adapters/adapters/src/openai-compatible.d.ts +62 -0
- package/dist/vendor/adapters/adapters/src/openai-compatible.js +306 -0
- package/dist/vendor/adapters/adapters/src/runtime-support.d.ts +17 -0
- package/dist/vendor/adapters/adapters/src/runtime-support.js +59 -0
- package/dist/vendor/adapters/adapters/src/stub-agent-cli.d.ts +8 -0
- package/dist/vendor/adapters/adapters/src/stub-agent-cli.js +40 -0
- package/dist/vendor/adapters/adapters/src/stub-direct-provider.d.ts +8 -0
- package/dist/vendor/adapters/adapters/src/stub-direct-provider.js +12 -0
- package/dist/vendor/adapters/adapters/src/verifier-only.d.ts +9 -0
- package/dist/vendor/adapters/adapters/src/verifier-only.js +63 -0
- package/dist/vendor/adapters/claude-cli.js +130 -68
- package/dist/vendor/adapters/codex-launcher.js +10 -1
- package/dist/vendor/adapters/contracts/src/context-graph.d.ts +48 -0
- package/dist/vendor/adapters/contracts/src/context-graph.js +26 -0
- package/dist/vendor/adapters/contracts/src/execution-policy.d.ts +78 -0
- package/dist/vendor/adapters/contracts/src/execution-policy.js +43 -0
- package/dist/vendor/adapters/contracts/src/governance.d.ts +24 -0
- package/dist/vendor/adapters/contracts/src/governance.js +11 -0
- package/dist/vendor/adapters/contracts/src/identity.d.ts +29 -0
- package/dist/vendor/adapters/contracts/src/identity.js +30 -0
- package/dist/vendor/adapters/contracts/src/index.d.ts +412 -0
- package/dist/vendor/adapters/contracts/src/index.js +225 -0
- package/dist/vendor/adapters/contracts/src/operator.d.ts +19 -0
- package/dist/vendor/adapters/contracts/src/operator.js +11 -0
- package/dist/vendor/adapters/contracts/src/trajectory.d.ts +26 -0
- package/dist/vendor/adapters/contracts/src/trajectory.js +27 -0
- package/dist/vendor/adapters/core/src/compiler.d.ts +52 -0
- package/dist/vendor/adapters/core/src/compiler.js +52 -0
- package/dist/vendor/adapters/core/src/context-graph.d.ts +3 -0
- package/dist/vendor/adapters/core/src/context-graph.js +371 -0
- package/dist/vendor/adapters/core/src/context-integrity.d.ts +26 -0
- package/dist/vendor/adapters/core/src/context-integrity.js +80 -0
- package/dist/vendor/adapters/core/src/grounding.d.ts +38 -0
- package/dist/vendor/adapters/core/src/grounding.js +273 -0
- package/dist/vendor/adapters/core/src/identity.d.ts +20 -0
- package/dist/vendor/adapters/core/src/identity.js +86 -0
- package/dist/vendor/adapters/core/src/index.d.ts +186 -0
- package/dist/vendor/adapters/core/src/index.js +1495 -0
- package/dist/vendor/adapters/core/src/leash.d.ts +48 -0
- package/dist/vendor/adapters/core/src/leash.js +497 -0
- package/dist/vendor/adapters/core/src/persistence/compiler.d.ts +18 -0
- package/dist/vendor/adapters/core/src/persistence/compiler.js +34 -0
- package/dist/vendor/adapters/core/src/persistence/index.d.ts +10 -0
- package/dist/vendor/adapters/core/src/persistence/index.js +5 -0
- package/dist/vendor/adapters/core/src/persistence/integrity.d.ts +39 -0
- package/dist/vendor/adapters/core/src/persistence/integrity.js +252 -0
- package/dist/vendor/adapters/core/src/persistence/ledger.d.ts +23 -0
- package/dist/vendor/adapters/core/src/persistence/ledger.js +9 -0
- package/dist/vendor/adapters/core/src/persistence/memory-store.d.ts +63 -0
- package/dist/vendor/adapters/core/src/persistence/memory-store.js +115 -0
- package/dist/vendor/adapters/core/src/persistence/runs-reader.d.ts +66 -0
- package/dist/vendor/adapters/core/src/persistence/runs-reader.js +140 -0
- package/dist/vendor/adapters/core/src/persistence/store.d.ts +89 -0
- package/dist/vendor/adapters/core/src/persistence/store.js +125 -0
- package/dist/vendor/adapters/core/src/persistence/trace-store.d.ts +85 -0
- package/dist/vendor/adapters/core/src/persistence/trace-store.js +125 -0
- package/dist/vendor/adapters/core/src/policy-compiler.d.ts +2 -0
- package/dist/vendor/adapters/core/src/policy-compiler.js +195 -0
- package/dist/vendor/adapters/core/src/policy.d.ts +156 -0
- package/dist/vendor/adapters/core/src/policy.js +704 -0
- package/dist/vendor/adapters/core/src/repo-analyzer.d.ts +53 -0
- package/dist/vendor/adapters/core/src/repo-analyzer.js +263 -0
- package/dist/vendor/adapters/core/src/rollback.d.ts +15 -0
- package/dist/vendor/adapters/core/src/rollback.js +253 -0
- package/dist/vendor/adapters/core/src/routing.d.ts +82 -0
- package/dist/vendor/adapters/core/src/routing.js +336 -0
- package/dist/vendor/adapters/core/src/test-integrity.d.ts +64 -0
- package/dist/vendor/adapters/core/src/test-integrity.js +197 -0
- package/dist/vendor/adapters/core/src/trajectory.d.ts +18 -0
- package/dist/vendor/adapters/core/src/trajectory.js +295 -0
- package/dist/vendor/adapters/openai-compatible.js +6 -6
- package/dist/vendor/adapters/verifier-only.js +2 -2
- package/dist/vendor/contracts/delivery.d.ts +47 -0
- package/dist/vendor/contracts/delivery.js +18 -0
- package/dist/vendor/contracts/index.d.ts +3 -1
- package/dist/vendor/contracts/index.js +2 -0
- package/dist/vendor/core/compiler.js +4 -9
- package/dist/vendor/core/delivery/index.d.ts +6 -0
- package/dist/vendor/core/delivery/index.js +4 -0
- package/dist/vendor/core/delivery/message-client.d.ts +18 -0
- package/dist/vendor/core/delivery/message-client.js +38 -0
- package/dist/vendor/core/delivery/message-ledger.d.ts +35 -0
- package/dist/vendor/core/delivery/message-ledger.js +97 -0
- package/dist/vendor/core/delivery/message-schema.d.ts +16 -0
- package/dist/vendor/core/delivery/message-schema.js +111 -0
- package/dist/vendor/core/delivery/update-check.d.ts +19 -0
- package/dist/vendor/core/delivery/update-check.js +107 -0
- package/dist/vendor/core/index.d.ts +2 -0
- package/dist/vendor/core/index.js +3 -88
- package/dist/vendor/core/rollback.js +2 -3
- package/package.json +83 -76
- package/server.json +21 -21
|
@@ -17,22 +17,18 @@ import { createAdapterCapabilities, normalizeStructuredErrors, normalizeUsage }
|
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
18
|
// Cost estimation
|
|
19
19
|
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// flags or martin.config.yaml pricing section.
|
|
20
|
+
// Streaming enforcement needs a model-specific estimate until Claude emits
|
|
21
|
+
// authoritative total_cost_usd on the final result event. Unknown Claude
|
|
22
|
+
// models are never assigned another model's price.
|
|
24
23
|
// ---------------------------------------------------------------------------
|
|
25
24
|
const BLENDED_INPUT_COST_PER_1K = 0.003; // $/1K input tokens
|
|
26
25
|
const BLENDED_OUTPUT_COST_PER_1K = 0.012; // $/1K output tokens
|
|
27
|
-
//
|
|
26
|
+
// USD per 1K tokens. Claude cache creation uses the documented default
|
|
27
|
+
// five-minute rate; cache reads are priced independently from fresh input.
|
|
28
28
|
const MODEL_PRICING = {
|
|
29
|
-
"claude-opus-4-6": { inputPer1K: 0.
|
|
30
|
-
"claude-sonnet-4-6": { inputPer1K: 0.003, outputPer1K: 0.015 },
|
|
31
|
-
"claude-haiku-4-5": { inputPer1K: 0.
|
|
32
|
-
// Keep legacy names working
|
|
33
|
-
"claude-opus": { inputPer1K: 0.015, outputPer1K: 0.075 },
|
|
34
|
-
"claude-sonnet": { inputPer1K: 0.003, outputPer1K: 0.015 },
|
|
35
|
-
"claude-haiku": { inputPer1K: 0.00025, outputPer1K: 0.00125 },
|
|
29
|
+
"claude-opus-4-6": { inputPer1K: 0.005, cachedInputPer1K: 0.0005, cacheCreationInputPer1K: 0.00625, outputPer1K: 0.025 },
|
|
30
|
+
"claude-sonnet-4-6": { inputPer1K: 0.003, cachedInputPer1K: 0.0003, cacheCreationInputPer1K: 0.00375, outputPer1K: 0.015 },
|
|
31
|
+
"claude-haiku-4-5": { inputPer1K: 0.001, cachedInputPer1K: 0.0001, cacheCreationInputPer1K: 0.00125, outputPer1K: 0.005 },
|
|
36
32
|
// OpenAI coding models
|
|
37
33
|
"codex": { inputPer1K: 0.00125, cachedInputPer1K: 0.000125, outputPer1K: 0.01 },
|
|
38
34
|
"gpt-5-codex": { inputPer1K: 0.00125, cachedInputPer1K: 0.000125, outputPer1K: 0.01 },
|
|
@@ -41,6 +37,37 @@ const MODEL_PRICING = {
|
|
|
41
37
|
"gpt-5.2-codex": { inputPer1K: 0.00175, cachedInputPer1K: 0.000175, outputPer1K: 0.014 },
|
|
42
38
|
"codex-mini-latest": { inputPer1K: 0.0015, cachedInputPer1K: 0.000375, outputPer1K: 0.006 }
|
|
43
39
|
};
|
|
40
|
+
const CLAUDE_MODEL_ALIASES = [
|
|
41
|
+
{ canonicalModelId: "claude-opus-4-6", aliases: [/^claude-opus-4-6-\d{8}$/u, /^claude-opus$/u] },
|
|
42
|
+
{ canonicalModelId: "claude-sonnet-4-6", aliases: [/^claude-sonnet-4-6-\d{8}$/u, /^claude-sonnet$/u] },
|
|
43
|
+
{ canonicalModelId: "claude-haiku-4-5", aliases: [/^claude-haiku-4-5-\d{8}$/u, /^claude-haiku$/u] }
|
|
44
|
+
];
|
|
45
|
+
function resolveModelPricing(modelLabel) {
|
|
46
|
+
const normalized = modelLabel?.trim().toLowerCase();
|
|
47
|
+
if (!normalized) {
|
|
48
|
+
return { status: "unknown" };
|
|
49
|
+
}
|
|
50
|
+
const exact = MODEL_PRICING[normalized];
|
|
51
|
+
if (exact) {
|
|
52
|
+
return { status: "exact", canonicalModelId: normalized, pricing: exact };
|
|
53
|
+
}
|
|
54
|
+
for (const family of CLAUDE_MODEL_ALIASES) {
|
|
55
|
+
if (family.aliases.some((alias) => alias.test(normalized))) {
|
|
56
|
+
return {
|
|
57
|
+
status: "alias",
|
|
58
|
+
canonicalModelId: family.canonicalModelId,
|
|
59
|
+
pricing: MODEL_PRICING[family.canonicalModelId]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return { status: "unknown" };
|
|
64
|
+
}
|
|
65
|
+
function calculateUsageCost(usage, pricing) {
|
|
66
|
+
return ((usage.inputTokens / 1000) * pricing.inputPer1K +
|
|
67
|
+
(usage.cachedInputTokens / 1000) * (pricing.cachedInputPer1K ?? pricing.inputPer1K) +
|
|
68
|
+
(usage.cacheCreationInputTokens / 1000) * (pricing.cacheCreationInputPer1K ?? pricing.inputPer1K) +
|
|
69
|
+
(usage.outputTokens / 1000) * pricing.outputPer1K);
|
|
70
|
+
}
|
|
44
71
|
function extractUsage(parsed, modelLabel) {
|
|
45
72
|
if (!parsed?.usage) {
|
|
46
73
|
return normalizeUsage({
|
|
@@ -50,34 +77,38 @@ function extractUsage(parsed, modelLabel) {
|
|
|
50
77
|
provenance: "unavailable"
|
|
51
78
|
});
|
|
52
79
|
}
|
|
53
|
-
const promptTokens =
|
|
54
|
-
|
|
80
|
+
const promptTokens = parsed.usage.inputTokens ?? parsed.usage.input_tokens ?? 0;
|
|
81
|
+
const cacheCreationInputTokens = parsed.usage.cacheCreationInputTokens ?? parsed.usage.cache_creation_input_tokens ?? 0;
|
|
55
82
|
const cachedInputTokens = parsed.usage.cacheReadInputTokens ?? parsed.usage.cache_read_input_tokens ?? 0;
|
|
56
|
-
const tokensIn = promptTokens + cachedInputTokens;
|
|
83
|
+
const tokensIn = promptTokens + cachedInputTokens + cacheCreationInputTokens;
|
|
57
84
|
const tokensOut = parsed.usage.outputTokens ?? parsed.usage.output_tokens ?? 0;
|
|
58
|
-
const
|
|
59
|
-
{ inputPer1K: BLENDED_INPUT_COST_PER_1K, outputPer1K: BLENDED_OUTPUT_COST_PER_1K };
|
|
85
|
+
const pricingResolution = resolveModelPricing(modelLabel);
|
|
60
86
|
// Prefer Claude's own authoritative total_cost_usd (present on the final
|
|
61
87
|
// `result` event in json/stream-json output) over our pricing-table estimate,
|
|
62
88
|
// which can drift from real billed cost (cache discounts, surcharges, etc).
|
|
63
89
|
const hasAuthoritativeCost = typeof parsed.total_cost_usd === "number";
|
|
64
90
|
const actualUsd = hasAuthoritativeCost
|
|
65
91
|
? parsed.total_cost_usd
|
|
66
|
-
:
|
|
67
|
-
|
|
68
|
-
|
|
92
|
+
: pricingResolution.pricing
|
|
93
|
+
? calculateUsageCost({
|
|
94
|
+
inputTokens: promptTokens,
|
|
95
|
+
cachedInputTokens,
|
|
96
|
+
cacheCreationInputTokens,
|
|
97
|
+
outputTokens: tokensOut
|
|
98
|
+
}, pricingResolution.pricing)
|
|
99
|
+
: 0;
|
|
69
100
|
return normalizeUsage({
|
|
70
101
|
actualUsd: Number(actualUsd.toFixed(6)),
|
|
71
102
|
tokensIn,
|
|
72
103
|
tokensOut,
|
|
73
104
|
cachedInputTokens,
|
|
74
|
-
provenance: hasAuthoritativeCost ? "actual" : "estimated",
|
|
105
|
+
provenance: hasAuthoritativeCost ? "actual" : pricingResolution.pricing ? "estimated" : "unavailable",
|
|
75
106
|
providerSettlement: {
|
|
76
107
|
providerId: "claude",
|
|
77
108
|
model: modelLabel ?? "claude",
|
|
78
109
|
transport: "cli",
|
|
79
110
|
source: "claude_json",
|
|
80
|
-
inputTokens: promptTokens,
|
|
111
|
+
inputTokens: promptTokens + cacheCreationInputTokens,
|
|
81
112
|
cachedInputTokens,
|
|
82
113
|
outputTokens: tokensOut,
|
|
83
114
|
rawUsageAvailable: true,
|
|
@@ -240,8 +271,7 @@ function extractGeminiJsonResult(stdout, modelLabel) {
|
|
|
240
271
|
};
|
|
241
272
|
}
|
|
242
273
|
function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate) {
|
|
243
|
-
|
|
244
|
-
{ inputPer1K: BLENDED_INPUT_COST_PER_1K, outputPer1K: BLENDED_OUTPUT_COST_PER_1K };
|
|
274
|
+
let pricingResolution = resolveModelPricing(modelLabel);
|
|
245
275
|
// Safety margin: terminate at 80% of cap to bound one-turn overshoot.
|
|
246
276
|
// Without this, a single expensive turn can blow past the cap before the
|
|
247
277
|
// next check fires (proven live: $1.50 cap → $28.42 actual).
|
|
@@ -251,10 +281,12 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
251
281
|
// Token-count ceiling fallback: if no usage events are ever parsed (e.g.
|
|
252
282
|
// Claude changes its stream-json event format), use raw byte volume as a
|
|
253
283
|
// last-resort circuit breaker. Derived from budget / blended cost per char.
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
284
|
+
const resolveBlendedCostPerChar = () => {
|
|
285
|
+
const pricing = pricingResolution.pricing;
|
|
286
|
+
return pricing
|
|
287
|
+
? (pricing.inputPer1K / 1000 / 4) + (pricing.outputPer1K / 1000 / 4)
|
|
288
|
+
: undefined;
|
|
289
|
+
};
|
|
258
290
|
// Time-based fallback: if we receive data but no usage events for this long,
|
|
259
291
|
// estimate spend from byte volume and enforce the cap. Prevents the inspector
|
|
260
292
|
// from going blind when Claude changes its stream-json event format.
|
|
@@ -276,6 +308,9 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
276
308
|
}
|
|
277
309
|
};
|
|
278
310
|
const extractUsageFromEvent = (event, terminate) => {
|
|
311
|
+
if (event.type === "system" && event.subtype === "init" && typeof event.model === "string") {
|
|
312
|
+
pricingResolution = resolveModelPricing(event.model);
|
|
313
|
+
}
|
|
279
314
|
// Check for authoritative total_cost_usd on ANY event — if Claude reports
|
|
280
315
|
// cost exceeding cap, terminate immediately regardless of event type.
|
|
281
316
|
if (typeof event.total_cost_usd === "number" && event.total_cost_usd > 0) {
|
|
@@ -295,16 +330,27 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
295
330
|
return;
|
|
296
331
|
}
|
|
297
332
|
const usageRecord = usage;
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
333
|
+
const turnInputTokens = usageRecord.input_tokens ?? usageRecord.inputTokens ?? 0;
|
|
334
|
+
const turnCachedInputTokens = usageRecord.cache_read_input_tokens ?? usageRecord.cacheReadInputTokens ?? 0;
|
|
335
|
+
const turnCacheCreationInputTokens = usageRecord.cache_creation_input_tokens ?? usageRecord.cacheCreationInputTokens ?? 0;
|
|
336
|
+
const turnTokensIn = turnInputTokens + turnCachedInputTokens + turnCacheCreationInputTokens;
|
|
301
337
|
const turnTokensOut = usageRecord.output_tokens ?? usageRecord.outputTokens ?? 0;
|
|
302
338
|
if (turnTokensIn === 0 && turnTokensOut === 0) {
|
|
303
339
|
return;
|
|
304
340
|
}
|
|
305
|
-
const turnUsd =
|
|
341
|
+
const turnUsd = pricingResolution.pricing
|
|
342
|
+
? calculateUsageCost({
|
|
343
|
+
inputTokens: turnInputTokens,
|
|
344
|
+
cachedInputTokens: turnCachedInputTokens,
|
|
345
|
+
cacheCreationInputTokens: turnCacheCreationInputTokens,
|
|
346
|
+
outputTokens: turnTokensOut
|
|
347
|
+
}, pricingResolution.pricing)
|
|
348
|
+
: undefined;
|
|
306
349
|
const remainingBudgetBeforeTurn = Math.max(capUsd - cumulativeUsd, 0);
|
|
307
|
-
if (
|
|
350
|
+
if (turnUsd !== undefined &&
|
|
351
|
+
capUsd > 0 &&
|
|
352
|
+
remainingBudgetBeforeTurn > 0 &&
|
|
353
|
+
turnUsd > remainingBudgetBeforeTurn * 0.5) {
|
|
308
354
|
cumulativeUsd += turnUsd;
|
|
309
355
|
tokensIn += turnTokensIn;
|
|
310
356
|
tokensOut += turnTokensOut;
|
|
@@ -318,7 +364,9 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
318
364
|
tokensOut += turnTokensOut;
|
|
319
365
|
turns += 1;
|
|
320
366
|
usageEventSeen = true;
|
|
321
|
-
|
|
367
|
+
if (turnUsd !== undefined) {
|
|
368
|
+
cumulativeUsd += turnUsd;
|
|
369
|
+
}
|
|
322
370
|
checkBudgetExceeded(terminate);
|
|
323
371
|
};
|
|
324
372
|
const ingestLine = (line, terminate) => {
|
|
@@ -333,10 +381,14 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
333
381
|
catch {
|
|
334
382
|
return;
|
|
335
383
|
}
|
|
336
|
-
|
|
384
|
+
// result events contain aggregate usage that duplicates previously streamed
|
|
385
|
+
// assistant-message usage events — skip to avoid double-counting.
|
|
337
386
|
if (event.type === "result") {
|
|
338
387
|
finalResult = event;
|
|
339
388
|
}
|
|
389
|
+
else {
|
|
390
|
+
extractUsageFromEvent(event, terminate);
|
|
391
|
+
}
|
|
340
392
|
};
|
|
341
393
|
return {
|
|
342
394
|
onChunk: (chunk, terminate) => {
|
|
@@ -347,7 +399,11 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
347
399
|
// Token-count ceiling fallback: if we've ingested a lot of bytes but
|
|
348
400
|
// never seen a single usage event, the event format may have changed
|
|
349
401
|
// and the inspector is silently blind. Terminate as a last resort.
|
|
350
|
-
|
|
402
|
+
const blendedCostPerChar = resolveBlendedCostPerChar();
|
|
403
|
+
const bytesCeiling = blendedCostPerChar && blendedCostPerChar > 0
|
|
404
|
+
? Math.ceil((capUsd / blendedCostPerChar) * 2)
|
|
405
|
+
: undefined;
|
|
406
|
+
if (!usageEventSeen && capUsd > 0 && bytesCeiling !== undefined && totalBytes > bytesCeiling) {
|
|
351
407
|
terminate(`Streaming byte ceiling exceeded (${String(totalBytes)} bytes > ${String(bytesCeiling)} ceiling) ` +
|
|
352
408
|
`without any usage events parsed. The Claude stream-json event format may have changed. ` +
|
|
353
409
|
`Subprocess terminated as a fallback budget guard for cap $${capUsd.toFixed(4)}.`);
|
|
@@ -362,8 +418,8 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
|
|
|
362
418
|
firstChunkAt !== undefined &&
|
|
363
419
|
Date.now() - firstChunkAt > USAGE_BLIND_TIMEOUT_MS &&
|
|
364
420
|
totalBytes > 10_000) {
|
|
365
|
-
const estimatedUsd = totalBytes * blendedCostPerChar;
|
|
366
|
-
if (estimatedUsd > effectiveCapUsd) {
|
|
421
|
+
const estimatedUsd = blendedCostPerChar === undefined ? undefined : totalBytes * blendedCostPerChar;
|
|
422
|
+
if (estimatedUsd !== undefined && estimatedUsd > effectiveCapUsd) {
|
|
367
423
|
terminate(`No usage events received after ${String(Math.round((Date.now() - firstChunkAt) / 1000))}s ` +
|
|
368
424
|
`(${String(totalBytes)} bytes). Estimated cost ~$${estimatedUsd.toFixed(4)} exceeds cap ` +
|
|
369
425
|
`$${capUsd.toFixed(4)}. Subprocess terminated to prevent unmetered spend.`);
|
|
@@ -457,11 +513,11 @@ export function createAgentCliAdapter(options) {
|
|
|
457
513
|
},
|
|
458
514
|
async execute(request) {
|
|
459
515
|
const prompt = buildPrompt(request);
|
|
460
|
-
const estimatedUsage = estimateUsage(prompt, options.model ?? options.command);
|
|
516
|
+
const estimatedUsage = estimateUsage(prompt, options.model ?? options.command, options.command);
|
|
461
517
|
// Preflight: bail if projected cost exceeds remaining budget
|
|
462
518
|
if (request.context.remainingBudgetUsd > 0) {
|
|
463
|
-
const projected = estimatePromptCost(prompt, options.model ?? "");
|
|
464
|
-
if (projected > request.context.remainingBudgetUsd * 0.95) {
|
|
519
|
+
const projected = estimatePromptCost(prompt, options.model ?? "", options.command);
|
|
520
|
+
if (projected !== undefined && projected > request.context.remainingBudgetUsd * 0.95) {
|
|
465
521
|
return {
|
|
466
522
|
status: "failed",
|
|
467
523
|
summary: `Preflight: projected cost $${projected.toFixed(4)} exceeds remaining budget $${request.context.remainingBudgetUsd.toFixed(4)}.`,
|
|
@@ -536,10 +592,14 @@ export function createAgentCliAdapter(options) {
|
|
|
536
592
|
};
|
|
537
593
|
}
|
|
538
594
|
if (agentResult.exitCode !== 0 && agentResult.stdout.trim().length === 0) {
|
|
595
|
+
const fullStderr = agentResult.stderr.trim();
|
|
596
|
+
const stderrSnippet = fullStderr ? fullStderr.slice(0, 2000) : "(no stderr)";
|
|
597
|
+
const stdoutLen = agentResult.stdout.length;
|
|
598
|
+
const diagnosticSummary = `${options.command} exited (code ${String(agentResult.exitCode)}) with empty stdout (${String(stdoutLen)} bytes). stderr: ${stderrSnippet}`;
|
|
539
599
|
const failureMessage = formatPreVerifierSubprocessFailure(options.command, agentResult.stderr, agentResult.exitCode);
|
|
540
600
|
return {
|
|
541
601
|
status: "failed",
|
|
542
|
-
summary:
|
|
602
|
+
summary: diagnosticSummary,
|
|
543
603
|
usage: normalizeUsage({
|
|
544
604
|
actualUsd: 0,
|
|
545
605
|
tokensIn: 0,
|
|
@@ -548,6 +608,9 @@ export function createAgentCliAdapter(options) {
|
|
|
548
608
|
}),
|
|
549
609
|
verification: { passed: false, summary: `Verifier not run: ${failureMessage}` },
|
|
550
610
|
failure: {
|
|
611
|
+
// Raw stderr is preserved in diagnosticSummary above; use the
|
|
612
|
+
// normalized/classified message here so downstream consumers and
|
|
613
|
+
// tests get a consistent, parseable failure signal.
|
|
551
614
|
message: failureMessage
|
|
552
615
|
}
|
|
553
616
|
};
|
|
@@ -810,12 +873,15 @@ export function createClaudeCliAdapter(options = {}) {
|
|
|
810
873
|
"--verbose",
|
|
811
874
|
"--print",
|
|
812
875
|
"--dangerously-skip-permissions",
|
|
813
|
-
//
|
|
814
|
-
//
|
|
815
|
-
//
|
|
816
|
-
//
|
|
817
|
-
|
|
818
|
-
|
|
876
|
+
// Subprocess isolation strategy:
|
|
877
|
+
// --bare: skips hooks (prevents SessionEnd/hook failures causing non-zero exits),
|
|
878
|
+
// MCP server loading, LSP, CLAUDE.md discovery, and background prefetches.
|
|
879
|
+
// Requires ANTHROPIC_API_KEY (OAuth/keychain auth not available in bare mode).
|
|
880
|
+
// --strict-mcp-config: fallback when ANTHROPIC_API_KEY is not set — still
|
|
881
|
+
// prevents parent MCP servers from being inherited by the subprocess.
|
|
882
|
+
...(process.env["ANTHROPIC_API_KEY"] ? ["--bare"] : ["--strict-mcp-config"]),
|
|
883
|
+
// NOTE: --max-tokens does not exist in the claude CLI. Token cap enforcement
|
|
884
|
+
// is handled at the MartinLoop layer via streamingUsageCap, not via subprocess flags.
|
|
819
885
|
...modelArgs,
|
|
820
886
|
...extraArgs
|
|
821
887
|
],
|
|
@@ -915,21 +981,13 @@ function buildPrompt(request) {
|
|
|
915
981
|
const lines = [];
|
|
916
982
|
const mutationMode = request.context.mutationMode ?? "edit";
|
|
917
983
|
lines.push("You are running in autonomous agentic mode.");
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
lines.push("Do not ask for confirmation. Do not ask clarifying questions.");
|
|
921
|
-
}
|
|
922
|
-
else {
|
|
923
|
-
lines.push("MAKE ALL REQUIRED FILE EDITS NOW. Do not ask for confirmation. Do not ask clarifying questions.");
|
|
924
|
-
lines.push("Do not explain what you found without also making the changes. Edit the files and complete the task.");
|
|
925
|
-
}
|
|
984
|
+
lines.push("MAKE ALL REQUIRED FILE EDITS NOW. Do not ask for confirmation. Do not ask clarifying questions.");
|
|
985
|
+
lines.push("Do not explain what you found without also making the changes. Edit the files and complete the task.");
|
|
926
986
|
lines.push("");
|
|
927
987
|
lines.push("If PROGRESS.md exists in your working directory, read it first for context from prior attempts.");
|
|
928
988
|
lines.push("If it does not exist, proceed with the objective below.");
|
|
929
989
|
lines.push("");
|
|
930
|
-
lines.push(
|
|
931
|
-
? "Complete the following verification-only task without making file changes."
|
|
932
|
-
: "Complete the following coding task. Make all necessary file changes.");
|
|
990
|
+
lines.push("Complete the following coding task. Make all necessary file changes.");
|
|
933
991
|
lines.push("When you are done, the verification commands listed below must pass.");
|
|
934
992
|
lines.push("");
|
|
935
993
|
lines.push("OBJECTIVE:");
|
|
@@ -967,9 +1025,7 @@ function buildPrompt(request) {
|
|
|
967
1025
|
lines.push(` Attempt ${String(attemptNumber)}`);
|
|
968
1026
|
lines.push(` Remaining budget: $${String(request.context.remainingBudgetUsd)} USD`);
|
|
969
1027
|
lines.push(` Remaining iterations: ${String(request.context.remainingIterations)}`);
|
|
970
|
-
lines.push(
|
|
971
|
-
? " Do not modify files; only run verification."
|
|
972
|
-
: " Do not expand scope beyond what is needed to pass verification.");
|
|
1028
|
+
lines.push(" Do not expand scope beyond what is needed to pass verification.");
|
|
973
1029
|
lines.push("");
|
|
974
1030
|
if (request.previousAttempts.length > 0) {
|
|
975
1031
|
lines.push("PRIOR FAILED ATTEMPTS (learn from these — do not repeat the same mistakes):");
|
|
@@ -1040,21 +1096,27 @@ function sanitizeForPrompt(input) {
|
|
|
1040
1096
|
}
|
|
1041
1097
|
return redactSecretsForPrompt(out);
|
|
1042
1098
|
}
|
|
1043
|
-
function estimatePromptCost(promptText, model) {
|
|
1099
|
+
function estimatePromptCost(promptText, model, providerCommand) {
|
|
1044
1100
|
const inputTokens = Math.ceil(promptText.length / 3.5);
|
|
1045
1101
|
const outputTokens = 2000;
|
|
1046
|
-
const pricing =
|
|
1102
|
+
const pricing = resolveModelPricing(model).pricing ?? (providerCommand === "claude"
|
|
1103
|
+
? undefined
|
|
1104
|
+
: { inputPer1K: BLENDED_INPUT_COST_PER_1K, outputPer1K: BLENDED_OUTPUT_COST_PER_1K });
|
|
1105
|
+
if (!pricing) {
|
|
1106
|
+
return undefined;
|
|
1107
|
+
}
|
|
1047
1108
|
return (inputTokens / 1000) * pricing.inputPer1K + (outputTokens / 1000) * pricing.outputPer1K;
|
|
1048
1109
|
}
|
|
1049
|
-
function estimateUsage(promptText, model) {
|
|
1110
|
+
function estimateUsage(promptText, model, providerCommand) {
|
|
1050
1111
|
const inputTokens = Math.ceil(promptText.length / 3.5);
|
|
1051
1112
|
const outputTokens = 2_000;
|
|
1113
|
+
const estimatedUsd = estimatePromptCost(promptText, model, providerCommand);
|
|
1052
1114
|
return normalizeUsage({
|
|
1053
|
-
actualUsd:
|
|
1054
|
-
estimatedUsd:
|
|
1115
|
+
actualUsd: estimatedUsd ?? 0,
|
|
1116
|
+
...(estimatedUsd === undefined ? {} : { estimatedUsd }),
|
|
1055
1117
|
tokensIn: inputTokens,
|
|
1056
1118
|
tokensOut: outputTokens,
|
|
1057
|
-
provenance: "estimated"
|
|
1119
|
+
provenance: estimatedUsd === undefined ? "unavailable" : "estimated"
|
|
1058
1120
|
});
|
|
1059
1121
|
}
|
|
1060
1122
|
function redactSecretsForPrompt(input) {
|
|
@@ -357,6 +357,10 @@ function discoverCommandOffPath(command, platform, env) {
|
|
|
357
357
|
const localAppData = env.LOCALAPPDATA;
|
|
358
358
|
if (localAppData)
|
|
359
359
|
dirs.push(join(localAppData, "OpenAI", "Codex", "bin"));
|
|
360
|
+
// Claude Code native installer places binary at %USERPROFILE%\.local\bin
|
|
361
|
+
const userProfile = env.USERPROFILE ?? env.HOMEPATH;
|
|
362
|
+
if (userProfile)
|
|
363
|
+
dirs.push(join(userProfile, ".local", "bin"));
|
|
360
364
|
if (home)
|
|
361
365
|
dirs.push(join(home, "scoop", "shims"));
|
|
362
366
|
}
|
|
@@ -383,8 +387,13 @@ function discoverCommandOffPath(command, platform, env) {
|
|
|
383
387
|
return undefined;
|
|
384
388
|
}
|
|
385
389
|
function suggestInstall(command) {
|
|
390
|
+
if (command === "claude") {
|
|
391
|
+
const installCmd = process.platform === "win32"
|
|
392
|
+
? "irm https://claude.ai/install.ps1 | iex"
|
|
393
|
+
: "curl -fsSL https://claude.ai/install.sh | bash";
|
|
394
|
+
return `Install with: ${installCmd}`;
|
|
395
|
+
}
|
|
386
396
|
const installs = {
|
|
387
|
-
claude: "Install with: npm install -g @anthropic-ai/claude-code",
|
|
388
397
|
codex: "Install with: npm install -g @openai/codex",
|
|
389
398
|
gemini: "Install with: npm install -g @google/gemini-cli"
|
|
390
399
|
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type ContextGraphNodeKind = "source_file" | "document" | "manifest" | "script" | "config";
|
|
2
|
+
export type ContextGraphEdgeKind = "imports" | "documents";
|
|
3
|
+
export interface ContextGraphNode {
|
|
4
|
+
nodeId: string;
|
|
5
|
+
path: string;
|
|
6
|
+
kind: ContextGraphNodeKind;
|
|
7
|
+
language?: string;
|
|
8
|
+
sizeBytes: number;
|
|
9
|
+
headings: string[];
|
|
10
|
+
symbols: string[];
|
|
11
|
+
keywords: string[];
|
|
12
|
+
imports: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface ContextGraphEdge {
|
|
15
|
+
fromNodeId: string;
|
|
16
|
+
toNodeId: string;
|
|
17
|
+
kind: ContextGraphEdgeKind;
|
|
18
|
+
}
|
|
19
|
+
export interface ContextGraphSnapshot {
|
|
20
|
+
schemaVersion: "martin.context-graph.v1";
|
|
21
|
+
repoRoot: string;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
nodeCount: number;
|
|
24
|
+
edgeCount: number;
|
|
25
|
+
truncated: boolean;
|
|
26
|
+
nodes: ContextGraphNode[];
|
|
27
|
+
edges: ContextGraphEdge[];
|
|
28
|
+
}
|
|
29
|
+
export interface ContextQuery {
|
|
30
|
+
text?: string;
|
|
31
|
+
terms?: string[];
|
|
32
|
+
pathPrefix?: string;
|
|
33
|
+
kinds?: ContextGraphNodeKind[];
|
|
34
|
+
limit?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ContextGraphBuildOptions {
|
|
37
|
+
maxFiles?: number;
|
|
38
|
+
maxFileBytes?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface ContextGraphHit {
|
|
41
|
+
nodeId: string;
|
|
42
|
+
path: string;
|
|
43
|
+
kind: ContextGraphNodeKind;
|
|
44
|
+
score: number;
|
|
45
|
+
matchedTerms: string[];
|
|
46
|
+
reasons: string[];
|
|
47
|
+
}
|
|
48
|
+
export declare function cloneContextGraphSnapshot(snapshot: ContextGraphSnapshot): ContextGraphSnapshot;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function cloneContextGraphSnapshot(snapshot) {
|
|
2
|
+
return {
|
|
3
|
+
schemaVersion: snapshot.schemaVersion,
|
|
4
|
+
repoRoot: snapshot.repoRoot,
|
|
5
|
+
createdAt: snapshot.createdAt,
|
|
6
|
+
nodeCount: snapshot.nodeCount,
|
|
7
|
+
edgeCount: snapshot.edgeCount,
|
|
8
|
+
truncated: snapshot.truncated,
|
|
9
|
+
nodes: snapshot.nodes.map((node) => ({
|
|
10
|
+
nodeId: node.nodeId,
|
|
11
|
+
path: node.path,
|
|
12
|
+
kind: node.kind,
|
|
13
|
+
...(node.language ? { language: node.language } : {}),
|
|
14
|
+
sizeBytes: node.sizeBytes,
|
|
15
|
+
headings: [...node.headings],
|
|
16
|
+
symbols: [...node.symbols],
|
|
17
|
+
keywords: [...node.keywords],
|
|
18
|
+
imports: [...node.imports]
|
|
19
|
+
})),
|
|
20
|
+
edges: snapshot.edges.map((edge) => ({
|
|
21
|
+
fromNodeId: edge.fromNodeId,
|
|
22
|
+
toNodeId: edge.toNodeId,
|
|
23
|
+
kind: edge.kind
|
|
24
|
+
}))
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { ApprovalPolicy, LoopBudget, LoopTask, MutationMode } from "./index.js";
|
|
2
|
+
import type { DestructiveActionPolicy, PolicyProfile, TelemetryDestination } from "./governance.js";
|
|
3
|
+
export interface ExecutionPolicy {
|
|
4
|
+
configPath: string;
|
|
5
|
+
budget: LoopBudget;
|
|
6
|
+
governance: {
|
|
7
|
+
policyProfile: PolicyProfile;
|
|
8
|
+
telemetryDestination: TelemetryDestination;
|
|
9
|
+
destructiveActionPolicy: DestructiveActionPolicy;
|
|
10
|
+
};
|
|
11
|
+
task: {
|
|
12
|
+
verificationPlan: string[];
|
|
13
|
+
mutationMode?: MutationMode;
|
|
14
|
+
repoRoot?: string;
|
|
15
|
+
allowedPaths?: string[];
|
|
16
|
+
deniedPaths?: string[];
|
|
17
|
+
acceptanceCriteria?: string[];
|
|
18
|
+
approvalPolicy?: ApprovalPolicy;
|
|
19
|
+
};
|
|
20
|
+
provenance: ExecutionPolicyProvenanceEntry[];
|
|
21
|
+
}
|
|
22
|
+
export interface ExecutionPolicyProvenanceEntry {
|
|
23
|
+
field: string;
|
|
24
|
+
source: "default" | "config" | "request";
|
|
25
|
+
value: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ExecutionPolicyDefaults {
|
|
28
|
+
budget: LoopBudget;
|
|
29
|
+
policyProfile: PolicyProfile;
|
|
30
|
+
telemetryDestination: TelemetryDestination;
|
|
31
|
+
destructiveActionPolicy: DestructiveActionPolicy;
|
|
32
|
+
verifierRules: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface ExecutionPolicyConfigInput {
|
|
35
|
+
policyProfile?: string;
|
|
36
|
+
budget?: Partial<LoopBudget>;
|
|
37
|
+
governance?: {
|
|
38
|
+
destructiveActionPolicy?: string;
|
|
39
|
+
telemetryDestination?: string;
|
|
40
|
+
verifierRules?: string[];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface ExecutionPolicyRequestInput {
|
|
44
|
+
budget: LoopBudget;
|
|
45
|
+
budgetOverrides?: Partial<Record<keyof LoopBudget, true>>;
|
|
46
|
+
policyProfile?: string;
|
|
47
|
+
telemetryDestination?: string;
|
|
48
|
+
verificationPlan?: string[];
|
|
49
|
+
mutationMode?: LoopTask["mutationMode"];
|
|
50
|
+
repoRoot?: string;
|
|
51
|
+
allowedPaths?: string[];
|
|
52
|
+
deniedPaths?: string[];
|
|
53
|
+
acceptanceCriteria?: string[];
|
|
54
|
+
approvalPolicy?: ApprovalPolicy;
|
|
55
|
+
}
|
|
56
|
+
export interface ExecutionPolicyCompileInput {
|
|
57
|
+
configPath: string;
|
|
58
|
+
defaults: ExecutionPolicyDefaults;
|
|
59
|
+
config?: ExecutionPolicyConfigInput;
|
|
60
|
+
request: ExecutionPolicyRequestInput;
|
|
61
|
+
}
|
|
62
|
+
export type RoutingMode = "direct" | "manager" | "adaptive" | "consensus";
|
|
63
|
+
export interface RoutingPolicy {
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
mode: RoutingMode;
|
|
66
|
+
/** Max percentage of total budget that can be spent before first code change. */
|
|
67
|
+
maxPreworkBudgetPct: number;
|
|
68
|
+
/** Hard dollar cap on pre-work spend. */
|
|
69
|
+
maxPreworkCostUsd: number;
|
|
70
|
+
/** Max model calls allowed for manager/router/planner before worker starts. */
|
|
71
|
+
maxManagerCalls: number;
|
|
72
|
+
/** Skip orchestration entirely if task confidence is above this threshold (0-1). */
|
|
73
|
+
skipOrchestrationIfConfidenceAbove: number;
|
|
74
|
+
/** Force direct execution for tasks classified as simple. */
|
|
75
|
+
requireDirectForSimpleTasks: boolean;
|
|
76
|
+
}
|
|
77
|
+
export declare const DEFAULT_ROUTING_POLICY: RoutingPolicy;
|
|
78
|
+
export declare function cloneExecutionPolicy(policy: ExecutionPolicy): ExecutionPolicy;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const DEFAULT_ROUTING_POLICY = {
|
|
2
|
+
enabled: true,
|
|
3
|
+
mode: "adaptive",
|
|
4
|
+
maxPreworkBudgetPct: 25,
|
|
5
|
+
maxPreworkCostUsd: 2.0,
|
|
6
|
+
maxManagerCalls: 2,
|
|
7
|
+
skipOrchestrationIfConfidenceAbove: 0.85,
|
|
8
|
+
requireDirectForSimpleTasks: true
|
|
9
|
+
};
|
|
10
|
+
export function cloneExecutionPolicy(policy) {
|
|
11
|
+
return {
|
|
12
|
+
configPath: policy.configPath,
|
|
13
|
+
budget: {
|
|
14
|
+
maxUsd: policy.budget.maxUsd,
|
|
15
|
+
softLimitUsd: policy.budget.softLimitUsd,
|
|
16
|
+
maxIterations: policy.budget.maxIterations,
|
|
17
|
+
maxTokens: policy.budget.maxTokens
|
|
18
|
+
},
|
|
19
|
+
governance: {
|
|
20
|
+
policyProfile: policy.governance.policyProfile,
|
|
21
|
+
telemetryDestination: policy.governance.telemetryDestination,
|
|
22
|
+
destructiveActionPolicy: policy.governance.destructiveActionPolicy
|
|
23
|
+
},
|
|
24
|
+
task: {
|
|
25
|
+
verificationPlan: [...policy.task.verificationPlan],
|
|
26
|
+
...(policy.task.mutationMode ? { mutationMode: policy.task.mutationMode } : {}),
|
|
27
|
+
...(policy.task.repoRoot ? { repoRoot: policy.task.repoRoot } : {}),
|
|
28
|
+
...(policy.task.allowedPaths ? { allowedPaths: [...policy.task.allowedPaths] } : {}),
|
|
29
|
+
...(policy.task.deniedPaths ? { deniedPaths: [...policy.task.deniedPaths] } : {}),
|
|
30
|
+
...(policy.task.acceptanceCriteria
|
|
31
|
+
? { acceptanceCriteria: [...policy.task.acceptanceCriteria] }
|
|
32
|
+
: {}),
|
|
33
|
+
...(policy.task.approvalPolicy
|
|
34
|
+
? {
|
|
35
|
+
approvalPolicy: {
|
|
36
|
+
...policy.task.approvalPolicy
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
: {})
|
|
40
|
+
},
|
|
41
|
+
provenance: policy.provenance.map((entry) => ({ ...entry }))
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type PolicyProfile = "strict" | "balanced" | "overnight" | "debug";
|
|
2
|
+
export type DestructiveActionPolicy = "never" | "approval" | "allowed";
|
|
3
|
+
export type TelemetryDestination = "local-only" | "control-plane";
|
|
4
|
+
export type GovernanceSnapshot = {
|
|
5
|
+
policyProfile: PolicyProfile;
|
|
6
|
+
maxUsd: number;
|
|
7
|
+
softLimitUsd: number;
|
|
8
|
+
maxTokens: number;
|
|
9
|
+
maxIterations: number;
|
|
10
|
+
allowedAdapters: string[];
|
|
11
|
+
allowedModels: string[];
|
|
12
|
+
destructiveActionPolicy: DestructiveActionPolicy;
|
|
13
|
+
approvalRequired: boolean;
|
|
14
|
+
verifierRules: string[];
|
|
15
|
+
escalationRoute: string;
|
|
16
|
+
telemetryDestination: TelemetryDestination;
|
|
17
|
+
retentionPolicy: string;
|
|
18
|
+
provenance: Array<{
|
|
19
|
+
field: string;
|
|
20
|
+
value: string;
|
|
21
|
+
source: string;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
export declare function createGovernanceSnapshot(snapshot: GovernanceSnapshot): GovernanceSnapshot;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function createGovernanceSnapshot(snapshot) {
|
|
2
|
+
return {
|
|
3
|
+
...snapshot,
|
|
4
|
+
allowedAdapters: [...snapshot.allowedAdapters],
|
|
5
|
+
allowedModels: [...snapshot.allowedModels],
|
|
6
|
+
verifierRules: [...snapshot.verifierRules],
|
|
7
|
+
provenance: snapshot.provenance.map((entry) => ({
|
|
8
|
+
...entry
|
|
9
|
+
}))
|
|
10
|
+
};
|
|
11
|
+
}
|