You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Move the real type definitions into pkg/* and leave aliases behind in internal/*, reversing the current direction so the public API is the source of truth.
Problem
Every public package is a type-alias facade over an internal one:
The public API is undocumented. pkg.go.dev does not publish internal/ docs, so a consumer sees type ChatMessage = llm.ChatMessage and cannot see a single field. For a library that is offered to external consumers, this is close to disqualifying.
No compiler-enforced boundary. Any refactor of an internal type is an immediate breaking change to downstream consumers, and nothing in review or CI shows it. The blast radius is invisible at the point of change.
The direction encodes the wrong intent.internal is where design happens and pkg follows. If the library is to be promoted, that has to reverse.
docs/public-agent-packages.md already commits to these packages as a supported surface, so the gap is between the stated intent and the mechanism.
Scope
Invert pkg/llm first — 4 internal dependencies makes it the lowest-risk starting point. Move ChatMessage, ContentBlock, ToolCall, ToolSchema, ChatOptions, ChatResponse, Usage, Client, and the role/tier types into pkg/llm.
Leave type X = pkg.X aliases in internal/llm so no internal call site changes in the same PR.
Repeat for pkg/session, pkg/memory, pkg/skill (2-3 dependencies each).
Part of #919. Phase 2 of the public library boundary track. LP-009.
Prerequisite: #927 (LP-008).
Blocks #929 (LP-010).
Summary
Move the real type definitions into
pkg/*and leave aliases behind ininternal/*, reversing the current direction so the public API is the source of truth.Problem
Every public package is a type-alias facade over an internal one:
Three consequences, in order of severity:
internal/docs, so a consumer seestype ChatMessage = llm.ChatMessageand cannot see a single field. For a library that is offered to external consumers, this is close to disqualifying.internalis where design happens andpkgfollows. If the library is to be promoted, that has to reverse.docs/public-agent-packages.mdalready commits to these packages as a supported surface, so the gap is between the stated intent and the mechanism.Scope
pkg/llmfirst — 4 internal dependencies makes it the lowest-risk starting point. MoveChatMessage,ContentBlock,ToolCall,ToolSchema,ChatOptions,ChatResponse,Usage,Client, and the role/tier types intopkg/llm.type X = pkg.Xaliases ininternal/llmso no internal call site changes in the same PR.pkg/session,pkg/memory,pkg/skill(2-3 dependencies each).pkg/toolsandpkg/agentloop, which refactor(tool): split internal/tool into core primitives and TARS app tools #927 has made tractable.pkg/tarsclientas is; it already has zero internal dependencies.internal/authandinternal/llmdefaults.Acceptance Criteria
go doc github.com/devlikebear/tars/pkg/llm ChatMessageshows the fields.examples/min-agentbuilds unchanged.Validation
go vet ./...and a doc-comment lint overpkg/make testmake test-diffmake lint-diffmake buildgo docinspection of each inverted packageOut of Scope
internal/agentruntime,workstore, or anything else that stays internal.