Bug Description
pkg/kit/ is documented as the dependency-agnostic public SDK surface. AGENTS.md states explicitly:
Internal dependency names (e.g. charm.land/fantasy) must not appear in exported function/method names, exported type names, godoc comments on exported symbols, or struct field names/tags on exported types.
In practice the SDK currently leaks fantasy.* into consumer code via type X = internal/agent.X aliases. Because internal/agent's public structs are themselves built out of fantasy.AgentTool, fantasy.Message, fantasy.Usage, fantasy.Response, etc., any SDK consumer constructing one of these aliased types is forced to import "charm.land/fantasy" directly. The dependency name also shows up in the rendered pkg.go.dev documentation for pkg/kit.
Expected: Consumers can use pkg/kit without importing charm.land/fantasy; godoc does not reference fantasy.*.
Actual: fantasy.* is part of the visible SDK contract.
Steps to Reproduce
-
As an external consumer, depend on github.com/mark3labs/kit/pkg/kit.
-
Try to construct an AgentConfig with custom core tools:
cfg := kit.AgentConfig{
CoreTools: []???.AgentTool{ /* ... */ },
}
-
Observe that CoreTools requires []fantasy.AgentTool, forcing import "charm.land/fantasy" in consumer code.
-
Run go doc github.com/mark3labs/kit/pkg/kit AgentConfig — fantasy.AgentTool appears in the rendered SDK documentation.
Relevant Code / Configuration
pkg/kit/types.go re-exports internal/agent types directly:
// pkg/kit/types.go:78-96
// ==== Agent Types (internal/agent/) ====
type AgentConfig = agent.AgentConfig
type (
ToolCallHandler = agent.ToolCallHandler
ToolExecutionHandler = agent.ToolExecutionHandler
ToolResultHandler = agent.ToolResultHandler
ResponseHandler = agent.ResponseHandler
StreamingResponseHandler = agent.StreamingResponseHandler
ToolCallContentHandler = agent.ToolCallContentHandler
)
The aliased internal/agent.AgentConfig is full of fantasy.*:
// internal/agent/agent.go:20-67
type AgentConfig struct {
// ...
CoreTools []fantasy.AgentTool
ExtraTools []fantasy.AgentTool
ToolWrapper func([]fantasy.AgentTool) []fantasy.AgentTool
// ...
}
Other leaks through aliases:
agent.StepMessagesHandler → func([]fantasy.Message)
agent.StepFinishHandler → func(int, bool, string, fantasy.Usage)
agent.StreamFinishHandler → func(fantasy.Usage, string)
agent.PrepareStepHandler → func(int, []fantasy.Message) []fantasy.Message
agent.GenerateWithLoopResult → fields FinalResponse *fantasy.Response, ConversationMessages []fantasy.Message, TotalUsage fantasy.Usage
Per AGENTS.md the SDK should use dependency-agnostic naming:
- Type aliases re-exporting dependency types: use
LLM* prefix (e.g. LLMMessage, LLMUsage, LLMResponse)
- Conversion helpers: use
ConvertToLLM* / ConvertFromLLM*
- Provider queries: use
GetLLMProviders (not GetFantasyProviders)
Affected Component
pkg/kit (public SDK surface) — interactions with internal/agent.
Kit Version
main @ 35b9360d
Additional Context
Why moving internal/agent into pkg/kit is not the fix
A tempting structural answer is "just promote internal/agent to pkg/kit/agent." That does not fix the leak — the offending struct fields and function signatures would still be exported and would still reference fantasy.*. The fix has to be at the SDK boundary, not in directory layout. Keeping internal/agent private (engine) and pkg/kit as a curated façade is the right shape; the façade is just doing too little wrapping today.
Proposed fix
Replace bare type-alias re-exports with wrapper structs and LLM*-prefixed aliases owned by pkg/kit:
- Define SDK-owned wrapper types in
pkg/kit whose fields use LLM* types per the naming convention:
kit.LLMTool (wraps fantasy.AgentTool)
kit.LLMMessage (wraps fantasy.Message)
kit.LLMUsage (wraps fantasy.Usage)
kit.LLMResponse (wraps fantasy.Response)
- Change
kit.AgentConfig from a type alias into a real struct in pkg/kit whose CoreTools / ExtraTools / ToolWrapper fields use []LLMTool. Translate to internal/agent.AgentConfig inside kit.New (private code, where fantasy references are allowed).
- Replace the handler aliases (
StepFinishHandler, PrepareStepHandler, …) with SDK-side function types whose signatures use LLM*.
- Add
ConvertToLLM* / ConvertFromLLM* helpers between the wrapper types and the underlying fantasy.* representations.
- For one release cycle, retain the old alias names as deprecated wrappers per the deprecation pattern in
AGENTS.md.
This preserves the layering (cmd/ → pkg/kit → internal/agent → fantasy) while making the public SDK genuinely dependency-agnostic, as advertised.
Bug Description
pkg/kit/is documented as the dependency-agnostic public SDK surface.AGENTS.mdstates explicitly:In practice the SDK currently leaks
fantasy.*into consumer code viatype X = internal/agent.Xaliases. Becauseinternal/agent's public structs are themselves built out offantasy.AgentTool,fantasy.Message,fantasy.Usage,fantasy.Response, etc., any SDK consumer constructing one of these aliased types is forced toimport "charm.land/fantasy"directly. The dependency name also shows up in the renderedpkg.go.devdocumentation forpkg/kit.Expected: Consumers can use
pkg/kitwithout importingcharm.land/fantasy; godoc does not referencefantasy.*.Actual:
fantasy.*is part of the visible SDK contract.Steps to Reproduce
As an external consumer, depend on
github.com/mark3labs/kit/pkg/kit.Try to construct an
AgentConfigwith custom core tools:Observe that
CoreToolsrequires[]fantasy.AgentTool, forcingimport "charm.land/fantasy"in consumer code.Run
go doc github.com/mark3labs/kit/pkg/kit AgentConfig—fantasy.AgentToolappears in the rendered SDK documentation.Relevant Code / Configuration
pkg/kit/types.gore-exportsinternal/agenttypes directly:The aliased
internal/agent.AgentConfigis full offantasy.*:Other leaks through aliases:
agent.StepMessagesHandler→func([]fantasy.Message)agent.StepFinishHandler→func(int, bool, string, fantasy.Usage)agent.StreamFinishHandler→func(fantasy.Usage, string)agent.PrepareStepHandler→func(int, []fantasy.Message) []fantasy.Messageagent.GenerateWithLoopResult→ fieldsFinalResponse *fantasy.Response,ConversationMessages []fantasy.Message,TotalUsage fantasy.UsagePer
AGENTS.mdthe SDK should use dependency-agnostic naming:Affected Component
pkg/kit(public SDK surface) — interactions withinternal/agent.Kit Version
main@35b9360dAdditional Context
Why moving
internal/agentintopkg/kitis not the fixA tempting structural answer is "just promote
internal/agenttopkg/kit/agent." That does not fix the leak — the offending struct fields and function signatures would still be exported and would still referencefantasy.*. The fix has to be at the SDK boundary, not in directory layout. Keepinginternal/agentprivate (engine) andpkg/kitas a curated façade is the right shape; the façade is just doing too little wrapping today.Proposed fix
Replace bare type-alias re-exports with wrapper structs and
LLM*-prefixed aliases owned bypkg/kit:pkg/kitwhose fields useLLM*types per the naming convention:kit.LLMTool(wrapsfantasy.AgentTool)kit.LLMMessage(wrapsfantasy.Message)kit.LLMUsage(wrapsfantasy.Usage)kit.LLMResponse(wrapsfantasy.Response)kit.AgentConfigfrom a type alias into a real struct inpkg/kitwhoseCoreTools/ExtraTools/ToolWrapperfields use[]LLMTool. Translate tointernal/agent.AgentConfiginsidekit.New(private code, wherefantasyreferences are allowed).StepFinishHandler,PrepareStepHandler, …) with SDK-side function types whose signatures useLLM*.ConvertToLLM*/ConvertFromLLM*helpers between the wrapper types and the underlyingfantasy.*representations.AGENTS.md.This preserves the layering (
cmd/→pkg/kit→internal/agent→fantasy) while making the public SDK genuinely dependency-agnostic, as advertised.