Skip to content

Commit bc64290

Browse files
authored
Merge pull request #1673 from ksylvan/0806-update-anthropic-to-support-opus-4-1
Add Support for Claude Opus 4.1 Model
2 parents 9ef3518 + fa13503 commit bc64290

File tree

9 files changed

+161
-51
lines changed

9 files changed

+161
-51
lines changed

.github/workflows/release.yml

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,39 @@ jobs:
2727
- name: Run tests
2828
run: go test -v ./...
2929

30+
get_version:
31+
name: Get version
32+
runs-on: ubuntu-latest
33+
outputs:
34+
latest_tag: ${{ steps.get_version.outputs.latest_tag }}
35+
steps:
36+
- name: Checkout code
37+
uses: actions/checkout@v4
38+
with:
39+
fetch-depth: 0
40+
41+
- name: Get version from source
42+
id: get_version
43+
shell: bash
44+
run: |
45+
if [ ! -f "nix/pkgs/fabric/version.nix" ]; then
46+
echo "Error: version.nix file not found"
47+
exit 1
48+
fi
49+
version=$(cat nix/pkgs/fabric/version.nix | tr -d '"' | tr -cd '0-9.')
50+
if [ -z "$version" ]; then
51+
echo "Error: version is empty"
52+
exit 1
53+
fi
54+
if ! echo "$version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' > /dev/null; then
55+
echo "Error: Invalid version format: $version"
56+
exit 1
57+
fi
58+
echo "latest_tag=v$version" >> $GITHUB_OUTPUT
59+
3060
build:
3161
name: Build binaries for Windows, macOS, and Linux
62+
needs: [test, get_version]
3263
runs-on: ${{ matrix.os }}
3364
permissions:
3465
contents: write
@@ -51,25 +82,14 @@ jobs:
5182
with:
5283
go-version-file: ./go.mod
5384

54-
- name: Determine OS Name
55-
id: os-name
56-
run: |
57-
if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then
58-
echo "OS=linux" >> $GITHUB_ENV
59-
elif [ "${{ matrix.os }}" == "macos-latest" ]; then
60-
echo "OS=darwin" >> $GITHUB_ENV
61-
else
62-
echo "OS=windows" >> $GITHUB_ENV
63-
fi
64-
shell: bash
65-
6685
- name: Build binary on Linux and macOS
6786
if: matrix.os != 'windows-latest'
6887
env:
69-
GOOS: ${{ env.OS }}
88+
GOOS: ${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}
7089
GOARCH: ${{ matrix.arch }}
7190
run: |
72-
go build -o fabric-${OS}-${{ matrix.arch }} ./cmd/fabric
91+
OS_NAME="${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}"
92+
go build -o fabric-${OS_NAME}-${{ matrix.arch }} ./cmd/fabric
7393
7494
- name: Build binary on Windows
7595
if: matrix.os == 'windows-latest'
@@ -83,8 +103,8 @@ jobs:
83103
if: matrix.os != 'windows-latest'
84104
uses: actions/upload-artifact@v4
85105
with:
86-
name: fabric-${OS}-${{ matrix.arch }}
87-
path: fabric-${OS}-${{ matrix.arch }}
106+
name: fabric-${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}-${{ matrix.arch }}
107+
path: fabric-${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}-${{ matrix.arch }}
88108

89109
- name: Upload build artifact
90110
if: matrix.os == 'windows-latest'
@@ -93,48 +113,49 @@ jobs:
93113
name: fabric-windows-${{ matrix.arch }}.exe
94114
path: fabric-windows-${{ matrix.arch }}.exe
95115

