Skip to content

chains: export ChainCallOptions so custom Chain implementations can read options#1495

Open
zxuhan wants to merge 1 commit into
tmc:mainfrom
zxuhan:fix/chains-export-call-options
Open

chains: export ChainCallOptions so custom Chain implementations can read options#1495
zxuhan wants to merge 1 commit into
tmc:mainfrom
zxuhan:fix/chains-export-call-options

Conversation

@zxuhan
Copy link
Copy Markdown

@zxuhan zxuhan commented Apr 22, 2026

Summary

ChainCallOption is currently defined as:

type ChainCallOption func(*chainCallOption)

where chainCallOption is unexported. That makes it impossible to implement the chains.Chain interface from outside the chains package while still respecting caller-supplied options — callers can pass a []ChainCallOption, but a custom implementation has no way to construct a *chainCallOption to invoke the functions against, and no way to read the resulting field values.

This PR exports the struct as ChainCallOptions (plural, to avoid colliding with the existing ChainCallOption function type), exports the *Set flags, and adds a public ApplyChainCallOptions helper:

type ChainCallOptions struct {
    Model    string
    ModelSet bool
    // ...
}

func ApplyChainCallOptions(options ...ChainCallOption) ChainCallOptions

Custom implementations can now write:

func (c *MyChain) Call(ctx context.Context, in map[string]any, opts ...chains.ChainCallOption) (map[string]any, error) {
    resolved := chains.ApplyChainCallOptions(opts...)
    if resolved.ModelSet { /* ... */ }
    // ...
}

Internal usage (NewLLMChain, GetLLMCallOptions) was switched over to ApplyChainCallOptions for consistency.

Compatibility

Renaming chainCallOptionChainCallOptions and the xxxSet flags → XxxSet is non-breaking: external callers could not reference the private type, so no existing import path changes. The ChainCallOption function type itself is unchanged at the signature level.

Fixes #1085.

Test plan

  • go build ./... clean
  • go vet ./chains/... ./agents/... clean
  • New TestApplyChainCallOptions_ExternalChain in chains_test (external package) demonstrates implementing chains.Chain from outside and reading caller options
  • New TestApplyChainCallOptions_Empty covers the zero-value path
  • Existing chains/ unit tests pass; only failing tests (TestLLMChainWithGoogleAI, TestConstitutionalChain) are pre-existing integration tests requiring external credentials

…ead options

ChainCallOption was declared as func(*chainCallOption), where
chainCallOption was unexported. Code outside the chains package could
accept a ChainCallOption slice but had no way to invoke the functions
or read the values the caller set, making it impossible to implement
the Chain interface externally while respecting caller options.

Export the struct as ChainCallOptions with exported Set flags and add
ApplyChainCallOptions as the entry point for custom implementations.
Internal uses in this package now go through ApplyChainCallOptions too.

Fixes tmc#1085.
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.

It's impossible to implement the chains.Chain interface because it depends on a private struct

1 participant