rubenglez

Langdrift

Locale-aware evals for AI agents

TypeScriptAI agentsEvals

View on GitHub ↗

Agents that work perfectly in English often quietly degrade in other languages: same intent, different words, different behavior. Langdrift asks one question: does your agent still choose the right tool, with the right arguments, when the same request arrives in French, Arabic, Chinese, Basque, or Swahili? It checks behavior, not fluency; there is no LLM-as-judge in the core loop, so every failure is deterministic and explainable.

You can see the failure mode in 30 seconds without an API key. The repo ships a fake agent that intentionally drops tool calls for Swahili and Chinese:

Locale  Passed  Failure       Detail
en      1/1     -             create_refund_ticket
sw      0/1     no_tool_call  expected create_refund_ticket, got no tool calls
zh      0/1     no_tool_call  expected create_refund_ticket, got no tool calls

Result: failed, 2 of 12 locales failed

For your own agent, install the CLI (Node >= 24, zero runtime dependencies) and run it against your endpoint:

npm install -g langdrift
langdrift run ./my-scenario.yaml --target http://localhost:3010/api/agent

Scenarios are plain YAML. Argument assertions accept oneOf lists for canonical values, and responseLanguage verifies the reply’s script, useful for catching agents that fall back to English:

id: refund_request
agent: support

locales:
  en:
    input: "I was charged twice for my subscription"
    expect:
      toolCall:
        name: create_refund_ticket
        arguments:
          reason: duplicate_charge
  fr:
    input: "J'ai été facturé deux fois"
    expect:
      toolCall:
        name: create_refund_ticket
      responseLanguage: fr

This is not hypothetical. In the included benchmark, the same locale weaknesses recurred across three independently trained models: prompts in Basque, Yoruba, Swahili, Chinese, Welsh, and Mongolian triggered missing tool calls or wrong arguments where English passed. The full methodology, results, and limitations are in the repo’s RESEARCH.md.

01

Write a scenario

One YAML file per intent, with per-locale inputs and the tool calls you expect. langdrift init generates a starter from templates, and langdrift translate uses an LLM to draft the other locales for you.

02

Point it at your agent

Langdrift POSTs each locale's input to any HTTP endpoint and reads back text and tool calls. No SDK, no framework lock-in; if your agent can answer one request, it can be tested.

03

Read the drift report

Every locale gets a pass or fail with a classified failure mode, so you see what broke, not just that something did. Output as a terminal table, JSON, or a markdown table for PR comments.

04

Gate your CI

Exits non-zero on failure. Use --min-pass-rate to set a threshold, --allow-fail to keep reporting a known weak locale without blocking the build, and --iterations to smooth out flaky runs.

Failure modes

Failure modeWhat it means
no_tool_callThe agent stopped calling tools in that locale
wrong_toolSame intent, different tool selected
wrong_argumentRight tool, wrong argument value
missing_argumentAn expected argument never arrived
forbidden_toolA tool that should never fire, fired
wrong_sequenceTool calls happened in the wrong order
wrong_languageThe reply came back in the wrong script
A langdrift run in the terminal showing a per-locale results table — English, French and other locales pass while Arabic, Chinese and Swahili fail with wrong_argument and no_tool_call classifications, ending in a failed result