96-
- name: Get version from source
97-
id: get_version
98-
shell: bash
99-
run: |
100-
if [ ! -f "nix/pkgs/fabric/version.nix" ]; then
101-
echo "Error: version.nix file not found"
102-
exit 1
103-
fi
104-
version=$(cat nix/pkgs/fabric/version.nix | tr -d '"' | tr -cd '0-9.')
105-
if [ -z "$version" ]; then
106-
echo "Error: version is empty"
107-
exit 1
108-
fi
109-
if ! echo "$version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' > /dev/null; then
110-
echo "Error: Invalid version format: $version"
111-
exit 1
112-
fi
113-
echo "latest_tag=v$version" >> $GITHUB_ENV
114-
115116
- name: Create release if it doesn't exist
116117
shell: bash
117118
env:
118119
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
119120
run: |
120-
if ! gh release view ${{ env.latest_tag }} >/dev/null 2>&1; then
121-
gh release create ${{ env.latest_tag }} --title "Release ${{ env.latest_tag }}" --notes "Automated release for ${{ env.latest_tag }}"
121+
if ! gh release view ${{ needs.get_version.outputs.latest_tag }} >/dev/null 2>&1; then
122+
gh release create ${{ needs.get_version.outputs.latest_tag }} --title "Release ${{ needs.get_version.outputs.latest_tag }}" --notes "Automated release for ${{ needs.get_version.outputs.latest_tag }}"
122123
else
123-
echo "Release ${{ env.latest_tag }} already exists."
124+
echo "Release ${{ needs.get_version.outputs.latest_tag }} already exists."
124125
fi
125-
go run ./cmd/generate_changelog --sync-db
126-
go run ./cmd/generate_changelog --release ${{ env.latest_tag }}
127126
128127
- name: Upload release artifact
129128
if: matrix.os == 'windows-latest'
130129
env:
131130
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
132131
run: |
133-
gh release upload ${{ env.latest_tag }} fabric-windows-${{ matrix.arch }}.exe
132+
gh release upload ${{ needs.get_version.outputs.latest_tag }} fabric-windows-${{ matrix.arch }}.exe
134133
135134
- name: Upload release artifact
136135
if: matrix.os != 'windows-latest'
137136
env:
138137
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
139138
run: |
140-
gh release upload ${{ env.latest_tag }} fabric-${OS}-${{ matrix.arch }}
139+
OS_NAME="${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}"
140+
gh release upload ${{ needs.get_version.outputs.latest_tag }} fabric-${OS_NAME}-${{ matrix.arch }}
141+
142+
update_release_notes:
143+
needs: [build, get_version]
144+
runs-on: ubuntu-latest
145+
steps:
146+
- name: Checkout code
147+
uses: actions/checkout@v4
148+
with:
149+
fetch-depth: 0
150+
151+
- name: Set up Go
152+
uses: actions/setup-go@v4
153+
with:
154+
go-version-file: ./go.mod
155+
156+
- name: Update release description
157+
env:
158+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
159+
run: |
160+
go run ./cmd/generate_changelog --sync-db
161+
go run ./cmd/generate_changelog --release ${{ needs.get_version.outputs.latest_tag }}

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"jessevdk",
7474
"Jina",
7575
"joho",
76+
"Keploy",
7677
"Kore",
7778
"ksylvan",
7879
"Langdock",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### PR [#1673](https://github.com/danielmiessler/Fabric/pull/1673) by [ksylvan](https://github.com/ksylvan): Add Support for Claude Opus 4.1 Model
2+
3+
- Add Claude Opus 4.1 model support
4+
- Upgrade anthropic-sdk-go from v1.4.0 to v1.7.0
5+
- Fix temperature/topP parameter conflict for models
6+
- Refactor release workflow to use shared version job and simplify OS handling
7+
- Improve chat parameter defaults handling with domain constants

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.24.0
55
toolchain go1.24.2
66

