@tyrpay/seller-skill
v0.1.10
Published
LLM-callable seller-side tools for the TyrPay Phase 1 protocol.
Readme
@tyrpay/seller-skill
LLM-callable seller-side tools for the TyrPay Phase 1 protocol.
This package wraps a configured SellerAgent plus a readable settlement
contract into structured tool definitions that an agent can execute directly.
What This Package Exports
createSellerTools(config): returns six seller-side toolsSellerSkillToolError: structured error class withcode,field,suggestion,retryableSellerTool: the shared tool shape used by this packageReadableContractLike: the read/write contract interface expected by the toolsSellerSkillConfig: configuration shape forcreateSellerTools
Tool names:
tyrpay_readytyrpay_discover_model_endpointtyrpay_accept_tasktyrpay_execute_tasktyrpay_submit_prooftyrpay_check_settlement
Installation
pnpm add @tyrpay/seller-skill @tyrpay/seller-sdk @tyrpay/storage-adapter @tyrpay/zktls-adapterThis package assumes you already have a configured SellerAgent.
End-to-End Flow
Typical seller-side flow:
- Call
tyrpay_readyto verify signer access and storage adapter connectivity. - Receive a
taskIdfrom the buyer through your own application or messaging layer. - For 0G TeeTLS/TeeML execution, call
tyrpay_discover_model_endpointwith the target model and use the recommended endpoint in the commitment. - Call
tyrpay_accept_taskto build and submit the execution commitment. - Wait for the buyer to validate that commitment and fund the task.
Poll with
tyrpay_check_settlementuntil status isREADY_TO_EXECUTE. - Read the funded task from the settlement contract and obtain its
taskNonce. - Call
tyrpay_execute_taskonce per proved upstream API call. - Keep each returned receipt.
- Call
tyrpay_submit_proofwith the commitment and collected receipts. - Use
tyrpay_check_settlementto monitor whether the verifier settled or refunded the task.
When using 0G TeeTLS, the commitment target and model must describe the actual 0G TeeTLS request the adapter will make. Do not commit to a generic upstream OpenAI endpoint or a preferred model name unless that is the endpoint/model resolved from 0G TeeTLS service metadata.
seller-skill does not discover tasks, coordinate with the buyer, or operate a
verifier. Those responsibilities stay outside this package.
Prerequisites
Before calling createSellerTools, prepare:
- a seller wallet signer connected to a provider
- the TyrPay settlement contract address
- the target chain ID
- a storage adapter
- a zkTLS adapter
- a contract instance that supports:
submitCommitmentsubmitProofBundlegetTask
- the registry-authorized verifier signer address that should be embedded into commitments
Contract ABI compatibility
The contract passed to createSellerTools must use an ABI that matches the
deployed TyrPaySettlement contract. In particular, getTask(bytes32) must
return the current Task struct in this exact order:
taskId, taskNonce, buyer, seller, token, amount, deadlineMs,
requiredMinUsage, requiredModelsHash, commitmentHash, commitmentURI,
fundedAtMs, proofBundleHash, proofBundleURI, proofSubmittedAtMs,
reportHash, settledAtMs, refundedAtMs, statusUse this ABI fragment when constructing an ethers contract for seller-skill:
const TyrPaySettlementAbi = [
"function submitCommitment(bytes32 taskId,bytes32 commitmentHash,string commitmentURI,uint256 commitmentMinUsage,string[] commitmentModels)",
"function submitProofBundle(bytes32 taskId,bytes32 proofBundleHash,string proofBundleURI)",
"function getTask(bytes32 taskId) view returns ((bytes32 taskId, bytes32 taskNonce, address buyer, address seller, address token, uint256 amount, uint256 deadlineMs, uint256 requiredMinUsage, bytes32 requiredModelsHash, bytes32 commitmentHash, string commitmentURI, uint256 fundedAtMs, bytes32 proofBundleHash, string proofBundleURI, uint256 proofSubmittedAtMs, bytes32 reportHash, uint256 settledAtMs, uint256 refundedAtMs, uint8 status))"
];If an older ABI has deadline instead of deadlineMs, omits taskNonce, or
orders commitmentHash before deadlineMs, ethers can still return a value but
seller-skill will read the wrong field names. Typical symptoms are:
tyrpay_check_settlementreports an impossible status.tyrpay_accept_taskreads the wrong buyer or seller.tyrpay_execute_taskcannot derive the expected task context.- Receipt
taskContext.commitmentHashdoes not match the commitment used later.
Do not rely on positional array indexes from getTask() unless you map them to
the field names above before passing the contract into seller-skill.
Minimal SellerAgent setup:
import { SellerAgent } from "@tyrpay/seller-sdk";
import { MemoryStorageAdapter } from "@tyrpay/storage-adapter";
import { ReclaimZkTlsAdapter } from "@tyrpay/zktls-adapter";
const agent = new SellerAgent({
signer,
settlementContract,
chainId,
storageAdapter: new MemoryStorageAdapter(), // local tests only
zkTlsAdapter: new ReclaimZkTlsAdapter({
appId: process.env.RECLAIM_APP_ID,
appSecret: process.env.RECLAIM_APP_SECRET
})
});Environment Variables
seller-skill itself does not read environment variables, but constructing the full
seller stack requires the following values. The table groups them by component.
Settlement chain & wallet
| Variable | Required | Description |
|---|---|---|
| ZERO_G_EVM_RPC | yes | EVM RPC endpoint for the settlement chain; also used by the 0G storage adapter |
| SELLER_PRIVATE_KEY | yes | Private key of the seller wallet; used to sign on-chain transactions |
| CHAIN_ID | yes | Settlement chain ID (must match the RPC endpoint) |
| SETTLEMENT_CONTRACT | yes | Address of the deployed TyrPay settlement contract |
0G storage adapter (production)
Required if using ZeroGStorageAdapter. Omit if using MemoryStorageAdapter (testing only).
| Variable | Required | Description |
|---|---|---|
| ZERO_G_INDEXER_RPC | yes | 0G indexer endpoint for storage reads |
| ZERO_G_STORAGE_PRIVATE_KEY | yes | Private key for uploading proofs and receipts to 0G storage |
MemoryStorageAdapter returns memory://... URIs. Those URIs are valid only
inside the same JavaScript process that wrote the object. They must not be used
for a task that the buyer, verifier, or another agent process needs to read.
For real settlement flows, use persistent shared storage such as
ZeroGStorageAdapter or another adapter that returns retrievable 0g://,
ipfs://, or https:// URIs.
Reclaim zkTLS adapter (production)
Required if using ReclaimZkTlsAdapter. Omit if using MockZkTlsAdapter (testing only).
Install these optional peer dependencies in the runtime that constructs
ReclaimZkTlsAdapter:
pnpm add @reclaimprotocol/zk-fetch @reclaimprotocol/js-sdk| Variable | Required | Description |
|---|---|---|
| RECLAIM_APP_ID | yes | Reclaim protocol application ID |
| RECLAIM_APP_SECRET | yes | Reclaim protocol application secret |
Upstream API key (runtime)
Passed at call time through providerOptions.privateOptions.headers, not in constructor config.
The key name depends on the upstream service being proven.
| Variable | Required | Description |
|---|---|---|
| OPENAI_API_KEY | example | Bearer token for the upstream API (OpenAI shown as an example) |
Optional
| Variable | Default | Description |
|---|---|---|
| tyrpay_E2E_TIMING | unset | Set to "1" to enable end-to-end timing logs in SellerAgent.provenFetch() |
Basic Usage
Raw tool definitions
import { createSellerTools } from "@tyrpay/seller-skill";
const tools = createSellerTools({
agent,
contract,
verifierSignerAddress
});verifierSignerAddress is the address that signs VerificationReport objects
and is authorized by VerifierRegistry. It is not the settlement contract
address, verifier registry contract address, verifier service URL, or a verifier
service contract address. The legacy config field verifier is still accepted
for compatibility, but it has the same signer-address meaning.
Each returned tool has:
namedescriptioninputSchemaexecute(input)
Claude-style tool format
const claudeTools = createSellerTools({
agent,
contract,
verifierSignerAddress
}).map((tool) => ({
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema
}));OpenAI-style tool format
const openAITools = createSellerTools({
agent,
contract,
verifierSignerAddress
}).map((tool) => ({
type: "function",
function: {
name: tool.name,
description: tool.description,
parameters: tool.inputSchema
}
}));Executing a returned tool call
const tools = createSellerTools({
agent,
contract,
verifierSignerAddress
});
const acceptTask = tools.find((entry) => entry.name === "tyrpay_accept_task");
if (!acceptTask) {
throw new Error("seller tool not found");
}
const accepted = await acceptTask.execute({
taskId: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
host: "api.openai.com",
path: "/v1/chat/completions",
method: "POST",
allowedModels: ["gpt-4o-mini"],
minTotalTokens: 500,
deadline: "1760000000000"
});For provider "0g-teetls", call tyrpay_discover_model_endpoint first when
you only know the desired model. Use the recommended endpoint's host, path,
method, and model in tyrpay_accept_task, then pass its providerOptions
to tyrpay_execute_task. host and path must be the actual 0G endpoint,
method must be POST, and allowedModels must include the 0G service
metadata model that execution will declare.
Error Handling
All tools wrap errors in SellerSkillToolError, which provides structured fields:
code: one ofVALIDATION_ERROR,CONFIGURATION_ERROR,NETWORK_ERROR,TIMEOUT,UNKNOWN_ERRORmessage: human-readable error descriptionfield: the input field that caused the error (for validation errors)received: the actual value that was rejectedsuggestion: guidance on how to fix the errorretryable: whether the operation can be retriedcauseName: the underlying error class name
import { SellerSkillToolError } from "@tyrpay/seller-skill";
try {
await acceptTask.execute({ taskId: "bad-id" });
} catch (error) {
if (error instanceof SellerSkillToolError) {
console.log(error.code); // "VALIDATION_ERROR"
console.log(error.field); // "taskId"
console.log(error.suggestion); // "Fix the tool arguments and try again."
console.log(error.retryable); // false
}
}Tool Semantics
tyrpay_ready
Lightweight readiness check that verifies the seller signer is reachable.
Call this before the first task workflow to fail fast on misconfiguration.
Returns:
ok: alwaystrueon successsignerAddress: the seller's wallet addressuserStatus:READYuserMessage: confirmation that signer is reachable
tyrpay_discover_model_endpoint
Discovers reachable TeeTLS/TeeML endpoints for a requested model.
Use this before tyrpay_accept_task when the seller intends to execute through
provider "0g-teetls" but only has a model name.
Returns:
endpoints: all matching discovered endpoints up tolimitrecommended: the first endpoint to use, ornullwhen none are foundhost,path,method,model: values to pass intotyrpay_accept_taskproviderOptions: values to pass intotyrpay_execute_taskuserStatus:ENDPOINT_READYorNO_ENDPOINT_FOUND
tyrpay_accept_task
Builds the ExecutionCommitment, uploads it through the configured storage
adapter, and submits its hash/URI on-chain.
Call this after the buyer has shared a taskId.
Returns:
txHash: transaction hash forsubmitCommitmenttaskId: task identifier bound into the commitmentcommitmentHash: hash of the submitted commitmentcommitmentURI: storage URI of the submitted commitmentcommitment: the fully constructedExecutionCommitmentobjectuserStatus: currentlyWAITING_FOR_BUYER_FUNDINGuserMessage: seller-facing explanation of what happens next
tyrpay_execute_task
Runs one zkTLS-proven upstream API call using the supplied commitment, request, task nonce, and declared model.
Returns:
receipt: normalizedDeliveryReceiptreceiptURI: storage URI for the receipt objectreceiptHash: canonical hash of the receipt objectrawProofURI: storage URI for the raw provider proofrawProofHash: canonical hash of the raw provider proofuserStatus: currentlyPROOF_CAPTUREDuserMessage: seller-facing explanation to submit proof next
tyrpay_submit_proof
Builds a ProofBundle from one or more receipts, uploads it, and submits the
resulting proof bundle hash on-chain.
Returns:
txHash: transaction hash forsubmitProofBundletaskId: task identifier for the submitted proof bundleproofBundleHash: submitted proof bundle hashproofBundleURI: storage URI for the submitted proof bundleuserStatus: currentlyAWAITING_VERIFICATIONuserMessage: seller-facing explanation that payout now depends on verification
tyrpay_check_settlement
Reads task settlement status from the contract.
Seller-facing statuses currently exposed:
READY_TO_ACCEPTWAITING_FOR_BUYER_FUNDINGREADY_TO_EXECUTEAWAITING_VERIFICATIONPAIDNOT_PAID_REFUNDED
Returns:
taskId: queried task identifierstatus: current on-chain task statussettled: whether the task reachedSETTLEDrefunded: whether the task reachedREFUNDEDproofSubmittedAt: proof submission timestamp if presentproofBundleHash: submitted proof bundle hash if presentproofBundleURI: submitted proof bundle URI if presentsettledAt: settlement timestamp if presentrefundedAt: refund timestamp if presentreportHash: verifier report hash if presentuserStatus: simplified seller-facing payout statususerMessage: short explanation of the current stage
Notes For Agent Authors
taskNoncefortyrpay_execute_taskcomes from the on-chain task record.- The
commitmentpassed totyrpay_execute_taskandtyrpay_submit_proofmust be the exact object returned bytyrpay_accept_taskor fetched from the submittedcommitmentURI. It cannot be reconstructed fromgetTask()alone. declaredModelmust be included incommitment.allowedModels.request.host,request.path, andrequest.methodmust match the commitment target exactly.- For 0G TeeTLS, the commitment target/model must be the actual endpoint/model resolved by the 0G TeeTLS adapter. Committing to a different upstream endpoint or model will fail execution or verification.
- All tool inputs are validated at runtime before any SDK or on-chain calls.
Troubleshooting Seller Skill Runs
Seller address matches, buyer funded, task exists, but tool state is wrong
Check the ABI used to construct the readable settlement contract. The current
seller-skill expects named getTask() fields matching the contract struct order
listed in Contract ABI compatibility. A stale ABI
can make task.seller, task.commitmentHash, task.status, or timestamp
fields point at the wrong return slot.
Quick checks:
- Confirm the deployed contract is the current
TyrPaySettlement.sol. - Confirm the ABI contains
taskNonceand usesdeadlineMs,fundedAtMs,proofSubmittedAtMs,settledAtMs, andrefundedAtMs. - Log the raw
getTask(taskId)result and compare both named fields and numeric indexes against the expected order.
memory:// storage is rejected or cannot be read
memory:// is not a portable storage URI. It only works when every participant
uses the same in-memory adapter instance in the same process. A buyer SDK,
verifier service, or separate seller agent cannot retrieve it. Use 0G/IPFS/HTTP
storage before writing hashes and URIs that other parties must verify.
Commitment hash mismatch
commitmentHash is the canonical hash of the full ExecutionCommitment, not a
hash derived from the on-chain task fields. The full object includes target
host/path/method, allowed models, min usage, verifier, seller, buyer, deadline,
schema version, and task id. Any missing field, case difference, changed model
list order, timestamp change, or different canonical JSON payload changes the
hash.
To recover:
- Read
commitmentHashandcommitmentURIfromgetTask(taskId). - Fetch the full commitment object from
commitmentURIusing the same storage adapter family that wrote it. - Recompute
hashExecutionCommitment(commitment). - Continue only if the recomputed hash equals the on-chain
commitmentHash.
If the original commitment was written to memory:// by another process, it is
not recoverable from chain data alone. The buyer or seller process that created
the task must provide the original commitment object or submit a new task.
Reclaim zkTLS dependency or proof generation failure
ReclaimZkTlsAdapter dynamically imports @reclaimprotocol/zk-fetch at
runtime. Real Reclaim proofs require the package, @reclaimprotocol/js-sdk,
valid RECLAIM_APP_ID and RECLAIM_APP_SECRET, and downloaded zk resources:
node node_modules/@reclaimprotocol/zk-fetch/scripts/download-files.jsOn Windows, Reclaim TEE mode is not supported by @reclaimprotocol/zk-fetch;
keep useTee unset or false. If the package cannot be installed in the
current runtime, seller-skill cannot produce a real Reclaim zkTLS proof. Use
MockZkTlsAdapter only for local tests, or switch to a runtime where Reclaim
dependencies install and initialize successfully.
Related Packages
@tyrpay/seller-sdk: proof generation, bundle assembly, and on-chain seller flow@tyrpay/agent-kit: prebuilt Claude/OpenAI wrappers if you do not want to map the tool shape yourself
