go.mod 🔗
@@ -47,7 +47,7 @@ require (
mvdan.cc/sh/v3 v3.12.1-0.20250902163504-3cf4fd5717a5
)
-replace charm.land/fantasy => ../fantasy/
+replace charm.land/fantasy => ../../fantasy/main/
require (
cloud.google.com/go v0.116.0 // indirect
kujtimiihoxha created
go.mod | 2 +-
internal/agent/agent.go | 6 ++++++
internal/agent/coordinator.go | 7 +++++++
internal/agent/tools/ls.go | 2 +-
internal/message/content.go | 33 ++++++++++++++++++++++++++++-----
5 files changed, 43 insertions(+), 7 deletions(-)
@@ -47,7 +47,7 @@ require (
mvdan.cc/sh/v3 v3.12.1-0.20250902163504-3cf4fd5717a5
)
-replace charm.land/fantasy => ../fantasy/
+replace charm.land/fantasy => ../../fantasy/main/
require (
cloud.google.com/go v0.116.0 // indirect
@@ -15,6 +15,7 @@ import (
"charm.land/fantasy"
"charm.land/fantasy/providers/anthropic"
"charm.land/fantasy/providers/bedrock"
+ "charm.land/fantasy/providers/google"
"charm.land/fantasy/providers/openai"
"github.com/charmbracelet/catwalk/pkg/catwalk"
"github.com/charmbracelet/crush/internal/agent/tools"
@@ -243,6 +244,11 @@ func (a *sessionAgent) Run(ctx context.Context, call SessionAgentCall) (*fantasy
currentAssistant.AppendReasoningSignature(reasoning.Signature)
}
}
+ if googleData, ok := reasoning.ProviderMetadata[google.Name]; ok {
+ if reasoning, ok := googleData.(*google.ReasoningMetadata); ok {
+ currentAssistant.AppendReasoningSignature(reasoning.Signature)
+ }
+ }
if openaiData, ok := reasoning.ProviderMetadata[openai.Name]; ok {
if reasoning, ok := openaiData.(*openai.ResponsesReasoningMetadata); ok {
currentAssistant.SetReasoningResponsesData(reasoning)
@@ -218,6 +218,13 @@ func getProviderOptions(model Model, tp catwalk.Type) fantasy.ProviderOptions {
options[openrouter.Name] = parsed
}
case google.Name:
+ _, hasReasoning := mergedOptions["thinking_config"]
+ if !hasReasoning {
+ mergedOptions["thinking_config"] = map[string]any{
+ "thinking_budget": 2000,
+ "include_thoughts": true,
+ }
+ }
parsed, err := google.ParseOptions(mergedOptions)
if err == nil {
options[google.Name] = parsed
@@ -16,7 +16,7 @@ import (
)
type LSParams struct {
- Path string `json:"path" description:"The path to the directory to list (defaults to current working directory)"`
+ Path string `json:"path,omitempty" description:"The path to the directory to list (defaults to current working directory)"`
Ignore []string `json:"ignore,omitempty" description:"List of glob patterns to ignore"`
Depth int `json:"depth,omitempty" description:"The maximum depth to traverse"`
}
@@ -9,6 +9,7 @@ import (
"charm.land/fantasy"
"charm.land/fantasy/providers/anthropic"
+ "charm.land/fantasy/providers/google"
"charm.land/fantasy/providers/openai"
"github.com/charmbracelet/catwalk/pkg/catwalk"
)
@@ -41,11 +42,12 @@ type ContentPart interface {
}
type ReasoningContent struct {
- Thinking string `json:"thinking"`
- Signature string `json:"signature"`
- ResponsesData *openai.ResponsesReasoningMetadata `json:"responses_data"`
- StartedAt int64 `json:"started_at,omitempty"`
- FinishedAt int64 `json:"finished_at,omitempty"`
+ Thinking string `json:"thinking"`
+ Signature string `json:"signature"`
+ ThoughtSignature string `json:"thought_signature"` // Used for google
+ ResponsesData *openai.ResponsesReasoningMetadata `json:"responses_data"`
+ StartedAt int64 `json:"started_at,omitempty"`
+ FinishedAt int64 `json:"finished_at,omitempty"`
}
func (tc ReasoningContent) String() string {
@@ -259,6 +261,22 @@ func (m *Message) AppendReasoningContent(delta string) {
}
}
+func (m *Message) AppendThoughtSignature(signature string) {
+ for i, part := range m.Parts {
+ if c, ok := part.(ReasoningContent); ok {
+ m.Parts[i] = ReasoningContent{
+ Thinking: c.Thinking,
+ ThoughtSignature: c.ThoughtSignature + signature,
+ Signature: c.Signature,
+ StartedAt: c.StartedAt,
+ FinishedAt: c.FinishedAt,
+ }
+ return
+ }
+ }
+ m.Parts = append(m.Parts, ReasoningContent{ThoughtSignature: signature})
+}
+
func (m *Message) AppendReasoningSignature(signature string) {
for i, part := range m.Parts {
if c, ok := part.(ReasoningContent); ok {
@@ -443,6 +461,11 @@ func (m *Message) ToAIMessage() []fantasy.Message {
if reasoning.ResponsesData != nil {
reasoningPart.ProviderOptions[openai.Name] = reasoning.ResponsesData
}
+ if reasoning.ThoughtSignature != "" {
+ reasoningPart.ProviderOptions[google.Name] = &google.ReasoningMetadata{
+ Signature: reasoning.ThoughtSignature,
+ }
+ }
parts = append(parts, reasoningPart)
}
for _, call := range m.ToolCalls() {