@dvmkit/dvmctl 0.3.1-rc.1 → 0.3.3-rc.1
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/package.json
CHANGED
|
@@ -84,18 +84,45 @@ dvm request --endpoint "$dvm_endpoint" --data "$DVM_INPUT" --rail cashu --mint "
|
|
|
84
84
|
--max-increment "$DVM_PAYMENT_CAP" --max-payments 1 </dev/null >"$test_root/paid.json"
|
|
85
85
|
dvm wallet show >"$test_root/after.json"
|
|
86
86
|
job_id="$(node -p 'require(process.argv[1]).jobId' "$test_root/paid.json")"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
result_dir="$PWD/.dvmkit-test-results/$job_id"
|
|
88
|
+
mkdir -p -m 700 "$result_dir"
|
|
89
|
+
cp "$test_root/unpaid.json" "$test_root/before.json" "$test_root/after.json" "$test_root/paid.json" "$result_dir/"
|
|
90
|
+
dvm messages "$job_id" --no-stream >/dev/null
|
|
91
|
+
TMPDIR="$result_dir" dvm messages "$job_id" --no-stream --human | tee "$result_dir/artifacts.txt"
|
|
92
|
+
retained_config="$result_dir/caller"
|
|
93
|
+
node - "$DVM_CONFIG_DIR" "$retained_config" "$result_dir/messages.json" "$job_id" <<'NODE'
|
|
94
|
+
const { mkdirSync, readFileSync, writeFileSync } = require("node:fs");
|
|
95
|
+
const { join } = require("node:path");
|
|
96
|
+
const [source, destination, resultPath, jobId] = process.argv.slice(2);
|
|
97
|
+
const job = JSON.parse(readFileSync(join(source, "jobs.json"), "utf8")).find(item => item.id === jobId);
|
|
98
|
+
if (!job) throw Error(`caller state did not retain ${jobId}`);
|
|
99
|
+
const receipts = readFileSync(join(source, "receipts.jsonl"), "utf8").trim().split("\n").filter(Boolean).filter(line => JSON.parse(line).receipt?.job_id === jobId);
|
|
100
|
+
if (receipts.length !== 1) throw Error(`expected one receipt for ${jobId}, found ${receipts.length}`);
|
|
101
|
+
const messages = readFileSync(join(source, "messages", `${jobId}.jsonl`), "utf8").trim().split("\n").filter(Boolean).map(line => JSON.parse(line));
|
|
102
|
+
const retainedMessages = messages.filter(message => ["text", "artifact", "complete", "cancel"].includes(message.type));
|
|
103
|
+
if (!retainedMessages.some(message => message.type === "complete" || message.type === "cancel")) throw Error("caller state did not retain a terminal message");
|
|
104
|
+
const retainedJob = { id: job.id, endpoint: job.endpoint, status: job.status, submittedAt: job.submittedAt, completedAt: job.completedAt, completion: job.completion, paymentsHonoured: job.paymentsHonoured, policy: job.policy };
|
|
105
|
+
mkdirSync(join(destination, "messages"), { recursive: true, mode: 0o700 });
|
|
106
|
+
writeFileSync(join(destination, "jobs.json"), `${JSON.stringify([retainedJob])}\n`, { mode: 0o600 });
|
|
107
|
+
writeFileSync(join(destination, "receipts.jsonl"), `${receipts[0]}\n`, { mode: 0o600 });
|
|
108
|
+
writeFileSync(join(destination, "messages", `${jobId}.jsonl`), `${retainedMessages.map(message => JSON.stringify(message)).join("\n")}\n`, { mode: 0o600 });
|
|
109
|
+
writeFileSync(resultPath, `${JSON.stringify({ jobId, messages: retainedMessages })}\n`, { mode: 0o600 });
|
|
110
|
+
NODE
|
|
111
|
+
DVM_CONFIG_DIR="$retained_config" dvm receipts verify "$job_id" >"$result_dir/verified.json"
|
|
112
|
+
node - "$result_dir/unpaid.json" "$result_dir/before.json" "$result_dir/after.json" "$result_dir/paid.json" "$result_dir/messages.json" "$result_dir/verified.json" <<'NODE'
|
|
113
|
+
const [challengePath, beforePath, afterPath, paidPath, messagesPath, verifiedPath] = process.argv.slice(2);
|
|
114
|
+
const challenge=require(challengePath), before=require(beforePath), after=require(afterPath), paid=require(paidPath), messages=require(messagesPath), verified=require(verifiedPath);
|
|
91
115
|
const validReceiptStatuses = new Set(["verified", "verified_unattested"]);
|
|
92
116
|
const expectedSats=challenge.required_msats/1000;
|
|
93
117
|
if (before.total_sats-after.total_sats !== expectedSats) throw Error(`Cashu debit was ${before.total_sats-after.total_sats}, quote was ${expectedSats} sats`);
|
|
94
118
|
if (!paid.jobId || paid.next_action !== null || !validReceiptStatuses.has(paid.receipt_verified)) throw Error("paid result is not terminal with a valid receipt signature");
|
|
95
119
|
if (paid.receipt?.outcome !== "completed" || paid.receipt?.paid?.rail !== "cashu" || paid.receipt.paid.msats !== challenge.required_msats) throw Error("receipt is not bound to the 402 quote");
|
|
96
|
-
if (
|
|
120
|
+
if (!messages.messages?.some(message => message.type === "complete")) throw Error("paid messages did not complete");
|
|
121
|
+
if ((paid.has_artifacts || paid.artifact_count > 0) && !messages.messages?.some(message => message.type === "artifact")) throw Error("paid result advertised an artifact that was not retrieved");
|
|
122
|
+
if (verified.job_id !== paid.jobId || !validReceiptStatuses.has(verified.receipt_verified) || verified.receipt_checks?.result_hash !== "ok") throw Error("stored receipt and paid result hash did not verify");
|
|
97
123
|
NODE
|
|
98
|
-
cat "$
|
|
124
|
+
cat "$result_dir/paid.json"
|
|
125
|
+
printf '\nPaid result and artifact evidence retained in %s\n' "$result_dir"
|
|
99
126
|
```
|
|
100
127
|
|
|
101
128
|
The observed hosted-mint acceptance for a `$0.01` call quoted `12000` msats and debited `12` test sats. That is evidence from that rate snapshot, not a constant for future runs.
|
|
@@ -56,17 +56,34 @@ dvm request --endpoint "$dvm_endpoint" --data "$DVM_INPUT" --rail tempo \
|
|
|
56
56
|
--budget "$DVM_PAYMENT_CAP" --auto-pay-below "$DVM_PAYMENT_CAP" \
|
|
57
57
|
--max-increment "$DVM_PAYMENT_CAP" --max-payments 1 </dev/null >"$test_root/paid.json"
|
|
58
58
|
job_id="$(node -p 'require(process.argv[1]).jobId' "$test_root/paid.json")"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
result_dir="$PWD/.dvmkit-test-results/$job_id"
|
|
60
|
+
mkdir -p -m 700 "$result_dir"
|
|
61
|
+
cp "$test_root/unpaid.json" "$test_root/paid.json" "$result_dir/"
|
|
62
|
+
dvm messages "$job_id" --no-stream >/dev/null
|
|
63
|
+
TMPDIR="$result_dir" dvm messages "$job_id" --no-stream --human | tee "$result_dir/artifacts.txt"
|
|
64
|
+
retained_config="$result_dir/caller"
|
|
65
|
+
node - "$DVM_CONFIG_DIR" "$retained_config" "$result_dir/messages.json" "$job_id" <<'NODE'
|
|
66
|
+
const { mkdirSync, readFileSync, writeFileSync }=require("node:fs");const { join }=require("node:path");const [source,destination,resultPath,jobId]=process.argv.slice(2);
|
|
67
|
+
const job=JSON.parse(readFileSync(join(source,"jobs.json"),"utf8")).find(item=>item.id===jobId);if(!job)throw Error(`caller state did not retain ${jobId}`);
|
|
68
|
+
const receipts=readFileSync(join(source,"receipts.jsonl"),"utf8").trim().split("\n").filter(Boolean).filter(line=>JSON.parse(line).receipt?.job_id===jobId);if(receipts.length!==1)throw Error(`expected one receipt for ${jobId}, found ${receipts.length}`);
|
|
69
|
+
const messages=readFileSync(join(source,"messages",`${jobId}.jsonl`),"utf8").trim().split("\n").filter(Boolean).map(line=>JSON.parse(line));const retainedMessages=messages.filter(message=>["text","artifact","complete","cancel"].includes(message.type));if(!retainedMessages.some(message=>message.type==="complete"||message.type==="cancel"))throw Error("caller state did not retain a terminal message");
|
|
70
|
+
const retainedJob={id:job.id,endpoint:job.endpoint,status:job.status,submittedAt:job.submittedAt,completedAt:job.completedAt,completion:job.completion,paymentsHonoured:job.paymentsHonoured,policy:job.policy};mkdirSync(join(destination,"messages"),{recursive:true,mode:0o700});
|
|
71
|
+
writeFileSync(join(destination,"jobs.json"),`${JSON.stringify([retainedJob])}\n`,{mode:0o600});writeFileSync(join(destination,"receipts.jsonl"),`${receipts[0]}\n`,{mode:0o600});writeFileSync(join(destination,"messages",`${jobId}.jsonl`),`${retainedMessages.map(message=>JSON.stringify(message)).join("\n")}\n`,{mode:0o600});writeFileSync(resultPath,`${JSON.stringify({jobId,messages:retainedMessages})}\n`,{mode:0o600});
|
|
72
|
+
NODE
|
|
73
|
+
DVM_CONFIG_DIR="$retained_config" dvm receipts verify "$job_id" >"$result_dir/verified.json"
|
|
74
|
+
node - "$result_dir/unpaid.json" "$result_dir/paid.json" "$result_dir/messages.json" "$result_dir/verified.json" <<'NODE'
|
|
75
|
+
const [challengePath,paidPath,messagesPath,verifiedPath]=process.argv.slice(2);const challenge=require(challengePath),paid=require(paidPath),messages=require(messagesPath),verified=require(verifiedPath);
|
|
62
76
|
const validReceiptStatuses=new Set(["verified","verified_unattested"]);
|
|
63
77
|
if(!paid.jobId || paid.next_action!==null || !validReceiptStatuses.has(paid.receipt_verified)) throw Error("paid result is not terminal with a valid receipt signature");
|
|
64
78
|
const receipt=paid.receipt;
|
|
65
79
|
if(receipt?.outcome!=="completed" || receipt?.paid?.rail!=="tempo" || receipt.paid.msats!==challenge.required_msats) throw Error("receipt is not quote-bound Tempo");
|
|
66
80
|
if(receipt.paid.native_amount!==10000 || receipt.paid.native_asset!=="usdc") throw Error("$0.01 must settle as exactly 10000 pathUSD micro-units");
|
|
67
|
-
if(
|
|
81
|
+
if(!messages.messages?.some(message=>message.type==="complete")) throw Error("paid messages did not complete");
|
|
82
|
+
if((paid.has_artifacts || paid.artifact_count>0) && !messages.messages?.some(message=>message.type==="artifact")) throw Error("paid result advertised an artifact that was not retrieved");
|
|
83
|
+
if(verified.job_id!==paid.jobId || !validReceiptStatuses.has(verified.receipt_verified) || verified.receipt_checks?.result_hash!=="ok") throw Error("stored receipt and paid result hash did not verify");
|
|
68
84
|
NODE
|
|
69
|
-
cat "$
|
|
85
|
+
cat "$result_dir/paid.json"
|
|
86
|
+
printf '\nPaid result and artifact evidence retained in %s\n' "$result_dir"
|
|
70
87
|
```
|
|
71
88
|
|
|
72
89
|
Stop if the Moderato chain check, faucet, balance, or cap fails. Do not switch to mainnet or fund a production wallet as a workaround.
|
|
@@ -58,17 +58,34 @@ dvm request --endpoint "$dvm_endpoint" --data "$DVM_INPUT" --rail x402 \
|
|
|
58
58
|
--budget "$DVM_PAYMENT_CAP" --auto-pay-below "$DVM_PAYMENT_CAP" \
|
|
59
59
|
--max-increment "$DVM_PAYMENT_CAP" --max-payments 1 </dev/null >"$test_root/paid.json"
|
|
60
60
|
job_id="$(node -p 'require(process.argv[1]).jobId' "$test_root/paid.json")"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
result_dir="$PWD/.dvmkit-test-results/$job_id"
|
|
62
|
+
mkdir -p -m 700 "$result_dir"
|
|
63
|
+
cp "$test_root/unpaid.json" "$test_root/paid.json" "$result_dir/"
|
|
64
|
+
dvm messages "$job_id" --no-stream >/dev/null
|
|
65
|
+
TMPDIR="$result_dir" dvm messages "$job_id" --no-stream --human | tee "$result_dir/artifacts.txt"
|
|
66
|
+
retained_config="$result_dir/caller"
|
|
67
|
+
node - "$DVM_CONFIG_DIR" "$retained_config" "$result_dir/messages.json" "$job_id" <<'NODE'
|
|
68
|
+
const { mkdirSync, readFileSync, writeFileSync }=require("node:fs");const { join }=require("node:path");const [source,destination,resultPath,jobId]=process.argv.slice(2);
|
|
69
|
+
const job=JSON.parse(readFileSync(join(source,"jobs.json"),"utf8")).find(item=>item.id===jobId);if(!job)throw Error(`caller state did not retain ${jobId}`);
|
|
70
|
+
const receipts=readFileSync(join(source,"receipts.jsonl"),"utf8").trim().split("\n").filter(Boolean).filter(line=>JSON.parse(line).receipt?.job_id===jobId);if(receipts.length!==1)throw Error(`expected one receipt for ${jobId}, found ${receipts.length}`);
|
|
71
|
+
const messages=readFileSync(join(source,"messages",`${jobId}.jsonl`),"utf8").trim().split("\n").filter(Boolean).map(line=>JSON.parse(line));const retainedMessages=messages.filter(message=>["text","artifact","complete","cancel"].includes(message.type));if(!retainedMessages.some(message=>message.type==="complete"||message.type==="cancel"))throw Error("caller state did not retain a terminal message");
|
|
72
|
+
const retainedJob={id:job.id,endpoint:job.endpoint,status:job.status,submittedAt:job.submittedAt,completedAt:job.completedAt,completion:job.completion,paymentsHonoured:job.paymentsHonoured,policy:job.policy};mkdirSync(join(destination,"messages"),{recursive:true,mode:0o700});
|
|
73
|
+
writeFileSync(join(destination,"jobs.json"),`${JSON.stringify([retainedJob])}\n`,{mode:0o600});writeFileSync(join(destination,"receipts.jsonl"),`${receipts[0]}\n`,{mode:0o600});writeFileSync(join(destination,"messages",`${jobId}.jsonl`),`${retainedMessages.map(message=>JSON.stringify(message)).join("\n")}\n`,{mode:0o600});writeFileSync(resultPath,`${JSON.stringify({jobId,messages:retainedMessages})}\n`,{mode:0o600});
|
|
74
|
+
NODE
|
|
75
|
+
DVM_CONFIG_DIR="$retained_config" dvm receipts verify "$job_id" >"$result_dir/verified.json"
|
|
76
|
+
node - "$result_dir/unpaid.json" "$result_dir/paid.json" "$result_dir/messages.json" "$result_dir/verified.json" <<'NODE'
|
|
77
|
+
const [challengePath,paidPath,messagesPath,verifiedPath]=process.argv.slice(2);const challenge=require(challengePath),paid=require(paidPath),messages=require(messagesPath),verified=require(verifiedPath);
|
|
64
78
|
const validReceiptStatuses=new Set(["verified","verified_unattested"]);
|
|
65
79
|
if(!paid.jobId || paid.next_action!==null || !validReceiptStatuses.has(paid.receipt_verified)) throw Error("paid result is not terminal with a valid receipt signature");
|
|
66
80
|
const receipt=paid.receipt;
|
|
67
81
|
if(receipt?.outcome!=="completed" || receipt?.paid?.rail!=="x402" || receipt.paid.msats!==challenge.required_msats) throw Error("receipt is not quote-bound x402");
|
|
68
82
|
if(receipt.paid.native_amount!==10000 || receipt.paid.native_asset!=="usdc") throw Error("$0.01 must settle as exactly 10000 micro-USDC");
|
|
69
|
-
if(
|
|
83
|
+
if(!messages.messages?.some(message=>message.type==="complete")) throw Error("paid messages did not complete");
|
|
84
|
+
if((paid.has_artifacts || paid.artifact_count>0) && !messages.messages?.some(message=>message.type==="artifact")) throw Error("paid result advertised an artifact that was not retrieved");
|
|
85
|
+
if(verified.job_id!==paid.jobId || !validReceiptStatuses.has(verified.receipt_verified) || verified.receipt_checks?.result_hash!=="ok") throw Error("stored receipt and paid result hash did not verify");
|
|
70
86
|
NODE
|
|
71
|
-
cat "$
|
|
87
|
+
cat "$result_dir/paid.json"
|
|
88
|
+
printf '\nPaid result and artifact evidence retained in %s\n' "$result_dir"
|
|
72
89
|
```
|
|
73
90
|
|
|
74
91
|
Stop on a missing balance, RPC/facilitator failure, or cap refusal. Do not replace the network, key, or cap without new approval.
|