@haven_ai/signer 0.0.0-dev.202610071535.a5affd7 → 0.0.0-dev.202610071600.91b951e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -1
- package/dist/cli.cjs +33 -11
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +33 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +33 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +33 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -206,6 +206,26 @@ relays ("Connection closed" plus this process's exit message) names the same
|
|
|
206
206
|
command. The consent hash covers identity, tool names and the surface version —
|
|
207
207
|
not the block's prose — so neither change re-prompts an acknowledged install.
|
|
208
208
|
|
|
209
|
+
## Several Haven pairs on one machine (#3738)
|
|
210
|
+
|
|
211
|
+
One harness can carry several Haven pairs — `haven-research` +
|
|
212
|
+
`haven-signer-research`, `haven-ops` + `haven-signer-ops`, alongside a bare
|
|
213
|
+
`haven` + `haven-signer` (Codex: `haven` + `haven_signer`). A model must act as
|
|
214
|
+
one agent per task and keep hosted and signer calls inside that pair. Server
|
|
215
|
+
names are easy to cross, so the signer's `initialize` instructions state what
|
|
216
|
+
it is bound to:
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
This signer is bound to agent id <agent_id> and delegate address <0x…>.
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The agent id comes from the credential file's `agent_id` (or `HAVEN_AGENT_ID`
|
|
223
|
+
alongside `HAVEN_DELEGATE_KEY`); when neither is set the line says "no recorded
|
|
224
|
+
agent id" and still gives the delegate address, which is then compared alone.
|
|
225
|
+
The model compares it with `haven_get_agent`'s `id` and `delegateAddress` from
|
|
226
|
+
the hosted server it called, and signs nothing on a mismatch. Neither value is secret (the consent screen prints both), and
|
|
227
|
+
the line is advisory: what the signer refuses to sign is unchanged.
|
|
228
|
+
|
|
209
229
|
## Orchestration
|
|
210
230
|
|
|
211
231
|
Direct payment:
|
|
@@ -333,7 +353,7 @@ refusal class — `fallback`, `retry_with_new_quote`, `http_status`,
|
|
|
333
353
|
`SIGN_CONTEXT_REFUSED` (other) row names the hosted status read
|
|
334
354
|
(`next_tool_server_role: hosted`, `next_tool_name: haven_get_payment_status`,
|
|
335
355
|
`next_arguments: { payment_id }` — resolve the role against your own server
|
|
336
|
-
names); every other row carries `next_tool_omitted_reason` with the exact
|
|
356
|
+
names, and with several Haven pairs against this signer's own pair); every other row carries `next_tool_omitted_reason` with the exact
|
|
337
357
|
remedy. `message` is unchanged.
|
|
338
358
|
|
|
339
359
|
**#3271: `haven_sign` (never `haven_sign_x402`) has one escape from this
|
package/dist/cli.cjs
CHANGED
|
@@ -909,7 +909,7 @@ function encodeSiwxHeader(payload) {
|
|
|
909
909
|
|
|
910
910
|
// src/tools.ts
|
|
911
911
|
var SIGNER_NAME = "@haven_ai/signer";
|
|
912
|
-
var SIGNER_VERSION = "0.0.0-dev.
|
|
912
|
+
var SIGNER_VERSION = "0.0.0-dev.202610071600.91b951e";
|
|
913
913
|
var UNSUPPORTED_ARGUMENT_MARKER = "HavenSignerUnsupportedArgument:";
|
|
914
914
|
var USEROP_BINDING_MISMATCH = "USEROP_BINDING_MISMATCH";
|
|
915
915
|
var HavenUserOpBindingRefusedError = class extends edge.HavenSigningError {
|
|
@@ -2349,7 +2349,13 @@ function signerCompatibility() {
|
|
|
2349
2349
|
function signerCapabilityAdvertisement() {
|
|
2350
2350
|
return { experimental: { [SIGNER_CAPABILITY_KEY]: signerCompatibility() } };
|
|
2351
2351
|
}
|
|
2352
|
-
function
|
|
2352
|
+
function signerIdentityLines(identity) {
|
|
2353
|
+
if (!identity?.agentId && !identity?.delegateAddress) return [];
|
|
2354
|
+
const agent = identity.agentId ? `agent id ${identity.agentId}` : "no recorded agent id";
|
|
2355
|
+
const delegate = identity.delegateAddress ? ` and delegate address ${identity.delegateAddress}` : "";
|
|
2356
|
+
return [`This signer is bound to ${agent}${delegate}.`];
|
|
2357
|
+
}
|
|
2358
|
+
function signerInstructions(identity) {
|
|
2353
2359
|
const compatibility = signerCompatibility();
|
|
2354
2360
|
return [
|
|
2355
2361
|
"Haven edge signer: sign-only tools bound to the local delegate key. It never emits the",
|
|
@@ -2358,12 +2364,15 @@ function signerInstructions() {
|
|
|
2358
2364
|
"#3271, and delegation-rail x402) or haven_sign_x402 (x402 only) instead of relaying bulky",
|
|
2359
2365
|
"typed-data payloads yourself.",
|
|
2360
2366
|
"",
|
|
2361
|
-
|
|
2362
|
-
"
|
|
2363
|
-
"
|
|
2364
|
-
"
|
|
2365
|
-
"
|
|
2366
|
-
"
|
|
2367
|
+
...signerIdentityLines(identity),
|
|
2368
|
+
"When more than one Haven pair is configured, you act as ONE agent per task: if the",
|
|
2369
|
+
"user has not said which (in the request, or a project-level choice they stated), ask",
|
|
2370
|
+
"before any payment tool. Sign only through the signer of the hosted server you called:",
|
|
2371
|
+
"haven-<slug> with haven-signer-<slug>, bare haven with haven-signer, Codex haven with",
|
|
2372
|
+
"haven_signer. Before signing, compare the identity this signer states with",
|
|
2373
|
+
"haven_get_agent (its id and delegateAddress) from that hosted server \u2014 the delegate",
|
|
2374
|
+
"address alone when this signer has no recorded agent id. If they differ, stop and sign",
|
|
2375
|
+
"nothing \u2014 switch to the signer whose identity matches.",
|
|
2367
2376
|
"",
|
|
2368
2377
|
"Version compatibility (check this BEFORE signing, not after):",
|
|
2369
2378
|
`- x402 expected-context versions supported: ${compatibility.x402_expected_context_versions.join(", ")}`,
|
|
@@ -2383,14 +2392,22 @@ function signerInstructions() {
|
|
|
2383
2392
|
"machine-readable, not just prose: it carries code, supported_versions, received_version, and",
|
|
2384
2393
|
"fallback fields alongside the message, so you can branch on it directly. Every signer",
|
|
2385
2394
|
"refusal also carries the next-step family: next_tool_name + next_tool_server_role when a",
|
|
2386
|
-
"hosted tool follows (resolve the role against your own server names
|
|
2395
|
+
"hosted tool follows (resolve the role against your own server names \u2014 with several",
|
|
2396
|
+
"Haven pairs, the hosted server of THIS signer's pair), else",
|
|
2387
2397
|
"next_tool_omitted_reason saying why not.",
|
|
2388
2398
|
"",
|
|
2389
2399
|
"An undeclared top-level argument is refused, not stripped: haven_sign answers",
|
|
2390
2400
|
"UNSUPPORTED_ARGUMENT with unknown_arguments, signer_version and fallback (the update",
|
|
2391
2401
|
"command) instead of dropping the key and answering the generic signing error \u2014 if you see",
|
|
2392
2402
|
"that refusal, this signer predates the argument form you sent. Update the signer; nothing",
|
|
2393
|
-
"was signed, fetched or audited."
|
|
2403
|
+
"was signed, fetched or audited.",
|
|
2404
|
+
"",
|
|
2405
|
+
"Sign-In-With-X (#3728): when a merchant 402 carries a sign-in-with-x extension (or the",
|
|
2406
|
+
"merchant documents a CAIP-122 sign-in route), call haven_sign_siwx with { url, challenge }.",
|
|
2407
|
+
"The signer composes the EIP-4361 message itself from the validated challenge and signs it with",
|
|
2408
|
+
"the delegate key \u2014 it returns { sign_in_with_x_header }; retry the merchant with the",
|
|
2409
|
+
"SIGN-IN-WITH-X header set to that value. This proves the delegate wallet paid the merchant; it",
|
|
2410
|
+
"moves no funds and cannot approve any payment."
|
|
2394
2411
|
].join("\n");
|
|
2395
2412
|
}
|
|
2396
2413
|
async function loadSignerCredentials(path = process.env.HAVEN_CREDENTIALS) {
|
|
@@ -2519,7 +2536,12 @@ function buildSignerMcpServer(signer, options = {}) {
|
|
|
2519
2536
|
{ name: SIGNER_NAME, version: SIGNER_VERSION },
|
|
2520
2537
|
{
|
|
2521
2538
|
capabilities: signerCapabilityAdvertisement(),
|
|
2522
|
-
|
|
2539
|
+
// #3738: the identity line lets a model holding several Haven pairs
|
|
2540
|
+
// confirm this signer belongs to the hosted server it called.
|
|
2541
|
+
instructions: signerInstructions({
|
|
2542
|
+
agentId: options.credentials?.agentId,
|
|
2543
|
+
delegateAddress: signer.delegateAddress
|
|
2544
|
+
})
|
|
2523
2545
|
}
|
|
2524
2546
|
);
|
|
2525
2547
|
const credentialsPath = options.credentials?.sourcePath;
|