clanka 0.2.71 → 0.3.0
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/dist/Acp.d.ts +88 -0
- package/dist/Acp.d.ts.map +1 -0
- package/dist/Acp.js +387 -0
- package/dist/Acp.js.map +1 -0
- package/dist/Acp.test.d.ts +2 -0
- package/dist/Acp.test.d.ts.map +1 -0
- package/dist/Acp.test.js +179 -0
- package/dist/Acp.test.js.map +1 -0
- package/dist/AgentExecutor.d.ts +36 -36
- package/dist/AgentExecutor.d.ts.map +1 -1
- package/dist/AgentExecutor.js +5 -5
- package/dist/AgentExecutor.js.map +1 -1
- package/dist/AgentOutput.js +1 -1
- package/dist/AgentOutput.js.map +1 -1
- package/dist/ChunkRepo.js +1 -1
- package/dist/ChunkRepo.js.map +1 -1
- package/dist/CodeChunker.js +1 -1
- package/dist/CodeChunker.js.map +1 -1
- package/dist/CodexAuth.js +1 -1
- package/dist/CodexAuth.js.map +1 -1
- package/dist/CopilotAuth.js +1 -1
- package/dist/CopilotAuth.js.map +1 -1
- package/dist/DeviceCodeHandler.d.ts +2 -1
- package/dist/DeviceCodeHandler.d.ts.map +1 -1
- package/dist/DeviceCodeHandler.js +4 -0
- package/dist/DeviceCodeHandler.js.map +1 -1
- package/dist/ExaSearch.js +1 -1
- package/dist/ExaSearch.js.map +1 -1
- package/dist/McpClient.js +1 -1
- package/dist/McpClient.js.map +1 -1
- package/dist/SemanticSearch.d.ts +2 -2
- package/dist/SemanticSearch.d.ts.map +1 -1
- package/dist/SemanticSearch.js.map +1 -1
- package/dist/TypeBuilder.js +1 -1
- package/dist/TypeBuilder.js.map +1 -1
- package/dist/cli.js +40 -29
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +21 -21
- package/src/Acp.test.ts +288 -0
- package/src/Acp.ts +596 -0
- package/src/AgentExecutor.ts +18 -24
- package/src/AgentOutput.ts +1 -1
- package/src/ChunkRepo.ts +1 -1
- package/src/CodeChunker.ts +1 -1
- package/src/CodexAuth.ts +1 -1
- package/src/CopilotAuth.ts +1 -1
- package/src/DeviceCodeHandler.ts +8 -1
- package/src/ExaSearch.ts +1 -1
- package/src/McpClient.ts +1 -1
- package/src/SemanticSearch.ts +2 -2
- package/src/TypeBuilder.ts +1 -1
- package/src/cli.ts +100 -46
- package/src/index.ts +5 -0
package/src/DeviceCodeHandler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Console from "effect/Console"
|
|
2
|
-
import
|
|
2
|
+
import * as Effect from "effect/Effect"
|
|
3
3
|
import * as Layer from "effect/Layer"
|
|
4
4
|
import * as Context from "effect/Context"
|
|
5
5
|
|
|
@@ -19,3 +19,10 @@ export const layerConsole = Layer.succeed(DeviceCodeHandler, {
|
|
|
19
19
|
`Open ${options.verifyUrl} and enter code ${options.deviceCode}.`,
|
|
20
20
|
),
|
|
21
21
|
})
|
|
22
|
+
|
|
23
|
+
export const layerLog = Layer.succeed(DeviceCodeHandler, {
|
|
24
|
+
onCode: (options) =>
|
|
25
|
+
Effect.logWarning(
|
|
26
|
+
`Open ${options.verifyUrl} and enter code ${options.deviceCode}.`,
|
|
27
|
+
),
|
|
28
|
+
})
|
package/src/ExaSearch.ts
CHANGED
|
@@ -42,7 +42,7 @@ class ExaSearchResult extends Schema.Class<ExaSearchResult>("ExaSearchResult")({
|
|
|
42
42
|
* @since 1.0.0
|
|
43
43
|
* @category Errors
|
|
44
44
|
*/
|
|
45
|
-
export class ExaError extends Schema.
|
|
45
|
+
export class ExaError extends Schema.TaggedError<ExaError>()("ExaError", {
|
|
46
46
|
cause: Schema.Defect(),
|
|
47
47
|
}) {}
|
|
48
48
|
|
package/src/McpClient.ts
CHANGED
|
@@ -30,7 +30,7 @@ export class McpClient extends Context.Service<
|
|
|
30
30
|
* @since 1.0.0
|
|
31
31
|
* @category Errors
|
|
32
32
|
*/
|
|
33
|
-
export class McpClientError extends Schema.
|
|
33
|
+
export class McpClientError extends Schema.TaggedError<McpClientError>()(
|
|
34
34
|
"McpClientError",
|
|
35
35
|
{
|
|
36
36
|
cause: Schema.Defect(),
|
package/src/SemanticSearch.ts
CHANGED
|
@@ -41,12 +41,12 @@ const resolveChunkConfig = (options: {
|
|
|
41
41
|
})
|
|
42
42
|
|
|
43
43
|
export const makeEmbeddingResolver = (
|
|
44
|
-
resolver: EmbeddingModel.
|
|
44
|
+
resolver: EmbeddingModel.EmbeddingModel["resolver"],
|
|
45
45
|
options: {
|
|
46
46
|
readonly embeddingBatchSize?: number | undefined
|
|
47
47
|
readonly embeddingRequestDelay?: Duration.Input | undefined
|
|
48
48
|
},
|
|
49
|
-
): EmbeddingModel.
|
|
49
|
+
): EmbeddingModel.EmbeddingModel["resolver"] =>
|
|
50
50
|
resolver.pipe(
|
|
51
51
|
RequestResolver.setDelay(
|
|
52
52
|
options.embeddingRequestDelay ?? Duration.millis(50),
|
package/src/TypeBuilder.ts
CHANGED
package/src/cli.ts
CHANGED
|
@@ -7,6 +7,8 @@ import * as Flag from "effect/unstable/cli/Flag"
|
|
|
7
7
|
import * as NodeServices from "@effect/platform-node/NodeServices"
|
|
8
8
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime"
|
|
9
9
|
import * as NodeSocket from "@effect/platform-node/NodeSocket"
|
|
10
|
+
import * as Acp from "./Acp.ts"
|
|
11
|
+
import * as AgentExecutor from "./AgentExecutor.ts"
|
|
10
12
|
import * as Codex from "./Codex.ts"
|
|
11
13
|
import * as Copilot from "./Copilot.ts"
|
|
12
14
|
import * as Agent from "./Agent.ts"
|
|
@@ -15,17 +17,65 @@ import * as OutputFormatter from "./OutputFormatter.ts"
|
|
|
15
17
|
import * as Stdio from "effect/Stdio"
|
|
16
18
|
import { pipe } from "effect/Function"
|
|
17
19
|
import * as Layer from "effect/Layer"
|
|
20
|
+
import * as Logger from "effect/Logger"
|
|
18
21
|
import * as Path from "effect/Path"
|
|
22
|
+
import * as Schema from "effect/Schema"
|
|
23
|
+
import type * as LanguageModel from "effect/unstable/ai/LanguageModel"
|
|
24
|
+
import type * as Model from "effect/unstable/ai/Model"
|
|
19
25
|
import * as Config from "effect/Config"
|
|
20
26
|
import * as KeyValueStore from "effect/unstable/persistence/KeyValueStore"
|
|
21
27
|
import * as Option from "effect/Option"
|
|
22
28
|
import { OpenAiClient, OpenAiEmbeddingModel } from "@effect/ai-openai"
|
|
23
29
|
import { DeviceCodeHandler } from "./index.ts"
|
|
24
30
|
|
|
25
|
-
const
|
|
31
|
+
const version = "0.0.1"
|
|
32
|
+
|
|
33
|
+
type Provider = "openai" | "copilot"
|
|
34
|
+
|
|
35
|
+
const providers: ReadonlyArray<Provider> = ["openai", "copilot"]
|
|
36
|
+
|
|
37
|
+
const withSubagentModel = <E, R>(
|
|
38
|
+
model: Layer.Layer<
|
|
39
|
+
LanguageModel.LanguageModel | Model.ProviderName | Model.ModelName,
|
|
40
|
+
E,
|
|
41
|
+
R
|
|
42
|
+
>,
|
|
43
|
+
) => Layer.merge(model, Agent.layerSubagentModel(model))
|
|
44
|
+
|
|
45
|
+
const modelLayer = (provider: Provider, model: string, effort: string) =>
|
|
46
|
+
provider === "openai"
|
|
47
|
+
? withSubagentModel(
|
|
48
|
+
Codex.modelWebSocket(model, { reasoning: { effort: effort as any } }),
|
|
49
|
+
).pipe(Layer.provide(Codex.layerClient))
|
|
50
|
+
: withSubagentModel(Copilot.model(model, { reasoning: { effort } })).pipe(
|
|
51
|
+
Layer.provide(Copilot.layerClient),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
const parseModelId = (modelId: string) => {
|
|
55
|
+
const [provider, model, effort, ...rest] = modelId.split("/")
|
|
56
|
+
return provider !== undefined &&
|
|
57
|
+
providers.includes(provider as Provider) &&
|
|
58
|
+
model !== undefined &&
|
|
59
|
+
effort !== undefined &&
|
|
60
|
+
rest.length === 0
|
|
61
|
+
? Option.some({ provider: provider as Provider, model, effort })
|
|
62
|
+
: Option.none()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const ModelId = Schema.String.pipe(
|
|
66
|
+
Schema.check(
|
|
67
|
+
Schema.makeFilter(
|
|
68
|
+
(modelId: string) =>
|
|
69
|
+
Option.isSome(parseModelId(modelId)) ||
|
|
70
|
+
`Invalid model "${modelId}", expected <provider>/<model>/<effort>`,
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
const provider = Flag.Literals("provider", providers).pipe(
|
|
26
76
|
Flag.withAlias("p"),
|
|
27
77
|
Flag.withFallbackPrompt(
|
|
28
|
-
Prompt.
|
|
78
|
+
Prompt.Select({
|
|
29
79
|
message: "Select a provider",
|
|
30
80
|
choices: [
|
|
31
81
|
{
|
|
@@ -42,12 +92,12 @@ const provider = Flag.choice("provider", ["openai", "copilot"]).pipe(
|
|
|
42
92
|
),
|
|
43
93
|
)
|
|
44
94
|
|
|
45
|
-
const model = Flag.
|
|
95
|
+
const model = Flag.String("model").pipe(
|
|
46
96
|
Flag.withAlias("m"),
|
|
47
97
|
Flag.withFallbackPrompt(
|
|
48
|
-
Prompt.
|
|
98
|
+
Prompt.String({
|
|
49
99
|
message: "Enter a model",
|
|
50
|
-
default: "gpt-
|
|
100
|
+
default: "gpt-6-astra/medium",
|
|
51
101
|
validate(value) {
|
|
52
102
|
const parts = value.split("/")
|
|
53
103
|
if (parts.length !== 2) {
|
|
@@ -59,7 +109,7 @@ const model = Flag.string("model").pipe(
|
|
|
59
109
|
),
|
|
60
110
|
)
|
|
61
111
|
|
|
62
|
-
const semantic = Flag.
|
|
112
|
+
const semantic = Flag.Directory("search").pipe(
|
|
63
113
|
Flag.withDescription(
|
|
64
114
|
"Directory for semantic search data (uses OPENAI_API_KEY env var)",
|
|
65
115
|
),
|
|
@@ -67,7 +117,7 @@ const semantic = Flag.directory("search").pipe(
|
|
|
67
117
|
Flag.optional,
|
|
68
118
|
)
|
|
69
119
|
|
|
70
|
-
const prompt = Flag.
|
|
120
|
+
const prompt = Flag.String("prompt").pipe(
|
|
71
121
|
Flag.withDescription("Pass a prompt in non-interactive mode"),
|
|
72
122
|
Flag.optional,
|
|
73
123
|
)
|
|
@@ -76,9 +126,9 @@ const Kvs = Layer.unwrap(
|
|
|
76
126
|
Effect.gen(function* () {
|
|
77
127
|
const path = yield* Path.Path
|
|
78
128
|
|
|
79
|
-
const configHome = yield* Config.
|
|
129
|
+
const configHome = yield* Config.NonEmptyString("XDG_CONFIG_HOME").pipe(
|
|
80
130
|
Config.orElse(() =>
|
|
81
|
-
Config.
|
|
131
|
+
Config.NonEmptyString("HOME").pipe(
|
|
82
132
|
Config.map((home) => path.join(home, ".config")),
|
|
83
133
|
),
|
|
84
134
|
),
|
|
@@ -90,7 +140,7 @@ const Kvs = Layer.unwrap(
|
|
|
90
140
|
const Search = (directory: string) =>
|
|
91
141
|
Layer.unwrap(
|
|
92
142
|
Effect.gen(function* () {
|
|
93
|
-
const apiKey = yield* Config.
|
|
143
|
+
const apiKey = yield* Config.Redacted("OPENAI_API_KEY").pipe(
|
|
94
144
|
Config.option,
|
|
95
145
|
)
|
|
96
146
|
|
|
@@ -123,6 +173,42 @@ const Search = (directory: string) =>
|
|
|
123
173
|
}),
|
|
124
174
|
).pipe(Layer.provide([NodeServices.layer, NodeHttpClient.layerUndici]))
|
|
125
175
|
|
|
176
|
+
const acpModel = Flag.String("model").pipe(
|
|
177
|
+
Flag.withAlias("m"),
|
|
178
|
+
Flag.withDescription(
|
|
179
|
+
"Default model as <provider>/<model>/<effort>, e.g. openai/gpt-6-astra/medium",
|
|
180
|
+
),
|
|
181
|
+
Flag.withSchema(ModelId),
|
|
182
|
+
Flag.withDefault("openai/gpt-6-astra/medium"),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
const acp = Command.make("acp", { model: acpModel }).pipe(
|
|
186
|
+
Command.withDescription(
|
|
187
|
+
"Run as an Agent Client Protocol (ACP) server over stdio",
|
|
188
|
+
),
|
|
189
|
+
Command.withHandler(({ model }) =>
|
|
190
|
+
Acp.runStdio({
|
|
191
|
+
version,
|
|
192
|
+
defaultModel: model,
|
|
193
|
+
makeAgent: (cwd) =>
|
|
194
|
+
Agent.make.pipe(
|
|
195
|
+
Effect.provide(AgentExecutor.layerLocal({ directory: cwd })),
|
|
196
|
+
),
|
|
197
|
+
makeModel: (modelId) =>
|
|
198
|
+
Option.map(parseModelId(modelId), ({ provider, model, effort }) =>
|
|
199
|
+
modelLayer(provider, model, effort),
|
|
200
|
+
),
|
|
201
|
+
}),
|
|
202
|
+
),
|
|
203
|
+
Command.provide(
|
|
204
|
+
Layer.mergeAll(
|
|
205
|
+
Agent.ConversationMode.layer(true),
|
|
206
|
+
Layer.succeed(Logger.LogToStderr, true),
|
|
207
|
+
DeviceCodeHandler.layerLog,
|
|
208
|
+
),
|
|
209
|
+
),
|
|
210
|
+
)
|
|
211
|
+
|
|
126
212
|
Command.make("clanka", { provider, model, semantic, prompt }).pipe(
|
|
127
213
|
Command.withHandler(
|
|
128
214
|
Effect.fnUntraced(function* ({
|
|
@@ -133,40 +219,7 @@ Command.make("clanka", { provider, model, semantic, prompt }).pipe(
|
|
|
133
219
|
}) {
|
|
134
220
|
const stdio = yield* Stdio.Stdio
|
|
135
221
|
const [model, reasoning] = modelRaw.split("/") as [string, string]
|
|
136
|
-
const Model =
|
|
137
|
-
provider === "openai"
|
|
138
|
-
? Codex.modelWebSocket(model, {
|
|
139
|
-
reasoning: {
|
|
140
|
-
effort: reasoning as any,
|
|
141
|
-
},
|
|
142
|
-
}).pipe(
|
|
143
|
-
Layer.merge(
|
|
144
|
-
Agent.layerSubagentModel(
|
|
145
|
-
Codex.modelWebSocket("gpt-5.4-mini", {
|
|
146
|
-
reasoning: {
|
|
147
|
-
effort: "high",
|
|
148
|
-
},
|
|
149
|
-
}),
|
|
150
|
-
),
|
|
151
|
-
),
|
|
152
|
-
Layer.provide(Codex.layerClient),
|
|
153
|
-
)
|
|
154
|
-
: Copilot.model(model, {
|
|
155
|
-
reasoning: {
|
|
156
|
-
effort: reasoning,
|
|
157
|
-
},
|
|
158
|
-
}).pipe(
|
|
159
|
-
Layer.merge(
|
|
160
|
-
Agent.layerSubagentModel(
|
|
161
|
-
Copilot.model(model, {
|
|
162
|
-
reasoning: {
|
|
163
|
-
effort: "medium",
|
|
164
|
-
},
|
|
165
|
-
}),
|
|
166
|
-
),
|
|
167
|
-
),
|
|
168
|
-
Layer.provide(Copilot.layerClient),
|
|
169
|
-
)
|
|
222
|
+
const Model = modelLayer(provider, model, reasoning)
|
|
170
223
|
|
|
171
224
|
return yield* Effect.gen(function* () {
|
|
172
225
|
const agent = yield* Agent.Agent
|
|
@@ -181,7 +234,7 @@ Command.make("clanka", { provider, model, semantic, prompt }).pipe(
|
|
|
181
234
|
}
|
|
182
235
|
|
|
183
236
|
while (true) {
|
|
184
|
-
const prompt = yield* Prompt.
|
|
237
|
+
const prompt = yield* Prompt.String({
|
|
185
238
|
message: ">",
|
|
186
239
|
})
|
|
187
240
|
|
|
@@ -214,8 +267,9 @@ Command.make("clanka", { provider, model, semantic, prompt }).pipe(
|
|
|
214
267
|
Command.provide(({ prompt }) =>
|
|
215
268
|
Agent.ConversationMode.layer(Option.isNone(prompt)),
|
|
216
269
|
),
|
|
270
|
+
Command.withSubcommands([acp]),
|
|
217
271
|
Command.run({
|
|
218
|
-
version
|
|
272
|
+
version,
|
|
219
273
|
}),
|
|
220
274
|
Effect.provide([
|
|
221
275
|
NodeServices.layer,
|