| Age | Commit message (Collapse) | Author |
|
|
|
|
|
Teach provider config and auth resolution about the Codex Responses
dialect, including user-facing `style = "openai_responses"` with
`dialect = "codex"`. Serialize and parse Responses traffic with
provider-specific reasoning replay, assistant phase metadata, and robust
function-call assembly keyed by `output_index` so streamed tool inputs
survive proxy quirks and empty terminal payloads.
Also persist thinking origins and message metadata across sessions, add
the Anthropic interleaved-thinking header switch, write per-session
debug logs, and improve the TUI and scripts for inspecting tool output
and session costs.
|
|
|
|
Collapse the auth schema: infer `type` from keys, replace key/key_env_var with
a single `key` (resolved via substitution), flatten the exchange to flat
`exchange_*` keys, and drop the auth-level headers tables in favor of reusing
the provider's `extra_headers` on the auth HTTP calls. Add `${sibling}` and
`${env:VAR}` substitution over auth values (GitHub Enterprise = set `domain`).
Restore api_key-empty → provider-drop. Update default config, docs, and tests.
|
|
Add the OpenAI Responses API wire dialect (openai_responses APIStyle +
OpenAIResponsesConfig), a request serializer (instructions/input items,
flat function tools, reasoning, store:false, include encrypted reasoning),
and a streaming state machine over the typed response.* SSE events mapping
to the shared block model. Wire dispatch, buildProviderConfig, the C-ABI
free switch, and the reasoning selectors. Ship a commented Codex example in
the default config.
Implemented from the Responses API docs + the open-source Codex client and
covered by fixture tests; live verification against a ChatGPT plan is still
required (documented).
|
|
Resolve the active provider's auth before each turn via the AuthManager,
rendering an inline device-code prompt when login is needed, and force a
single refresh/exchange retry on a provider auth failure. Wire the manager
through RunOptions from main.zig.
|
|
Add src/auth_manager.zig (turn-time resolution: load→login→refresh→exchange→
build credential, patch live config) and `panto auth status|login|logout`
subcommands with a line-based device-code presenter. Add config_file.loadFromString.
|
|
Add libpanto http_helper (non-streaming request/response over the global
client, plus dotted-JSON-path readers) and token persistence in auth.zig
(load/save/delete TokenSet under an embedder-chosen auth dir, owner-only
files). Add $PANTO_HOME/auth to the panto_home layout.
|
|
Replace provider-level api_key/api_key_env_var with named auth sessions:
providers now reference `auth = "<name>"` and credentials live under
`[auth.<name>]`. Adds the libpanto auth type surface (AuthConfig, TokenSet,
ResolvedCredential), a Header type and provider `extra_headers`, and rewires
the CLI config loader (parse [auth.<name>], require auth=, providers always
survive, eager api_key resolution). Updates the shipped default config.
|
|
|
|
|
|
|
|
|
|
Remove setFrameTime() method and fps-related rendering from Footer.
Replace with setModel() to display model name with dim styling. Update
all Footer tests accordingly, adjusting line counts and expectations for
new layout with top/bottom rules wrapping content. Remove reverse video
styling from footer.
|
|
- FSJSONLStore: don't require `cwd`, instead panto CLI provides it in
the session metadata
- Lua: expose the `SessionStore` interface and the `FSJSONLStore` and
`NullStore` implementations
- C: use idiomatic `const char *` for incoming strings
- C: expose the `FSJSONLStore` and `NullStore` implementations
|
|
|
|
output
The root cause was a two-part bug:
1. Engine slot management (tui_engine.zig): The app rebuilds its full
component list on every new transcript entry. The old approach drained
every slot then re-added them all, resetting every component's render
baseline. When earlier content had scrolled into native scrollback
(viewport_top > 0), the engine's viewport-escape rule escalated any
cut above the viewport top to a scrollback-clearing full redraw — the
visible flash on every streamed block while a tool call was expanded.
Fix: replace drain+rebuild with syncComponents(), which reconciles the
live slot list in place by finding the longest common prefix and suffix
(matched by component pointer). Prefix and suffix slots keep their
baselines verbatim; only the changed region in the middle gets new
empty slots. A pure insertion (the dominant case: a new transcript
entry appended just before the pinned input+footer suffix) stays on
the differential path with no clear. A structural change (slot
replaced or removed) sets force_full for correctness.
2. RenderCache dirty signal (tui_component.zig): firstLineChanged()
was returning the retained changed_from diff index even when the cache
was clean. A first-paint store records changed_from == 0, so a clean
but previously-rendered component was pegging the differential cut to
line 0 on every subsequent frame, making unchanged slots above the
insertion point drag the cut all the way up. Fix: when the cache is
clean, firstLineChanged() returns null unconditionally. The recorded
changed_from is now internal render bookkeeping only, not a live
signal.
Additional changes:
- ToolUse.collapsed_tail_lines raised from 5 to 8 lines.
- ToolUse collapsed-view test updated to use 12 output lines and
collapsed_tail_lines symbolically so the numbers self-document.
- tui_app.zig: override-slot test comment and assertion clarified to
reflect that the override owns the slot pointer (not just renders it),
and the SWAPPED-AT-DETAILS render check replaced with a pointer-equality
check.
- lua_event_bridge.zig: minor related fixes.
- New tests: syncComponents middle-insertion no-clear, syncComponents
structural removal forces full, syncComponents override swap; streaming
expanded-tools no-clear regression test in tui_app.
|
|
|
|
Conversation.addUserMessage now takes a []ContentBlock (symmetric with
addAssistantMessage). Introduce a thin addUserText wrapper in agent.zig
for the plain-text case and update every call site in agent.zig and
anthropic_messages_json.zig accordingly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
determine support for the kitty protocol and then pick output sequences
accordingly.
tested on ghostty (supports kitty) and tmux-in-ghostty (tmux does not
support kitty protocol) with shift+enter as newline.
|
|
Implement TUI Phase 1: a raw-mode terminal, differential render engine,
pinned input box + footer, and component model wired into the libpanto
event stream. Adds foundation modules (theme, key, component, input,
terminal), the render engine, components, and the app loop; removes the
old print CLIRenderer and driveTurn REPL from main.zig.
Also removes scratch status reports (tui-p1/, progress.md) for the now
completed work.
|
|
|
|
Push the API-shaping we'd done in the public facade down into the internal
types, collapsing the wrappers:
- Stream: rename phase->state, Phase->State; underscore-prefix the internal
fields (_agent/_queue/_response/_start/_persisted/_pending_error). state
is the one intended-public field. public.zig now aliases Stream; run
returns *Stream.
- Agent compaction: pure transform compact()->private _compactInPlace;
compactAndPersist()->compact() (the public name, persists).
- Agent system prompt: addSystemMessage(text,mode) split into
addSystemMessage(text) + setSystemPrompt(text) over a private
_persistSystemMessage.
- UserMessage moved off Agent to module scope.
- Underscore-prefix pure-internal Agent fields: _open_stream_fn,
_auto_compacted, _retry_prng.
The Agent facade is now pure 1:1 forwarders; it stays a wrapper only because
init heap-pins the inner (copyable, move-safe handle) and conversation()/
sessionId() are accessors. Conversation and Stream are plain aliases.
|
|
A facade that forwards every method 1:1 is worse than paring the real type
down to the intended surface and aliasing it. conversation.Conversation's
interface is already the public surface we want (init/deinit, the
add*/replace* builders, and messages/allocator as plain data fields), so
public.zig now aliases it straight through and Agent.conversation() returns
a borrowed *Conversation for in-place surgery. Drops the ConversationData
alias and the pointer-wrapper.
Merged addAssistantMessageWithUsage into addAssistantMessage(blocks, ?usage)
on the real type (separate method deleted), so the alias has the intended
one-method shape; all call sites updated.
Only Agent and Stream remain true facades -- they have genuinely-internal
fields plus API-shaping renames (Stream.phase->state, Phase->State) an alias
can't express.
|
|
Close the gap that forced the CLI to import internal libpanto namespaces,
then delete the transitional re-exports. The CLI now uses only the curated
public surface.
Additions to the public Agent facade:
- init/deinit (heap-pin the inner; the handle is a copyable value).
- addSystemMessage (.append) and setSystemPrompt (.replace).
- compact(override_system_prompt, extra) falling back to the config prompt.
- sessionId() accessor.
CompactionConfig gains compaction_prompt, which owns the compaction system
prompt for both auto-compaction and the explicit compact() default; the
Agent.compaction_system_prompt field is deleted. ConversationData is the
public name for the owned conversation value type (Session.load returns it,
Agent.init adopts it), distinct from the borrowed Conversation handle.
Agent.addSystemMessage/setSystemPrompt are kept on Agent (they persist with
the SystemMode) rather than dropped as the plan first proposed.
|
|
Move the CLI off the internal libpanto module namespaces onto the curated
public API: data-type aliases (Config family, Message/MessageRole/
effectiveSystemBlocks, Event, Pricing/PricingRegistry, the session seam,
FileSystemJSONLStore, ContentBlockType), process lifecycle (panto.init/
deinit), and ResultParts.fromText/fromTextOwned/deinit in place of the
freestanding textResult/ownedTextResult/freeResultParts.
The CLI remains on two flagged internal namespaces, panto.agent and
panto.conversation: it is a deep embedder that drives the loop below the
curated Agent/Conversation facades (system-prompt seeding through the
agent, compaction_system_prompt, the open_stream_fn test seam, standalone
Conversation values, compactAndPersist). These stay re-exported from
public.zig as a documented deep-embedder escape hatch; trimming the
transitional block removed every other internal re-export.
|
|
Replace the single-session SessionManager seam with a directory-backed
catalog. session_manager.zig -> file_system_jsonl_store.zig; the old
machinery becomes internal SessionFile, and a new FileSystemJSONLStore
implements the redesigned SessionStore vtable (create/list/resolve/latest/
load/appendMessages) minting Session/SessionInfo handles.
Session logs now record wire-format provider identity
({api_style, base_url, model, reasoning}) instead of a single provider
string or CLI aliases; no api_key material is ever stored. Disk* content
types renamed Stored*; the rich audit-oriented write record is
PersistentMessage (in-memory Message + WireIdentity + provenance).
Agent.init now takes a Session; persist_provider/persist_model display
strings deleted (banner stays alias-based, resume picks default model).
Message.metadata round-trips. Dangling-prompt recovery dropped. CLI
migrated to the catalog store for run/resume/list. Clean break, no version
bump (old logs wiped).
|
|
The tool set is no longer part of the per-turn Config snapshot. Agent now
owns a ToolRegistry (created empty at init), populated via the new
Agent.registerTool / registerToolSource methods. openStream and
OpenStreamFn take the registry as an explicit parameter rather than reading
it from cfg.registry, so swapping provider/model between turns (setConfig)
no longer disturbs the tool set.
CLI migrated to register the Lua tool source onto the agent instead of a
locally-owned registry. Test harnesses updated to stage tools on the agent.
|
|
converted the main agent loop from push-based (into callbacks on a
Receiver vtable) to pull-based, where `next()` re-enters a state-machine
Stream until the next event can be returned.
|
|
The Agent now owns its Conversation and a SessionStore, and persists
everything it generates as turns progress. Embedders get persistence for
free; the CLI no longer drives the session log.
libpanto:
- Agent.init takes a SessionStore + optional Conversation to adopt (resume
path). Agent owns/tears down the conversation; turn-driving methods drop
the *Conversation param and operate on self.conversation.
- New Agent methods: submitUserMessage (adds+persists the user prompt
immediately), addSystemMessage(text, mode), runStep persists the turn on
every exit path (incl. partial turns on error), compactAndPersist for the
explicit /compact path. Auto-compaction persists its window via runStep's
tail.
- turn_persist.zig: DiskMessage mapping moved out of the CLI; reads usage
off Message.usage (no per-message-usage list). System mode rides on
DiskMessage.mode, derived from the System block.
- NullStore is now an allocator-bearing struct (frees consumed messages per
the store-consumes-messages contract).
- Tests: in-memory CapturingStore round-trip + NullStore turn test.
panto CLI:
- Delete src/session_persist.zig. REPL is submitUserMessage + runStep.
- Reorder construction: store -> registry -> agent -> bootstrap -> seed/
reconcile system prompt through the agent -> load extensions.
- command.Context drops conv/session_mgr; commands reach ctx.agent.
- system_prompt seed/reconcile call agent.addSystemMessage.
- CLIReceiver is display-only (per_message_usage removed).
Phases 3-5 of docs/pluggable-session-store.md. Behavior preserved; full
build + test suite green.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Replace all references to the "system" layer with "base" to better reflect
its role as the foundational extension/tool layer in panto's hierarchy.
The layer hierarchy now consistently uses: project > user > base.
Includes:
- Update agent README and build.zig documentation
- Refactor tool registry and config module to support layered lookups
- Add TestHarness abstraction for cleaner test setup
- Improve JSON serialization with wire-encoded tool names
- Add glob pattern matching for tool/extension discovery
|
|
|
|
|
|
|