Allow optional API keys in desktop and mobile settings and share credential resolution across model requests. Missing stored credentials remain errors. Enable user-configured HTTP endpoints and pin signed AgentKit 0.13.1, which omits empty authentication headers for probes and inference. Validation: AgentKit's 216 tests and iOS's 461 tests passed, along with Swift formatting, localization checks, native screenshots, and real HTTP smoke tests on both apps. macOS passed 1419 of 1422 tests initially; existing Metrics timing, waveform PNG comparison, and MCP upload runner failures were observed. MCP and Metrics passed a focused rerun, while Metrics remains intermittent and waveform comparison still fails. iOS simulator LAN-IP access timed out; desktop LAN-IP and both platforms' localhost, loopback-IP, and local-domain requests passed.
33 lines
1.7 KiB
Swift
33 lines
1.7 KiB
Swift
import AgentKit
|
|
import Foundation
|
|
import TermindApplication
|
|
import Testing
|
|
|
|
/// Opt-in real-network smoke test against a disposable compatible model server.
|
|
/// TERMIND_MODEL_HTTP_TEST_URLS is a comma-separated list of base URLs. The server
|
|
/// answers ordinary prompts with OK and honors the title/command JSON contracts.
|
|
@Suite @MainActor
|
|
struct ProviderHTTPIntegrationTests {
|
|
@Test func nativeAppCanUseAnonymousHTTPEndpoints() async throws {
|
|
guard let urls = ProcessInfo.processInfo.environment["TERMIND_MODEL_HTTP_TEST_URLS"] else { return }
|
|
for base in urls.split(separator: ",").map(String.init) {
|
|
let provider = ModelProvider(
|
|
name: "Anonymous HTTP", inferenceURL: base + "/chat/completions", baseURL: base,
|
|
models: [AIModel(id: "test")])
|
|
let ai = AIConfigurationModel(modelProviders: [provider], persistsSecrets: false)
|
|
let secret = try #require(ai.modelSecret(for: provider))
|
|
#expect(secret.isEmpty)
|
|
let models = try await ModelCatalogClient().models(for: provider, secret: secret)
|
|
#expect(models.map(\.id) == ["test"])
|
|
let probe = try await ChatProbe().run(model: provider.models[0], on: provider, secret: secret)
|
|
#expect(probe.reply == "OK")
|
|
let command = CommandGeneratorController(ai: ai)
|
|
#expect(command.isLocallyAvailable)
|
|
#expect(try await command.generate(.init(draft: "say OK", shell: "zsh", cwd: "/tmp")) == "echo OK")
|
|
let title = try await ConversationTitleController(ai: ai).summarize(
|
|
.init(firstUserMessage: "Say OK", firstAssistantMessage: "OK"))
|
|
#expect(title == "Local model")
|
|
}
|
|
}
|
|
}
|