feat(tools): typed Phone + Voice tools — fixes agent discovery for phone/voice#58
Merged
Conversation
…etc.)
Phone and voice were previously only reachable via the generic `blockrun`
primitive — the agent had to know to POST /v1/phone/numbers/list or
/v1/voice/call by string and hand-craft the body shape. In practice this
meant models either (1) refused outright because no tool's name pattern-
matched "make a phone call", or (2) tried to discover the schema by
GETing /.well-known/x402 — which currently omits phone/voice — and
concluded the endpoints don't exist.
This adds 8 typed tools wrapping the same endpoints, named to match
intent:
ListPhoneNumbers — $0.001 POST /v1/phone/numbers/list
BuyPhoneNumber — $5 POST /v1/phone/numbers/buy
RenewPhoneNumber — $5 POST /v1/phone/numbers/renew
ReleasePhoneNumber — free POST /v1/phone/numbers/release
PhoneLookup — $0.01 POST /v1/phone/lookup
PhoneFraudCheck — $0.05 POST /v1/phone/lookup/fraud
VoiceCall — $0.54 POST /v1/voice/call (Bland.ai)
VoiceStatus — free GET /v1/voice/call/{id}
Each spec.description spells out the use case, cost, and required fields
explicitly (incl. that VoiceCall needs a wallet-owned `from` number from
BuyPhoneNumber first). This matches the existing ImageGen/VideoGen/
ExaSearch/SearchX pattern — agents grep tool names and select on the
first hit instead of opening discovery manifests.
x402 payment flow mirrors src/tools/exa.ts (Base + Solana). VoiceStatus
is the only GET, and it's free — no payment signing path.
Repro for the discovery failure mode this fixes:
1. User: "list my BlockRun phone numbers"
2. Opus 4.7 with old tool list: calls blockrun → real number returned
3. User: "now call +1..."
4. Opus loses tool_result to compaction, distrusts memory, GETs
/.well-known/x402, doesn't see phone, retracts the earlier answer.
With this PR Opus picks VoiceCall by name in step 3, never opens the
discovery manifest, and the conversation flows naturally.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phone and voice endpoints were previously only reachable via the generic `blockrun` primitive — the agent had to know to POST `/v1/phone/numbers/list` or `/v1/voice/call` by string and hand-craft the body shape. In practice this meant:
This PR adds 8 typed tools wrapping the same `/v1/phone/` and `/v1/voice/` endpoints, named to match user intent — same pattern as `ImageGen` / `VideoGen` / `ExaSearch` / `SearchX`.
New tools
Each `spec.description` spells out cost, use case, required fields, and the Buy-number-first requirement for `VoiceCall`. Same x402 payment flow as `src/tools/exa.ts` (Base + Solana). `VoiceStatus` is the only GET, free — no payment signing path.
Repro this fixes
Verified end-to-end today with Opus 4.7 in Franklin agent:
```
Turn 1: "list my BlockRun phone numbers"
→ blockrun POST /v1/phone/numbers/list → real number, real tx hash
Turn 2: "now call +1 213-361-0872"
→ tool_result from turn 1 was already cleared by microCompact
→ Opus distrusts its own memory, GETs /.well-known/x402 to verify
→ manifest doesn't list phone (gateway bug, separate PR)
→ Opus concludes earlier success was hallucination, retracts
```
With this PR Opus picks `VoiceCall` from the tool list in turn 2 (name match → "call"), never opens discovery, dials directly.
Tests
`npm test` — all 399 tests pass. `npm run build` clean.
No new tests added — the tools are thin wrappers around the same x402 path that `exa` / `blockrun` tools already use, covered by their existing test suites.
Related
🤖 Generated with Claude Code