clanka 0.1.11 → 0.1.13

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "clanka",
3
3
  "type": "module",
4
- "version": "0.1.11",
4
+ "version": "0.1.13",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -23,35 +23,35 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@modelcontextprotocol/sdk": "^1.27.1",
26
- "@vscode/ripgrep": "^1.17.0",
26
+ "@vscode/ripgrep": "^1.17.1",
27
27
  "chalk": "^5.6.2",
28
28
  "glob": "^13.0.6",
29
29
  "turndown": "^7.2.2"
30
30
  },
31
31
  "peerDependencies": {
32
- "@effect/ai-openai": "4.0.0-beta.31",
33
- "@effect/ai-openai-compat": "4.0.0-beta.31",
34
- "effect": "4.0.0-beta.31"
32
+ "@effect/ai-openai": "4.0.0-beta.32",
33
+ "@effect/ai-openai-compat": "4.0.0-beta.32",
34
+ "effect": "4.0.0-beta.32"
35
35
  },
36
36
  "devDependencies": {
37
- "@changesets/changelog-github": "^0.5.2",
37
+ "@changesets/changelog-github": "^0.6.0",
38
38
  "@changesets/cli": "^2.29.8",
39
- "@effect/ai-openai": "4.0.0-beta.31",
40
- "@effect/ai-openai-compat": "4.0.0-beta.31",
41
- "@effect/language-service": "^0.75.1",
42
- "@effect/platform-node": "4.0.0-beta.31",
43
- "@effect/vitest": "4.0.0-beta.31",
44
- "@linear/sdk": "^75.0.0",
45
- "@types/node": "^25.3.5",
39
+ "@effect/ai-openai": "4.0.0-beta.32",
40
+ "@effect/ai-openai-compat": "4.0.0-beta.32",
41
+ "@effect/language-service": "^0.80.0",
42
+ "@effect/platform-node": "4.0.0-beta.32",
43
+ "@effect/vitest": "4.0.0-beta.32",
44
+ "@linear/sdk": "^77.0.0",
45
+ "@types/node": "^25.5.0",
46
46
  "@types/turndown": "^5.0.6",
47
- "@typescript/native-preview": "7.0.0-dev.20260219.1",
48
- "effect": "4.0.0-beta.31",
47
+ "@typescript/native-preview": "7.0.0-dev.20260315.1",
48
+ "effect": "4.0.0-beta.32",
49
49
  "husky": "^9.1.7",
50
- "lint-staged": "^16.2.7",
51
- "oxlint": "^1.49.0",
50
+ "lint-staged": "^16.4.0",
51
+ "oxlint": "^1.55.0",
52
52
  "prettier": "^3.8.1",
53
53
  "typescript": "^5.9.3",
54
- "vitest": "^4.0.18"
54
+ "vitest": "^4.1.0"
55
55
  },
