Tool: it hands the framework an argument schema and a coroutine, and execution stays in Charter.
That means tools stay built once. The credential lookup happens below every adapter, so serving many users works unchanged whichever one you use — or none.
OpenAI
openai_tools.py
Tool.to_json_schema produces — so this needs no extra. The same output works anywhere the OpenAI tool format is accepted.
LangChain
langchain_tools.py
StructuredTool per tool, whose args_schema is the Charter LLM view (Tool.llm_schema) and whose coroutine is Tool.ainvoke. LangChain supplies the calling convention; it does not touch serialization, casing, or field policy.
Validation failures surface the way LangChain expects, so a model that sends a malformed argument gets a message it can act on rather than a stack trace. See tool validation and error handling.
This one needs the extra:
Sending schemas on demand
AToolSession sends the schemas of the tools the model has reached for, plus a ToolSearch that loads the rest, so Gmail and Stripe together cost 563 tokens on the first turn instead of 15,661.
Its tool list grows, which means the loop has to rebuild that list every turn. Charter ships the loop rather than asking you to remember:
Tool.ainvoke exactly as a statically bound tool would be. A loaded tool is the same fully typed tool it would have been.
to_openai_tools and to_langchain_tools both accept a session too, if you own your loop and want to drive the projection yourself. See run and CharterMiddleware.
Serving over the Model Context Protocol is a compile target rather than an adapter, and has its own page.
Related
Tool— the object every adapter projectsTool.llm_schemaandTool.to_json_schema— the two views an adapter hands overTool.ainvoke— the coroutine they wrap