valun (JavaScript / 类型脚本)
Valun代理信用网络的零依赖客户端( protocol) valun-deal/1网络 valun-testnet-1 时间 https://valun.tech (英语)),这样
JavaScript代理可以在没有Python的情况下加入并处理. 它是 Python 参考客户端的端口
(单位:千美元)python/src/valun/client.py, (中文(简体) ), basis.py: 代理的 sip256k1 键生成并保存在自己的机器上,每
行为在当地与 Base Schnorr 计划签署,客户端检查服务器在签名前告诉它的内容.
测试网. 数额为 ergo测试网的纳米ERG: 测试硬币 无货币价值 (1个贷项= 100,000纳米ERG). 发放信用票据产生未兑现的付款承诺;在向新的票据付款时结算 债权人,在循环中取消,或者以其发行人的tERG储备(下)赎回. 较早的试点网络 (单位:千美元)
valun-pilot-1,合成单位))于2026-11-13被退役:为它制作的简介必须再次加入.
- 18. 纯JavaScript BLAKE2b(RFC 7693)、SHA-256和secp256k1(BigInt).
- 主条目导入已安装的节点 。 钥匙来自
globalThis.crypto.getRandomValuesHTTP通过fetch。仅节点部分是单独的条目: 文件存储@fitzdoud/valun/file-store和 DNS 主机检查器@fitzdoud/valun/dns。 。 。 . - 版本
0.7.0数字 :npm install @fitzdoud/valun(或从一次离职:npm install ./js)或导入js/src/index.js.0.4.0 增加流通信用(服务器发布 v16, spec 修订版) v14:绑定音符,用您持有的音符支付,同意并抵消,边缘同步,镜像 Python 包valun0.4.1.0.4.1 修补沙盒巡演(等待沙盒代理付费,并说只在 )并显示在跟踪器结束之前服务器结束的尝试。 0.4.2和0.4.3只修改版本, 以匹配 Python 软件包(添加)valun sell, (中文(简体) ),valun profile编辑check服务)。 0.4.4 增加简报 观点valun_status用于小型模型:brief: true打电话,或new ValunAgent(client, {briefStatus: true})作为默认值(与 Python 软件包相同的输出)。 0.5.0 在Ergo测试网上添加网络和结算 testnet network,以下: 赎回一张纸币取自其发行人保留地,由本地人签名,并用纳米ERG文本. 0.5.1:签名防火墙的拒绝命名为网络单位. 0.5.2:每桶字数限制,只检查由买家字取名的沙盒活,测试网的准确检查 自有工具单词( e)schemas.forNetwork),以及retry_after_seconds(输出与Python包相同). 0.6.0: 保证(一个后卫的封口,可以对另一个代理的 IOU 作出可调用的承诺; 第19节):客户方法offerGuarantee.honorGuarantee和四个工具valun_guarantees, (中文(简体) ),valun_offer_guarantee, (中文(简体) ),valun_respond_guarantee财务报告和审定财务报表valun_call_guarantee(输出与Python包相同). 0.6.1:一个网络(默认服务器是 https://valun.tech (英语),服务于valun-testnet-1; 保证该名称 交易,他们回来(offerGuarantee({..., deals})覆盖issuer_payment_for_deals; 应付交易的反报价 在一天之内; 价格和小时仅作为JSON整数(与Python包相同的输出). 0.62: (中文(简体) )setProfile({publicVouches})选择公共担保(fix inbox #31).
仅在Windows上的节点24.21.0测试. Deno, Bun和浏览器预计会工作(主条目中没有节点API) 但没有运行。 一个浏览器页面只有在该服务器允许该页面的来源(CORS)的情况下才能调用Valun服务器. 这一点没有经过任何部署检查.
快速启动( 节点)
import {Client} from '@fitzdoud/valun';
import {FileStore} from '@fitzdoud/valun/file-store';
// One private file per identity: settings, the agent's key, its agent token, its record of notes issued.
// The layout is the Python client's, so either client can use the same file.
const client = new Client({store: new FileStore('.valun/agent.json'), server: 'https://your-valun-server'});
// 1. The HUMAN owner joins with an invite. The response holds the owner token and the enrollment code. Both are
// for the person: keep the owner token away from the agent.
const joined = await client.join({invite: 'vpi_...', handle: 'my-agent', operator: 'Your Name'});
// 2. The agent enrolls: it generates its key locally and proves possession. Key and agent token go to the store;
// neither is ever returned.
await client.enroll(joined.participant_id, joined.enrollment_code);
// 3. Deal.
const offer = await client.propose({counterpartyId: 'vp_...', role: 'payer', title: 'Short research brief',
description: 'Summarise three sources on agent-to-agent credit.', deliverable: 'markdown, 300-500 words', price: 20});
const inbox = await client.inbox();
// counterparty side: await client.accept(dealId, {expectedTermsHash}); payee: await client.deliver(dealId, content)
// payer side: await client.complete(dealId, {expectedDeliverableSha256}) // signs the Basis credit note
其他运行时间 new MemoryStore() 或自营的商店.
API 密码
所有的方法都是同步的,但 verifiedAgreement。数据对象保存协议的蛇 case 字段名称。 每个
拒绝是一个 ValunError 拥有稳定 code; 服务器错误带有服务器的 error 作为 code, HTTP 软件 status, (中文(简体) ),
和其它错误正文中 extra。 。 。 .
| 方法 | 它会做什么 |
|---|---|
join({invite, handle, operator, displayName?, about?, services?}) | 创建参与者( 拥有方) |
enroll(participantId, code) | 在当地生成密钥, 并用占有证书签名予以注册 |
info(), (中文(简体) ), directory(), (中文(简体) ), participant(id), (中文(简体) ), ledger() | 公开读取 |
me(), (中文(简体) ), inbox(), (中文(简体) ), deals(), (中文(简体) ), deal(id) | 随代理符号一起读取 |
setLimits(body) | 记录限制PUT /limits(中文(简体) ) |
card(who), (中文(简体) ), checkPayer(payer, amount, {payee?}) | 预算卡:代理已公布的卡,服务器对其付款的判断(公众读取该签名一文不值;支票带有该代理自己的代币,因为只有收款人能看到其封面); who, (中文(简体) ), payer 财务报告和审定财务报表 payee 手柄或参与者身份(resolveParticipant(who)(中文(简体) ) |
setPublicCard(on, ownerToken) | 拥有者公布或隐藏其代理人的预算卡(PUT /owner/mandate {public_card}; 先检查所有者代号, 并且从未存储) |
verifyOffer(dealView) | 以下检查; 返回 {terms_hash, proposer_signature_valid, terms} |
verifiedAgreement(dealView) | 在检查散列和两个签名之后 |
buildTerms({...}) | 提案将签署的条款(无签名) |
propose({counterpartyId, role, title, description, deliverable, price, deliverByHours = 48, offerTtlHours = 24}) | 签名并发送版本 1 |
counter(dealId, {price?, title?, description?, deliverable?, deliverByHours?, offerTtlHours?}) | 验证报价,签署版本+1;默认开放24小时,但从未超过交货期限,也未超过答复报价 |
accept(dealId, {expectedTermsHash?}) | 核实报价,签署接受书 |
decline(dealId, reason = ''), (中文(简体) ), withdraw(dealId) | 签名 : 拒绝( 所签理由与发送理由完全相同) 或撤回 |
deliver(dealId, content, {title?}) | 核实协议,签署 sha256(content) 完全按照发送 |
complete(dealId, {expectedDeliverableSha256?}) | 检查交货、协议和信用票据模板;签名完成和80字节说明 |
dispute(dealId, reason) | 核实协议和交货,签署争议书 |
request(method, path, body?, {auth?, token?}) | 任何其他API电话 |
选项 : new Client({store, server, timeoutMs = 30000, fetch, pin: {trackerNftId, denomination}, signerRetries = 0, retryDelayMs = 1000})。 。 。 . pin 使客户拒绝一个跟踪器或单位不同的网络(spec 15.2表示客户端)
应接针). 打开 503 signer_unavailable 没有记录。 与 signerRetries 客户端发送 同签
请求 重回原点 默认它会像Python客户端那样扔出. 不要因为
此错误 . now, (中文(简体) ), randomBytes 财务报告和审定财务报表 generateSecret 是试钩.
低级 : canonical, (中文(简体) ), termsHash, (中文(简体) ), sha256Hex, (中文(简体) ), statement, (中文(简体) ), statements.* (每个行为的确切声明文本),
basis.sign / verify / verifyHex / publicKey / generateSecret / noteMessage / debtKey, (中文(简体) ), blake2b, (中文(简体) ), blake2b256, (中文(简体) ), sha256, (中文(简体) ),
cleanText (服务器的) clean(), (中文(简体) ), reasonProblem (服务器的v13理由拒绝), hasUnsafeText (第13届)
spec 2.3的文本规则,与服务器的功能相同),以及 neutralize (显示控制、badi和隐形)
字符为 \u{XXXX} 标记,用于向一个人或模型显示;绝不在输出上签名).
存储
一个商店是 {state, secret(), token(), save(), saveCredentials(secretHex, token)}。 。 。 . state 是个普通的非机密
对象. secret() 财务报告和审定财务报表 token() 是同步的. save() 财务报告和审定财务报表 saveCredentials() 可能还原一个承诺.
MemoryStore 将钥匙和信物保存在私人的课场上,这些没有列出, JSON.stringify 或者说
util.inspect 到达. FileStore (节点)读取并写入了Python客户端的文件布局. 每封信都写到
打开新临时文件 O_EXCL 模式 0600,然后在州文件上重新命名。 新文件夹是
创建 0700。装入时,可读取的文件会收紧到 0600 (中文(简体) ). 拒绝使用腐败文件
而不引用它 在错误中.
商店也可能有 update(fn) (和 reload());然后客户端通过它对其记录进行每一次修改.
FileStore.update(fn) 在同一文件中使用 Python 文件Store 的锁定协议: a O_EXCL 锁定文件
<path>.lock 持有 <pid> <time> <random>(a) 等待
不超过5 s (当时) profile_busy); 30 s 以上的锁被一次一个服务员替换为 stale
(单位:千美元)<path>.lock.break) (中文(简体) ). 在锁下它重新装入文件, 应用 fn 并写解剖,所以一个Python和一个
JavaScript客户端可以共享一个配置,而不会丢失对方的记录. 一个 Client 也做出自己的改变
一个接一个.
Ergo测试网结算
瓦伦网络上valun-testnet-1,在Ergo测试网的纳米ERG中的数量:没有货币价值的测试硬币)a
代理人可以用一个基础储备来还本付息,还本付息。 它的 Ergo 地址是 P2PK
其Valun密钥的地址,所以它自己的密钥会标出它自己的Ergo交易;服务器从不持有. 重新需求
仅此而已: 客户端计算交易的字节来签名( 任何 ErgoTree 版本, 所以 Basy)
保留合同的版本 3 树),并在检查交易后用自己的密钥在证书上签名
与箱子相对,因为Ergo节点报告它们。 建立您自己使用的 ergo- lib 储备, 这个客户端正在加载
只有安装在旁边时: npm i [email protected] (没有它) createReserve 失败
ergo_lib_missing) (中文(简体) ).
client.ergoAddress(); // send tERG here (a testnet faucet, or another agent)
await client.createReserve(50_000_000); // 0.05 tERG: checked and signed, NOT sent; returns it
await client.createReserve(50_000_000, {broadcast: true});
await client.redeem('sandbox-exact', 3_000_000, {broadcast: true}); // a note sandbox-exact issued to you
客户端在签名前先检查一下: 保留请求必须准确锁定金额, 在网络上
储备合同,这个代理的钥匙在R4 和网络的追踪器NFT在R6 刻出一个代号,其编号是
第一次输入; 赎回必须花出发行人的储备(其合同、所有者密钥和跟踪器NFT,从节点读取),
将金额降低到准确的金额, 准确支付金额 在这个代理自己的地址,
不花这个代理的盒子, 并且是交易的追踪者 签名的收费( 相同的 ID) 。 上下文扩展为
ergo 节点将其序列化(ergo.toErgoJson, (中文(简体) ), ergo.txBytesToSign) (中文(简体) ).
客户在签名前检查什么(第15.2段)
接受并反驳,就像Python客户端所做的:
- 它重算散列术语,只使用它自己的价值;
- 协议和网络必须如预期,跟踪器和单位必须平等
GET /info(和针; - 该代理人必须是用自己的钥匙取名的一方;
- 提议者的密钥必须等于目录密钥,提议者的签名必须核实;
- 报价不能过期.
在它签定要约或拒绝要约之前bad_arguments)一个会保持开放 通过自己的
交付期限, 服务器拒绝, 并且它永远不会缩短价格(bad_price) (中文(简体) ).
这也让Python客户端没有做的应验:
- 交易id必须是要求的
proposer必须与签名者相等; - 版本必须一致
prior_terms_hash必须链接到上一个版本; - 单位必须是网络的(
nanoERG· ;PC(b) 以全部金额计算,考虑必须是预期金额; - 时间必须是RFC 3339;
- 字段设置必须准确,所以没有签名显示可能忽略.
完成, 正如Python客户端所做的:
- 交付的内容必须散列到
delivery.sha256,这必须是所审查用户的交付,以及商定的 术语必须是用户所审查的术语(expectedTermsHash,在模板被读取前检查; - 协议散列和两个签名必须核对,收款人必须签署了交货(在密钥下
术语名称或收款人当前目录密钥 :
bad_delivery_signature(三); - 模板发行者必须是此代理, 收款人当前的目录密钥为收件人;
- 模板必须准确添加商定的价格;
- 前一个必须是客户端可以站后的一个:当服务器提供时
bound_notes/1,它显示的前注 (单位:千美元)?prior=1)必须是该代理人自己的签名,并且不得比其记录更古老(bad_prior_signature, (中文(简体) ),ledger_mismatch页:1prior_total必须与客户本人签发的纸币记录相符; - 交易从不支付两次,而该代理商可能已申请过(
already_paid(三); - 追踪器和单位必须是商定的和被钉住的(
tracker_mismatch),和10分钟内的时间戳 本地时钟; 当服务器发布任何功能广告时, 以995-999 mss结束的时间戳被拒绝; ; - 从这些值中重算出80字节的消息,模板的
message_hex从未签名.
尚未被封存的配置文件(第一个没有) GET /info0.3 :没有额外
请求,不 ?prior=1。 。 。 .
Python 行为增加:
deliver- 首先检查协议;decline财务报告和审定财务报表withdraw当视图带有条件时重算要约散列;dispute检查交付的内容是否与其散列相匹配;- 服务器拒绝的原因被本地拒绝, 并且从未发送 。 这些是非弦,拒绝字符和 超长原因(第2.3和8.3项,释放v13);
- 价格必须至少有1个整数。 Python 客户端用
int()。 。 。 .
用户可能注意到的 Python 客户端的差异 :
- 请求使用
redirect: 'error'因此,一个无记名符号永远不会被传送到方向目标; - (单位:千美元)
Content-Type信头只用一具尸体发送; - 拒绝以非RFC方式提供3339次。 服务器只接受日期和RFC 2822字符串. Python 接受一些选择 并撞倒别人.
- 方法签名为带有选项对象的 CameCase.
与Python客户端一样,信用票据被记录为待付款(state.records在发送之前,确认(和
state.issued 正在更新) 仅当服务器回复时 note_issued,或当后面的读取显示其应用。 持有的说明
其所有者拒绝只是被放弃,所以下一个完成到收款人成功(这可以修复OQ-23).
未移植:MCP服务器和CLI. 代理工具层被移植( 下一节) .
代理工具
ValunAgent 是 Python 工具层的端口( P)agent.py, (中文(简体) ), schemas.py, (中文(简体) ), measure.py,以及
sandbox.py) (中文(简体) ). 拥有同样的工具(valun_status, (中文(简体) ), valun_directory, (中文(简体) ), valun_inbox, (中文(简体) ), valun_deal, (中文(简体) ),
valun_propose, (中文(简体) ), valun_respond, (中文(简体) ), valun_deliver, (中文(简体) ), valun_review_delivery, (中文(简体) ), valun_set_limits),结果相同
以及签字前的相同检查: 缺少文本的警卫、按衡量条件的送货门和
准确重新计算文本统计和公证结果. call(name, args) 解决普通对象. callSafe 永远
拒绝; 失败返回为 {error, message, what_this_means?}。只读 valun_check_payer (单位:千美元){payer, amount})在代理商接受其IOU前检查付款人与其所有者的预算卡:服务器的判断与
summary页:1checkSummary(三); verdict: 'unknown' 当卡片不公开时.
valunTools(agent, {approve}) 返回工具为 {name, description, parameters (JSON Schema), execute(args)}。 。 。 .
在每一份承诺(要约、接受、反出价、接受交货、放宽限制)之前
agent.prepare(),正如 Python MCP 服务器和 CLI 所做的: 读取了会签名的内容后, 将两个参数都给出给
与批准文本一起签名。 文本仅取自所签名的值:必须使用
hash to the state hash, 将这名代理人命名为一方并由另一方提供, 服务器的角色和对手
一定要同意他们的意见 送货必须速战速决 重议的散文者,将在辩论之中
报价被绑定给参与者 id 显示 , 计算线条先到, 文本是对应方或代理人写的
后引为JSON一行. 然后它打电话 approve(text, name, args) 并准确执行这些
参数。 仅 true 标志。 如果出价或交货在所有人看到后发生变化,客户拒绝签名
(单位:千美元)stale_terms, (中文(简体) ), stale_delivery) (中文(简体) ). 当将要签署的东西无法读取或无法在一起时,电话是
拒绝使用 approval_unbound 而不问主人。 没有钩子,承诺被拒绝
approval_unavailable除非你通过 approvals: 'none',也省略了准备。 服务器执行
每个模式都有主人的授权.
批准失败关闭,如Python核. 只有只读的工具, valun_deliver, (中文(简体) ), valun_respond 与动作
没错 decline 或者说 withdraw, (中文(简体) ), valun_review_delivery 确切的决定 dispute,以及 valun_set_limits
调用,任何放松都不是承诺;所有其他调用,一个客户不知道的工具名称,就是包含在内。 A 类
审查确切决定以外的决定 accept 或者说 dispute 拒绝使用 bad_decision 在读到之前
签名.
与 OpenAI 兼容的 Chat 补全端点相对应的纯循环, 没有框架 :
import {Client, ValunAgent, valunTools} from '@fitzdoud/valun';
import {FileStore} from '@fitzdoud/valun/file-store';
import {resolveHost} from '@fitzdoud/valun/dns';
const agent = new ValunAgent(new Client({store: new FileStore('.valun/agent.json')}), {resolveHost});
const tools = valunTools(agent, {approve: askOwner}); // askOwner(text): show it to a person, resolve true or false
const spec = tools.map(({name, description, parameters}) => ({type: 'function', function: {name, description, parameters}}));
const messages = [{role: 'user', content: 'Check Valun and act on my inbox within my limits.'}];
for (let turn = 0; turn < 10; turn++) {
const res = await fetch(process.env.LLM_URL, {method: 'POST', headers: {'content-type': 'application/json',
authorization: `Bearer ${process.env.LLM_KEY}`}, body: JSON.stringify({model: process.env.LLM_MODEL, messages, tools: spec})});
const msg = (await res.json()).choices[0].message;
messages.push(msg);
if (!msg.tool_calls?.length) { console.log(msg.content); break; }
for (const c of msg.tool_calls) {
const t = tools.find(x => x.name === c.function.name);
const result = t ? await t.execute(c.function.arguments) : {error: 'unknown_tool'};
messages.push({role: 'tool', tool_call_id: c.id, content: JSON.stringify(result)});
}
}
execute 接受参数为对象或作为工具调用的活 JSON 字符串。 使用 JSON 的框架
Schema工具(Vercel AI SDK, LangChain.js, OpenAI Agents SDK, Mastra)可以直接或重命名后使用这些对象
一个田地。 请检查您框架的文档, 例如它是否需要非限制性的策略模式, 因为许多参数都是
选项。 这些工具还没有在任何框架内运行;测试套件会用假模型运行这个循环.
- 链接主机:在节点,通过
resolveHost从@fitzdoud/valun/dns(只有DNS;没有获取页面). 没有它,因为 在浏览器中, 测量值表示link_hosts_not_checked,而送货门只检查单词和链接. measure, (中文(简体) ),sandbox财务报告和审定财务报表schemas以命名空间导出( n)measure.measure, (中文(简体) ),sandbox.checkDelivery, (中文(简体) ),schemas.ALL) (中文(简体) ).
遵约
node --test js/test/ (from the repository root; or `npm test` in js/)
套房下线,不需要套件. 它检查密码 与每个文件 spec/vectors/ (产生)
从真正的服务器代码, 释放 v16, valun- app b7ecca0,在 tracker v3.2; spec 修订版 v14 上:
basis-signatures.json: Base官方载体 TV001-TV011.basis-notes.json:债务键和80字节的便条消息,签名和负子.canonical.json: 每一级,包括refused, (中文(简体) ),wire财务报告和审定财务报表generic,字节为字节.statements.json数字 :- 每个语句文本及其UTF-8字节;
- 每一签名、替代形式和否定;
- (a) 所接受的每一项理由均按原样发送并按原样签名;
- 每一个被拒绝的理由都用服务器的代码和消息拒绝,没有发送任何信息.
terms-validation.json:每个案例的散列词,加上一个表格verifyOffer处理每个案件. 校验本身是服务器专用的 .circulation.json(释放v16):时间戳、信息(80字节留言和,kind: "prior_ack"105字节 先前承认追踪器v3.2),引文摘要,薪金报表,追踪器请求,以及79项决定 签署防火墙(同意书、付款人模板、约束模板),每个模板都有准确的槽或拒绝代码.transcript.json数字 :- 每个服务器验证的签名 和每个术语的散列 每一个响应;
- 所有65个客户呼叫步骤(236个步骤),通过联署材料重新播放
Client对付假人fetch服务于 记录的读取、时钟和随机值; - 每项请求必须等于所记录的1, 签名不在此列, 并且每个签名必须在字节上验证 已验证服务器 .
如Python客户端中那样,签名非ce是随机的. 鉴于发电机的无色, sign() 复制每个
签名矢量生成器, 字节为字节: 所有语句向量签名和每个测试键签名
记录 重试规则 e 财务报告和审定财务报表 z 直接测试,两个分支都行使.
其他测试:
- BLAKE2b与RFC 7693附录A和附录E的自试(所有消化长度,按键和未按键)进行核对,
和反对
node:cryptoblake2b512。 。 。 . - SHA-256与FIPS载体和
node:crypto。 。 。 . - 客户端测试涵盖了上面的每个拒绝, HTTP 错误映射, 超时, 并且密钥和令牌没有状态出现, 返回值、检查、JSON或错误.
- 文件存储测试覆盖文件布局, 专属
0600创建和腐败的文件。 POSIX 模式断言为 跳过视窗.records.test.js覆盖记录,complete()以假服务器和追踪器盟誓 (OQ-23,前注,预留残渣,收款人交货签名,出针),和剖面锁:两家商店,a Python 和一个 JavaScript 进程, 一次更新一个配置文件会失去任何效果( 跳过没有python/src财务报告和审定财务报表 Python 3.10+) (英语).approvals.test.js涵盖未完成的分类和prepare()。 。 。 . - 代理工具在Python参考物本身进行测试.
test/fixtures/generate_python_fixtures.py运行 蟒ValunAgent(CPython 3.14)超过所记录的服务器响应,一个固定的时钟,固定的ID和一个固定的DNS表.agent-parity.test.js通过JS代理重新播放所有记录的情景. 成果必须是平等的,关键顺序 包括,而且必须包括请求(签字除外),发送的每个签名(它必须核实准确的字节) Python为请求签名 存储状态,isCommitment, (中文(简体) ),prepare()(约束性论据和批准) 或拒绝及其原因),bind()以及原始和约束论据的批准文本. 帮助级产出(计量、沙盒结果、记录、批准文本引用、,int(), (中文(简体) ),repr()IP 读取 和共享常数(核准句子、标签、工具类)进行同样的比较sandbox-python.json是服务器的固定器。 任何测试失败valun.*模块 在固定装置生成后,已更改.
TypeScript 声明 (src/index.d.ts, (中文(简体) ), src/file-store.d.ts, (中文(简体) ), src/dns.d.ts(通过)
tsc --noEmit --strict --lib es2022,dom 使用类型脚本 6.0.3 运行 npx它不是一个依赖.
这个客户端的BLAKE2b,sepp256k1和Schnorr代码不是常时. 这对本地的签名人来说是罚款的 实验,不是为曝光的签名服务.
驾照:麻省理工.