56
56
  "lint-staged": {
57
57
  "*.{ts,tsx}": [
package/src/Agent.ts CHANGED
@@ -19,7 +19,7 @@ import * as Effect from "effect/Effect"
19
19
  import * as Stream from "effect/Stream"
20
20
  import type * as Scope from "effect/Scope"
21
21
  import * as LanguageModel from "effect/unstable/ai/LanguageModel"
22
- import type * as AiError from "effect/unstable/ai/AiError"
22
+ import * as AiError from "effect/unstable/ai/AiError"
23
23
  import * as ServiceMap from "effect/ServiceMap"
24
24
  import * as Option from "effect/Option"
25
25
  import { identity, pipe } from "effect/Function"
@@ -31,6 +31,7 @@ import * as Layer from "effect/Layer"
31
31
  import * as Tool from "effect/unstable/ai/Tool"
32
32
  import * as Toolkit from "effect/unstable/ai/Toolkit"
33
33
  import * as Semaphore from "effect/Semaphore"
34
+ import * as Schedule from "effect/Schedule"
34
35
 
35
36
  /**
36
37
  * @since 1.0.0
@@ -167,7 +168,6 @@ ${content}
167
168
  >()
168
169
  let finalSummary = Option.none<string>()
169
170
 
170
- const singleToolMode = modelConfig.supportsNoTools !== true
171
171
  const output = yield* Queue.make<Output, AgentFinished | AiError.AiError>()
172
172
  const prompt = opts.disableHistory ? MutableRef.make(Prompt.empty) : history
173
173
 
@@ -176,7 +176,7 @@ ${content}
176
176
  const generateSystem =
177
177
  typeof opts.system === "function" ? opts.system : defaultSystem
178
178
 
179
- const toolInstructions = generateSystemTools(toolsDts, !singleToolMode)
179
+ const toolInstructions = generateSystemTools(toolsDts)
180
180
  let system = generateSystem({
181
181
  toolInstructions,
182
182
  agentsMd: Option.getOrElse(agentsMd, () => ""),
@@ -295,25 +295,8 @@ ${content}
295
295
  MutableRef.update(prompt, Prompt.setSystem(system))
296
296
  }
297
297
 
298
- let currentScript = ""
299
298
  yield* Effect.gen(function* () {
300
299
  while (true) {
301
- if (!singleToolMode && currentScript.length > 0) {
302
- const result = yield* executeScript(currentScript)
303
- MutableRef.update(
304
- prompt,
305
- Prompt.concat([
306
- {
307
- role: modelConfig.supportsAssistantPrefill
308
- ? "assistant"
309
- : "user",
310
- content: `Console output from executing javascript code:\n\n${result}`,
311
- },
312
- ]),
313
- )
314
- currentScript = ""
315
- }
316
-
317
300
  if (Option.isSome(finalSummary)) {
318
301
  yield* Queue.fail(
319
302
  output,
@@ -343,19 +326,8 @@ ${content}
343
326
  let reasoningStarted = false
344
327
  let hadReasoningDelta = false
345
328
  yield* pipe(
346
- ai.streamText(
347
- singleToolMode
348
- ? { prompt: prompt.current, toolkit: singleTool }
349
- : { prompt: prompt.current },
350
- ),
329
+ ai.streamText({ prompt: prompt.current, toolkit: singleTool }),
351
330
  Stream.takeUntil((part) => {
352
- if (
353
- !singleToolMode &&
354
- part.type === "text-end" &&
355
- currentScript.trim().length > 0
356
- ) {
357
- return true
358
- }
359
331
  if (
360
332
  (part.type === "text-end" || part.type === "reasoning-end") &&
361
333
  pendingMessages.size > 0
@@ -370,68 +342,10 @@ ${content}
370
342
  for (const part of parts) {
371
343
  switch (part.type) {
372
344
  case "text-start":
373
- if (singleToolMode) {
374
- if (hadReasoningDelta) {
375
- hadReasoningDelta = false
376
- maybeSend({
377
- agentId,
378
- part: new ReasoningEnd(),
379
- release: true,
380
- })
381
- }
382
- reasoningStarted = true
383
- break
384
- }
385
- currentScript = ""
386
- break
387
- case "text-delta": {
388
- if (singleToolMode) {
389
- hadReasoningDelta = true
390
- if (reasoningStarted) {
391
- reasoningStarted = false
392
- maybeSend({
393
- agentId,
394
- part: new ReasoningStart(),
395
- acquire: true,
396
- })
397
- }
398
- maybeSend({
399
- agentId,
400
- part: new ReasoningDelta({ delta: part.delta }),
401
- })
402
- break
403
- }
404
- if (currentScript === "" && part.delta.length > 0) {
405
- maybeSend({
406
- agentId,
407
- part: new ScriptStart(),
408
- acquire: true,
409
- })
410
- }
411
- maybeSend({
412
- agentId,
413
- part: new ScriptDelta({ delta: part.delta }),
414
- })
415
- currentScript += part.delta
416
- break
417
- }
418
- case "text-end": {
419
- if (singleToolMode) {
420
- reasoningStarted = false
421
- if (hadReasoningDelta) {
422
- hadReasoningDelta = false
423
- maybeSend({
424
- agentId,
425
- part: new ReasoningEnd(),
426
- release: true,
427
- })
428
- }
429
- }
430
- break
431
- }
432
345
  case "reasoning-start":
433
346
  reasoningStarted = true
434
347
  break
348
+ case "text-delta":
435
349
  case "reasoning-delta":
436
350
  hadReasoningDelta = true
437
351
  if (reasoningStarted) {
@@ -447,6 +361,7 @@ ${content}
447
361
  part: new ReasoningDelta({ delta: part.delta }),
448
362
  })
449
363
  break
364
+ case "text-end":
450
365
  case "reasoning-end":
451
366
  reasoningStarted = false
452
367
  if (hadReasoningDelta) {
@@ -468,8 +383,12 @@ ${content}
468
383
  Effect.retry({
469
384
  while: (err) => {
470
385
  response = []
386
+ if (err.isRetryable) {
387
+ maybeSend({ agentId, part: new ErrorRetry({ error: err }) })
388
+ }
471
389
  return err.isRetryable
472
390
  },
391
+ schedule: retryPolicy,
473
392
  }),
474
393
  modelConfig.systemPromptTransform
475
394
  ? (effect) => modelConfig.systemPromptTransform!(system, effect)
@@ -479,7 +398,6 @@ ${content}
479
398
  prompt,
480
399
  Prompt.concat(Prompt.fromResponseParts(response)),
481
400
  )
482
- currentScript = currentScript.trim()
483
401
  }
484
402
  }).pipe(
485
403
  Effect.provideService(ScriptExecutor, (script) => {
@@ -526,6 +444,11 @@ ${content}
526
444
  })
527
445
  })
528
446
 
447
+ const retryPolicy = Schedule.exponential(100, 1.5).pipe(
448
+ Schedule.either(Schedule.spaced(5000)),
449
+ Schedule.jittered,
450
+ )
451
+
529
452
  const defaultSystem = (options: {
530
453
  readonly toolInstructions: string
531
454
  readonly agentsMd: string | null
@@ -540,12 +463,28 @@ ${options.toolInstructions}
540
463
  ${options.agentsMd}
541
464
  `
542
465
 
543
- const generateSystemTools = (toolsDts: string, multi: boolean) => {
544
- const toolMd = multi
545
- ? generateSystemMulti(toolsDts)
546
- : generateSystemSingle(toolsDts)
466
+ const generateSystemTools = (
467
+ toolsDts: string,
468
+ ) => `**YOU ONLY HAVE ACCESS TO ONE TOOL** "execute", to run javascript code to do your work.
469
+
470
+ - Use \`console.log\` to print any output you need.
471
+ - Top level await is supported.
472
+ - AVOID passing scripts into the "bash" function, and instead write javascript.
473
+ - Do as much work as possible in a single script, using \`Promise.all\` to run multiple functions in parallel.
474
+ - Variables **are not shared** between executions, so you must include all necessary code in each script you execute.
475
+
476
+ **When you have fully completed your task**, call the "taskComplete" function with the final output.
477
+ DO NOT output the final result without wrapping it with "taskComplete".
478
+ Make sure every detail of the task is done before calling "taskComplete".
479
+
480
+ You have the following functions available to you:
547
481
 
548
- return `${toolMd}
482
+ \`\`\`ts
483
+ ${toolsDts}
484
+
485
+ /** The global Fetch API available for making HTTP requests. */
486
+ declare const fetch: typeof globalThis.fetch
487
+ \`\`\`
549
488
 
550
489
  For example, here is how you would read a file. First you would respond with
551
490
  javascript code that uses the "readFile" function:
@@ -562,51 +501,12 @@ console.log(JSON.parse(content))
562
501
  And then you will revieve back the console output:
563
502
 
564
503
  \`\`\`
565
- Console output from executing javascript code:
566
-
567
504
  [22:44:53.054] INFO (#47): Calling "readFile" { path: 'package.json' }
568
505
  {
569
506
  "name": "my-project",
570
507
  "version": "1.0.0"
571
508
  }
572
509
  \`\`\``
573
- }
574
-
575
- const generateSystemMulti = (toolsDts: string) => {
576
- return `You complete your tasks by **only writing javascript code** to interact with your environment.
577
-
578
- ${systemToolsCommon(toolsDts)}`
579
- }
580
-
581
- // oxlint-disable-next-line typescript/no-explicit-any
582
- const generateSystemSingle = (toolsDts: string) => {
583
- return `**YOU ONLY HAVE ACCESS TO ONE TOOL** "execute", to run javascript code to do your work.
584
-
585
- ${systemToolsCommon(toolsDts)}`
586
- }
587
-
588
- const systemToolsCommon = (
589
- toolsDts: string,
590
- ) => `- Use \`console.log\` to print any output you need.
591
- - Top level await is supported.
592
- - AVOID passing scripts into the "bash" function, and instead write javascript.
593
- - PREFER the "search" function over "rg" for finding information or code
594
- - Do as much work as possible in a single script, using \`Promise.all\` to run multiple functions in parallel.
595
- - Variables **are not shared** between executions, so you must include all necessary code in each script you execute.
596
- - Make use of the "delegate" tool to delegate exploration and small research tasks. You can delegate multiple tasks in parallel with Promise.all
597
-
598
- **When you have fully completed your task**, call the "taskComplete" function with the final output.
599
- DO NOT output the final result without wrapping it with "taskComplete".
600
- Make sure every detail of the task is done before calling "taskComplete".
601
-
602
- You have the following functions available to you:
603
-
604
- \`\`\`ts
605
- ${toolsDts}
606
-
607
- /** The global Fetch API available for making HTTP requests. */
608
- declare const fetch: typeof globalThis.fetch
609
- \`\`\``
610
510
 
611
511
  class ScriptExecutor extends ServiceMap.Service<
612
512
  ScriptExecutor,
@@ -690,12 +590,12 @@ export const layerSubagentModel = <E, R>(
690
590
  * @category System prompts
691
591
  */
692
592
  export class AgentModelConfig extends ServiceMap.Reference<{
693
- readonly systemPromptTransform?: <A, E, R>(
694
- system: string,
695
- effect: Effect.Effect<A, E, R>,
696
- ) => Effect.Effect<A, E, R>
697
- readonly supportsAssistantPrefill?: boolean | undefined
698
- readonly supportsNoTools?: boolean | undefined
593
+ readonly systemPromptTransform?:
594
+ | (<A, E, R>(
595
+ system: string,
596
+ effect: Effect.Effect<A, E, R>,
597
+ ) => Effect.Effect<A, E, R>)
598
+ | undefined
699
599
  }>("clanka/Agent/SystemPromptTransform", {
700
600
  defaultValue: () => ({}),
701
601
  }) {
@@ -776,6 +676,14 @@ export class ScriptEnd extends Schema.TaggedClass<ScriptEnd>()(
776
676
  {},
777
677
  ) {}
778
678
 
679
+ /**
680
+ * @since 1.0.0
681
+ * @category Output
682
+ */
683
+ export class ErrorRetry extends Schema.TaggedClass<ErrorRetry>()("ErrorRetry", {
684
+ error: AiError.AiError,
685
+ }) {}
686
+
779
687
  /**
780
688
  * @since 1.0.0
781
689
  * @category Output
@@ -825,6 +733,7 @@ export type ContentPart =
825
733
  | ScriptDelta
826
734
  | ScriptEnd
827
735
  | ScriptOutput
736
+ | ErrorRetry
828
737
 
829
738
  export const ContentPart = Schema.Union([
830
739
  ReasoningStart,
@@ -834,6 +743,7 @@ export const ContentPart = Schema.Union([
834
743
  ScriptDelta,
835
744
  ScriptEnd,
836
745
  ScriptOutput,
746
+ ErrorRetry,
837
747
  ])
838
748
 
839
749
  /**
@@ -875,6 +785,7 @@ export const Output = Schema.Union([
875
785
  SubagentStart,
876
786
  SubagentComplete,
877
787
  SubagentPart,
788
+ ErrorRetry,
878
789
  ])
879
790
 
880
791
  /**
package/src/AgentTools.ts CHANGED
@@ -20,7 +20,6 @@ import { pipe } from "effect/Function"
20
20
  import * as Array from "effect/Array"
21
21
  import * as Data from "effect/Data"
22
22
  import * as Layer from "effect/Layer"
23
- import * as Duration from "effect/Duration"
24
23
 
25
24
  /**
26
25
  * @since 1.0.0
@@ -75,14 +74,51 @@ export const AgentTools = Toolkit.make(
75
74
  success: Schema.NullOr(Schema.String),
76
75
  dependencies: [CurrentDirectory],
77
76
  }),
78
- Tool.make("search", {
79
- description: "Find information from a description",
77
+ Tool.make("rg", {
78
+ description: "Search for a pattern in files using ripgrep",
79
+ parameters: Schema.Struct({
80
+ pattern: Schema.String,
81
+ glob: Schema.optional(Schema.String).annotate({
82
+ documentation: "--glob",
83
+ }),
84
+ maxLines: Schema.optional(Schema.Finite).annotate({
85
+ documentation:
86
+ "The total maximum number of lines to return across all files (default: 500)",
87
+ }),
88
+ }),
89
+ success: Schema.String,
90
+ dependencies: [CurrentDirectory],
91
+ }),
92
+ Tool.make("delegate", {
93
+ description:
94
+ "Delegate a task to another software engineer / sub-agent. Returns the result of the task.",
80
95
  parameters: Schema.String.annotate({
81
- identifier: "description",
96
+ identifier: "task",
82
97
  }),
83
98
  success: Schema.String,
84
99
  dependencies: [SubagentExecutor],
85
100
  }),
101
+ Tool.make("glob", {
102
+ description: "Find files matching a glob pattern.",
103
+ parameters: Schema.String.annotate({
104
+ identifier: "pattern",
105
+ }),
106
+ success: Schema.Array(Schema.String),
107
+ dependencies: [CurrentDirectory],
108
+ }),
109
+ Tool.make("bash", {
110
+ description: "Run a bash command and return the output",
111
+ parameters: Schema.Struct({
112
+ command: Schema.String,
113
+ timeoutMs: Schema.optional(Schema.Finite).annotate({
114
+ documentation: "Timeout in ms (default: 120000)",
115
+ }),
116
+ }).annotate({
117
+ identifier: "command",
118
+ }),
119
+ success: Schema.String,
120
+ dependencies: [CurrentDirectory],
121
+ }),
86
122
  Tool.make("writeFile", {
87
123
  description:
88
124
  "Write content to a file, creating parent directories if needed. PREFER USING applyPatch to update existing files.",
@@ -132,43 +168,6 @@ export const AgentTools = Toolkit.make(
132
168
  success: Schema.Array(Schema.String),
133
169
  dependencies: [CurrentDirectory],
134
170
  }),
135
- Tool.make("rg", {
136
- description:
137
- "Search for a pattern in files using ripgrep. Prefer the search function unless finding something specific",
138
- parameters: Schema.Struct({
139
- pattern: Schema.String,
140
- glob: Schema.optional(Schema.String).annotate({
141
- documentation: "--glob",
142
- }),
143
- maxLines: Schema.optional(Schema.Finite).annotate({
144
- documentation:
145
- "The total maximum number of lines to return across all files (default: 500)",
146
- }),
147
- }),
148
- success: Schema.String,
149
- dependencies: [CurrentDirectory],
150
- }),
151
- Tool.make("glob", {
152
- description: "Find files matching a glob pattern.",
153
- parameters: Schema.String.annotate({
154
- identifier: "pattern",
155
- }),
156
- success: Schema.Array(Schema.String),
157
- dependencies: [CurrentDirectory],
158
- }),
159
- Tool.make("bash", {
160
- description: "Run a bash command and return the output",
161
- parameters: Schema.Struct({
162
- command: Schema.String,
163
- timeoutMs: Schema.optional(Schema.Finite).annotate({
164
- documentation: "Timeout in ms (default: 120000)",
165
- }),
166
- }).annotate({
167
- identifier: "command",
168
- }),
169
- success: Schema.String,
170
- dependencies: [CurrentDirectory],
171
- }),
172
171
  Tool.make("gh", {
173
172
  description: "Use the GitHub CLI to run a command and return the output",
174
173
  parameters: Schema.Array(Schema.String).annotate({
@@ -177,15 +176,6 @@ export const AgentTools = Toolkit.make(
177
176
  success: Schema.String,
178
177
  dependencies: [CurrentDirectory],
179
178
  }),
180
- Tool.make("delegate", {
181
- description:
182
- "Delegate a task to another software engineer. Returns the result of the task.",
183
- parameters: Schema.String.annotate({
184
- identifier: "task",
185
- }),
186
- success: Schema.String,
187
- dependencies: [SubagentExecutor],
188
- }),
189
179
  Tool.make("webSearch", {
190
180
  description: "Search the web for recent information.",
191
181
  parameters: ExaSearch.ExaSearchOptions,
@@ -356,11 +346,11 @@ export const AgentToolHandlersNoDeps = AgentTools.toLayer(
356
346
  return yield* Effect.promise(() => Glob.glob(pattern, { cwd }))
357
347
  }),
358
348
  bash: Effect.fn("AgentTools.bash")(function* (options) {
359
- const timeout = Duration.millis(options.timeoutMs ?? 120_000)
349
+ const timeoutMs = options.timeoutMs ?? 120_000
360
350
  yield* Effect.logInfo(`Calling "bash"`).pipe(
361
351
  Effect.annotateLogs({
362
352
  ...options,
363
- timeoutMs: Duration.format(timeout),
353
+ timeoutMs,
364
354
  }),
365
355
  )
366
356
  const cwd = yield* CurrentDirectory
@@ -370,13 +360,9 @@ export const AgentToolHandlersNoDeps = AgentTools.toLayer(
370
360
  })
371
361
  return yield* execute(cmd).pipe(
372
362
  Effect.timeoutOrElse({
373
- duration: timeout,
363
+ duration: timeoutMs,
374
364
  onTimeout: () =>
375
- Effect.die(
376
- new Error(
377
- `Command timed out after ${Duration.format(timeout)}`,
378
- ),
379
- ),
365
+ Effect.die(new Error(`Command timed out after ${timeoutMs}ms`)),
380
366
  }),
381
367
  )
382
368
  }, Effect.orDie),
@@ -544,21 +530,9 @@ export const AgentToolHandlersNoDeps = AgentTools.toLayer(
544
530
  delegate: Effect.fn("AgentTools.delegate")(function* (prompt) {
545
531
  yield* Effect.logInfo(`Calling "delegate"`)
546
532
  const spawn = yield* SubagentExecutor
547
- return yield* spawn(`You have been asked using the "delegate" function to complete the following task. Try to avoid using the "delegate" or "search" functions yourself unless strictly necessary:
533
+ return yield* spawn(`You have been asked using the "delegate" function to complete the following task. Try to avoid using the "delegate" function yourself unless strictly necessary:
548
534
 
549
535
  ${prompt}`)
550
- }, Effect.orDie),
551
- search: Effect.fn("AgentTools.search")(function* (description) {
552
- yield* Effect.logInfo(`Calling "search"`)
553
- const spawn = yield* SubagentExecutor
554
- return yield* spawn(`You are to find the following information as fast as possible:
555
-
556
- ${description}
557
-
558
- Requirements:
559
- - DO NOT call the "search" or "delegate" functions.
560
- - Output a concise report with file names, line numbers, and code snippets.
561
- - If nothing relevant is found, say so clearly.`)
562
536
  }, Effect.orDie),
563
537
  taskComplete: Effect.fn("AgentTools.taskComplete")(function* (message) {
564
538
  const deferred = yield* TaskCompleter
package/src/Codex.ts CHANGED
@@ -40,11 +40,7 @@ export const model = (
40
40
  OpenAiLanguageModel.layer({
41
41
  model,
42
42
  config: {
43
- ...Struct.omit(options ?? {}, [
44
- "reasoning",
45
- "supportsNoTools",
46
- "supportsAssistantPrefill",
47
- ]),
43
+ ...Struct.omit(options ?? {}, ["reasoning"]),
48
44
  store: false,
49
45
  reasoning: {
50
46
  effort: options?.reasoning?.effort ?? "medium",
@@ -57,8 +53,6 @@ export const model = (
57
53
  OpenAiLanguageModel.withConfigOverride(effect, {
58
54
  instructions: system,
59
55
  }),
60
- supportsAssistantPrefill: options?.supportsAssistantPrefill ?? true,
61
- supportsNoTools: options?.supportsNoTools ?? true,
62
56
  }),
63
57
  ).pipe(Layer.provide(layerClient)),
64
58
  )
package/src/Copilot.ts CHANGED
@@ -45,8 +45,7 @@ export const model = (
45
45
  ]),
46
46
  }),
47
47
  AgentModelConfig.layer({
48
- supportsAssistantPrefill: options?.supportsAssistantPrefill ?? false,
49
- supportsNoTools: options?.supportsNoTools ?? false,
48
+ systemPromptTransform: options?.systemPromptTransform,
50
49
  }),
51
50
  ).pipe(Layer.provide(layerClient)),
52
51
  )
@@ -10,6 +10,7 @@ import * as Stream from "effect/Stream"
10
10
  import type { AgentFinished, Output } from "./Agent.ts"
11
11
  import chalk from "chalk"
12
12
  import type * as Prompt from "effect/unstable/ai/Prompt"
13
+ import * as Cause from "effect/Cause"
13
14
 
14
15
  /**
15
16
  * @since 1.0.0
@@ -73,6 +74,9 @@ ${output.summary}\n\n`
73
74
  : output.output
74
75
  return `${prefix}${chalkScriptHeading(`${scriptIcon} Script output`)}\n\n${chalk.dim(truncated)}\n\n`
75
76
  }
77
+ case "ErrorRetry": {
78
+ return `${prefix}${chalk.red(`Error: ${output.error}. Retrying...`)}\n\n${chalk.dim(Cause.pretty(Cause.fail(output.error)))}\n\n`
79
+ }
76
80
  }
77
81
  }),
78
82
  Stream.catchTag("AgentFinished", (finished) =>