motebit 1.8.2 → 1.8.3

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.
Files changed (2) hide show
  1. package/dist/index.js +1892 -1216
  2. package/package.json +20 -20
package/dist/index.js CHANGED
@@ -32,11 +32,11 @@ var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__
32
32
  mod2
33
33
  ));
34
34
 
35
- // ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.7_@types+node@22.19.11__jiti@2.7.0_postcss@8.5.16_ts_xuiywaftjaf3xqmztb5qab265a/node_modules/tsup/assets/esm_shims.js
35
+ // ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.9_@types+node@22.20.0__jiti@2.7.0_postcss@8.5.17_tsx_474vhr7z2nqb2hrdxb4x6wi5oi/node_modules/tsup/assets/esm_shims.js
36
36
  import path from "path";
37
37
  import { fileURLToPath } from "url";
38
38
  var init_esm_shims = __esm({
39
- "../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.7_@types+node@22.19.11__jiti@2.7.0_postcss@8.5.16_ts_xuiywaftjaf3xqmztb5qab265a/node_modules/tsup/assets/esm_shims.js"() {
39
+ "../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.9_@types+node@22.20.0__jiti@2.7.0_postcss@8.5.17_tsx_474vhr7z2nqb2hrdxb4x6wi5oi/node_modules/tsup/assets/esm_shims.js"() {
40
40
  "use strict";
41
41
  }
42
42
  });
@@ -4578,6 +4578,7 @@ You do not have eyes. "What you see" means what a tool returned this turn \u2014
4578
4578
  - Prefer element-addressed actions (\`click_element\`, \`focus_element\`, \`type_into\`) over coordinate-based \`click\` / \`type\` whenever the target was discovered via \`read_page\`. read_page returns \`inputs[]\` and \`buttons[]\` arrays where each entry carries an opaque server-issued \`element_id\`; pass that id to the element-addressed actions and the server resolves + acts atomically \u2014 durable against viewport, zoom, and layout shifts. Coordinate \`click\` / \`type\` remain available for purely-visual tasks (drag a slider to a position seen in pixels). If a call returns \`element_not_found\`, the page navigated or reloaded since read_page \u2014 call read_page again to refresh the id space, then retry.
4579
4579
  - The click family (\`click\` / \`double_click\` / \`click_element\`) and \`key\` action's \`ok: true\` only means the action fired \u2014 it does NOT mean a form submission or link triggered a navigation. Read \`navigation_triggered\` on the result. When \`navigation_triggered: false\` on a submit-class action (clicking the submit button by coordinate or element_id, pressing Enter in a form input), the click / keystroke landed but the page didn't move \u2014 the form submission was blocked, intercepted by an overlay (cookie banner, promo dialog), or silently dropped by bot-detection without rendering a CAPTCHA. Do NOT say "Done" / "submitted" / "search ran" when \`navigation_triggered: false\` on a submit-shape intent; surface the truth ("the click landed but the page didn't move \u2014 let me read the page to see what's there") and chain a fallback (read_page, fresh screenshot, or \u2014 for search-shape intents \u2014 \`web_search\`).
4580
4580
  - **Form submission: when \`read_page\` returns \`submit_button_id\`, prefer \`click_element(submit_button_id)\` over \`key("Enter")\`.** The runtime detects the form's primary submit element (via HTML \`input_type === "submit"\` first, label heuristic as fallback \u2014 "Search" / "Submit" / "Send" / "Sign in" / "Continue" etc.) and surfaces its element_id directly on the result. Clicking the resolved button is atomic \u2014 no focus race, no "did Enter go to the right thing?" ambiguity. Reserve \`key("Enter")\` for the three cases the wire field can't cover: \`submit_button_id\` is absent (custom widgets, terminals, REPLs), the form is in a sandboxed cross-origin iframe whose buttons don't surface (reCAPTCHA \u2014 neither tool works there; that's user-handoff territory), or Enter is the page's only path (code editors, multi-line entry commit). Same shape for the rest of the keyboard: Escape \u2192 close button via \`click_element\` first; Tab \u2192 \`focus_element\` with the next field's id. Keyboard is right when there's no element to address; when there is, address it.
4581
+ - **The live agent roster comes from \`discover_agents\`, never from recall.** "Who is discoverable / delegable right now, and at what price?" is answerable ONLY from a \`discover_agents\` result in this conversation \u2014 the one source stamped \`roster_source: "live_relay_read"\`. Your self-knowledge corpus and any repo self-description you recall describe the marketplace's DESIGN (which first-party services exist in the codebase, their intended pricing) \u2014 that is shape, never the current directory; agents in the repo may be undeployed, and agents on the relay may not be in the repo. Witnessed failure this rule kills: confidently reciting a six-agent roster with prices from the corpus while the live relay had two. A \`claimed_name\` on a discovered agent is a self-asserted claim, never a verified handle \u2014 say 'claims "The Researcher"', not 'is The Researcher'. If \`discover_agents\` is unavailable or fails, the honest answer is "I'd need to check the live directory" \u2014 never a reconstructed roster.
4581
4582
  - "I don't know without looking" is a complete answer when no tool result is available. Confabulation is the failure mode this rule exists to prevent.
4582
4583
  - **Task-step narration** \u2014 when you're actively doing something the user is supervising, emit a \`<narration>\` tag in your response with a single first-person present-tense sentence, ~80 chars max: \`<narration>Reading the page</narration>\`, \`<narration>Filling in the form</narration>\`, \`<narration>Solving a CAPTCHA</narration>\`, \`<narration>Hit a paywall \u2014 need your input</narration>\`, \`<narration>Submission didn't land \u2014 re-reading the page</narration>\`. Granularity is the supervisor-cares-about chunk between action ("Typing 'm-o-t-e-b-i-t'") and goal ("Looking up the M2 spec"). The runtime parses the tag into the \`task_step_narration\` field on your response; the chrome consumes that field and renders it in the slab's \`motebit \xD7 virtual_browser\` register; the runtime validates against typed-truth before display so \`<narration>Reading apple.com</narration>\` when the actual URL is google.com gets falsified and replaced with a runtime-templated fallback. The \`<narration>\` tag is stripped from the visible text so it doesn't leak into the chat / mote conversation register. Omit the tag when idle, thinking, or no active task-step (the chrome recedes to the empty register). One tag per response; the runtime takes the LAST tag if you emit multiple. Goals \u2014 what the user asked you to accomplish \u2014 go in your visible response text, not here.`;
4583
4584
  CONVERSATION_BEHAVIOR = `[How you converse]
@@ -6534,17 +6535,6 @@ var init_memory_index = __esm({
6534
6535
  });
6535
6536
 
6536
6537
  // ../../packages/memory-graph/dist/embeddings.js
6537
- var embeddings_exports = {};
6538
- __export(embeddings_exports, {
6539
- EMBEDDING_DIMENSIONS: () => EMBEDDING_DIMENSIONS,
6540
- embedText: () => embedText,
6541
- embedTextHash: () => embedTextHash,
6542
- resetPipeline: () => resetPipeline,
6543
- setRemoteEmbedUrl: () => setRemoteEmbedUrl
6544
- });
6545
- function setRemoteEmbedUrl(url) {
6546
- remoteEmbedUrl = url;
6547
- }
6548
6538
  async function remoteEmbed(text) {
6549
6539
  const res = await fetch(remoteEmbedUrl, {
6550
6540
  method: "POST",
@@ -6572,10 +6562,6 @@ async function getPipeline() {
6572
6562
  throw e2;
6573
6563
  }
6574
6564
  }
6575
- function resetPipeline() {
6576
- pipelineInstance = null;
6577
- pipelineFailed = false;
6578
- }
6579
6565
  async function embedText(text) {
6580
6566
  if (text === "") {
6581
6567
  return new Array(EMBEDDING_DIMENSIONS).fill(0);
@@ -7320,6 +7306,7 @@ var init_dist3 = __esm({
7320
7306
  init_promotion();
7321
7307
  init_memory_index();
7322
7308
  init_embeddings();
7309
+ init_embeddings();
7323
7310
  init_consolidation();
7324
7311
  init_retrieval();
7325
7312
  init_accrual2();
@@ -7437,13 +7424,15 @@ var init_dist3 = __esm({
7437
7424
  storage;
7438
7425
  eventStore;
7439
7426
  motebitId;
7427
+ embed;
7440
7428
  scoringConfig;
7441
7429
  _retrievalScores = [];
7442
7430
  _precisionOverride = null;
7443
- constructor(storage, eventStore, motebitId, scoringConfig) {
7431
+ constructor(storage, eventStore, motebitId, scoringConfig, embed = embedText) {
7444
7432
  this.storage = storage;
7445
7433
  this.eventStore = eventStore;
7446
7434
  this.motebitId = motebitId;
7435
+ this.embed = embed;
7447
7436
  this.scoringConfig = { ...DEFAULT_SCORING_CONFIG, ...scoringConfig };
7448
7437
  }
7449
7438
  /**
@@ -7971,8 +7960,7 @@ var init_dist3 = __esm({
7971
7960
  throw new Error(`No memory node with id ${oldNodeId}`);
7972
7961
  if (oldNode.tombstoned)
7973
7962
  throw new Error(`Memory ${oldNodeId} is already tombstoned`);
7974
- const { embedText: embedText2 } = await Promise.resolve().then(() => (init_embeddings(), embeddings_exports));
7975
- const embedding = await embedText2(newContent);
7963
+ const embedding = await this.embed(newContent);
7976
7964
  const now = Date.now();
7977
7965
  const newNode = await this.formMemory({
7978
7966
  content: newContent,
@@ -19875,7 +19863,11 @@ function deriveSolanaAddress(publicKey) {
19875
19863
  }
19876
19864
  return base58Encode(publicKey);
19877
19865
  }
19878
- var ASSET_NAME_USDC, Web3JsRpcAdapter;
19866
+ function isBlockhashExpiry(err2) {
19867
+ const msg = err2 instanceof Error ? err2.message : String(err2);
19868
+ return msg.includes("block height exceeded");
19869
+ }
19870
+ var ASSET_NAME_USDC, BROADCAST_MAX_ATTEMPTS, Web3JsRpcAdapter;
19879
19871
  var init_web3js_adapter = __esm({
19880
19872
  "../../packages/wallet-solana/dist/web3js-adapter.js"() {
19881
19873
  "use strict";
@@ -19883,6 +19875,7 @@ var init_web3js_adapter = __esm({
19883
19875
  init_dist();
19884
19876
  init_constants();
19885
19877
  ASSET_NAME_USDC = "USDC";
19878
+ BROADCAST_MAX_ATTEMPTS = 3;
19886
19879
  Web3JsRpcAdapter = class _Web3JsRpcAdapter {
19887
19880
  connection;
19888
19881
  keypair;
@@ -19961,7 +19954,7 @@ var init_web3js_adapter = __esm({
19961
19954
  }
19962
19955
  const sourceAta = await getAssociatedTokenAddress(this.mint, this.keypair.publicKey);
19963
19956
  const destAta = await getAssociatedTokenAddress(this.mint, recipient);
19964
- const tx = new Transaction();
19957
+ const instructions = [];
19965
19958
  let destExists = false;
19966
19959
  try {
19967
19960
  await getAccount(this.connection, destAta, this.commitment);
@@ -19971,7 +19964,7 @@ var init_web3js_adapter = __esm({
19971
19964
  throw err2;
19972
19965
  }
19973
19966
  if (!destExists) {
19974
- tx.add(createAssociatedTokenAccountInstruction(
19967
+ instructions.push(createAssociatedTokenAccountInstruction(
19975
19968
  this.keypair.publicKey,
19976
19969
  // payer
19977
19970
  destAta,
@@ -19979,22 +19972,49 @@ var init_web3js_adapter = __esm({
19979
19972
  this.mint
19980
19973
  ));
19981
19974
  }
19982
- tx.add(createTransferInstruction(sourceAta, destAta, this.keypair.publicKey, args.microAmount));
19983
- const latest = await this.connection.getLatestBlockhash(this.commitment);
19984
- tx.recentBlockhash = latest.blockhash;
19985
- tx.feePayer = this.keypair.publicKey;
19986
- tx.sign(this.keypair);
19987
- const signature = await this.connection.sendRawTransaction(tx.serialize());
19988
- const confirmation = await this.connection.confirmTransaction({
19989
- signature,
19990
- blockhash: latest.blockhash,
19991
- lastValidBlockHeight: latest.lastValidBlockHeight
19992
- }, this.commitment);
19993
- return {
19994
- signature,
19995
- slot: confirmation.context.slot,
19996
- confirmed: confirmation.value.err === null
19997
- };
19975
+ instructions.push(createTransferInstruction(sourceAta, destAta, this.keypair.publicKey, args.microAmount));
19976
+ return this.signSendConfirm(instructions);
19977
+ }
19978
+ /**
19979
+ * Build a transaction from `instructions`, sign it over a FRESH recent
19980
+ * blockhash, broadcast, and await confirmation — retrying with a new blockhash
19981
+ * on a `TransactionExpiredBlockheightExceededError` (the permanent-expiry
19982
+ * flake). Each attempt rebuilds the transaction from the instructions so no
19983
+ * stale blockhash/signature state carries over; the expired attempt can never
19984
+ * land (`isBlockhashExpiry`), so the retry cannot double-spend. Any non-expiry
19985
+ * error propagates immediately (conservative — only the known-safe failure is
19986
+ * retried).
19987
+ */
19988
+ async signSendConfirm(instructions) {
19989
+ let lastErr;
19990
+ for (let attempt = 1; attempt <= BROADCAST_MAX_ATTEMPTS; attempt++) {
19991
+ try {
19992
+ const tx = new Transaction();
19993
+ for (const ix of instructions)
19994
+ tx.add(ix);
19995
+ const latest = await this.connection.getLatestBlockhash(this.commitment);
19996
+ tx.recentBlockhash = latest.blockhash;
19997
+ tx.feePayer = this.keypair.publicKey;
19998
+ tx.sign(this.keypair);
19999
+ const signature = await this.connection.sendRawTransaction(tx.serialize());
20000
+ const confirmation = await this.connection.confirmTransaction({
20001
+ signature,
20002
+ blockhash: latest.blockhash,
20003
+ lastValidBlockHeight: latest.lastValidBlockHeight
20004
+ }, this.commitment);
20005
+ return {
20006
+ signature,
20007
+ slot: confirmation.context.slot,
20008
+ confirmed: confirmation.value.err === null
20009
+ };
20010
+ } catch (err2) {
20011
+ lastErr = err2;
20012
+ if (attempt < BROADCAST_MAX_ATTEMPTS && isBlockhashExpiry(err2))
20013
+ continue;
20014
+ throw err2;
20015
+ }
20016
+ }
20017
+ throw lastErr;
19998
20018
  }
19999
20019
  /**
20000
20020
  * Conservative max transfers per Solana transaction.
@@ -20031,7 +20051,7 @@ var init_web3js_adapter = __esm({
20031
20051
  continue;
20032
20052
  }
20033
20053
  try {
20034
- const tx = new Transaction();
20054
+ const instructions = [];
20035
20055
  const sourceAta = await getAssociatedTokenAddress(this.mint, this.keypair.publicKey);
20036
20056
  for (let i3 = start; i3 < end; i3++) {
20037
20057
  const item = items[i3];
@@ -20051,30 +20071,20 @@ var init_web3js_adapter = __esm({
20051
20071
  throw err2;
20052
20072
  }
20053
20073
  if (!destExists) {
20054
- tx.add(createAssociatedTokenAccountInstruction(this.keypair.publicKey, destAta, recipient, this.mint));
20074
+ instructions.push(createAssociatedTokenAccountInstruction(this.keypair.publicKey, destAta, recipient, this.mint));
20055
20075
  }
20056
- tx.add(createTransferInstruction(sourceAta, destAta, this.keypair.publicKey, item.microAmount));
20076
+ instructions.push(createTransferInstruction(sourceAta, destAta, this.keypair.publicKey, item.microAmount));
20057
20077
  }
20058
- const latest = await this.connection.getLatestBlockhash(this.commitment);
20059
- tx.recentBlockhash = latest.blockhash;
20060
- tx.feePayer = this.keypair.publicKey;
20061
- tx.sign(this.keypair);
20062
- const signature = await this.connection.sendRawTransaction(tx.serialize());
20063
- const confirmation = await this.connection.confirmTransaction({
20064
- signature,
20065
- blockhash: latest.blockhash,
20066
- lastValidBlockHeight: latest.lastValidBlockHeight
20067
- }, this.commitment);
20068
- const ok = confirmation.value.err === null;
20078
+ const { signature, slot, confirmed } = await this.signSendConfirm(instructions);
20069
20079
  for (let i3 = start; i3 < end; i3++) {
20070
20080
  results[i3] = {
20071
- ok,
20081
+ ok: confirmed,
20072
20082
  signature,
20073
- slot: confirmation.context.slot,
20074
- reason: ok ? null : "tx failed"
20083
+ slot,
20084
+ reason: confirmed ? null : "tx failed"
20075
20085
  };
20076
20086
  }
20077
- if (!ok)
20087
+ if (!confirmed)
20078
20088
  aborted = true;
20079
20089
  } catch (err2) {
20080
20090
  const reason = err2 instanceof Error ? err2.message : String(err2);
@@ -20978,7 +20988,7 @@ var init_config2 = __esm({
20978
20988
  "src/config.ts"() {
20979
20989
  "use strict";
20980
20990
  init_esm_shims();
20981
- VERSION = true ? "1.8.2" : "0.0.0-dev";
20991
+ VERSION = true ? "1.8.3" : "0.0.0-dev";
20982
20992
  CONFIG_DIR = process.env["MOTEBIT_CONFIG_DIR"] ?? path2.join(os.homedir(), ".motebit");
20983
20993
  CONFIG_PATH = path2.join(CONFIG_DIR, "config.json");
20984
20994
  RELAY_DIR = path2.join(CONFIG_DIR, "relay");
@@ -27280,6 +27290,153 @@ var init_agent_network = __esm({
27280
27290
  }
27281
27291
  });
27282
27292
 
27293
+ // ../../packages/semiring/dist/thompson.js
27294
+ function mulberry322(seed) {
27295
+ let a3 = seed >>> 0;
27296
+ return () => {
27297
+ a3 = a3 + 1831565813 | 0;
27298
+ let t3 = Math.imul(a3 ^ a3 >>> 15, 1 | a3);
27299
+ t3 = t3 + Math.imul(t3 ^ t3 >>> 7, 61 | t3) ^ t3;
27300
+ return ((t3 ^ t3 >>> 14) >>> 0) / 4294967296;
27301
+ };
27302
+ }
27303
+ function hashSeed(input) {
27304
+ let h5 = 2166136261 >>> 0;
27305
+ for (let i3 = 0; i3 < input.length; i3++) {
27306
+ h5 ^= input.charCodeAt(i3);
27307
+ h5 = Math.imul(h5, 16777619);
27308
+ }
27309
+ return h5 >>> 0;
27310
+ }
27311
+ function gammaInt(k4, rng) {
27312
+ let sum2 = 0;
27313
+ for (let i3 = 0; i3 < k4; i3++) {
27314
+ const u2 = rng();
27315
+ sum2 -= Math.log(u2 > 0 ? u2 : Number.MIN_VALUE);
27316
+ }
27317
+ return sum2;
27318
+ }
27319
+ function sampleBeta(alpha, beta, rng) {
27320
+ if (!Number.isInteger(alpha) || !Number.isInteger(beta) || alpha < 1 || beta < 1) {
27321
+ throw new RangeError(`sampleBeta requires positive integer shapes; got alpha=${alpha}, beta=${beta}`);
27322
+ }
27323
+ const ga = gammaInt(alpha, rng);
27324
+ const gb = gammaInt(beta, rng);
27325
+ return ga / (ga + gb);
27326
+ }
27327
+ function thompsonDraw(alpha, beta, seed) {
27328
+ return sampleBeta(alpha, beta, mulberry322(hashSeed(seed)));
27329
+ }
27330
+ var init_thompson = __esm({
27331
+ "../../packages/semiring/dist/thompson.js"() {
27332
+ "use strict";
27333
+ init_esm_shims();
27334
+ }
27335
+ });
27336
+
27337
+ // ../../packages/semiring/dist/worker-selection.js
27338
+ function levelPrior(level) {
27339
+ switch (level) {
27340
+ case AgentTrustLevel.Trusted:
27341
+ return { a: 3, b: 1 };
27342
+ case AgentTrustLevel.Verified:
27343
+ return { a: 2, b: 1 };
27344
+ default:
27345
+ return { a: 1, b: 1 };
27346
+ }
27347
+ }
27348
+ function competenceCounts(record, capability) {
27349
+ if (!record)
27350
+ return { successful: 0, failed: 0 };
27351
+ if (capability != null) {
27352
+ const bucket = record.capability_stats?.[capability];
27353
+ return { successful: bucket?.successful_tasks ?? 0, failed: bucket?.failed_tasks ?? 0 };
27354
+ }
27355
+ return { successful: record.successful_tasks ?? 0, failed: record.failed_tasks ?? 0 };
27356
+ }
27357
+ function clampStrength(x3) {
27358
+ return Number.isFinite(x3) ? Math.min(1, Math.max(0, x3)) : 0;
27359
+ }
27360
+ function cappedCounts(successful, failed) {
27361
+ const s0 = Math.max(0, Math.floor(successful));
27362
+ const f0 = Math.max(0, Math.floor(failed));
27363
+ const total = s0 + f0;
27364
+ if (total <= COUNT_CAP)
27365
+ return { s: s0, f: f0 };
27366
+ const s3 = Math.round(s0 * COUNT_CAP / total);
27367
+ return { s: s3, f: COUNT_CAP - s3 };
27368
+ }
27369
+ function exploratoryQuality(c3, explore, capability) {
27370
+ const prior = levelPrior(c3.trustRecord?.trust_level);
27371
+ const counts = competenceCounts(c3.trustRecord, capability);
27372
+ const { s: s3, f: f6 } = cappedCounts(counts.successful, counts.failed);
27373
+ const alpha = prior.a + s3;
27374
+ const beta = prior.b + f6;
27375
+ const mean = alpha / (alpha + beta);
27376
+ const base = clampStrength(explore.strength ?? 1);
27377
+ const strength = c3.bonded ? Math.min(1, base * BOND_EXPLORE_BOOST) : base;
27378
+ if (strength <= 0)
27379
+ return mean;
27380
+ const draw = thompsonDraw(alpha, beta, `${explore.seed}|${c3.motebit_id}`);
27381
+ return mean + strength * (draw - mean);
27382
+ }
27383
+ function reliabilityOf(record, capability) {
27384
+ if (!record)
27385
+ return 0.5;
27386
+ const { successful, failed } = competenceCounts(record, capability);
27387
+ return (1 + successful) / (2 + successful + failed);
27388
+ }
27389
+ function rankWorkers(selfId, candidates, opts) {
27390
+ const weights = opts?.weights ?? DEFAULT_WEIGHTS;
27391
+ const capability = opts?.capability;
27392
+ const explore = opts?.explore != null && clampStrength(opts.explore.strength ?? 1) > 0 ? opts.explore : void 0;
27393
+ const graph = new WeightedDigraph(RouteWeightSemiring);
27394
+ graph.addNode(selfId);
27395
+ for (const c3 of candidates) {
27396
+ if (c3.trustRecord?.trust_level === AgentTrustLevel.Blocked)
27397
+ continue;
27398
+ const trust = explore ? exploratoryQuality(c3, explore, capability) : trustLevelToScore(c3.trustRecord?.trust_level ?? AgentTrustLevel.Unknown);
27399
+ const reliability = explore ? trust : reliabilityOf(c3.trustRecord, capability);
27400
+ graph.setEdge(selfId, c3.motebit_id, {
27401
+ trust,
27402
+ cost: c3.unitCost ?? 0,
27403
+ latency: DEFAULT_LATENCY_MS,
27404
+ reliability,
27405
+ regulatory_risk: 0
27406
+ });
27407
+ }
27408
+ const ranked = rankReachableAgents(graph, selfId, {
27409
+ trust: weights.trust,
27410
+ cost: weights.cost,
27411
+ latency: weights.latency,
27412
+ reliability: weights.reliability,
27413
+ regulatory_risk: 0
27414
+ });
27415
+ return ranked.map((r2) => ({ motebit_id: r2.motebit_id, score: r2.score, route: r2.route })).sort((a3, b3) => b3.score - a3.score || (a3.motebit_id < b3.motebit_id ? -1 : 1));
27416
+ }
27417
+ function selectWorker(selfId, candidates, opts) {
27418
+ return rankWorkers(selfId, candidates, opts)[0] ?? null;
27419
+ }
27420
+ var DEFAULT_LATENCY_MS, COUNT_CAP, BOND_EXPLORE_BOOST, DEFAULT_WEIGHTS;
27421
+ var init_worker_selection = __esm({
27422
+ "../../packages/semiring/dist/worker-selection.js"() {
27423
+ "use strict";
27424
+ init_esm_shims();
27425
+ init_dist();
27426
+ init_agent_network();
27427
+ init_thompson();
27428
+ DEFAULT_LATENCY_MS = 5e3;
27429
+ COUNT_CAP = 100;
27430
+ BOND_EXPLORE_BOOST = 2;
27431
+ DEFAULT_WEIGHTS = {
27432
+ trust: 0.5,
27433
+ reliability: 0.3,
27434
+ cost: 0.2,
27435
+ latency: 0
27436
+ };
27437
+ }
27438
+ });
27439
+
27283
27440
  // ../../packages/semiring/dist/disambiguation.js
27284
27441
  var init_disambiguation = __esm({
27285
27442
  "../../packages/semiring/dist/disambiguation.js"() {
@@ -27339,6 +27496,8 @@ var init_dist14 = __esm({
27339
27496
  init_trust_algebra2();
27340
27497
  init_provenance();
27341
27498
  init_agent_network();
27499
+ init_worker_selection();
27500
+ init_thompson();
27342
27501
  init_disambiguation();
27343
27502
  init_hardware_attestation();
27344
27503
  }
@@ -42523,269 +42682,822 @@ var init_grant_verifier = __esm({
42523
42682
  }
42524
42683
  });
42525
42684
 
42526
- // ../../packages/runtime/dist/secret-redacting-provider.js
42527
- function redactPackForCloudEgress(pack, redact) {
42528
- let redactedCount = 0;
42529
- const labels = /* @__PURE__ */ new Set();
42530
- const apply = (text) => {
42531
- const r2 = redact(text);
42532
- redactedCount += r2.redactionCount;
42533
- for (const l6 of r2.labels)
42534
- labels.add(l6);
42535
- return r2.text;
42536
- };
42537
- const newPack = {
42538
- ...pack,
42539
- user_message: apply(pack.user_message),
42540
- ...pack.conversation_history !== void 0 ? {
42541
- conversation_history: pack.conversation_history.map((m3) => m3.role === "user" ? { ...m3, content: apply(m3.content) } : m3)
42542
- } : {}
42543
- };
42544
- return { pack: newPack, redactedCount, labels: [...labels] };
42545
- }
42546
- var SecretRedactingProvider;
42547
- var init_secret_redacting_provider = __esm({
42548
- "../../packages/runtime/dist/secret-redacting-provider.js"() {
42549
- "use strict";
42550
- init_esm_shims();
42551
- SecretRedactingProvider = class {
42552
- inner;
42553
- opts;
42554
- constructor(inner, opts) {
42555
- this.inner = inner;
42556
- this.opts = opts;
42557
- }
42558
- /** Redact the outbound pack unless the provider is sovereign (on-device). */
42559
- packFor(pack) {
42560
- if (this.opts.isSovereign())
42561
- return pack;
42562
- const { pack: redacted, redactedCount, labels } = redactPackForCloudEgress(pack, this.opts.redact);
42563
- if (redactedCount > 0)
42564
- this.opts.onRedacted?.({ count: redactedCount, labels });
42565
- return redacted;
42566
- }
42567
- get model() {
42568
- return this.inner.model;
42569
- }
42570
- get temperature() {
42571
- return this.inner.temperature;
42572
- }
42573
- get maxTokens() {
42574
- return this.inner.maxTokens;
42575
- }
42576
- setModel(model) {
42577
- this.inner.setModel(model);
42578
- }
42579
- setTemperature(temperature) {
42580
- this.inner.setTemperature?.(temperature);
42581
- }
42582
- setMaxTokens(maxTokens) {
42583
- this.inner.setMaxTokens?.(maxTokens);
42584
- }
42585
- generate(pack) {
42586
- return this.inner.generate(this.packFor(pack));
42587
- }
42588
- generateStream(pack) {
42589
- return this.inner.generateStream(this.packFor(pack));
42590
- }
42591
- estimateConfidence() {
42592
- return this.inner.estimateConfidence();
42593
- }
42594
- extractMemoryCandidates(response) {
42595
- return this.inner.extractMemoryCandidates(response);
42596
- }
42685
+ // ../../packages/runtime/dist/relay-delegation.js
42686
+ function classifyRelayError(status, body, retryAfterHeader) {
42687
+ const retryAfterSeconds = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : void 0;
42688
+ let relayCode;
42689
+ let relayMessage;
42690
+ try {
42691
+ const parsed = JSON.parse(body);
42692
+ relayCode = parsed.code;
42693
+ relayMessage = parsed.error;
42694
+ } catch {
42695
+ }
42696
+ const message2 = relayMessage ?? body.slice(0, 512);
42697
+ if (status === 401) {
42698
+ return { code: "auth_expired", message: message2, status };
42699
+ }
42700
+ if (relayCode === "TASK_P2P_PROOF_REQUIRED") {
42701
+ return { code: "payment_proof_required", message: message2, status };
42702
+ }
42703
+ if (status === 402 || relayCode === "INSUFFICIENT_FUNDS") {
42704
+ return { code: "insufficient_balance", message: message2, status };
42705
+ }
42706
+ if (status === 403) {
42707
+ return { code: "unauthorized", message: message2, status };
42708
+ }
42709
+ if (status === 429) {
42710
+ return {
42711
+ code: "rate_limited",
42712
+ message: message2,
42713
+ status,
42714
+ ...Number.isFinite(retryAfterSeconds) ? { retryAfterSeconds } : {}
42597
42715
  };
42598
42716
  }
42599
- });
42600
-
42601
- // ../../packages/runtime/dist/credential-manager.js
42602
- var CredentialManager;
42603
- var init_credential_manager = __esm({
42604
- "../../packages/runtime/dist/credential-manager.js"() {
42605
- "use strict";
42606
- init_esm_shims();
42607
- init_dist6();
42608
- CredentialManager = class {
42609
- deps;
42610
- _issuedCredentials = [];
42611
- changeListeners = /* @__PURE__ */ new Set();
42612
- /** Callback to submit credentials to relay for indexing. Set externally (e.g. by enableInteractiveDelegation). */
42613
- credentialSubmitter = null;
42614
- constructor(deps) {
42615
- this.deps = deps;
42616
- }
42617
- /**
42618
- * Subscribe to credential-set changes (fires after each `persistCredential`).
42619
- * Returns an unsubscribe function. Used by surfaces that render credentials
42620
- * as scene objects (satellites) so they don't have to poll.
42621
- */
42622
- onChange(fn) {
42623
- this.changeListeners.add(fn);
42624
- return () => {
42625
- this.changeListeners.delete(fn);
42626
- };
42627
- }
42628
- /**
42629
- * Issue a W3C Verifiable Credential containing this agent's current gradient.
42630
- * Returns null if no gradient has been computed or no private key is available.
42631
- */
42632
- async issueGradientCredential(privateKey, publicKey) {
42633
- const snapshot = this.deps.gradientStore.latest(this.deps.motebitId);
42634
- if (!snapshot)
42635
- return null;
42636
- return issueGradientCredential(snapshot, privateKey, publicKey);
42637
- }
42638
- /**
42639
- * Return all verifiable credentials issued by this runtime (gradient + trust).
42640
- * Credentials accumulate in memory; consumers can read and clear as needed.
42641
- */
42642
- getIssuedCredentials() {
42643
- return [...this._issuedCredentials];
42644
- }
42645
- /**
42646
- * Clear the in-memory credential cache (e.g. after persisting or presenting them).
42647
- */
42648
- clearIssuedCredentials() {
42649
- this._issuedCredentials = [];
42650
- }
42651
- /** Push a credential to both in-memory cache and persistent store. */
42652
- persistCredential(vc, subjectMotebitId) {
42653
- this._issuedCredentials.push(vc);
42654
- if (this.deps.credentialStore) {
42655
- try {
42656
- const credType = vc.type.find((t3) => t3 !== "VerifiableCredential") ?? "VerifiableCredential";
42657
- this.deps.credentialStore.save({
42658
- credential_id: crypto.randomUUID(),
42659
- subject_motebit_id: vc.credentialSubject?.id ?? "",
42660
- issuer_did: vc.issuer,
42661
- credential_type: credType,
42662
- credential_json: JSON.stringify(vc),
42663
- issued_at: Date.now()
42664
- });
42665
- } catch (err2) {
42666
- this.deps.logger.warn("credential persistence failed", {
42667
- error: err2 instanceof Error ? err2.message : String(err2)
42668
- });
42669
- }
42670
- }
42671
- if (this.credentialSubmitter && subjectMotebitId) {
42672
- this.credentialSubmitter(vc, subjectMotebitId).catch((err2) => {
42673
- this.deps.logger.warn("credential relay submission failed", {
42674
- error: err2 instanceof Error ? err2.message : String(err2)
42675
- });
42676
- });
42677
- }
42678
- for (const listener of this.changeListeners) {
42679
- try {
42680
- listener();
42681
- } catch (err2) {
42682
- this.deps.logger.warn("credential change listener threw", {
42683
- error: err2 instanceof Error ? err2.message : String(err2)
42684
- });
42685
- }
42686
- }
42717
+ if (status === 400) {
42718
+ return { code: "malformed_request", message: message2, status };
42719
+ }
42720
+ return { code: "unknown", message: message2, status };
42721
+ }
42722
+ async function submitAndPollDelegation(params) {
42723
+ const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
42724
+ const startedAt = Date.now();
42725
+ let submitHeader;
42726
+ let queryHeader;
42727
+ try {
42728
+ const [submitToken, queryToken] = await Promise.all([
42729
+ params.authToken("task:submit"),
42730
+ params.authToken("task:query")
42731
+ ]);
42732
+ submitHeader = `Bearer ${submitToken}`;
42733
+ queryHeader = `Bearer ${queryToken}`;
42734
+ } catch (err2) {
42735
+ return {
42736
+ ok: false,
42737
+ error: {
42738
+ code: "auth_expired",
42739
+ message: `Auth token mint failed: ${err2 instanceof Error ? err2.message : String(err2)}`
42687
42740
  }
42688
42741
  };
42689
42742
  }
42690
- });
42691
-
42692
- // ../../packages/runtime/dist/hardware-attestation-projection.js
42693
- function readLatestHardwareAttestationClaim(store, record) {
42694
- const candidates = [];
42695
- const seen = /* @__PURE__ */ new Set();
42696
- const collect = (subjectKey) => {
42697
- let rows;
42698
- try {
42699
- rows = store.listBySubject(subjectKey);
42700
- } catch {
42701
- return;
42743
+ let taskId;
42744
+ try {
42745
+ const body = {
42746
+ prompt: params.prompt,
42747
+ submitted_by: params.motebitId
42748
+ };
42749
+ if (params.requiredCapabilities && params.requiredCapabilities.length > 0) {
42750
+ body.required_capabilities = params.requiredCapabilities;
42702
42751
  }
42703
- for (const row of rows) {
42704
- if (row.credential_type !== TRUST_VC_TYPE)
42705
- continue;
42706
- if (seen.has(row.credential_id))
42707
- continue;
42708
- seen.add(row.credential_id);
42709
- candidates.push(row);
42752
+ if (params.routingStrategy) {
42753
+ body.routing_strategy = params.routingStrategy;
42710
42754
  }
42711
- };
42712
- if (record.public_key != null && record.public_key !== "") {
42713
- try {
42714
- collect(hexPublicKeyToDidKey(record.public_key));
42715
- } catch {
42755
+ if (params.invocationOrigin) {
42756
+ body.invocation_origin = params.invocationOrigin;
42716
42757
  }
42717
- }
42718
- collect(`did:motebit:${record.remote_motebit_id}`);
42719
- if (candidates.length === 0)
42720
- return null;
42721
- candidates.sort((a3, b3) => b3.issued_at - a3.issued_at);
42722
- for (const row of candidates) {
42723
- let parsed;
42724
- try {
42725
- parsed = JSON.parse(row.credential_json);
42726
- } catch {
42727
- continue;
42758
+ if (params.grantId != null) {
42759
+ body.grant_id = params.grantId;
42728
42760
  }
42729
- const claim = parsed.credentialSubject?.hardware_attestation;
42730
- if (claim != null) {
42761
+ const resp = await fetch(`${params.syncUrl}/agent/${params.motebitId}/task`, {
42762
+ method: "POST",
42763
+ headers: {
42764
+ "Content-Type": "application/json",
42765
+ Authorization: submitHeader,
42766
+ "Idempotency-Key": crypto.randomUUID()
42767
+ },
42768
+ body: JSON.stringify(body),
42769
+ signal: params.signal
42770
+ });
42771
+ if (!resp.ok) {
42772
+ const text = await resp.text().catch(() => "");
42731
42773
  return {
42732
- platform: claim.platform,
42733
- key_exported: claim.key_exported,
42734
- score: scoreAttestation(claim)
42774
+ ok: false,
42775
+ error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
42776
+ };
42777
+ }
42778
+ const data = await resp.json();
42779
+ taskId = data.task_id;
42780
+ } catch (err2) {
42781
+ if (err2 instanceof Error && err2.name === "AbortError") {
42782
+ return {
42783
+ ok: false,
42784
+ error: { code: "timeout", message: "Aborted before submission completed" }
42735
42785
  };
42736
42786
  }
42787
+ return {
42788
+ ok: false,
42789
+ error: {
42790
+ code: "network_unreachable",
42791
+ message: err2 instanceof Error ? err2.message : String(err2)
42792
+ }
42793
+ };
42737
42794
  }
42738
- return null;
42795
+ const result = await pollForReceipt({
42796
+ syncUrl: params.syncUrl,
42797
+ motebitId: params.motebitId,
42798
+ taskId,
42799
+ queryHeader,
42800
+ timeoutMs,
42801
+ startedAt,
42802
+ logger: params.logger,
42803
+ ...params.signal ? { signal: params.signal } : {}
42804
+ });
42805
+ return result.ok ? { ...result, settlement: { mode: "relay" } } : result;
42739
42806
  }
42740
- var TRUST_VC_TYPE;
42741
- var init_hardware_attestation_projection = __esm({
42742
- "../../packages/runtime/dist/hardware-attestation-projection.js"() {
42743
- "use strict";
42744
- init_esm_shims();
42745
- init_dist6();
42746
- init_dist14();
42747
- TRUST_VC_TYPE = "AgentTrustCredential";
42748
- }
42749
- });
42750
-
42751
- // ../../packages/runtime/dist/latency-stats-projection.js
42752
- async function readLatencyStats(store, motebitId, record) {
42753
- let stats;
42754
- try {
42755
- stats = await store.getStats(motebitId, record.remote_motebit_id);
42756
- } catch {
42757
- return null;
42807
+ async function pollForReceipt(args) {
42808
+ const maxPolls = Math.ceil(args.timeoutMs / POLL_INTERVAL_MS);
42809
+ for (let i3 = 0; i3 < maxPolls; i3++) {
42810
+ if (args.signal?.aborted) {
42811
+ return { ok: false, error: { code: "timeout", message: "Aborted mid-poll" } };
42812
+ }
42813
+ await new Promise((resolve14, reject) => {
42814
+ const t3 = setTimeout(resolve14, POLL_INTERVAL_MS);
42815
+ args.signal?.addEventListener("abort", () => {
42816
+ clearTimeout(t3);
42817
+ reject(new DOMException("Aborted", "AbortError"));
42818
+ }, { once: true });
42819
+ }).catch(() => {
42820
+ });
42821
+ try {
42822
+ const resp = await fetch(`${args.syncUrl}/agent/${args.motebitId}/task/${args.taskId}`, {
42823
+ headers: { Authorization: args.queryHeader },
42824
+ signal: args.signal
42825
+ });
42826
+ if (!resp.ok) {
42827
+ args.logger.warn("delegation poll failed", {
42828
+ taskId: args.taskId,
42829
+ status: resp.status,
42830
+ body: await resp.text().catch(() => "")
42831
+ });
42832
+ continue;
42833
+ }
42834
+ const data = await resp.json();
42835
+ if (data.receipt != null) {
42836
+ return { ok: true, receipt: data.receipt, taskId: args.taskId };
42837
+ }
42838
+ if (data.task.status === "failed") {
42839
+ return {
42840
+ ok: false,
42841
+ error: { code: "agent_failed", message: "Agent reported failure without a receipt" }
42842
+ };
42843
+ }
42844
+ } catch (err2) {
42845
+ if (err2 instanceof Error && err2.name === "AbortError") {
42846
+ return { ok: false, error: { code: "timeout", message: "Aborted mid-poll" } };
42847
+ }
42848
+ }
42758
42849
  }
42759
- if (stats.sample_count === 0)
42760
- return null;
42850
+ const elapsedMs = Date.now() - args.startedAt;
42761
42851
  return {
42762
- avg_ms: stats.avg_ms,
42763
- p95_ms: stats.p95_ms,
42764
- sample_count: stats.sample_count
42852
+ ok: false,
42853
+ error: { code: "timeout", message: `No receipt within ${Math.round(elapsedMs / 1e3)}s` }
42765
42854
  };
42766
42855
  }
42767
- var init_latency_stats_projection = __esm({
42768
- "../../packages/runtime/dist/latency-stats-projection.js"() {
42769
- "use strict";
42770
- init_esm_shims();
42856
+ async function submitP2pDelegation(params) {
42857
+ const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
42858
+ const startedAt = Date.now();
42859
+ let submitHeader;
42860
+ let queryHeader;
42861
+ try {
42862
+ const [submitToken, queryToken] = await Promise.all([
42863
+ params.authToken("task:submit"),
42864
+ params.authToken("task:query")
42865
+ ]);
42866
+ submitHeader = `Bearer ${submitToken}`;
42867
+ queryHeader = `Bearer ${queryToken}`;
42868
+ } catch (err2) {
42869
+ return {
42870
+ ok: false,
42871
+ error: {
42872
+ code: "auth_expired",
42873
+ message: `Auth token mint failed: ${err2 instanceof Error ? err2.message : String(err2)}`
42874
+ }
42875
+ };
42771
42876
  }
42772
- });
42773
-
42774
- // ../../packages/runtime/dist/plan-execution.js
42775
- var PlanExecutionManager;
42776
- var init_plan_execution = __esm({
42777
- "../../packages/runtime/dist/plan-execution.js"() {
42778
- "use strict";
42779
- init_esm_shims();
42780
- init_dist2();
42781
- init_dist6();
42782
- init_execution_ledger();
42783
- PlanExecutionManager = class {
42784
- deps;
42785
- _lastExecutionManifest = null;
42786
- _stepStates = /* @__PURE__ */ new Map();
42787
- /**
42788
- * Per-step delegation `task_id`, remembered on `step_delegated` so the
42877
+ let taskId;
42878
+ try {
42879
+ const body = {
42880
+ prompt: params.prompt,
42881
+ submitted_by: params.motebitId,
42882
+ target_agent: params.targetWorkerId,
42883
+ settlement_mode: "p2p",
42884
+ // The relay's task-submission handler reads the proof under `payment_proof`
42885
+ // (services/relay/src/tasks.ts) — NOT `p2p_payment_proof` (that's only the
42886
+ // relay's internal TaskQueue field name). Sending the wrong key made the
42887
+ // relay see no proof and reject every paid cross-agent delegation with 402
42888
+ // TASK_P2P_PROOF_REQUIRED. The federation-e2e client↔relay integration test
42889
+ // locks this wire key (the seam that mocked-fetch unit tests can't catch).
42890
+ payment_proof: params.paymentProof
42891
+ };
42892
+ if (params.requiredCapabilities && params.requiredCapabilities.length > 0) {
42893
+ body.required_capabilities = params.requiredCapabilities;
42894
+ }
42895
+ if (params.acknowledgeNoHistoryRisk === true) {
42896
+ body.delegator_acknowledges_no_history_risk = true;
42897
+ }
42898
+ if (params.invocationOrigin) {
42899
+ body.invocation_origin = params.invocationOrigin;
42900
+ }
42901
+ if (params.grantId != null) {
42902
+ body.grant_id = params.grantId;
42903
+ }
42904
+ const resp = await fetch(`${params.syncUrl}/agent/${params.motebitId}/task`, {
42905
+ method: "POST",
42906
+ headers: {
42907
+ "Content-Type": "application/json",
42908
+ Authorization: submitHeader,
42909
+ // Stable across retries of the SAME logical delegation so a re-submit
42910
+ // of the already-paid proof dedupes byte-identically rather than
42911
+ // racing a second task. Keyed on the onchain tx_hash, which uniquely
42912
+ // identifies this payment.
42913
+ "Idempotency-Key": params.paymentProof.tx_hash
42914
+ },
42915
+ body: JSON.stringify(body),
42916
+ signal: params.signal
42917
+ });
42918
+ if (!resp.ok) {
42919
+ const text = await resp.text().catch(() => "");
42920
+ return {
42921
+ ok: false,
42922
+ error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
42923
+ };
42924
+ }
42925
+ const data = await resp.json();
42926
+ taskId = data.task_id;
42927
+ } catch (err2) {
42928
+ if (err2 instanceof Error && err2.name === "AbortError") {
42929
+ return {
42930
+ ok: false,
42931
+ error: { code: "timeout", message: "Aborted before submission completed" }
42932
+ };
42933
+ }
42934
+ return {
42935
+ ok: false,
42936
+ error: {
42937
+ code: "network_unreachable",
42938
+ message: err2 instanceof Error ? err2.message : String(err2)
42939
+ }
42940
+ };
42941
+ }
42942
+ const result = await pollForReceipt({
42943
+ syncUrl: params.syncUrl,
42944
+ motebitId: params.motebitId,
42945
+ taskId,
42946
+ queryHeader,
42947
+ timeoutMs,
42948
+ startedAt,
42949
+ logger: params.logger,
42950
+ ...params.signal ? { signal: params.signal } : {}
42951
+ });
42952
+ if (result.ok) {
42953
+ const proof = params.paymentProof;
42954
+ return {
42955
+ ...result,
42956
+ settlement: {
42957
+ mode: "p2p",
42958
+ txHash: proof.tx_hash,
42959
+ paidMicro: proof.amount_micro,
42960
+ feeMicro: proof.fee_amount_micro + (proof.b_fee_amount_micro ?? 0)
42961
+ }
42962
+ };
42963
+ }
42964
+ return result;
42965
+ }
42966
+ function hexToBytes7(hex) {
42967
+ const clean2 = hex.startsWith("0x") ? hex.slice(2) : hex;
42968
+ if (clean2.length === 0 || clean2.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean2)) {
42969
+ throw new Error(`invalid hex: ${hex.slice(0, 16)}\u2026`);
42970
+ }
42971
+ const out = new Uint8Array(clean2.length / 2);
42972
+ for (let i3 = 0; i3 < out.length; i3++) {
42973
+ out[i3] = Number.parseInt(clean2.slice(i3 * 2, i3 * 2 + 2), 16);
42974
+ }
42975
+ return out;
42976
+ }
42977
+ async function resolveP2pPaymentRequest(params) {
42978
+ const { syncUrl, capability, motebitId } = params;
42979
+ let treasuryAddress;
42980
+ try {
42981
+ treasuryAddress = base58Encode(hexToBytes7(params.relayPublicKeyHex));
42982
+ } catch (err2) {
42983
+ return fail("malformed_request", `Invalid pinned relay public key: ${err2 instanceof Error ? err2.message : String(err2)}`);
42984
+ }
42985
+ let worker;
42986
+ try {
42987
+ const resp = await fetch(`${syncUrl}/api/v1/agents/discover?capability=${encodeURIComponent(capability)}`, { signal: params.signal });
42988
+ if (!resp.ok) {
42989
+ const text = await resp.text().catch(() => "");
42990
+ return {
42991
+ ok: false,
42992
+ error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
42993
+ };
42994
+ }
42995
+ const data = await resp.json();
42996
+ const admissible = (data.agents ?? []).filter((a3) => {
42997
+ if (a3.motebit_id === motebitId || a3.settlement_address == null)
42998
+ return false;
42999
+ if (params.targetWorkerId != null && a3.motebit_id !== params.targetWorkerId)
43000
+ return false;
43001
+ const modes = Array.isArray(a3.settlement_modes) ? a3.settlement_modes : String(a3.settlement_modes ?? "").split(",");
43002
+ return modes.includes("p2p");
43003
+ });
43004
+ let candidate = admissible[0];
43005
+ if (params.targetWorkerId == null && params.selectWorker != null && admissible.length > 1) {
43006
+ const priceFor3 = (a3) => (a3.pricing ?? []).find((p5) => p5.capability === capability)?.unit_cost ?? (a3.pricing ?? [])[0]?.unit_cost ?? void 0;
43007
+ const chosenId = await params.selectWorker(admissible.map((a3) => {
43008
+ const unitCost = priceFor3(a3);
43009
+ return { motebit_id: a3.motebit_id, ...unitCost != null ? { unitCost } : {} };
43010
+ }));
43011
+ if (chosenId != null) {
43012
+ const chosen = admissible.find((a3) => a3.motebit_id === chosenId);
43013
+ if (chosen != null)
43014
+ candidate = chosen;
43015
+ }
43016
+ }
43017
+ if (candidate?.settlement_address == null) {
43018
+ return fail("no_routing", params.targetWorkerId != null ? `Pinned worker "${params.targetWorkerId}" is not P2P-eligible for "${capability}".` : `No P2P-capable worker advertises "${capability}".`);
43019
+ }
43020
+ worker = {
43021
+ motebit_id: candidate.motebit_id,
43022
+ settlement_address: candidate.settlement_address,
43023
+ ...candidate.source_relay_public_key != null ? { sourceRelayPublicKey: candidate.source_relay_public_key } : {},
43024
+ pricing: candidate.pricing ?? null
43025
+ };
43026
+ } catch (err2) {
43027
+ if (err2 instanceof Error && err2.name === "AbortError") {
43028
+ return fail("timeout", "Aborted during discovery");
43029
+ }
43030
+ return fail("network_unreachable", err2 instanceof Error ? err2.message : String(err2));
43031
+ }
43032
+ let paymentRequest;
43033
+ if (worker.sourceRelayPublicKey != null) {
43034
+ let executorTreasuryAddress;
43035
+ try {
43036
+ executorTreasuryAddress = base58Encode(hexToBytes7(worker.sourceRelayPublicKey));
43037
+ } catch (err2) {
43038
+ return fail("malformed_request", `Invalid peer relay public key in discovery: ${err2 instanceof Error ? err2.message : String(err2)}`);
43039
+ }
43040
+ const priced = (worker.pricing ?? []).find((p5) => p5.capability === capability) ?? (worker.pricing ?? [])[0];
43041
+ if (priced?.unit_cost == null || priced.unit_cost <= 0) {
43042
+ return fail("worker_not_payable", `Remote worker has no positive price for "${capability}".`);
43043
+ }
43044
+ const budgetMicro = toMicro(priced.unit_cost);
43045
+ const split2 = computeFederatedFeeSplit(budgetMicro, PLATFORM_FEE_RATE);
43046
+ paymentRequest = {
43047
+ workerAddress: worker.settlement_address,
43048
+ amountMicro: split2.workerNetMicro,
43049
+ treasuryAddress,
43050
+ feeAmountMicro: split2.originFeeMicro,
43051
+ executorTreasuryAddress,
43052
+ executorFeeAmountMicro: split2.executorFeeMicro
43053
+ };
43054
+ } else {
43055
+ let preflightAllowed = false;
43056
+ try {
43057
+ const eligToken = await params.authToken("market:listing");
43058
+ const ackQuery = params.acknowledgeNoHistoryRisk === true ? "?acknowledge_no_history_risk=true" : "";
43059
+ const resp = await fetch(`${syncUrl}/api/v1/agents/${worker.motebit_id}/p2p-eligibility${ackQuery}`, { headers: { Authorization: `Bearer ${eligToken}` }, signal: params.signal });
43060
+ if (resp.ok) {
43061
+ const data = await resp.json();
43062
+ if (data.allowed !== true) {
43063
+ return fail("p2p_ineligible", data.reason ?? "Not P2P-eligible for this worker");
43064
+ }
43065
+ preflightAllowed = true;
43066
+ }
43067
+ } catch (err2) {
43068
+ if (err2 instanceof Error && err2.name === "AbortError") {
43069
+ return fail("timeout", "Aborted during eligibility pre-flight");
43070
+ }
43071
+ }
43072
+ if (!preflightAllowed) {
43073
+ return fail("p2p_ineligible", "P2P eligibility could not be confirmed (pre-flight unavailable) \u2014 refusing to broadcast an unconfirmed payment.");
43074
+ }
43075
+ let unitCost;
43076
+ try {
43077
+ const listingToken = await params.authToken("market:listing");
43078
+ const resp = await fetch(`${syncUrl}/api/v1/agents/${worker.motebit_id}/listing`, {
43079
+ headers: { Authorization: `Bearer ${listingToken}` },
43080
+ signal: params.signal
43081
+ });
43082
+ if (resp.status === 404) {
43083
+ return fail("worker_not_payable", "Worker has no service listing.");
43084
+ }
43085
+ if (!resp.ok) {
43086
+ const text = await resp.text().catch(() => "");
43087
+ return {
43088
+ ok: false,
43089
+ error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
43090
+ };
43091
+ }
43092
+ const data = await resp.json();
43093
+ const entry = (data.pricing ?? []).find((p5) => p5.capability === capability) ?? (data.pricing ?? [])[0];
43094
+ if (entry?.unit_cost == null || entry.unit_cost <= 0) {
43095
+ return fail("worker_not_payable", `Worker has no positive price for "${capability}".`);
43096
+ }
43097
+ unitCost = entry.unit_cost;
43098
+ } catch (err2) {
43099
+ if (err2 instanceof Error && err2.name === "AbortError") {
43100
+ return fail("timeout", "Aborted during pricing");
43101
+ }
43102
+ return fail("network_unreachable", err2 instanceof Error ? err2.message : String(err2));
43103
+ }
43104
+ const amountMicro = toMicro(unitCost);
43105
+ paymentRequest = {
43106
+ workerAddress: worker.settlement_address,
43107
+ amountMicro,
43108
+ treasuryAddress,
43109
+ feeAmountMicro: computeP2pFeeMicro(amountMicro, PLATFORM_FEE_RATE)
43110
+ };
43111
+ }
43112
+ return {
43113
+ ok: true,
43114
+ paymentRequest,
43115
+ workerMotebitId: worker.motebit_id,
43116
+ workerAddress: worker.settlement_address
43117
+ };
43118
+ }
43119
+ async function resolveAndSubmitP2pDelegation(params) {
43120
+ if (params.buildP2pPayment == null) {
43121
+ return fail("no_sovereign_rail", "Paid direct delegation needs a sovereign wallet rail that can build an atomic payment.");
43122
+ }
43123
+ const resolved = await resolveP2pPaymentRequest({
43124
+ motebitId: params.motebitId,
43125
+ syncUrl: params.syncUrl,
43126
+ authToken: params.authToken,
43127
+ capability: params.capability,
43128
+ relayPublicKeyHex: params.relayPublicKeyHex,
43129
+ ...params.targetWorkerId != null ? { targetWorkerId: params.targetWorkerId } : {},
43130
+ ...params.selectWorker != null ? { selectWorker: params.selectWorker } : {},
43131
+ ...params.acknowledgeNoHistoryRisk === true ? { acknowledgeNoHistoryRisk: true } : {},
43132
+ ...params.signal ? { signal: params.signal } : {}
43133
+ });
43134
+ if (!resolved.ok)
43135
+ return { ok: false, error: resolved.error };
43136
+ let proof;
43137
+ try {
43138
+ proof = await params.buildP2pPayment(resolved.paymentRequest);
43139
+ } catch (err2) {
43140
+ if (err2 instanceof Error && err2.name === "MoneyMeterDeniedError") {
43141
+ const denial = err2.denial;
43142
+ return {
43143
+ ok: false,
43144
+ error: {
43145
+ code: "money_meter_denied",
43146
+ message: err2.message,
43147
+ ...denial != null ? { denial } : {}
43148
+ }
43149
+ };
43150
+ }
43151
+ if (err2 instanceof Error && err2.name === "InsufficientUsdcBalanceError") {
43152
+ return fail("insufficient_balance", err2.message);
43153
+ }
43154
+ return fail("payment_broadcast_failed", `P2P payment failed to broadcast: ${err2 instanceof Error ? err2.message : String(err2)}`);
43155
+ }
43156
+ return submitP2pDelegation({
43157
+ motebitId: params.motebitId,
43158
+ syncUrl: params.syncUrl,
43159
+ authToken: params.authToken,
43160
+ prompt: params.prompt,
43161
+ targetWorkerId: resolved.workerMotebitId,
43162
+ // The relay needs the capability to locate + price a federated worker on its
43163
+ // operator; pinned via the same capability used for discovery.
43164
+ requiredCapabilities: [params.capability],
43165
+ ...params.acknowledgeNoHistoryRisk === true ? { acknowledgeNoHistoryRisk: true } : {},
43166
+ paymentProof: proof,
43167
+ ...params.invocationOrigin ? { invocationOrigin: params.invocationOrigin } : {},
43168
+ ...params.grantId != null ? { grantId: params.grantId } : {},
43169
+ ...params.timeoutMs != null ? { timeoutMs: params.timeoutMs } : {},
43170
+ logger: params.logger,
43171
+ ...params.signal ? { signal: params.signal } : {}
43172
+ });
43173
+ }
43174
+ async function selectAndRunDelegation(params) {
43175
+ const capability = params.requiredCapabilities?.[0];
43176
+ if (params.targetWorkerId != null) {
43177
+ if (capability == null) {
43178
+ return fail("malformed_request", "A pinned hire requires a capability to discover the worker by.");
43179
+ }
43180
+ if (params.buildP2pPayment == null || params.relayPublicKey == null) {
43181
+ return fail("no_sovereign_rail", "Hiring a specific agent settles peer-to-peer and needs a configured sovereign wallet rail.");
43182
+ }
43183
+ }
43184
+ if (params.buildP2pPayment != null && params.relayPublicKey != null && capability != null) {
43185
+ const p2p = await resolveAndSubmitP2pDelegation({
43186
+ motebitId: params.motebitId,
43187
+ syncUrl: params.syncUrl,
43188
+ authToken: params.authToken,
43189
+ prompt: params.prompt,
43190
+ capability,
43191
+ ...params.targetWorkerId != null ? { targetWorkerId: params.targetWorkerId } : {},
43192
+ relayPublicKeyHex: params.relayPublicKey,
43193
+ buildP2pPayment: params.buildP2pPayment,
43194
+ ...params.acknowledgeNoHistoryRisk === true ? { acknowledgeNoHistoryRisk: true } : {},
43195
+ ...params.invocationOrigin ? { invocationOrigin: params.invocationOrigin } : {},
43196
+ ...params.grantId != null ? { grantId: params.grantId } : {},
43197
+ ...params.timeoutMs != null ? { timeoutMs: params.timeoutMs } : {},
43198
+ logger: params.logger,
43199
+ ...params.signal ? { signal: params.signal } : {}
43200
+ });
43201
+ if (p2p.ok)
43202
+ return p2p;
43203
+ if (params.targetWorkerId != null)
43204
+ return p2p;
43205
+ if (p2p.error.code !== "no_routing" && p2p.error.code !== "worker_not_payable" && p2p.error.code !== "p2p_ineligible") {
43206
+ return p2p;
43207
+ }
43208
+ }
43209
+ return submitAndPollDelegation({
43210
+ motebitId: params.motebitId,
43211
+ syncUrl: params.syncUrl,
43212
+ authToken: params.authToken,
43213
+ prompt: params.prompt,
43214
+ ...params.requiredCapabilities ? { requiredCapabilities: params.requiredCapabilities } : {},
43215
+ ...params.routingStrategy ? { routingStrategy: params.routingStrategy } : {},
43216
+ ...params.invocationOrigin ? { invocationOrigin: params.invocationOrigin } : {},
43217
+ ...params.grantId != null ? { grantId: params.grantId } : {},
43218
+ ...params.timeoutMs != null ? { timeoutMs: params.timeoutMs } : {},
43219
+ logger: params.logger,
43220
+ ...params.signal ? { signal: params.signal } : {}
43221
+ });
43222
+ }
43223
+ var DEFAULT_TIMEOUT_MS, POLL_INTERVAL_MS, fail;
43224
+ var init_relay_delegation = __esm({
43225
+ "../../packages/runtime/dist/relay-delegation.js"() {
43226
+ "use strict";
43227
+ init_esm_shims();
43228
+ init_dist();
43229
+ DEFAULT_TIMEOUT_MS = 12e4;
43230
+ POLL_INTERVAL_MS = 2e3;
43231
+ fail = (code2, message2, status) => ({
43232
+ ok: false,
43233
+ error: status != null ? { code: code2, message: message2, status } : { code: code2, message: message2 }
43234
+ });
43235
+ }
43236
+ });
43237
+
43238
+ // ../../packages/runtime/dist/secret-redacting-provider.js
43239
+ function redactPackForCloudEgress(pack, redact) {
43240
+ let redactedCount = 0;
43241
+ const labels = /* @__PURE__ */ new Set();
43242
+ const apply = (text) => {
43243
+ const r2 = redact(text);
43244
+ redactedCount += r2.redactionCount;
43245
+ for (const l6 of r2.labels)
43246
+ labels.add(l6);
43247
+ return r2.text;
43248
+ };
43249
+ const newPack = {
43250
+ ...pack,
43251
+ user_message: apply(pack.user_message),
43252
+ ...pack.conversation_history !== void 0 ? {
43253
+ conversation_history: pack.conversation_history.map((m3) => m3.role === "user" ? { ...m3, content: apply(m3.content) } : m3)
43254
+ } : {}
43255
+ };
43256
+ return { pack: newPack, redactedCount, labels: [...labels] };
43257
+ }
43258
+ var SecretRedactingProvider;
43259
+ var init_secret_redacting_provider = __esm({
43260
+ "../../packages/runtime/dist/secret-redacting-provider.js"() {
43261
+ "use strict";
43262
+ init_esm_shims();
43263
+ SecretRedactingProvider = class {
43264
+ inner;
43265
+ opts;
43266
+ constructor(inner, opts) {
43267
+ this.inner = inner;
43268
+ this.opts = opts;
43269
+ }
43270
+ /** Redact the outbound pack unless the provider is sovereign (on-device). */
43271
+ packFor(pack) {
43272
+ if (this.opts.isSovereign())
43273
+ return pack;
43274
+ const { pack: redacted, redactedCount, labels } = redactPackForCloudEgress(pack, this.opts.redact);
43275
+ if (redactedCount > 0)
43276
+ this.opts.onRedacted?.({ count: redactedCount, labels });
43277
+ return redacted;
43278
+ }
43279
+ get model() {
43280
+ return this.inner.model;
43281
+ }
43282
+ get temperature() {
43283
+ return this.inner.temperature;
43284
+ }
43285
+ get maxTokens() {
43286
+ return this.inner.maxTokens;
43287
+ }
43288
+ setModel(model) {
43289
+ this.inner.setModel(model);
43290
+ }
43291
+ setTemperature(temperature) {
43292
+ this.inner.setTemperature?.(temperature);
43293
+ }
43294
+ setMaxTokens(maxTokens) {
43295
+ this.inner.setMaxTokens?.(maxTokens);
43296
+ }
43297
+ generate(pack) {
43298
+ return this.inner.generate(this.packFor(pack));
43299
+ }
43300
+ generateStream(pack) {
43301
+ return this.inner.generateStream(this.packFor(pack));
43302
+ }
43303
+ estimateConfidence() {
43304
+ return this.inner.estimateConfidence();
43305
+ }
43306
+ extractMemoryCandidates(response) {
43307
+ return this.inner.extractMemoryCandidates(response);
43308
+ }
43309
+ };
43310
+ }
43311
+ });
43312
+
43313
+ // ../../packages/runtime/dist/credential-manager.js
43314
+ var CredentialManager;
43315
+ var init_credential_manager = __esm({
43316
+ "../../packages/runtime/dist/credential-manager.js"() {
43317
+ "use strict";
43318
+ init_esm_shims();
43319
+ init_dist6();
43320
+ CredentialManager = class {
43321
+ deps;
43322
+ _issuedCredentials = [];
43323
+ changeListeners = /* @__PURE__ */ new Set();
43324
+ /** Callback to submit credentials to relay for indexing. Set externally (e.g. by enableInteractiveDelegation). */
43325
+ credentialSubmitter = null;
43326
+ constructor(deps) {
43327
+ this.deps = deps;
43328
+ }
43329
+ /**
43330
+ * Subscribe to credential-set changes (fires after each `persistCredential`).
43331
+ * Returns an unsubscribe function. Used by surfaces that render credentials
43332
+ * as scene objects (satellites) so they don't have to poll.
43333
+ */
43334
+ onChange(fn) {
43335
+ this.changeListeners.add(fn);
43336
+ return () => {
43337
+ this.changeListeners.delete(fn);
43338
+ };
43339
+ }
43340
+ /**
43341
+ * Issue a W3C Verifiable Credential containing this agent's current gradient.
43342
+ * Returns null if no gradient has been computed or no private key is available.
43343
+ */
43344
+ async issueGradientCredential(privateKey, publicKey) {
43345
+ const snapshot = this.deps.gradientStore.latest(this.deps.motebitId);
43346
+ if (!snapshot)
43347
+ return null;
43348
+ return issueGradientCredential(snapshot, privateKey, publicKey);
43349
+ }
43350
+ /**
43351
+ * Return all verifiable credentials issued by this runtime (gradient + trust).
43352
+ * Credentials accumulate in memory; consumers can read and clear as needed.
43353
+ */
43354
+ getIssuedCredentials() {
43355
+ return [...this._issuedCredentials];
43356
+ }
43357
+ /**
43358
+ * Clear the in-memory credential cache (e.g. after persisting or presenting them).
43359
+ */
43360
+ clearIssuedCredentials() {
43361
+ this._issuedCredentials = [];
43362
+ }
43363
+ /** Push a credential to both in-memory cache and persistent store. */
43364
+ persistCredential(vc, subjectMotebitId) {
43365
+ this._issuedCredentials.push(vc);
43366
+ if (this.deps.credentialStore) {
43367
+ try {
43368
+ const credType = vc.type.find((t3) => t3 !== "VerifiableCredential") ?? "VerifiableCredential";
43369
+ this.deps.credentialStore.save({
43370
+ credential_id: crypto.randomUUID(),
43371
+ subject_motebit_id: vc.credentialSubject?.id ?? "",
43372
+ issuer_did: vc.issuer,
43373
+ credential_type: credType,
43374
+ credential_json: JSON.stringify(vc),
43375
+ issued_at: Date.now()
43376
+ });
43377
+ } catch (err2) {
43378
+ this.deps.logger.warn("credential persistence failed", {
43379
+ error: err2 instanceof Error ? err2.message : String(err2)
43380
+ });
43381
+ }
43382
+ }
43383
+ if (this.credentialSubmitter && subjectMotebitId) {
43384
+ this.credentialSubmitter(vc, subjectMotebitId).catch((err2) => {
43385
+ this.deps.logger.warn("credential relay submission failed", {
43386
+ error: err2 instanceof Error ? err2.message : String(err2)
43387
+ });
43388
+ });
43389
+ }
43390
+ for (const listener of this.changeListeners) {
43391
+ try {
43392
+ listener();
43393
+ } catch (err2) {
43394
+ this.deps.logger.warn("credential change listener threw", {
43395
+ error: err2 instanceof Error ? err2.message : String(err2)
43396
+ });
43397
+ }
43398
+ }
43399
+ }
43400
+ };
43401
+ }
43402
+ });
43403
+
43404
+ // ../../packages/runtime/dist/hardware-attestation-projection.js
43405
+ function readLatestHardwareAttestationClaim(store, record) {
43406
+ const candidates = [];
43407
+ const seen = /* @__PURE__ */ new Set();
43408
+ const collect = (subjectKey) => {
43409
+ let rows;
43410
+ try {
43411
+ rows = store.listBySubject(subjectKey);
43412
+ } catch {
43413
+ return;
43414
+ }
43415
+ for (const row of rows) {
43416
+ if (row.credential_type !== TRUST_VC_TYPE)
43417
+ continue;
43418
+ if (seen.has(row.credential_id))
43419
+ continue;
43420
+ seen.add(row.credential_id);
43421
+ candidates.push(row);
43422
+ }
43423
+ };
43424
+ if (record.public_key != null && record.public_key !== "") {
43425
+ try {
43426
+ collect(hexPublicKeyToDidKey(record.public_key));
43427
+ } catch {
43428
+ }
43429
+ }
43430
+ collect(`did:motebit:${record.remote_motebit_id}`);
43431
+ if (candidates.length === 0)
43432
+ return null;
43433
+ candidates.sort((a3, b3) => b3.issued_at - a3.issued_at);
43434
+ for (const row of candidates) {
43435
+ let parsed;
43436
+ try {
43437
+ parsed = JSON.parse(row.credential_json);
43438
+ } catch {
43439
+ continue;
43440
+ }
43441
+ const claim = parsed.credentialSubject?.hardware_attestation;
43442
+ if (claim != null) {
43443
+ return {
43444
+ platform: claim.platform,
43445
+ key_exported: claim.key_exported,
43446
+ score: scoreAttestation(claim)
43447
+ };
43448
+ }
43449
+ }
43450
+ return null;
43451
+ }
43452
+ var TRUST_VC_TYPE;
43453
+ var init_hardware_attestation_projection = __esm({
43454
+ "../../packages/runtime/dist/hardware-attestation-projection.js"() {
43455
+ "use strict";
43456
+ init_esm_shims();
43457
+ init_dist6();
43458
+ init_dist14();
43459
+ TRUST_VC_TYPE = "AgentTrustCredential";
43460
+ }
43461
+ });
43462
+
43463
+ // ../../packages/runtime/dist/latency-stats-projection.js
43464
+ async function readLatencyStats(store, motebitId, record) {
43465
+ let stats;
43466
+ try {
43467
+ stats = await store.getStats(motebitId, record.remote_motebit_id);
43468
+ } catch {
43469
+ return null;
43470
+ }
43471
+ if (stats.sample_count === 0)
43472
+ return null;
43473
+ return {
43474
+ avg_ms: stats.avg_ms,
43475
+ p95_ms: stats.p95_ms,
43476
+ sample_count: stats.sample_count
43477
+ };
43478
+ }
43479
+ var init_latency_stats_projection = __esm({
43480
+ "../../packages/runtime/dist/latency-stats-projection.js"() {
43481
+ "use strict";
43482
+ init_esm_shims();
43483
+ }
43484
+ });
43485
+
43486
+ // ../../packages/runtime/dist/plan-execution.js
43487
+ var PlanExecutionManager;
43488
+ var init_plan_execution = __esm({
43489
+ "../../packages/runtime/dist/plan-execution.js"() {
43490
+ "use strict";
43491
+ init_esm_shims();
43492
+ init_dist2();
43493
+ init_dist6();
43494
+ init_execution_ledger();
43495
+ PlanExecutionManager = class {
43496
+ deps;
43497
+ _lastExecutionManifest = null;
43498
+ _stepStates = /* @__PURE__ */ new Map();
43499
+ /**
43500
+ * Per-step delegation `task_id`, remembered on `step_delegated` so the
42789
43501
  * subsequent terminal event can include it in its payload (spec §3.7).
42790
43502
  * Receivers join the delegation chain payload-directly instead of
42791
43503
  * reconstructing it by scanning sibling events.
@@ -43342,7 +44054,28 @@ var init_operator = __esm({
43342
44054
  });
43343
44055
 
43344
44056
  // ../../packages/runtime/dist/agent-trust.js
43345
- async function bumpTrustFromReceipt(deps, receipt, verified) {
44057
+ function resolveTaskCapability(explicit, receipt) {
44058
+ if (explicit != null && explicit !== "" && explicit !== "*")
44059
+ return explicit;
44060
+ const scope = receipt.delegated_scope;
44061
+ if (scope == null || scope === "" || scope === "*")
44062
+ return void 0;
44063
+ const parts = scope.split(",").map((s3) => s3.trim()).filter(Boolean);
44064
+ return parts.length === 1 ? parts[0] : void 0;
44065
+ }
44066
+ function bumpCapabilityStats(existing, capability, effectiveSuccess, effectiveFailure) {
44067
+ if (capability == null)
44068
+ return existing;
44069
+ const prev = existing?.[capability] ?? { successful_tasks: 0, failed_tasks: 0 };
44070
+ return {
44071
+ ...existing ?? {},
44072
+ [capability]: {
44073
+ successful_tasks: prev.successful_tasks + (effectiveSuccess ? 1 : 0),
44074
+ failed_tasks: prev.failed_tasks + (effectiveFailure ? 1 : 0)
44075
+ }
44076
+ };
44077
+ }
44078
+ async function bumpTrustFromReceipt(deps, receipt, verified, capability) {
43346
44079
  const { motebitId, agentTrustStore, events, agentGraph, signingKeys, onCredentialIssued, getRemoteHardwareAttestations, hardwareAttestationVerifiers } = deps;
43347
44080
  if (agentTrustStore == null)
43348
44081
  return;
@@ -43364,10 +44097,12 @@ async function bumpTrustFromReceipt(deps, receipt, verified) {
43364
44097
  }
43365
44098
  const effectiveSuccess = taskSucceeded && resultQuality >= 0.2;
43366
44099
  const effectiveFailure = taskFailed || taskSucceeded && resultQuality < 0.2;
44100
+ const taskCapability = resolveTaskCapability(capability, receipt);
43367
44101
  if (existing != null) {
43368
44102
  const alpha = 0.3;
43369
44103
  const prevQuality = existing.avg_quality ?? 1;
43370
44104
  const newQuality = alpha * resultQuality + (1 - alpha) * prevQuality;
44105
+ const nextCapabilityStats = bumpCapabilityStats(existing.capability_stats, taskCapability, effectiveSuccess, effectiveFailure);
43371
44106
  const updated = {
43372
44107
  ...existing,
43373
44108
  last_seen_at: now,
@@ -43375,7 +44110,8 @@ async function bumpTrustFromReceipt(deps, receipt, verified) {
43375
44110
  successful_tasks: (existing.successful_tasks ?? 0) + (effectiveSuccess ? 1 : 0),
43376
44111
  failed_tasks: (existing.failed_tasks ?? 0) + (effectiveFailure ? 1 : 0),
43377
44112
  avg_quality: newQuality,
43378
- quality_sample_count: (existing.quality_sample_count ?? 0) + 1
44113
+ quality_sample_count: (existing.quality_sample_count ?? 0) + 1,
44114
+ ...nextCapabilityStats != null ? { capability_stats: nextCapabilityStats } : {}
43379
44115
  };
43380
44116
  const newLevel = evaluateTrustTransition(updated);
43381
44117
  if (newLevel != null) {
@@ -43483,6 +44219,7 @@ async function bumpTrustFromReceipt(deps, receipt, verified) {
43483
44219
  }
43484
44220
  }
43485
44221
  } else {
44222
+ const firstCapabilityStats = bumpCapabilityStats(void 0, taskCapability, effectiveSuccess, effectiveFailure);
43486
44223
  const record = {
43487
44224
  motebit_id: motebitId,
43488
44225
  remote_motebit_id: remoteMotebitId,
@@ -43493,7 +44230,8 @@ async function bumpTrustFromReceipt(deps, receipt, verified) {
43493
44230
  successful_tasks: effectiveSuccess ? 1 : 0,
43494
44231
  failed_tasks: effectiveFailure ? 1 : 0,
43495
44232
  avg_quality: resultQuality,
43496
- quality_sample_count: 1
44233
+ quality_sample_count: 1,
44234
+ ...firstCapabilityStats != null ? { capability_stats: firstCapabilityStats } : {}
43497
44235
  };
43498
44236
  await agentTrustStore.setAgentTrust(record);
43499
44237
  agentGraph.invalidate();
@@ -52745,910 +53483,402 @@ ${snippet}`;
52745
53483
  // --- Layer-3 conversation search ---
52746
53484
  /**
52747
53485
  * BM25 search over every persisted message for this motebit. Used by
52748
- * the `search_conversations` tool — the Layer-3 transcript retrieval
52749
- * that complements Layer-1 (memory index) and Layer-2
52750
- * (`recall_memories` embedding search). Returns ranked hits with
52751
- * conversation id, timestamp, and a short snippet around the first
52752
- * matching token.
52753
- *
52754
- * Uses only the sync ConversationStoreAdapter surface, so callers
52755
- * with IDB-backed stores MUST preload message caches (e.g.
52756
- * `preloadAllMessages` on web) before invoking. The default for
52757
- * CLI/desktop/mobile with SQLite is sync all the way down and needs
52758
- * no preload.
52759
- */
52760
- searchHistory(query, limit = 5) {
52761
- const { store } = this.deps;
52762
- if (store == null)
52763
- return [];
52764
- const convos = store.listConversations(this.deps.motebitId);
52765
- const messages = [];
52766
- for (const c3 of convos) {
52767
- const msgs = store.loadMessages(c3.conversationId);
52768
- for (const m3 of msgs) {
52769
- if (m3.role !== "user" && m3.role !== "assistant")
52770
- continue;
52771
- messages.push({
52772
- conversationId: c3.conversationId,
52773
- role: m3.role,
52774
- content: m3.content,
52775
- createdAt: m3.createdAt
52776
- });
52777
- }
52778
- }
52779
- return searchConversationMessages(messages, query, { limit });
52780
- }
52781
- /**
52782
- * Heuristic-title every stored conversation whose title is currently
52783
- * null or empty. Idempotent: conversations with existing titles are
52784
- * skipped. Uses only the synchronous store API, so the caller is
52785
- * responsible for preloading message caches if the adapter is
52786
- * IDB-backed (web/mobile). Returns the count of conversations
52787
- * titled.
52788
- *
52789
- * Shipped to close out the prior autoTitle regression: conversations
52790
- * created before the AI-path hang was fixed carry `title: null`
52791
- * forever. This pass gives them a legible heuristic title on next
52792
- * app start without round-tripping the AI.
52793
- */
52794
- backfillMissingTitles() {
52795
- const { store } = this.deps;
52796
- if (store == null)
52797
- return 0;
52798
- const convos = store.listConversations(this.deps.motebitId);
52799
- let fixed = 0;
52800
- for (const c3 of convos) {
52801
- if (c3.title != null && c3.title !== "")
52802
- continue;
52803
- const messages = store.loadMessages(c3.conversationId);
52804
- const history = [];
52805
- for (const m3 of messages) {
52806
- if (m3.role === "user" || m3.role === "assistant") {
52807
- history.push({ role: m3.role, content: m3.content });
52808
- }
52809
- }
52810
- const title = deriveHeuristicTitle(history);
52811
- if (title != null) {
52812
- store.updateTitle(c3.conversationId, title);
52813
- fixed += 1;
52814
- }
52815
- }
52816
- return fixed;
52817
- }
52818
- // --- Task isolation ---
52819
- /** Save conversation state for isolated task execution. */
52820
- saveContext() {
52821
- return { history: [...this.history], id: this.currentId };
52822
- }
52823
- /** Restore conversation state after isolated task execution. */
52824
- restoreContext(ctx) {
52825
- this.history = ctx.history;
52826
- this.currentId = ctx.id;
52827
- }
52828
- /** Clear conversation for isolated execution (task context). */
52829
- clearForTask() {
52830
- this.history = [];
52831
- this.currentId = null;
52832
- }
52833
- // --- Agentic loop support ---
52834
- /**
52835
- * Inject intermediate messages into the live history (e.g. tool call/result
52836
- * pairs during the agentic loop). These are part of the context window for
52837
- * continuation turns but are not individually persisted as conversation
52838
- * messages — only the final user/assistant exchange is persisted via
52839
- * pushExchange().
52840
- */
52841
- injectIntermediateMessages(...messages) {
52842
- this.history.push(...messages);
52843
- }
52844
- /** Return the raw live history reference for continuation turns. */
52845
- get liveHistory() {
52846
- return this.history;
52847
- }
52848
- // --- Internal helpers ---
52849
- /** Get stored summary for the current conversation. */
52850
- getStoredSummary() {
52851
- const { store } = this.deps;
52852
- if (this.currentId == null || this.currentId === "" || store == null)
52853
- return null;
52854
- return store.getActiveConversation(this.deps.motebitId)?.summary ?? null;
52855
- }
52856
- async runSummarization() {
52857
- const provider = this.deps.getProvider();
52858
- const { store } = this.deps;
52859
- if (provider == null || store == null || this.currentId == null || this.currentId === "")
52860
- return;
52861
- try {
52862
- const existingSummary = this.getStoredSummary();
52863
- const clearedProvider = projectProviderClearance(this.deps.assertSensitivityPermitsAiCall("summarizeConversation"));
52864
- const summary = await summarizeConversation(this.history, existingSummary, clearedProvider, this.deps.getTaskRouter() ?? void 0);
52865
- if (summary && this.currentId) {
52866
- store.updateSummary(this.currentId, summary);
52867
- }
52868
- } catch {
52869
- }
52870
- }
52871
- };
52872
- }
52873
- });
52874
-
52875
- // ../../packages/runtime/dist/gradient-manager.js
52876
- var GradientManager;
52877
- var init_gradient_manager = __esm({
52878
- "../../packages/runtime/dist/gradient-manager.js"() {
52879
- "use strict";
52880
- init_esm_shims();
52881
- init_dist2();
52882
- init_gradient();
52883
- GradientManager = class {
52884
- deps;
52885
- _behavioralStats = {
52886
- turnCount: 0,
52887
- totalIterations: 0,
52888
- toolCallsSucceeded: 0,
52889
- toolCallsBlocked: 0,
52890
- toolCallsFailed: 0
52891
- };
52892
- _precision;
52893
- _curiosityTargets = [];
52894
- _lastReflection = null;
52895
- constructor(deps) {
52896
- this.deps = deps;
52897
- this._precision = NEUTRAL_PRECISION;
52898
- }
52899
- // --- Bootstrap ---
52900
- /** Apply accumulated intelligence baseline on startup. */
52901
- applyStartupBaseline() {
52902
- const latest = this.deps.gradientStore.latest(this.deps.motebitId);
52903
- if (latest) {
52904
- this._precision = computePrecision(latest);
52905
- this.deps.state.pushUpdate(computeStateBaseline(latest, this._precision));
52906
- }
52907
- }
52908
- // --- Accessors ---
52909
- /** Get the latest gradient snapshot, or null if none computed yet. */
52910
- getGradient() {
52911
- return this.deps.gradientStore.latest(this.deps.motebitId);
52912
- }
52913
- /** Get current active inference precision weights. */
52914
- getPrecision() {
52915
- return this._precision;
52916
- }
52917
- /** Get gradient history (most recent first). */
52918
- getGradientHistory(limit) {
52919
- return this.deps.gradientStore.list(this.deps.motebitId, limit);
52920
- }
52921
- /** Get gradient-informed market config for delegation routing. */
52922
- getMarketConfig() {
52923
- const snapshot = this.deps.gradientStore.latest(this.deps.motebitId);
52924
- if (!snapshot)
52925
- return void 0;
52926
- return gradientToMarketConfig(snapshot);
52927
- }
52928
- /** Self-model: the agent narrates its own trajectory from gradient history. */
52929
- getGradientSummary(limit = 20) {
52930
- const history = this.deps.gradientStore.list(this.deps.motebitId, limit);
52931
- return summarizeGradientHistory(history);
52932
- }
52933
- /** Return accumulated behavioral stats and reset the accumulator. */
52934
- getAndResetBehavioralStats() {
52935
- const stats = { ...this._behavioralStats };
52936
- this._behavioralStats = {
52937
- turnCount: 0,
52938
- totalIterations: 0,
52939
- toolCallsSucceeded: 0,
52940
- toolCallsBlocked: 0,
52941
- toolCallsFailed: 0
52942
- };
52943
- return stats;
52944
- }
52945
- /** Return the cached reflection from the last session (or null if none). */
52946
- getLastReflection() {
52947
- return this._lastReflection;
52948
- }
52949
- /** Set the last reflection result (called by reflection lifecycle). */
52950
- setLastReflection(result) {
52951
- this._lastReflection = result;
52952
- }
52953
- /** Get curiosity targets computed during last housekeeping cycle. */
52954
- getCuriosityTargets() {
52955
- return this._curiosityTargets;
52956
- }
52957
- /** Set curiosity targets (called from housekeeping). */
52958
- setCuriosityTargets(targets) {
52959
- this._curiosityTargets = targets;
52960
- }
52961
- /** Reference to the behavioral stats for direct mutation by callers. */
52962
- get behavioralStats() {
52963
- return this._behavioralStats;
52964
- }
52965
- // --- Computation ---
52966
- /** Force a gradient computation right now (useful for CLI/debug). */
52967
- async computeGradientNow() {
52968
- const { nodes } = await this.deps.memory.exportAll();
52969
- return this.computeAndStoreGradient(nodes);
52970
- }
52971
- async computeAndStoreGradient(allNodes) {
52972
- const exported = await this.deps.memory.exportAll();
52973
- const edges = exported.edges;
52974
- const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
52975
- const consolidationEvents = await this.deps.events.query({
52976
- motebit_id: this.deps.motebitId,
52977
- event_types: [EventType.MemoryConsolidated],
52978
- after_timestamp: sevenDaysAgo
52979
- });
52980
- const previous = this.deps.gradientStore.latest(this.deps.motebitId);
52981
- const previousGradient = previous ? previous.gradient : null;
52982
- const retrievalStats = this.deps.memory.getAndResetRetrievalStats();
52983
- let behavioralStats;
52984
- if (this.deps.toolAuditSink) {
52985
- const sinceTs = previous ? previous.timestamp : 0;
52986
- const auditStats = this.deps.toolAuditSink.queryStatsSince(sinceTs);
52987
- behavioralStats = {
52988
- turnCount: auditStats.distinctTurns,
52989
- // Approximate: each tool call ≈ 1 loop iteration
52990
- totalIterations: auditStats.totalToolCalls,
52991
- toolCallsSucceeded: auditStats.succeeded,
52992
- toolCallsBlocked: auditStats.blocked,
52993
- toolCallsFailed: auditStats.failed
52994
- };
52995
- } else {
52996
- behavioralStats = this.getAndResetBehavioralStats();
52997
- }
52998
- let curiosityPressure;
52999
- if (this._curiosityTargets.length > 0) {
53000
- const totalScore = this._curiosityTargets.reduce((sum2, t3) => sum2 + t3.curiosityScore, 0);
53001
- curiosityPressure = {
53002
- avgScore: totalScore / this._curiosityTargets.length,
53003
- count: this._curiosityTargets.length
53004
- };
53005
- }
53006
- const snapshot = computeGradient(this.deps.motebitId, allNodes, edges, consolidationEvents, previousGradient, void 0, retrievalStats, behavioralStats, curiosityPressure);
53007
- this.deps.gradientStore.save(snapshot);
53008
- const signingKeys = this.deps.getSigningKeys();
53009
- if (signingKeys) {
53010
- try {
53011
- const vc = await this.deps.issueGradientCredential(signingKeys.privateKey, signingKeys.publicKey);
53012
- if (vc != null)
53013
- this.deps.persistCredential(vc);
53014
- } catch (err2) {
53015
- this.deps.logger.warn("gradient credential issuance failed", {
53016
- error: err2 instanceof Error ? err2.message : String(err2)
53017
- });
53018
- }
53019
- }
53020
- this._precision = computePrecision(snapshot);
53021
- this.deps.state.pushUpdate(computeStateBaseline(snapshot, this._precision));
53022
- this.deps.memory.setPrecisionWeights(this._precision.retrievalPrecision);
53023
- return snapshot;
53024
- }
53025
- /**
53026
- * Lightweight precision refresh from behavioral stats alone.
53027
- * Patches the latest gradient snapshot's ie/te metrics with current
53028
- * session stats, recomputes precision, and feeds back into subsystems.
53029
- * No memory graph I/O — runs synchronously after each turn.
53030
- */
53031
- recomputePrecisionFromStats() {
53032
- const latest = this.deps.gradientStore.latest(this.deps.motebitId);
53033
- if (!latest)
53034
- return;
53035
- const stats = this._behavioralStats;
53036
- if (stats.turnCount === 0)
53037
- return;
53038
- const avgIterations = stats.totalIterations / stats.turnCount;
53039
- const ie2 = Math.max(0, Math.min(1, 1 - (avgIterations - 1) / 9));
53040
- const totalToolCalls = stats.toolCallsSucceeded + stats.toolCallsBlocked + stats.toolCallsFailed;
53041
- const te2 = totalToolCalls > 0 ? stats.toolCallsSucceeded / totalToolCalls : 0.5;
53042
- const patched = {
53043
- ...latest,
53044
- interaction_efficiency: ie2,
53045
- tool_efficiency: te2,
53046
- gradient: latest.gradient - 0.12 * latest.interaction_efficiency - 0.1 * latest.tool_efficiency + 0.12 * ie2 + 0.1 * te2
53047
- };
53048
- patched.delta = patched.gradient - latest.gradient;
53049
- this._precision = computePrecision(patched);
53050
- this.deps.state.pushUpdate(computeStateBaseline(patched, this._precision));
53051
- this.deps.memory.setPrecisionWeights(this._precision.retrievalPrecision);
53052
- }
53053
- // --- Self-Awareness Context ---
53054
- /** Convert curiosity targets to lightweight hints for the context pack. */
53055
- buildCuriosityHints() {
53056
- if (this._curiosityTargets.length === 0)
53057
- return void 0;
53058
- const DAY = 864e5;
53059
- const now = Date.now();
53060
- return this._curiosityTargets.slice(0, 2).map((t3) => ({
53061
- content: t3.node.content,
53062
- daysSinceDiscussed: Math.round((now - t3.node.last_accessed) / DAY)
53063
- }));
53064
- }
53065
- /**
53066
- * Build self-awareness context: precision posture + self-model narration.
53067
- *
53068
- * The precision context tells the creature how to behave (cautious/confident).
53069
- * The self-model tells the creature what it knows about itself — trajectory,
53070
- * strengths, weaknesses, memory stats.
53071
- */
53072
- buildSelfAwareness() {
53073
- const parts = [];
53074
- const posture = buildPrecisionContext(this._precision);
53075
- if (posture)
53076
- parts.push(posture);
53077
- const summary = this.getGradientSummary(10);
53078
- if (summary.snapshotCount > 0) {
53079
- const lines = [];
53080
- lines.push("[Self-Model \u2014 INTERNAL REFERENCE, never discuss mechanics with the user]");
53081
- lines.push(summary.trajectory);
53082
- lines.push(summary.overall);
53083
- if (summary.strengths.length > 0) {
53084
- lines.push(`Strengths: ${summary.strengths.join("; ")}.`);
53085
- }
53086
- if (summary.weaknesses.length > 0) {
53087
- lines.push(`Weaknesses: ${summary.weaknesses.join("; ")}.`);
53088
- }
53089
- const latest = this.deps.gradientStore.latest(this.deps.motebitId);
53090
- if (latest?.stats) {
53091
- const s3 = latest.stats;
53092
- lines.push(`Memory: ${s3.live_nodes} memories (${s3.semantic_count} semantic, ${s3.episodic_count} episodic, ${s3.pinned_count} pinned), ${s3.live_edges} connections.`);
53093
- }
53094
- parts.push(lines.join("\n"));
53095
- }
53096
- if (this._lastReflection) {
53097
- const rLines = [];
53098
- rLines.push("[Last Reflection \u2014 INTERNAL REFERENCE, never discuss mechanics with the user]");
53099
- if (this._lastReflection.planAdjustments.length > 0) {
53100
- rLines.push(`Behavioral adjustments: ${this._lastReflection.planAdjustments.join("; ")}.`);
53101
- }
53102
- if (this._lastReflection.insights.length > 0) {
53103
- rLines.push(`Insights: ${this._lastReflection.insights.join("; ")}.`);
53104
- }
53105
- if (this._lastReflection.patterns.length > 0) {
53106
- rLines.push(`Recurring patterns: ${this._lastReflection.patterns.join("; ")}.`);
53107
- }
53108
- if (this._lastReflection.selfAssessment) {
53109
- rLines.push(`Self-assessment: ${this._lastReflection.selfAssessment}`);
53486
+ * the `search_conversations` tool — the Layer-3 transcript retrieval
53487
+ * that complements Layer-1 (memory index) and Layer-2
53488
+ * (`recall_memories` embedding search). Returns ranked hits with
53489
+ * conversation id, timestamp, and a short snippet around the first
53490
+ * matching token.
53491
+ *
53492
+ * Uses only the sync ConversationStoreAdapter surface, so callers
53493
+ * with IDB-backed stores MUST preload message caches (e.g.
53494
+ * `preloadAllMessages` on web) before invoking. The default for
53495
+ * CLI/desktop/mobile with SQLite is sync all the way down and needs
53496
+ * no preload.
53497
+ */
53498
+ searchHistory(query, limit = 5) {
53499
+ const { store } = this.deps;
53500
+ if (store == null)
53501
+ return [];
53502
+ const convos = store.listConversations(this.deps.motebitId);
53503
+ const messages = [];
53504
+ for (const c3 of convos) {
53505
+ const msgs = store.loadMessages(c3.conversationId);
53506
+ for (const m3 of msgs) {
53507
+ if (m3.role !== "user" && m3.role !== "assistant")
53508
+ continue;
53509
+ messages.push({
53510
+ conversationId: c3.conversationId,
53511
+ role: m3.role,
53512
+ content: m3.content,
53513
+ createdAt: m3.createdAt
53514
+ });
53110
53515
  }
53111
- parts.push(rLines.join("\n"));
53112
53516
  }
53113
- return parts.join("\n\n");
53517
+ return searchConversationMessages(messages, query, { limit });
53114
53518
  }
53115
- // --- Reflection state ---
53116
- /** Restore the last reflection from the event log. */
53117
- async restoreLastReflection() {
53118
- try {
53119
- const events = await this.deps.events.query({
53120
- motebit_id: this.deps.motebitId,
53121
- event_types: [EventType.ReflectionCompleted],
53122
- limit: 1
53123
- });
53124
- if (events.length === 0)
53125
- return;
53126
- const payload = events[0].payload;
53127
- const insights = payload.insights;
53128
- const adjustments = payload.plan_adjustments;
53129
- const patterns = payload.patterns;
53130
- const assessment = payload.self_assessment;
53131
- if (insights || adjustments || patterns || assessment) {
53132
- this._lastReflection = {
53133
- insights: insights ?? [],
53134
- planAdjustments: adjustments ?? [],
53135
- patterns: patterns ?? [],
53136
- selfAssessment: assessment ?? ""
53137
- };
53519
+ /**
53520
+ * Heuristic-title every stored conversation whose title is currently
53521
+ * null or empty. Idempotent: conversations with existing titles are
53522
+ * skipped. Uses only the synchronous store API, so the caller is
53523
+ * responsible for preloading message caches if the adapter is
53524
+ * IDB-backed (web/mobile). Returns the count of conversations
53525
+ * titled.
53526
+ *
53527
+ * Shipped to close out the prior autoTitle regression: conversations
53528
+ * created before the AI-path hang was fixed carry `title: null`
53529
+ * forever. This pass gives them a legible heuristic title on next
53530
+ * app start without round-tripping the AI.
53531
+ */
53532
+ backfillMissingTitles() {
53533
+ const { store } = this.deps;
53534
+ if (store == null)
53535
+ return 0;
53536
+ const convos = store.listConversations(this.deps.motebitId);
53537
+ let fixed = 0;
53538
+ for (const c3 of convos) {
53539
+ if (c3.title != null && c3.title !== "")
53540
+ continue;
53541
+ const messages = store.loadMessages(c3.conversationId);
53542
+ const history = [];
53543
+ for (const m3 of messages) {
53544
+ if (m3.role === "user" || m3.role === "assistant") {
53545
+ history.push({ role: m3.role, content: m3.content });
53546
+ }
53547
+ }
53548
+ const title = deriveHeuristicTitle(history);
53549
+ if (title != null) {
53550
+ store.updateTitle(c3.conversationId, title);
53551
+ fixed += 1;
53138
53552
  }
53139
- } catch {
53140
53553
  }
53554
+ return fixed;
53141
53555
  }
53142
- };
53143
- }
53144
- });
53145
-
53146
- // ../../packages/runtime/dist/relay-delegation.js
53147
- function classifyRelayError(status, body, retryAfterHeader) {
53148
- const retryAfterSeconds = retryAfterHeader ? Number.parseInt(retryAfterHeader, 10) : void 0;
53149
- let relayCode;
53150
- let relayMessage;
53151
- try {
53152
- const parsed = JSON.parse(body);
53153
- relayCode = parsed.code;
53154
- relayMessage = parsed.error;
53155
- } catch {
53156
- }
53157
- const message2 = relayMessage ?? body.slice(0, 512);
53158
- if (status === 401) {
53159
- return { code: "auth_expired", message: message2, status };
53160
- }
53161
- if (relayCode === "TASK_P2P_PROOF_REQUIRED") {
53162
- return { code: "payment_proof_required", message: message2, status };
53163
- }
53164
- if (status === 402 || relayCode === "INSUFFICIENT_FUNDS") {
53165
- return { code: "insufficient_balance", message: message2, status };
53166
- }
53167
- if (status === 403) {
53168
- return { code: "unauthorized", message: message2, status };
53169
- }
53170
- if (status === 429) {
53171
- return {
53172
- code: "rate_limited",
53173
- message: message2,
53174
- status,
53175
- ...Number.isFinite(retryAfterSeconds) ? { retryAfterSeconds } : {}
53176
- };
53177
- }
53178
- if (status === 400) {
53179
- return { code: "malformed_request", message: message2, status };
53180
- }
53181
- return { code: "unknown", message: message2, status };
53182
- }
53183
- async function submitAndPollDelegation(params) {
53184
- const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
53185
- const startedAt = Date.now();
53186
- let submitHeader;
53187
- let queryHeader;
53188
- try {
53189
- const [submitToken, queryToken] = await Promise.all([
53190
- params.authToken("task:submit"),
53191
- params.authToken("task:query")
53192
- ]);
53193
- submitHeader = `Bearer ${submitToken}`;
53194
- queryHeader = `Bearer ${queryToken}`;
53195
- } catch (err2) {
53196
- return {
53197
- ok: false,
53198
- error: {
53199
- code: "auth_expired",
53200
- message: `Auth token mint failed: ${err2 instanceof Error ? err2.message : String(err2)}`
53201
- }
53202
- };
53203
- }
53204
- let taskId;
53205
- try {
53206
- const body = {
53207
- prompt: params.prompt,
53208
- submitted_by: params.motebitId
53209
- };
53210
- if (params.requiredCapabilities && params.requiredCapabilities.length > 0) {
53211
- body.required_capabilities = params.requiredCapabilities;
53212
- }
53213
- if (params.routingStrategy) {
53214
- body.routing_strategy = params.routingStrategy;
53215
- }
53216
- if (params.invocationOrigin) {
53217
- body.invocation_origin = params.invocationOrigin;
53218
- }
53219
- if (params.grantId != null) {
53220
- body.grant_id = params.grantId;
53221
- }
53222
- const resp = await fetch(`${params.syncUrl}/agent/${params.motebitId}/task`, {
53223
- method: "POST",
53224
- headers: {
53225
- "Content-Type": "application/json",
53226
- Authorization: submitHeader,
53227
- "Idempotency-Key": crypto.randomUUID()
53228
- },
53229
- body: JSON.stringify(body),
53230
- signal: params.signal
53231
- });
53232
- if (!resp.ok) {
53233
- const text = await resp.text().catch(() => "");
53234
- return {
53235
- ok: false,
53236
- error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
53237
- };
53238
- }
53239
- const data = await resp.json();
53240
- taskId = data.task_id;
53241
- } catch (err2) {
53242
- if (err2 instanceof Error && err2.name === "AbortError") {
53243
- return {
53244
- ok: false,
53245
- error: { code: "timeout", message: "Aborted before submission completed" }
53246
- };
53247
- }
53248
- return {
53249
- ok: false,
53250
- error: {
53251
- code: "network_unreachable",
53252
- message: err2 instanceof Error ? err2.message : String(err2)
53253
- }
53254
- };
53255
- }
53256
- const result = await pollForReceipt({
53257
- syncUrl: params.syncUrl,
53258
- motebitId: params.motebitId,
53259
- taskId,
53260
- queryHeader,
53261
- timeoutMs,
53262
- startedAt,
53263
- logger: params.logger,
53264
- ...params.signal ? { signal: params.signal } : {}
53265
- });
53266
- return result.ok ? { ...result, settlement: { mode: "relay" } } : result;
53267
- }
53268
- async function pollForReceipt(args) {
53269
- const maxPolls = Math.ceil(args.timeoutMs / POLL_INTERVAL_MS);
53270
- for (let i3 = 0; i3 < maxPolls; i3++) {
53271
- if (args.signal?.aborted) {
53272
- return { ok: false, error: { code: "timeout", message: "Aborted mid-poll" } };
53273
- }
53274
- await new Promise((resolve14, reject) => {
53275
- const t3 = setTimeout(resolve14, POLL_INTERVAL_MS);
53276
- args.signal?.addEventListener("abort", () => {
53277
- clearTimeout(t3);
53278
- reject(new DOMException("Aborted", "AbortError"));
53279
- }, { once: true });
53280
- }).catch(() => {
53281
- });
53282
- try {
53283
- const resp = await fetch(`${args.syncUrl}/agent/${args.motebitId}/task/${args.taskId}`, {
53284
- headers: { Authorization: args.queryHeader },
53285
- signal: args.signal
53286
- });
53287
- if (!resp.ok) {
53288
- args.logger.warn("delegation poll failed", {
53289
- taskId: args.taskId,
53290
- status: resp.status,
53291
- body: await resp.text().catch(() => "")
53292
- });
53293
- continue;
53556
+ // --- Task isolation ---
53557
+ /** Save conversation state for isolated task execution. */
53558
+ saveContext() {
53559
+ return { history: [...this.history], id: this.currentId };
53294
53560
  }
53295
- const data = await resp.json();
53296
- if (data.receipt != null) {
53297
- return { ok: true, receipt: data.receipt, taskId: args.taskId };
53561
+ /** Restore conversation state after isolated task execution. */
53562
+ restoreContext(ctx) {
53563
+ this.history = ctx.history;
53564
+ this.currentId = ctx.id;
53298
53565
  }
53299
- if (data.task.status === "failed") {
53300
- return {
53301
- ok: false,
53302
- error: { code: "agent_failed", message: "Agent reported failure without a receipt" }
53303
- };
53566
+ /** Clear conversation for isolated execution (task context). */
53567
+ clearForTask() {
53568
+ this.history = [];
53569
+ this.currentId = null;
53304
53570
  }
53305
- } catch (err2) {
53306
- if (err2 instanceof Error && err2.name === "AbortError") {
53307
- return { ok: false, error: { code: "timeout", message: "Aborted mid-poll" } };
53571
+ // --- Agentic loop support ---
53572
+ /**
53573
+ * Inject intermediate messages into the live history (e.g. tool call/result
53574
+ * pairs during the agentic loop). These are part of the context window for
53575
+ * continuation turns but are not individually persisted as conversation
53576
+ * messages — only the final user/assistant exchange is persisted via
53577
+ * pushExchange().
53578
+ */
53579
+ injectIntermediateMessages(...messages) {
53580
+ this.history.push(...messages);
53308
53581
  }
53309
- }
53310
- }
53311
- const elapsedMs = Date.now() - args.startedAt;
53312
- return {
53313
- ok: false,
53314
- error: { code: "timeout", message: `No receipt within ${Math.round(elapsedMs / 1e3)}s` }
53315
- };
53316
- }
53317
- async function submitP2pDelegation(params) {
53318
- const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
53319
- const startedAt = Date.now();
53320
- let submitHeader;
53321
- let queryHeader;
53322
- try {
53323
- const [submitToken, queryToken] = await Promise.all([
53324
- params.authToken("task:submit"),
53325
- params.authToken("task:query")
53326
- ]);
53327
- submitHeader = `Bearer ${submitToken}`;
53328
- queryHeader = `Bearer ${queryToken}`;
53329
- } catch (err2) {
53330
- return {
53331
- ok: false,
53332
- error: {
53333
- code: "auth_expired",
53334
- message: `Auth token mint failed: ${err2 instanceof Error ? err2.message : String(err2)}`
53582
+ /** Return the raw live history reference for continuation turns. */
53583
+ get liveHistory() {
53584
+ return this.history;
53335
53585
  }
53336
- };
53337
- }
53338
- let taskId;
53339
- try {
53340
- const body = {
53341
- prompt: params.prompt,
53342
- submitted_by: params.motebitId,
53343
- target_agent: params.targetWorkerId,
53344
- settlement_mode: "p2p",
53345
- // The relay's task-submission handler reads the proof under `payment_proof`
53346
- // (services/relay/src/tasks.ts) — NOT `p2p_payment_proof` (that's only the
53347
- // relay's internal TaskQueue field name). Sending the wrong key made the
53348
- // relay see no proof and reject every paid cross-agent delegation with 402
53349
- // TASK_P2P_PROOF_REQUIRED. The federation-e2e client↔relay integration test
53350
- // locks this wire key (the seam that mocked-fetch unit tests can't catch).
53351
- payment_proof: params.paymentProof
53352
- };
53353
- if (params.requiredCapabilities && params.requiredCapabilities.length > 0) {
53354
- body.required_capabilities = params.requiredCapabilities;
53355
- }
53356
- if (params.acknowledgeNoHistoryRisk === true) {
53357
- body.delegator_acknowledges_no_history_risk = true;
53358
- }
53359
- if (params.invocationOrigin) {
53360
- body.invocation_origin = params.invocationOrigin;
53361
- }
53362
- if (params.grantId != null) {
53363
- body.grant_id = params.grantId;
53364
- }
53365
- const resp = await fetch(`${params.syncUrl}/agent/${params.motebitId}/task`, {
53366
- method: "POST",
53367
- headers: {
53368
- "Content-Type": "application/json",
53369
- Authorization: submitHeader,
53370
- // Stable across retries of the SAME logical delegation so a re-submit
53371
- // of the already-paid proof dedupes byte-identically rather than
53372
- // racing a second task. Keyed on the onchain tx_hash, which uniquely
53373
- // identifies this payment.
53374
- "Idempotency-Key": params.paymentProof.tx_hash
53375
- },
53376
- body: JSON.stringify(body),
53377
- signal: params.signal
53378
- });
53379
- if (!resp.ok) {
53380
- const text = await resp.text().catch(() => "");
53381
- return {
53382
- ok: false,
53383
- error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
53384
- };
53385
- }
53386
- const data = await resp.json();
53387
- taskId = data.task_id;
53388
- } catch (err2) {
53389
- if (err2 instanceof Error && err2.name === "AbortError") {
53390
- return {
53391
- ok: false,
53392
- error: { code: "timeout", message: "Aborted before submission completed" }
53393
- };
53394
- }
53395
- return {
53396
- ok: false,
53397
- error: {
53398
- code: "network_unreachable",
53399
- message: err2 instanceof Error ? err2.message : String(err2)
53586
+ // --- Internal helpers ---
53587
+ /** Get stored summary for the current conversation. */
53588
+ getStoredSummary() {
53589
+ const { store } = this.deps;
53590
+ if (this.currentId == null || this.currentId === "" || store == null)
53591
+ return null;
53592
+ return store.getActiveConversation(this.deps.motebitId)?.summary ?? null;
53400
53593
  }
53401
- };
53402
- }
53403
- const result = await pollForReceipt({
53404
- syncUrl: params.syncUrl,
53405
- motebitId: params.motebitId,
53406
- taskId,
53407
- queryHeader,
53408
- timeoutMs,
53409
- startedAt,
53410
- logger: params.logger,
53411
- ...params.signal ? { signal: params.signal } : {}
53412
- });
53413
- if (result.ok) {
53414
- const proof = params.paymentProof;
53415
- return {
53416
- ...result,
53417
- settlement: {
53418
- mode: "p2p",
53419
- txHash: proof.tx_hash,
53420
- paidMicro: proof.amount_micro,
53421
- feeMicro: proof.fee_amount_micro + (proof.b_fee_amount_micro ?? 0)
53594
+ async runSummarization() {
53595
+ const provider = this.deps.getProvider();
53596
+ const { store } = this.deps;
53597
+ if (provider == null || store == null || this.currentId == null || this.currentId === "")
53598
+ return;
53599
+ try {
53600
+ const existingSummary = this.getStoredSummary();
53601
+ const clearedProvider = projectProviderClearance(this.deps.assertSensitivityPermitsAiCall("summarizeConversation"));
53602
+ const summary = await summarizeConversation(this.history, existingSummary, clearedProvider, this.deps.getTaskRouter() ?? void 0);
53603
+ if (summary && this.currentId) {
53604
+ store.updateSummary(this.currentId, summary);
53605
+ }
53606
+ } catch {
53607
+ }
53422
53608
  }
53423
53609
  };
53424
53610
  }
53425
- return result;
53426
- }
53427
- function hexToBytes7(hex) {
53428
- const clean2 = hex.startsWith("0x") ? hex.slice(2) : hex;
53429
- if (clean2.length === 0 || clean2.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean2)) {
53430
- throw new Error(`invalid hex: ${hex.slice(0, 16)}\u2026`);
53431
- }
53432
- const out = new Uint8Array(clean2.length / 2);
53433
- for (let i3 = 0; i3 < out.length; i3++) {
53434
- out[i3] = Number.parseInt(clean2.slice(i3 * 2, i3 * 2 + 2), 16);
53435
- }
53436
- return out;
53437
- }
53438
- async function resolveAndSubmitP2pDelegation(params) {
53439
- const { syncUrl, capability, motebitId } = params;
53440
- if (params.buildP2pPayment == null) {
53441
- return fail("no_sovereign_rail", "Paid direct delegation needs a sovereign wallet rail that can build an atomic payment.");
53442
- }
53443
- let treasuryAddress;
53444
- try {
53445
- treasuryAddress = base58Encode(hexToBytes7(params.relayPublicKeyHex));
53446
- } catch (err2) {
53447
- return fail("malformed_request", `Invalid pinned relay public key: ${err2 instanceof Error ? err2.message : String(err2)}`);
53448
- }
53449
- let worker;
53450
- try {
53451
- const resp = await fetch(`${syncUrl}/api/v1/agents/discover?capability=${encodeURIComponent(capability)}`, { signal: params.signal });
53452
- if (!resp.ok) {
53453
- const text = await resp.text().catch(() => "");
53454
- return {
53455
- ok: false,
53456
- error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
53457
- };
53458
- }
53459
- const data = await resp.json();
53460
- const candidate = (data.agents ?? []).find((a3) => {
53461
- if (a3.motebit_id === motebitId || a3.settlement_address == null)
53462
- return false;
53463
- if (params.targetWorkerId != null && a3.motebit_id !== params.targetWorkerId)
53464
- return false;
53465
- const modes = Array.isArray(a3.settlement_modes) ? a3.settlement_modes : String(a3.settlement_modes ?? "").split(",");
53466
- return modes.includes("p2p");
53467
- });
53468
- if (candidate?.settlement_address == null) {
53469
- return fail("no_routing", params.targetWorkerId != null ? `Pinned worker "${params.targetWorkerId}" is not P2P-eligible for "${capability}".` : `No P2P-capable worker advertises "${capability}".`);
53470
- }
53471
- worker = {
53472
- motebit_id: candidate.motebit_id,
53473
- settlement_address: candidate.settlement_address,
53474
- ...candidate.source_relay_public_key != null ? { sourceRelayPublicKey: candidate.source_relay_public_key } : {},
53475
- pricing: candidate.pricing ?? null
53476
- };
53477
- } catch (err2) {
53478
- if (err2 instanceof Error && err2.name === "AbortError") {
53479
- return fail("timeout", "Aborted during discovery");
53480
- }
53481
- return fail("network_unreachable", err2 instanceof Error ? err2.message : String(err2));
53482
- }
53483
- let paymentRequest;
53484
- if (worker.sourceRelayPublicKey != null) {
53485
- let executorTreasuryAddress;
53486
- try {
53487
- executorTreasuryAddress = base58Encode(hexToBytes7(worker.sourceRelayPublicKey));
53488
- } catch (err2) {
53489
- return fail("malformed_request", `Invalid peer relay public key in discovery: ${err2 instanceof Error ? err2.message : String(err2)}`);
53490
- }
53491
- const priced = (worker.pricing ?? []).find((p5) => p5.capability === capability) ?? (worker.pricing ?? [])[0];
53492
- if (priced?.unit_cost == null || priced.unit_cost <= 0) {
53493
- return fail("worker_not_payable", `Remote worker has no positive price for "${capability}".`);
53494
- }
53495
- const budgetMicro = toMicro(priced.unit_cost);
53496
- const split2 = computeFederatedFeeSplit(budgetMicro, PLATFORM_FEE_RATE);
53497
- paymentRequest = {
53498
- workerAddress: worker.settlement_address,
53499
- amountMicro: split2.workerNetMicro,
53500
- treasuryAddress,
53501
- feeAmountMicro: split2.originFeeMicro,
53502
- executorTreasuryAddress,
53503
- executorFeeAmountMicro: split2.executorFeeMicro
53504
- };
53505
- } else {
53506
- let preflightAllowed = false;
53507
- try {
53508
- const eligToken = await params.authToken("market:listing");
53509
- const ackQuery = params.acknowledgeNoHistoryRisk === true ? "?acknowledge_no_history_risk=true" : "";
53510
- const resp = await fetch(`${syncUrl}/api/v1/agents/${worker.motebit_id}/p2p-eligibility${ackQuery}`, { headers: { Authorization: `Bearer ${eligToken}` }, signal: params.signal });
53511
- if (resp.ok) {
53512
- const data = await resp.json();
53513
- if (data.allowed !== true) {
53514
- return fail("p2p_ineligible", data.reason ?? "Not P2P-eligible for this worker");
53611
+ });
53612
+
53613
+ // ../../packages/runtime/dist/gradient-manager.js
53614
+ var GradientManager;
53615
+ var init_gradient_manager = __esm({
53616
+ "../../packages/runtime/dist/gradient-manager.js"() {
53617
+ "use strict";
53618
+ init_esm_shims();
53619
+ init_dist2();
53620
+ init_gradient();
53621
+ GradientManager = class {
53622
+ deps;
53623
+ _behavioralStats = {
53624
+ turnCount: 0,
53625
+ totalIterations: 0,
53626
+ toolCallsSucceeded: 0,
53627
+ toolCallsBlocked: 0,
53628
+ toolCallsFailed: 0
53629
+ };
53630
+ _precision;
53631
+ _curiosityTargets = [];
53632
+ _lastReflection = null;
53633
+ constructor(deps) {
53634
+ this.deps = deps;
53635
+ this._precision = NEUTRAL_PRECISION;
53636
+ }
53637
+ // --- Bootstrap ---
53638
+ /** Apply accumulated intelligence baseline on startup. */
53639
+ applyStartupBaseline() {
53640
+ const latest = this.deps.gradientStore.latest(this.deps.motebitId);
53641
+ if (latest) {
53642
+ this._precision = computePrecision(latest);
53643
+ this.deps.state.pushUpdate(computeStateBaseline(latest, this._precision));
53515
53644
  }
53516
- preflightAllowed = true;
53517
53645
  }
53518
- } catch (err2) {
53519
- if (err2 instanceof Error && err2.name === "AbortError") {
53520
- return fail("timeout", "Aborted during eligibility pre-flight");
53646
+ // --- Accessors ---
53647
+ /** Get the latest gradient snapshot, or null if none computed yet. */
53648
+ getGradient() {
53649
+ return this.deps.gradientStore.latest(this.deps.motebitId);
53521
53650
  }
53522
- }
53523
- if (!preflightAllowed) {
53524
- return fail("p2p_ineligible", "P2P eligibility could not be confirmed (pre-flight unavailable) \u2014 refusing to broadcast an unconfirmed payment.");
53525
- }
53526
- let unitCost;
53527
- try {
53528
- const listingToken = await params.authToken("market:listing");
53529
- const resp = await fetch(`${syncUrl}/api/v1/agents/${worker.motebit_id}/listing`, {
53530
- headers: { Authorization: `Bearer ${listingToken}` },
53531
- signal: params.signal
53532
- });
53533
- if (resp.status === 404) {
53534
- return fail("worker_not_payable", "Worker has no service listing.");
53651
+ /** Get current active inference precision weights. */
53652
+ getPrecision() {
53653
+ return this._precision;
53535
53654
  }
53536
- if (!resp.ok) {
53537
- const text = await resp.text().catch(() => "");
53538
- return {
53539
- ok: false,
53540
- error: classifyRelayError(resp.status, text, resp.headers.get("Retry-After"))
53655
+ /** Get gradient history (most recent first). */
53656
+ getGradientHistory(limit) {
53657
+ return this.deps.gradientStore.list(this.deps.motebitId, limit);
53658
+ }
53659
+ /** Get gradient-informed market config for delegation routing. */
53660
+ getMarketConfig() {
53661
+ const snapshot = this.deps.gradientStore.latest(this.deps.motebitId);
53662
+ if (!snapshot)
53663
+ return void 0;
53664
+ return gradientToMarketConfig(snapshot);
53665
+ }
53666
+ /** Self-model: the agent narrates its own trajectory from gradient history. */
53667
+ getGradientSummary(limit = 20) {
53668
+ const history = this.deps.gradientStore.list(this.deps.motebitId, limit);
53669
+ return summarizeGradientHistory(history);
53670
+ }
53671
+ /** Return accumulated behavioral stats and reset the accumulator. */
53672
+ getAndResetBehavioralStats() {
53673
+ const stats = { ...this._behavioralStats };
53674
+ this._behavioralStats = {
53675
+ turnCount: 0,
53676
+ totalIterations: 0,
53677
+ toolCallsSucceeded: 0,
53678
+ toolCallsBlocked: 0,
53679
+ toolCallsFailed: 0
53541
53680
  };
53681
+ return stats;
53542
53682
  }
53543
- const data = await resp.json();
53544
- const entry = (data.pricing ?? []).find((p5) => p5.capability === capability) ?? (data.pricing ?? [])[0];
53545
- if (entry?.unit_cost == null || entry.unit_cost <= 0) {
53546
- return fail("worker_not_payable", `Worker has no positive price for "${capability}".`);
53683
+ /** Return the cached reflection from the last session (or null if none). */
53684
+ getLastReflection() {
53685
+ return this._lastReflection;
53547
53686
  }
53548
- unitCost = entry.unit_cost;
53549
- } catch (err2) {
53550
- if (err2 instanceof Error && err2.name === "AbortError") {
53551
- return fail("timeout", "Aborted during pricing");
53687
+ /** Set the last reflection result (called by reflection lifecycle). */
53688
+ setLastReflection(result) {
53689
+ this._lastReflection = result;
53690
+ }
53691
+ /** Get curiosity targets computed during last housekeeping cycle. */
53692
+ getCuriosityTargets() {
53693
+ return this._curiosityTargets;
53694
+ }
53695
+ /** Set curiosity targets (called from housekeeping). */
53696
+ setCuriosityTargets(targets) {
53697
+ this._curiosityTargets = targets;
53698
+ }
53699
+ /** Reference to the behavioral stats for direct mutation by callers. */
53700
+ get behavioralStats() {
53701
+ return this._behavioralStats;
53702
+ }
53703
+ // --- Computation ---
53704
+ /** Force a gradient computation right now (useful for CLI/debug). */
53705
+ async computeGradientNow() {
53706
+ const { nodes } = await this.deps.memory.exportAll();
53707
+ return this.computeAndStoreGradient(nodes);
53708
+ }
53709
+ async computeAndStoreGradient(allNodes) {
53710
+ const exported = await this.deps.memory.exportAll();
53711
+ const edges = exported.edges;
53712
+ const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
53713
+ const consolidationEvents = await this.deps.events.query({
53714
+ motebit_id: this.deps.motebitId,
53715
+ event_types: [EventType.MemoryConsolidated],
53716
+ after_timestamp: sevenDaysAgo
53717
+ });
53718
+ const previous = this.deps.gradientStore.latest(this.deps.motebitId);
53719
+ const previousGradient = previous ? previous.gradient : null;
53720
+ const retrievalStats = this.deps.memory.getAndResetRetrievalStats();
53721
+ let behavioralStats;
53722
+ if (this.deps.toolAuditSink) {
53723
+ const sinceTs = previous ? previous.timestamp : 0;
53724
+ const auditStats = this.deps.toolAuditSink.queryStatsSince(sinceTs);
53725
+ behavioralStats = {
53726
+ turnCount: auditStats.distinctTurns,
53727
+ // Approximate: each tool call ≈ 1 loop iteration
53728
+ totalIterations: auditStats.totalToolCalls,
53729
+ toolCallsSucceeded: auditStats.succeeded,
53730
+ toolCallsBlocked: auditStats.blocked,
53731
+ toolCallsFailed: auditStats.failed
53732
+ };
53733
+ } else {
53734
+ behavioralStats = this.getAndResetBehavioralStats();
53735
+ }
53736
+ let curiosityPressure;
53737
+ if (this._curiosityTargets.length > 0) {
53738
+ const totalScore = this._curiosityTargets.reduce((sum2, t3) => sum2 + t3.curiosityScore, 0);
53739
+ curiosityPressure = {
53740
+ avgScore: totalScore / this._curiosityTargets.length,
53741
+ count: this._curiosityTargets.length
53742
+ };
53743
+ }
53744
+ const snapshot = computeGradient(this.deps.motebitId, allNodes, edges, consolidationEvents, previousGradient, void 0, retrievalStats, behavioralStats, curiosityPressure);
53745
+ this.deps.gradientStore.save(snapshot);
53746
+ const signingKeys = this.deps.getSigningKeys();
53747
+ if (signingKeys) {
53748
+ try {
53749
+ const vc = await this.deps.issueGradientCredential(signingKeys.privateKey, signingKeys.publicKey);
53750
+ if (vc != null)
53751
+ this.deps.persistCredential(vc);
53752
+ } catch (err2) {
53753
+ this.deps.logger.warn("gradient credential issuance failed", {
53754
+ error: err2 instanceof Error ? err2.message : String(err2)
53755
+ });
53756
+ }
53757
+ }
53758
+ this._precision = computePrecision(snapshot);
53759
+ this.deps.state.pushUpdate(computeStateBaseline(snapshot, this._precision));
53760
+ this.deps.memory.setPrecisionWeights(this._precision.retrievalPrecision);
53761
+ return snapshot;
53762
+ }
53763
+ /**
53764
+ * Lightweight precision refresh from behavioral stats alone.
53765
+ * Patches the latest gradient snapshot's ie/te metrics with current
53766
+ * session stats, recomputes precision, and feeds back into subsystems.
53767
+ * No memory graph I/O — runs synchronously after each turn.
53768
+ */
53769
+ recomputePrecisionFromStats() {
53770
+ const latest = this.deps.gradientStore.latest(this.deps.motebitId);
53771
+ if (!latest)
53772
+ return;
53773
+ const stats = this._behavioralStats;
53774
+ if (stats.turnCount === 0)
53775
+ return;
53776
+ const avgIterations = stats.totalIterations / stats.turnCount;
53777
+ const ie2 = Math.max(0, Math.min(1, 1 - (avgIterations - 1) / 9));
53778
+ const totalToolCalls = stats.toolCallsSucceeded + stats.toolCallsBlocked + stats.toolCallsFailed;
53779
+ const te2 = totalToolCalls > 0 ? stats.toolCallsSucceeded / totalToolCalls : 0.5;
53780
+ const patched = {
53781
+ ...latest,
53782
+ interaction_efficiency: ie2,
53783
+ tool_efficiency: te2,
53784
+ gradient: latest.gradient - 0.12 * latest.interaction_efficiency - 0.1 * latest.tool_efficiency + 0.12 * ie2 + 0.1 * te2
53785
+ };
53786
+ patched.delta = patched.gradient - latest.gradient;
53787
+ this._precision = computePrecision(patched);
53788
+ this.deps.state.pushUpdate(computeStateBaseline(patched, this._precision));
53789
+ this.deps.memory.setPrecisionWeights(this._precision.retrievalPrecision);
53790
+ }
53791
+ // --- Self-Awareness Context ---
53792
+ /** Convert curiosity targets to lightweight hints for the context pack. */
53793
+ buildCuriosityHints() {
53794
+ if (this._curiosityTargets.length === 0)
53795
+ return void 0;
53796
+ const DAY = 864e5;
53797
+ const now = Date.now();
53798
+ return this._curiosityTargets.slice(0, 2).map((t3) => ({
53799
+ content: t3.node.content,
53800
+ daysSinceDiscussed: Math.round((now - t3.node.last_accessed) / DAY)
53801
+ }));
53802
+ }
53803
+ /**
53804
+ * Build self-awareness context: precision posture + self-model narration.
53805
+ *
53806
+ * The precision context tells the creature how to behave (cautious/confident).
53807
+ * The self-model tells the creature what it knows about itself — trajectory,
53808
+ * strengths, weaknesses, memory stats.
53809
+ */
53810
+ buildSelfAwareness() {
53811
+ const parts = [];
53812
+ const posture = buildPrecisionContext(this._precision);
53813
+ if (posture)
53814
+ parts.push(posture);
53815
+ const summary = this.getGradientSummary(10);
53816
+ if (summary.snapshotCount > 0) {
53817
+ const lines = [];
53818
+ lines.push("[Self-Model \u2014 INTERNAL REFERENCE, never discuss mechanics with the user]");
53819
+ lines.push(summary.trajectory);
53820
+ lines.push(summary.overall);
53821
+ if (summary.strengths.length > 0) {
53822
+ lines.push(`Strengths: ${summary.strengths.join("; ")}.`);
53823
+ }
53824
+ if (summary.weaknesses.length > 0) {
53825
+ lines.push(`Weaknesses: ${summary.weaknesses.join("; ")}.`);
53826
+ }
53827
+ const latest = this.deps.gradientStore.latest(this.deps.motebitId);
53828
+ if (latest?.stats) {
53829
+ const s3 = latest.stats;
53830
+ lines.push(`Memory: ${s3.live_nodes} memories (${s3.semantic_count} semantic, ${s3.episodic_count} episodic, ${s3.pinned_count} pinned), ${s3.live_edges} connections.`);
53831
+ }
53832
+ parts.push(lines.join("\n"));
53833
+ }
53834
+ if (this._lastReflection) {
53835
+ const rLines = [];
53836
+ rLines.push("[Last Reflection \u2014 INTERNAL REFERENCE, never discuss mechanics with the user]");
53837
+ if (this._lastReflection.planAdjustments.length > 0) {
53838
+ rLines.push(`Behavioral adjustments: ${this._lastReflection.planAdjustments.join("; ")}.`);
53839
+ }
53840
+ if (this._lastReflection.insights.length > 0) {
53841
+ rLines.push(`Insights: ${this._lastReflection.insights.join("; ")}.`);
53842
+ }
53843
+ if (this._lastReflection.patterns.length > 0) {
53844
+ rLines.push(`Recurring patterns: ${this._lastReflection.patterns.join("; ")}.`);
53845
+ }
53846
+ if (this._lastReflection.selfAssessment) {
53847
+ rLines.push(`Self-assessment: ${this._lastReflection.selfAssessment}`);
53848
+ }
53849
+ parts.push(rLines.join("\n"));
53850
+ }
53851
+ return parts.join("\n\n");
53852
+ }
53853
+ // --- Reflection state ---
53854
+ /** Restore the last reflection from the event log. */
53855
+ async restoreLastReflection() {
53856
+ try {
53857
+ const events = await this.deps.events.query({
53858
+ motebit_id: this.deps.motebitId,
53859
+ event_types: [EventType.ReflectionCompleted],
53860
+ limit: 1
53861
+ });
53862
+ if (events.length === 0)
53863
+ return;
53864
+ const payload = events[0].payload;
53865
+ const insights = payload.insights;
53866
+ const adjustments = payload.plan_adjustments;
53867
+ const patterns = payload.patterns;
53868
+ const assessment = payload.self_assessment;
53869
+ if (insights || adjustments || patterns || assessment) {
53870
+ this._lastReflection = {
53871
+ insights: insights ?? [],
53872
+ planAdjustments: adjustments ?? [],
53873
+ patterns: patterns ?? [],
53874
+ selfAssessment: assessment ?? ""
53875
+ };
53876
+ }
53877
+ } catch {
53878
+ }
53552
53879
  }
53553
- return fail("network_unreachable", err2 instanceof Error ? err2.message : String(err2));
53554
- }
53555
- const amountMicro = toMicro(unitCost);
53556
- paymentRequest = {
53557
- workerAddress: worker.settlement_address,
53558
- amountMicro,
53559
- treasuryAddress,
53560
- feeAmountMicro: computeP2pFeeMicro(amountMicro, PLATFORM_FEE_RATE)
53561
53880
  };
53562
53881
  }
53563
- let proof;
53564
- try {
53565
- proof = await params.buildP2pPayment(paymentRequest);
53566
- } catch (err2) {
53567
- if (err2 instanceof Error && err2.name === "InsufficientUsdcBalanceError") {
53568
- return fail("insufficient_balance", err2.message);
53569
- }
53570
- return fail("payment_broadcast_failed", `P2P payment failed to broadcast: ${err2 instanceof Error ? err2.message : String(err2)}`);
53571
- }
53572
- return submitP2pDelegation({
53573
- motebitId,
53574
- syncUrl,
53575
- authToken: params.authToken,
53576
- prompt: params.prompt,
53577
- targetWorkerId: worker.motebit_id,
53578
- // The relay needs the capability to locate + price a federated worker on its
53579
- // operator; pinned via the same capability used for discovery.
53580
- requiredCapabilities: [capability],
53581
- ...params.acknowledgeNoHistoryRisk === true ? { acknowledgeNoHistoryRisk: true } : {},
53582
- paymentProof: proof,
53583
- ...params.invocationOrigin ? { invocationOrigin: params.invocationOrigin } : {},
53584
- ...params.grantId != null ? { grantId: params.grantId } : {},
53585
- ...params.timeoutMs != null ? { timeoutMs: params.timeoutMs } : {},
53586
- logger: params.logger,
53587
- ...params.signal ? { signal: params.signal } : {}
53588
- });
53589
- }
53590
- async function selectAndRunDelegation(params) {
53591
- const capability = params.requiredCapabilities?.[0];
53592
- if (params.targetWorkerId != null) {
53593
- if (capability == null) {
53594
- return fail("malformed_request", "A pinned hire requires a capability to discover the worker by.");
53595
- }
53596
- if (params.buildP2pPayment == null || params.relayPublicKey == null) {
53597
- return fail("no_sovereign_rail", "Hiring a specific agent settles peer-to-peer and needs a configured sovereign wallet rail.");
53598
- }
53599
- }
53600
- if (params.buildP2pPayment != null && params.relayPublicKey != null && capability != null) {
53601
- const p2p = await resolveAndSubmitP2pDelegation({
53602
- motebitId: params.motebitId,
53603
- syncUrl: params.syncUrl,
53604
- authToken: params.authToken,
53605
- prompt: params.prompt,
53606
- capability,
53607
- ...params.targetWorkerId != null ? { targetWorkerId: params.targetWorkerId } : {},
53608
- relayPublicKeyHex: params.relayPublicKey,
53609
- buildP2pPayment: params.buildP2pPayment,
53610
- ...params.acknowledgeNoHistoryRisk === true ? { acknowledgeNoHistoryRisk: true } : {},
53611
- ...params.invocationOrigin ? { invocationOrigin: params.invocationOrigin } : {},
53612
- ...params.grantId != null ? { grantId: params.grantId } : {},
53613
- ...params.timeoutMs != null ? { timeoutMs: params.timeoutMs } : {},
53614
- logger: params.logger,
53615
- ...params.signal ? { signal: params.signal } : {}
53616
- });
53617
- if (p2p.ok)
53618
- return p2p;
53619
- if (params.targetWorkerId != null)
53620
- return p2p;
53621
- if (p2p.error.code !== "no_routing" && p2p.error.code !== "worker_not_payable" && p2p.error.code !== "p2p_ineligible") {
53622
- return p2p;
53623
- }
53624
- }
53625
- return submitAndPollDelegation({
53626
- motebitId: params.motebitId,
53627
- syncUrl: params.syncUrl,
53628
- authToken: params.authToken,
53629
- prompt: params.prompt,
53630
- ...params.requiredCapabilities ? { requiredCapabilities: params.requiredCapabilities } : {},
53631
- ...params.routingStrategy ? { routingStrategy: params.routingStrategy } : {},
53632
- ...params.invocationOrigin ? { invocationOrigin: params.invocationOrigin } : {},
53633
- ...params.grantId != null ? { grantId: params.grantId } : {},
53634
- ...params.timeoutMs != null ? { timeoutMs: params.timeoutMs } : {},
53635
- logger: params.logger,
53636
- ...params.signal ? { signal: params.signal } : {}
53637
- });
53638
- }
53639
- var DEFAULT_TIMEOUT_MS, POLL_INTERVAL_MS, fail;
53640
- var init_relay_delegation = __esm({
53641
- "../../packages/runtime/dist/relay-delegation.js"() {
53642
- "use strict";
53643
- init_esm_shims();
53644
- init_dist();
53645
- DEFAULT_TIMEOUT_MS = 12e4;
53646
- POLL_INTERVAL_MS = 2e3;
53647
- fail = (code2, message2, status) => ({
53648
- ok: false,
53649
- error: status != null ? { code: code2, message: message2, status } : { code: code2, message: message2 }
53650
- });
53651
- }
53652
53882
  });
53653
53883
 
53654
53884
  // ../../packages/runtime/dist/interactive-delegation.js
@@ -53756,6 +53986,11 @@ var init_interactive_delegation = __esm({
53756
53986
  // medical/financial/secret AND the configured provider is not
53757
53987
  // sovereign.
53758
53988
  outbound: true,
53989
+ // api-tier per the hybrid-engine structural preference. Inline
53990
+ // registration escapes check-tool-modes' literal scan (it only
53991
+ // sweeps exported Definition consts) — tagged here so the registry
53992
+ // sort still prefers it over pixel-tier fallbacks.
53993
+ mode: "api",
53759
53994
  // Risk classification is explicit, never inferred: with a
53760
53995
  // payment rail configured, a paid delegation settles real money
53761
53996
  // onchain (R4_MONEY, irreversible) — the name/description
@@ -53804,13 +54039,78 @@ var init_interactive_delegation = __esm({
53804
54039
  stashReceipt(result.receipt);
53805
54040
  const workerResult = result.receipt.result ?? "Task completed (no result text)";
53806
54041
  const settlementNote = formatSettlementNote(result.settlement);
54042
+ const workerNote = `[delegated_to: ${result.receipt.motebit_id}]`;
54043
+ const footnotes = [workerNote, ...settlementNote ? [settlementNote] : []].join("\n");
53807
54044
  return {
53808
54045
  ok: true,
53809
- data: settlementNote ? `${workerResult}
54046
+ data: `${workerResult}
53810
54047
 
53811
- ${settlementNote}` : workerResult
54048
+ ${footnotes}`
53812
54049
  };
53813
54050
  });
54051
+ const DISCOVER_TOOL = "discover_agents";
54052
+ if (!this.deps.toolRegistry.has(DISCOVER_TOOL)) {
54053
+ this.deps.toolRegistry.register({
54054
+ name: DISCOVER_TOOL,
54055
+ description: "List the agents discoverable on the connected relay RIGHT NOW \u2014 the live directory read. Use whenever the user asks who is available, what agents exist, what delegation costs, or before choosing a delegation target. Names are self-asserted claims, never verified handles. This is the ONLY source for the current roster; never answer roster questions from memory or self-description.",
54056
+ inputSchema: {
54057
+ type: "object",
54058
+ properties: {
54059
+ capability: {
54060
+ type: "string",
54061
+ description: "Optional capability filter (e.g. 'research'). Omit for the full roster."
54062
+ }
54063
+ },
54064
+ required: []
54065
+ },
54066
+ // Same outbound boundary as web_search — a network read that
54067
+ // reveals the question being asked, nothing more. Read-class.
54068
+ outbound: true,
54069
+ mode: "api",
54070
+ riskHint: { risk: RiskLevel.R0_READ, sideEffect: SideEffect.NONE }
54071
+ }, async (args) => {
54072
+ const capability = typeof args.capability === "string" ? args.capability : void 0;
54073
+ try {
54074
+ const token = await config.authToken();
54075
+ const url = new URL(`${config.syncUrl}/api/v1/agents/discover`);
54076
+ if (capability != null && capability.length > 0) {
54077
+ url.searchParams.set("capability", capability);
54078
+ }
54079
+ const resp = await fetch(url.toString(), {
54080
+ headers: { Authorization: `Bearer ${token}` }
54081
+ });
54082
+ if (!resp.ok) {
54083
+ return { ok: false, error: `discover read failed: HTTP ${resp.status}` };
54084
+ }
54085
+ const body = await resp.json();
54086
+ const agents = (body.agents ?? []).map((a3) => ({
54087
+ motebit_id: a3.motebit_id,
54088
+ // A self-asserted CLAIM (agents-as-first-person-trust-graph §3)
54089
+ // — surfaced under that name so the model inherits the framing.
54090
+ ...a3.display_name != null && a3.display_name.length > 0 ? { claimed_name: a3.display_name } : {},
54091
+ ...a3.description != null && a3.description.length > 0 ? { description: a3.description } : {},
54092
+ capabilities: a3.capabilities,
54093
+ ...a3.pricing != null && a3.pricing.length > 0 ? { pricing: a3.pricing } : {},
54094
+ ...a3.freshness != null ? { freshness: a3.freshness } : {},
54095
+ ...a3.trust_level != null ? { trust_level: a3.trust_level } : {},
54096
+ ...a3.settlement_modes != null ? { settlement_modes: a3.settlement_modes } : {}
54097
+ }));
54098
+ return {
54099
+ ok: true,
54100
+ data: JSON.stringify({
54101
+ roster_source: "live_relay_read",
54102
+ relay: config.syncUrl,
54103
+ as_of_ms: Date.now(),
54104
+ agent_count: agents.length,
54105
+ agents
54106
+ })
54107
+ };
54108
+ } catch (err2) {
54109
+ const msg = err2 instanceof Error ? err2.message : String(err2);
54110
+ return { ok: false, error: `discover read failed: ${msg}` };
54111
+ }
54112
+ });
54113
+ }
53814
54114
  this.deps.wireLoopDeps();
53815
54115
  }
53816
54116
  /**
@@ -55946,7 +56246,14 @@ var init_agent_task_handler = __esm({
55946
56246
  function slabTurnIdForRun(runId) {
55947
56247
  return `slab-turn-${runId}`;
55948
56248
  }
55949
- var SovereignTierRequiredError, DropTargetGovernanceRequiredError, CONSOLIDATION_TREE_HASH_VERSION, TENDING_ALLOWED_TOOLS, DEFAULT_PROACTIVE_CATCH_UP_MAX_AGE_MS, MotebitRuntime;
56249
+ function explorationStrengthForStakes(costUsd) {
56250
+ if (!(costUsd > EXPLORE_STAKES_FLOOR_USD))
56251
+ return 1;
56252
+ if (costUsd >= EXPLORE_STAKES_CEIL_USD)
56253
+ return 0;
56254
+ return 1 - (costUsd - EXPLORE_STAKES_FLOOR_USD) / (EXPLORE_STAKES_CEIL_USD - EXPLORE_STAKES_FLOOR_USD);
56255
+ }
56256
+ var SovereignTierRequiredError, DropTargetGovernanceRequiredError, CONSOLIDATION_TREE_HASH_VERSION, TENDING_ALLOWED_TOOLS, DEFAULT_PROACTIVE_CATCH_UP_MAX_AGE_MS, EXPLORE_STAKES_FLOOR_USD, EXPLORE_STAKES_CEIL_USD, MotebitRuntime;
55950
56257
  var init_motebit_runtime = __esm({
55951
56258
  "../../packages/runtime/dist/motebit-runtime.js"() {
55952
56259
  "use strict";
@@ -55971,6 +56278,7 @@ var init_motebit_runtime = __esm({
55971
56278
  init_dist11();
55972
56279
  init_money_meter();
55973
56280
  init_grant_verifier();
56281
+ init_relay_delegation();
55974
56282
  init_dist();
55975
56283
  init_dist6();
55976
56284
  init_gradient();
@@ -56048,6 +56356,8 @@ var init_motebit_runtime = __esm({
56048
56356
  "search_conversations"
56049
56357
  ]);
56050
56358
  DEFAULT_PROACTIVE_CATCH_UP_MAX_AGE_MS = 60 * 60 * 1e3;
56359
+ EXPLORE_STAKES_FLOOR_USD = 0.1;
56360
+ EXPLORE_STAKES_CEIL_USD = 1;
56051
56361
  MotebitRuntime = class _MotebitRuntime {
56052
56362
  motebitId;
56053
56363
  state;
@@ -56219,6 +56529,15 @@ var init_motebit_runtime = __esm({
56219
56529
  * `getSolanaAddress`, `getSolanaBalance`, and `sendUsdc`.
56220
56530
  */
56221
56531
  _solanaWallet = null;
56532
+ /**
56533
+ * Relay coordinates for the deterministic granted-spend path
56534
+ * (`executeGrantedDelegation`), stashed when `enableInteractiveDelegation`
56535
+ * is called with a pinned relay key. Null until then — a granted spend with
56536
+ * no coordinates fails closed (`sync_not_enabled`). The pinned hex key is the
56537
+ * treasury trust root; the auth-token minter is the same audience-scoped
56538
+ * minter the AI-loop delegation path uses.
56539
+ */
56540
+ _grantedSpendCoords = null;
56222
56541
  /**
56223
56542
  * Sovereign receipt exchange transport. Null when no transport is
56224
56543
  * configured — in that state, the runtime can still send USDC via
@@ -59019,8 +59338,8 @@ var init_motebit_runtime = __esm({
59019
59338
  hardwareAttestationVerifiers: this._hardwareAttestationVerifiers
59020
59339
  };
59021
59340
  }
59022
- async bumpTrustFromReceipt(receipt, verified) {
59023
- return bumpTrustFromReceipt(this.trustDeps, receipt, verified);
59341
+ async bumpTrustFromReceipt(receipt, verified, capability) {
59342
+ return bumpTrustFromReceipt(this.trustDeps, receipt, verified, capability);
59024
59343
  }
59025
59344
  async recordAgentInteraction(remoteMotebitId, publicKey, motebitType) {
59026
59345
  return recordAgentInteraction(this.trustDeps, remoteMotebitId, publicKey, motebitType);
@@ -59338,6 +59657,175 @@ var init_motebit_runtime = __esm({
59338
59657
  ...buildP2pPayment ? { buildP2pPayment } : {},
59339
59658
  getActiveGrantId: () => this._activeTurnGrant?.grant_id ?? null
59340
59659
  });
59660
+ if (config.relayPublicKey != null) {
59661
+ this._grantedSpendCoords = {
59662
+ syncUrl: config.syncUrl,
59663
+ authToken: config.authToken,
59664
+ relayPublicKeyHex: config.relayPublicKey,
59665
+ ...config.acknowledgeNoHistoryRisk != null ? { acknowledgeNoHistoryRisk: config.acknowledgeNoHistoryRisk } : {}
59666
+ };
59667
+ }
59668
+ }
59669
+ /**
59670
+ * Execute a paid sub-delegation autonomously under a signed standing grant —
59671
+ * the DETERMINISTIC (human-absent) money path that a first-party spending
59672
+ * molecule (the Clerk archetype) drives. Unlike the AI loop (whose R4 spend
59673
+ * is authorized by a live human approval or a grant-carrying turn) and
59674
+ * `invokeCapability` (a user tap IS the human authorizer, so it uses the RAW
59675
+ * builder), this path has no human — so it re-composes the FULL R4 AND the
59676
+ * loop enforces, fail-CLOSED:
59677
+ *
59678
+ * 1. serialize under `_isProcessing` — the rail seam trusts `_activeTurnGrant`
59679
+ * only because turns are single-by-construction;
59680
+ * 2. verify the grant via the SOLE producer `verifyGrantForTurn` — a null
59681
+ * result (absent / expired / revoked / malformed) REFUSES, no broadcast
59682
+ * (the exact inverse of the loop's fail-OPEN-to-no-grant, safe there only
59683
+ * because a live human backstops that path);
59684
+ * 3. re-run the policy gate's scope check (`this.policy.validate` with the
59685
+ * grant's SIGNED scope) — the meter enforces the ceiling but never scope;
59686
+ * 4. route the broadcast through the meter-wrapped builder
59687
+ * (`wrapP2pPaymentWithMeter`), NEVER the raw wallet method.
59688
+ *
59689
+ * `dryRun` exercises 1–3 and the blast-radius meter (over-ceiling / replay
59690
+ * refuse with the `BlastRadiusDenial` code) against a THROWAWAY in-memory
59691
+ * store, then stops before any broadcast or submit — so a fake spend cannot
59692
+ * poison the live lifetime ceiling and no funds move (no wallet required).
59693
+ * Refusals carry only the denial CODE; the `spend_overage_micro` residual is
59694
+ * owner-facing and never relayed. Adds zero new authority surface; locked by
59695
+ * the `check-money-authority` deterministic-path assertion.
59696
+ */
59697
+ async executeGrantedDelegation(params) {
59698
+ const coords = this._grantedSpendCoords;
59699
+ if (coords == null)
59700
+ return { ok: false, code: "sync_not_enabled" };
59701
+ const delegateToolDef = this.toolRegistry.get("delegate_to_agent");
59702
+ if (delegateToolDef == null)
59703
+ return { ok: false, code: "sync_not_enabled" };
59704
+ if (this._isProcessing)
59705
+ throw new Error("Already processing a message");
59706
+ this._isProcessing = true;
59707
+ try {
59708
+ const presentedGrant = await verifyGrantForTurn(params.delegation.token, params.delegation.grant, params.delegation.revocations ?? []);
59709
+ if (presentedGrant == null)
59710
+ return { ok: false, code: "requires_verified_grant" };
59711
+ const decision = this.policy.validate(delegateToolDef, { prompt: params.prompt, required_capabilities: [params.capability] }, {
59712
+ ...this.policy.createTurnContext(),
59713
+ verifiedGrant: presentedGrant,
59714
+ delegationScope: params.delegation.grant.scope
59715
+ });
59716
+ if (!decision.allowed)
59717
+ return { ok: false, code: "missing_scope" };
59718
+ this._activeTurnGrant = presentedGrant;
59719
+ const ack = typeof coords.acknowledgeNoHistoryRisk === "function" ? coords.acknowledgeNoHistoryRisk() : coords.acknowledgeNoHistoryRisk;
59720
+ const exploreSeed = params.delegation.token.signature;
59721
+ const selectWorker2 = params.targetWorkerId != null ? void 0 : async (candidates) => {
59722
+ const rankable = await Promise.all(candidates.map(async (c3) => ({
59723
+ motebit_id: c3.motebit_id,
59724
+ trustRecord: await this.getAgentTrust(c3.motebit_id),
59725
+ ...c3.unitCost != null ? { unitCost: c3.unitCost } : {}
59726
+ })));
59727
+ const repCostUsd = Math.min(...rankable.map((r2) => r2.unitCost ?? 0));
59728
+ const strength = explorationStrengthForStakes(repCostUsd);
59729
+ const capability = params.capability;
59730
+ const exploitTop = selectWorker(this.motebitId, rankable, { capability });
59731
+ const winner = selectWorker(this.motebitId, rankable, {
59732
+ capability,
59733
+ explore: { seed: exploreSeed, strength }
59734
+ });
59735
+ if (winner != null) {
59736
+ this._logger.warn("routing.worker_selected", {
59737
+ selected: winner.motebit_id,
59738
+ capability,
59739
+ candidates: rankable.length,
59740
+ strength: Number(strength.toFixed(3)),
59741
+ explored: exploitTop != null && winner.motebit_id !== exploitTop.motebit_id,
59742
+ quality: Number(winner.route.trust.toFixed(3))
59743
+ });
59744
+ }
59745
+ return winner?.motebit_id ?? null;
59746
+ };
59747
+ if (params.dryRun === true) {
59748
+ const resolved = await resolveP2pPaymentRequest({
59749
+ motebitId: this.motebitId,
59750
+ syncUrl: coords.syncUrl,
59751
+ authToken: coords.authToken,
59752
+ capability: params.capability,
59753
+ relayPublicKeyHex: coords.relayPublicKeyHex,
59754
+ ...params.targetWorkerId != null ? { targetWorkerId: params.targetWorkerId } : {},
59755
+ ...selectWorker2 != null ? { selectWorker: selectWorker2 } : {},
59756
+ ...ack === true ? { acknowledgeNoHistoryRisk: true } : {}
59757
+ });
59758
+ if (!resolved.ok)
59759
+ return { ok: false, code: resolved.error.code };
59760
+ const req = resolved.paymentRequest;
59761
+ const totalOutflowMicro = req.amountMicro + req.feeAmountMicro + (req.executorFeeAmountMicro ?? 0);
59762
+ const dryMeter = createMoneyMeter(new InMemoryGrantSpendStore());
59763
+ const verdict = await dryMeter(presentedGrant, "p2p_payment", {
59764
+ amount_micro: totalOutflowMicro,
59765
+ counterparty: resolved.workerAddress
59766
+ });
59767
+ if (!verdict.allowed)
59768
+ return { ok: false, code: verdict.denial ?? "money_meter_denied" };
59769
+ return {
59770
+ ok: true,
59771
+ dryRun: true,
59772
+ settlement: {
59773
+ mode: "p2p",
59774
+ paidMicro: req.amountMicro,
59775
+ feeMicro: req.feeAmountMicro + (req.executorFeeAmountMicro ?? 0)
59776
+ }
59777
+ };
59778
+ }
59779
+ const rawBuild = this._solanaWallet?.buildP2pPayment?.bind(this._solanaWallet);
59780
+ if (rawBuild == null)
59781
+ return { ok: false, code: "no_sovereign_rail" };
59782
+ const buildP2pPayment = wrapP2pPaymentWithMeter(rawBuild, () => this._activeTurnGrant, this.moneyMeter);
59783
+ const result = await resolveAndSubmitP2pDelegation({
59784
+ motebitId: this.motebitId,
59785
+ syncUrl: coords.syncUrl,
59786
+ authToken: coords.authToken,
59787
+ relayPublicKeyHex: coords.relayPublicKeyHex,
59788
+ prompt: params.prompt,
59789
+ capability: params.capability,
59790
+ buildP2pPayment,
59791
+ grantId: presentedGrant.grant_id,
59792
+ invocationOrigin: "agent-to-agent",
59793
+ ...params.targetWorkerId != null ? { targetWorkerId: params.targetWorkerId } : {},
59794
+ ...selectWorker2 != null ? { selectWorker: selectWorker2 } : {},
59795
+ ...ack === true ? { acknowledgeNoHistoryRisk: true } : {},
59796
+ logger: this._logger
59797
+ });
59798
+ if (!result.ok) {
59799
+ const code2 = result.error.code === "money_meter_denied" ? result.error.denial ?? "money_meter_denied" : result.error.code;
59800
+ this._logger.warn("delegation.paid_failed", {
59801
+ code: code2,
59802
+ capability: params.capability,
59803
+ ...result.error.code !== "money_meter_denied" && "message" in result.error ? { message: result.error.message } : {}
59804
+ });
59805
+ return { ok: false, code: code2 };
59806
+ }
59807
+ try {
59808
+ const workerReceipt = result.receipt;
59809
+ if (workerReceipt.public_key != null && workerReceipt.public_key !== "") {
59810
+ const valid = await verifyExecutionReceipt(workerReceipt, hexToBytes5(workerReceipt.public_key));
59811
+ if (valid)
59812
+ await this.bumpTrustFromReceipt(workerReceipt, true, params.capability);
59813
+ }
59814
+ } catch (err2) {
59815
+ this._logger.warn("routing.trust_bump_skipped", {
59816
+ reason: err2 instanceof Error ? err2.message : String(err2)
59817
+ });
59818
+ }
59819
+ return {
59820
+ ok: true,
59821
+ dryRun: false,
59822
+ receipt: result.receipt,
59823
+ ...result.settlement ? { settlement: result.settlement } : {}
59824
+ };
59825
+ } finally {
59826
+ this._activeTurnGrant = null;
59827
+ this._isProcessing = false;
59828
+ }
59341
59829
  }
59342
59830
  /**
59343
59831
  * Drain interactive delegation receipts (used by handleAgentTask to include
@@ -59671,6 +60159,7 @@ __export(dist_exports7, {
59671
60159
  resolveAndSubmitP2pDelegation: () => resolveAndSubmitP2pDelegation,
59672
60160
  resolveAttachedAct: () => resolveAttachedAct,
59673
60161
  resolveAttachedRead: () => resolveAttachedRead,
60162
+ resolveP2pPaymentRequest: () => resolveP2pPaymentRequest,
59674
60163
  resolveProactiveAnchor: () => resolveProactiveAnchor,
59675
60164
  selectAndRunDelegation: () => selectAndRunDelegation,
59676
60165
  slabTurnIdForRun: () => slabTurnIdForRun,
@@ -78657,6 +79146,21 @@ var init_migrations_registry = __esm({
78657
79146
  high_water_nonce INTEGER NOT NULL
78658
79147
  )`
78659
79148
  ]
79149
+ },
79150
+ {
79151
+ version: 42,
79152
+ description: "agent_trust.capability_stats \u2014 per-capability competence counts",
79153
+ statements: [
79154
+ // AgentTrustRecord gained an optional `capability_stats` map: per-capability
79155
+ // successful/failed counts so first-person routing scopes competence to the
79156
+ // capability being hired (docs/doctrine/first-person-worker-routing.md).
79157
+ // The pairwise trust_level (a relationship) stays capability-agnostic; only
79158
+ // the success/fail counts split by capability. Additive nullable JSON column
79159
+ // ({capability: {successful_tasks, failed_tasks}}); NULL ⇒ no per-capability
79160
+ // history yet. Local private state — never on the wire (the .strict()
79161
+ // TrustCredentialSubject carries only the aggregate counts).
79162
+ "ALTER TABLE agent_trust ADD COLUMN capability_stats TEXT"
79163
+ ]
78660
79164
  }
78661
79165
  ];
78662
79166
  }
@@ -79189,7 +79693,30 @@ function rowToGradientSnapshot(row) {
79189
79693
  stats: JSON.parse(row.stats)
79190
79694
  };
79191
79695
  }
79696
+ function parseCapabilityStats(raw) {
79697
+ if (raw == null || raw === "")
79698
+ return void 0;
79699
+ try {
79700
+ const parsed = JSON.parse(raw);
79701
+ if (parsed == null || typeof parsed !== "object")
79702
+ return void 0;
79703
+ const out = {};
79704
+ for (const [cap, v2] of Object.entries(parsed)) {
79705
+ if (v2 == null || typeof v2 !== "object")
79706
+ continue;
79707
+ const s3 = v2.successful_tasks;
79708
+ const f6 = v2.failed_tasks;
79709
+ if (typeof s3 === "number" && typeof f6 === "number") {
79710
+ out[cap] = { successful_tasks: s3, failed_tasks: f6 };
79711
+ }
79712
+ }
79713
+ return Object.keys(out).length > 0 ? out : void 0;
79714
+ } catch {
79715
+ return void 0;
79716
+ }
79717
+ }
79192
79718
  function rowToAgentTrust(row) {
79719
+ const capabilityStats = parseCapabilityStats(row.capability_stats);
79193
79720
  return {
79194
79721
  motebit_id: row.motebit_id,
79195
79722
  remote_motebit_id: row.remote_motebit_id,
@@ -79201,7 +79728,8 @@ function rowToAgentTrust(row) {
79201
79728
  successful_tasks: row.successful_tasks ?? 0,
79202
79729
  failed_tasks: row.failed_tasks ?? 0,
79203
79730
  notes: row.notes ?? void 0,
79204
- petname: row.petname ?? void 0
79731
+ petname: row.petname ?? void 0,
79732
+ ...capabilityStats != null ? { capability_stats: capabilityStats } : {}
79205
79733
  };
79206
79734
  }
79207
79735
  function rowToServiceListing(row) {
@@ -80426,8 +80954,8 @@ CREATE INDEX IF NOT EXISTS idx_agent_trust_motebit ON agent_trust (motebit_id);
80426
80954
  constructor(db) {
80427
80955
  this.stmtGet = db.prepare(`SELECT * FROM agent_trust WHERE motebit_id = ? AND remote_motebit_id = ?`);
80428
80956
  this.stmtSet = db.prepare(`INSERT OR REPLACE INTO agent_trust
80429
- (motebit_id, remote_motebit_id, trust_level, public_key, first_seen_at, last_seen_at, interaction_count, successful_tasks, failed_tasks, notes, petname)
80430
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
80957
+ (motebit_id, remote_motebit_id, trust_level, public_key, first_seen_at, last_seen_at, interaction_count, successful_tasks, failed_tasks, notes, petname, capability_stats)
80958
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
80431
80959
  this.stmtList = db.prepare(`SELECT * FROM agent_trust WHERE motebit_id = ? ORDER BY last_seen_at DESC`);
80432
80960
  this.stmtUpdateLevel = db.prepare(`UPDATE agent_trust SET trust_level = ?, last_seen_at = ? WHERE motebit_id = ? AND remote_motebit_id = ?`);
80433
80961
  }
@@ -80438,7 +80966,7 @@ CREATE INDEX IF NOT EXISTS idx_agent_trust_motebit ON agent_trust (motebit_id);
80438
80966
  return rowToAgentTrust(row);
80439
80967
  }
80440
80968
  async setAgentTrust(record) {
80441
- this.stmtSet.run(record.motebit_id, record.remote_motebit_id, record.trust_level, record.public_key ?? null, record.first_seen_at, record.last_seen_at, record.interaction_count, record.successful_tasks ?? 0, record.failed_tasks ?? 0, record.notes ?? null, record.petname ?? null);
80969
+ this.stmtSet.run(record.motebit_id, record.remote_motebit_id, record.trust_level, record.public_key ?? null, record.first_seen_at, record.last_seen_at, record.interaction_count, record.successful_tasks ?? 0, record.failed_tasks ?? 0, record.notes ?? null, record.petname ?? null, record.capability_stats != null && Object.keys(record.capability_stats).length > 0 ? JSON.stringify(record.capability_stats) : null);
80442
80970
  }
80443
80971
  async listAgentTrust(motebitId) {
80444
80972
  const rows = this.stmtList.all(motebitId);
@@ -84102,7 +84630,10 @@ function createRecallSelfHandler(searchFn) {
84102
84630
  }
84103
84631
  const formatted = hits.map((h5, i3) => `${i3 + 1}. [${h5.source} \xB7 ${h5.title} \xB7 score=${h5.score.toFixed(2)}]
84104
84632
  ${h5.content}`).join("\n\n---\n\n");
84105
- return { ok: true, data: formatted };
84633
+ const banner = "[SELF_DESCRIPTION \u2014 committed repo corpus: design + intent, not live state. For the current agent roster use discover_agents; for runtime state read the [Now] block.]";
84634
+ return { ok: true, data: `${banner}
84635
+
84636
+ ${formatted}` };
84106
84637
  } catch (err2) {
84107
84638
  const msg = err2 instanceof Error ? err2.message : String(err2);
84108
84639
  return { ok: false, error: `Interior recall error: ${msg}` };
@@ -87195,7 +87726,7 @@ function finalizeScores(scores, maxCandidates, explorationWeight) {
87195
87726
  }
87196
87727
  }
87197
87728
  function graphRankCandidates(selfId, candidates, requirements, config) {
87198
- const weights = { ...DEFAULT_WEIGHTS, ...config?.weights };
87729
+ const weights = { ...DEFAULT_WEIGHTS2, ...config?.weights };
87199
87730
  const maxCandidates = config?.maxCandidates ?? 10;
87200
87731
  const explorationWeight = config?.explorationWeight ?? 0;
87201
87732
  const compositeFn = config?.compositeFunction;
@@ -87240,7 +87771,7 @@ function findTrustedRoute(selfId, targetId, candidates, peerEdges) {
87240
87771
  return { trust: result.value, path: result.path };
87241
87772
  }
87242
87773
  function explainedRankCandidates(selfId, candidates, requirements, config) {
87243
- const weights = { ...DEFAULT_WEIGHTS, ...config?.weights };
87774
+ const weights = { ...DEFAULT_WEIGHTS2, ...config?.weights };
87244
87775
  const maxCandidates = config?.maxCandidates ?? 10;
87245
87776
  const explorationWeight = config?.explorationWeight ?? 0;
87246
87777
  const compositeFn = config?.compositeFunction;
@@ -87328,7 +87859,7 @@ function computePriceEfficiency(candidate, requirements) {
87328
87859
  return 0.7;
87329
87860
  return Math.max(0, 1 - totalCost / requirements.max_budget);
87330
87861
  }
87331
- var DEFAULT_WEIGHTS, weightedSumComposite, lexicographicComposite, ORGANIZATIONAL_TRUST_BASELINE, HARDWARE_ATTESTATION_BOOST, TrustAttestationSemiring;
87862
+ var DEFAULT_WEIGHTS2, weightedSumComposite, lexicographicComposite, ORGANIZATIONAL_TRUST_BASELINE, HARDWARE_ATTESTATION_BOOST, TrustAttestationSemiring;
87332
87863
  var init_graph_routing = __esm({
87333
87864
  "../../packages/market/dist/graph-routing.js"() {
87334
87865
  "use strict";
@@ -87337,7 +87868,7 @@ var init_graph_routing = __esm({
87337
87868
  init_dist14();
87338
87869
  init_dist14();
87339
87870
  init_credential_weight();
87340
- DEFAULT_WEIGHTS = {
87871
+ DEFAULT_WEIGHTS2 = {
87341
87872
  trust: 0.3,
87342
87873
  cost: 0.2,
87343
87874
  latency: 0.15,
@@ -87345,7 +87876,7 @@ var init_graph_routing = __esm({
87345
87876
  regulatory_risk: 0.2
87346
87877
  };
87347
87878
  weightedSumComposite = (_route, scores) => {
87348
- return scores.trust * DEFAULT_WEIGHTS.trust + scores.costScore * DEFAULT_WEIGHTS.cost + scores.latencyNorm * DEFAULT_WEIGHTS.latency + scores.reliability * DEFAULT_WEIGHTS.reliability + scores.riskScore * DEFAULT_WEIGHTS.regulatory_risk;
87879
+ return scores.trust * DEFAULT_WEIGHTS2.trust + scores.costScore * DEFAULT_WEIGHTS2.cost + scores.latencyNorm * DEFAULT_WEIGHTS2.latency + scores.reliability * DEFAULT_WEIGHTS2.reliability + scores.riskScore * DEFAULT_WEIGHTS2.regulatory_risk;
87349
87880
  };
87350
87881
  lexicographicComposite = (_route, scores) => {
87351
87882
  return scores.trust * 1e6 + scores.reliability * 1e3 + scores.costScore;
@@ -88295,6 +88826,18 @@ async function forwardTaskViaMcp(endpointUrl, taskId, prompt2, agentId, taskQueu
88295
88826
  // the MCP server is ready. 10s was too tight for cold start + TLS + init.
88296
88827
  signal: AbortSignal.timeout(3e4)
88297
88828
  });
88829
+ if (!initResp.ok) {
88830
+ const detail = await initResp.text().catch(() => "");
88831
+ logger43.warn("task.mcp_forward_failed", {
88832
+ correlationId: taskId,
88833
+ agent: agentId,
88834
+ endpoint: mcpEndpoint,
88835
+ step: "initialize",
88836
+ status: initResp.status,
88837
+ detail: detail.slice(0, 200)
88838
+ });
88839
+ return;
88840
+ }
88298
88841
  const sessionId = initResp.headers.get("mcp-session-id");
88299
88842
  if (sessionId)
88300
88843
  mcpHeaders["Mcp-Session-Id"] = sessionId;
@@ -88315,6 +88858,18 @@ async function forwardTaskViaMcp(endpointUrl, taskId, prompt2, agentId, taskQueu
88315
88858
  }),
88316
88859
  signal: AbortSignal.timeout(12e4)
88317
88860
  });
88861
+ if (!taskResp.ok) {
88862
+ const detail = await taskResp.text().catch(() => "");
88863
+ logger43.warn("task.mcp_forward_failed", {
88864
+ correlationId: taskId,
88865
+ agent: agentId,
88866
+ endpoint: mcpEndpoint,
88867
+ step: "tools/call",
88868
+ status: taskResp.status,
88869
+ detail: detail.slice(0, 200)
88870
+ });
88871
+ return;
88872
+ }
88318
88873
  const mcpResult = await parseMcpResponse(taskResp, 2);
88319
88874
  if (mcpResult?.result?.content) {
88320
88875
  const textContent = mcpResult.result.content.find((c3) => c3.type === "text");
@@ -108053,7 +108608,7 @@ function parseTokenPayloadUnsafe(token) {
108053
108608
  return null;
108054
108609
  }
108055
108610
  }
108056
- async function verifySignedTokenForDevice(token, motebitId, identityManager, expectedAudience, blacklistCheck, agentRevokedCheck) {
108611
+ async function verifySignedTokenForDevice(token, motebitId, identityManager, expectedAudience, blacklistCheck, agentRevokedCheck, agentKeyLookup) {
108057
108612
  const claims = parseTokenPayloadUnsafe(token);
108058
108613
  if (!claims || claims.mid !== motebitId || !claims.did)
108059
108614
  return false;
@@ -108062,9 +108617,13 @@ async function verifySignedTokenForDevice(token, motebitId, identityManager, exp
108062
108617
  if (blacklistCheck && claims.jti && blacklistCheck(claims.jti, motebitId))
108063
108618
  return false;
108064
108619
  const device = await identityManager.loadDeviceById(claims.did, motebitId);
108065
- if (!device || !device.public_key)
108620
+ let pubKeyHex = device?.public_key ?? null;
108621
+ if (pubKeyHex === null && agentKeyLookup) {
108622
+ pubKeyHex = agentKeyLookup(motebitId);
108623
+ }
108624
+ if (pubKeyHex === null)
108066
108625
  return false;
108067
- const pubKeyBytes = hexToBytes5(device.public_key);
108626
+ const pubKeyBytes = hexToBytes5(pubKeyHex);
108068
108627
  const payload = await verifySignedToken(token, pubKeyBytes);
108069
108628
  if (payload === null || payload.mid !== motebitId)
108070
108629
  return false;
@@ -114141,12 +114700,15 @@ function extractMotebitIdFromPath(path19) {
114141
114700
  const match = path19.match(/\/agent\/([^/]+)\/task/);
114142
114701
  return match ? match[1] : null;
114143
114702
  }
114144
- function getListingUnitCost(moteDb, agentId) {
114703
+ function getListingUnitCost(moteDb, agentId, capability) {
114145
114704
  const row = moteDb.db.prepare("SELECT pricing FROM relay_service_listings WHERE motebit_id = ? ORDER BY updated_at DESC LIMIT 1").get(agentId);
114146
114705
  if (!row)
114147
114706
  return 0;
114148
114707
  try {
114149
114708
  const pricing = JSON.parse(row.pricing);
114709
+ if (capability != null) {
114710
+ return pricing.find((p5) => p5.capability === capability)?.unit_cost ?? 0;
114711
+ }
114150
114712
  return pricing.reduce((sum2, p5) => sum2 + (p5.unit_cost ?? 0), 0);
114151
114713
  } catch {
114152
114714
  return 0;
@@ -114423,6 +114985,52 @@ async function handleReceiptIngestion(receipt, taskId, motebitId, entry, deps) {
114423
114985
  }
114424
114986
  return;
114425
114987
  }
114988
+ if (subEntry.settlement_mode === "p2p") {
114989
+ const subP2pProof = subEntry.p2p_payment_proof;
114990
+ const subWorkerAmount = subP2pProof?.amount_micro ?? 0;
114991
+ const subIsFederatedExecutor = subEntry.origin_relay != null;
114992
+ const subFeeAmount = subIsFederatedExecutor ? subP2pProof?.b_fee_amount_micro ?? 0 : subP2pProof?.fee_amount_micro ?? 0;
114993
+ const subP2pGross = subWorkerAmount + subFeeAmount;
114994
+ const subP2pFeeRate = subP2pGross > 0 ? Math.round(subFeeAmount / subP2pGross * 1e4) / 1e4 : 0;
114995
+ const subP2pSettlementId = crypto.randomUUID();
114996
+ const subP2pSettledAt = Date.now();
114997
+ const signedSubP2p = await signSettlement({
114998
+ settlement_id: subP2pSettlementId,
114999
+ allocation_id: `p2p-${subRelayTaskId}`,
115000
+ // Payee = the sub-agent that executed and was paid onchain.
115001
+ motebit_id: sub.motebit_id,
115002
+ receipt_hash: sub.result_hash ?? "",
115003
+ ledger_hash: null,
115004
+ amount_settled: subWorkerAmount,
115005
+ platform_fee: subFeeAmount,
115006
+ platform_fee_rate: subP2pFeeRate,
115007
+ // Lane in the signed body — the relay's custody posture is
115008
+ // committed-to, not derivable.
115009
+ settlement_mode: "p2p",
115010
+ status: "completed",
115011
+ settled_at: subP2pSettledAt,
115012
+ issuer_relay_id: relayIdentity.relayMotebitId
115013
+ }, relayIdentity.privateKey);
115014
+ moteDb.db.prepare(`INSERT OR IGNORE INTO relay_settlements
115015
+ (settlement_id, allocation_id, task_id, motebit_id, receipt_hash,
115016
+ amount_settled, platform_fee, platform_fee_rate, status, settled_at,
115017
+ settlement_mode, p2p_tx_hash, payment_verification_status, delegator_id,
115018
+ issuer_relay_id, suite, signature, record_json)
115019
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(subP2pSettlementId, `p2p-${subRelayTaskId}`, subRelayTaskId, sub.motebit_id, sub.result_hash ?? "", subWorkerAmount, subFeeAmount, subP2pFeeRate, "completed", subP2pSettledAt, "p2p", subP2pProof?.tx_hash ?? null, "pending", subEntry.submitted_by ?? null, signedSubP2p.issuer_relay_id, signedSubP2p.suite, signedSubP2p.signature, canonicalJson(signedSubP2p));
115020
+ logger33.info("multihop.settlement.p2p_recorded", {
115021
+ correlationId: parentTaskId,
115022
+ subTaskId: subRelayTaskId,
115023
+ subAgent: sub.motebit_id,
115024
+ net: subWorkerAmount,
115025
+ fee: subFeeAmount,
115026
+ depth
115027
+ });
115028
+ const nestedReceipts2 = sub.delegation_receipts ?? [];
115029
+ for (const nested of nestedReceipts2) {
115030
+ await settleSubReceipt(nested, parentTaskId, depth + 1);
115031
+ }
115032
+ return;
115033
+ }
114426
115034
  logger33.error("multihop.settlement.relay_residual_fired", {
114427
115035
  correlationId: parentTaskId,
114428
115036
  subTaskId: subRelayTaskId,
@@ -115041,7 +115649,10 @@ async function registerTaskRoutes(deps) {
115041
115649
  };
115042
115650
  const callerMotebitId = c3.get("callerMotebitId");
115043
115651
  const submittedBy = callerMotebitId ?? body.submitted_by;
115044
- const unitCostAtSubmission = getListingUnitCost(moteDb, motebitId);
115652
+ const isP2pProofSubmission = typeof body.target_agent === "string" && body.target_agent.length > 0;
115653
+ const pricingAgent = isP2pProofSubmission ? body.target_agent : motebitId;
115654
+ const pricingCapability = isP2pProofSubmission && Array.isArray(body.required_capabilities) && body.required_capabilities.length === 1 ? String(body.required_capabilities[0]) : void 0;
115655
+ const unitCostAtSubmission = getListingUnitCost(moteDb, pricingAgent, pricingCapability);
115045
115656
  const priceSnapshot = unitCostAtSubmission > 0 ? toMicro(computeGrossAmount(unitCostAtSubmission, platformFeeRate)) : void 0;
115046
115657
  const x402TxHash = lastSettleTxHash;
115047
115658
  const x402Net = lastSettleNetwork;
@@ -115100,7 +115711,14 @@ async function registerTaskRoutes(deps) {
115100
115711
  }
115101
115712
  const unitCostMicro = unitCostAtSubmission > 0 ? toMicro(unitCostAtSubmission) : void 0;
115102
115713
  if (unitCostMicro != null && proof.amount_micro !== unitCostMicro) {
115103
- throw new TaskError("TASK_P2P_AMOUNT_MISMATCH", `Payment amount ${proof.amount_micro} does not match expected ${priceSnapshot}`, 400);
115714
+ throw new TaskError(
115715
+ "TASK_P2P_AMOUNT_MISMATCH",
115716
+ // Report the NET worker-leg amount the check actually compares against
115717
+ // (`unitCostMicro`), not the gross `priceSnapshot` — the earlier
115718
+ // message showed the gross and misled the diagnosis.
115719
+ `Payment worker-leg amount ${proof.amount_micro} does not match expected ${unitCostMicro} for capability "${pricingCapability ?? "?"}"`,
115720
+ 400
115721
+ );
115104
115722
  }
115105
115723
  if (unitCostMicro != null && platformFeeRate > 0) {
115106
115724
  const expectedFeeMicro = computeP2pFeeMicro(unitCostMicro, platformFeeRate);
@@ -115247,7 +115865,54 @@ async function registerTaskRoutes(deps) {
115247
115865
  let routed = false;
115248
115866
  let federationAttempted = false;
115249
115867
  let routingChoice;
115250
- if (requiredCaps.length > 0) {
115868
+ let pinnedLocalHandled = false;
115869
+ if (settlementMode === "p2p" && body.target_agent != null && !federatedP2pIntent) {
115870
+ pinnedLocalHandled = true;
115871
+ const pinnedId = body.target_agent;
115872
+ routingChoice = {
115873
+ selected_agent: pinnedId,
115874
+ composite_score: 1,
115875
+ sub_scores: { pinned: 1 },
115876
+ routing_paths: [[pinnedId]],
115877
+ alternatives_considered: 0
115878
+ };
115879
+ const pinnedPeers = connections.get(pinnedId);
115880
+ if (pinnedPeers && pinnedPeers.length > 0) {
115881
+ for (const peer of pinnedPeers) {
115882
+ peer.ws.send(payload);
115883
+ }
115884
+ routed = true;
115885
+ logger33.info("task.p2p_pinned_dispatched", {
115886
+ correlationId: taskId,
115887
+ worker: pinnedId,
115888
+ via: "websocket"
115889
+ });
115890
+ } else {
115891
+ const pinnedReg = moteDb.db.prepare("SELECT endpoint_url FROM agent_registry WHERE motebit_id = ? AND expires_at > ?").get(pinnedId, Date.now());
115892
+ if (pinnedReg?.endpoint_url?.trim()) {
115893
+ void forwardTaskViaMcp(pinnedReg.endpoint_url, taskId, body.prompt, pinnedId, taskQueue, logger33, apiToken, async (receiptCandidate) => {
115894
+ const mcpEntry = taskQueue.get(taskId);
115895
+ if (!mcpEntry || mcpEntry.settled)
115896
+ return;
115897
+ await handleReceiptIngestion(receiptCandidate, taskId, mcpEntry.task.motebit_id, mcpEntry, ingestionDeps);
115898
+ });
115899
+ routed = true;
115900
+ logger33.info("task.p2p_pinned_dispatched", {
115901
+ correlationId: taskId,
115902
+ worker: pinnedId,
115903
+ via: "mcp",
115904
+ endpoint: pinnedReg.endpoint_url
115905
+ });
115906
+ } else {
115907
+ logger33.error("task.p2p_pinned_unroutable", {
115908
+ correlationId: taskId,
115909
+ worker: pinnedId,
115910
+ reason: "no WebSocket connection and no registered endpoint_url"
115911
+ });
115912
+ }
115913
+ }
115914
+ }
115915
+ if (!pinnedLocalHandled && requiredCaps.length > 0) {
115251
115916
  try {
115252
115917
  const { profiles, requirements } = taskRouter.buildCandidateProfiles(requiredCaps[0], void 0, 20, callerMotebitId);
115253
115918
  const multiCapProfiles = requiredCaps.length > 1 ? profiles.filter((p5) => requiredCaps.every((cap) => p5.listing?.capabilities.includes(cap))) : profiles;
@@ -115485,6 +116150,12 @@ async function registerTaskRoutes(deps) {
115485
116150
  });
115486
116151
  } else {
115487
116152
  taskRouter.recordPeerForwardResult(peerEndpoint, false);
116153
+ logger33.warn("task.forward_rejected", {
116154
+ correlationId: taskId,
116155
+ peerRelay: peerEndpoint,
116156
+ targetAgent: selId,
116157
+ status: resp.status
116158
+ });
115488
116159
  }
115489
116160
  } catch (fwdErr) {
115490
116161
  taskRouter.recordPeerForwardResult(peerEndpoint, false);
@@ -115523,7 +116194,7 @@ async function registerTaskRoutes(deps) {
115523
116194
  throw err2;
115524
116195
  }
115525
116196
  }
115526
- if (!routed && !federationAttempted) {
116197
+ if (!pinnedLocalHandled && !routed && !federationAttempted) {
115527
116198
  const peers = connections.get(motebitId);
115528
116199
  if (peers) {
115529
116200
  for (const peer of peers) {
@@ -115537,7 +116208,7 @@ async function registerTaskRoutes(deps) {
115537
116208
  }
115538
116209
  }
115539
116210
  }
115540
- if (!routed && !federationAttempted && requiredCaps.length > 0) {
116211
+ if (!pinnedLocalHandled && !routed && !federationAttempted && requiredCaps.length > 0) {
115541
116212
  const now2 = Date.now();
115542
116213
  const capFilter = requiredCaps[0];
115543
116214
  const httpCandidate = moteDb.db.prepare(`SELECT r.motebit_id, r.endpoint_url FROM agent_registry r
@@ -115554,7 +116225,7 @@ async function registerTaskRoutes(deps) {
115554
116225
  routed = true;
115555
116226
  }
115556
116227
  }
115557
- if (!routed && !federationAttempted && pushAdapter) {
116228
+ if (!pinnedLocalHandled && !routed && !federationAttempted && pushAdapter) {
115558
116229
  void attemptPushWake(motebitId, { pushAdapter, db: moteDb.db });
115559
116230
  }
115560
116231
  const responseBody = {
@@ -116592,6 +117263,11 @@ async function createSyncRelay(config) {
116592
117263
  return acc;
116593
117264
  }, {})
116594
117265
  });
117266
+ const agentRegistryKeyLookup = (mid) => {
117267
+ const row = moteDb.db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(mid);
117268
+ return row?.public_key ?? null;
117269
+ };
117270
+ const verifySignedTokenForDeviceWithFallback = (token, mid, im, aud, blacklistCheck, agentRevokedCheck, agentKeyLookup) => verifySignedTokenForDevice(token, mid, im, aud, blacklistCheck, agentRevokedCheck, agentKeyLookup ?? agentRegistryKeyLookup);
116595
117271
  const { allLimiters, wsLimiter } = registerMiddleware({
116596
117272
  app,
116597
117273
  apiToken,
@@ -116602,7 +117278,7 @@ async function createSyncRelay(config) {
116602
117278
  getFreezeReason,
116603
117279
  isTokenBlacklisted,
116604
117280
  isAgentRevoked,
116605
- verifySignedTokenForDevice,
117281
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
116606
117282
  parseTokenPayloadUnsafe,
116607
117283
  getShuttingDown: config.getShuttingDown,
116608
117284
  getConnectionCount: () => getConnectionCount(),
@@ -116685,7 +117361,7 @@ async function createSyncRelay(config) {
116685
117361
  wsLimiter,
116686
117362
  isTokenBlacklisted,
116687
117363
  isAgentRevoked,
116688
- verifySignedTokenForDevice,
117364
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
116689
117365
  parseTokenPayloadUnsafe,
116690
117366
  logger: logger43,
116691
117367
  onCommandResponse: handleCommandResponse,
@@ -116696,7 +117372,7 @@ async function createSyncRelay(config) {
116696
117372
  apiToken,
116697
117373
  identityManager,
116698
117374
  parseTokenPayloadUnsafe,
116699
- verifySignedTokenForDevice,
117375
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
116700
117376
  isTokenBlacklisted,
116701
117377
  isAgentRevoked
116702
117378
  });
@@ -116712,7 +117388,7 @@ async function createSyncRelay(config) {
116712
117388
  getFreezeReason,
116713
117389
  isTokenBlacklisted,
116714
117390
  isAgentRevoked,
116715
- verifySignedTokenForDevice,
117391
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
116716
117392
  parseTokenPayloadUnsafe
116717
117393
  });
116718
117394
  const federationCallbacks = createFederationCallbacks({
@@ -116920,7 +117596,7 @@ async function createSyncRelay(config) {
116920
117596
  apiToken,
116921
117597
  identityManager,
116922
117598
  parseTokenPayloadUnsafe,
116923
- verifySignedTokenForDevice,
117599
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
116924
117600
  isTokenBlacklisted,
116925
117601
  isAgentRevoked
116926
117602
  });
@@ -116984,7 +117660,7 @@ async function createSyncRelay(config) {
116984
117660
  federationConfig,
116985
117661
  federationQueryCache,
116986
117662
  parseTokenPayloadUnsafe,
116987
- verifySignedTokenForDevice,
117663
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
116988
117664
  isTokenBlacklisted,
116989
117665
  isAgentRevoked
116990
117666
  });
@@ -117182,7 +117858,7 @@ async function createSyncRelay(config) {
117182
117858
  maxTasksPerSubmitter: MAX_TASKS_PER_SUBMITTER,
117183
117859
  x402Config,
117184
117860
  parseTokenPayloadUnsafe,
117185
- verifySignedTokenForDevice,
117861
+ verifySignedTokenForDevice: verifySignedTokenForDeviceWithFallback,
117186
117862
  isTokenBlacklisted,
117187
117863
  isAgentRevoked,
117188
117864
  platformFeeRate,