DEV Community

anusha
anusha

Posted on

I Built an Agent That Can Decide When to Text You or Call You

I wanted a simple way to show what LLM tool calling looks like when the tools are real communication actions.

Not a weather lookup. Not a calculator.

Something you can feel immediately from your phone.

The Telnyx code example is here:

https://github.com/team-telnyx/telnyx-code-examples/tree/main/agent-with-tool-calling

The result is an agent that can read a normal message like:

Text +13125550001 I am running five minutes late
Enter fullscreen mode Exit fullscreen mode

and decide to call the SMS tool.

Or:

Call me at +13125550001
Enter fullscreen mode Exit fullscreen mode

and decide to call the voice tool.

The Idea

Most demos make the user choose the action first.

Click this button to send a text. Click that button to place a call. Pick a workflow. Fill in a form.

This sample flips that around.

The user writes what they want. The model reads the request, chooses one of the allowed tools, extracts the phone number and message body, and the application executes the action through Telnyx.

The approved tools are:

  • send_sms
  • make_call
  • check_status

The model does not get to run arbitrary code. It gets a small, explicit set of tools with JSON schemas.

The Full Loop

The important part is that tool calling is a loop, not a single model response.

The flow is:

user message
  -> model receives tool definitions
  -> model returns a tool call
  -> app executes the selected tool
  -> app appends the tool result with the same toolCallId
  -> model sees the tool result
  -> model writes the final response
Enter fullscreen mode Exit fullscreen mode

That last model pass matters. The tool result is structured data. The final assistant response is the human-readable summary.

So if the model chooses send_sms, the app sends the SMS first. Then the model gets the result and can say what happened in a clean sentence.

Why I Like This Example

It makes tool calling concrete.

You can inspect the code and see the exact line where Telnyx Inference is called:

this.env.TELNYX.ai.openai.chat.createCompletion()
Enter fullscreen mode Exit fullscreen mode

You can inspect the SMS dispatch:

this.env.TELNYX.messages.send()
Enter fullscreen mode Exit fullscreen mode

You can inspect the voice dispatch:

this.env.TELNYX.calls.dial()
Enter fullscreen mode Exit fullscreen mode

And you can inspect the ledger that records each tool call and its toolCallId.

That makes the demo much easier to trust. If something happens, you can trace it.

What The Agent Remembers

The sample runs on Telnyx Edge Compute with the Agent SDK.

The ToolAgent keeps conversation history and records tool activity. That means a user can ask a follow-up like:

Did the SMS send?
Enter fullscreen mode Exit fullscreen mode

The model can choose check_status, and the app can look up the latest send_sms event in the local ledger.

That is a useful pattern for real workflows. Users ask follow-up questions. They do not always phrase the second message with all the context from the first one.

The Phone Is The Interface

The fun part of this sample is that the phone becomes the proof.

When the agent sends an SMS, the recipient sees the message.

When the agent places a call, the phone rings.

That makes it different from a lot of LLM demos. You are not just watching a terminal print JSON. You are watching a model choose an action that reaches a real person through a real communications channel.

Running It

Start with the code sample:

git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/agent-with-tool-calling
npm install
Enter fullscreen mode Exit fullscreen mode

Run:

npm run typecheck
npm run types
npm run ship
Enter fullscreen mode Exit fullscreen mode

Then configure your Telnyx number, Messaging Profile webhook, Call Control application, and Edge function settings.

Try:

Text +13125550001 meet me at the front desk
Call me at +13125550001
Did the SMS send?
Enter fullscreen mode Exit fullscreen mode

The Pattern To Reuse

This is the shape I would reuse for a lot of communication workflows:

  • let the LLM classify intent
  • keep the tool surface small
  • validate phone numbers before dispatch
  • execute tools exactly once
  • store a ledger
  • pass the tool result back to the model
  • return a short final answer

That gives you the flexibility of natural language with the control of normal application code.

Resources

Top comments (0)