From 5e76e4aa90e70245404c10085e809880635572a0 Mon Sep 17 00:00:00 2001 From: t Date: Tue, 23 Jun 2026 11:20:45 -0600 Subject: Fix tool override swaps to stay differential Treat 1:1 component swaps and pure insertions as differential TUI updates instead of structural changes that force full redraws. Keep full redraws for net removals and edits above the viewport, and add tests covering the streaming-tool flicker regression and scrollback behavior. Also remove the unfinished Go ToolSource batch-registration bridge. --- libpanto-go/panto.go | 71 ++++++---------------------------------------------- 1 file changed, 7 insertions(+), 64 deletions(-) (limited to 'libpanto-go') diff --git a/libpanto-go/panto.go b/libpanto-go/panto.go index 89e4317..543d4b6 100644 --- a/libpanto-go/panto.go +++ b/libpanto-go/panto.go @@ -16,7 +16,6 @@ static PantoStatus pantoGoStoreAppendMessagesConst(void *ctx, PantoSlice session return pantoGoStoreAppendMessages(ctx, session_id, (PantoPersistentMessage*)messages, len); } extern PantoStatus pantoGoToolInvoke(void *ctx, PantoSlice input, PantoResultParts *out); -extern PantoStatus pantoGoToolSourceInvokeBatch(void *ctx, PantoToolCall *calls, PantoToolCallResult *results, size_t len); extern void pantoGoCallbackDestroy(void *ctx); static PantoSessionStoreVTable panto_go_store_vtable = { pantoGoStoreCreate, @@ -1264,16 +1263,6 @@ type ( } ) -type ( - ToolCall struct{ ToolName, Input string } - ToolSourceFunc func(calls []ToolCall) ([]ResultParts, []error, error) - ToolSource struct { - Name string - Tools []ToolDecl - InvokeBatch ToolSourceFunc - } -) - var ( callbackHandles = map[uintptr]any{} nextCallbackHandle uintptr = 1 @@ -1298,35 +1287,16 @@ func pantoGoToolInvoke(ctx unsafe.Pointer, input C.PantoSlice, out *C.PantoResul return C.PANTO_OK } -//export pantoGoToolSourceInvokeBatch -func pantoGoToolSourceInvokeBatch(ctx unsafe.Pointer, calls *C.PantoToolCall, results *C.PantoToolCallResult, n C.size_t) C.PantoStatus { - src := callbackHandles[uintptr(ctx)].(ToolSource) - cc := unsafe.Slice(calls, int(n)) - goCalls := make([]ToolCall, int(n)) - for i, c := range cc { - goCalls[i] = ToolCall{ToolName: goSlice(c.tool_name), Input: goSlice(c.input)} - } - parts, errs, err := src.InvokeBatch(goCalls) - if err != nil { - return C.PANTO_ERROR - } - rr := unsafe.Slice(results, int(n)) - for i := range rr { - if i < len(errs) && errs[i] != nil { - rr[i].ok = false - continue - } - rr[i].ok = true - if i < len(parts) { - rr[i].parts = makeCResultParts(parts[i]) - } - } - return C.PANTO_OK -} - //export pantoGoCallbackDestroy func pantoGoCallbackDestroy(ctx unsafe.Pointer) { dropCallback(ctx) } +// RegisterTool registers a single tool. Note: libpanto invokes each tool call +// on its own thread, so Invoke may run concurrently — guard any shared state. +// +// TODO: back all Go tool registrations with one process-global Zig ToolSource so +// libpanto delivers the whole turn's batch on a single thread and we fan out onto +// goroutines instead of libpanto threads. Pure efficiency (cheaper than N pthreads +// per turn); the public API stays exactly this. Punted as not worth the work yet. func (a *Agent) RegisterTool(t Tool) error { ctx := saveCallback(t) d, free := cToolDecl(t.Decl) @@ -1338,33 +1308,6 @@ func (a *Agent) RegisterTool(t Tool) error { return nil } -func (a *Agent) RegisterToolSource(src ToolSource) error { - ctx := saveCallback(src) - cname := cSlice(src.Name) - defer C.free(unsafe.Pointer(cname.ptr)) - decls := make([]C.PantoToolDecl, len(src.Tools)) - frees := make([]func(), 0, len(src.Tools)) - for i, d := range src.Tools { - cd, fr := cToolDecl(d) - decls[i] = cd - frees = append(frees, fr) - } - defer func() { - for _, f := range frees { - f() - } - }() - var ptr *C.PantoToolDecl - if len(decls) > 0 { - ptr = &decls[0] - } - if C.panto_agent_register_tool_source(a.ptr, cname, ptr, C.size_t(len(decls)), ctx, (C.PantoToolSourceInvokeBatchFn)(C.pantoGoToolSourceInvokeBatch), (C.PantoToolDestroyFn)(C.pantoGoCallbackDestroy)) != C.PANTO_OK { - dropCallback(ctx) - return lastError() - } - return nil -} - func cToolDecl(d ToolDecl) (C.PantoToolDecl, func()) { n := cSlice(d.Name) desc := cSlice(d.Description) -- cgit v1.3