dialekt 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -10
- package/TESTING.md +29 -29
- package/dist/cli/main.d.mts +1 -1
- package/dist/cli/main.mjs +549 -362
- package/dist/formatters-De4Q-X1d.mjs +516 -435
- package/dist/index.d.mts +162 -25
- package/dist/index.mjs +119 -34
- package/package.json +3 -3
- package/pnpm-workspace.yaml +3 -3
- package/src/adapter/types.test.ts +57 -57
- package/src/adapter/types.ts +7 -4
- package/src/benchmark/metrics.test.ts +141 -69
- package/src/benchmark/metrics.ts +6 -6
- package/src/benchmark/report.test.ts +38 -38
- package/src/benchmark/report.ts +6 -6
- package/src/benchmark/runner.test.ts +70 -72
- package/src/benchmark/runner.ts +4 -4
- package/src/cli/commands/add.test.ts +90 -109
- package/src/cli/commands/add.ts +40 -28
- package/src/cli/commands/benchmark.test.ts +77 -64
- package/src/cli/commands/benchmark.ts +64 -41
- package/src/cli/commands/languages.test.ts +45 -42
- package/src/cli/commands/languages.ts +16 -12
- package/src/cli/commands/missing.test.ts +143 -92
- package/src/cli/commands/missing.ts +24 -17
- package/src/cli/commands/translate.test.ts +79 -79
- package/src/cli/commands/translate.ts +41 -31
- package/src/cli/commands/unused.test.ts +62 -51
- package/src/cli/commands/unused.ts +18 -14
- package/src/cli/commands/validate.test.ts +130 -72
- package/src/cli/commands/validate.ts +25 -20
- package/src/cli/config-resolution.test.ts +169 -49
- package/src/cli/config-resolution.ts +5 -7
- package/src/cli/format.test.ts +50 -50
- package/src/cli/format.ts +57 -60
- package/src/cli/formatters.test.ts +128 -106
- package/src/cli/formatters.ts +72 -95
- package/src/cli/main.ts +13 -13
- package/src/config/define-config.test.ts +44 -29
- package/src/config/define-config.ts +1 -1
- package/src/config/load-config.test.ts +21 -18
- package/src/config/load-config.ts +5 -5
- package/src/config/types.test.ts +50 -44
- package/src/config/types.ts +2 -2
- package/src/index.ts +22 -26
- package/src/keys/flatten.test.ts +52 -52
- package/src/keys/flatten.ts +7 -9
- package/src/sdk/file-io.test.ts +47 -59
- package/src/sdk/file-io.ts +2 -2
- package/src/sdk/node-layer.test.ts +18 -18
- package/src/sdk/node-layer.ts +2 -2
- package/src/sdk/php-array-reader.test.ts +49 -40
- package/src/sdk/php-array-reader.ts +5 -5
- package/src/translation/chunking.test.ts +52 -44
- package/src/translation/chunking.ts +1 -1
- package/src/translation/missing-keys.test.ts +86 -93
- package/src/translation/missing-keys.ts +4 -6
- package/src/translation/model-registry.test.ts +41 -32
- package/src/translation/model-registry.ts +9 -9
- package/src/translation/one-shot-strategy.test.ts +105 -86
- package/src/translation/one-shot-strategy.ts +10 -12
- package/src/translation/orchestrator.test.ts +90 -101
- package/src/translation/orchestrator.ts +26 -26
- package/src/translation/prompt.test.ts +76 -76
- package/src/translation/prompt.ts +2 -2
- package/src/translation/tool-loop-strategy.test.ts +134 -107
- package/src/translation/tool-loop-strategy.ts +14 -18
- package/src/translation/types.test.ts +22 -22
- package/src/translation/types.ts +3 -3
- package/tsdown.config.ts +3 -3
- package/vitest.config.ts +3 -3
|
@@ -1,179 +1,172 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import { Effect } from
|
|
3
|
-
import { computeMissingKeys } from
|
|
4
|
-
import type { TranslationAdapter } from
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { computeMissingKeys } from "./missing-keys.js";
|
|
4
|
+
import type { TranslationAdapter } from "../adapter/types.js";
|
|
5
5
|
|
|
6
|
-
describe(
|
|
7
|
-
it(
|
|
6
|
+
describe("computeMissingKeys", () => {
|
|
7
|
+
it("lists missing keys per resource/locale", async () => {
|
|
8
8
|
const adapter: TranslationAdapter = {
|
|
9
|
-
name:
|
|
9
|
+
name: "test",
|
|
10
10
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
11
|
-
listLocales: () => Effect.succeed([
|
|
12
|
-
listResources: () => Effect.succeed([{ key:
|
|
11
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
12
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
13
13
|
readResource: (locale: string) =>
|
|
14
|
-
Effect.succeed(
|
|
15
|
-
locale === 'en' ? { hello: 'Hello', bye: 'Bye' } : { hello: 'Hallo' },
|
|
16
|
-
),
|
|
14
|
+
Effect.succeed(locale === "en" ? { hello: "Hello", bye: "Bye" } : { hello: "Hallo" }),
|
|
17
15
|
writeResource: () => Effect.void,
|
|
18
16
|
};
|
|
19
17
|
|
|
20
|
-
const result = await Effect.runPromise(
|
|
21
|
-
computeMissingKeys(adapter,
|
|
22
|
-
) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
18
|
+
const result = (await Effect.runPromise(
|
|
19
|
+
computeMissingKeys(adapter, "en", ["de"]),
|
|
20
|
+
)) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
23
21
|
expect(result).toHaveLength(1);
|
|
24
|
-
expect(result[0]!.missing).toEqual([
|
|
22
|
+
expect(result[0]!.missing).toEqual(["bye"]);
|
|
25
23
|
});
|
|
26
24
|
|
|
27
|
-
it(
|
|
25
|
+
it("returns empty when nothing is missing", async () => {
|
|
28
26
|
const adapter: TranslationAdapter = {
|
|
29
|
-
name:
|
|
27
|
+
name: "test",
|
|
30
28
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
31
|
-
listLocales: () => Effect.succeed([
|
|
32
|
-
listResources: () => Effect.succeed([{ key:
|
|
33
|
-
readResource: () => Effect.succeed({ hello:
|
|
29
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
30
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
31
|
+
readResource: () => Effect.succeed({ hello: "Hello" }),
|
|
34
32
|
writeResource: () => Effect.void,
|
|
35
33
|
};
|
|
36
34
|
|
|
37
|
-
const result = await Effect.runPromise(
|
|
38
|
-
computeMissingKeys(adapter,
|
|
39
|
-
) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
35
|
+
const result = (await Effect.runPromise(
|
|
36
|
+
computeMissingKeys(adapter, "en", ["de"]),
|
|
37
|
+
)) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
40
38
|
expect(result).toHaveLength(0);
|
|
41
39
|
});
|
|
42
40
|
|
|
43
|
-
it(
|
|
41
|
+
it("handles multiple resources", async () => {
|
|
44
42
|
const adapter: TranslationAdapter = {
|
|
45
|
-
name:
|
|
43
|
+
name: "test",
|
|
46
44
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
47
|
-
listLocales: () => Effect.succeed([
|
|
45
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
48
46
|
listResources: () =>
|
|
49
47
|
Effect.succeed([
|
|
50
|
-
{ key:
|
|
51
|
-
{ key:
|
|
48
|
+
{ key: "auth", label: "auth" },
|
|
49
|
+
{ key: "validation", label: "validation" },
|
|
52
50
|
]),
|
|
53
51
|
readResource: (locale: string, resource) =>
|
|
54
52
|
Effect.succeed(
|
|
55
|
-
locale ===
|
|
56
|
-
? resource.key ===
|
|
57
|
-
? { login:
|
|
58
|
-
: { email:
|
|
59
|
-
: resource.key ===
|
|
60
|
-
? { login:
|
|
53
|
+
locale === "en"
|
|
54
|
+
? resource.key === "auth"
|
|
55
|
+
? { login: "Login" }
|
|
56
|
+
: { email: "Email" }
|
|
57
|
+
: resource.key === "auth"
|
|
58
|
+
? { login: "Anmelden" }
|
|
61
59
|
: {},
|
|
62
60
|
),
|
|
63
61
|
writeResource: () => Effect.void,
|
|
64
62
|
};
|
|
65
63
|
|
|
66
|
-
const result = await Effect.runPromise(
|
|
67
|
-
computeMissingKeys(adapter,
|
|
68
|
-
) as ReadonlyArray<{ resource: { label: string }; missing: readonly string[] }>;
|
|
64
|
+
const result = (await Effect.runPromise(
|
|
65
|
+
computeMissingKeys(adapter, "en", ["de"]),
|
|
66
|
+
)) as ReadonlyArray<{ resource: { label: string }; missing: readonly string[] }>;
|
|
69
67
|
expect(result).toHaveLength(1);
|
|
70
|
-
expect(result[0]!.resource.label).toBe(
|
|
71
|
-
expect(result[0]!.missing).toEqual([
|
|
68
|
+
expect(result[0]!.resource.label).toBe("validation");
|
|
69
|
+
expect(result[0]!.missing).toEqual(["email"]);
|
|
72
70
|
});
|
|
73
71
|
|
|
74
|
-
it(
|
|
72
|
+
it("handles multiple target locales", async () => {
|
|
75
73
|
const adapter: TranslationAdapter = {
|
|
76
|
-
name:
|
|
74
|
+
name: "test",
|
|
77
75
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
78
|
-
listLocales: () => Effect.succeed([
|
|
79
|
-
listResources: () => Effect.succeed([{ key:
|
|
80
|
-
readResource: (locale: string) =>
|
|
81
|
-
Effect.succeed(
|
|
82
|
-
locale === 'en' ? { hello: 'Hello' } : {},
|
|
83
|
-
),
|
|
76
|
+
listLocales: () => Effect.succeed(["en", "de", "fr"]),
|
|
77
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
78
|
+
readResource: (locale: string) => Effect.succeed(locale === "en" ? { hello: "Hello" } : {}),
|
|
84
79
|
writeResource: () => Effect.void,
|
|
85
80
|
};
|
|
86
81
|
|
|
87
|
-
const result = await Effect.runPromise(
|
|
88
|
-
computeMissingKeys(adapter,
|
|
89
|
-
) as ReadonlyArray<{ locale: string; missing: readonly string[] }>;
|
|
82
|
+
const result = (await Effect.runPromise(
|
|
83
|
+
computeMissingKeys(adapter, "en", ["de", "fr"]),
|
|
84
|
+
)) as ReadonlyArray<{ locale: string; missing: readonly string[] }>;
|
|
90
85
|
expect(result).toHaveLength(2);
|
|
91
86
|
const locales = result.map((r) => r.locale);
|
|
92
|
-
expect(locales).toContain(
|
|
93
|
-
expect(locales).toContain(
|
|
87
|
+
expect(locales).toContain("de");
|
|
88
|
+
expect(locales).toContain("fr");
|
|
94
89
|
});
|
|
95
90
|
|
|
96
|
-
it(
|
|
91
|
+
it("handles empty target locales", async () => {
|
|
97
92
|
const adapter: TranslationAdapter = {
|
|
98
|
-
name:
|
|
93
|
+
name: "test",
|
|
99
94
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
100
|
-
listLocales: () => Effect.succeed([
|
|
101
|
-
listResources: () => Effect.succeed([{ key:
|
|
95
|
+
listLocales: () => Effect.succeed(["en"]),
|
|
96
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
102
97
|
readResource: () => Effect.succeed({}),
|
|
103
98
|
writeResource: () => Effect.void,
|
|
104
99
|
};
|
|
105
100
|
|
|
106
|
-
const result = await Effect.runPromise(
|
|
107
|
-
computeMissingKeys(adapter,
|
|
108
|
-
) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
101
|
+
const result = (await Effect.runPromise(
|
|
102
|
+
computeMissingKeys(adapter, "en", []),
|
|
103
|
+
)) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
109
104
|
expect(result).toHaveLength(0);
|
|
110
105
|
});
|
|
111
106
|
|
|
112
|
-
it(
|
|
107
|
+
it("handles empty resources", async () => {
|
|
113
108
|
const adapter: TranslationAdapter = {
|
|
114
|
-
name:
|
|
109
|
+
name: "test",
|
|
115
110
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
116
|
-
listLocales: () => Effect.succeed([
|
|
111
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
117
112
|
listResources: () => Effect.succeed([]),
|
|
118
113
|
readResource: () => Effect.succeed({}),
|
|
119
114
|
writeResource: () => Effect.void,
|
|
120
115
|
};
|
|
121
116
|
|
|
122
|
-
const result = await Effect.runPromise(
|
|
123
|
-
computeMissingKeys(adapter,
|
|
124
|
-
) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
117
|
+
const result = (await Effect.runPromise(
|
|
118
|
+
computeMissingKeys(adapter, "en", ["de"]),
|
|
119
|
+
)) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
125
120
|
expect(result).toHaveLength(0);
|
|
126
121
|
});
|
|
127
122
|
|
|
128
|
-
it(
|
|
123
|
+
it("handles adapter readResource failure", async () => {
|
|
129
124
|
const adapter: TranslationAdapter = {
|
|
130
|
-
name:
|
|
125
|
+
name: "broken",
|
|
131
126
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
132
|
-
listLocales: () => Effect.succeed([
|
|
133
|
-
listResources: () => Effect.succeed([{ key:
|
|
134
|
-
readResource: () => Effect.fail(new Error(
|
|
127
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
128
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
129
|
+
readResource: () => Effect.fail(new Error("read failed") as never),
|
|
135
130
|
writeResource: () => Effect.void,
|
|
136
131
|
};
|
|
137
132
|
|
|
138
|
-
await expect(Effect.runPromise(computeMissingKeys(adapter,
|
|
133
|
+
await expect(Effect.runPromise(computeMissingKeys(adapter, "en", ["de"]))).rejects.toThrow(
|
|
134
|
+
"read failed",
|
|
135
|
+
);
|
|
139
136
|
});
|
|
140
137
|
|
|
141
|
-
it(
|
|
138
|
+
it("handles all keys missing", async () => {
|
|
142
139
|
const adapter: TranslationAdapter = {
|
|
143
|
-
name:
|
|
140
|
+
name: "test",
|
|
144
141
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
145
|
-
listLocales: () => Effect.succeed([
|
|
146
|
-
listResources: () => Effect.succeed([{ key:
|
|
142
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
143
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
147
144
|
readResource: (locale: string) =>
|
|
148
|
-
Effect.succeed(
|
|
149
|
-
locale === 'en' ? { a: 'A', b: 'B', c: 'C' } : {},
|
|
150
|
-
),
|
|
145
|
+
Effect.succeed(locale === "en" ? { a: "A", b: "B", c: "C" } : {}),
|
|
151
146
|
writeResource: () => Effect.void,
|
|
152
147
|
};
|
|
153
148
|
|
|
154
|
-
const result = await Effect.runPromise(
|
|
155
|
-
computeMissingKeys(adapter,
|
|
156
|
-
) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
149
|
+
const result = (await Effect.runPromise(
|
|
150
|
+
computeMissingKeys(adapter, "en", ["de"]),
|
|
151
|
+
)) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
157
152
|
expect(result).toHaveLength(1);
|
|
158
|
-
expect(result[0]!.missing).toEqual([
|
|
153
|
+
expect(result[0]!.missing).toEqual(["a", "b", "c"]);
|
|
159
154
|
});
|
|
160
155
|
|
|
161
|
-
it(
|
|
156
|
+
it("ignores target keys not present in source", async () => {
|
|
162
157
|
const adapter: TranslationAdapter = {
|
|
163
|
-
name:
|
|
158
|
+
name: "test",
|
|
164
159
|
capabilities: { canCreateResource: true, unusedKeyDetection: false },
|
|
165
|
-
listLocales: () => Effect.succeed([
|
|
166
|
-
listResources: () => Effect.succeed([{ key:
|
|
160
|
+
listLocales: () => Effect.succeed(["en", "de"]),
|
|
161
|
+
listResources: () => Effect.succeed([{ key: "messages", label: "messages" }]),
|
|
167
162
|
readResource: (locale: string) =>
|
|
168
|
-
Effect.succeed(
|
|
169
|
-
locale === 'en' ? { a: 'A' } : { a: 'A-de', b: 'B-de' },
|
|
170
|
-
),
|
|
163
|
+
Effect.succeed(locale === "en" ? { a: "A" } : { a: "A-de", b: "B-de" }),
|
|
171
164
|
writeResource: () => Effect.void,
|
|
172
165
|
};
|
|
173
166
|
|
|
174
|
-
const result = await Effect.runPromise(
|
|
175
|
-
computeMissingKeys(adapter,
|
|
176
|
-
) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
167
|
+
const result = (await Effect.runPromise(
|
|
168
|
+
computeMissingKeys(adapter, "en", ["de"]),
|
|
169
|
+
)) as ReadonlyArray<{ missing: readonly string[] }>;
|
|
177
170
|
expect(result).toHaveLength(0);
|
|
178
171
|
});
|
|
179
172
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Effect } from
|
|
2
|
-
import type { TranslationAdapter, ResourceRef, AdapterReadError } from
|
|
3
|
-
import { diffKeys } from
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { TranslationAdapter, ResourceRef, AdapterReadError } from "../adapter/types.js";
|
|
3
|
+
import { diffKeys } from "../keys/flatten.js";
|
|
4
4
|
|
|
5
5
|
export interface MissingKeyEntry {
|
|
6
6
|
readonly adapter: string;
|
|
@@ -23,9 +23,7 @@ export function computeMissingKeys(
|
|
|
23
23
|
Effect.gen(function* () {
|
|
24
24
|
const targetMap = yield* adapter.readResource(locale, resource);
|
|
25
25
|
const missing = diffKeys(sourceMap, targetMap);
|
|
26
|
-
return missing.length > 0
|
|
27
|
-
? [{ adapter: adapter.name, locale, resource, missing }]
|
|
28
|
-
: [];
|
|
26
|
+
return missing.length > 0 ? [{ adapter: adapter.name, locale, resource, missing }] : [];
|
|
29
27
|
}),
|
|
30
28
|
);
|
|
31
29
|
return localeEntries.flat();
|
|
@@ -1,54 +1,63 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import { Effect, Either } from
|
|
3
|
-
import { resolveModel, UnknownProviderError } from
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Effect, Either } from "effect";
|
|
3
|
+
import { resolveModel, UnknownProviderError } from "./model-registry.js";
|
|
4
4
|
|
|
5
|
-
describe(
|
|
6
|
-
it(
|
|
7
|
-
const program = resolveModel({ provider:
|
|
8
|
-
const exit = await Effect.runPromise(Effect.either(program)) as Either.Either<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
describe("resolveModel", () => {
|
|
6
|
+
it("returns UnknownProviderError for unknown provider", async () => {
|
|
7
|
+
const program = resolveModel({ provider: "unknown", modelId: "x" });
|
|
8
|
+
const exit = (await Effect.runPromise(Effect.either(program))) as Either.Either<
|
|
9
|
+
unknown,
|
|
10
|
+
UnknownProviderError
|
|
11
|
+
>;
|
|
12
|
+
if (exit._tag === "Left") {
|
|
13
|
+
expect(exit.left._tag).toBe("UnknownProviderError");
|
|
14
|
+
expect(exit.left.provider).toBe("unknown");
|
|
12
15
|
} else {
|
|
13
|
-
throw new Error(
|
|
16
|
+
throw new Error("Expected Left");
|
|
14
17
|
}
|
|
15
18
|
});
|
|
16
19
|
|
|
17
|
-
it(
|
|
18
|
-
const program = resolveModel({ provider:
|
|
19
|
-
const exit = await Effect.runPromise(Effect.either(program)) as Either.Either<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
it("returns UnknownProviderError for empty provider string", async () => {
|
|
21
|
+
const program = resolveModel({ provider: "", modelId: "x" });
|
|
22
|
+
const exit = (await Effect.runPromise(Effect.either(program))) as Either.Either<
|
|
23
|
+
unknown,
|
|
24
|
+
UnknownProviderError
|
|
25
|
+
>;
|
|
26
|
+
if (exit._tag === "Left") {
|
|
27
|
+
expect(exit.left._tag).toBe("UnknownProviderError");
|
|
28
|
+
expect(exit.left.provider).toBe("");
|
|
23
29
|
} else {
|
|
24
|
-
throw new Error(
|
|
30
|
+
throw new Error("Expected Left");
|
|
25
31
|
}
|
|
26
32
|
});
|
|
27
33
|
|
|
28
|
-
it(
|
|
29
|
-
const program = resolveModel({ provider:
|
|
30
|
-
const exit = await Effect.runPromise(Effect.either(program)) as Either.Either<
|
|
34
|
+
it("resolves openai provider when package is available", async () => {
|
|
35
|
+
const program = resolveModel({ provider: "openai", modelId: "gpt-4o" });
|
|
36
|
+
const exit = (await Effect.runPromise(Effect.either(program))) as Either.Either<
|
|
37
|
+
unknown,
|
|
38
|
+
UnknownProviderError
|
|
39
|
+
>;
|
|
31
40
|
// Package is installed in this repo, so it should succeed
|
|
32
|
-
expect(exit._tag).toBe(
|
|
41
|
+
expect(exit._tag).toBe("Right");
|
|
33
42
|
});
|
|
34
43
|
|
|
35
|
-
it(
|
|
36
|
-
const err = new UnknownProviderError({ provider:
|
|
37
|
-
expect(err.provider).toBe(
|
|
38
|
-
expect(err._tag).toBe(
|
|
44
|
+
it("UnknownProviderError preserves provider in message", () => {
|
|
45
|
+
const err = new UnknownProviderError({ provider: "foo" });
|
|
46
|
+
expect(err.provider).toBe("foo");
|
|
47
|
+
expect(err._tag).toBe("UnknownProviderError");
|
|
39
48
|
});
|
|
40
49
|
|
|
41
|
-
it(
|
|
42
|
-
const providers = [
|
|
50
|
+
it("accepts all known providers without type error", () => {
|
|
51
|
+
const providers = ["openai", "anthropic", "google"] as const;
|
|
43
52
|
for (const provider of providers) {
|
|
44
53
|
// Should compile without error
|
|
45
|
-
const config = { provider, modelId:
|
|
54
|
+
const config = { provider, modelId: "test" };
|
|
46
55
|
expect(config.provider).toBe(provider);
|
|
47
56
|
}
|
|
48
57
|
});
|
|
49
58
|
|
|
50
|
-
it(
|
|
51
|
-
const config = { provider:
|
|
52
|
-
expect(config.modelId).toBe(
|
|
59
|
+
it("modelId is passed through", () => {
|
|
60
|
+
const config = { provider: "openai" as const, modelId: "gpt-4o" };
|
|
61
|
+
expect(config.modelId).toBe("gpt-4o");
|
|
53
62
|
});
|
|
54
63
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Effect, Data } from
|
|
2
|
-
import type { LanguageModel } from
|
|
1
|
+
import { Effect, Data } from "effect";
|
|
2
|
+
import type { LanguageModel } from "ai";
|
|
3
3
|
|
|
4
|
-
export class UnknownProviderError extends Data.TaggedError(
|
|
4
|
+
export class UnknownProviderError extends Data.TaggedError("UnknownProviderError")<{
|
|
5
5
|
readonly provider: string;
|
|
6
6
|
}> {}
|
|
7
7
|
|
|
@@ -19,16 +19,16 @@ export function resolveModel(
|
|
|
19
19
|
return Effect.tryPromise({
|
|
20
20
|
try: async () => {
|
|
21
21
|
switch (config.provider) {
|
|
22
|
-
case
|
|
23
|
-
const { openai } = await import(
|
|
22
|
+
case "openai": {
|
|
23
|
+
const { openai } = await import("@ai-sdk/openai");
|
|
24
24
|
return openai(config.modelId);
|
|
25
25
|
}
|
|
26
|
-
case
|
|
27
|
-
const { anthropic } = await import(
|
|
26
|
+
case "anthropic": {
|
|
27
|
+
const { anthropic } = await import("@ai-sdk/anthropic");
|
|
28
28
|
return anthropic(config.modelId);
|
|
29
29
|
}
|
|
30
|
-
case
|
|
31
|
-
const { google } = await import(
|
|
30
|
+
case "google": {
|
|
31
|
+
const { google } = await import("@ai-sdk/google");
|
|
32
32
|
return google(config.modelId);
|
|
33
33
|
}
|
|
34
34
|
default:
|