DEV Community

Cover image for How Rewire built a voice agent that rewrites itself after every wrong answer
Praise James for Actian for Developers

Posted on Originally published at actian.com

How Rewire built a voice agent that rewrites itself after every wrong answer

This article was originally published on the Actian blog. The build was first submitted to the Self-Evolving Agents Hackathon.

This post breaks down Rewire, a voice agent system that repairs its own workflow after a wrong answer. It traces the failure to the node responsible, generates competing fixes, replays past calls to reject any fix that breaks something, and stores the survivor in Actian VectorAI DB. You'll see the memory commit code, the failure signature that makes fixes reusable, and three patterns to apply in your own agents.

The headline result came from two unrelated agents. An auto-servicing agent fabricated a brake price, and Rewire fixed it. Later, a healthcare agent fabricated a $40 insurance copay against a verified $47, retrieved that brake-pricing fix, and corrected the copay on its first try. Builder Aayush Gupta summed up the approach. "We wrote the fitness function. It wrote the rules."

The results

Metric Value
Candidate fixes per generation 3, each from a different mutation operator
Candidates generated across the run 33
Candidates rejected by the validator 27
Cross-domain transfer Brake-pricing fix corrected a $40 copay to the verified $47

Why prompt engineering falls short

Patching a prompt by hand fixes one instance. The same mistake can show up in another workflow, and you write the patch again there.

Prompts also change behavior probabilistically. Telling an agent to look up an approved price doesn't guarantee it calls the lookup tool. RAG improves what gets retrieved, and Rewire targets the instruction or routing that failed to trigger retrieval at all. In Gupta's words, "Nobody touches a prompt."

How the loop is wired

Rewire self-evolving architecture

  • Dograh orchestrates and versions the conversation flow.
  • Pioneer serves inference through an OpenAI-compatible endpoint running gpt-5.4-mini. Each call returns the node, instructions, tools, tool calls, and transitions.
  • Senso returns the verified answer with a citation. SensoOracle compares the agent's response against it and returns a verdict with a correctness score, groundedness, the ground-truth value, the failure type, diagnostic reasoning, and an escalation result.
  • The validator traces the root node, generates patches, replays them against history, and updates the live graph.
  • VectorAI DB stores domain-free failure signatures with their patches.

In the brake-pricing failure, the agent had the knowledge-base tool available and never called it. Senso supplied the verified price.

1. Trace the failure to its root node

Rewire follows Dograh's node_transition events and execution history to find the node that caused the failure. That can differ from the node that spoke the wrong answer.

2. Generate competing fixes

The failure signature picks from four bounded mutation operators.

Operator What it changes
append_constraint Adds a constraint to the node's existing instruction
add_tool_requirement Requires a specific tool call under a defined condition
rewrite_instruction Replaces the node's instructions
change_transition Changes graph routing

Each generation produces three candidates from structurally different operators. For the brake price, the winner was add_tool_requirement, which made pricing_lookup call the knowledge base before quoting any specific price.

3. Kill fixes by replay

A Guild-hosted validator applies each candidate to a local copy of the workflow and replays historical calls. A candidate survives only if it fixes the failure without breaking behavior that was already correct. The survivor with the highest validation confidence goes live. Across the run, 27 of 33 candidates didn't survive.

4. Commit the fix to VectorAI DB

The vector comes from the failure signature, which records the node's role, the failure type, whether a retrieval tool was available, whether it was invoked, and whether the agent asserted a specific value. The caller's words and domain terms stay out.

def to_embedding_text(self) -> str:
    """The ONLY text that may be embedded into `signature_vector`.

    Deliberately reads as structured English rather than a token soup:
    we want semantically *near* signatures (same failure type, same role,
    differing only in whether a tool existed) to land near each other in
    vector space, which a bag of flags would not achieve.

    Note what is absent: the utterance, the ground truth, the vertical,
    the node id, the product. If you are tempted to add any of them here
    to improve retrieval precision, that is the transfer beat dying.
    """
    return (
        f"A {self.node_role.value} node produced a {self.failure_type.value} failure. "
        f"A retrieval tool was {'available' if self.tool_available else 'not available'} "
        f"and was {'invoked' if self.tool_invoked else 'not invoked'}. "
        f"The agent {'asserted a specific factual value' if self.asserted_specific_value else 'did not assert a specific value'}."
    )
Enter fullscreen mode Exit fullscreen mode

That method, from the project's repo, builds the only text that gets embedded. The store() method commits a validated patch.

def store(self, patch: WorkflowPatch) -> str:
    """Embed the patch's failure signature, upsert with its flat payload.

    Returns the Actian point id (a uuid5 of `patch.patch_id`, so this is a
    true upsert — storing the same patch twice after validation flips it
    from candidate to promoted in place rather than duplicating it).
    """
    self._require_ready()
    vector = embed(patch.signature.to_embedding_text())
    pid = point_id_for(patch.patch_id)
    self.client.points.upsert(
        self.collection,
        [PointStruct(id=pid, vector=vector, payload=patch.to_actian_payload())],
    )
    return pid
Enter fullscreen mode Exit fullscreen mode

store() embeds the signature text into a 384-dimensional vector and derives a deterministic point ID from the patch ID with uuid5. Because the ID is stable, storing the same patch again after validation updates the existing point from candidate to promoted, so no duplicate appears.

Why the healthcare agent matched

The copay failure and the brake failure share a shape. In both, the agent asserted a specific value while a verification tool sat unused. With domain words left out of the embedding, that shape is all VectorAI DB compares. Gupta said the healthcare agent "matched purely on the shape of the failure, and fixed a fabricated insurance copay first try."

The retrieved fix still went through validation before touching the healthcare graph.

Three patterns to reuse

Pattern What Rewire did What you implement
Index by shape Encoded failure signatures from structural properties and stored them in VectorAI DB without domain content Define a normalized failure schema describing how the agent failed, then embed it
Eliminate by replay Tested generated and retrieved fixes against the triggering failure and historical calls, promoting only fixes with no regressions Apply each candidate to the current workflow, replay representative cases, and promote only after a regression gate
Let the agent write the rules Let the agent propose graph updates within bounded mutation operators, then validated the result Constrain the operators, let the agent propose rules, and let execution-based validation pick survivors

Embed only the failure representation you want reused. Full conversations bring in domain vocabulary that narrows matches to one vertical.

Wrapping up

Rewire records how a failure happened, keeps only fixes that pass replay, and stores them where any agent can find them by shape. That's how a fix written for brake prices ended up correcting an insurance copay.

What's next

Top comments (0)