Skip to content

Commit f338f33

Browse files
committed
add(smoke): anthropic continuity replay live validation
1 parent 65ec288 commit f338f33

3 files changed

Lines changed: 66 additions & 1 deletion

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@testable import AgentRunKit
2+
import Foundation
3+
import Testing
4+
5+
func assertSmokeAnthropicContinuityReplay(client: some LLMClient) async throws {
6+
let addTool = try makeSmokeAddTool()
7+
let configuration = AgentConfiguration(
8+
maxIterations: 5,
9+
systemPrompt: """
10+
You are a calculator assistant. When asked to add numbers, call the add tool exactly once.
11+
After receiving the tool result, immediately call finish with the numeric answer.
12+
Do not answer in plain text and do not call add again.
13+
"""
14+
)
15+
let agent = Agent<EmptyContext>(client: client, tools: [addTool], configuration: configuration)
16+
17+
var firstHistory: [ChatMessage]?
18+
for try await event in agent.stream(userMessage: "What is 17 + 25?", context: EmptyContext()) {
19+
guard case let .finished(_, _, _, history) = event.kind else { continue }
20+
firstHistory = history
21+
}
22+
let history = try #require(firstHistory)
23+
24+
let replayableAssistant = history.compactMap { message -> AssistantMessage? in
25+
guard case let .assistant(assistant) = message else { return nil }
26+
guard assistant.continuity?.substrate == .anthropicMessages else { return nil }
27+
return assistant
28+
}.first
29+
let continuity = try #require(replayableAssistant?.continuity)
30+
31+
#expect(continuity.substrate == .anthropicMessages)
32+
guard case let .object(payload) = continuity.payload,
33+
case let .array(blocks) = payload["content"]
34+
else {
35+
Issue.record("Expected Anthropic continuity payload with content array")
36+
return
37+
}
38+
#expect(!blocks.isEmpty)
39+
40+
let secondResult = try await agent.run(
41+
userMessage: "What was the previous sum? Reply with just the number.",
42+
history: history,
43+
context: EmptyContext()
44+
)
45+
#expect(try requireContent(secondResult).contains("42"))
46+
}

Tests/AgentRunKitTests/Smoke/AnthropicSmokeTests.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ struct AnthropicSmokeTests {
142142
try await assertSmokeReasoningGenerate(client: thinkingClient)
143143
}
144144

145+
@Test func continuityReplay() async throws {
146+
try await assertSmokeAnthropicContinuityReplay(client: client)
147+
}
148+
145149
@Test func approvalGate() async throws {
146150
try await assertSmokeApprovalGate(client: client)
147151
}

Tests/AgentRunKitTests/Smoke/VertexAnthropicSmokeTests.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ private let hasVertexAnthropicConfig =
1717
))
1818
struct VertexAnthropicSmokeTests {
1919
private func makeClient() throws -> VertexAnthropicClient {
20+
try VertexAnthropicClient(
21+
projectID: vertexProjectID,
22+
location: vertexLocation,
23+
model: anthropicModel,
24+
authService: GoogleAuthService(),
25+
maxTokens: 1024
26+
)
27+
}
28+
29+
private func makeBudgetClient() throws -> VertexAnthropicClient {
2030
try VertexAnthropicClient(
2131
projectID: vertexProjectID,
2232
location: vertexLocation,
@@ -29,6 +39,11 @@ struct VertexAnthropicSmokeTests {
2939

3040
@Test
3141
func budgetHistoryIntegrity() async throws {
32-
try await assertSmokeBudgetHistoryIntegrity(client: makeClient())
42+
try await assertSmokeBudgetHistoryIntegrity(client: makeBudgetClient())
43+
}
44+
45+
@Test
46+
func continuityReplay() async throws {
47+
try await assertSmokeAnthropicContinuityReplay(client: makeClient())
3348
}
3449
}

0 commit comments

Comments
 (0)