mirror of
https://github.com/anomalyco/opencode.git
synced 2026-06-01 19:05:38 +00:00
Migrate custom provider tests to instance fixtures
Migrate the next custom provider/model config tests to Effect-aware instance fixtures while keeping timing neutral and behavior unchanged.
This commit is contained in:
@@ -228,81 +228,65 @@ it.instance(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
test("custom model alias via config", async () => {
|
it.instance(
|
||||||
await using tmp = await tmpdir({
|
"custom model alias via config",
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
await Bun.write(
|
yield* setProcessEnv("ANTHROPIC_API_KEY", "test-api-key")
|
||||||
path.join(dir, "opencode.json"),
|
const providers = yield* Provider.Service.use((provider) => provider.list())
|
||||||
JSON.stringify({
|
expect(providers[ProviderID.anthropic]).toBeDefined()
|
||||||
$schema: "https://opencode.ai/config.json",
|
expect(providers[ProviderID.anthropic].models["my-alias"]).toBeDefined()
|
||||||
provider: {
|
expect(providers[ProviderID.anthropic].models["my-alias"].name).toBe("My Custom Alias")
|
||||||
anthropic: {
|
}),
|
||||||
models: {
|
{
|
||||||
"my-alias": {
|
config: {
|
||||||
id: "claude-sonnet-4-20250514",
|
provider: {
|
||||||
name: "My Custom Alias",
|
anthropic: {
|
||||||
},
|
models: {
|
||||||
},
|
"my-alias": {
|
||||||
|
id: "claude-sonnet-4-20250514",
|
||||||
|
name: "My Custom Alias",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
)
|
},
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
await withTestInstance({
|
)
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
await set(ctx, "ANTHROPIC_API_KEY", "test-api-key")
|
|
||||||
const providers = await list(ctx)
|
|
||||||
expect(providers[ProviderID.anthropic]).toBeDefined()
|
|
||||||
expect(providers[ProviderID.anthropic].models["my-alias"]).toBeDefined()
|
|
||||||
expect(providers[ProviderID.anthropic].models["my-alias"].name).toBe("My Custom Alias")
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("custom provider with npm package", async () => {
|
it.instance(
|
||||||
await using tmp = await tmpdir({
|
"custom provider with npm package",
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
await Bun.write(
|
const providers = yield* Provider.Service.use((provider) => provider.list())
|
||||||
path.join(dir, "opencode.json"),
|
expect(providers[ProviderID.make("custom-provider")]).toBeDefined()
|
||||||
JSON.stringify({
|
expect(providers[ProviderID.make("custom-provider")].name).toBe("Custom Provider")
|
||||||
$schema: "https://opencode.ai/config.json",
|
expect(providers[ProviderID.make("custom-provider")].models["custom-model"]).toBeDefined()
|
||||||
provider: {
|
}),
|
||||||
"custom-provider": {
|
{
|
||||||
name: "Custom Provider",
|
config: {
|
||||||
npm: "@ai-sdk/openai-compatible",
|
provider: {
|
||||||
api: "https://api.custom.com/v1",
|
"custom-provider": {
|
||||||
env: ["CUSTOM_API_KEY"],
|
name: "Custom Provider",
|
||||||
models: {
|
npm: "@ai-sdk/openai-compatible",
|
||||||
"custom-model": {
|
api: "https://api.custom.com/v1",
|
||||||
name: "Custom Model",
|
env: ["CUSTOM_API_KEY"],
|
||||||
tool_call: true,
|
models: {
|
||||||
limit: {
|
"custom-model": {
|
||||||
context: 128000,
|
name: "Custom Model",
|
||||||
output: 4096,
|
tool_call: true,
|
||||||
},
|
limit: {
|
||||||
},
|
context: 128000,
|
||||||
},
|
output: 4096,
|
||||||
options: {
|
|
||||||
apiKey: "custom-key",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
options: {
|
||||||
)
|
apiKey: "custom-key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
await withTestInstance({
|
)
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const providers = await list(ctx)
|
|
||||||
expect(providers[ProviderID.make("custom-provider")]).toBeDefined()
|
|
||||||
expect(providers[ProviderID.make("custom-provider")].name).toBe("Custom Provider")
|
|
||||||
expect(providers[ProviderID.make("custom-provider")].models["custom-model"]).toBeDefined()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it.instance(
|
it.instance(
|
||||||
"filters alpha provider models by default",
|
"filters alpha provider models by default",
|
||||||
@@ -324,66 +308,58 @@ experimentalModels.instance(
|
|||||||
{ config: alphaProviderConfig },
|
{ config: alphaProviderConfig },
|
||||||
)
|
)
|
||||||
|
|
||||||
test("custom DeepSeek openai-compatible model defaults interleaved reasoning field", async () => {
|
it.instance(
|
||||||
await using tmp = await tmpdir({
|
"custom DeepSeek openai-compatible model defaults interleaved reasoning field",
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
await Bun.write(
|
const providers = yield* Provider.Service.use((provider) => provider.list())
|
||||||
path.join(dir, "opencode.json"),
|
const provider = providers[ProviderID.make("custom-provider")]
|
||||||
JSON.stringify({
|
expect(provider.models["deepseek-r1"].capabilities.interleaved).toEqual({ field: "reasoning_content" })
|
||||||
$schema: "https://opencode.ai/config.json",
|
expect(provider.models["deepseek-details"].capabilities.interleaved).toEqual({ field: "reasoning_details" })
|
||||||
provider: {
|
expect(provider.models["custom-model"].capabilities.interleaved).toBe(false)
|
||||||
"custom-provider": {
|
expect(providers[ProviderID.make("custom-anthropic-provider")].models["deepseek-r1"].capabilities.interleaved).toBe(
|
||||||
name: "Custom Provider",
|
false,
|
||||||
npm: "@ai-sdk/openai-compatible",
|
)
|
||||||
api: "https://api.custom.com/v1",
|
}),
|
||||||
models: {
|
{
|
||||||
"deepseek-r1": {
|
config: {
|
||||||
name: "DeepSeek R1",
|
provider: {
|
||||||
},
|
"custom-provider": {
|
||||||
"deepseek-details": {
|
name: "Custom Provider",
|
||||||
name: "DeepSeek Details",
|
npm: "@ai-sdk/openai-compatible",
|
||||||
interleaved: { field: "reasoning_details" },
|
api: "https://api.custom.com/v1",
|
||||||
},
|
models: {
|
||||||
"custom-model": {
|
"deepseek-r1": {
|
||||||
name: "Custom Model",
|
name: "DeepSeek R1",
|
||||||
},
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
apiKey: "custom-key",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"custom-anthropic-provider": {
|
"deepseek-details": {
|
||||||
name: "Custom Anthropic Provider",
|
name: "DeepSeek Details",
|
||||||
npm: "@ai-sdk/anthropic",
|
interleaved: { field: "reasoning_details" },
|
||||||
api: "https://api.custom.com/v1",
|
},
|
||||||
models: {
|
"custom-model": {
|
||||||
"deepseek-r1": {
|
name: "Custom Model",
|
||||||
name: "DeepSeek R1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
apiKey: "custom-key",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
options: {
|
||||||
)
|
apiKey: "custom-key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"custom-anthropic-provider": {
|
||||||
|
name: "Custom Anthropic Provider",
|
||||||
|
npm: "@ai-sdk/anthropic",
|
||||||
|
api: "https://api.custom.com/v1",
|
||||||
|
models: {
|
||||||
|
"deepseek-r1": {
|
||||||
|
name: "DeepSeek R1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
apiKey: "custom-key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
await withTestInstance({
|
)
|
||||||
directory: tmp.path,
|
|
||||||
fn: async (ctx) => {
|
|
||||||
const providers = await list(ctx)
|
|
||||||
const provider = providers[ProviderID.make("custom-provider")]
|
|
||||||
expect(provider.models["deepseek-r1"].capabilities.interleaved).toEqual({ field: "reasoning_content" })
|
|
||||||
expect(provider.models["deepseek-details"].capabilities.interleaved).toEqual({ field: "reasoning_details" })
|
|
||||||
expect(provider.models["custom-model"].capabilities.interleaved).toBe(false)
|
|
||||||
expect(
|
|
||||||
providers[ProviderID.make("custom-anthropic-provider")].models["deepseek-r1"].capabilities.interleaved,
|
|
||||||
).toBe(false)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("env variable takes precedence, config merges options", async () => {
|
test("env variable takes precedence, config merges options", async () => {
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ Repeated setup work, long sleeps/timeouts, serial integration tests, filesystem/
|
|||||||
| HTTP listen PTY ticket tests restart the same listener topology twice | Folded directory-scoped ticket regression into the broader unsafe-ticket test | 7.051s | 6.170s | keep | Two targeted reruns passed after the change: 6.76s, 6.17s; still covers mint failure and successful same-directory upgrade. |
|
| HTTP listen PTY ticket tests restart the same listener topology twice | Folded directory-scoped ticket regression into the broader unsafe-ticket test | 7.051s | 6.170s | keep | Two targeted reruns passed after the change: 6.76s, 6.17s; still covers mint failure and successful same-directory upgrade. |
|
||||||
| File watcher readiness can write before async native subscriptions are active | Retried short readiness writes and accepted symlink-realpath HEAD events | failed | 4.62s | keep | Three sequential focused watcher runs passed: 4.62s, 4.57s, 4.64s; full suite no longer failed in `watcher.test.ts`. |
|
| File watcher readiness can write before async native subscriptions are active | Retried short readiness writes and accepted symlink-realpath HEAD events | failed | 4.62s | keep | Three sequential focused watcher runs passed: 4.62s, 4.57s, 4.64s; full suite no longer failed in `watcher.test.ts`. |
|
||||||
| First provider config/env/filtering block can use Effect-aware instance fixtures | Migrated six `tmpdir` + `withTestInstance` cases to `it.instance` | 6.06s | 6.07s | keep | Neutral timing, but removes manual config file writes and instance plumbing; use as the pattern for later provider slices. |
|
| First provider config/env/filtering block can use Effect-aware instance fixtures | Migrated six `tmpdir` + `withTestInstance` cases to `it.instance` | 6.06s | 6.07s | keep | Neutral timing, but removes manual config file writes and instance plumbing; use as the pattern for later provider slices. |
|
||||||
|
| Custom provider/model config cases can use Effect-aware instance fixtures | Migrated three more config-heavy provider cases to `it.instance` | 6.07s | 6.12s | keep | Neutral timing within noise, but continues removing manual config file writes on top of the first provider fixture PR. |
|
||||||
|
|
||||||
## Profiling Results
|
## Profiling Results
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user