diff options
| author | t <t@tjp.lol> | 2026-06-18 13:38:32 -0600 |
|---|---|---|
| committer | t <t@tjp.lol> | 2026-06-18 13:39:49 -0600 |
| commit | 7c2d8825660f73198149c0b2ce26166b16ba3532 (patch) | |
| tree | ae57a23e5dcb905b29718c63a0ed2f6c65d93d53 /libpanto-c/include/panto.h | |
| parent | fc77c3900ef80ff0e2934c03ca37dfc309a6e7b9 (diff) | |
Preserve content blocks and thinking origin in C store append
Round-trip persistent message content through the C session store bridge
instead of dropping it, including tool-use, tool-result, system, and
thinking blocks. Reconstruct borrowed C content blocks with arena-backed
helpers, carry message identity fields like API style/model/reasoning, and
add tests covering append marshalling and thinking signature origin
round-tripping.
Diffstat (limited to 'libpanto-c/include/panto.h')
| -rw-r--r-- | libpanto-c/include/panto.h | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/libpanto-c/include/panto.h b/libpanto-c/include/panto.h index d0c272f..c43b39f 100644 --- a/libpanto-c/include/panto.h +++ b/libpanto-c/include/panto.h @@ -58,7 +58,36 @@ typedef struct { size_t message_index; } PantoToolDispatchComplete; typedef struct { PantoEventTag tag; union { PantoMessageRole message_start; PantoBlockStart block_start; PantoToolDetails tool_details; PantoContentDelta content_delta; PantoBlockComplete block_complete; PantoMessageComplete message_complete; PantoProviderRetry provider_retry; PantoToolDispatchStart tool_dispatch_start; PantoToolDispatchComplete tool_dispatch_complete; } data; } PantoEvent; -typedef struct { PantoMessageRole role; bool has_usage; PantoUsage usage; bool has_metadata; PantoSlice metadata; } PantoPersistentMessage; +/* One content block of a message being appended. A flattened, borrow-only + * view: every slice points into the in-memory message and is valid only for + * the duration of the append_messages call. `text` carries the Text body, + * Thinking text, ToolUse input JSON, concatenated ToolResult text, or + * System/CompactionSummary text depending on `tag`. `tool_id` is the ToolUse + * id or ToolResult tool_use_id; `tool_name` is the ToolUse name; `is_error` + * is the ToolResult error flag; `system_mode` is the System block mode; + * `thinking_signature` is the Thinking signature (empty when absent), and the + * `thinking_signature_*` fields record the provider/style/model that emitted + * it. To replay a thinking block faithfully (Anthropic drops thinking blocks + * whose signature lacks a matching origin) a store must persist the signature + * AND all three origin fields, then feed them back via the message builder. */ +typedef struct { + PantoContentBlockTag tag; + PantoSlice text; + PantoSlice tool_id; + PantoSlice tool_name; + bool is_error; + PantoSystemMode system_mode; + PantoSlice thinking_signature; + PantoAPIStyle thinking_signature_api_style; + PantoSlice thinking_signature_base_url; + PantoSlice thinking_signature_model; +} PantoOwnedContentBlock; + +/* `api_style`/`base_url`/`model`/`reasoning` are the per-message wire identity + * (the provider that produced this message), which can drift within a single + * conversation (compaction on a different model, a mid-chat model switch). A + * store should persist these per message rather than from static config. */ +typedef struct { PantoMessageRole role; bool has_usage; PantoUsage usage; bool has_metadata; PantoSlice metadata; PantoAPIStyle api_style; PantoSlice base_url; PantoSlice model; PantoReasoningEffort reasoning; const PantoOwnedContentBlock *content; size_t content_len; } PantoPersistentMessage; typedef struct { PantoStatus (*create)(void *ctx, PantoSession **out); @@ -93,6 +122,34 @@ PANTO_EXPORT PantoStatus panto_conversation_replace_system_message(PantoConversa PANTO_EXPORT PantoStatus panto_conversation_add_user_text(PantoConversation *conversation, const char *text); PANTO_EXPORT PantoStatus panto_conversation_add_assistant_text(PantoConversation *conversation, const char *text, bool has_usage, PantoUsage usage); PANTO_EXPORT PantoStatus panto_conversation_add_compaction_summary(PantoConversation *conversation, const char *text); + +/* Rich, block-level message builder. Accumulate content blocks, then commit + * the whole message to a conversation in one call — the path for rebuilding a + * persisted conversation that contains tool calls or thinking. The builder + * uses the same allocator as the conversation it is committed to. + * + * Usage: create -> add_* (one per block, in order) -> conversation_add_message. + * `panto_conversation_add_message` ALWAYS consumes the builder (it is freed on + * both success and failure); do not destroy it afterwards. Call + * `panto_message_builder_destroy` only to discard a builder you never commit. + * Each `text`/`signature`/etc. argument is copied. */ +typedef struct PantoMessageBuilder PantoMessageBuilder; +PANTO_EXPORT PantoMessageBuilder *panto_message_builder_create(PantoMessageRole role); +PANTO_EXPORT void panto_message_builder_destroy(PantoMessageBuilder *builder); +PANTO_EXPORT PantoStatus panto_message_builder_add_text(PantoMessageBuilder *builder, const char *text); +/* `signature` may be NULL/empty when the provider emitted no signature, in + * which case the `signature_*` origin args are ignored. When a signature is + * supplied, pass the origin (style/base_url/model) it was produced under so + * the block can be replayed; an Anthropic request drops thinking blocks whose + * signature origin does not match the request's base_url/model. */ +PANTO_EXPORT PantoStatus panto_message_builder_add_thinking(PantoMessageBuilder *builder, const char *text, const char *signature, PantoAPIStyle signature_api_style, const char *signature_base_url, const char *signature_model); +PANTO_EXPORT PantoStatus panto_message_builder_add_tool_use(PantoMessageBuilder *builder, const char *id, const char *name, const char *input); +PANTO_EXPORT PantoStatus panto_message_builder_add_tool_result(PantoMessageBuilder *builder, const char *tool_use_id, const char *text, bool is_error); +PANTO_EXPORT PantoStatus panto_message_builder_add_system(PantoMessageBuilder *builder, const char *text, PantoSystemMode mode); +/* Commit the builder's blocks as one message of the builder's role. Consumes + * (frees) the builder. `usage` applies to assistant turns; pass has_usage=false + * otherwise. */ +PANTO_EXPORT PantoStatus panto_conversation_add_message(PantoConversation *conversation, PantoMessageBuilder *builder, bool has_usage, PantoUsage usage); PANTO_EXPORT PantoStatus panto_session_create_null(PantoSession **out); PANTO_EXPORT PantoStatus panto_session_create(PantoSessionStore *store, PantoSessionInfo info, PantoSession **out); PANTO_EXPORT void panto_session_destroy(PantoSession *session); |
