Cyclium.Synthesizer.Interactive.LLM behaviour (Cyclium v0.2.0)

Copy Markdown View Source

Behaviour for LLM clients used by the Interactive synthesizer.

chat/3 is the text contract: the model replies with a JSON ActionPlan envelope as text, which the synthesizer parses.

chat_with_native_tools/4 is the optional native contract: tool signatures are passed to the provider as structured tools, and the model replies with validated tool_use blocks instead of a text envelope — removing the whole class of text-parse failures (smart quotes, dotted names, over-structured values). The synthesizer uses the native path by default whenever the configured client exports chat_with_native_tools/4; an actor opts out with strategy_config: %{tool_mode: :text}, and a client that doesn't implement the callback falls back to the text path automatically. Return shape:

{:ok, %{
  tool_calls: [%{name: "tool__action", input: %{...}}],  # [] if none
  text: "assistant prose, if any",
  model: "model-id",   # optional
  usage: %{...}        # optional
}}

Summary

Callbacks

chat(system_prompt, user_message, opts)

@callback chat(system_prompt :: String.t(), user_message :: String.t(), opts :: keyword()) ::
  {:ok, String.t()} | {:error, :no_api_key} | {:error, {atom(), term()}}

chat_with_native_tools(system_prompt, user_message, tools, opts)

(optional)
@callback chat_with_native_tools(
  system_prompt :: String.t(),
  user_message :: String.t(),
  tools :: [map()],
  opts :: keyword()
) :: {:ok, map()} | {:error, :no_api_key} | {:error, {atom(), term()}}