summaryrefslogtreecommitdiff
path: root/libpanto-go/panto_test.go
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-07-07 11:29:23 -0600
committert <t@tjp.lol>2026-07-07 12:15:28 -0600
commit621d7fee0ace729f8d44126032d2c6e13f72ee7f (patch)
treea2938b0a9e5c0930e8644721abbe94875df9ff08 /libpanto-go/panto_test.go
parent0fa6d4209ff9b4a95e7d1955887aa4c73ee3423c (diff)
Move libpanto projects to libpantograph dependencyHEADmain
Remove the in-repo libpanto sources and binding projects from pantograph. Consume libpantograph through the Zig package URL at code.tjp.lol/libpantograph.git, including the Lua module artifact used by CLI extensions.
Diffstat (limited to 'libpanto-go/panto_test.go')
-rw-r--r--libpanto-go/panto_test.go213
1 files changed, 0 insertions, 213 deletions
diff --git a/libpanto-go/panto_test.go b/libpanto-go/panto_test.go
deleted file mode 100644
index 1270ead..0000000
--- a/libpanto-go/panto_test.go
+++ /dev/null
@@ -1,213 +0,0 @@
-package panto
-
-import "testing"
-
-// memStore is a minimal custom SessionStore that mints its sessions via
-// NewSession (gap #1) rather than dispatching back into the vtable.
-type memStore struct {
- self *GoSessionStore
- created bool
-}
-
-func (m *memStore) Create() (*Session, error) {
- m.created = true
- return NewSession(m.self, SessionInfo{ID: "sess-1"})
-}
-func (m *memStore) List() ([]SessionInfo, error) { return nil, nil }
-func (m *memStore) Resolve(id string) (*Session, bool, error) {
- if id != "sess-1" {
- return nil, false, nil
- }
- s, err := NewSession(m.self, SessionInfo{ID: id})
- return s, err == nil, err
-}
-func (m *memStore) Latest() (*Session, bool, error) { return m.Resolve("sess-1") }
-func (m *memStore) Load(id string) (*Conversation, bool, error) { return nil, false, nil }
-func (m *memStore) AppendMessages(string, []PersistentMessage) error {
- return nil
-}
-
-// Gap #1: a Go store can mint and return a *Session from its own Create()
-// without recursing back into the vtable.
-func TestCustomStoreMintsSession(t *testing.T) {
- Init()
- defer Deinit()
-
- impl := &memStore{}
- gss, err := NewGoSessionStore(impl)
- if err != nil {
- t.Fatalf("NewGoSessionStore: %v", err)
- }
- defer gss.Close()
- impl.self = gss
-
- sess, err := gss.Create()
- if err != nil {
- t.Fatalf("Create: %v", err)
- }
- if sess == nil || sess.ptr == nil {
- t.Fatal("Create returned nil session")
- }
- if !impl.created {
- t.Fatal("custom Create() was not invoked")
- }
-
- got, ok, err := gss.Resolve("sess-1")
- if err != nil || !ok || got == nil {
- t.Fatalf("Resolve: got=%v ok=%v err=%v", got, ok, err)
- }
-}
-
-// Gap #3: rebuild a conversation containing tool_use / tool_result / thinking
-// via the value-block API, then read the blocks back losslessly.
-func TestMessageBuilderRoundTrip(t *testing.T) {
- Init()
- defer Deinit()
-
- conv, err := NewConversation()
- if err != nil {
- t.Fatalf("NewConversation: %v", err)
- }
- defer conv.Close()
-
- if err := conv.AddMessage(UserMessage(
- ToolResultBlock("call-1", "result text", false),
- )); err != nil {
- t.Fatalf("AddMessage(user): %v", err)
- }
-
- if err := conv.AddMessage(AssistantMessage(&Usage{Input: 10, Output: 5},
- TextBlock("let me search"),
- ThinkingBlock("hmm", "sig", AnthropicMessages, "https://api", "claude"),
- ToolUseBlock("call-1", "search", `{"q":1}`),
- )); err != nil {
- t.Fatalf("AddMessage(assistant): %v", err)
- }
-
- if got := conv.MessageCount(); got != 2 {
- t.Fatalf("MessageCount = %d, want 2", got)
- }
-
- user := conv.Message(0).Snapshot()
- if user.Role != RoleUser || len(user.Content) != 1 {
- t.Fatalf("user message: role=%v blocks=%d", user.Role, len(user.Content))
- }
- if tr := user.Content[0]; tr.Tag != BlockToolResult || tr.ToolID != "call-1" || tr.Text != "result text" || tr.IsError {
- t.Fatalf("tool_result block: %+v", tr)
- }
-
- asst := conv.Message(1).Snapshot()
- if asst.Role != RoleAssistant || len(asst.Content) != 3 {
- t.Fatalf("assistant message: role=%v blocks=%d", asst.Role, len(asst.Content))
- }
- if b := asst.Content[0]; b.Tag != BlockText || b.Text != "let me search" {
- t.Fatalf("text block: %+v", b)
- }
- if b := asst.Content[1]; b.Tag != BlockThinking || b.Text != "hmm" {
- t.Fatalf("thinking block: %+v", b)
- }
- if b := asst.Content[2]; b.Tag != BlockToolUse || b.ToolID != "call-1" || b.ToolName != "search" || b.Text != `{"q":1}` {
- t.Fatalf("tool_use block: %+v", b)
- }
- if asst.Usage == nil || asst.Usage.Input != 10 || asst.Usage.Output != 5 {
- t.Fatalf("assistant usage: %+v", asst.Usage)
- }
-}
-
-// TestMessageBuilderSetIdentity rebuilds a message with a per-message wire
-// identity (and no per-block thinking origin), the resumption path that lets
-// callers avoid copying the identity onto every thinking block.
-func TestMessageBuilderSetIdentity(t *testing.T) {
- Init()
- defer Deinit()
-
- conv, err := NewConversation()
- if err != nil {
- t.Fatalf("NewConversation: %v", err)
- }
- defer conv.Close()
-
- // Thinking block with a signature but NO per-block origin; provenance is
- // carried at the message level instead, via WithIdentity.
- msg := AssistantMessage(&Usage{Input: 10, Output: 5},
- ThinkingBlock("reasoned", "sig", OpenAIChat, "", ""),
- TextBlock("answer"),
- ).WithIdentity(MessageIdentity{
- APIStyle: AnthropicMessages,
- BaseURL: "https://api.anthropic.com",
- Model: "claude",
- Reasoning: ReasoningDefault,
- })
- if err := conv.AddMessage(msg); err != nil {
- t.Fatalf("AddMessage: %v", err)
- }
-
- asst := conv.Message(0).Snapshot()
- if asst.Role != RoleAssistant || len(asst.Content) != 2 {
- t.Fatalf("assistant message: role=%v blocks=%d", asst.Role, len(asst.Content))
- }
- if b := asst.Content[0]; b.Tag != BlockThinking || b.Text != "reasoned" {
- t.Fatalf("thinking block: %+v", b)
- }
-}
-
-func testConfig() Config {
- return Config{
- Provider: ProviderConfig{
- OpenAIChat: &OpenAIChatConfig{
- APIKey: "test-key",
- BaseURL: "http://localhost",
- Model: "test-model",
- MaxTokens: 16,
- },
- },
- }
-}
-
-func TestOpenAIResponsesProviderConfigPassesThrough(t *testing.T) {
- provider := ProviderConfig{
- OpenAIResponses: &OpenAIResponsesConfig{
- APIKey: "test-key",
- BaseURL: "http://localhost",
- Model: "test-model",
- Reasoning: ReasoningMedium,
- MaxTokens: 128,
- },
- }
- c, strings, err := provider.c()
- if err != nil {
- t.Fatalf("ProviderConfig.c: %v", err)
- }
- defer strings.free()
-
- if APIStyle(c.tag) != OpenAIResponses {
- t.Fatalf("tag = %v, want %v", APIStyle(c.tag), OpenAIResponses)
- }
-
- Init()
- defer Deinit()
-
- a, err := NewAgent(Config{Provider: provider})
- if err != nil {
- t.Fatalf("NewAgent: %v", err)
- }
- defer a.Close()
-}
-
-func TestNewAgentSetSystemPromptDoesNotCrash(t *testing.T) {
- Init()
- defer Deinit()
-
- a, err := NewAgent(testConfig())
- if err != nil {
- t.Fatalf("NewAgent: %v", err)
- }
- defer a.Close()
-
- if err := a.SetSystemPrompt("be brief"); err != nil {
- t.Fatalf("SetSystemPrompt: %v", err)
- }
- if err := a.AddSystemMessage("also be accurate"); err != nil {
- t.Fatalf("AddSystemMessage: %v", err)
- }
-}