fix: restore precision in tool descriptions and design-doc caveats after the voice pass

This commit is contained in:
FilipBl4gojevic
2026-08-01 10:31:18 +02:00
parent 864d363aaa
commit 1f4a7030b5
5 changed files with 12 additions and 11 deletions

View File

@@ -119,7 +119,7 @@ interface Policy {
`vector_signer_decode_transaction` is a read-only preview so an agent can show a human what it is about to sign.
**Accepted trade-off of the 4-call shape:** the signer records **intent to spend** at signing time, not confirmed submission. If a submit later fails, the audit log over-counts. Conservative, therefore acceptable, and it is the price of the signer having no network access.
**Accepted trade-off of the 4-call shape:** the signer records **intent to spend** at signing time, not confirmed submission. If a submit later fails, the audit log over-counts. Conservative, therefore acceptable, and it is the price of the signer having no network access. This trade-off is documented.
### Two-step self-improvement flow
@@ -250,7 +250,7 @@ CI only runs `npm run build`, and `tsup`/esbuild strips types without checking t
**Native-asset outflow is not limited in v1.** Spend limits apply to lovelace. A transaction moving ~2 AP3X plus a valuable NFT to a foreign address passes the lovelace check. Blanket-denying asset outflow is not viable because legitimate registry flows mint an NFT to the registry script address.
v1 mitigation: all asset movements are decoded, logged, and returned in the policy decision, and `assetOutflowPolicy` is configurable (`allow` default | `deny` | `allowlist`) for high-value wallets. Post-v1: per-policy asset rules.
v1 mitigation: all asset movements are decoded, logged, and returned in the policy decision, and `assetOutflowPolicy` is configurable (`allow` default | `deny` | `allowlist`) for high-value wallets. **This is a stated limitation.** Post-v1: per-policy asset rules.
**Key at rest is plaintext in v1** (env var or `0600` file). The win is that the key is *local and never transits the LLM or a shared host*, not that it is in an HSM. `KeySource` exists so keychain/HSM/hardware land later without touching the sign path.

View File

@@ -230,7 +230,7 @@ Non-custodial flow: 1) sign locally with vector_signer_sign { txCbor } - your ke
"vector_build_send_tokens",
"Build an UNSIGNED transaction sending Vector native tokens. Takes no key material - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
{
changeAddress: z.string().describe("Your wallet address (holds the AP3X; receives change). Get it from your local signer's vector_signer_get_address."),
changeAddress: z.string().describe("Your wallet address (holds the AP3X and tokens; receives change). Get it from your local signer's vector_signer_get_address."),
recipientAddress: z.string().describe("Recipient Vector address (addr1...)"),
policyId: z.string().describe("Token policy ID (56 hex characters)"),
assetName: z.string().describe("Asset name (text or hex; can be empty for policy-only tokens)"),
@@ -287,7 +287,7 @@ Non-custodial flow: 1) sign locally with vector_signer_sign { txCbor }; 2) broad
"vector_build_transaction",
"Build an UNSIGNED multi-output transaction with optional metadata. Takes no key material and never submits - sign the returned CBOR with your local signer (vector_signer_sign), then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
{
changeAddress: z.string().describe("Your wallet address (holds the AP3X; receives change). Get it from your local signer's vector_signer_get_address."),
changeAddress: z.string().describe("Your wallet address (supplies the inputs; receives change). Get it from your local signer's vector_signer_get_address."),
outputs: z.array(z.object({
address: z.string().describe("Recipient Vector address"),
lovelace: z.number().describe("Amount in lovelace (1 AP3X = 1,000,000 lovelace)"),
@@ -659,7 +659,7 @@ Sign locally with vector_signer_sign, broadcast with vector_submit_transaction,
"vector_build_interact_contract",
"Build an UNSIGNED transaction interacting with a deployed Plutus/Aiken contract - lock AP3X at it or spend from it. Takes no key material - sign with your local signer, then broadcast with vector_submit_transaction and confirm with vector_await_transaction.",
{
changeAddress: z.string().describe("Your wallet address (holds the AP3X, receives change, and is the required signer for spends). Get it from your local signer's vector_signer_get_address."),
changeAddress: z.string().describe("Your wallet address (supplies the inputs, receives change, and is the required signer for spends). Get it from your local signer's vector_signer_get_address."),
scriptCbor: z.string().describe("Compiled Plutus/Aiken script in CBOR hex"),
scriptType: z.enum(["PlutusV1", "PlutusV2", "PlutusV3"]).describe("Script version"),
action: z.enum(["spend", "lock"]).describe("'spend' to collect UTxOs from the script, 'lock' to send AP3X to it"),

View File

@@ -52,7 +52,7 @@ describe('buildMultiOutput', () => {
});
describe('buildDeployContract', () => {
test('locks funds at the derived script address with an inline datum', async () => {
test('locks AP3X at the derived script address with an inline datum', async () => {
const r = await buildDeployContract(lucid, {
scriptCbor: ALWAYS_SUCCEEDS_V2, scriptType: 'PlutusV2', lovelaceAmount: 2_000_000,
});

View File

@@ -87,7 +87,7 @@
"type": "object",
"properties": {
"changeAddress": {
"description": "Your wallet address (holds the AP3X, receives change, and is the required signer for spends). Get it from your local signer's vector_signer_get_address.",
"description": "Your wallet address (supplies the inputs, receives change, and is the required signer for spends). Get it from your local signer's vector_signer_get_address.",
"type": "string"
},
"scriptCbor": {
@@ -494,7 +494,7 @@
"type": "object",
"properties": {
"changeAddress": {
"description": "Your wallet address (holds the AP3X; receives change). Get it from your local signer's vector_signer_get_address.",
"description": "Your wallet address (holds the AP3X and tokens; receives change). Get it from your local signer's vector_signer_get_address.",
"type": "string"
},
"recipientAddress": {
@@ -534,7 +534,7 @@
"type": "object",
"properties": {
"changeAddress": {
"description": "Your wallet address (holds the AP3X; receives change). Get it from your local signer's vector_signer_get_address.",
"description": "Your wallet address (supplies the inputs; receives change). Get it from your local signer's vector_signer_get_address.",
"type": "string"
},
"outputs": {

View File

@@ -126,8 +126,9 @@ over-counts, which refuses too much rather than too little.
today's spend, which quietly raises the effective daily limit. The practical effect: if the
audit log's directory disappears, the disk fills, or the path loses write permission, every
`vector_signer_sign` call starts returning `REFUSED`, including transactions well inside
policy, until it is writable again. That refusal names the audit failure explicitly, unlike
an ordinary policy refusal. Signing stops outright until the log is writable again.
policy, until it is writable again. That refusal names the audit failure explicitly rather
than reading like an ordinary policy refusal, but it is still a full stop on signing, not a
warning.
- **The key is plaintext at rest** in v1 (env var or file). The win is that it is *local*
and never transits your model provider or a shared host, not that it is in an HSM.
`KeySource` exists so keychain and hardware backends can be added without touching the