77
require (
8-
github.com/anthropics/anthropic-sdk-go v1.4.0
8+
github.com/anthropics/anthropic-sdk-go v1.7.0
99
github.com/atotto/clipboard v0.1.4
1010
github.com/aws/aws-sdk-go-v2 v1.36.4
1111
github.com/aws/aws-sdk-go-v2/config v1.27.27

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
1919
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
2020
github.com/anthropics/anthropic-sdk-go v1.4.0 h1:fU1jKxYbQdQDiEXCxeW5XZRIOwKevn/PMg8Ay1nnUx0=
2121
github.com/anthropics/anthropic-sdk-go v1.4.0/go.mod h1:AapDW22irxK2PSumZiQXYUFvsdQgkwIWlpESweWZI/c=
22+
github.com/anthropics/anthropic-sdk-go v1.7.0 h1:5iVf5fG/2gqVsOce8mq02r/WdgqpokM/8DXg2Ue6C9Y=
23+
github.com/anthropics/anthropic-sdk-go v1.7.0/go.mod h1:3qSNQ5NrAmjC8A2ykuruSQttfqfdEYNZY5o8c0XSHB8=
2224
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
2325
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
2426
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=

internal/cli/flags.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
)
2121

2222
// Flags create flags struct. the users flags go into this, this will be passed to the chat struct in cli
23+
// Chat parameter defaults set in the struct tags must match domain.Default* constants
24+
2325
type Flags struct {
2426
Pattern string `short:"p" long:"pattern" yaml:"pattern" description:"Choose a pattern from the available patterns" default:""`
2527
PatternVariables map[string]string `short:"v" long:"variable" description:"Values for pattern variables, e.g. -v=#role:expert -v=#points:30"`

internal/domain/domain.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import "github.com/danielmiessler/fabric/internal/chat"
44

55
const ChatMessageRoleMeta = "meta"
66

7+
// Default values for chat options (must match cli/flags.go defaults)
8+
const (
9+
DefaultTemperature = 0.7
10+
DefaultTopP = 0.9
11+
DefaultPresencePenalty = 0.0
12+
DefaultFrequencyPenalty = 0.0
13+
)
14+
715
type ChatRequest struct {
816
ContextName string
917
SessionName string

internal/plugins/ai/anthropic/anthropic.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func NewClient() (ret *Client) {
4646
string(anthropic.ModelClaude_3_5_Sonnet_20240620), string(anthropic.ModelClaude3OpusLatest),
4747
string(anthropic.ModelClaude_3_Opus_20240229), string(anthropic.ModelClaude_3_Haiku_20240307),
4848
string(anthropic.ModelClaudeOpus4_20250514), string(anthropic.ModelClaudeSonnet4_20250514),
49+
string(anthropic.ModelClaudeOpus4_1_20250805),
4950
}
5051

5152
return
@@ -181,11 +182,19 @@ func (an *Client) buildMessageParams(msgs []anthropic.MessageParam, opts *domain
181182
params anthropic.MessageNewParams) {
182183

183184
params = anthropic.MessageNewParams{
184-
Model: anthropic.Model(opts.Model),
185-
MaxTokens: int64(an.maxTokens),
186-
TopP: anthropic.Opt(opts.TopP),
187-
Temperature: anthropic.Opt(opts.Temperature),
188-
Messages: msgs,
185+
Model: anthropic.Model(opts.Model),
186+
MaxTokens: int64(an.maxTokens),
187+
Messages: msgs,
188+
}
189+
190+
// Only set one of Temperature or TopP as some models don't allow both
191+
// Always set temperature to ensure consistent behavior (Anthropic default is 1.0, Fabric default is 0.7)
192+
if opts.TopP != domain.DefaultTopP {
193+
// User explicitly set TopP, so use that instead of temperature
194+
params.TopP = anthropic.Opt(opts.TopP)
195+
} else {
196+
// Use temperature (always set to ensure Fabric's default of 0.7, not Anthropic's 1.0)
197+
params.Temperature = anthropic.Opt(opts.Temperature)
189198
}
190199

191200
// Add Claude Code spoofing system message for OAuth authentication

internal/plugins/ai/anthropic/anthropic_test.go

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ func TestBuildMessageParams_WithoutSearch(t *testing.T) {
7272
client := NewClient()
7373
opts := &domain.ChatOptions{
7474
Model: "claude-3-5-sonnet-latest",
75-
Temperature: 0.7,
75+
Temperature: 0.8, // Use non-default value to ensure it gets set
76+
TopP: domain.DefaultTopP, // Use default TopP so temperature takes precedence
7677
Search: false,
7778
}
7879

@@ -90,6 +91,7 @@ func TestBuildMessageParams_WithoutSearch(t *testing.T) {
9091
t.Errorf("Expected model %s, got %s", opts.Model, params.Model)
9192
}
9293

94+
// When using non-default temperature, it should be set in params
9395
if params.Temperature.Value != opts.Temperature {
9496
t.Errorf("Expected temperature %f, got %f", opts.Temperature, params.Temperature.Value)
9597
}
@@ -99,7 +101,8 @@ func TestBuildMessageParams_WithSearch(t *testing.T) {
99101
client := NewClient()
100102
opts := &domain.ChatOptions{
101103
Model: "claude-3-5-sonnet-latest",
102-
Temperature: 0.7,
104+
Temperature: 0.8, // Use non-default value
105+
TopP: domain.DefaultTopP, // Use default TopP so temperature takes precedence
103106
Search: true,
104107
}
105108

@@ -135,7 +138,8 @@ func TestBuildMessageParams_WithSearchAndLocation(t *testing.T) {
135138
client := NewClient()
136139
opts := &domain.ChatOptions{
137140
Model: "claude-3-5-sonnet-latest",
138-
Temperature: 0.7,
141+
Temperature: 0.8, // Use non-default value
142+
TopP: domain.DefaultTopP, // Use default TopP so temperature takes precedence
139143
Search: true,
140144
SearchLocation: "America/Los_Angeles",
141145
}
@@ -256,3 +260,59 @@ func TestCitationFormatting(t *testing.T) {
256260
t.Errorf("Expected 2 unique citations, got %d", citationCount)
257261
}
258262
}
263+
264+
func TestBuildMessageParams_DefaultValues(t *testing.T) {
265+
client := NewClient()
266+
267+
// Test with default temperature - should always set temperature unless TopP is explicitly set
268+
opts := &domain.ChatOptions{
269+
Model: "claude-3-5-sonnet-latest",
270+
Temperature: domain.DefaultTemperature, // 0.7 - should be set to override Anthropic's 1.0 default
271+
TopP: domain.DefaultTopP, // 0.9 - default, so temperature takes precedence
272+
Search: false,
273+
}
274+
275+
messages := []anthropic.MessageParam{
276+
anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")),
277+
}
278+
279+
params := client.buildMessageParams(messages, opts)
280+
281+
// Temperature should be set when using default value to override Anthropic's 1.0 default
282+
if params.Temperature.Value != opts.Temperature {
283+
t.Errorf("Expected temperature %f, got %f", opts.Temperature, params.Temperature.Value)
284+
}
285+
286+
// TopP should not be set when using default value (temperature takes precedence)
287+
if params.TopP.Value != 0 {
288+
t.Errorf("Expected TopP to not be set (0), but got %f", params.TopP.Value)
289+
}
290+
}
291+
292+
func TestBuildMessageParams_ExplicitTopP(t *testing.T) {
293+
client := NewClient()
294+
295+
// Test with explicit TopP - should set TopP instead of temperature
296+
opts := &domain.ChatOptions{
297+
Model: "claude-3-5-sonnet-latest",
298+
Temperature: domain.DefaultTemperature, // 0.7 - ignored when TopP is explicitly set
299+
TopP: 0.5, // Non-default - should be set
300+
Search: false,
301+
}
302+
303+
messages := []anthropic.MessageParam{
304+
anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")),
305+
}
306+
307+
params := client.buildMessageParams(messages, opts)
308+
309+
// Temperature should not be set when TopP is explicitly set
310+
if params.Temperature.Value != 0 {
311+
t.Errorf("Expected temperature to not be set (0), but got %f", params.Temperature.Value)
312+
}
313+
314+
// TopP should be set when using non-default value
315+
if params.TopP.Value != opts.TopP {
316+
t.Errorf("Expected TopP %f, got %f", opts.TopP, params.TopP.Value)
317+
}
318+
}

0 commit comments

Comments
 (0)