@atbash/sdk 0.10.7-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 +128 -19
- package/dist/browser.mjs +204 -70
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +128 -19
- package/dist/index.d.ts +128 -19
- package/dist/index.js +320 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +318 -108
- 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,23 +3032,83 @@ 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)
|
|
3046
3046
|
});
|
|
3047
3047
|
}
|
|
3048
3048
|
async fetch(url, init4) {
|
|
3049
|
-
|
|
3049
|
+
try {
|
|
3050
|
+
return await fetch(url, {
|
|
3051
|
+
...init4,
|
|
3052
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
3053
|
+
});
|
|
3054
|
+
} catch (err) {
|
|
3055
|
+
throw classifyTransportError(err, url, init4.method ?? "GET", this.timeoutMs);
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
};
|
|
3059
|
+
var HttpTransportError = class extends Error {
|
|
3060
|
+
kind;
|
|
3061
|
+
constructor(kind, message, options) {
|
|
3062
|
+
super(message, options);
|
|
3063
|
+
this.name = "HttpTransportError";
|
|
3064
|
+
this.kind = kind;
|
|
3050
3065
|
}
|
|
3051
3066
|
};
|
|
3067
|
+
function classifyTransportError(err, url, method, timeoutMs) {
|
|
3068
|
+
const name2 = err instanceof Error ? err.name : "";
|
|
3069
|
+
const cause = err instanceof Error ? err.cause : void 0;
|
|
3070
|
+
const code2 = cause && typeof cause === "object" && "code" in cause ? String(cause.code) : "";
|
|
3071
|
+
if (name2 === "TimeoutError") {
|
|
3072
|
+
return new HttpTransportError(
|
|
3073
|
+
"timeout",
|
|
3074
|
+
`${method} ${url} did not respond within ${timeoutMs} ms \u2014 the judge may be slow to boot or the LLM is under load; retry in a moment`,
|
|
3075
|
+
{ cause: err }
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
3078
|
+
if (name2 === "AbortError") {
|
|
3079
|
+
return new HttpTransportError(
|
|
3080
|
+
"aborted",
|
|
3081
|
+
`${method} ${url} was cancelled by the caller`,
|
|
3082
|
+
{ cause: err }
|
|
3083
|
+
);
|
|
3084
|
+
}
|
|
3085
|
+
if (code2 === "ENOTFOUND" || code2 === "EAI_AGAIN") {
|
|
3086
|
+
return new HttpTransportError(
|
|
3087
|
+
"dns",
|
|
3088
|
+
`could not resolve the judge hostname (${url}) \u2014 check the endpoint and DNS`,
|
|
3089
|
+
{ cause: err }
|
|
3090
|
+
);
|
|
3091
|
+
}
|
|
3092
|
+
if (code2 === "ECONNREFUSED") {
|
|
3093
|
+
return new HttpTransportError(
|
|
3094
|
+
"connect_refused",
|
|
3095
|
+
`judge refused the connection (${url}) \u2014 the service may be down or restarting`,
|
|
3096
|
+
{ cause: err }
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
if (code2 === "ECONNRESET" || code2 === "EPIPE") {
|
|
3100
|
+
return new HttpTransportError(
|
|
3101
|
+
"connection_reset",
|
|
3102
|
+
`judge dropped the connection mid-request (${url}) \u2014 retry once`,
|
|
3103
|
+
{ cause: err }
|
|
3104
|
+
);
|
|
3105
|
+
}
|
|
3106
|
+
return new HttpTransportError(
|
|
3107
|
+
"unknown",
|
|
3108
|
+
`${method} ${url} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3109
|
+
{ cause: err }
|
|
3110
|
+
);
|
|
3111
|
+
}
|
|
3052
3112
|
|
|
3053
3113
|
// src-ts/keyLoader.ts
|
|
3054
3114
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -3321,6 +3381,16 @@ var Atbash = class _Atbash {
|
|
|
3321
3381
|
* calls don't re-hit the dashboard. Cleared by `clearChainCache()`.
|
|
3322
3382
|
*/
|
|
3323
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;
|
|
3324
3394
|
/**
|
|
3325
3395
|
* Cached bearer token for risk-engine / insurance read calls. Built
|
|
3326
3396
|
* lazily as a signed `log_tool_call` tx and refreshed every 4 min so
|
|
@@ -3340,7 +3410,7 @@ var Atbash = class _Atbash {
|
|
|
3340
3410
|
this.failClosed = options.failClosed !== false;
|
|
3341
3411
|
this.debug = options.debug === true;
|
|
3342
3412
|
this.logger = options.logger ?? {};
|
|
3343
|
-
this.http = new HttpClient(this.endpoint, options.timeoutMs ??
|
|
3413
|
+
this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 6e4);
|
|
3344
3414
|
this.logEnvironmentOnce();
|
|
3345
3415
|
if (this.endpoint !== DEFAULT_ENDPOINT) {
|
|
3346
3416
|
this.logger.warn?.("[atbash] running on non-default judge endpoint", {
|
|
@@ -3420,9 +3490,18 @@ var Atbash = class _Atbash {
|
|
|
3420
3490
|
*/
|
|
3421
3491
|
async checkAgentExists(pubkey, opts) {
|
|
3422
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
|
+
}
|
|
3423
3502
|
return this.track("checkAgentExists", pk, async () => {
|
|
3424
3503
|
const query = { pubkey: pk };
|
|
3425
|
-
if (
|
|
3504
|
+
if (network) query.network = network;
|
|
3426
3505
|
const resp = await this.http.get(
|
|
3427
3506
|
"/api/ai/exists",
|
|
3428
3507
|
query,
|
|
@@ -3430,11 +3509,21 @@ var Atbash = class _Atbash {
|
|
|
3430
3509
|
);
|
|
3431
3510
|
await this.raiseIfError(resp);
|
|
3432
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
|
+
}
|
|
3433
3523
|
if (pk === this.auth.pubkey) {
|
|
3434
|
-
|
|
3435
|
-
this._orgKeyFromChain = typeof key3 === "string" && key3 ? key3 : null;
|
|
3524
|
+
this._orgKeyFromChain = orgKey;
|
|
3436
3525
|
}
|
|
3437
|
-
return
|
|
3526
|
+
return registered;
|
|
3438
3527
|
});
|
|
3439
3528
|
}
|
|
3440
3529
|
/* ── log_tool_call (sign-only) ─────────────────────────────────────────── */
|
|
@@ -3515,12 +3604,19 @@ var Atbash = class _Atbash {
|
|
|
3515
3604
|
}
|
|
3516
3605
|
let chainOpts = options.chainOpts;
|
|
3517
3606
|
if (options.orgName) {
|
|
3518
|
-
const
|
|
3519
|
-
if (
|
|
3520
|
-
chainOpts = { network:
|
|
3521
|
-
} else
|
|
3522
|
-
const
|
|
3523
|
-
|
|
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
|
+
}
|
|
3524
3620
|
}
|
|
3525
3621
|
}
|
|
3526
3622
|
const brid = this.bridFromChainOpts(chainOpts);
|
|
@@ -3969,6 +4065,10 @@ var Atbash = class _Atbash {
|
|
|
3969
4065
|
clearChainCache() {
|
|
3970
4066
|
this._chainCache.clear();
|
|
3971
4067
|
}
|
|
4068
|
+
/** Drop the short-TTL `/api/ai/exists` cache. Useful in tests. */
|
|
4069
|
+
clearAgentExistsCache() {
|
|
4070
|
+
this._agentExistsCache = null;
|
|
4071
|
+
}
|
|
3972
4072
|
/* ── internals ─────────────────────────────────────────────────────────── */
|
|
3973
4073
|
/**
|
|
3974
4074
|
* Wrap an SDK method body in telemetry — records the call at start
|
|
@@ -4071,8 +4171,27 @@ var Atbash = class _Atbash {
|
|
|
4071
4171
|
this.endpoint
|
|
4072
4172
|
);
|
|
4073
4173
|
}
|
|
4074
|
-
/**
|
|
4174
|
+
/**
|
|
4175
|
+
* Wrap a transport failure (fetch threw, no response) as an AtbashAPIError.
|
|
4176
|
+
*
|
|
4177
|
+
* `HttpTransportError.kind` names the cause; the message is already
|
|
4178
|
+
* human-readable. `debug` echoes the original exception so operators can
|
|
4179
|
+
* cross-reference with node / undici logs when a class doesn't match.
|
|
4180
|
+
*/
|
|
4075
4181
|
transportError(err) {
|
|
4182
|
+
if (err instanceof HttpTransportError) {
|
|
4183
|
+
if (this.debug) {
|
|
4184
|
+
this.logger.warn?.(
|
|
4185
|
+
`[atbash] transport failed \u2014 kind=${err.kind}`,
|
|
4186
|
+
{
|
|
4187
|
+
kind: err.kind,
|
|
4188
|
+
cause: err.cause instanceof Error ? err.cause.message : String(err.cause ?? ""),
|
|
4189
|
+
endpoint: this.endpoint
|
|
4190
|
+
}
|
|
4191
|
+
);
|
|
4192
|
+
}
|
|
4193
|
+
return new AtbashAPIError(0, err.message, "", this.endpoint);
|
|
4194
|
+
}
|
|
4076
4195
|
return new AtbashAPIError(0, errorMessage(err), "", this.endpoint);
|
|
4077
4196
|
}
|
|
4078
4197
|
async json(resp) {
|
|
@@ -4299,24 +4418,29 @@ async function scanMemory(entry, auth, opts) {
|
|
|
4299
4418
|
toolArgsJson: opts?.toolArgsJson ?? JSON.stringify({ key: entry.key, source: entry.source }),
|
|
4300
4419
|
mode: "memory-scan"
|
|
4301
4420
|
});
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
return {
|
|
4307
|
-
safe: false,
|
|
4308
|
-
verdict: "red",
|
|
4309
|
-
reason: unknownAction ? `judge returned unrecognised action_type "${result.actionType}"` : "judge returned no verdict",
|
|
4310
|
-
confidence: result.confidence,
|
|
4311
|
-
score: native.defaultScoreForVerdict("red"),
|
|
4312
|
-
toolCallId: result.toolCallId
|
|
4313
|
-
};
|
|
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
|
+
);
|
|
4314
4425
|
}
|
|
4315
|
-
const
|
|
4316
|
-
|
|
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,
|
|
4317
4435
|
result.confidence,
|
|
4318
4436
|
threshold
|
|
4319
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
|
+
}
|
|
4320
4444
|
const parsed = native.parseScoreFromReason(result.reason);
|
|
4321
4445
|
const score = result.score ?? parsed.score ?? native.defaultScoreForVerdict(verdict);
|
|
4322
4446
|
return {
|
|
@@ -9222,8 +9346,8 @@ Reporter$3.prototype.wrapResult = function wrapResult(result) {
|
|
|
9222
9346
|
errors: state2.errors
|
|
9223
9347
|
};
|
|
9224
9348
|
};
|
|
9225
|
-
function ReporterError$1(
|
|
9226
|
-
this.path =
|
|
9349
|
+
function ReporterError$1(path7, msg) {
|
|
9350
|
+
this.path = path7;
|
|
9227
9351
|
this.rethrow(msg);
|
|
9228
9352
|
}
|
|
9229
9353
|
inherits$v(ReporterError$1, Error);
|
|
@@ -29444,8 +29568,8 @@ Reporter.prototype.wrapResult = function wrapResult2(result) {
|
|
|
29444
29568
|
errors: state2.errors
|
|
29445
29569
|
};
|
|
29446
29570
|
};
|
|
29447
|
-
function ReporterError(
|
|
29448
|
-
this.path =
|
|
29571
|
+
function ReporterError(path7, msg) {
|
|
29572
|
+
this.path = path7;
|
|
29449
29573
|
this.rethrow(msg);
|
|
29450
29574
|
}
|
|
29451
29575
|
inherits(ReporterError, Error);
|
|
@@ -32475,8 +32599,8 @@ var parseUtil = {};
|
|
|
32475
32599
|
const errors_js_12 = errors$3;
|
|
32476
32600
|
const en_js_12 = __importDefault2(en);
|
|
32477
32601
|
const makeIssue = (params) => {
|
|
32478
|
-
const { data, path:
|
|
32479
|
-
const fullPath = [...
|
|
32602
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
32603
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
32480
32604
|
const fullIssue = {
|
|
32481
32605
|
...issueData,
|
|
32482
32606
|
path: fullPath
|
|
@@ -32613,11 +32737,11 @@ var errorUtil_js_1 = errorUtil$1;
|
|
|
32613
32737
|
var parseUtil_js_1 = parseUtil;
|
|
32614
32738
|
var util_js_1 = util;
|
|
32615
32739
|
var ParseInputLazyPath = class {
|
|
32616
|
-
constructor(parent, value,
|
|
32740
|
+
constructor(parent, value, path7, key3) {
|
|
32617
32741
|
this._cachedPath = [];
|
|
32618
32742
|
this.parent = parent;
|
|
32619
32743
|
this.data = value;
|
|
32620
|
-
this._path =
|
|
32744
|
+
this._path = path7;
|
|
32621
32745
|
this._key = key3;
|
|
32622
32746
|
}
|
|
32623
32747
|
get path() {
|
|
@@ -39523,21 +39647,21 @@ function createTimeoutController(timeout) {
|
|
|
39523
39647
|
const timeoutId = setTimeout(() => controller.abort(timeoutError), timeout);
|
|
39524
39648
|
return { controller, timeoutId };
|
|
39525
39649
|
}
|
|
39526
|
-
function handleRequest(method,
|
|
39650
|
+
function handleRequest(method, path7, endpoint, timeout, postObject) {
|
|
39527
39651
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39528
39652
|
if (method == enums_1$2.Method.GET) {
|
|
39529
|
-
return yield get(
|
|
39653
|
+
return yield get(path7, endpoint, timeout);
|
|
39530
39654
|
} else {
|
|
39531
|
-
return yield post(
|
|
39655
|
+
return yield post(path7, endpoint, timeout, postObject);
|
|
39532
39656
|
}
|
|
39533
39657
|
});
|
|
39534
39658
|
}
|
|
39535
|
-
function get(
|
|
39659
|
+
function get(path7, endpoint, timeout) {
|
|
39536
39660
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39537
|
-
logger.debug(`GET URL ${new URL(
|
|
39661
|
+
logger.debug(`GET URL ${new URL(path7, endpoint).href}`);
|
|
39538
39662
|
try {
|
|
39539
39663
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39540
|
-
const response = yield fetch(new URL(
|
|
39664
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39541
39665
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39542
39666
|
});
|
|
39543
39667
|
if (timeoutId)
|
|
@@ -39575,9 +39699,9 @@ function constructBufferResponseBody(response) {
|
|
|
39575
39699
|
return responseText ? responseText : response.statusText;
|
|
39576
39700
|
});
|
|
39577
39701
|
}
|
|
39578
|
-
function post(
|
|
39702
|
+
function post(path7, endpoint, timeout, requestBody) {
|
|
39579
39703
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39580
|
-
logger.debug(`POST URL ${new URL(
|
|
39704
|
+
logger.debug(`POST URL ${new URL(path7, endpoint).href}`);
|
|
39581
39705
|
logger.debug(`POST body ${JSON.stringify(requestBody)}`);
|
|
39582
39706
|
if (buffer_1.Buffer.isBuffer(requestBody)) {
|
|
39583
39707
|
try {
|
|
@@ -39591,7 +39715,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39591
39715
|
},
|
|
39592
39716
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39593
39717
|
};
|
|
39594
|
-
const response = yield fetch(new URL(
|
|
39718
|
+
const response = yield fetch(new URL(path7, endpoint).href, requestOptions);
|
|
39595
39719
|
if (timeoutId)
|
|
39596
39720
|
clearTimeout(timeoutId);
|
|
39597
39721
|
const transactionTimestamp = response.headers.get("X-Transaction-Timestamp");
|
|
@@ -39602,7 +39726,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39602
39726
|
} else {
|
|
39603
39727
|
try {
|
|
39604
39728
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39605
|
-
const response = yield fetch(new URL(
|
|
39729
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39606
39730
|
method: "post",
|
|
39607
39731
|
body: JSON.stringify(requestBody),
|
|
39608
39732
|
headers: {
|
|
@@ -39782,10 +39906,10 @@ function requireFailoverStrategies() {
|
|
|
39782
39906
|
}
|
|
39783
39907
|
}
|
|
39784
39908
|
function abortOnError(_a2) {
|
|
39785
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39909
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39786
39910
|
return yield retryRequest({
|
|
39787
39911
|
method,
|
|
39788
|
-
path:
|
|
39912
|
+
path: path7,
|
|
39789
39913
|
config: config2,
|
|
39790
39914
|
postObject,
|
|
39791
39915
|
timeoutOverride,
|
|
@@ -39796,10 +39920,10 @@ function requireFailoverStrategies() {
|
|
|
39796
39920
|
});
|
|
39797
39921
|
}
|
|
39798
39922
|
function tryNextOnError(_a2) {
|
|
39799
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39923
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39800
39924
|
return yield retryRequest({
|
|
39801
39925
|
method,
|
|
39802
|
-
path:
|
|
39926
|
+
path: path7,
|
|
39803
39927
|
config: config2,
|
|
39804
39928
|
postObject,
|
|
39805
39929
|
timeoutOverride,
|
|
@@ -39815,7 +39939,7 @@ function requireFailoverStrategies() {
|
|
|
39815
39939
|
return endpointPoolLength - (endpointPoolLength - 1) / 3;
|
|
39816
39940
|
}
|
|
39817
39941
|
function queryMajority(_a2) {
|
|
39818
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39942
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39819
39943
|
var _b;
|
|
39820
39944
|
const bftMajorityThreshold = calculateBftMajorityThreshold(config2.endpointPool.length);
|
|
39821
39945
|
const failureThreshold = config2.endpointPool.length - bftMajorityThreshold + 1;
|
|
@@ -39826,7 +39950,7 @@ function requireFailoverStrategies() {
|
|
|
39826
39950
|
const promises = availableNodes.map((node2) => __awaiter2(this, void 0, void 0, function* () {
|
|
39827
39951
|
try {
|
|
39828
39952
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39829
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
39953
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39830
39954
|
const { statusCode } = response;
|
|
39831
39955
|
if (statusCode && (0, http_utils_1.isSuccessfulStatusCode)(statusCode)) {
|
|
39832
39956
|
outcomes.push({ type: "SUCCESS", result: response });
|
|
@@ -39873,7 +39997,7 @@ function requireFailoverStrategies() {
|
|
|
39873
39997
|
});
|
|
39874
39998
|
}
|
|
39875
39999
|
function singleEndpoint(_a2) {
|
|
39876
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40000
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39877
40001
|
let statusCode = null;
|
|
39878
40002
|
let rspBody = null;
|
|
39879
40003
|
let error4 = null;
|
|
@@ -39884,7 +40008,7 @@ function requireFailoverStrategies() {
|
|
|
39884
40008
|
}
|
|
39885
40009
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
39886
40010
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39887
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40011
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, endpoint.url, requestTimeout, postObject);
|
|
39888
40012
|
if (response) {
|
|
39889
40013
|
({ error: error4, statusCode, rspBody, transactionTimestamp } = response);
|
|
39890
40014
|
}
|
|
@@ -39899,7 +40023,7 @@ function requireFailoverStrategies() {
|
|
|
39899
40023
|
});
|
|
39900
40024
|
}
|
|
39901
40025
|
function retryRequest(_a2) {
|
|
39902
|
-
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 }) {
|
|
39903
40027
|
var _b, _c, _d;
|
|
39904
40028
|
let statusCode = null;
|
|
39905
40029
|
let rspBody = null;
|
|
@@ -39910,7 +40034,7 @@ function requireFailoverStrategies() {
|
|
|
39910
40034
|
for (const node2 of availableNodes) {
|
|
39911
40035
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
39912
40036
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39913
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40037
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39914
40038
|
error4 = (_b = response === null || response === void 0 ? void 0 : response.error) !== null && _b !== void 0 ? _b : null;
|
|
39915
40039
|
statusCode = (_c = response === null || response === void 0 ? void 0 : response.statusCode) !== null && _c !== void 0 ? _c : null;
|
|
39916
40040
|
rspBody = (_d = response === null || response === void 0 ? void 0 : response.rspBody) !== null && _d !== void 0 ? _d : null;
|
|
@@ -40053,19 +40177,19 @@ function requireRequestWithFailoverStrategy() {
|
|
|
40053
40177
|
const enums_12 = enums;
|
|
40054
40178
|
const failoverStrategies_1 = requireFailoverStrategies();
|
|
40055
40179
|
function requestWithFailoverStrategy$1(method_1, path_1, config_1, postObject_1) {
|
|
40056
|
-
return __awaiter2(this, arguments, void 0, function* (method,
|
|
40180
|
+
return __awaiter2(this, arguments, void 0, function* (method, path7, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
|
|
40057
40181
|
switch (config2.failoverStrategy) {
|
|
40058
40182
|
case enums_12.FailoverStrategy.AbortOnError:
|
|
40059
|
-
return yield (0, failoverStrategies_1.abortOnError)({ method, path:
|
|
40183
|
+
return yield (0, failoverStrategies_1.abortOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40060
40184
|
case enums_12.FailoverStrategy.TryNextOnError:
|
|
40061
|
-
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path:
|
|
40185
|
+
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40062
40186
|
case enums_12.FailoverStrategy.SingleEndpoint:
|
|
40063
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40187
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40064
40188
|
case enums_12.FailoverStrategy.QueryMajority:
|
|
40065
40189
|
if (forceSingleEndpoint) {
|
|
40066
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40190
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40067
40191
|
}
|
|
40068
|
-
return yield (0, failoverStrategies_1.queryMajority)({ method, path:
|
|
40192
|
+
return yield (0, failoverStrategies_1.queryMajority)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40069
40193
|
default:
|
|
40070
40194
|
throw new Error(`Unsupported failover strategy: ${config2.failoverStrategy}`);
|
|
40071
40195
|
}
|
|
@@ -41264,7 +41388,7 @@ var networkSettings = {};
|
|
|
41264
41388
|
const restNetworkSettingsValidationContext = RestNetworkSettingsSchema.safeParse(networkSettings2);
|
|
41265
41389
|
if ("error" in restNetworkSettingsValidationContext) {
|
|
41266
41390
|
const { error: { issues } = {} } = restNetworkSettingsValidationContext;
|
|
41267
|
-
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(", ");
|
|
41268
41392
|
if (throwOnError) {
|
|
41269
41393
|
throw new Error(errorMessage2);
|
|
41270
41394
|
}
|
|
@@ -42646,6 +42770,7 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
|
|
|
42646
42770
|
}
|
|
42647
42771
|
|
|
42648
42772
|
// src-ts/memory/guard.ts
|
|
42773
|
+
import path3 from "path";
|
|
42649
42774
|
function emitDebugProbe(event, ctx, memEntry, logger2) {
|
|
42650
42775
|
if (!logger2?.info) return;
|
|
42651
42776
|
const ev = event ?? {};
|
|
@@ -42682,7 +42807,8 @@ async function guardMemoryWrite(input) {
|
|
|
42682
42807
|
toolNames,
|
|
42683
42808
|
enforce = true,
|
|
42684
42809
|
debug: debug2 = false,
|
|
42685
|
-
logger: logger2
|
|
42810
|
+
logger: logger2,
|
|
42811
|
+
memoryFilePath
|
|
42686
42812
|
} = input;
|
|
42687
42813
|
const memEntry = classifyMemoryWrite(event, ctx, { patterns, toolNames });
|
|
42688
42814
|
if (debug2) emitDebugProbe(event, ctx, memEntry, logger2);
|
|
@@ -42718,17 +42844,28 @@ async function guardMemoryWrite(input) {
|
|
|
42718
42844
|
committed: false
|
|
42719
42845
|
};
|
|
42720
42846
|
}
|
|
42721
|
-
|
|
42722
|
-
|
|
42723
|
-
|
|
42724
|
-
|
|
42725
|
-
|
|
42726
|
-
|
|
42727
|
-
|
|
42728
|
-
|
|
42729
|
-
|
|
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
|
+
});
|
|
42730
42859
|
});
|
|
42731
|
-
}
|
|
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
|
+
}
|
|
42732
42869
|
logger2?.info?.(
|
|
42733
42870
|
scanResult.verdict === "yellow" ? "[atbash] memory HOLD" : "[atbash] memory ALLOW",
|
|
42734
42871
|
{ path: memEntry.key, score: scanResult.score, reason: scanResult.reason }
|
|
@@ -42737,7 +42874,7 @@ async function guardMemoryWrite(input) {
|
|
|
42737
42874
|
handled: true,
|
|
42738
42875
|
decision: { allow: true },
|
|
42739
42876
|
scanResult,
|
|
42740
|
-
committed:
|
|
42877
|
+
committed: isManagedMemoryFile
|
|
42741
42878
|
};
|
|
42742
42879
|
}
|
|
42743
42880
|
|
|
@@ -42756,26 +42893,26 @@ async function syncLocalMemory(auth, pointer, opts = {}) {
|
|
|
42756
42893
|
const now = Date.now();
|
|
42757
42894
|
const withinTtl = !opts.force && now - pointer.checkedAt < ttl;
|
|
42758
42895
|
if (withinTtl) {
|
|
42759
|
-
return { drifted: false, pointer };
|
|
42896
|
+
return { drifted: false, checked: false, pointer };
|
|
42760
42897
|
}
|
|
42761
42898
|
const currentId = await getActiveMemoryId(auth, opts.chainOpts);
|
|
42762
42899
|
const nextPointer = { activeId: currentId, checkedAt: now };
|
|
42763
42900
|
if (currentId === pointer.activeId) {
|
|
42764
|
-
return { drifted: false, pointer: nextPointer };
|
|
42901
|
+
return { drifted: false, checked: true, pointer: nextPointer };
|
|
42765
42902
|
}
|
|
42766
42903
|
if (currentId === null) {
|
|
42767
|
-
return { drifted: true, current: null, pointer: nextPointer };
|
|
42904
|
+
return { drifted: true, checked: true, current: null, pointer: nextPointer };
|
|
42768
42905
|
}
|
|
42769
42906
|
const row = await getMemoryById(currentId, auth, opts.chainOpts);
|
|
42770
42907
|
if (row.decryptError) {
|
|
42771
42908
|
throw new MemoryIntegrityError(currentId, row.decryptError);
|
|
42772
42909
|
}
|
|
42773
|
-
return { drifted: true, current: row, pointer: nextPointer };
|
|
42910
|
+
return { drifted: true, checked: true, current: row, pointer: nextPointer };
|
|
42774
42911
|
}
|
|
42775
42912
|
|
|
42776
42913
|
// src-ts/memory/pointer-store.ts
|
|
42777
42914
|
import { promises as fs } from "fs";
|
|
42778
|
-
import
|
|
42915
|
+
import path4 from "path";
|
|
42779
42916
|
var EMPTY = { version: 1, agents: {} };
|
|
42780
42917
|
var PointerStore = class {
|
|
42781
42918
|
constructor(filePath) {
|
|
@@ -42817,19 +42954,19 @@ var PointerStore = class {
|
|
|
42817
42954
|
this.cache = { ...EMPTY, agents: {} };
|
|
42818
42955
|
}
|
|
42819
42956
|
async persist(file) {
|
|
42820
|
-
await fs.mkdir(
|
|
42957
|
+
await fs.mkdir(path4.dirname(this.filePath), { recursive: true });
|
|
42821
42958
|
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
42822
42959
|
await fs.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
|
|
42823
42960
|
await fs.rename(tmp, this.filePath);
|
|
42824
42961
|
}
|
|
42825
42962
|
};
|
|
42826
42963
|
function defaultPointerPath(workspaceDir = process.cwd()) {
|
|
42827
|
-
return
|
|
42964
|
+
return path4.join(workspaceDir, ".atbash", "memory-pointer.json");
|
|
42828
42965
|
}
|
|
42829
42966
|
|
|
42830
42967
|
// src-ts/memory/file-logger.ts
|
|
42831
42968
|
import { promises as fs2 } from "fs";
|
|
42832
|
-
import
|
|
42969
|
+
import path5 from "path";
|
|
42833
42970
|
function formatMeta(meta) {
|
|
42834
42971
|
if (!meta || Object.keys(meta).length === 0) return "";
|
|
42835
42972
|
try {
|
|
@@ -42841,7 +42978,7 @@ function formatMeta(meta) {
|
|
|
42841
42978
|
function createFileLogger(filePath, upstream) {
|
|
42842
42979
|
let queue = Promise.resolve();
|
|
42843
42980
|
async function ensureDir() {
|
|
42844
|
-
await fs2.mkdir(
|
|
42981
|
+
await fs2.mkdir(path5.dirname(filePath), { recursive: true });
|
|
42845
42982
|
}
|
|
42846
42983
|
function append(level, message, meta) {
|
|
42847
42984
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
|
|
@@ -42861,7 +42998,7 @@ function createFileLogger(filePath, upstream) {
|
|
|
42861
42998
|
};
|
|
42862
42999
|
}
|
|
42863
43000
|
function defaultPluginLogPath(workspaceDir = process.cwd()) {
|
|
42864
|
-
return
|
|
43001
|
+
return path5.join(workspaceDir, ".atbash", "plugin.log");
|
|
42865
43002
|
}
|
|
42866
43003
|
|
|
42867
43004
|
// src-ts/memory/read-classifier.ts
|
|
@@ -42876,13 +43013,13 @@ function classifyMemoryRead(event, ctx, opts = {}) {
|
|
|
42876
43013
|
|
|
42877
43014
|
// src-ts/memory/guard-manager.ts
|
|
42878
43015
|
import { promises as fs3 } from "fs";
|
|
42879
|
-
import
|
|
43016
|
+
import path6 from "path";
|
|
42880
43017
|
var DEFAULT_SYNC_TTL_MS = 3e4;
|
|
42881
43018
|
var MemoryGuardManager = class {
|
|
42882
43019
|
constructor(opts) {
|
|
42883
43020
|
this.opts = opts;
|
|
42884
43021
|
const workspaceDir = opts.workspaceDir;
|
|
42885
|
-
this.memoryFilePath = opts.memoryFilePath ??
|
|
43022
|
+
this.memoryFilePath = opts.memoryFilePath ?? path6.join(workspaceDir, "MEMORY.md");
|
|
42886
43023
|
this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
|
|
42887
43024
|
this.logger = createFileLogger(
|
|
42888
43025
|
opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
|
|
@@ -42912,7 +43049,11 @@ var MemoryGuardManager = class {
|
|
|
42912
43049
|
async runBootProbe() {
|
|
42913
43050
|
try {
|
|
42914
43051
|
const seed = { activeId: null, checkedAt: 0 };
|
|
42915
|
-
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
|
+
});
|
|
42916
43057
|
if (!result.drifted && result.pointer.activeId == null) {
|
|
42917
43058
|
this.logger.info(
|
|
42918
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.`
|
|
@@ -42944,15 +43085,19 @@ var MemoryGuardManager = class {
|
|
|
42944
43085
|
}
|
|
42945
43086
|
}
|
|
42946
43087
|
/**
|
|
42947
|
-
* Returns a `HookDecision` when the
|
|
42948
|
-
*
|
|
42949
|
-
*
|
|
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.
|
|
42950
43096
|
*/
|
|
42951
43097
|
async handleBeforeToolCall(event, ctx) {
|
|
42952
43098
|
if (classifyMemoryRead(event, ctx, this.opts.memoryReadClassifier)) {
|
|
42953
43099
|
this.logger.info("[atbash] memory read intercepted \u2014 running sync check");
|
|
42954
|
-
|
|
42955
|
-
return readDecision ?? { allow: true };
|
|
43100
|
+
return await this.handleMemoryRead(event, ctx);
|
|
42956
43101
|
}
|
|
42957
43102
|
const guardLogger = {
|
|
42958
43103
|
info: (msg, meta) => this.logger.info(msg, meta && typeof meta === "object" ? meta : void 0),
|
|
@@ -42969,7 +43114,9 @@ var MemoryGuardManager = class {
|
|
|
42969
43114
|
toolNames: this.opts.memoryWriteToolNames,
|
|
42970
43115
|
enforce: this.enforce,
|
|
42971
43116
|
debug: this.opts.debug,
|
|
42972
|
-
logger: guardLogger
|
|
43117
|
+
logger: guardLogger,
|
|
43118
|
+
// Only this file may reach the single, path-less chain memory slot.
|
|
43119
|
+
memoryFilePath: this.memoryFilePath
|
|
42973
43120
|
});
|
|
42974
43121
|
return this.mapGuardResult(guard);
|
|
42975
43122
|
}
|
|
@@ -42987,30 +43134,81 @@ var MemoryGuardManager = class {
|
|
|
42987
43134
|
block: true,
|
|
42988
43135
|
blockReason: d.reason ?? "",
|
|
42989
43136
|
allow: false,
|
|
42990
|
-
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 } : {}
|
|
42991
43143
|
};
|
|
42992
43144
|
}
|
|
42993
43145
|
this.logger.info(
|
|
42994
43146
|
`[atbash] guardMemoryWrite ALLOWED \u2014 verdict=${verdict} score=${score} committed=${guard.committed === true}`
|
|
42995
43147
|
);
|
|
42996
|
-
|
|
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 };
|
|
42997
43160
|
}
|
|
42998
|
-
|
|
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) {
|
|
42999
43193
|
const pointer = await this.pointerStore.get(this.agentPubkeyHex);
|
|
43000
43194
|
let result;
|
|
43001
43195
|
try {
|
|
43002
|
-
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
|
+
});
|
|
43003
43200
|
} catch (err) {
|
|
43004
43201
|
if (err instanceof MemoryIntegrityError) {
|
|
43005
43202
|
const reason = `Memory integrity check failed on id ${err.id} \u2014 read blocked.`;
|
|
43006
43203
|
this.logger.warn("[atbash] MEMORY INTEGRITY FAILURE", { id: err.id, error: err.message });
|
|
43007
43204
|
if (!this.enforce) return null;
|
|
43008
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43205
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43009
43206
|
}
|
|
43010
43207
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43011
43208
|
this.logger.warn("[atbash] memory sync failed (serving local copy)", { error: msg });
|
|
43012
43209
|
return null;
|
|
43013
43210
|
}
|
|
43211
|
+
let onDiskIsCurrent = result.checked;
|
|
43014
43212
|
if (result.drifted) {
|
|
43015
43213
|
const fresh = result.current;
|
|
43016
43214
|
if (fresh) {
|
|
@@ -43018,7 +43216,7 @@ var MemoryGuardManager = class {
|
|
|
43018
43216
|
const reason = `Rolled-back memory version #${fresh.id} scored ${fresh.score} (below threshold ${this.rollbackMinScore}) \u2014 read blocked.`;
|
|
43019
43217
|
this.logger.warn("[atbash] blocking read on low-score rollback", { id: fresh.id, score: fresh.score });
|
|
43020
43218
|
if (!this.enforce) return null;
|
|
43021
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43219
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43022
43220
|
}
|
|
43023
43221
|
this.logger.info("[atbash] memory drift detected \u2014 refreshing local file", {
|
|
43024
43222
|
id: fresh.id,
|
|
@@ -43029,16 +43227,26 @@ var MemoryGuardManager = class {
|
|
|
43029
43227
|
} catch (err) {
|
|
43030
43228
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43031
43229
|
this.logger.warn("[atbash] failed to write refreshed memory (serving old)", { error: msg });
|
|
43230
|
+
onDiskIsCurrent = false;
|
|
43032
43231
|
}
|
|
43033
43232
|
} else {
|
|
43034
43233
|
this.logger.info("[atbash] active memory removed on chain", { pubkey: this.agentPubkeyHex });
|
|
43234
|
+
onDiskIsCurrent = false;
|
|
43035
43235
|
}
|
|
43036
43236
|
}
|
|
43037
|
-
|
|
43038
|
-
|
|
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 };
|
|
43039
43247
|
}
|
|
43040
43248
|
async writeMemoryAtomic(content) {
|
|
43041
|
-
await fs3.mkdir(
|
|
43249
|
+
await fs3.mkdir(path6.dirname(this.memoryFilePath), { recursive: true });
|
|
43042
43250
|
const tmp = `${this.memoryFilePath}.${process.pid}.tmp`;
|
|
43043
43251
|
await fs3.writeFile(tmp, content, "utf8");
|
|
43044
43252
|
await fs3.rename(tmp, this.memoryFilePath);
|
|
@@ -43176,6 +43384,8 @@ export {
|
|
|
43176
43384
|
DEFAULT_MEMORY_READ_TOOL_NAMES,
|
|
43177
43385
|
DEFAULT_MEMORY_WRITE_TOOL_NAMES,
|
|
43178
43386
|
EciesDomain,
|
|
43387
|
+
HttpClient,
|
|
43388
|
+
HttpTransportError,
|
|
43179
43389
|
KEY_FILENAMES,
|
|
43180
43390
|
MemoryGuardManager,
|
|
43181
43391
|
MemoryIntegrityError,
|