Skip to content

fix(sdk): stop leaking fantasy types through pkg/kit.AgentConfig (#30)#32

Merged
ezynda3 merged 2 commits into
masterfrom
fix/30-sdk-dependency-leak
May 13, 2026
Merged

fix(sdk): stop leaking fantasy types through pkg/kit.AgentConfig (#30)#32
ezynda3 merged 2 commits into
masterfrom
fix/30-sdk-dependency-leak

Conversation

@ezynda3

@ezynda3 ezynda3 commented May 13, 2026

Copy link
Copy Markdown
Contributor

Description

pkg/kit/ is documented as the dependency-agnostic public SDK surface, but AgentConfig and the agent handler types were type X = internal/agent.X aliases over structs and signatures that referenced charm.land/fantasy.*. Any external consumer that wanted to populate CoreTools, ExtraTools, or ToolWrapper was forced to import "charm.land/fantasy", and fantasy.* showed up in the rendered godoc on pkg.go.dev.

This PR makes AgentConfig and the handler types Kit-owned, so the SDK contract is genuinely dependency-agnostic — matching the rules in AGENTS.md. An unexported (*AgentConfig).toInternal() translates to internal/agent.AgentConfig at the SDK boundary, where fantasy references are allowed. Because kit.Tool is still a type alias for the underlying tool type, slice and function fields convert without allocation.

Before (forced fantasy import):

import "charm.land/fantasy"

cfg := kit.AgentConfig{
    CoreTools:   []fantasy.AgentTool{ /* ... */ },
    ToolWrapper: func(in []fantasy.AgentTool) []fantasy.AgentTool { return in },
}

After (SDK-only):

cfg := kit.AgentConfig{
    CoreTools:   []kit.Tool{ /* ... */ },
    ToolWrapper: func(in []kit.Tool) []kit.Tool { return in },
}

go doc github.com/mark3labs/kit/pkg/kit AgentConfig no longer mentions fantasy.* anywhere.

Fixes #30

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactor

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally (go test ./... -race)
  • go vet ./... and golangci-lint run both pass
  • I have updated the documentation (pkg/kit/README.md "Re-exported Types")

Additional Information

Files changed

  • pkg/kit/types.goAgentConfig is now a real struct with SDK-typed fields; ToolCallHandler, ToolExecutionHandler, ToolResultHandler, ResponseHandler, StreamingResponseHandler, ToolCallContentHandler, and SpinnerFunc are now SDK-owned named types. Added (*AgentConfig).toInternal() conversion helper.
  • pkg/kit/kit.go — single call-site cast (agent.SpinnerFunc(opts.CLI.SpinnerFunc)) needed because SpinnerFunc is no longer an alias.
  • pkg/kit/agent_config_internal_test.go (new) — table-driven tests for toInternal(): nil receiver, scalar fields, tool slices, ToolWrapper invocation, OnMCPServerLoaded, and auth/token-factory wiring.
  • pkg/kit/types_test.go — added TestAgentConfigNoFantasyImport, TestAgentConfigToolWrapperSignature, TestSpinnerFuncSignature, TestHandlerTypesSignatures. The kit_test package file deliberately does not import charm.land/fantasy; the file compiling is the regression proof for the leak.
  • pkg/kit/README.md — updated the "Re-exported Types" section to record that AgentConfig and the handler types are now Kit-owned (not aliases).

Backwards compatibility

Source-level backwards compatible. All field names, types, and function signatures on AgentConfig and the handler types are unchanged from a consumer's point of view — the only difference is that the underlying type identities are now SDK-owned. Consumers that previously imported charm.land/fantasy only to satisfy these signatures can now drop that import.

Verification

  • go test ./... -race — all packages pass
  • go vet ./... — clean
  • golangci-lint run ./... — 0 issues
  • go doc ./pkg/kit AgentConfig — no fantasy.* references
  • Interactive TUI smoke test (tmux): prompt round-trip + bash tool call both work
  • ACP smoke test (scripts/acp_smoke_test.py) against opencode/kimi-k2.5: 67 streaming updates, stopReason: end_turn

Summary by CodeRabbit

  • New Features
    • Introduced MCPTaskConfig for customizing MCP task execution behavior with per-server mode overrides, TTL settings, polling intervals, and progress tracking callbacks.
  • Documentation
    • Expanded README documentation with detailed type export information and clarification on SDK-owned vs. re-exported types.
  • Tests
    • Added regression test suite for agent configuration conversion.

Review Change Stack

Replace the alias-based AgentConfig and handler types with SDK-owned
structs and function types. CoreTools / ExtraTools / ToolWrapper now
accept []kit.Tool, and the handler types (ToolCallHandler,
ToolExecutionHandler, ToolResultHandler, ResponseHandler,
StreamingResponseHandler, ToolCallContentHandler) plus SpinnerFunc are
declared in pkg/kit/ with signatures that reference only SDK types.

Consumers no longer need to import charm.land/fantasy to populate an
AgentConfig or assign a handler. go doc pkg/kit AgentConfig output no
longer mentions fantasy.*.

- Add unexported (*AgentConfig).toInternal() to convert at the SDK
  boundary; Tool is still an alias for the underlying tool type, so
  slice and function fields convert without allocation.
- Add agent_config_internal_test.go covering nil receiver, scalar
  fields, tool slices, ToolWrapper invocation, OnMCPServerLoaded, and
  auth/token-factory wiring.
- Add types_test.go cases that populate AgentConfig and SpinnerFunc
  without importing fantasy -- the file compiling is the regression
  proof for the leak.
- Update pkg/kit/README.md Re-exported Types section to record that
  AgentConfig and the handler types are now Kit-owned.

Fixes #30
@mark-iii-labs-huly

Copy link
Copy Markdown

Connected to Huly®: KIT-33

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR refactors the pkg/kit public SDK boundary to eliminate dependency leakage of charm.land/fantasy types. It replaces bare type-alias re-exports with SDK-owned wrapper structs and explicit function types, introduces MCP task-level configuration, and validates the new contract through comprehensive tests and updated documentation.

Changes

SDK Type System Refactoring

Layer / File(s) Summary
SDK-Owned Type Definitions and Conversion Logic
pkg/kit/types.go
Adds internal/tools import and replaces internal/agent type-alias re-exports with SDK-owned DebugLogger interface, AgentConfig struct (with fields for model config, MCP config, auth/token/debug wiring, tool selection and wrapping, MCP-load callback, and task config), explicit callback function types (ToolCallHandler, ToolExecutionHandler, ToolResultHandler, ResponseHandler, StreamingResponseHandler, ToolCallContentHandler), and toInternal() conversion method mapping SDK config to internal agent config. SpinnerFunc is now an explicit function type rather than an alias.
MCPTaskConfig Configuration and Conversion
pkg/kit/mcp_tasks.go
Introduces exported MCPTaskConfig struct with per-server mode overrides, TTL, polling intervals, timeout, and progress callback. Implements toToolsConfig() to translate SDK-level configuration into internal tools.MCPTaskConfig, including per-server mode mapping and progress handler wrapping.
Kit.New() Type Conversion for SpinnerFunc
pkg/kit/kit.go
Updates Kit.New() to explicitly convert opts.CLI.SpinnerFunc using the new SpinnerFunc type definition.
SDK Type Signature and Behavior Tests
pkg/kit/types_test.go
Adds compile-time tests verifying AgentConfig populates without fantasy import, ToolWrapper signature matches func([]kit.Tool) []kit.Tool, SpinnerFunc has signature func(fn func() error) error, and handler function types accept documented parameter lists.
AgentConfig.toInternal() Conversion Tests
pkg/kit/agent_config_internal_test.go
Comprehensive regression test suite (TestAgentConfigToInternal) validating nil handling, scalar field round-tripping, tool slice propagation, ToolWrapper delegation, OnMCPServerLoaded propagation, DebugLogger forwarding, MCPTaskConfig propagation including per-server mode and progress handler, and AuthHandler/TokenStoreFactory wiring. Includes fakeAuthHandler and fakeDebugLogger test doubles.
Documentation of SDK Type Contract
pkg/kit/README.md
Updates "Re-exported Types" section to clarify SDK-owned vs. re-exported types, expands Go code listing with explicit LLM* alias documentation and complete agent-configuration type categories (debug logger, MCP task config, tool/response/streaming handlers, spinner).

Sequence Diagram(s)

sequenceDiagram
  participant SDKConsumer as SDK Consumer
  participant AgentConfig as AgentConfig (SDK)
  participant toInternal as toInternal()
  participant InternalAgent as agent.AgentConfig
  
  SDKConsumer->>AgentConfig: populate DebugLogger, AuthHandler, TokenStoreFactory
  SDKConsumer->>AgentConfig: set CoreTools, ToolWrapper
  SDKConsumer->>AgentConfig: set MCPTaskConfig with Progress callback
  AgentConfig->>toInternal: convert SDK config
  toInternal->>InternalAgent: wire converted auth/token/debug hooks
  toInternal->>InternalAgent: assign tools and tool wrapper
  toInternal->>InternalAgent: convert MCPTaskConfig to internal.tools.MCPTaskConfig
  InternalAgent-->>SDKConsumer: ready for Kit.New()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • mark3labs/kit#22: Adds internal agent/tool MCP task configuration that is now plumbed through the new SDK-level MCPTaskConfig and its conversion logic in this PR.

Poem

🐰 The aliases vanished, the types stand tall,
SDK-owned now, no fantasy call,
MCPTaskConfig blooms with progress in tow,
Tests validate conversion—the refactor's aglow! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(sdk): stop leaking fantasy types through pkg/kit.AgentConfig (#30)' clearly and concisely summarizes the main objective of eliminating fantasy type leakage from the public SDK surface.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding objectives from issue #30: replaces alias-based AgentConfig with SDK-owned struct, creates SDK-owned handler types, adds toInternal() conversion, prevents fantasy imports in public signatures, updates documentation, and maintains source-level compatibility.
Out of Scope Changes check ✅ Passed All changes directly support the goal of eliminating fantasy type leakage: type conversions, test additions, documentation updates, and supporting types (DebugLogger, MCPTaskConfig) are scope-aligned with issue #30 requirements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/30-sdk-dependency-leak

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the public pkg/kit SDK surface so AgentConfig and related handler types no longer re-export internal/agent aliases that expose charm.land/fantasy.* in consumer code and rendered godoc, aligning with the dependency-agnostic boundary described in AGENTS.md / issue #30.

Changes:

  • Replace kit.AgentConfig and agent handler type aliases with Kit-owned types and add an internal conversion helper (*AgentConfig).toInternal().
  • Adjust pkg/kit.New to cast opts.CLI.SpinnerFunc into the internal agent spinner function type.
  • Add regression tests ensuring consumers can use AgentConfig and handler types without importing charm.land/fantasy, plus conversion-focused tests for toInternal(), and update SDK documentation.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/kit/types.go Introduces Kit-owned AgentConfig + handler types, adds toInternal() conversion, and makes SpinnerFunc a named SDK type.
pkg/kit/kit.go Casts SDK SpinnerFunc to internal agent.SpinnerFunc at the setup boundary.
pkg/kit/agent_config_internal_test.go Adds unit tests validating AgentConfig.toInternal() conversion behavior.
pkg/kit/types_test.go Adds compile-time/usage tests proving AgentConfig and handler types don’t require a fantasy import.
pkg/kit/README.md Updates documentation to reflect Kit-owned agent configuration and callback types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/kit/types.go
Comment on lines +146 to +157
out := &agent.AgentConfig{
ModelConfig: c.ModelConfig,
MCPConfig: c.MCPConfig,
SystemPrompt: c.SystemPrompt,
MaxSteps: c.MaxSteps,
StreamingEnabled: c.StreamingEnabled,
CoreTools: c.CoreTools,
DisableCoreTools: c.DisableCoreTools,
ExtraTools: c.ExtraTools,
ToolWrapper: c.ToolWrapper,
OnMCPServerLoaded: c.OnMCPServerLoaded,
}
The first revision of the SDK-owned AgentConfig dropped two fields that
internal/agent.AgentConfig carried: DebugLogger (tools.DebugLogger) and
MCPTaskConfig (tools.MCPTaskConfig). Restore them with SDK-owned
equivalents and wire them through toInternal().

- Add kit.DebugLogger interface (LogDebug / IsDebugEnabled) mirroring
  tools.DebugLogger. Interface-to-interface assignment is automatic
  because the method sets match.
- Add kit.MCPTaskConfig struct mirroring tools.MCPTaskConfig with SDK
  types (MCPTaskMode, MCPTaskProgressHandler) and a toToolsConfig()
  helper that converts at the SDK boundary.
- Wire both new fields in (*AgentConfig).toInternal().
- Extend agent_config_internal_test.go with cases for both fields.
- Document the additions in pkg/kit/README.md.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
pkg/kit/types.go (1)

3-17: ⚡ Quick win

Reorder imports to match repository grouping rules.

Line 14-16 keeps local imports mixed ahead of third-party imports. Group as stdlib → third-party → local with blank lines.

♻️ Proposed fix
 import (
 	"context"
 
 	"charm.land/fantasy"
+	"github.com/mark3labs/mcp-go/client/transport"
+	"github.com/mark3labs/mcp-go/server"
 
 	"github.com/mark3labs/kit/internal/agent"
 	"github.com/mark3labs/kit/internal/compaction"
 	"github.com/mark3labs/kit/internal/config"
 	"github.com/mark3labs/kit/internal/message"
 	"github.com/mark3labs/kit/internal/models"
 	"github.com/mark3labs/kit/internal/session"
 	"github.com/mark3labs/kit/internal/tools"
-	"github.com/mark3labs/mcp-go/client/transport"
-	"github.com/mark3labs/mcp-go/server"
 )

As per coding guidelines, **/*.go: "Organize imports in order: stdlib → third-party → local, with blank lines between groups".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/kit/types.go` around lines 3 - 17, The import block in types.go mixes
local packages with third-party packages; reorder the imports into three groups
separated by blank lines: standard library (e.g., context), third-party (e.g.,
"charm.land/fantasy", "github.com/mark3labs/mcp-go/client/transport",
"github.com/mark3labs/mcp-go/server"), and then local/internal packages (e.g.,
"github.com/mark3labs/kit/internal/agent", "compaction", "config", "message",
"models", "session", "tools"), so move the local
github.com/mark3labs/kit/internal/* imports to the last group and ensure blank
lines between groups to satisfy the repo import ordering rule.
pkg/kit/mcp_tasks.go (1)

136-163: ⚡ Quick win

De-duplicate toToolsConfig mapping to prevent drift.

Line 136-163 duplicates the same field/mode/progress mapping already present in mcpTaskOptions.toToolsConfig. Extract a shared private helper so future field additions can’t diverge across paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/kit/mcp_tasks.go` around lines 136 - 163, Extract the duplicated mapping
logic into a single unexported helper (e.g. mapMCPConfigToTools(cfg
MCPTaskConfig) tools.MCPTaskConfig) and have both MCPTaskConfig.toToolsConfig
and mcpTaskOptions.toToolsConfig call it; move the shared assignments
(DefaultTTL, PollInterval, MaxPollInterval, Timeout, PerServerMode conversion,
and Progress wrapper) into that helper and return the populated
tools.MCPTaskConfig so each original method can apply any additional
method-specific fields afterward.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/kit/mcp_tasks.go`:
- Around line 136-163: Extract the duplicated mapping logic into a single
unexported helper (e.g. mapMCPConfigToTools(cfg MCPTaskConfig)
tools.MCPTaskConfig) and have both MCPTaskConfig.toToolsConfig and
mcpTaskOptions.toToolsConfig call it; move the shared assignments (DefaultTTL,
PollInterval, MaxPollInterval, Timeout, PerServerMode conversion, and Progress
wrapper) into that helper and return the populated tools.MCPTaskConfig so each
original method can apply any additional method-specific fields afterward.

In `@pkg/kit/types.go`:
- Around line 3-17: The import block in types.go mixes local packages with
third-party packages; reorder the imports into three groups separated by blank
lines: standard library (e.g., context), third-party (e.g.,
"charm.land/fantasy", "github.com/mark3labs/mcp-go/client/transport",
"github.com/mark3labs/mcp-go/server"), and then local/internal packages (e.g.,
"github.com/mark3labs/kit/internal/agent", "compaction", "config", "message",
"models", "session", "tools"), so move the local
github.com/mark3labs/kit/internal/* imports to the last group and ensure blank
lines between groups to satisfy the repo import ordering rule.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59860ead-4487-4186-a3c7-1d72105f0b74

📥 Commits

Reviewing files that changed from the base of the PR and between 975c30a and 72365d4.

📒 Files selected for processing (6)
  • pkg/kit/README.md
  • pkg/kit/agent_config_internal_test.go
  • pkg/kit/kit.go
  • pkg/kit/mcp_tasks.go
  • pkg/kit/types.go
  • pkg/kit/types_test.go

@ezynda3 ezynda3 merged commit 64caed5 into master May 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants