Renders the typed SDK a Code Mode program is written against.
Under mode: :code this text is the model's only declaration of the
tools — there is no native tool schema alongside it — which is what drives
every rule below.
Byte stability
Tools are sorted lexicographically by name and every map is walked in a
sorted order, so the same tool set renders to the same bytes on every call.
The SDK travels in the run_code tool's description, i.e. in the prompt
prefix of every request; an unstable ordering would invalidate the provider's
KV cache each turn and silently double the cost of a run. Assert
render(lang, tools) == render(lang, Enum.shuffle(tools)) when you change
anything here.
Total, never raising, on schemas
json_schema_to_type/2 is total over arbitrary input. Any node it cannot
express — a $ref it cannot resolve, an unknown type, a malformed map, a
nesting deeper than a dozen levels — becomes the language's escape hatch
(unknown for JS/TS, Any for Python). An exotic schema costs that node its
type; it must never cost the SDK its parseability, because a program written
against an unparseable SDK cannot call any tool at all.
Addressing
tools is an object/mapping indexed by each tool's exact name, so
tools["my-tool"](args) works with no alias table and no name mangling.
Names are emitted as JSON string literals, which are valid string literals in
both target languages.
Languages
:javascript and :typescript render the same TypeScript declaration —
under JavaScript it is read as documentation, not executed. :python renders
a stub module. Structural fidelity differs by language and that is deliberate:
Python has no intersection type and no anonymous nested record type, so
allOf and nested objects degrade there while JS/TS keeps them.
Summary
Types
A language this generator can render. Providers report their language as a
string via Nous.CodeRuntime.language/1; both forms are accepted.
Functions
Resolve a language given as an atom or a string.
The exception class name the SDK tells the program to expect from a failed
call. Bindings carry the same name in Nous.CodeRuntime.Binding.error_class.
The type a node gets when the generator cannot express it.
The name of the global the program calls tools through.
Convert one JSON Schema node to a language type expression.
Every language render/2 can generate.
Render the SDK declaring tools.
Types
@type language() :: :javascript | :typescript | :python
A language this generator can render. Providers report their language as a
string via Nous.CodeRuntime.language/1; both forms are accepted.
Functions
Resolve a language given as an atom or a string.
Returns :error rather than raising, so a caller holding a language it read
from provider configuration can fall back instead of failing a run.
Examples
iex> Nous.CodeMode.Sdk.coerce_language("typescript")
{:ok, :typescript}
iex> Nous.CodeMode.Sdk.coerce_language(:ruby)
:error
@spec error_class() :: String.t()
The exception class name the SDK tells the program to expect from a failed
call. Bindings carry the same name in Nous.CodeRuntime.Binding.error_class.
The type a node gets when the generator cannot express it.
Examples
iex> Nous.CodeMode.Sdk.escape_hatch(:typescript)
"unknown"
iex> Nous.CodeMode.Sdk.escape_hatch(:python)
"Any"
@spec global() :: String.t()
The name of the global the program calls tools through.
The bindings a provider is handed must use this same global, or the SDK describes something the program cannot reach.
Convert one JSON Schema node to a language type expression.
Total: any node the generator cannot express returns escape_hatch/1 rather
than raising. Accepts string- or atom-keyed schema maps.
Examples
iex> Nous.CodeMode.Sdk.json_schema_to_type(:typescript, %{"type" => "integer"})
"number"
iex> Nous.CodeMode.Sdk.json_schema_to_type(:python, %{"type" => "array"})
"list[Any]"
iex> Nous.CodeMode.Sdk.json_schema_to_type(:typescript, %{"$ref" => "#/definitions/x"})
"unknown"
@spec languages() :: [language()]
Every language render/2 can generate.
@spec render(language() | String.t(), [Nous.Tool.t()]) :: String.t()
Render the SDK declaring tools.
Tools are deduplicated by name (first occurrence wins, matching the runner's own lookup) and sorted lexicographically, so output depends on the tool set, never on the order it arrived in.
Raises ArgumentError for a language this generator does not know; that is
provider configuration, not model input.
Examples
iex> tool = %Nous.Tool{
...> name: "greet",
...> description: "Say hi",
...> function: fn _ctx, _args -> {:ok, "hi"} end,
...> parameters: %{
...> "type" => "object",
...> "properties" => %{"name" => %{"type" => "string"}},
...> "required" => ["name"]
...> }
...> }
iex> sdk = Nous.CodeMode.Sdk.render("javascript", [tool])
iex> sdk =~ ~s|"greet"(args: {|
true