Skip to content

Commit b588173

Browse files
committed
bugfixes
1 parent 0200ca6 commit b588173

File tree

11 files changed

+80
-57
lines changed

11 files changed

+80
-57
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ kotlinxDatetime = "0.6.2"
88
ktor = "3.1.1"
99
kotest = "6.0.0.M2"
1010

11-
xemanticKotlinTest = "1.8.10"
11+
xemanticKotlinTest = "1.9.0"
1212
xemanticAiToolSchema = "1.1.0"
1313
xemanticAiMoney = "0.2"
1414
xemanticAiFileMagic = "0.3.1"

src/commonMain/kotlin/Anthropic.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class Anthropic internal constructor(
172172
}.build()
173173
)
174174

175-
suspend fun create(
175+
private suspend fun create(
176176
request: MessageRequest
177177
): MessageResponse {
178178
val apiResponse = client.post("/v1/messages") {
@@ -185,8 +185,8 @@ class Anthropic internal constructor(
185185
resolvedModel = anthropicModel
186186
costCollector += costWithUsage
187187

188-
val toolMap = request.tools!!.associateBy { it.name }
189-
content.filterIsInstance<ToolUse>() .forEach { toolUse ->
188+
val toolMap = request.tools?.associateBy { it.name } ?: emptyMap()
189+
content.filterIsInstance<ToolUse>().forEach { toolUse ->
190190
val tool = toolMap[toolUse.name]
191191
if (tool != null) {
192192
toolUse.tool = tool

src/commonMain/kotlin/cost/Cost.kt

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.xemantic.ai.anthropic.cost
1818

19+
import com.xemantic.ai.anthropic.json.toPrettyJson
1920
import com.xemantic.ai.anthropic.usage.Usage
2021
import com.xemantic.ai.money.Money
2122
import com.xemantic.ai.money.Ratio
@@ -29,8 +30,8 @@ import kotlin.contracts.contract
2930
class Cost private constructor(
3031
val inputTokens: Money,
3132
val outputTokens: Money,
32-
val cacheCreationInputTokens: Money = inputTokens * Money.Ratio("1.25"),
33-
val cacheReadInputTokens: Money = inputTokens * Money.Ratio("0.1"),
33+
val cacheCreationInputTokens: Money,
34+
val cacheReadInputTokens: Money,
3435
) {
3536

3637
class Builder {
@@ -41,10 +42,18 @@ class Cost private constructor(
4142
var cacheReadInputTokens: Money? = null
4243

4344
fun build(): Cost = Cost(
44-
requireNotNull(inputTokens) { "inputTokens cannot be null" },
45-
requireNotNull(outputTokens) { "outputTokens cannot be null" },
46-
requireNotNull(cacheCreationInputTokens) { "cacheCreationInputTokens cannot be null" },
47-
requireNotNull(cacheReadInputTokens) { "cacheReadInputTokens cannot be null" }
45+
inputTokens = requireNotNull(inputTokens) { "inputTokens cannot be null" },
46+
outputTokens = requireNotNull(outputTokens) { "outputTokens cannot be null" },
47+
cacheCreationInputTokens = if (cacheCreationInputTokens != null) {
48+
cacheCreationInputTokens!!
49+
} else {
50+
inputTokens!! * Money.Ratio("1.25")
51+
},
52+
cacheReadInputTokens = if (cacheReadInputTokens != null) {
53+
cacheReadInputTokens!!
54+
} else {
55+
inputTokens!! * Money.Ratio("0.1")
56+
}
4857
)
4958

5059
}
@@ -80,7 +89,9 @@ class Cost private constructor(
8089
companion object {
8190
val ZERO = Cost(
8291
inputTokens = Money.ZERO,
83-
outputTokens = Money.ZERO
92+
outputTokens = Money.ZERO,
93+
cacheCreationInputTokens = Money.ZERO,
94+
cacheReadInputTokens = Money.ZERO
8495
)
8596
}
8697

@@ -106,6 +117,8 @@ class Cost private constructor(
106117
return result
107118
}
108119

120+
override fun toString(): String = toPrettyJson()
121+
109122
}
110123

111124
@OptIn(ExperimentalContracts::class)

src/commonMain/kotlin/cost/CostCollection.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.xemantic.ai.anthropic.cost
1818

19+
import com.xemantic.ai.anthropic.json.toPrettyJson
1920
import com.xemantic.ai.anthropic.usage.Usage
2021
import com.xemantic.ai.anthropic.util.update
2122
import kotlinx.serialization.Serializable
@@ -41,6 +42,8 @@ data class CostWithUsage(
4142

4243
}
4344

45+
override fun toString(): String = toPrettyJson()
46+
4447
}
4548

4649
/**
@@ -70,6 +73,6 @@ class CostCollector {
7073
*
7174
* @return A string containing the current usage and cost.
7275
*/
73-
override fun toString(): String = "UsageAndCostCollector(${_costWithUsage.load()})"
76+
override fun toString(): String = "CostCollector ${_costWithUsage.load()}"
7477

7578
}

src/commonMain/kotlin/usage/Usage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.xemantic.ai.anthropic.usage
1818

19+
import com.xemantic.ai.anthropic.json.toPrettyJson
1920
import kotlinx.serialization.SerialName
2021
import kotlinx.serialization.Serializable
2122
import kotlin.contracts.ExperimentalContracts
@@ -93,6 +94,7 @@ class Usage private constructor(
9394
return result
9495
}
9596

97+
override fun toString(): String = toPrettyJson()
9698

9799
}
98100

src/commonTest/kotlin/cost/CostCollectorTest.kt

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,36 @@ class CostCollectorTest {
3737
@Test
3838
fun `toString should return String representation of UsageCollector`() {
3939
assert(
40-
CostCollector().toString() ==
41-
"UsageCollector(usage=" +
42-
"Usage(inputTokens=0, outputTokens=0, cacheCreationInputTokens=0, cacheReadInputTokens=0), cost=" +
43-
"Cost(inputTokens=0, outputTokens=0, cacheCreationInputTokens=0, cacheReadInputTokens=0))"
40+
CostCollector().toString() == """
41+
CostCollector {
42+
"cost": {
43+
"inputTokens": "0",
44+
"outputTokens": "0",
45+
"cacheCreationInputTokens": "0",
46+
"cacheReadInputTokens": "0"
47+
},
48+
"usage": {
49+
"input_tokens": 0,
50+
"output_tokens": 0,
51+
"cache_creation_input_tokens": 0,
52+
"cache_read_input_tokens": 0
53+
}
54+
}
55+
""".trimIndent()
4456
)
4557
}
4658

4759
@Test
4860
fun `Should update cost and usage`() {
4961
// given
5062
val collector = CostCollector()
63+
val usage = Usage {
64+
inputTokens = 1000
65+
outputTokens = 1000
66+
}
5167
val costWithUsage = CostWithUsage(
52-
usage = Usage {
53-
inputTokens = 1000
54-
outputTokens = 1000
55-
},
56-
cost = Model.Companion.DEFAULT.cost
68+
cost = Model.DEFAULT.cost * usage,
69+
usage = usage,
5770
)
5871

5972
// when
@@ -65,16 +78,14 @@ class CostCollectorTest {
6578
usage == Usage {
6679
inputTokens = 1000
6780
outputTokens = 1000
68-
cacheCreationInputTokens = 0
69-
cacheReadInputTokens = 0
7081
}
7182
)
7283
have(
7384
cost == Cost {
7485
inputTokens = Money(".003")
7586
outputTokens = Money(".015")
76-
cacheCreationInputTokens = Money.Companion.ZERO
77-
cacheReadInputTokens = Money.Companion.ZERO
87+
cacheCreationInputTokens = Money.ZERO
88+
cacheReadInputTokens = Money.ZERO
7889
}
7990
)
8091
}
@@ -93,16 +104,16 @@ class CostCollectorTest {
93104

94105
// when
95106
collector += CostWithUsage(
107+
cost = Model.CLAUDE_3_5_SONNET.cost * testUsage,
96108
usage = testUsage,
97-
cost = Model.CLAUDE_3_5_SONNET.cost
98109
)
99110
collector += CostWithUsage(
100-
usage = testUsage,
101-
cost = Model.CLAUDE_3_5_HAIKU.cost
111+
cost = Model.CLAUDE_3_5_HAIKU.cost * testUsage,
112+
usage = testUsage
102113
)
103114
collector += CostWithUsage(
104-
usage = testUsage,
105-
cost = Model.CLAUDE_3_OPUS.cost
115+
cost = Model.CLAUDE_3_OPUS.cost * testUsage,
116+
usage = testUsage
106117
)
107118

108119
// then

src/commonTest/kotlin/cost/CostReportTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CostReportTest {
4545
outputTokens = 86
4646
}
4747
).apply {
48-
resolvedModel = Model.Companion.DEFAULT
48+
resolvedModel = Model.DEFAULT
4949
}
5050
val usageWithCost = response.costWithUsage
5151
collector += usageWithCost

src/commonTest/kotlin/cost/CostTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ class CostTest {
6161
val cost1 = Cost {
6262
inputTokens = Money("0.001")
6363
outputTokens = Money("0.002")
64-
cacheCreationInputTokens = Money.Companion.ZERO
65-
cacheReadInputTokens = Money.Companion.ZERO
64+
cacheCreationInputTokens = Money.ZERO
65+
cacheReadInputTokens = Money.ZERO
6666
}
6767
val cost2 = Cost {
6868
inputTokens = Money("0.003")
6969
outputTokens = Money("0.004")
70-
cacheCreationInputTokens = Money.Companion.ZERO
71-
cacheReadInputTokens = Money.Companion.ZERO
70+
cacheCreationInputTokens = Money.ZERO
71+
cacheReadInputTokens = Money.ZERO
7272
}
7373

7474
// when
@@ -78,8 +78,8 @@ class CostTest {
7878
result should {
7979
have(inputTokens == Money("0.004"))
8080
have(outputTokens == Money("0.006"))
81-
have(cacheCreationInputTokens == Money.Companion.ZERO)
82-
have(cacheReadInputTokens == Money.Companion.ZERO)
81+
have(cacheCreationInputTokens == Money.ZERO)
82+
have(cacheReadInputTokens == Money.ZERO)
8383
}
8484
}
8585

@@ -126,10 +126,10 @@ class CostTest {
126126
@Test
127127
fun `Should create ZERO Cost instance`() {
128128
Cost.ZERO should {
129-
have(inputTokens == Money.Companion.ZERO)
130-
have(outputTokens == Money.Companion.ZERO)
131-
have(cacheCreationInputTokens == Money.Companion.ZERO)
132-
have(cacheReadInputTokens == Money.Companion.ZERO)
129+
have(inputTokens == Money.ZERO)
130+
have(outputTokens == Money.ZERO)
131+
have(cacheCreationInputTokens == Money.ZERO)
132+
have(cacheReadInputTokens == Money.ZERO)
133133
}
134134
}
135135

src/commonTest/kotlin/message/MessageRequestTest.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class MessageRequestTest {
5959
]
6060
}
6161
],
62-
"max_tokens": 8182
62+
"max_tokens": 64000
6363
}
6464
"""
6565
// Note: max_tokens value will default to the max for a given model
@@ -93,7 +93,7 @@ class MessageRequestTest {
9393
]
9494
}
9595
],
96-
"max_tokens": 8182
96+
"max_tokens": 64000
9797
}
9898
"""
9999
// Note: max_tokens value will default to the max for a given model
@@ -127,7 +127,7 @@ class MessageRequestTest {
127127
]
128128
}
129129
],
130-
"max_tokens": 8182
130+
"max_tokens": 64000
131131
}
132132
"""
133133
// Note: max_tokens value will default to the max for a given model
@@ -193,7 +193,7 @@ class MessageRequestTest {
193193
]
194194
}
195195
],
196-
"max_tokens": 8182,
196+
"max_tokens": 64000,
197197
"tools": [
198198
{
199199
"type": "computer_20250124",
@@ -267,7 +267,7 @@ class MessageRequestTest {
267267
]
268268
}
269269
],
270-
"max_tokens": 8182,
270+
"max_tokens": 64000,
271271
"tool_choice": {
272272
"type": "tool",
273273
"name": "get_weather",

src/commonTest/kotlin/tool/ToolUseTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ToolUseTest {
4646
val initialResponse = client.messages.create {
4747
messages = conversation
4848
tools = mathTools
49-
toolChoice = ToolChoice.Companion.Tool<Calculator>()
49+
toolChoice = ToolChoice.Tool<Calculator>()
5050
}
5151
conversation += initialResponse
5252

@@ -176,7 +176,7 @@ class ToolUseTest {
176176
system(systemPrompt)
177177
messages = conversation
178178
tools = mathTools
179-
toolChoice = ToolChoice.Companion.Tool<FibonacciCalculator>()
179+
toolChoice = ToolChoice.Tool<FibonacciCalculator>()
180180
}
181181
conversation += fibonacciResponse
182182

@@ -194,7 +194,7 @@ class ToolUseTest {
194194
val calculatorResponse = client.messages.create {
195195
messages = conversation
196196
tools = mathTools
197-
toolChoice = ToolChoice.Companion.Tool<Calculator>()
197+
toolChoice = ToolChoice.Tool<Calculator>()
198198
}
199199
conversation += calculatorResponse
200200

src/jvmMain/kotlin/JavaAnthropic.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ class JavaAnthropic private constructor(
4444
fun createBlocking(
4545
builder: Consumer<MessageRequest.Builder>
4646
): MessageResponse = runBlocking {
47-
val kotlinBuilder = MessageRequest.Builder()
48-
builder.accept(kotlinBuilder)
49-
anthropic.messages.create(kotlinBuilder.build())
47+
anthropic.messages.create { builder.accept(this) }
5048
}
5149

5250
}
@@ -56,8 +54,4 @@ class JavaAnthropic private constructor(
5654

5755
}
5856

59-
inline fun <reified T> noOpConsumer(): Consumer<T> = object : Consumer<T> {
60-
override fun accept(any: T) {
61-
/* do nothing*/
62-
}
63-
}
57+
inline fun <reified T> noOpConsumer(): Consumer<T> = Consumer<T> { /* do nothing*/ }

0 commit comments

Comments
 (0)