Two lines. Provely finds your framework and fixes the failure itself.
Malformed JSON, an invented tool, a hung call, a payment made twice: one deterministic check for each failure, and an automatic fix. It works beside the defences you already wrote.
typescript/weather-repaired.ts+28 lines of code by hand
importOpenAIfrom'openai';
const getWeather = ({ city }: { city: string }) => `Sunny in ${city}`;
const parameters = { type: 'object', properties: { city: { type: 'string' } } };
function repairJson(text: string): string {
// the model may wrap the JSON in a Markdown fenceconst fence = text.trim().match(/^```(?:json)?\s*([\s\S]*?)\s*```$/);
const source = fence ? fence[1]! : text;
let out = '';
let quote: string | null = null;
for (let i = 0; i < source.length; i += 1) {
const char = source[i]!;
if (quote === null) {
// the model may use single quotes: every string gets double quotesif (char === "'" || char === '"') quote = char;
out += quote === null ? char : '"';
} elseif (char === '\\') {
// an escaped single quote is not valid JSON: keep the quote, drop the backslashconst next = source[i + 1] ?? '';
out += next === "'" ? "'" : char + next;
i += 1;
} elseif (char === quote) {
quote = null;
out += '"';
} else {
// a double quote inside a single-quoted string must be escaped out += char === '"' ? '\\"' : char;
}
}
return out;
}
const reply = awaitnewOpenAI().chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'What is the weather in Paris?' }],
tools: [{ type: 'function', function: { name: 'get_weather', parameters } }],
});
const call = reply.choices[0]!.message.tool_calls![0]!;
// the model may send arguments that are not JSON: tell the user, do not crashtry {
console.log(getWeather(JSON.parse(repairJson(call.function.arguments))));
} catch (error) {
console.log(`Could not read the tool arguments: ${(error as Error).message}`);
}
$ node weather.ts
SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
exit 1
Failed. The model writes the arguments of get_weather with single quotes, so they are not JSON.
$ node weather-repaired.ts
Sunny in Paris
exit 0
Fixed by hand, for 2 kinds of fault.
$ node weather.ts
Sunny in Paris
exit 0
Auto fixed by Provelyrepair_in_place · single_quoted_strings · get_weather
Lines of code: 0 → breaks · 5 → caught, no answer · 28 → fixes 2 kinds of fault · 2 → Provely's checks
A hand-written fix of these faults adds 34 lines with its comments, 28 lines of code. The counts come from a line diff of the recorded files, 2026-10-17.
real framework apps, one fix at a time
The same app, without Provely and with it.
Each fix ran twice: once with no Provely line, and once with the two lines. Pick your framework to see the code you know.
The same file with Provely · ts/langchain · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
// LangChain `createAgent` over the real OpenAI client class.//// The developer writes the agent and two Provely lines: one import and one instance. The// runner removes the two lines for the control run, and no other line names Provely.
The model sendsrefund_charge(```json
{"charge": "ch_1051", "amount": 4200, "reason": "duplicate",}
```)
Without Provely
refunds that ran: 0
final answer: (none)
exit 0
Failed. The refund never ran, and the agent gave no answer.
The check that failedthe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · strip_code_fence, remove_trailing_commas · refund_charge
A hung tool, bounded
LangChain · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
answered; the runner ended it
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
A duplicate refund, refused: the money moves once
LangChain · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
A repeat after a 502, refused
LangChain · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
An invented amount, refused under enforce
LangChain · TypeScript · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · py/langchain · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
"""LangChain`create_agent` over the real OpenAI client class.The developer writes the agent and two Provely lines: one importand one instance. Therunner removes the two lines for the control run, and no other line names Provely."""
model = ChatOpenAI( model=app.MODEL, api_key=app.API_KEY, base_url=f"{app.MODEL_URL}/v1", max_retries=0, timeout=app.CODE_TIMEOUT_S,)
agent = create_agent(model, tools=[refund_charge, get_charge], system_prompt=app.PROMPT)for _run in range(app.INVOCATIONS): state = app.invoke(lambda: agent.invoke({"messages": [{"role": "user", "content": app.ASK}]}))app.finish(state["messages"][-1].content)
Malformed JSON, repaired in place
LangChain · Python
The model sendsrefund_charge(```json
{"charge": "ch_1051", "amount": 4200, "reason": "duplicate",}
```)
Without Provely
refunds that ran: 0
final answer: (none)
exit 0
Failed. The refund never ran, and the agent gave no answer.
The check that failedthe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · strip_code_fence, remove_trailing_commas · refund_charge
A hung tool, bounded
LangChain · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
answered; the runner ended it
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
An invented amount, refused under enforce
LangChain · Python · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · ts/llamaindex · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
// The LlamaIndex `agent` workflow over the real OpenAI client class.//// The developer writes the agent and two Provely lines: one import and one instance. The// runner removes the two lines for the control run, and no other line names Provely.
const workflow = agent({ tools: [refund, lookup], llm, systemPrompt: app.prompt });let result;for (let run = 0; run < app.invocations; run += 1) result = await app.invoke(() => workflow.run(app.ask));app.finish(String(result.data?.result ?? ''));
Malformed JSON, repaired in place
LlamaIndex · TypeScript
The model sendsrefund_charge(```json
{"charge": "ch_1051", "amount": 4200, "reason": "duplicate",}
```)
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: SyntaxError: Unexpected token '`', "```jsonthe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · strip_code_fence, remove_trailing_commas · refund_charge
A wrong tool name, renamed
LlamaIndex · TypeScript
The model sendsRefund_Charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: Error: Tools not found: Refund_Chargethe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (Refund_Charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · tool_name_case · Refund_Charge
A schema error, returned to the model and fixed
LlamaIndex · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran with no amount, and the call needs one.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · arguments_schema_mismatch · refund_charge
A hung tool, bounded
LlamaIndex · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
answered; the runner ended it
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
A duplicate refund, refused: the money moves once
LlamaIndex · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
A repeat after a 502, refused
LlamaIndex · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
An invented amount, refused under enforce
LlamaIndex · TypeScript · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · ts/openai-chat · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
// A plain tool loop over the OpenAI Chat Completions client.//// The developer writes the loop and two Provely lines: one import and one instance. The// loop holds no defensive code: no parse guard, no tool-name check, and no catch. The// runner removes the two Provely lines for the control run.
importOpenAIfrom'openai';import * as app from'./common.mjs';import { Provely } from'@provely/sdk';newProvely();
/** One invocation of the agent: one conversation with the model. */asyncfunction converse() {const messages = [ { role: 'system', content: app.prompt }, { role: 'user', content: app.ask }, ];let final = null;for (let turn = 0; turn < 6 && final === null; turn += 1) {const completion = await client.chat.completions.create({ model: app.modelName, messages, tools: [app.tool, app.readTool].map((item) => ({ type: 'function', function: item })), });const message = completion.choices[0].message; messages.push(message);if (!message.tool_calls?.length) final = message.content;for (const call of message.tool_calls ?? []) {const output = await handlers[call.function.name](JSON.parse(call.function.arguments)); messages.push({ role: 'tool', tool_call_id: call.id, content: JSON.stringify(output) }); } }return final;}let final = null;for (let run = 0; run < app.invocations; run += 1) final = await app.invoke(converse);app.finish(final);
Malformed JSON, repaired in place
OpenAI SDK, no framework · TypeScript
The model sendsrefund_charge(```json
{"charge": "ch_1051", "amount": 4200, "reason": "duplicate",}
```)
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: SyntaxError: Unexpected token '`', "```jsonthe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · strip_code_fence, remove_trailing_commas · refund_charge
A wrong tool name, renamed
OpenAI SDK, no framework · TypeScript
The model sendsRefund_Charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: TypeError: handlers[call.function.name] is not a functionthe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (Refund_Charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · tool_name_case · Refund_Charge
A schema error, returned to the model and fixed
OpenAI SDK, no framework · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran with no amount, and the call needs one.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · arguments_schema_mismatch · refund_charge
A duplicate refund, refused: the money moves once
OpenAI SDK, no framework · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
An invented amount, refused under enforce
OpenAI SDK, no framework · TypeScript · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · py/openai-chat · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
"""A plain tool loop over the OpenAIChatCompletions client.The developer writes the loop and two Provely lines: one importand one instance. The loopholds no defensive code: no parse guard, no tool-name check, and no catch. The runnerremoves the two Provely lines for the control run."""
import jsonfrom openai importOpenAIimport common as appfrom provely importProvelyProvely()
def converse():"""One invocation of the agent: one conversation with the model.""" messages = [{"role": "system", "content": app.PROMPT}, {"role": "user", "content": app.ASK}]for _turn in range(6): completion = client.chat.completions.create(model=app.MODEL, messages=messages, tools=tools) message = completion.choices[0].message messages.append(message.model_dump(exclude_none=True))ifnot message.tool_calls:return message.contentfor call in message.tool_calls: output = handlers[call.function.name](**json.loads(call.function.arguments)) messages.append( {"role": "tool", "tool_call_id": call.id, "content": json.dumps(output)} )returnNonefinal = Nonefor _run in range(app.INVOCATIONS): final = app.invoke(converse)app.finish(final)
Malformed JSON, repaired in place
OpenAI SDK, no framework · Python
The model sendsrefund_charge(```json
{"charge": "ch_1051", "amount": 4200, "reason": "duplicate",}
```)
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)the tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · strip_code_fence, remove_trailing_commas · refund_charge
A wrong tool name, renamed
OpenAI SDK, no framework · Python
The model sendsRefund_Charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: KeyError: 'Refund_Charge'the tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (Refund_Charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · tool_name_case · Refund_Charge
A schema error, returned to the model and fixed
OpenAI SDK, no framework · Python
The model sendsrefund_charge({"charge": "ch_1051", "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: TypeError: refund() missing 1 required positional argument: 'amount'the tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · arguments_schema_mismatch · refund_charge
A duplicate refund, refused: the money moves once
OpenAI SDK, no framework · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
An invented amount, refused under enforce
OpenAI SDK, no framework · Python · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · ts/openai-agents · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
// The OpenAI Agents `Agent` over the real Responses API client.//// The developer writes the agent and two Provely lines: one import and one instance. The// runner removes the two lines for the control run, and no other line names Provely.
The model sendsRefund_Charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: ModelBehaviorError: Tool Refund_Charge not found in agent refunds.the tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (Refund_Charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · tool_name_case · Refund_Charge
A hung tool, bounded
OpenAI Agents · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
answered; the runner ended it
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
A duplicate refund, refused: the money moves once
OpenAI Agents · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
A repeat after a 502, refused
OpenAI Agents · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
An invented amount, refused under enforce
OpenAI Agents · TypeScript · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · py/openai-agents · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
"""TheOpenAIAgents`Agent` over the real ResponsesAPI client.The developer writes the agent and two Provely lines: one importand one instance. Therunner removes the two lines for the control run, and no other line names Provely."""
The model sendsRefund_Charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: agents.exceptions.ModelBehaviorError: Tool Refund_Charge not found in agent refundsthe tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model received no result for call_0_0 (Refund_Charge)
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrepair_in_place · tool_name_case · Refund_Charge
A hung tool, bounded
OpenAI Agents · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
answered; the runner ended it
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
A duplicate refund, refused: the money moves once
OpenAI Agents · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
A repeat after a 502, refused
OpenAI Agents · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
An invented amount, refused under enforce
OpenAI Agents · Python · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · py/llamaindex · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
"""TheLlamaIndex`FunctionAgent` over the real OpenAI client class.The developer writes the agent and two Provely lines: one importand one instance. Therunner removes the two lines for the control run, and no other line names Provely."""
import asyncioimport jsonfrom llama_index.core.agent.workflow importFunctionAgentfrom llama_index.core.tools importFunctionToolfrom llama_index.llms.openai importOpenAIimport common as appfrom provely importProvelyProvely()def refund_charge(charge: str, amount: float, reason: app.Reason) -> str:"""Refund a charge."""return json.dumps(app.refund(charge, amount, reason))def get_charge(charge: str) -> str:"""Read a charge."""return json.dumps(app.read(charge))asyncdef main() -> None:# A workflow binds to the running event loop, so the agent is built inside it.
llm=llm, system_prompt=app.PROMPT, ) result = Nonefor _run in range(app.INVOCATIONS): result = await app.invoke_async(lambda: agent.run(user_msg=app.ASK)) app.finish(result)asyncio.run(main())
A hung tool, bounded
LlamaIndex · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
A duplicate refund, refused: the money moves once
LlamaIndex · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
A repeat after a 502, refused
LlamaIndex · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
An invented amount, refused under enforce
LlamaIndex · Python · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
A cut stream, asked again
LlamaIndex · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 0
final answer: (none)
exit 1
Failed. The app crashed with exit code 1.
The check that failedthe app stopped with exit code 1: httpcore.RemoteProtocolError: peer closed connection without sending complete message body (incomplete chunked read)the tool moved money 0 time(s) with [], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · stream_ended_without_success · refund_charge
The same file with Provely · ts/vercel-ai-stream · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
// The Vercel AI SDK `streamText` over the real OpenAI client class.//// The developer writes the agent and two Provely lines: one import and one instance. The// runner removes the two lines for the control run, and no other line names Provely.
let text = '';for (let run = 0; run < app.invocations; run += 1) { text = await app.invoke(async () => {let answer = '';forawait (const delta of streamText(options).textStream) answer += delta;return answer; });}app.finish(text);
A hung tool, bounded
Vercel AI · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: (none)
still running at the bound
Failed. The tool never answered, and the run never ended.
The check that failedthe run did not end within 20 sthe model received no result for call_0_0 (refund_charge)
With Provely
refunds that ran: 1
final answer: I will check the refund later.
answered; the runner ended it
Auto fixed by Provelyreturn_error_to_model · tool_timed_out · refund_charge
A duplicate refund, refused: the money moves once
Vercel AI · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · write_already_completed · refund_charge
A repeat after a 502, refused
Vercel AI · TypeScript
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"}) refund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
An invented amount, refused under enforce
Vercel AI · TypeScript · with guard_mode enforce, which is not the default
The model sendsrefund_charge({"charge": "ch_1051", "amount": 9900, "reason": "duplicate"})
Without Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Failed. The refund ran for 9900, and the person asked for 4200.
The check that failedthe tool moved money 1 time(s) with [{"charge":"ch_1051","amount":9900,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the model read a success for call_0_0, a call that must not succeed
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyrefuse · argument_model_invented · refund_charge
The same file with Provely · ts/langchain · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
// LangChain `createAgent` with the defences of a developer.//// The developer wrote the defences below. Each one is a toggle: `ZC_DEFENCES` names the// defences that are on (`all` by default). The two Provely lines are the same as in// `apps/`, and the runner removes them for the defended control. `app.handled` counts each// run of a handler for property C4; it is test instrumentation, not a defence.//// - tool_try: the tool catches its own error and answers the error text.// - tool_error: `toolErrorMiddleware` turns a tool error into an error message.// - model_retry: `modelRetryMiddleware` retries a failed model call one time.// - tool_retry: `toolRetryMiddleware` re-runs a failed tool call up to two times.// - call_limit (opt-in): `toolCallLimitMiddleware` lets the refund run one time per run.// - client_retry: the chat client retries one time, with a timeout of 10 s.// - recursion_limit: the run stops after ZC_MAX_TURNS turns, when the case sets it.// - abort_timeout: an abort signal stops the run after ZC_ABORT_MS, when the case sets it.// - idem_key: the tool sends its own idempotency key to the provider.
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the decision log names no line for call_0_0
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
The same file with Provely · py/langchain · the page shows the Provely import above the Provely call, and moves no other line
The comment at the top of the file
"""LangChain`create_agent`with the defences of a developer.The developer wrote the defences below. Each one is a toggle: `ZC_DEFENCES` names the defencesthat are on (`all` by default). The two Provely lines are the same asin`apps/py`, and therunner removes them for the defended control. `app.handled` counts each run of a handler forproperty C4; it is test instrumentation, not a defence.- tool_try: the tool catches its own error and answers the error text.- validation_error: `handle_validation_error` answers a bad argument object with a text.- tool_error: `ToolErrorMiddleware` turns a tool error into an error message.- tool_retry: `ToolRetryMiddleware` runs a failed tool one more time.- model_retry: `ModelRetryMiddleware` retries a failed model call one time.- fallback: `ModelFallbackMiddleware` asks a second model when the first one fails.- call_limit: `ModelCallLimitMiddleware`and`ToolCallLimitMiddleware` bound the run.- client_retry: the chat client retries one time, with a timeout of 10 s.- recursion_limit: the graph stops after 12 steps, or after ZC_MAX_TURNS turns.- idem_key: the tool sends its own idempotency key to the provider."""
import jsonfrom langchain.agents import create_agentfrom langchain.agents.middleware import (ModelCallLimitMiddleware,ModelFallbackMiddleware,ModelRetryMiddleware,ToolCallLimitMiddleware,ToolErrorMiddleware,ToolRetryMiddleware,)from langchain_core.tools import toolfrom langchain_openai importChatOpenAIimport common as appfrom provely importProvelyProvely()def _validation_error(error: Exception) -> str: app.handled("validation_error", error)return f"Error: the arguments are not valid ({type(error).__name__})."@tool(app.TOOL_NAME, description=app.TOOL_DESCRIPTION)def refund_charge(charge: str, amount: float, reason: app.Reason) -> str: key = f"refund-{charge}-{amount}"if app.defended("idem_key") elseNoneifnot app.defended("tool_try"):return json.dumps(app.refund(charge, amount, reason, key))try:return json.dumps(app.refund(charge, amount, reason, key))exceptExceptionas error: app.handled("tool_try", error)return f"Error: {error}"if app.defended("validation_error"): refund_charge.handle_validation_error = _validation_error@tool(app.READ_TOOL_NAME, description=app.READ_TOOL_DESCRIPTION)def get_charge(charge: str) -> str:return json.dumps(app.read(charge))def _model(retries: int) -> ChatOpenAI:returnChatOpenAI( model=app.MODEL, api_key=app.API_KEY, base_url=f"{app.MODEL_URL}/v1", max_retries=retries,# A timeout that the agent code states wins. Else the client retry sets 10 s. timeout=app.CODE_TIMEOUT_Sor (10if app.defended("client_retry") elseNone), )def _tool_error(error: Exception) -> str: app.handled("tool_error", error)return f"Error: {type(error).__name__}"model = _model(1if app.defended("client_retry") else0)
agent = create_agent( model, tools=[refund_charge, get_charge], system_prompt=app.PROMPT, middleware=middleware)# Two graph steps make one turn: the model, then the tools. A case can set the turn limit.limit = 12if app.MAX_TURNSisNoneelse2 * app.MAX_TURNSconfig = {"recursion_limit": limit} if app.defended("recursion_limit") else {}for _run in range(app.INVOCATIONS): state = app.invoke(lambda: agent.invoke({"messages": [{"role": "user", "content": app.ASK}]}, config=config) )app.finish(state["messages"][-1].content)
Provely works beside your own defences
LangChain · Python
The model sendsrefund_charge({"charge": "ch_1051", "amount": 4200, "reason": "duplicate"})
Without Provely
refunds that ran: 2
final answer: The refund is done.
exit 0
Failed. The refund ran 2 times, and the person asked for 1.
The check that failedthe tool moved money 2 time(s) with [{"charge":"ch_1051","amount":4200,"reason":"duplicate"},{"charge":"ch_1051","amount":4200,"reason":"duplicate"}], and the case permits [{"charge":"ch_1051","amount":4200,"reason":"duplicate"}]the decision log names no line for call_0_0
With Provely
refunds that ran: 1
final answer: The refund is done.
exit 0
Auto fixed by Provelyreturn_error_to_model · tool_raised · refund_chargerefuse · repeat_of_unknown_write · refund_charge
# 1. With access, install the SDK package that your access names.$ npm install <the SDK package of your access>
# 2. Set your API key. Make it at app.provely.sh/account/api-keys, or run provely login once on your machine.$export PROVELY_API_KEY=…
# 3. Add the two Provely lines to your agent, then run it.$ node agent.mjs
# 4. Optional: see what Provely fixed. Each decision is a line in the local log.$ tail -n 1 .provely/decisions.jsonl
{"call_id":"call_0_0","tool":"refund_charge","decision":"repair_in_place","check":"fm.argument_repair@1.0.0","code":"arguments_unparseable","rules":["single_quoted_strings"]}
Get your API key: sign in at app.provely.sh/account/api-keys, open API keys, and create a key. The dashboard shows the key once. Keep it in an environment variable, never in code. Or run provely login once on your machine: the SDKs then read the key that it stores.
works beside your own defences
Keep the defences you wrote.
Your retries, validators, guardrails and timeouts stay. Six properties state how Provely works beside them, and the grid tests each one on every path.
C1 · Clean runs do not changeC2 · Never worseC3 · One decision for each callC4 · Your handler still runsC5 · The stricter choice winsC6 · No loop
TypeScript: 21 of 27 (rules cases not yet measured) cases hold every property on 9 paths (measured 2026-10-17). Python: 24 of 27 (1 passes under guard_mode: enforce; observe records only; rules cases not yet measured) cases hold every property on 6 paths (measured 2026-10-17).