@wrongstack/core 0.9.19 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -33
- package/dist/{agent-bridge-DMVOX0cF.d.ts → agent-bridge-DBBGP5O4.d.ts} +1 -1
- package/dist/{agent-subagent-runner-C4qt9e5Y.d.ts → agent-subagent-runner-KwufTWwn.d.ts} +3 -4
- package/dist/compactor-D1RHFRmF.d.ts +41 -0
- package/dist/{config-CWva0qoL.d.ts → config-CJXBka2r.d.ts} +38 -2
- package/dist/{context-BRNbHmRM.d.ts → context-7u93AcGD.d.ts} +140 -0
- package/dist/coordination/index.d.ts +13 -13
- package/dist/coordination/index.js +786 -200
- package/dist/coordination/index.js.map +1 -1
- package/dist/{default-config-Uzla85H-.d.ts → default-config-DEXI4jsl.d.ts} +10 -1
- package/dist/defaults/index.d.ts +24 -24
- package/dist/defaults/index.js +1612 -528
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-CiG9qUM_.d.ts → events-Bw1K5E6K.d.ts} +49 -1
- package/dist/execution/index.d.ts +46 -32
- package/dist/execution/index.js +663 -169
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/extension/index.js.map +1 -1
- package/dist/goal-store-BeRsj7YX.d.ts +188 -0
- package/dist/{index-p95HQ22A.d.ts → index-DIt5TIaF.d.ts} +8 -8
- package/dist/{index-aizK8olO.d.ts → index-DgQWnZxP.d.ts} +11 -8
- package/dist/index.d.ts +338 -41
- package/dist/index.js +2747 -787
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +36 -0
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +9 -9
- package/dist/kernel/index.js +57 -8
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-BkVEqkRe.d.ts → mcp-servers-BgINZzuo.d.ts} +25 -3
- package/dist/models/index.d.ts +3 -3
- package/dist/models/index.js +164 -11
- package/dist/models/index.js.map +1 -1
- package/dist/models-registry-gwMAo6E3.d.ts +86 -0
- package/dist/{multi-agent-3ZnTB1aT.d.ts → multi-agent-C1O8EFzb.d.ts} +77 -24
- package/dist/{multi-agent-coordinator-bRaI_aD1.d.ts → multi-agent-coordinator-DoVSBFNx.d.ts} +20 -2
- package/dist/{null-fleet-bus-DKM3Iy9d.d.ts → null-fleet-bus-T-s3JaOt.d.ts} +413 -110
- package/dist/observability/index.d.ts +2 -2
- package/dist/{path-resolver-TcJfc29Y.d.ts → path-resolver-BfyK-I7w.d.ts} +2 -2
- package/dist/{permission-bPuzAy4x.d.ts → permission-B6sldrSp.d.ts} +1 -1
- package/dist/{permission-policy-BUQSutpl.d.ts → permission-policy-CtNscWOA.d.ts} +10 -9
- package/dist/{plan-templates-fkQTyz3U.d.ts → plan-templates-BWs6Je7j.d.ts} +8 -8
- package/dist/{provider-runner-BEpikbbN.d.ts → provider-runner-BmPe2RuU.d.ts} +3 -3
- package/dist/{retry-policy-BYkq0ugs.d.ts → retry-policy-KF18W4dg.d.ts} +1 -1
- package/dist/sdd/index.d.ts +9 -10
- package/dist/sdd/index.js +350 -122
- package/dist/sdd/index.js.map +1 -1
- package/dist/security/index.d.ts +65 -4
- package/dist/security/index.js +67 -19
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-pox8abg0.d.ts → selector-DmXxpFyM.d.ts} +1 -1
- package/dist/{session-reader-CSWcb5Ga.d.ts → session-reader-CCSBfQmd.d.ts} +2 -2
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.js +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +392 -8
- package/dist/storage/index.js +796 -40
- package/dist/storage/index.js.map +1 -1
- package/dist/{system-prompt-Bs-Wliab.d.ts → system-prompt-CM6zOhd2.d.ts} +19 -1
- package/dist/{tool-executor-Boo3dekH.d.ts → tool-executor-D7RxLtg4.d.ts} +9 -4
- package/dist/types/index.d.ts +16 -16
- package/dist/types/index.js +404 -14
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +40 -8
- package/dist/utils/index.js +127 -57
- package/dist/utils/index.js.map +1 -1
- package/dist/{wstack-paths-BCgmTNlG.d.ts → wstack-paths-eMXnY1_X.d.ts} +8 -0
- package/package.json +1 -1
- package/dist/compactor-DVTKL7XD.d.ts +0 -23
- package/dist/goal-store-C7jcumEh.d.ts +0 -96
- package/dist/models-registry-OG_30xqZ.d.ts +0 -46
package/dist/types/index.js
CHANGED
|
@@ -66,8 +66,10 @@ var ERROR_CODES = {
|
|
|
66
66
|
// Container / Registry
|
|
67
67
|
CONTAINER_TOKEN_ALREADY_BOUND: "CONTAINER_TOKEN_ALREADY_BOUND",
|
|
68
68
|
CONTAINER_TOKEN_NOT_BOUND: "CONTAINER_TOKEN_NOT_BOUND",
|
|
69
|
+
CONTAINER_CIRCULAR_DEPENDENCY: "CONTAINER_CIRCULAR_DEPENDENCY",
|
|
69
70
|
REGISTRY_DUPLICATE: "REGISTRY_DUPLICATE",
|
|
70
71
|
REGISTRY_NOT_FOUND: "REGISTRY_NOT_FOUND",
|
|
72
|
+
REGISTRY_INVALID: "REGISTRY_INVALID",
|
|
71
73
|
// File system
|
|
72
74
|
FS_READ_FAILED: "FS_READ_FAILED",
|
|
73
75
|
FS_WRITE_FAILED: "FS_WRITE_FAILED",
|
|
@@ -315,6 +317,14 @@ var DEFAULT_CONTEXT_CONFIG = Object.freeze({
|
|
|
315
317
|
var DEFAULT_AUTONOMY_CONFIG = Object.freeze({
|
|
316
318
|
autoProceedDelayMs: 45e3
|
|
317
319
|
});
|
|
320
|
+
var DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({
|
|
321
|
+
auditLevel: "standard",
|
|
322
|
+
sampling: {
|
|
323
|
+
toolProgress: {
|
|
324
|
+
sampleRate: 8
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
318
328
|
|
|
319
329
|
// src/types/secret-vault.ts
|
|
320
330
|
var ENCRYPTED_PREFIX = "enc:v1:";
|
|
@@ -867,6 +877,54 @@ function estimateToolResultTokens(content) {
|
|
|
867
877
|
function estimateTextTokens(text) {
|
|
868
878
|
return RoughTokenEstimate(text);
|
|
869
879
|
}
|
|
880
|
+
function estimateToolDefTokens(tool) {
|
|
881
|
+
return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
|
|
882
|
+
}
|
|
883
|
+
function estimateRequestTokens(messages, systemPrompt, tools) {
|
|
884
|
+
let messagesTokens = 0;
|
|
885
|
+
if (typeof messages === "string") {
|
|
886
|
+
messagesTokens = RoughTokenEstimate(messages);
|
|
887
|
+
} else if (Array.isArray(messages)) {
|
|
888
|
+
for (const m of messages) {
|
|
889
|
+
if (typeof m === "object" && m !== null && "content" in m) {
|
|
890
|
+
const content = m.content;
|
|
891
|
+
if (typeof content === "string") {
|
|
892
|
+
messagesTokens += RoughTokenEstimate(content);
|
|
893
|
+
} else if (Array.isArray(content)) {
|
|
894
|
+
for (const b of content) {
|
|
895
|
+
if (typeof b === "object" && b !== null) {
|
|
896
|
+
if (b.type === "text") {
|
|
897
|
+
messagesTokens += RoughTokenEstimate(b.text);
|
|
898
|
+
} else {
|
|
899
|
+
messagesTokens += RoughTokenEstimate(JSON.stringify(b));
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
let systemTokens = 0;
|
|
908
|
+
if (typeof systemPrompt === "string") {
|
|
909
|
+
systemTokens = RoughTokenEstimate(systemPrompt);
|
|
910
|
+
} else if (Array.isArray(systemPrompt)) {
|
|
911
|
+
for (const b of systemPrompt) {
|
|
912
|
+
if (typeof b === "object" && b !== null && b.type === "text") {
|
|
913
|
+
systemTokens += RoughTokenEstimate(b.text);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
let toolsTokens = 0;
|
|
918
|
+
for (const t of tools) {
|
|
919
|
+
toolsTokens += estimateToolDefTokens(t);
|
|
920
|
+
}
|
|
921
|
+
return {
|
|
922
|
+
messages: messagesTokens,
|
|
923
|
+
systemPrompt: systemTokens,
|
|
924
|
+
tools: toolsTokens,
|
|
925
|
+
total: messagesTokens + systemTokens + toolsTokens
|
|
926
|
+
};
|
|
927
|
+
}
|
|
870
928
|
|
|
871
929
|
// src/utils/message-invariants.ts
|
|
872
930
|
function repairToolUseAdjacency(messages) {
|
|
@@ -972,6 +1030,7 @@ var HybridCompactor = class {
|
|
|
972
1030
|
}
|
|
973
1031
|
async compact(ctx, opts = {}) {
|
|
974
1032
|
const beforeTokens = this.estimateMessages(ctx.messages);
|
|
1033
|
+
const beforeFull = this.estimateFullRequest(ctx);
|
|
975
1034
|
const reductions = [];
|
|
976
1035
|
const policy = readContextWindowPolicy(ctx);
|
|
977
1036
|
const preserveK = policy?.preserveK ?? this.preserveK;
|
|
@@ -987,9 +1046,12 @@ var HybridCompactor = class {
|
|
|
987
1046
|
ctx.state.replaceMessages(repaired.messages);
|
|
988
1047
|
}
|
|
989
1048
|
const afterTokens = this.estimateMessages(ctx.messages);
|
|
1049
|
+
const afterFull = this.estimateFullRequest(ctx);
|
|
990
1050
|
return {
|
|
991
1051
|
before: beforeTokens,
|
|
992
1052
|
after: afterTokens,
|
|
1053
|
+
fullRequestTokensBefore: beforeFull,
|
|
1054
|
+
fullRequestTokensAfter: afterFull,
|
|
993
1055
|
reductions,
|
|
994
1056
|
repaired: repaired.report.changed ? {
|
|
995
1057
|
removedToolUses: repaired.report.removedToolUses,
|
|
@@ -998,6 +1060,14 @@ var HybridCompactor = class {
|
|
|
998
1060
|
} : void 0
|
|
999
1061
|
};
|
|
1000
1062
|
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Estimate the full API request token count: messages + systemPrompt + toolDefs.
|
|
1065
|
+
* This is the accurate figure for context-window pressure monitoring.
|
|
1066
|
+
*/
|
|
1067
|
+
estimateFullRequest(ctx) {
|
|
1068
|
+
const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
|
|
1069
|
+
return breakdown.total;
|
|
1070
|
+
}
|
|
1001
1071
|
eliseOldToolResults(ctx, preserveK = this.preserveK, eliseThreshold = this.eliseThreshold) {
|
|
1002
1072
|
const messages = ctx.messages;
|
|
1003
1073
|
let pairCount = 0;
|
|
@@ -1421,6 +1491,71 @@ var DefaultSecretScrubber = class {
|
|
|
1421
1491
|
return visit(obj);
|
|
1422
1492
|
}
|
|
1423
1493
|
};
|
|
1494
|
+
|
|
1495
|
+
// src/utils/merge-models-payload.ts
|
|
1496
|
+
function mergeModelsPayload(base, overlay) {
|
|
1497
|
+
const out = {};
|
|
1498
|
+
for (const [id, provider] of Object.entries(base)) {
|
|
1499
|
+
out[id] = cloneProvider(provider);
|
|
1500
|
+
}
|
|
1501
|
+
for (const [id, ovProvider] of Object.entries(overlay)) {
|
|
1502
|
+
const existing = out[id];
|
|
1503
|
+
out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
|
|
1504
|
+
}
|
|
1505
|
+
return out;
|
|
1506
|
+
}
|
|
1507
|
+
function mergeProvider(base, overlay) {
|
|
1508
|
+
const models = {};
|
|
1509
|
+
for (const [mid, m] of Object.entries(base.models ?? {})) {
|
|
1510
|
+
models[mid] = { ...m };
|
|
1511
|
+
}
|
|
1512
|
+
for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
|
|
1513
|
+
const existing = models[mid];
|
|
1514
|
+
models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
|
|
1515
|
+
}
|
|
1516
|
+
return {
|
|
1517
|
+
...base,
|
|
1518
|
+
// Overlay scalar fields win when explicitly provided; otherwise keep base.
|
|
1519
|
+
...stripUndefined({
|
|
1520
|
+
id: overlay.id,
|
|
1521
|
+
name: overlay.name,
|
|
1522
|
+
npm: overlay.npm,
|
|
1523
|
+
api: overlay.api,
|
|
1524
|
+
env: overlay.env,
|
|
1525
|
+
doc: overlay.doc
|
|
1526
|
+
}),
|
|
1527
|
+
models
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
function mergeModel(base, overlay) {
|
|
1531
|
+
const merged = { ...base, ...overlay };
|
|
1532
|
+
if (base.limit || overlay.limit) {
|
|
1533
|
+
merged.limit = { ...base.limit, ...overlay.limit };
|
|
1534
|
+
}
|
|
1535
|
+
if (base.cost || overlay.cost) {
|
|
1536
|
+
merged.cost = { ...base.cost, ...overlay.cost };
|
|
1537
|
+
}
|
|
1538
|
+
if (base.modalities || overlay.modalities) {
|
|
1539
|
+
merged.modalities = { ...base.modalities, ...overlay.modalities };
|
|
1540
|
+
}
|
|
1541
|
+
return merged;
|
|
1542
|
+
}
|
|
1543
|
+
function cloneProvider(p) {
|
|
1544
|
+
const models = {};
|
|
1545
|
+
for (const [mid, m] of Object.entries(p.models ?? {})) {
|
|
1546
|
+
models[mid] = { ...m };
|
|
1547
|
+
}
|
|
1548
|
+
return { ...p, models };
|
|
1549
|
+
}
|
|
1550
|
+
function stripUndefined(obj) {
|
|
1551
|
+
const out = {};
|
|
1552
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
1553
|
+
if (v !== void 0) out[k] = v;
|
|
1554
|
+
}
|
|
1555
|
+
return out;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
// src/models/models-registry.ts
|
|
1424
1559
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
1425
1560
|
var DEFAULT_TTL_SECONDS = 24 * 3600;
|
|
1426
1561
|
var FAMILY_BY_NPM = {
|
|
@@ -1448,7 +1583,10 @@ function classifyFamily(npm) {
|
|
|
1448
1583
|
return FAMILY_BY_NPM[npm] ?? "unsupported";
|
|
1449
1584
|
}
|
|
1450
1585
|
var DefaultModelsRegistry = class {
|
|
1586
|
+
/** Merged (base + overlay) payload — what every reader sees. */
|
|
1451
1587
|
payload;
|
|
1588
|
+
/** Memoised overlay payload (in-memory / fetched / file). */
|
|
1589
|
+
overlayPayload;
|
|
1452
1590
|
fetchedAt;
|
|
1453
1591
|
cacheFile;
|
|
1454
1592
|
url;
|
|
@@ -1456,6 +1594,10 @@ var DefaultModelsRegistry = class {
|
|
|
1456
1594
|
fetchImpl;
|
|
1457
1595
|
seed;
|
|
1458
1596
|
maxStaleAgeMs;
|
|
1597
|
+
overlay;
|
|
1598
|
+
overlayUrl;
|
|
1599
|
+
overlayFile;
|
|
1600
|
+
overlayCacheFile;
|
|
1459
1601
|
constructor(opts) {
|
|
1460
1602
|
this.cacheFile = opts.cacheFile;
|
|
1461
1603
|
this.url = opts.url ?? DEFAULT_URL;
|
|
@@ -1464,6 +1606,10 @@ var DefaultModelsRegistry = class {
|
|
|
1464
1606
|
this.seed = opts.seed;
|
|
1465
1607
|
const maxStaleSeconds = opts.maxStaleAgeSeconds ?? 7 * 24 * 3600;
|
|
1466
1608
|
this.maxStaleAgeMs = maxStaleSeconds * 1e3;
|
|
1609
|
+
this.overlay = opts.overlay;
|
|
1610
|
+
this.overlayUrl = opts.overlayUrl;
|
|
1611
|
+
this.overlayFile = opts.overlayFile;
|
|
1612
|
+
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path4.join(path4.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
|
|
1467
1613
|
}
|
|
1468
1614
|
async load(opts = {}) {
|
|
1469
1615
|
if (this.payload && !opts.force) return this.payload;
|
|
@@ -1472,27 +1618,45 @@ var DefaultModelsRegistry = class {
|
|
|
1472
1618
|
this.fetchedAt = /* @__PURE__ */ new Date();
|
|
1473
1619
|
return this.payload;
|
|
1474
1620
|
}
|
|
1621
|
+
const overlay = await this.loadOverlay(opts);
|
|
1622
|
+
const base = await this.loadBase(opts, Object.keys(overlay).length > 0);
|
|
1623
|
+
this.payload = mergeModelsPayload(base, overlay);
|
|
1624
|
+
return this.payload;
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Load the models.dev base payload: fresh cache → network → stale cache.
|
|
1628
|
+
* On total failure, degrade to `{}` (so a non-empty overlay still drives
|
|
1629
|
+
* the catalog) rather than throwing — unless there's no curated overlay to
|
|
1630
|
+
* fall back on, in which case the original error propagates so pure-
|
|
1631
|
+
* models.dev setups still surface the problem.
|
|
1632
|
+
*/
|
|
1633
|
+
async loadBase(opts = {}, overlayAvailable = false) {
|
|
1475
1634
|
if (!opts.force) {
|
|
1476
|
-
const cached = await this.
|
|
1635
|
+
const cached = await this.readCacheAt(this.cacheFile);
|
|
1477
1636
|
if (cached && this.isFresh(cached.fetchedAt)) {
|
|
1478
|
-
this.payload = cached.payload;
|
|
1479
1637
|
this.fetchedAt = new Date(cached.fetchedAt);
|
|
1480
1638
|
return cached.payload;
|
|
1481
1639
|
}
|
|
1482
1640
|
}
|
|
1483
1641
|
try {
|
|
1484
|
-
return await this.
|
|
1642
|
+
return await this.refreshBase();
|
|
1485
1643
|
} catch (err) {
|
|
1486
|
-
const cached = await this.
|
|
1644
|
+
const cached = await this.readCacheAt(this.cacheFile);
|
|
1487
1645
|
if (cached && this.isWithinMaxStaleAge(cached.fetchedAt)) {
|
|
1488
|
-
this.payload = cached.payload;
|
|
1489
1646
|
this.fetchedAt = new Date(cached.fetchedAt);
|
|
1490
1647
|
return cached.payload;
|
|
1491
1648
|
}
|
|
1649
|
+
if (overlayAvailable) {
|
|
1650
|
+
console.warn(
|
|
1651
|
+
`ModelsRegistry: models.dev unavailable (${err instanceof Error ? err.message : String(err)}); serving curated overlay only.`
|
|
1652
|
+
);
|
|
1653
|
+
return {};
|
|
1654
|
+
}
|
|
1492
1655
|
throw err;
|
|
1493
1656
|
}
|
|
1494
1657
|
}
|
|
1495
|
-
|
|
1658
|
+
/** Fetch + cache the models.dev base. Throws on failure (used by `refresh`). */
|
|
1659
|
+
async refreshBase() {
|
|
1496
1660
|
const res = await this.fetchImpl(this.url, {
|
|
1497
1661
|
method: "GET",
|
|
1498
1662
|
headers: { accept: "application/json" }
|
|
@@ -1501,7 +1665,6 @@ var DefaultModelsRegistry = class {
|
|
|
1501
1665
|
throw new Error(`ModelsRegistry: HTTP ${res.status} fetching ${this.url}`);
|
|
1502
1666
|
}
|
|
1503
1667
|
const json = await res.json();
|
|
1504
|
-
this.payload = json;
|
|
1505
1668
|
this.fetchedAt = /* @__PURE__ */ new Date();
|
|
1506
1669
|
const envelope = {
|
|
1507
1670
|
fetchedAt: this.fetchedAt.toISOString(),
|
|
@@ -1511,6 +1674,68 @@ var DefaultModelsRegistry = class {
|
|
|
1511
1674
|
await atomicWrite(this.cacheFile, JSON.stringify(envelope));
|
|
1512
1675
|
return json;
|
|
1513
1676
|
}
|
|
1677
|
+
/**
|
|
1678
|
+
* Resolve the curated overlay, memoised. Order: in-memory `overlay` →
|
|
1679
|
+
* fetched `overlayUrl` (cached, same TTL/stale rules) → `overlayFile` on
|
|
1680
|
+
* disk. Never throws — a missing/broken overlay yields `{}`.
|
|
1681
|
+
*/
|
|
1682
|
+
async loadOverlay(opts = {}) {
|
|
1683
|
+
if (this.overlayPayload && !opts.force) return this.overlayPayload;
|
|
1684
|
+
if (this.overlay) {
|
|
1685
|
+
this.overlayPayload = this.overlay;
|
|
1686
|
+
return this.overlayPayload;
|
|
1687
|
+
}
|
|
1688
|
+
const fetched = await this.loadOverlayFromUrl(opts);
|
|
1689
|
+
if (fetched) {
|
|
1690
|
+
this.overlayPayload = fetched;
|
|
1691
|
+
return fetched;
|
|
1692
|
+
}
|
|
1693
|
+
const fromFile = await this.readOverlayFile();
|
|
1694
|
+
this.overlayPayload = fromFile ?? {};
|
|
1695
|
+
return this.overlayPayload;
|
|
1696
|
+
}
|
|
1697
|
+
async loadOverlayFromUrl(opts) {
|
|
1698
|
+
if (!this.overlayUrl || !this.overlayCacheFile) return void 0;
|
|
1699
|
+
if (!opts.force) {
|
|
1700
|
+
const cached = await this.readCacheAt(this.overlayCacheFile);
|
|
1701
|
+
if (cached && this.isFresh(cached.fetchedAt)) return cached.payload;
|
|
1702
|
+
}
|
|
1703
|
+
try {
|
|
1704
|
+
const res = await this.fetchImpl(this.overlayUrl, {
|
|
1705
|
+
method: "GET",
|
|
1706
|
+
headers: { accept: "application/json" }
|
|
1707
|
+
});
|
|
1708
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1709
|
+
const json = await res.json();
|
|
1710
|
+
const envelope = {
|
|
1711
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1712
|
+
url: this.overlayUrl,
|
|
1713
|
+
payload: json
|
|
1714
|
+
};
|
|
1715
|
+
await atomicWrite(this.overlayCacheFile, JSON.stringify(envelope)).catch(() => {
|
|
1716
|
+
});
|
|
1717
|
+
return json;
|
|
1718
|
+
} catch {
|
|
1719
|
+
const cached = await this.readCacheAt(this.overlayCacheFile);
|
|
1720
|
+
if (cached && this.isWithinMaxStaleAge(cached.fetchedAt)) return cached.payload;
|
|
1721
|
+
return void 0;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
async readOverlayFile() {
|
|
1725
|
+
if (!this.overlayFile) return void 0;
|
|
1726
|
+
try {
|
|
1727
|
+
const raw = await fs.readFile(this.overlayFile, "utf8");
|
|
1728
|
+
return JSON.parse(raw);
|
|
1729
|
+
} catch {
|
|
1730
|
+
return void 0;
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
async refresh() {
|
|
1734
|
+
const base = await this.refreshBase();
|
|
1735
|
+
const overlay = await this.loadOverlay({ force: true });
|
|
1736
|
+
this.payload = mergeModelsPayload(base, overlay);
|
|
1737
|
+
return this.payload;
|
|
1738
|
+
}
|
|
1514
1739
|
async listProviders() {
|
|
1515
1740
|
const payload = await this.load();
|
|
1516
1741
|
return Object.values(payload).map((p) => this.resolveProvider(p));
|
|
@@ -1551,7 +1776,7 @@ var DefaultModelsRegistry = class {
|
|
|
1551
1776
|
}
|
|
1552
1777
|
async ageSeconds() {
|
|
1553
1778
|
if (!this.fetchedAt) {
|
|
1554
|
-
const cached = await this.
|
|
1779
|
+
const cached = await this.readCacheAt(this.cacheFile);
|
|
1555
1780
|
if (!cached) return Number.POSITIVE_INFINITY;
|
|
1556
1781
|
return (Date.now() - new Date(cached.fetchedAt).getTime()) / 1e3;
|
|
1557
1782
|
}
|
|
@@ -1575,9 +1800,9 @@ var DefaultModelsRegistry = class {
|
|
|
1575
1800
|
isWithinMaxStaleAge(fetchedAtIso) {
|
|
1576
1801
|
return Date.now() - new Date(fetchedAtIso).getTime() < this.maxStaleAgeMs;
|
|
1577
1802
|
}
|
|
1578
|
-
async
|
|
1803
|
+
async readCacheAt(file) {
|
|
1579
1804
|
try {
|
|
1580
|
-
const raw = await fs.readFile(
|
|
1805
|
+
const raw = await fs.readFile(file, "utf8");
|
|
1581
1806
|
return JSON.parse(raw);
|
|
1582
1807
|
} catch {
|
|
1583
1808
|
return void 0;
|
|
@@ -2149,6 +2374,141 @@ function topologicalSort(graph) {
|
|
|
2149
2374
|
return result;
|
|
2150
2375
|
}
|
|
2151
2376
|
|
|
2377
|
+
// src/security/capabilities.ts
|
|
2378
|
+
var ToolCapabilities = {
|
|
2379
|
+
/** Can execute arbitrary commands in the user's shell (the `bash` tool). */
|
|
2380
|
+
SHELL_ARBITRARY: "shell.arbitrary",
|
|
2381
|
+
/** Can write / modify / delete files inside the project. */
|
|
2382
|
+
FS_WRITE: "fs.write",
|
|
2383
|
+
/** Can write files outside the current project root (very high risk). */
|
|
2384
|
+
FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
|
|
2385
|
+
/** Proxies tools from external MCP servers (unknown capability). */
|
|
2386
|
+
MCP_PROXY: "mcp.proxy",
|
|
2387
|
+
/** Can spawn or manage subagents / multi-agent tasks. */
|
|
2388
|
+
SUBAGENT_SPAWN: "subagent.spawn",
|
|
2389
|
+
/** Can mutate global or session configuration / trust state. */
|
|
2390
|
+
CONFIG_MUTATE: "config.mutate",
|
|
2391
|
+
/** Can install packages or run package managers with side effects. */
|
|
2392
|
+
PACKAGE_INSTALL: "package.install"
|
|
2393
|
+
};
|
|
2394
|
+
var DANGEROUS_FOR_SUBAGENTS = [
|
|
2395
|
+
ToolCapabilities.SHELL_ARBITRARY,
|
|
2396
|
+
ToolCapabilities.FS_WRITE,
|
|
2397
|
+
ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
|
|
2398
|
+
ToolCapabilities.MCP_PROXY,
|
|
2399
|
+
ToolCapabilities.SUBAGENT_SPAWN,
|
|
2400
|
+
ToolCapabilities.CONFIG_MUTATE,
|
|
2401
|
+
ToolCapabilities.PACKAGE_INSTALL
|
|
2402
|
+
];
|
|
2403
|
+
function hasDangerousCapabilityForSubagents(toolOrCaps) {
|
|
2404
|
+
if (!toolOrCaps) return false;
|
|
2405
|
+
const input = toolOrCaps;
|
|
2406
|
+
const caps = Array.isArray(input) ? input : input?.capabilities ?? [];
|
|
2407
|
+
return caps.some((c) => DANGEROUS_FOR_SUBAGENTS.includes(c));
|
|
2408
|
+
}
|
|
2409
|
+
function getDangerousCapabilities(toolOrCaps) {
|
|
2410
|
+
if (!toolOrCaps) return [];
|
|
2411
|
+
const input = toolOrCaps;
|
|
2412
|
+
const caps = Array.isArray(input) ? input : input?.capabilities ?? [];
|
|
2413
|
+
return caps.filter(
|
|
2414
|
+
(c) => DANGEROUS_FOR_SUBAGENTS.includes(c)
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
// src/utils/json-schema-validate.ts
|
|
2419
|
+
function validateAgainstSchema(value, schema) {
|
|
2420
|
+
const errors = [];
|
|
2421
|
+
walk2(value, schema, "", errors);
|
|
2422
|
+
return { ok: errors.length === 0, errors };
|
|
2423
|
+
}
|
|
2424
|
+
function walk2(value, schema, path6, errors) {
|
|
2425
|
+
if (schema.enum !== void 0) {
|
|
2426
|
+
if (!schema.enum.some((e) => deepEqual(e, value))) {
|
|
2427
|
+
errors.push({
|
|
2428
|
+
path: path6 || "<root>",
|
|
2429
|
+
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
2430
|
+
});
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
if (typeof schema.type === "string") {
|
|
2435
|
+
if (!checkType(value, schema.type)) {
|
|
2436
|
+
errors.push({
|
|
2437
|
+
path: path6 || "<root>",
|
|
2438
|
+
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
2439
|
+
});
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
if (schema.type === "object" && isPlainObject(value)) {
|
|
2444
|
+
const obj = value;
|
|
2445
|
+
for (const req of schema.required ?? []) {
|
|
2446
|
+
if (!(req in obj)) {
|
|
2447
|
+
errors.push({ path: joinPath(path6, req), message: "required property missing" });
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
if (schema.properties) {
|
|
2451
|
+
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
2452
|
+
if (key in obj) {
|
|
2453
|
+
walk2(obj[key], subSchema, joinPath(path6, key), errors);
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
2459
|
+
value.forEach((item, i) => walk2(item, schema.items, `${path6}[${i}]`, errors));
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
function checkType(value, type) {
|
|
2463
|
+
switch (type) {
|
|
2464
|
+
case "string":
|
|
2465
|
+
return typeof value === "string";
|
|
2466
|
+
case "number":
|
|
2467
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
2468
|
+
case "integer":
|
|
2469
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
2470
|
+
case "boolean":
|
|
2471
|
+
return typeof value === "boolean";
|
|
2472
|
+
case "null":
|
|
2473
|
+
return value === null;
|
|
2474
|
+
case "array":
|
|
2475
|
+
return Array.isArray(value);
|
|
2476
|
+
case "object":
|
|
2477
|
+
return isPlainObject(value);
|
|
2478
|
+
default:
|
|
2479
|
+
return true;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
function isPlainObject(v) {
|
|
2483
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2484
|
+
}
|
|
2485
|
+
function describeType(v) {
|
|
2486
|
+
if (v === null) return "null";
|
|
2487
|
+
if (Array.isArray(v)) return "array";
|
|
2488
|
+
return typeof v;
|
|
2489
|
+
}
|
|
2490
|
+
function joinPath(parent, key) {
|
|
2491
|
+
if (!parent) return key;
|
|
2492
|
+
return `${parent}.${key}`;
|
|
2493
|
+
}
|
|
2494
|
+
function deepEqual(a, b) {
|
|
2495
|
+
if (a === b) return true;
|
|
2496
|
+
if (typeof a !== typeof b) return false;
|
|
2497
|
+
if (a === null || b === null) return a === b;
|
|
2498
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2499
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
2500
|
+
}
|
|
2501
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
2502
|
+
const ak = Object.keys(a);
|
|
2503
|
+
const bk = Object.keys(b);
|
|
2504
|
+
if (ak.length !== bk.length) return false;
|
|
2505
|
+
return ak.every(
|
|
2506
|
+
(k) => deepEqual(a[k], b[k])
|
|
2507
|
+
);
|
|
2508
|
+
}
|
|
2509
|
+
return false;
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2152
2512
|
// src/utils/tool-output-serializer.ts
|
|
2153
2513
|
function createToolOutputSerializer(opts = {}) {
|
|
2154
2514
|
const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
|
|
@@ -2230,18 +2590,45 @@ var ToolExecutor = class {
|
|
|
2230
2590
|
budget = this.decrementBudget(result, budget);
|
|
2231
2591
|
return { result, tool, durationMs: Date.now() - start };
|
|
2232
2592
|
}
|
|
2593
|
+
const validation = validateAgainstSchema(use.input, tool.inputSchema);
|
|
2594
|
+
if (!validation.ok) {
|
|
2595
|
+
const errorDetails = validation.errors.map((e) => ` - ${e.path || "input"}: ${e.message}`).join("\n");
|
|
2596
|
+
const result = {
|
|
2597
|
+
type: "tool_result",
|
|
2598
|
+
tool_use_id: use.id,
|
|
2599
|
+
content: `Invalid arguments for tool "${tool.name}".
|
|
2600
|
+
|
|
2601
|
+
Validation errors:
|
|
2602
|
+
${errorDetails}
|
|
2603
|
+
|
|
2604
|
+
Please call the tool again with arguments that match its inputSchema. You can use the "tool-help" tool with name="${tool.name}" to see the exact expected schema.`,
|
|
2605
|
+
is_error: true
|
|
2606
|
+
};
|
|
2607
|
+
budget = this.decrementBudget(result, budget);
|
|
2608
|
+
return { result, tool, durationMs: Date.now() - start };
|
|
2609
|
+
}
|
|
2610
|
+
const toolDangerousCaps = getDangerousCapabilities(tool);
|
|
2611
|
+
if (toolDangerousCaps.length > 0) {
|
|
2612
|
+
if (this.opts.events) ;
|
|
2613
|
+
}
|
|
2233
2614
|
if (hasMalformedArguments(use.input)) {
|
|
2234
2615
|
const result = this.malformedInputResult(use, extractMalformedRaw(use.input));
|
|
2235
2616
|
budget = this.decrementBudget(result, budget);
|
|
2236
2617
|
return { result, tool, durationMs: Date.now() - start };
|
|
2237
2618
|
}
|
|
2238
2619
|
const decision = await this.opts.permissionPolicy.evaluate(tool, use.input, ctx);
|
|
2239
|
-
|
|
2620
|
+
let effectivePermission = decision.permission;
|
|
2621
|
+
const policy = this.opts.permissionPolicy;
|
|
2622
|
+
const yolo = policy.getYolo?.() === true || policy.getForceAllYolo?.() === true;
|
|
2623
|
+
if (toolDangerousCaps.length > 0 && effectivePermission === "auto" && !yolo) {
|
|
2624
|
+
effectivePermission = "confirm";
|
|
2625
|
+
}
|
|
2626
|
+
if (effectivePermission === "deny") {
|
|
2240
2627
|
const result = this.deniedResult(use, decision.reason);
|
|
2241
2628
|
budget = this.decrementBudget(result, budget);
|
|
2242
2629
|
return { result, tool, durationMs: Date.now() - start };
|
|
2243
2630
|
}
|
|
2244
|
-
if (
|
|
2631
|
+
if (effectivePermission === "confirm") {
|
|
2245
2632
|
if (this.opts.confirmAwaiter) {
|
|
2246
2633
|
const choice = await this.opts.confirmAwaiter(tool, use.input, use.id, tool.name);
|
|
2247
2634
|
if (choice !== "yes" && choice !== "always") {
|
|
@@ -2266,10 +2653,13 @@ var ToolExecutor = class {
|
|
|
2266
2653
|
return { result: pending, tool, durationMs: Date.now() - start };
|
|
2267
2654
|
}
|
|
2268
2655
|
}
|
|
2656
|
+
const toolCapsForAudit = hasDangerousCapabilityForSubagents(tool) ? tool.capabilities ?? [] : [];
|
|
2269
2657
|
const span = this.opts.tracer?.startSpan(`tool.${tool.name}`, {
|
|
2270
2658
|
"tool.name": tool.name,
|
|
2271
2659
|
"tool.mutating": tool.mutating,
|
|
2272
|
-
"tool.permission": tool.permission
|
|
2660
|
+
"tool.permission": tool.permission,
|
|
2661
|
+
"tool.capabilities": JSON.stringify(tool.capabilities ?? []),
|
|
2662
|
+
"tool.has_dangerous_capabilities": toolCapsForAudit.length > 0
|
|
2273
2663
|
});
|
|
2274
2664
|
try {
|
|
2275
2665
|
const result = await this.executeTool(tool, use, ctx, budget);
|
|
@@ -2814,6 +3204,6 @@ function renderPlainText(meta, events) {
|
|
|
2814
3204
|
return lines.join("\n");
|
|
2815
3205
|
}
|
|
2816
3206
|
|
|
2817
|
-
export { AgentError, CONTEXT_WINDOW_MODES, ConfigError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_TOOLS_CONFIG, DefaultErrorHandler, DefaultLogger, DefaultModelsRegistry, DefaultPathResolver, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultTokenCounter, ERROR_CODES, FsError, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, PluginError, ProviderError, SessionError, ToolError, ToolExecutor, WrongStackError, asBlocks, asText, buildRecoveryStrategies, classifyFamily, computeTaskProgress, createMessage, decryptConfigSecrets, encryptConfigSecrets, findCriticalPath, formatContextWindowModeList, getContextWindowMode, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, migratePlaintextSecrets, resolveContextWindowPolicy, rewriteConfigEncrypted, toWrongStackError, topologicalSort };
|
|
3207
|
+
export { AgentError, CONTEXT_WINDOW_MODES, ConfigError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SESSION_LOGGING_CONFIG, DEFAULT_SPEC_TEMPLATE, DEFAULT_TOOLS_CONFIG, DefaultErrorHandler, DefaultLogger, DefaultModelsRegistry, DefaultPathResolver, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultTokenCounter, ERROR_CODES, FsError, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, PluginError, ProviderError, SessionError, ToolError, ToolExecutor, WrongStackError, asBlocks, asText, buildRecoveryStrategies, classifyFamily, computeTaskProgress, createMessage, decryptConfigSecrets, encryptConfigSecrets, findCriticalPath, formatContextWindowModeList, getContextWindowMode, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, migratePlaintextSecrets, resolveContextWindowPolicy, rewriteConfigEncrypted, toWrongStackError, topologicalSort };
|
|
2818
3208
|
//# sourceMappingURL=index.js.map
|
|
2819
3209
|
//# sourceMappingURL=index.js.map
|