Skip to content

Commit da4c0b1

Browse files
committed
anthropic calls can now be cached (by default)
1 parent c83621f commit da4c0b1

File tree

8 files changed

+84
-17
lines changed

8 files changed

+84
-17
lines changed

frontend/src/components/Consumption.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="text-center">
33
<v-chip prepend-icon="mdi-import" class="mx-2" variant="outlined" label v-if="inputToken !== undefined">
4-
{{(inputToken - cachedToken).toLocaleString()}}
4+
{{inputToken.toLocaleString()}}
55
</v-chip>
66
<v-chip prepend-icon="mdi-cached" class="mx-2" variant="outlined" label v-if="inputToken !== undefined && cachedToken">
77
{{cachedToken.toLocaleString()}}

frontend/wailsjs/go/models.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,10 +1688,27 @@ export namespace http {
16881688

16891689
export namespace llm {
16901690

1691+
export class AnthropicCache {
1692+
SystemMessage: boolean;
1693+
Tools: boolean;
1694+
Chat: boolean;
1695+
1696+
static createFrom(source: any = {}) {
1697+
return new AnthropicCache(source);
1698+
}
1699+
1700+
constructor(source: any = {}) {
1701+
if ('string' === typeof source) source = JSON.parse(source);
1702+
this.SystemMessage = source["SystemMessage"];
1703+
this.Tools = source["Tools"];
1704+
this.Chat = source["Chat"];
1705+
}
1706+
}
16911707
export class AnthropicConfig {
16921708
Token: common.Secret;
16931709
BaseUrl: string;
16941710
Model: string;
1711+
Cache?: AnthropicCache;
16951712

16961713
static createFrom(source: any = {}) {
16971714
return new AnthropicConfig(source);
@@ -1702,6 +1719,7 @@ export namespace llm {
17021719
this.Token = this.convertValues(source["Token"], common.Secret);
17031720
this.BaseUrl = source["BaseUrl"];
17041721
this.Model = source["Model"];
1722+
this.Cache = this.convertValues(source["Cache"], AnthropicCache);
17051723
}
17061724

17071725
convertValues(a: any, classs: any, asMap: boolean = false): any {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ require (
7272
gopkg.in/yaml.v3 v3.0.1 // indirect
7373
)
7474

75-
replace github.com/tmc/langchaingo => github.com/rainu/langchaingo v0.0.0-20250529115311-2c0e8fe0b340
75+
replace github.com/tmc/langchaingo => github.com/rainu/langchaingo v0.0.0-20250529142520-123929cc4bd7

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ github.com/rainu/go-command-chain v0.4.0 h1:qgrNbNsqkTfJHdwGzVuGPPK+p+XSnGAhAT/8
9999
github.com/rainu/go-command-chain v0.4.0/go.mod h1:RvLsDKnTGD9XoUY7nmBz73ayffI0bFCDH/EVJPRgfks=
100100
github.com/rainu/go-yacl v0.2.1 h1:BZdwonr/JA8RiE/8xptE9RKT0+COwyfTmyB7kiANGPw=
101101
github.com/rainu/go-yacl v0.2.1/go.mod h1:cZwUkCDYE1w6xlTUi6vCqdV1O3iLvM/govQdUn6I9NU=
102-
github.com/rainu/langchaingo v0.0.0-20250529115311-2c0e8fe0b340 h1:bPPPcONFkLvC2dq9e/fQ4z4t4R3/OF4qbMIlmHkLcXc=
103-
github.com/rainu/langchaingo v0.0.0-20250529115311-2c0e8fe0b340/go.mod h1:5TXP7bKcWjN05g9e2+MpqUXprf5jwI62Q2xGtAKLno8=
102+
github.com/rainu/langchaingo v0.0.0-20250529142520-123929cc4bd7 h1:sQyN78q6HJVyoCwfGhxIqkCGB41ds6Xd7QIORrrtEbM=
103+
github.com/rainu/langchaingo v0.0.0-20250529142520-123929cc4bd7/go.mod h1:5TXP7bKcWjN05g9e2+MpqUXprf5jwI62Q2xGtAKLno8=
104104
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
105105
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
106106
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=

internal/config/model/llm/anthropic.go

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,34 @@ import (
55
"github.com/rainu/ask-mai/internal/config/model/common"
66
iAnthropic "github.com/rainu/ask-mai/internal/llms/anthropic"
77
llmCommon "github.com/rainu/ask-mai/internal/llms/common"
8+
"github.com/rainu/go-yacl"
89
"github.com/tmc/langchaingo/llms/anthropic"
910
)
1011

1112
type AnthropicConfig struct {
1213
Token common.Secret `yaml:"api-key,omitempty" usage:"API Key"`
1314
BaseUrl string `yaml:"base-url,omitempty" usage:"BaseUrl"`
1415
Model string `yaml:"model,omitempty" usage:"Model"`
16+
17+
Cache AnthropicCache `yaml:"disable-cache,omitempty" usage:"disable "`
1518
}
1619

17-
func (c *AnthropicConfig) AsOptions() (opts []anthropic.Option) {
18-
if v := c.Token.GetOrPanicWithDefaultTimeout(); v != nil {
19-
opts = append(opts, anthropic.WithToken(string(v)))
20+
type AnthropicCache struct {
21+
SystemMessage *bool `yaml:"system-message,omitempty" usage:"system message cache"`
22+
Tools *bool `yaml:"tools,omitempty" usage:"tools cache"`
23+
Chat *bool `yaml:"chat,omitempty" usage:"chat cache"`
24+
}
25+
26+
func (c *AnthropicCache) SetDefaults() {
27+
if c.SystemMessage == nil {
28+
c.SystemMessage = yacl.P(false)
2029
}
21-
if c.BaseUrl != "" {
22-
opts = append(opts, anthropic.WithBaseURL(c.BaseUrl))
30+
if c.Tools == nil {
31+
c.Tools = yacl.P(false)
2332
}
24-
if c.Model != "" {
25-
opts = append(opts, anthropic.WithModel(c.Model))
33+
if c.Chat == nil {
34+
c.Chat = yacl.P(false)
2635
}
27-
28-
return
2936
}
3037

3138
func (c *AnthropicConfig) SetDefaults() {
@@ -45,6 +52,29 @@ func (c *AnthropicConfig) Validate() error {
4552
return nil
4653
}
4754

55+
func (c *AnthropicConfig) AsOptions() (opts []anthropic.Option) {
56+
if v := c.Token.GetOrPanicWithDefaultTimeout(); v != nil {
57+
opts = append(opts, anthropic.WithToken(string(v)))
58+
}
59+
if c.BaseUrl != "" {
60+
opts = append(opts, anthropic.WithBaseURL(c.BaseUrl))
61+
}
62+
if c.Model != "" {
63+
opts = append(opts, anthropic.WithModel(c.Model))
64+
}
65+
if c.Cache.SystemMessage != nil && !*c.Cache.SystemMessage {
66+
opts = append(opts, anthropic.WithCacheSystemMessage())
67+
}
68+
if c.Cache.Tools != nil && !*c.Cache.Tools {
69+
opts = append(opts, anthropic.WithCacheTools())
70+
}
71+
if c.Cache.Chat != nil && !*c.Cache.Chat {
72+
opts = append(opts, anthropic.WithCacheChat())
73+
}
74+
75+
return
76+
}
77+
4878
func (c *AnthropicConfig) BuildLLM() (llmCommon.Model, error) {
4979
return iAnthropic.New(c.AsOptions())
5080
}

internal/llms/anthropic/consumption.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
)
77

88
const (
9-
tokenKeyInput = "InputTokens"
10-
tokenKeyOutput = "OutputTokens"
9+
tokenKeyInput = "InputTokens"
10+
tokenKeyOutput = "OutputTokens"
11+
tokenKeyCachedCreation = "CacheCreationInputTokens"
12+
tokenKeyCachedRead = "CacheReadInputTokens"
1113
)
1214

1315
func (a *Anthropic) ConsumptionOf(resp *llms.ContentResponse) common.Consumption {
@@ -23,6 +25,12 @@ func (a *Anthropic) ConsumptionOf(resp *llms.ContentResponse) common.Consumption
2325
if t, ok := choice.GenerationInfo[tokenKeyOutput]; ok {
2426
result.output += uint64(t.(int))
2527
}
28+
if t, ok := choice.GenerationInfo[tokenKeyCachedCreation]; ok {
29+
result.cachedCreation += uint64(t.(int))
30+
}
31+
if t, ok := choice.GenerationInfo[tokenKeyCachedRead]; ok {
32+
result.cachedRead += uint64(t.(int))
33+
}
2634
}
2735

2836
return result
@@ -31,15 +39,23 @@ func (a *Anthropic) ConsumptionOf(resp *llms.ContentResponse) common.Consumption
3139
type consumption struct {
3240
input uint64
3341
output uint64
42+
43+
cachedCreation uint64
44+
cachedRead uint64
3445
}
3546

3647
func (t *consumption) Summary() common.ConsumptionSummary {
37-
return common.NewSimpleConsumption(t.input, t.output)
48+
base := common.NewCachedConsumption(t.input, t.cachedRead, t.output)
49+
base["CacheCreation"] = t.cachedCreation
50+
51+
return base
3852
}
3953

4054
func (t *consumption) Add(add common.Consumption) {
4155
if token, ok := add.(*consumption); ok {
4256
t.input += token.input
4357
t.output += token.output
58+
t.cachedCreation += token.cachedCreation
59+
t.cachedRead += token.cachedRead
4460
}
4561
}

internal/llms/openai/consumption.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func (o *OpenAI) ConsumptionOf(resp *llms.ContentResponse) common.Consumption {
2727
}
2828
if t, ok := choice.GenerationInfo[tokenKeyCached]; ok {
2929
result.cached += uint64(t.(int))
30+
result.input -= uint64(t.(int)) // cached tokens are already part of the input
3031
}
3132
if t, ok := choice.GenerationInfo[tokenKeyReasoning]; ok {
3233
result.reason += uint64(t.(int))

internal/llms/openai/consumption_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ func TestOpenAI_ConsumptionOf(t *testing.T) {
3030
{
3131
GenerationInfo: map[string]interface{}{
3232
tokenKeyInput: 42,
33+
tokenKeyCached: 40,
3334
tokenKeyCompletion: 123,
3435
tokenKeyReasoning: 7,
3536
},
3637
},
3738
},
3839
},
3940
expectedTokens: consumption{
40-
input: 42,
41+
input: 2,
42+
cached: 40,
4143
output: 123,
4244
reason: 7,
4345
},

0 commit comments

Comments
 (0)