clanka 0.2.72 → 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/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,14 +17,62 @@ 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 provider = Flag.Literals("provider", ["openai", "copilot"]).pipe(
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
78
  Prompt.Select({
@@ -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(model, {
146
- reasoning: {
147
- effort: reasoning as any,
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: reasoning,
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
@@ -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: "0.0.1",
272
+ version,
219
273
  }),
220
274
  Effect.provide([
221
275
  NodeServices.layer,
package/src/index.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ export * as Acp from "./Acp.ts"
5
+
1
6
  /**
2
7
  * @since 1.0.0
3
8
  */