Skip to content

fix: pkg/kit leaks charm.land/fantasy types through type-alias re-exports #30

Description

@ezynda3

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

  1. As an external consumer, depend on github.com/mark3labs/kit/pkg/kit.

  2. Try to construct an AgentConfig with custom core tools:

    cfg := kit.AgentConfig{
        CoreTools: []???.AgentTool{ /* ... */ },
    }
  3. Observe that CoreTools requires []fantasy.AgentTool, forcing import "charm.land/fantasy" in consumer code.

  4. Run go doc github.com/mark3labs/kit/pkg/kit AgentConfigfantasy.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.StepMessagesHandlerfunc([]fantasy.Message)
  • agent.StepFinishHandlerfunc(int, bool, string, fantasy.Usage)
  • agent.StreamFinishHandlerfunc(fantasy.Usage, string)
  • agent.PrepareStepHandlerfunc(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:

  1. 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)
  2. 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).
  3. Replace the handler aliases (StepFinishHandler, PrepareStepHandler, …) with SDK-side function types whose signatures use LLM*.
  4. Add ConvertToLLM* / ConvertFromLLM* helpers between the wrapper types and the underlying fantasy.* representations.
  5. 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/kitinternal/agentfantasy) while making the public SDK genuinely dependency-agnostic, as advertised.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions