@atbash/sdk 0.10.9-dev.0 → 0.10.10-dev.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/dist/browser.d.mts +83 -17
- package/dist/browser.mjs +120 -67
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +83 -17
- package/dist/index.d.ts +83 -17
- package/dist/index.js +234 -105
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +234 -105
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -3021,8 +3021,8 @@ var HttpClient = class {
|
|
|
3021
3021
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
3022
3022
|
this.timeoutMs = timeoutMs;
|
|
3023
3023
|
}
|
|
3024
|
-
buildUrl(
|
|
3025
|
-
const url = new URL(this.baseUrl +
|
|
3024
|
+
buildUrl(path7, query) {
|
|
3025
|
+
const url = new URL(this.baseUrl + path7);
|
|
3026
3026
|
if (query) {
|
|
3027
3027
|
for (const [k, v] of Object.entries(query)) {
|
|
3028
3028
|
if (v !== void 0 && v !== null && v !== "") {
|
|
@@ -3032,14 +3032,14 @@ var HttpClient = class {
|
|
|
3032
3032
|
}
|
|
3033
3033
|
return url.toString();
|
|
3034
3034
|
}
|
|
3035
|
-
async get(
|
|
3036
|
-
return this.fetch(this.buildUrl(
|
|
3035
|
+
async get(path7, query, headers) {
|
|
3036
|
+
return this.fetch(this.buildUrl(path7, query), {
|
|
3037
3037
|
method: "GET",
|
|
3038
3038
|
...headers && { headers }
|
|
3039
3039
|
});
|
|
3040
3040
|
}
|
|
3041
|
-
async post(
|
|
3042
|
-
return this.fetch(this.buildUrl(
|
|
3041
|
+
async post(path7, body, headers) {
|
|
3042
|
+
return this.fetch(this.buildUrl(path7), {
|
|
3043
3043
|
method: "POST",
|
|
3044
3044
|
headers: { "Content-Type": "application/json", ...headers },
|
|
3045
3045
|
body: JSON.stringify(body)
|
|
@@ -3381,6 +3381,16 @@ var Atbash = class _Atbash {
|
|
|
3381
3381
|
* calls don't re-hit the dashboard. Cleared by `clearChainCache()`.
|
|
3382
3382
|
*/
|
|
3383
3383
|
_chainCache = /* @__PURE__ */ new Map();
|
|
3384
|
+
/**
|
|
3385
|
+
* Short-TTL cache for `/api/ai/exists`. The `registered` field is
|
|
3386
|
+
* monotonic (once true, stays true), so most calls in a burst re-fetch
|
|
3387
|
+
* data that hasn't changed. The `org_encryption_pubkey` field CAN change
|
|
3388
|
+
* — an org toggling encryption mid-session — so the TTL is deliberately
|
|
3389
|
+
* short (see `AGENT_EXISTS_TTL_MS`). Keyed by (pubkey, network) so
|
|
3390
|
+
* cross-agent / cross-network calls don't collide.
|
|
3391
|
+
*/
|
|
3392
|
+
_agentExistsCache = null;
|
|
3393
|
+
static AGENT_EXISTS_TTL_MS = 5e3;
|
|
3384
3394
|
/**
|
|
3385
3395
|
* Cached bearer token for risk-engine / insurance read calls. Built
|
|
3386
3396
|
* lazily as a signed `log_tool_call` tx and refreshed every 4 min so
|
|
@@ -3480,9 +3490,18 @@ var Atbash = class _Atbash {
|
|
|
3480
3490
|
*/
|
|
3481
3491
|
async checkAgentExists(pubkey, opts) {
|
|
3482
3492
|
const pk = pubkey ?? this.auth.pubkey;
|
|
3493
|
+
const network = opts?.network;
|
|
3494
|
+
const now = Date.now();
|
|
3495
|
+
const cached = this._agentExistsCache;
|
|
3496
|
+
if (cached && cached.pubkey === pk && cached.network === network && cached.expiresAt > now) {
|
|
3497
|
+
if (pk === this.auth.pubkey) {
|
|
3498
|
+
this._orgKeyFromChain = cached.orgKey;
|
|
3499
|
+
}
|
|
3500
|
+
return cached.registered;
|
|
3501
|
+
}
|
|
3483
3502
|
return this.track("checkAgentExists", pk, async () => {
|
|
3484
3503
|
const query = { pubkey: pk };
|
|
3485
|
-
if (
|
|
3504
|
+
if (network) query.network = network;
|
|
3486
3505
|
const resp = await this.http.get(
|
|
3487
3506
|
"/api/ai/exists",
|
|
3488
3507
|
query,
|
|
@@ -3490,11 +3509,21 @@ var Atbash = class _Atbash {
|
|
|
3490
3509
|
);
|
|
3491
3510
|
await this.raiseIfError(resp);
|
|
3492
3511
|
const data = await this.json(resp);
|
|
3512
|
+
const registered = Boolean(data?.registered);
|
|
3513
|
+
const orgKey = typeof data?.org_encryption_pubkey === "string" && data.org_encryption_pubkey ? data.org_encryption_pubkey : null;
|
|
3514
|
+
if (registered) {
|
|
3515
|
+
this._agentExistsCache = {
|
|
3516
|
+
pubkey: pk,
|
|
3517
|
+
network,
|
|
3518
|
+
expiresAt: Date.now() + _Atbash.AGENT_EXISTS_TTL_MS,
|
|
3519
|
+
registered,
|
|
3520
|
+
orgKey
|
|
3521
|
+
};
|
|
3522
|
+
}
|
|
3493
3523
|
if (pk === this.auth.pubkey) {
|
|
3494
|
-
|
|
3495
|
-
this._orgKeyFromChain = typeof key3 === "string" && key3 ? key3 : null;
|
|
3524
|
+
this._orgKeyFromChain = orgKey;
|
|
3496
3525
|
}
|
|
3497
|
-
return
|
|
3526
|
+
return registered;
|
|
3498
3527
|
});
|
|
3499
3528
|
}
|
|
3500
3529
|
/* ── log_tool_call (sign-only) ─────────────────────────────────────────── */
|
|
@@ -3575,12 +3604,19 @@ var Atbash = class _Atbash {
|
|
|
3575
3604
|
}
|
|
3576
3605
|
let chainOpts = options.chainOpts;
|
|
3577
3606
|
if (options.orgName) {
|
|
3578
|
-
const
|
|
3579
|
-
if (
|
|
3580
|
-
chainOpts = { network:
|
|
3581
|
-
} else
|
|
3582
|
-
const
|
|
3583
|
-
|
|
3607
|
+
const cached = this._chainCache.get(options.orgName);
|
|
3608
|
+
if (cached) {
|
|
3609
|
+
chainOpts = { network: cached.network };
|
|
3610
|
+
} else {
|
|
3611
|
+
const mapNetwork = await this.getActiveNetworkForOrg(options.orgName);
|
|
3612
|
+
if (mapNetwork) {
|
|
3613
|
+
const chain = mapNetwork === "private" ? PRIVATE_CHAIN : PUBLIC_CHAIN;
|
|
3614
|
+
this._chainCache.set(options.orgName, chain);
|
|
3615
|
+
chainOpts = { network: mapNetwork };
|
|
3616
|
+
} else if (!chainOpts?.blockchainRid) {
|
|
3617
|
+
const resolved = await this.resolveChainFromMap(options.orgName, null);
|
|
3618
|
+
chainOpts = { ...chainOpts, network: resolved.network };
|
|
3619
|
+
}
|
|
3584
3620
|
}
|
|
3585
3621
|
}
|
|
3586
3622
|
const brid = this.bridFromChainOpts(chainOpts);
|
|
@@ -4029,6 +4065,10 @@ var Atbash = class _Atbash {
|
|
|
4029
4065
|
clearChainCache() {
|
|
4030
4066
|
this._chainCache.clear();
|
|
4031
4067
|
}
|
|
4068
|
+
/** Drop the short-TTL `/api/ai/exists` cache. Useful in tests. */
|
|
4069
|
+
clearAgentExistsCache() {
|
|
4070
|
+
this._agentExistsCache = null;
|
|
4071
|
+
}
|
|
4032
4072
|
/* ── internals ─────────────────────────────────────────────────────────── */
|
|
4033
4073
|
/**
|
|
4034
4074
|
* Wrap an SDK method body in telemetry — records the call at start
|
|
@@ -4378,24 +4418,29 @@ async function scanMemory(entry, auth, opts) {
|
|
|
4378
4418
|
toolArgsJson: opts?.toolArgsJson ?? JSON.stringify({ key: entry.key, source: entry.source }),
|
|
4379
4419
|
mode: "memory-scan"
|
|
4380
4420
|
});
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
return {
|
|
4386
|
-
safe: false,
|
|
4387
|
-
verdict: "red",
|
|
4388
|
-
reason: unknownAction ? `judge returned unrecognised action_type "${result.actionType}"` : "judge returned no verdict",
|
|
4389
|
-
confidence: result.confidence,
|
|
4390
|
-
score: native.defaultScoreForVerdict("red"),
|
|
4391
|
-
toolCallId: result.toolCallId
|
|
4392
|
-
};
|
|
4421
|
+
if (result.verdict === "No verdict" && result.status !== "logged") {
|
|
4422
|
+
throw new Error(
|
|
4423
|
+
`memory scan: judge returned no verdict without an audit-tier marker (status: ${result.status || "absent"})`
|
|
4424
|
+
);
|
|
4393
4425
|
}
|
|
4394
|
-
const
|
|
4395
|
-
|
|
4426
|
+
const KNOWN_ACTIONS = ["allow", "block", "hold_for_user_confirm"];
|
|
4427
|
+
const action = result.actionType.trim().toLowerCase();
|
|
4428
|
+
if (result.verdict !== "No verdict" && !KNOWN_ACTIONS.includes(action)) {
|
|
4429
|
+
throw new Error(
|
|
4430
|
+
`memory scan: unrecognized action_type from judge (${result.actionType || "absent"})`
|
|
4431
|
+
);
|
|
4432
|
+
}
|
|
4433
|
+
const mapped = native.mapVerdict(
|
|
4434
|
+
action,
|
|
4396
4435
|
result.confidence,
|
|
4397
4436
|
threshold
|
|
4398
4437
|
);
|
|
4438
|
+
let verdict = mapped;
|
|
4439
|
+
if (result.verdict === "BLOCK") {
|
|
4440
|
+
verdict = "red";
|
|
4441
|
+
} else if (result.verdict === "HOLD" && mapped === "green") {
|
|
4442
|
+
verdict = "yellow";
|
|
4443
|
+
}
|
|
4399
4444
|
const parsed = native.parseScoreFromReason(result.reason);
|
|
4400
4445
|
const score = result.score ?? parsed.score ?? native.defaultScoreForVerdict(verdict);
|
|
4401
4446
|
return {
|
|
@@ -9301,8 +9346,8 @@ Reporter$3.prototype.wrapResult = function wrapResult(result) {
|
|
|
9301
9346
|
errors: state2.errors
|
|
9302
9347
|
};
|
|
9303
9348
|
};
|
|
9304
|
-
function ReporterError$1(
|
|
9305
|
-
this.path =
|
|
9349
|
+
function ReporterError$1(path7, msg) {
|
|
9350
|
+
this.path = path7;
|
|
9306
9351
|
this.rethrow(msg);
|
|
9307
9352
|
}
|
|
9308
9353
|
inherits$v(ReporterError$1, Error);
|
|
@@ -29523,8 +29568,8 @@ Reporter.prototype.wrapResult = function wrapResult2(result) {
|
|
|
29523
29568
|
errors: state2.errors
|
|
29524
29569
|
};
|
|
29525
29570
|
};
|
|
29526
|
-
function ReporterError(
|
|
29527
|
-
this.path =
|
|
29571
|
+
function ReporterError(path7, msg) {
|
|
29572
|
+
this.path = path7;
|
|
29528
29573
|
this.rethrow(msg);
|
|
29529
29574
|
}
|
|
29530
29575
|
inherits(ReporterError, Error);
|
|
@@ -32554,8 +32599,8 @@ var parseUtil = {};
|
|
|
32554
32599
|
const errors_js_12 = errors$3;
|
|
32555
32600
|
const en_js_12 = __importDefault2(en);
|
|
32556
32601
|
const makeIssue = (params) => {
|
|
32557
|
-
const { data, path:
|
|
32558
|
-
const fullPath = [...
|
|
32602
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
32603
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
32559
32604
|
const fullIssue = {
|
|
32560
32605
|
...issueData,
|
|
32561
32606
|
path: fullPath
|
|
@@ -32692,11 +32737,11 @@ var errorUtil_js_1 = errorUtil$1;
|
|
|
32692
32737
|
var parseUtil_js_1 = parseUtil;
|
|
32693
32738
|
var util_js_1 = util;
|
|
32694
32739
|
var ParseInputLazyPath = class {
|
|
32695
|
-
constructor(parent, value,
|
|
32740
|
+
constructor(parent, value, path7, key3) {
|
|
32696
32741
|
this._cachedPath = [];
|
|
32697
32742
|
this.parent = parent;
|
|
32698
32743
|
this.data = value;
|
|
32699
|
-
this._path =
|
|
32744
|
+
this._path = path7;
|
|
32700
32745
|
this._key = key3;
|
|
32701
32746
|
}
|
|
32702
32747
|
get path() {
|
|
@@ -39602,21 +39647,21 @@ function createTimeoutController(timeout) {
|
|
|
39602
39647
|
const timeoutId = setTimeout(() => controller.abort(timeoutError), timeout);
|
|
39603
39648
|
return { controller, timeoutId };
|
|
39604
39649
|
}
|
|
39605
|
-
function handleRequest(method,
|
|
39650
|
+
function handleRequest(method, path7, endpoint, timeout, postObject) {
|
|
39606
39651
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39607
39652
|
if (method == enums_1$2.Method.GET) {
|
|
39608
|
-
return yield get(
|
|
39653
|
+
return yield get(path7, endpoint, timeout);
|
|
39609
39654
|
} else {
|
|
39610
|
-
return yield post(
|
|
39655
|
+
return yield post(path7, endpoint, timeout, postObject);
|
|
39611
39656
|
}
|
|
39612
39657
|
});
|
|
39613
39658
|
}
|
|
39614
|
-
function get(
|
|
39659
|
+
function get(path7, endpoint, timeout) {
|
|
39615
39660
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39616
|
-
logger.debug(`GET URL ${new URL(
|
|
39661
|
+
logger.debug(`GET URL ${new URL(path7, endpoint).href}`);
|
|
39617
39662
|
try {
|
|
39618
39663
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39619
|
-
const response = yield fetch(new URL(
|
|
39664
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39620
39665
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39621
39666
|
});
|
|
39622
39667
|
if (timeoutId)
|
|
@@ -39654,9 +39699,9 @@ function constructBufferResponseBody(response) {
|
|
|
39654
39699
|
return responseText ? responseText : response.statusText;
|
|
39655
39700
|
});
|
|
39656
39701
|
}
|
|
39657
|
-
function post(
|
|
39702
|
+
function post(path7, endpoint, timeout, requestBody) {
|
|
39658
39703
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39659
|
-
logger.debug(`POST URL ${new URL(
|
|
39704
|
+
logger.debug(`POST URL ${new URL(path7, endpoint).href}`);
|
|
39660
39705
|
logger.debug(`POST body ${JSON.stringify(requestBody)}`);
|
|
39661
39706
|
if (buffer_1.Buffer.isBuffer(requestBody)) {
|
|
39662
39707
|
try {
|
|
@@ -39670,7 +39715,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39670
39715
|
},
|
|
39671
39716
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39672
39717
|
};
|
|
39673
|
-
const response = yield fetch(new URL(
|
|
39718
|
+
const response = yield fetch(new URL(path7, endpoint).href, requestOptions);
|
|
39674
39719
|
if (timeoutId)
|
|
39675
39720
|
clearTimeout(timeoutId);
|
|
39676
39721
|
const transactionTimestamp = response.headers.get("X-Transaction-Timestamp");
|
|
@@ -39681,7 +39726,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39681
39726
|
} else {
|
|
39682
39727
|
try {
|
|
39683
39728
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39684
|
-
const response = yield fetch(new URL(
|
|
39729
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39685
39730
|
method: "post",
|
|
39686
39731
|
body: JSON.stringify(requestBody),
|
|
39687
39732
|
headers: {
|
|
@@ -39861,10 +39906,10 @@ function requireFailoverStrategies() {
|
|
|
39861
39906
|
}
|
|
39862
39907
|
}
|
|
39863
39908
|
function abortOnError(_a2) {
|
|
39864
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39909
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39865
39910
|
return yield retryRequest({
|
|
39866
39911
|
method,
|
|
39867
|
-
path:
|
|
39912
|
+
path: path7,
|
|
39868
39913
|
config: config2,
|
|
39869
39914
|
postObject,
|
|
39870
39915
|
timeoutOverride,
|
|
@@ -39875,10 +39920,10 @@ function requireFailoverStrategies() {
|
|
|
39875
39920
|
});
|
|
39876
39921
|
}
|
|
39877
39922
|
function tryNextOnError(_a2) {
|
|
39878
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39923
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39879
39924
|
return yield retryRequest({
|
|
39880
39925
|
method,
|
|
39881
|
-
path:
|
|
39926
|
+
path: path7,
|
|
39882
39927
|
config: config2,
|
|
39883
39928
|
postObject,
|
|
39884
39929
|
timeoutOverride,
|
|
@@ -39894,7 +39939,7 @@ function requireFailoverStrategies() {
|
|
|
39894
39939
|
return endpointPoolLength - (endpointPoolLength - 1) / 3;
|
|
39895
39940
|
}
|
|
39896
39941
|
function queryMajority(_a2) {
|
|
39897
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39942
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39898
39943
|
var _b;
|
|
39899
39944
|
const bftMajorityThreshold = calculateBftMajorityThreshold(config2.endpointPool.length);
|
|
39900
39945
|
const failureThreshold = config2.endpointPool.length - bftMajorityThreshold + 1;
|
|
@@ -39905,7 +39950,7 @@ function requireFailoverStrategies() {
|
|
|
39905
39950
|
const promises = availableNodes.map((node2) => __awaiter2(this, void 0, void 0, function* () {
|
|
39906
39951
|
try {
|
|
39907
39952
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39908
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
39953
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39909
39954
|
const { statusCode } = response;
|
|
39910
39955
|
if (statusCode && (0, http_utils_1.isSuccessfulStatusCode)(statusCode)) {
|
|
39911
39956
|
outcomes.push({ type: "SUCCESS", result: response });
|
|
@@ -39952,7 +39997,7 @@ function requireFailoverStrategies() {
|
|
|
39952
39997
|
});
|
|
39953
39998
|
}
|
|
39954
39999
|
function singleEndpoint(_a2) {
|
|
39955
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40000
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39956
40001
|
let statusCode = null;
|
|
39957
40002
|
let rspBody = null;
|
|
39958
40003
|
let error4 = null;
|
|
@@ -39963,7 +40008,7 @@ function requireFailoverStrategies() {
|
|
|
39963
40008
|
}
|
|
39964
40009
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
39965
40010
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39966
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40011
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, endpoint.url, requestTimeout, postObject);
|
|
39967
40012
|
if (response) {
|
|
39968
40013
|
({ error: error4, statusCode, rspBody, transactionTimestamp } = response);
|
|
39969
40014
|
}
|
|
@@ -39978,7 +40023,7 @@ function requireFailoverStrategies() {
|
|
|
39978
40023
|
});
|
|
39979
40024
|
}
|
|
39980
40025
|
function retryRequest(_a2) {
|
|
39981
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40026
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
|
|
39982
40027
|
var _b, _c, _d;
|
|
39983
40028
|
let statusCode = null;
|
|
39984
40029
|
let rspBody = null;
|
|
@@ -39989,7 +40034,7 @@ function requireFailoverStrategies() {
|
|
|
39989
40034
|
for (const node2 of availableNodes) {
|
|
39990
40035
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
39991
40036
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39992
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40037
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39993
40038
|
error4 = (_b = response === null || response === void 0 ? void 0 : response.error) !== null && _b !== void 0 ? _b : null;
|
|
39994
40039
|
statusCode = (_c = response === null || response === void 0 ? void 0 : response.statusCode) !== null && _c !== void 0 ? _c : null;
|
|
39995
40040
|
rspBody = (_d = response === null || response === void 0 ? void 0 : response.rspBody) !== null && _d !== void 0 ? _d : null;
|
|
@@ -40132,19 +40177,19 @@ function requireRequestWithFailoverStrategy() {
|
|
|
40132
40177
|
const enums_12 = enums;
|
|
40133
40178
|
const failoverStrategies_1 = requireFailoverStrategies();
|
|
40134
40179
|
function requestWithFailoverStrategy$1(method_1, path_1, config_1, postObject_1) {
|
|
40135
|
-
return __awaiter2(this, arguments, void 0, function* (method,
|
|
40180
|
+
return __awaiter2(this, arguments, void 0, function* (method, path7, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
|
|
40136
40181
|
switch (config2.failoverStrategy) {
|
|
40137
40182
|
case enums_12.FailoverStrategy.AbortOnError:
|
|
40138
|
-
return yield (0, failoverStrategies_1.abortOnError)({ method, path:
|
|
40183
|
+
return yield (0, failoverStrategies_1.abortOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40139
40184
|
case enums_12.FailoverStrategy.TryNextOnError:
|
|
40140
|
-
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path:
|
|
40185
|
+
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40141
40186
|
case enums_12.FailoverStrategy.SingleEndpoint:
|
|
40142
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40187
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40143
40188
|
case enums_12.FailoverStrategy.QueryMajority:
|
|
40144
40189
|
if (forceSingleEndpoint) {
|
|
40145
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40190
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40146
40191
|
}
|
|
40147
|
-
return yield (0, failoverStrategies_1.queryMajority)({ method, path:
|
|
40192
|
+
return yield (0, failoverStrategies_1.queryMajority)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40148
40193
|
default:
|
|
40149
40194
|
throw new Error(`Unsupported failover strategy: ${config2.failoverStrategy}`);
|
|
40150
40195
|
}
|
|
@@ -41343,7 +41388,7 @@ var networkSettings = {};
|
|
|
41343
41388
|
const restNetworkSettingsValidationContext = RestNetworkSettingsSchema.safeParse(networkSettings2);
|
|
41344
41389
|
if ("error" in restNetworkSettingsValidationContext) {
|
|
41345
41390
|
const { error: { issues } = {} } = restNetworkSettingsValidationContext;
|
|
41346
|
-
const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path:
|
|
41391
|
+
const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path7 }) => `${path7[0]}: ${message}`).join(", ");
|
|
41347
41392
|
if (throwOnError) {
|
|
41348
41393
|
throw new Error(errorMessage2);
|
|
41349
41394
|
}
|
|
@@ -42725,6 +42770,7 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
|
|
|
42725
42770
|
}
|
|
42726
42771
|
|
|
42727
42772
|
// src-ts/memory/guard.ts
|
|
42773
|
+
import path3 from "path";
|
|
42728
42774
|
function emitDebugProbe(event, ctx, memEntry, logger2) {
|
|
42729
42775
|
if (!logger2?.info) return;
|
|
42730
42776
|
const ev = event ?? {};
|
|
@@ -42761,7 +42807,8 @@ async function guardMemoryWrite(input) {
|
|
|
42761
42807
|
toolNames,
|
|
42762
42808
|
enforce = true,
|
|
42763
42809
|
debug: debug2 = false,
|
|
42764
|
-
logger: logger2
|
|
42810
|
+
logger: logger2,
|
|
42811
|
+
memoryFilePath
|
|
42765
42812
|
} = input;
|
|
42766
42813
|
const memEntry = classifyMemoryWrite(event, ctx, { patterns, toolNames });
|
|
42767
42814
|
if (debug2) emitDebugProbe(event, ctx, memEntry, logger2);
|
|
@@ -42797,17 +42844,28 @@ async function guardMemoryWrite(input) {
|
|
|
42797
42844
|
committed: false
|
|
42798
42845
|
};
|
|
42799
42846
|
}
|
|
42800
|
-
|
|
42801
|
-
|
|
42802
|
-
|
|
42803
|
-
|
|
42804
|
-
|
|
42805
|
-
|
|
42806
|
-
|
|
42807
|
-
|
|
42808
|
-
|
|
42847
|
+
const isManagedMemoryFile = memoryFilePath !== void 0 && path3.resolve(memEntry.key) === path3.resolve(memoryFilePath);
|
|
42848
|
+
if (isManagedMemoryFile) {
|
|
42849
|
+
commitMemoryVersion(memEntry.value, auth, {
|
|
42850
|
+
score: scanResult.score,
|
|
42851
|
+
orgName,
|
|
42852
|
+
endpoint
|
|
42853
|
+
}).catch((err) => {
|
|
42854
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
42855
|
+
logger2?.warn?.("[atbash] memory commit to chain failed", {
|
|
42856
|
+
path: memEntry.key,
|
|
42857
|
+
reason
|
|
42858
|
+
});
|
|
42809
42859
|
});
|
|
42810
|
-
}
|
|
42860
|
+
} else {
|
|
42861
|
+
logger2?.info?.(
|
|
42862
|
+
"[atbash] scanned but not committed \u2014 not the managed memory file",
|
|
42863
|
+
{
|
|
42864
|
+
path: memEntry.key,
|
|
42865
|
+
memoryFilePath: memoryFilePath ?? "(not configured)"
|
|
42866
|
+
}
|
|
42867
|
+
);
|
|
42868
|
+
}
|
|
42811
42869
|
logger2?.info?.(
|
|
42812
42870
|
scanResult.verdict === "yellow" ? "[atbash] memory HOLD" : "[atbash] memory ALLOW",
|
|
42813
42871
|
{ path: memEntry.key, score: scanResult.score, reason: scanResult.reason }
|
|
@@ -42816,7 +42874,7 @@ async function guardMemoryWrite(input) {
|
|
|
42816
42874
|
handled: true,
|
|
42817
42875
|
decision: { allow: true },
|
|
42818
42876
|
scanResult,
|
|
42819
|
-
committed:
|
|
42877
|
+
committed: isManagedMemoryFile
|
|
42820
42878
|
};
|
|
42821
42879
|
}
|
|
42822
42880
|
|
|
@@ -42835,26 +42893,26 @@ async function syncLocalMemory(auth, pointer, opts = {}) {
|
|
|
42835
42893
|
const now = Date.now();
|
|
42836
42894
|
const withinTtl = !opts.force && now - pointer.checkedAt < ttl;
|
|
42837
42895
|
if (withinTtl) {
|
|
42838
|
-
return { drifted: false, pointer };
|
|
42896
|
+
return { drifted: false, checked: false, pointer };
|
|
42839
42897
|
}
|
|
42840
42898
|
const currentId = await getActiveMemoryId(auth, opts.chainOpts);
|
|
42841
42899
|
const nextPointer = { activeId: currentId, checkedAt: now };
|
|
42842
42900
|
if (currentId === pointer.activeId) {
|
|
42843
|
-
return { drifted: false, pointer: nextPointer };
|
|
42901
|
+
return { drifted: false, checked: true, pointer: nextPointer };
|
|
42844
42902
|
}
|
|
42845
42903
|
if (currentId === null) {
|
|
42846
|
-
return { drifted: true, current: null, pointer: nextPointer };
|
|
42904
|
+
return { drifted: true, checked: true, current: null, pointer: nextPointer };
|
|
42847
42905
|
}
|
|
42848
42906
|
const row = await getMemoryById(currentId, auth, opts.chainOpts);
|
|
42849
42907
|
if (row.decryptError) {
|
|
42850
42908
|
throw new MemoryIntegrityError(currentId, row.decryptError);
|
|
42851
42909
|
}
|
|
42852
|
-
return { drifted: true, current: row, pointer: nextPointer };
|
|
42910
|
+
return { drifted: true, checked: true, current: row, pointer: nextPointer };
|
|
42853
42911
|
}
|
|
42854
42912
|
|
|
42855
42913
|
// src-ts/memory/pointer-store.ts
|
|
42856
42914
|
import { promises as fs } from "fs";
|
|
42857
|
-
import
|
|
42915
|
+
import path4 from "path";
|
|
42858
42916
|
var EMPTY = { version: 1, agents: {} };
|
|
42859
42917
|
var PointerStore = class {
|
|
42860
42918
|
constructor(filePath) {
|
|
@@ -42896,19 +42954,19 @@ var PointerStore = class {
|
|
|
42896
42954
|
this.cache = { ...EMPTY, agents: {} };
|
|
42897
42955
|
}
|
|
42898
42956
|
async persist(file) {
|
|
42899
|
-
await fs.mkdir(
|
|
42957
|
+
await fs.mkdir(path4.dirname(this.filePath), { recursive: true });
|
|
42900
42958
|
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
42901
42959
|
await fs.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
|
|
42902
42960
|
await fs.rename(tmp, this.filePath);
|
|
42903
42961
|
}
|
|
42904
42962
|
};
|
|
42905
42963
|
function defaultPointerPath(workspaceDir = process.cwd()) {
|
|
42906
|
-
return
|
|
42964
|
+
return path4.join(workspaceDir, ".atbash", "memory-pointer.json");
|
|
42907
42965
|
}
|
|
42908
42966
|
|
|
42909
42967
|
// src-ts/memory/file-logger.ts
|
|
42910
42968
|
import { promises as fs2 } from "fs";
|
|
42911
|
-
import
|
|
42969
|
+
import path5 from "path";
|
|
42912
42970
|
function formatMeta(meta) {
|
|
42913
42971
|
if (!meta || Object.keys(meta).length === 0) return "";
|
|
42914
42972
|
try {
|
|
@@ -42920,7 +42978,7 @@ function formatMeta(meta) {
|
|
|
42920
42978
|
function createFileLogger(filePath, upstream) {
|
|
42921
42979
|
let queue = Promise.resolve();
|
|
42922
42980
|
async function ensureDir() {
|
|
42923
|
-
await fs2.mkdir(
|
|
42981
|
+
await fs2.mkdir(path5.dirname(filePath), { recursive: true });
|
|
42924
42982
|
}
|
|
42925
42983
|
function append(level, message, meta) {
|
|
42926
42984
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
|
|
@@ -42940,7 +42998,7 @@ function createFileLogger(filePath, upstream) {
|
|
|
42940
42998
|
};
|
|
42941
42999
|
}
|
|
42942
43000
|
function defaultPluginLogPath(workspaceDir = process.cwd()) {
|
|
42943
|
-
return
|
|
43001
|
+
return path5.join(workspaceDir, ".atbash", "plugin.log");
|
|
42944
43002
|
}
|
|
42945
43003
|
|
|
42946
43004
|
// src-ts/memory/read-classifier.ts
|
|
@@ -42955,13 +43013,13 @@ function classifyMemoryRead(event, ctx, opts = {}) {
|
|
|
42955
43013
|
|
|
42956
43014
|
// src-ts/memory/guard-manager.ts
|
|
42957
43015
|
import { promises as fs3 } from "fs";
|
|
42958
|
-
import
|
|
43016
|
+
import path6 from "path";
|
|
42959
43017
|
var DEFAULT_SYNC_TTL_MS = 3e4;
|
|
42960
43018
|
var MemoryGuardManager = class {
|
|
42961
43019
|
constructor(opts) {
|
|
42962
43020
|
this.opts = opts;
|
|
42963
43021
|
const workspaceDir = opts.workspaceDir;
|
|
42964
|
-
this.memoryFilePath = opts.memoryFilePath ??
|
|
43022
|
+
this.memoryFilePath = opts.memoryFilePath ?? path6.join(workspaceDir, "MEMORY.md");
|
|
42965
43023
|
this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
|
|
42966
43024
|
this.logger = createFileLogger(
|
|
42967
43025
|
opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
|
|
@@ -42991,7 +43049,11 @@ var MemoryGuardManager = class {
|
|
|
42991
43049
|
async runBootProbe() {
|
|
42992
43050
|
try {
|
|
42993
43051
|
const seed = { activeId: null, checkedAt: 0 };
|
|
42994
|
-
const result = await syncLocalMemory(this.opts.auth, seed, {
|
|
43052
|
+
const result = await syncLocalMemory(this.opts.auth, seed, {
|
|
43053
|
+
ttlMs: 0,
|
|
43054
|
+
force: true,
|
|
43055
|
+
chainOpts: this.opts.chainOpts
|
|
43056
|
+
});
|
|
42995
43057
|
if (!result.drifted && result.pointer.activeId == null) {
|
|
42996
43058
|
this.logger.info(
|
|
42997
43059
|
`[atbash] no active memory on chain for agent=${this.agentPubkeyHex.slice(0, 16)}\u2026 org=${this.opts.orgName ?? "(none)"} \u2014 either the agent isn't registered on this chain or hasn't written any memory. Sync will remain a no-op until a write lands.`
|
|
@@ -43023,15 +43085,19 @@ var MemoryGuardManager = class {
|
|
|
43023
43085
|
}
|
|
43024
43086
|
}
|
|
43025
43087
|
/**
|
|
43026
|
-
* Returns a `HookDecision` when the
|
|
43027
|
-
*
|
|
43028
|
-
*
|
|
43088
|
+
* Returns a `HookDecision` when the guard reached a decision about this event.
|
|
43089
|
+
* Returns `null` when it did not — either the event isn't memory-related, or it
|
|
43090
|
+
* is but the guard could not check it. In both cases the host falls through to
|
|
43091
|
+
* its own audit.
|
|
43092
|
+
*
|
|
43093
|
+
* A returned decision carries `audited` (see `HookDecision`). Only
|
|
43094
|
+
* `{ allow: true, audited: true }` means "checked and cleared"; anything else
|
|
43095
|
+
* that allows is a call the host still needs to judge.
|
|
43029
43096
|
*/
|
|
43030
43097
|
async handleBeforeToolCall(event, ctx) {
|
|
43031
43098
|
if (classifyMemoryRead(event, ctx, this.opts.memoryReadClassifier)) {
|
|
43032
43099
|
this.logger.info("[atbash] memory read intercepted \u2014 running sync check");
|
|
43033
|
-
|
|
43034
|
-
return readDecision ?? { allow: true };
|
|
43100
|
+
return await this.handleMemoryRead(event, ctx);
|
|
43035
43101
|
}
|
|
43036
43102
|
const guardLogger = {
|
|
43037
43103
|
info: (msg, meta) => this.logger.info(msg, meta && typeof meta === "object" ? meta : void 0),
|
|
@@ -43048,7 +43114,9 @@ var MemoryGuardManager = class {
|
|
|
43048
43114
|
toolNames: this.opts.memoryWriteToolNames,
|
|
43049
43115
|
enforce: this.enforce,
|
|
43050
43116
|
debug: this.opts.debug,
|
|
43051
|
-
logger: guardLogger
|
|
43117
|
+
logger: guardLogger,
|
|
43118
|
+
// Only this file may reach the single, path-less chain memory slot.
|
|
43119
|
+
memoryFilePath: this.memoryFilePath
|
|
43052
43120
|
});
|
|
43053
43121
|
return this.mapGuardResult(guard);
|
|
43054
43122
|
}
|
|
@@ -43066,30 +43134,81 @@ var MemoryGuardManager = class {
|
|
|
43066
43134
|
block: true,
|
|
43067
43135
|
blockReason: d.reason ?? "",
|
|
43068
43136
|
allow: false,
|
|
43069
|
-
reason: d.reason
|
|
43137
|
+
reason: d.reason,
|
|
43138
|
+
// A block IS a decision — the most thoroughly checked one the guard
|
|
43139
|
+
// makes. Without this a host following the documented `!audited ->
|
|
43140
|
+
// judge it yourself` rule would re-judge its way past a red scan.
|
|
43141
|
+
audited: true,
|
|
43142
|
+
...sr2 ? { verdict: sr2.verdict } : {}
|
|
43070
43143
|
};
|
|
43071
43144
|
}
|
|
43072
43145
|
this.logger.info(
|
|
43073
43146
|
`[atbash] guardMemoryWrite ALLOWED \u2014 verdict=${verdict} score=${score} committed=${guard.committed === true}`
|
|
43074
43147
|
);
|
|
43075
|
-
|
|
43148
|
+
if (sr2 === void 0) {
|
|
43149
|
+
return { allow: true, audited: false, reason: "memory scan did not run (observe mode)" };
|
|
43150
|
+
}
|
|
43151
|
+
if (sr2.verdict !== "green") {
|
|
43152
|
+
return {
|
|
43153
|
+
allow: true,
|
|
43154
|
+
audited: false,
|
|
43155
|
+
verdict: sr2.verdict,
|
|
43156
|
+
reason: `memory scan returned ${sr2.verdict} but this guard is not enforcing it`
|
|
43157
|
+
};
|
|
43158
|
+
}
|
|
43159
|
+
return { allow: true, audited: true, verdict: sr2.verdict };
|
|
43076
43160
|
}
|
|
43077
|
-
|
|
43161
|
+
/**
|
|
43162
|
+
* Whether the pointer state this manager tracks actually describes the file
|
|
43163
|
+
* this call is about to read.
|
|
43164
|
+
*
|
|
43165
|
+
* The classifier fires on nine patterns — including the bare tokens
|
|
43166
|
+
* `"memory/"`, `"CLAUDE.md"` and `"AGENTS.md"` — but the sync path only ever
|
|
43167
|
+
* reads, refreshes, or vouches for `this.memoryFilePath`. Without this check a
|
|
43168
|
+
* read of `/repo/CLAUDE.md` (or any path merely containing `memory/`) would
|
|
43169
|
+
* receive an `audited: true` for a file the guard never opened.
|
|
43170
|
+
*
|
|
43171
|
+
* Conservative on purpose: every path-shaped value found must resolve to the
|
|
43172
|
+
* managed file. If none is found, or any one differs, the answer is no. That
|
|
43173
|
+
* also covers events carrying two different path keys, where the classifier
|
|
43174
|
+
* and the host could otherwise disagree about which one is authoritative.
|
|
43175
|
+
*/
|
|
43176
|
+
vouchesForTarget(event, ctx) {
|
|
43177
|
+
const KEYS = ["path", "file_path", "filePath", "notebook_path", "notebookPath", "target"];
|
|
43178
|
+
const found = [];
|
|
43179
|
+
for (const src of [event, ctx]) {
|
|
43180
|
+
for (const bag of [src, src?.params]) {
|
|
43181
|
+
if (!bag || typeof bag !== "object") continue;
|
|
43182
|
+
const rec = bag;
|
|
43183
|
+
for (const k of KEYS) {
|
|
43184
|
+
if (typeof rec[k] === "string" && rec[k]) found.push(rec[k]);
|
|
43185
|
+
}
|
|
43186
|
+
}
|
|
43187
|
+
}
|
|
43188
|
+
if (found.length === 0) return false;
|
|
43189
|
+
const managed = path6.resolve(this.memoryFilePath);
|
|
43190
|
+
return found.every((p) => path6.resolve(p) === managed);
|
|
43191
|
+
}
|
|
43192
|
+
async handleMemoryRead(event, ctx) {
|
|
43078
43193
|
const pointer = await this.pointerStore.get(this.agentPubkeyHex);
|
|
43079
43194
|
let result;
|
|
43080
43195
|
try {
|
|
43081
|
-
result = await syncLocalMemory(this.opts.auth, pointer, {
|
|
43196
|
+
result = await syncLocalMemory(this.opts.auth, pointer, {
|
|
43197
|
+
ttlMs: this.ttlMs,
|
|
43198
|
+
chainOpts: this.opts.chainOpts
|
|
43199
|
+
});
|
|
43082
43200
|
} catch (err) {
|
|
43083
43201
|
if (err instanceof MemoryIntegrityError) {
|
|
43084
43202
|
const reason = `Memory integrity check failed on id ${err.id} \u2014 read blocked.`;
|
|
43085
43203
|
this.logger.warn("[atbash] MEMORY INTEGRITY FAILURE", { id: err.id, error: err.message });
|
|
43086
43204
|
if (!this.enforce) return null;
|
|
43087
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43205
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43088
43206
|
}
|
|
43089
43207
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43090
43208
|
this.logger.warn("[atbash] memory sync failed (serving local copy)", { error: msg });
|
|
43091
43209
|
return null;
|
|
43092
43210
|
}
|
|
43211
|
+
let onDiskIsCurrent = result.checked;
|
|
43093
43212
|
if (result.drifted) {
|
|
43094
43213
|
const fresh = result.current;
|
|
43095
43214
|
if (fresh) {
|
|
@@ -43097,7 +43216,7 @@ var MemoryGuardManager = class {
|
|
|
43097
43216
|
const reason = `Rolled-back memory version #${fresh.id} scored ${fresh.score} (below threshold ${this.rollbackMinScore}) \u2014 read blocked.`;
|
|
43098
43217
|
this.logger.warn("[atbash] blocking read on low-score rollback", { id: fresh.id, score: fresh.score });
|
|
43099
43218
|
if (!this.enforce) return null;
|
|
43100
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43219
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43101
43220
|
}
|
|
43102
43221
|
this.logger.info("[atbash] memory drift detected \u2014 refreshing local file", {
|
|
43103
43222
|
id: fresh.id,
|
|
@@ -43108,16 +43227,26 @@ var MemoryGuardManager = class {
|
|
|
43108
43227
|
} catch (err) {
|
|
43109
43228
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43110
43229
|
this.logger.warn("[atbash] failed to write refreshed memory (serving old)", { error: msg });
|
|
43230
|
+
onDiskIsCurrent = false;
|
|
43111
43231
|
}
|
|
43112
43232
|
} else {
|
|
43113
43233
|
this.logger.info("[atbash] active memory removed on chain", { pubkey: this.agentPubkeyHex });
|
|
43234
|
+
onDiskIsCurrent = false;
|
|
43114
43235
|
}
|
|
43115
43236
|
}
|
|
43116
|
-
|
|
43117
|
-
|
|
43237
|
+
if (onDiskIsCurrent) {
|
|
43238
|
+
await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
|
|
43239
|
+
} else {
|
|
43240
|
+
this.logger.warn(
|
|
43241
|
+
"[atbash] not advancing memory pointer \u2014 local file is stale or revoked; reads stay unaudited until it is refreshed"
|
|
43242
|
+
);
|
|
43243
|
+
}
|
|
43244
|
+
if (!onDiskIsCurrent) return null;
|
|
43245
|
+
if (!this.vouchesForTarget(event, ctx)) return null;
|
|
43246
|
+
return { allow: true, audited: true };
|
|
43118
43247
|
}
|
|
43119
43248
|
async writeMemoryAtomic(content) {
|
|
43120
|
-
await fs3.mkdir(
|
|
43249
|
+
await fs3.mkdir(path6.dirname(this.memoryFilePath), { recursive: true });
|
|
43121
43250
|
const tmp = `${this.memoryFilePath}.${process.pid}.tmp`;
|
|
43122
43251
|
await fs3.writeFile(tmp, content, "utf8");
|
|
43123
43252
|
await fs3.rename(tmp, this.memoryFilePath);
|