//! `public.zig` — the sole exported root of `libpanto`. //! //! This file is the **explicit public API allowlist**. Internal modules keep //! their `pub` declarations (needed for cross-file linking) but are never //! re-exported here; the public surface is what this file names, not //! "whatever happens to be `pub`." //! //! The surface is organized around two user jobs (see //! `docs/libpanto-cleanup.md`): //! 1. Run an agent loop — configure a provider, register tools, submit a //! turn, consume the pull event stream, persist. //! 2. Construct & operate on conversations — build a `Conversation` by //! hand, do context-management surgery. //! //! Every name here is a straight alias of an internal decl: the internal //! types have been shaped to *be* the public API (public methods + a //! transparent public field or two, every other field underscore-prefixed //! internal state), so this file selects the surface rather than wrapping //! it. Three buckets: //! - **behavioral** (`Agent`, `Stream`, `Conversation`): heap-pinned //! drivers whose `init` hands back a cheap, movable pointer; the chosen //! methods plus a transparent field (`Agent.conversation`, //! `Stream.state`) are the surface. //! - **data (read/output)** (`Event`, `Usage`, `Pricing`, `SessionInfo`): //! inspected field-by-field. //! - **data (constructed)** (`ContentBlock`, `Message`, the block types, //! the `Config` family): Zig users build them with `ArrayList` directly. const std = @import("std"); const config_mod = @import("config.zig"); const auth_mod = @import("auth.zig"); const conversation_mod = @import("conversation.zig"); const agent_mod = @import("agent.zig"); const stream_mod = @import("stream.zig"); const provider_mod = @import("provider.zig"); const tool_mod = @import("tool.zig"); const tool_source_mod = @import("tool_source.zig"); const pricing_mod = @import("pricing.zig"); const session_store_mod = @import("session_store.zig"); const fs_store_mod = @import("file_system_jsonl_store.zig"); const null_store_mod = @import("null_store.zig"); // =========================================================================== // Process lifecycle // =========================================================================== /// Initialize the process-global HTTP client. Call once before any turn. pub fn init(allocator: std.mem.Allocator, io: std.Io) void { config_mod.initHttp(allocator, io); } /// Tear down the process-global HTTP client. Call once at shutdown. pub fn deinit() void { config_mod.deinitHttp(); } /// Borrow the process-global HTTP client (asserts `init` has run). Embedders /// driving the OAuth auth flows need this to pass to `oauthLogin` etc. pub const httpClient = config_mod.httpClient; // =========================================================================== // Config (data, aliased) // =========================================================================== pub const Config = config_mod.Config; pub const ProviderConfig = config_mod.ProviderConfig; pub const OpenAIChatConfig = config_mod.OpenAIChatConfig; pub const AnthropicMessagesConfig = config_mod.AnthropicMessagesConfig; pub const OpenAIResponsesConfig = config_mod.OpenAIResponsesConfig; pub const APIStyle = config_mod.APIStyle; pub const ReasoningEffort = config_mod.ReasoningEffort; pub const Thinking = config_mod.Thinking; pub const Effort = config_mod.Effort; pub const CompactionConfig = config_mod.CompactionConfig; pub const RetryConfig = config_mod.RetryConfig; pub const WireIdentity = config_mod.WireIdentity; pub const Header = config_mod.Header; // =========================================================================== // Auth (data + flows, aliased) // =========================================================================== pub const AuthConfig = auth_mod.AuthConfig; pub const AuthType = auth_mod.AuthType; pub const ApiKeyAuth = auth_mod.ApiKeyAuth; pub const OAuthDeviceAuth = auth_mod.OAuthDeviceAuth; pub const ExchangeConfig = auth_mod.ExchangeConfig; pub const DeviceDialect = auth_mod.DeviceDialect; pub const TokenRequestFormat = auth_mod.TokenRequestFormat; pub const TokenSet = auth_mod.TokenSet; pub const ParsedTokenSet = auth_mod.ParsedTokenSet; pub const ResolvedCredential = auth_mod.ResolvedCredential; /// Token persistence under an embedder-chosen auth directory /// (`$PANTO_HOME/auth`). Files are written owner-only. pub const loadTokenSet = auth_mod.loadTokenSet; pub const saveTokenSet = auth_mod.saveTokenSet; pub const deleteTokenSet = auth_mod.deleteTokenSet; // OAuth device-flow mechanism: interactive login, refresh, exchange, and the // pure credential/JWT helpers the embedder's auth manager composes. pub const AuthError = auth_mod.AuthError; pub const Presenter = auth_mod.Presenter; pub const DeviceCodePrompt = auth_mod.DeviceCodePrompt; pub const OAuthTokens = auth_mod.OAuthTokens; pub const oauthLogin = auth_mod.login; pub const refreshTokens = auth_mod.refreshTokens; pub const runExchange = auth_mod.runExchange; pub const buildCredential = auth_mod.buildCredential; pub const tokensToTokenSet = auth_mod.tokensToTokenSet; pub const needsRefresh = auth_mod.needsRefresh; pub const needsExchange = auth_mod.needsExchange; pub const parseJwtExp = auth_mod.parseJwtExp; pub const extractAccountId = auth_mod.extractAccountId; /// Non-streaming HTTP helper over the process-global client, plus JSON /// path readers — the building blocks of the OAuth flows. pub const http = @import("http_helper.zig"); // =========================================================================== // Conversation construction (data, aliased) // =========================================================================== pub const ContentBlock = conversation_mod.ContentBlock; pub const Message = conversation_mod.Message; pub const MessageRole = conversation_mod.MessageRole; pub const TextualBlock = conversation_mod.TextualBlock; /// Build a `TextualBlock` (the streaming text buffer used inside content /// blocks) from a slice, copying the bytes with `alloc`. The canonical way /// for binding code to construct `.Text`/`.Thinking`/tool-result text when /// assembling `ContentBlock`s by hand (e.g. for conversation resumption). pub const textualBlockFromSlice = conversation_mod.textualBlockFromSlice; pub const SignatureOrigin = conversation_mod.SignatureOrigin; pub const ThinkingBlock = conversation_mod.ThinkingBlock; pub const ToolUseBlock = conversation_mod.ToolUseBlock; pub const ToolResultBlock = conversation_mod.ToolResultBlock; pub const ResultPartStored = conversation_mod.ResultPartStored; pub const StoredMediaPart = conversation_mod.StoredMediaPart; pub const SystemBlock = conversation_mod.SystemBlock; pub const SystemMode = conversation_mod.SystemMode; pub const CompactionSummaryBlock = conversation_mod.CompactionSummaryBlock; pub const Usage = conversation_mod.Usage; pub const effectiveSystemBlocks = conversation_mod.effectiveSystemBlocks; /// The conversation type. Aliased straight through: its interface has been /// pared down to exactly the public surface (constructors `init`/`deinit`, /// the `add*`/`replace*` builders, and the `messages`/`allocator` data /// fields), so no façade is needed. This is what `Session.load` returns, /// what `Agent.init` adopts, and what `Agent.conversation()` borrows a /// pointer to (for in-place surgery). Build one standalone with `init` for /// by-hand construction; once handed to an `Agent` it is owned by the agent. pub const Conversation = conversation_mod.Conversation; // =========================================================================== // Tools (data, aliased) // =========================================================================== pub const Tool = tool_mod.Tool; pub const ToolSource = tool_source_mod.ToolSource; pub const ToolDecl = tool_mod.ToolDecl; pub const ToolCall = tool_source_mod.Call; pub const ToolCallResult = tool_source_mod.CallResult; pub const MediaPart = tool_mod.MediaPart; pub const ResultPart = tool_mod.ResultPart; /// Result-part ergonomics: a thin wrapper around `[]ResultPart` carrying /// the `fromText`/`fromTextOwned` constructors and `deinit`. Aliased /// straight through. pub const ResultParts = tool_mod.ResultParts; // =========================================================================== // Stream (behavioral, heap-pinned) // =========================================================================== pub const Event = stream_mod.Event; pub const ContentBlockType = provider_mod.ContentBlockType; pub const ProviderRetryInfo = provider_mod.ProviderRetryInfo; /// The pull event stream for one turn. Aliased straight through: its public /// surface is exactly `next`/`deinit` plus the transparent `state` field /// (`State`); every other field is underscore-prefixed internal state. /// `Agent.run` returns a `*Stream` (heap-pinned); the caller owns it and /// must `deinit` it (which persists the turn tail and frees the allocation). /// /// `next()` returns `!?Event`: a value is progress (including the terminal /// event), `null` is exhaustion, an error is a genuine failure. pub const Stream = agent_mod.Stream; // =========================================================================== // Agent (behavioral, heap-pinned) // =========================================================================== pub const UserMessage = agent_mod.UserMessage; pub const CompactionResult = agent_mod.CompactionResult; /// The agent loop driver. Aliased straight through: its public surface is /// exactly the chosen methods (`init`/`deinit`, `registerTool`, /// `registerToolSource`, `setConfig`, `run`, `addSystemMessage`, /// `setSystemPrompt`, `compact`, `sessionId`) plus the transparent /// `conversation` field; every other field is underscore-prefixed internal /// state. /// /// `init` heap-pins the agent and returns a `*Agent` — a cheap, movable /// handle out of the gate ("don't move the Agent" stops being a rule anyone /// can violate). The caller owns it and must `deinit` it. `session` is /// minted via `store.create()` (fresh) or `resolve`/`latest` (resume); when /// `maybe_conversation` is non-null it is adopted (ownership transferred) — /// the resume path hands the value returned by `Session.load`. /// /// Operate on the live conversation in place via the `conversation` field /// (valid for the agent's lifetime; do not retain past it). pub const Agent = agent_mod.Agent; // =========================================================================== // Pricing (data, aliased) // =========================================================================== pub const Pricing = pricing_mod.Pricing; pub const PricingRegistry = pricing_mod.Registry; // =========================================================================== // Sessions // =========================================================================== pub const SessionStore = session_store_mod.SessionStore; pub const Session = session_store_mod.Session; pub const SessionInfo = session_store_mod.SessionInfo; pub const PersistentMessage = session_store_mod.PersistentMessage; pub const NullStore = null_store_mod.NullStore; pub const FileSystemJSONLStore = fs_store_mod.FileSystemJSONLStore; // =========================================================================== // Tests // =========================================================================== const openai_chat_json = @import("openai_chat_json.zig"); const provider_openai_chat = @import("provider_openai_chat.zig"); const anthropic_messages_json = @import("anthropic_messages_json.zig"); const provider_anthropic_messages = @import("provider_anthropic_messages.zig"); const openai_responses_json = @import("openai_responses_json.zig"); const provider_openai_responses = @import("provider_openai_responses.zig"); const compaction_mod = @import("compaction.zig"); const sse_mod = @import("sse.zig"); const tool_registry_mod = @import("tool_registry.zig"); const session_mod = @import("session.zig"); const turn_persist_mod = @import("turn_persist.zig"); const image_mod = @import("image.zig"); test { // See the note in the old root.zig: gate test logs at `.err` so expected // warning-path tests stay quiet. std.testing.log_level = .err; std.testing.refAllDecls(@This()); // Internal modules' tests (not part of the public surface, but their // tests must still run). std.testing.refAllDecls(config_mod); std.testing.refAllDecls(auth_mod); std.testing.refAllDecls(@import("http_helper.zig")); std.testing.refAllDecls(conversation_mod); std.testing.refAllDecls(agent_mod); std.testing.refAllDecls(stream_mod); std.testing.refAllDecls(provider_mod); std.testing.refAllDecls(tool_mod); std.testing.refAllDecls(tool_source_mod); std.testing.refAllDecls(tool_registry_mod); std.testing.refAllDecls(pricing_mod); std.testing.refAllDecls(session_store_mod); std.testing.refAllDecls(fs_store_mod); std.testing.refAllDecls(null_store_mod); std.testing.refAllDecls(session_mod); std.testing.refAllDecls(turn_persist_mod); std.testing.refAllDecls(compaction_mod); std.testing.refAllDecls(sse_mod); std.testing.refAllDecls(image_mod); std.testing.refAllDecls(openai_chat_json); std.testing.refAllDecls(provider_openai_chat); std.testing.refAllDecls(anthropic_messages_json); std.testing.refAllDecls(provider_anthropic_messages); std.testing.refAllDecls(openai_responses_json); std.testing.refAllDecls(provider_openai_responses); }