saeeol 1.2.7 → 1.2.9

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/ltm/types.ts CHANGED
@@ -1,14 +1,12 @@
1
- /** LTM — long-term memory type definitions */
1
+ /** LTM — long-term memory type definitions */
2
2
 
3
3
  import { Schema } from "effect"
4
4
  import { optionalOmitUndefined } from "@/util/schema"
5
5
 
6
- // ── Memory types ──
7
6
 
8
7
  export const MemoryType = Schema.Literals(["episodic", "semantic", "procedural"])
9
8
  export type MemoryType = Schema.Schema.Type<typeof MemoryType>
10
9
 
11
- // ── Memory entry ──
12
10
 
13
11
  export const MemoryMetadata = Schema.Struct({
14
12
  source: Schema.String,
@@ -30,7 +28,6 @@ export const Memory = Schema.Struct({
30
28
  })
31
29
  export type Memory = Schema.Schema.Type<typeof Memory>
32
30
 
33
- // ── Embedding server ──
34
31
 
35
32
  export const EmbedderStatus = Schema.Literals(["stopped", "starting", "running", "error"])
36
33
  export type EmbedderStatus = Schema.Schema.Type<typeof EmbedderStatus>
@@ -45,7 +42,6 @@ export const EmbeddingServer = Schema.Struct({
45
42
  })
46
43
  export type EmbeddingServer = Schema.Schema.Type<typeof EmbeddingServer>
47
44
 
48
- // ── Hardware profile ──
49
45
 
50
46
  export const HardwareProfile = Schema.Struct({
51
47
  gpuCount: Schema.Number,
@@ -57,7 +53,6 @@ export const HardwareProfile = Schema.Struct({
57
53
  })
58
54
  export type HardwareProfile = Schema.Schema.Type<typeof HardwareProfile>
59
55
 
60
- // ── LLM parameters (deterministic) ──
61
56
 
62
57
  export const LLMBakeParams = Schema.Struct({
63
58
  /** Embedding model ID */
@@ -79,7 +74,6 @@ export const LLMBakeParams = Schema.Struct({
79
74
  })
80
75
  export type LLMBakeParams = Schema.Schema.Type<typeof LLMBakeParams>
81
76
 
82
- // ── LTM configuration ──
83
77
 
84
78
  export const LTMConfig = Schema.Struct({
85
79
  enabled: Schema.Boolean,
@@ -105,4 +99,4 @@ export const LTMConfig = Schema.Struct({
105
99
  maxTokens: Schema.Number,
106
100
  }),
107
101
  })
108
- export type LTMConfig = Schema.Schema.Type<typeof LTMConfig>
102
+ export type LTMConfig = Schema.Schema.Type<typeof LTMConfig>
@@ -1,4 +1,4 @@
1
- /** Local embedding server — Ollama-based embedding model lifecycle management */
1
+ /** Local embedding server — Ollama-based embedding model lifecycle management */
2
2
 
3
3
  import { Effect } from "effect"
4
4
  import * as Log from "@saeeol/core/util/log"
@@ -17,8 +17,6 @@ const log = Log.create({ service: "local/embedder" })
17
17
 
18
18
  let server: EmbeddingServer | undefined
19
19
 
20
- // ── Ollama status checks ──
21
-
22
20
  async function isOllamaRunning(endpoint: string): Promise<boolean> {
23
21
  try {
24
22
  const res = await fetch(`${endpoint}/api/tags`, { signal: AbortSignal.timeout(3000) })
@@ -53,8 +51,6 @@ async function isModelInstalled(endpoint: string, model: string): Promise<boolea
53
51
  }
54
52
  }
55
53
 
56
- // ── Pull model from Ollama ──
57
-
58
54
  async function pullModel(endpoint: string, model: string): Promise<void> {
59
55
  log.info("pulling embedding model", { model })
60
56
  const ollamaModel = getOllamaModelName(model)
@@ -91,8 +87,6 @@ function getOllamaModelName(modelId: string): string {
91
87
  return map[modelId] ?? modelId
92
88
  }
93
89
 
94
- // ── Embedding API call ──
95
-
96
90
  async function embedViaOllama(endpoint: string, model: string, texts: string[]): Promise<number[][]> {
97
91
  const ollamaModel = getOllamaModelName(model)
98
92
  const res = await fetch(`${endpoint}/api/embed`, {
@@ -114,16 +108,12 @@ async function embedViaOllama(endpoint: string, model: string, texts: string[]):
114
108
  return data.embeddings
115
109
  }
116
110
 
117
- // ── VRAM estimation ──
118
-
119
111
  function estimateEmbeddingVRAM(modelId: string): number {
120
112
  const model = RAG.EMBEDDING_MODELS.find((m) => m.id === modelId)
121
113
  if (!model) return 200
122
114
  return Math.ceil(model.sizeBytes * 1.2 / (1024 * 1024))
123
115
  }
124
116
 
125
- // ── Public API ──
126
-
127
117
  /** Start the embedding server */
128
118
  export async function start(bake: LLMBakeParams): Promise<EmbeddingServer> {
129
119
  if (server && server.status === "running") {
@@ -146,8 +136,6 @@ export async function start(bake: LLMBakeParams): Promise<EmbeddingServer> {
146
136
  }
147
137
 
148
138
  void Bus.publish(LTMEvent.EmbedderStatusChanged, { status: "starting", model: bake.embeddingModel })
149
-
150
- // Check if Ollama is running
151
139
  const running = await isOllamaRunning(endpoint)
152
140
  if (!running) {
153
141
  log.warn("Ollama not running, embedding server unavailable", { endpoint })
@@ -155,16 +143,12 @@ export async function start(bake: LLMBakeParams): Promise<EmbeddingServer> {
155
143
  void Bus.publish(LTMEvent.EmbedderStatusChanged, { status: "error", model: bake.embeddingModel })
156
144
  return server
157
145
  }
158
-
159
- // Check if model is installed
160
146
  const ollamaModel = getOllamaModelName(bake.embeddingModel)
161
147
  const installed = await isModelInstalled(endpoint, ollamaModel)
162
148
  if (!installed) {
163
149
  log.info("model not installed, pulling", { model: ollamaModel })
164
150
  await pullModel(endpoint, ollamaModel)
165
151
  }
166
-
167
- // Check if model is loaded (auto-loaded on first call)
168
152
  const loaded = await isModelLoaded(endpoint, ollamaModel)
169
153
  if (!loaded) {
170
154
  // Warmup call — load model into memory
@@ -217,4 +201,4 @@ export async function embedOne(text: string): Promise<number[]> {
217
201
  /** VRAM usage in MB */
218
202
  export function vramUsage(): number {
219
203
  return server?.vramMB ?? 0
220
- }
204
+ }
@@ -1,4 +1,4 @@
1
- import { Provider } from "@/provider/provider"
1
+ import { Provider } from "@/provider/provider"
2
2
  import * as Log from "@saeeol/core/util/log"
3
3
  import { Context, Effect, Layer, Record } from "effect"
4
4
  import * as Stream from "effect/Stream"
@@ -119,11 +119,8 @@ const live: Layer.Layer<
119
119
  system.push(
120
120
  [
121
121
  ...(isOpenaiOauth ? [] : [SystemPrompt.soul()]),
122
- // use agent prompt otherwise provider prompt
123
122
  ...(input.agent.prompt ? [input.agent.prompt] : SystemPrompt.provider(input.model)),
124
- // any custom prompt passed into this call
125
123
  ...input.system,
126
- // any custom prompt from last user message
127
124
  ...(input.user.system ? [input.user.system] : []),
128
125
  ]
129
126
  .filter((x) => x)
@@ -435,7 +432,6 @@ const live: Layer.Layer<
435
432
  specificationVersion: "v3" as const,
436
433
  async transformParams(args) {
437
434
  if (args.type === "stream") {
438
- // @ts-expect-error
439
435
  args.params.prompt = ProviderTransform.message(args.params.prompt, input.model, options)
440
436
  }
441
437
  return args.params
@@ -501,4 +497,4 @@ export function hasToolCalls(messages: ModelMessage[]): boolean {
501
497
  return false
502
498
  }
503
499
 
504
- export * as LLM from "./llm"
500
+ export * as LLM from "./llm"
@@ -1,4 +1,4 @@
1
- import type { NamedError } from "@saeeol/core/util/error"
1
+ import type { NamedError } from "@saeeol/core/util/error"
2
2
  import { Cause, Clock, Duration, Effect, Schedule } from "effect"
3
3
  import { MessageV2 } from "../message/message-v2"
4
4
  import { isSaeeolError } from "@/saeeol/errors"
@@ -36,10 +36,8 @@ export function delay(attempt: number, error?: MessageV2.APIError) {
36
36
  if (retryAfter) {
37
37
  const parsedSeconds = Number.parseFloat(retryAfter)
38
38
  if (!Number.isNaN(parsedSeconds)) {
39
- // convert seconds to milliseconds
40
39
  return cap(Math.ceil(parsedSeconds * 1000))
41
40
  }
42
- // Try parsing as HTTP date format
43
41
  const parsed = Date.parse(retryAfter) - Date.now()
44
42
  if (!Number.isNaN(parsed) && parsed > 0) {
45
43
  return cap(Math.ceil(parsed))
@@ -68,8 +66,6 @@ export function retryable(error: Err) {
68
66
  if (error.data.responseBody?.includes("FreeUsageLimitError")) return undefined
69
67
  return error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message
70
68
  }
71
-
72
- // Check for rate limit patterns in plain text error messages
73
69
  const msg = error.data?.message
74
70
  if (typeof msg === "string") {
75
71
  const lower = msg.toLowerCase()
@@ -146,4 +142,4 @@ export function policy(opts: {
146
142
  )
147
143
  }
148
144
 
149
- export * as SessionRetry from "./retry"
145
+ export * as SessionRetry from "./retry"
@@ -0,0 +1,101 @@
1
+ /**
2
+ * session-events.ts — SyncEvent/BusEvent 정의 단일 소스
3
+ *
4
+ * core/session.ts와 core/session-types.ts가 공유.
5
+ * SaeeolSession overlay를 import하지 않아 순환 의존 없음.
6
+ * TurnOpen/TurnClose는 overlay 의존이 필요하므로 각 소비자에서 직접 추가.
7
+ */
8
+
9
+ import { BusEvent } from "@/bus/bus-event"
10
+ import { SyncEvent } from "../../sync"
11
+ import { SessionID } from "./schema"
12
+ import { Snapshot } from "@/snapshot"
13
+ import { MessageV2 } from "../message/message-v2"
14
+ import { Info, Summary, Revert } from "./session-types"
15
+ import { ArchivedTimestamp } from "./session-types"
16
+ import { Schema } from "effect"
17
+ import { Permission } from "@/permission"
18
+ import { ProjectID } from "../../project/schema"
19
+ import { WorkspaceID } from "../../control-plane/schema"
20
+ import { NonNegativeInt } from "@/util/schema"
21
+
22
+ // ── Event schemas ──
23
+
24
+ const UpdatedShare = Schema.Struct({
25
+ url: Schema.optional(Schema.NullOr(Schema.String)),
26
+ })
27
+
28
+ const UpdatedTime = Schema.Struct({
29
+ created: Schema.optional(Schema.NullOr(NonNegativeInt)),
30
+ updated: Schema.optional(Schema.NullOr(NonNegativeInt)),
31
+ compacting: Schema.optional(Schema.NullOr(NonNegativeInt)),
32
+ archived: Schema.optional(Schema.NullOr(ArchivedTimestamp)),
33
+ })
34
+
35
+ const UpdatedInfo = Schema.Struct({
36
+ id: Schema.optional(Schema.NullOr(SessionID)),
37
+ slug: Schema.optional(Schema.NullOr(Schema.String)),
38
+ projectID: Schema.optional(Schema.NullOr(ProjectID)),
39
+ workspaceID: Schema.optional(Schema.NullOr(WorkspaceID)),
40
+ directory: Schema.optional(Schema.NullOr(Schema.String)),
41
+ path: Schema.optional(Schema.NullOr(Schema.String)),
42
+ parentID: Schema.optional(Schema.NullOr(SessionID)),
43
+ summary: Schema.optional(Schema.NullOr(Summary)),
44
+ share: Schema.optional(UpdatedShare),
45
+ title: Schema.optional(Schema.NullOr(Schema.String)),
46
+ version: Schema.optional(Schema.NullOr(Schema.String)),
47
+ time: Schema.optional(UpdatedTime),
48
+ permission: Schema.optional(Schema.NullOr(Permission.Ruleset)),
49
+ revert: Schema.optional(Schema.NullOr(Revert)),
50
+ })
51
+
52
+ export const CreatedEventSchema = Schema.Struct({
53
+ sessionID: SessionID,
54
+ info: Info,
55
+ })
56
+
57
+ export const UpdatedEventSchema = Schema.Struct({
58
+ sessionID: SessionID,
59
+ info: UpdatedInfo,
60
+ })
61
+
62
+ // ── Event definitions (singleton registration) ──
63
+
64
+ export const SyncEvents = {
65
+ Created: SyncEvent.define({
66
+ type: "session.created",
67
+ version: 1,
68
+ aggregate: "sessionID",
69
+ schema: CreatedEventSchema,
70
+ }),
71
+ Updated: SyncEvent.define({
72
+ type: "session.updated",
73
+ version: 1,
74
+ aggregate: "sessionID",
75
+ schema: UpdatedEventSchema,
76
+ busSchema: CreatedEventSchema,
77
+ }),
78
+ Deleted: SyncEvent.define({
79
+ type: "session.deleted",
80
+ version: 1,
81
+ aggregate: "sessionID",
82
+ schema: CreatedEventSchema,
83
+ }),
84
+ }
85
+
86
+ export const BusEvents = {
87
+ Diff: BusEvent.define(
88
+ "session.diff",
89
+ Schema.Struct({
90
+ sessionID: SessionID,
91
+ diff: Schema.Array(Snapshot.FileDiff),
92
+ }),
93
+ ),
94
+ Error: BusEvent.define(
95
+ "session.error",
96
+ Schema.Struct({
97
+ sessionID: Schema.optional(SessionID),
98
+ error: MessageV2.Assistant.fields.error,
99
+ }),
100
+ ),
101
+ }
@@ -19,6 +19,7 @@ import { SaeeolSession } from "@/saeeol/session"
19
19
  import { Effect, Schema, Types } from "effect"
20
20
  import { zod } from "@/util/effect-zod"
21
21
  import { NonNegativeInt, optionalOmitUndefined, withStatics } from "@/util/schema"
22
+ import { SyncEvents, BusEvents } from "./session-events"
22
23
 
23
24
  const log = Log.create({ service: "session" })
24
25
 
@@ -70,11 +71,11 @@ export function sessionPath(worktree: string, cwd: string) {
70
71
  return path.relative(path.resolve(worktree), cwd).replaceAll("\\", "/")
71
72
  }
72
73
 
73
- const Summary = Schema.Struct({ additions: NonNegativeInt, deletions: NonNegativeInt, files: NonNegativeInt, diffs: optionalOmitUndefined(Schema.Array(Snapshot.SummaryFileDiff)) })
74
+ export const Summary = Schema.Struct({ additions: NonNegativeInt, deletions: NonNegativeInt, files: NonNegativeInt, diffs: optionalOmitUndefined(Schema.Array(Snapshot.SummaryFileDiff)) })
74
75
  const Share = Schema.Struct({ url: Schema.String })
75
76
  export const ArchivedTimestamp = Schema.Finite
76
77
  const Time = Schema.Struct({ created: NonNegativeInt, updated: NonNegativeInt, compacting: optionalOmitUndefined(NonNegativeInt), archived: optionalOmitUndefined(ArchivedTimestamp) })
77
- const Revert = Schema.Struct({ messageID: MessageID, partID: optionalOmitUndefined(PartID), snapshot: optionalOmitUndefined(Schema.String), diff: optionalOmitUndefined(Schema.String) })
78
+ export const Revert = Schema.Struct({ messageID: MessageID, partID: optionalOmitUndefined(PartID), snapshot: optionalOmitUndefined(Schema.String), diff: optionalOmitUndefined(Schema.String) })
78
79
 
79
80
  export const Info = Schema.Struct({
80
81
  id: SessionID, slug: Schema.String, projectID: ProjectID, workspaceID: optionalOmitUndefined(WorkspaceID),
@@ -125,11 +126,8 @@ const UpdatedInfo = Schema.Struct({
125
126
  const UpdatedEventSchema = Schema.Struct({ sessionID: SessionID, info: UpdatedInfo })
126
127
 
127
128
  export const Event = {
128
- Created: SyncEvent.define({ type: "session.created", version: 1, aggregate: "sessionID", schema: CreatedEventSchema }),
129
- Updated: SyncEvent.define({ type: "session.updated", version: 1, aggregate: "sessionID", schema: UpdatedEventSchema, busSchema: CreatedEventSchema }),
130
- Deleted: SyncEvent.define({ type: "session.deleted", version: 1, aggregate: "sessionID", schema: CreatedEventSchema }),
131
- Diff: BusEvent.define("session.diff", Schema.Struct({ sessionID: SessionID, diff: Schema.Array(Snapshot.FileDiff) })),
132
- Error: BusEvent.define("session.error", Schema.Struct({ sessionID: Schema.optional(SessionID), error: MessageV2.Assistant.fields.error })),
129
+ ...SyncEvents,
130
+ ...BusEvents,
133
131
  TurnOpen: SaeeolSession.Event.TurnOpen,
134
132
  TurnClose: SaeeolSession.Event.TurnClose,
135
133
  }
@@ -1,4 +1,4 @@
1
- import { Slug } from "@saeeol/core/util/slug"
1
+ import { Slug } from "@saeeol/core/util/slug"
2
2
  import path from "path"
3
3
  import { BusEvent } from "@/bus/bus-event"
4
4
  import { Bus } from "@/bus"
@@ -33,6 +33,7 @@ import { fn } from "@/util/fn"
33
33
  import { Effect, Layer, Option, Context, Schema, Types } from "effect"
34
34
  import { zod } from "@/util/effect-zod"
35
35
  import { NonNegativeInt, optionalOmitUndefined, withStatics } from "@/util/schema"
36
+ import { SyncEvents, BusEvents } from "./session-events"
36
37
 
37
38
  const log = Log.create({ service: "session" })
38
39
 
@@ -280,41 +281,8 @@ const UpdatedEventSchema = Schema.Struct({
280
281
  })
281
282
 
282
283
  export const Event = {
283
- Created: SyncEvent.define({
284
- type: "session.created",
285
- version: 1,
286
- aggregate: "sessionID",
287
- schema: CreatedEventSchema,
288
- }),
289
- Updated: SyncEvent.define({
290
- type: "session.updated",
291
- version: 1,
292
- aggregate: "sessionID",
293
- schema: UpdatedEventSchema,
294
- busSchema: CreatedEventSchema,
295
- }),
296
- Deleted: SyncEvent.define({
297
- type: "session.deleted",
298
- version: 1,
299
- aggregate: "sessionID",
300
- schema: CreatedEventSchema,
301
- }),
302
- Diff: BusEvent.define(
303
- "session.diff",
304
- Schema.Struct({
305
- sessionID: SessionID,
306
- diff: Schema.Array(Snapshot.FileDiff),
307
- }),
308
- ),
309
- Error: BusEvent.define(
310
- "session.error",
311
- Schema.Struct({
312
- sessionID: Schema.optional(SessionID),
313
- // Reuses MessageV2.Assistant.fields.error (already Schema.optional) so
314
- // the derived zod keeps the same discriminated-union shape on the bus.
315
- error: MessageV2.Assistant.fields.error,
316
- }),
317
- ),
284
+ ...SyncEvents,
285
+ ...BusEvents,
318
286
  TurnOpen: SaeeolSession.Event.TurnOpen,
319
287
  TurnClose: SaeeolSession.Event.TurnClose,
320
288
  }
@@ -348,11 +316,8 @@ export const getUsage = (input: {
348
316
  input.usage.inputTokenDetails?.cacheWriteTokens ??
349
317
  input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ??
350
318
  // google-vertex-anthropic returns metadata under "vertex" key
351
- // (AnthropicMessagesLanguageModel custom provider key from 'vertex.anthropic.messages')
352
319
  input.metadata?.["vertex"]?.["cacheCreationInputTokens"] ??
353
- // @ts-expect-error
354
320
  input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ??
355
- // @ts-expect-error
356
321
  input.metadata?.["venice"]?.["usage"]?.["cacheCreationInputTokens"] ??
357
322
  0,
358
323
  ),
@@ -840,9 +805,6 @@ function* listByProject(
840
805
  )
841
806
  }
842
807
  } else if (input.scope !== "project" && !Flag.SAEEOL_EXPERIMENTAL_WORKSPACES) {
843
- // if (input.directory) {
844
- // conditions.push(eq(SessionTable.directory, input.directory))
845
- // }
846
808
  }
847
809
  if (input.roots) {
848
810
  conditions.push(isNull(SessionTable.parent_id))
@@ -945,4 +907,4 @@ export const updatePartDelta = fn(
945
907
  (input) => runPromise((svc) => svc.updatePartDelta(input)),
946
908
  )
947
909
 
948
- export * as Session from "./session"
910
+ export * as Session from "./session"
@@ -1,4 +1,4 @@
1
- /** Error types + fromError + OutputFormat — extracted from message-v2.ts */
1
+ /** Error types + fromError + OutputFormat — extracted from message-v2.ts */
2
2
 
3
3
  import { APICallError, LoadAPIKeyError } from "ai"
4
4
  import { NamedError } from "@saeeol/core/util/error"
@@ -37,8 +37,6 @@ const _Format = Schema.Union([OutputFormatText, OutputFormatJsonSchema]).annotat
37
37
  export { _Format }
38
38
  export const Format = Object.assign(_Format, { zod: zod(_Format) })
39
39
  export type OutputFormat = Schema.Schema.Type<typeof _Format>
40
-
41
- // Assistant error union (Zod)
42
40
  import z from "zod"
43
41
  const AssistantErrorZod = z.discriminatedUnion("name", [
44
42
  AuthError.Schema, NamedError.Unknown.Schema, OutputLengthError.Schema, AbortedError.Schema,
@@ -46,8 +44,6 @@ const AssistantErrorZod = z.discriminatedUnion("name", [
46
44
  ])
47
45
  export type AssistantError = z.infer<typeof AssistantErrorZod>
48
46
  export { AssistantErrorZod }
49
-
50
- // Assistant error union (Effect Schema)
51
47
  export const AssistantErrorSchema = Schema.Union([
52
48
  AuthError.EffectSchema,
53
49
  Schema.Struct({ name: Schema.Literal("UnknownError"), data: Schema.Struct({ message: Schema.String }) }).annotate({ identifier: "UnknownError" }),
@@ -80,4 +76,4 @@ export function fromError(e: unknown, ctx: { providerID: ProviderID; aborted?: b
80
76
  } catch {}
81
77
  return new NamedError.Unknown({ message: JSON.stringify(e) }, { cause: e }).toObject()
82
78
  }
83
- }
79
+ }
@@ -1,4 +1,4 @@
1
- /** Part schemas + ToolState + Input schemas — extracted from message-v2.ts */
1
+ /** Part schemas + ToolState + Input schemas — extracted from message-v2.ts */
2
2
 
3
3
  import { SessionID, MessageID, PartID } from "../core/schema"
4
4
  import { LSP } from "@/lsp/lsp"
@@ -81,9 +81,7 @@ export const AgentPartInput = Schema.Struct({ id: Schema.optional(PartID), type:
81
81
  export type AgentPartInput = Types.DeepMutable<Schema.Schema.Type<typeof AgentPartInput>>
82
82
  export const SubtaskPartInput = Schema.Struct({ id: Schema.optional(PartID), type: Schema.Literal("subtask"), prompt: Schema.String, description: Schema.String, agent: Schema.String, model: Schema.optional(Schema.Struct({ providerID: ProviderID, modelID: ModelID })), command: Schema.optional(Schema.String) }).annotate({ identifier: "SubtaskPartInput" }).pipe(withStatics((s) => ({ zod: zod(s) })))
83
83
  export type SubtaskPartInput = Types.DeepMutable<Schema.Schema.Type<typeof SubtaskPartInput>>
84
-
85
- // Part union
86
84
  const _Part = Schema.Union([TextPart, SubtaskPart, ReasoningPart, FilePart, ToolPart, StepStartPart, StepFinishPart, SnapshotPart, PatchPart, AgentPart, RetryPart, CompactionPart]).annotate({ discriminator: "type", identifier: "Part" })
87
85
  export const Part = Object.assign(_Part, { zod: zod(_Part) as unknown as z.ZodType<TextPart | SubtaskPart | ReasoningPart | FilePart | ToolPart | StepStartPart | StepFinishPart | SnapshotPart | PatchPart | AgentPart | RetryPart | CompactionPart> })
88
86
  export type Part = TextPart | SubtaskPart | ReasoningPart | FilePart | ToolPart | StepStartPart | StepFinishPart | SnapshotPart | PatchPart | AgentPart | RetryPart | CompactionPart
89
- export { _Part }
87
+ export { _Part }
@@ -1,5 +1,4 @@
1
- // @ts-ignore
2
- globalThis.AI_SDK_LOG_WARNINGS = false
1
+ globalThis.AI_SDK_LOG_WARNINGS = false
3
2
 
4
3
  import { Effect, Layer, Scope, Latch, Context } from "effect"
5
4
  import { ChildProcessSpawner } from "effect/unstable/process"
@@ -208,4 +207,4 @@ export const prompt = (input: PromptInput) => runPromise((svc) => svc.prompt(inp
208
207
  export const loopExport = (input: LoopInput) => runPromise((svc) => svc.loop(input))
209
208
  export const cancel = (sessionID: SessionID) => runPromise((svc) => svc.cancel(sessionID))
210
209
 
211
- export * as SessionPrompt from "./prompt"
210
+ export * as SessionPrompt from "./prompt"
@@ -37,8 +37,6 @@ export const ApplyPatchTool = Tool.define(
37
37
  if (!params.patchText) {
38
38
  return yield* Effect.fail(new Error("patchText is required"))
39
39
  }
40
-
41
- // Parse the patch to get hunks
42
40
  let hunks: Patch.Hunk[]
43
41
  try {
44
42
  const parseResult = Patch.parsePatch(params.patchText)
@@ -56,8 +54,6 @@ export const ApplyPatchTool = Tool.define(
56
54
  }
57
55
 
58
56
  const instance = yield* InstanceState.context
59
-
60
- // Validate file paths and check permissions
61
57
  const fileChanges: Array<{
62
58
  filePath: string
63
59
  oldContent: string
@@ -109,7 +105,6 @@ export const ApplyPatchTool = Tool.define(
109
105
  }
110
106
 
111
107
  case "update": {
112
- // Check if file exists for update
113
108
  const stats = yield* afs.stat(filePath).pipe(Effect.catch(() => Effect.succeed(undefined)))
114
109
  if (!stats || stats.type === "Directory") {
115
110
  return yield* Effect.fail(
@@ -132,8 +127,6 @@ export const ApplyPatchTool = Tool.define(
132
127
  let newContent = oldContent
133
128
  let bom = source.bom
134
129
  let encoding = read.encoding
135
-
136
- // Apply the update chunks to get new content
137
130
  try {
138
131
  const fileUpdate = Patch.deriveNewContentsFromChunks(filePath, hunk.chunks)
139
132
  newContent = fileUpdate.content
@@ -205,8 +198,6 @@ export const ApplyPatchTool = Tool.define(
205
198
  }
206
199
  }
207
200
  }
208
-
209
- // Build per-file metadata for UI rendering (used for both permission and result)
210
201
  const files = fileChanges.map((change) => ({
211
202
  filePath: change.filePath,
212
203
  relativePath: path.relative(instance.worktree, change.movePath ?? change.filePath).replaceAll("\\", "/"),
@@ -216,8 +207,6 @@ export const ApplyPatchTool = Tool.define(
216
207
  deletions: change.deletions,
217
208
  movePath: change.movePath,
218
209
  }))
219
-
220
- // Check permissions if needed
221
210
  const relativePaths = fileChanges.map((c) => path.relative(instance.worktree, c.filePath).replaceAll("\\", "/"))
222
211
  yield* ctx.ask({
223
212
  permission: "edit",
@@ -229,15 +218,12 @@ export const ApplyPatchTool = Tool.define(
229
218
  files,
230
219
  },
231
220
  })
232
-
233
- // Apply the changes
234
221
  const updates: Array<{ file: string; event: "add" | "change" | "unlink" }> = []
235
222
 
236
223
  for (const change of fileChanges) {
237
224
  const edited = change.type === "delete" ? undefined : (change.movePath ?? change.filePath)
238
225
  switch (change.type) {
239
226
  case "add":
240
- // Create parent directories (recursive: true is safe on existing/root dirs)
241
227
  yield* EncodedIO.write(change.filePath, Bom.join(change.newContent, change.bom), change.encoding)
242
228
  updates.push({ file: change.filePath, event: "add" })
243
229
  break
@@ -249,7 +235,6 @@ export const ApplyPatchTool = Tool.define(
249
235
 
250
236
  case "move":
251
237
  if (change.movePath) {
252
- // Create parent directories (recursive: true is safe on existing/root dirs)
253
238
  yield* EncodedIO.write(change.movePath!, Bom.join(change.newContent, change.bom), change.encoding)
254
239
  yield* afs.remove(change.filePath)
255
240
  updates.push({ file: change.filePath, event: "unlink" })
@@ -270,21 +255,15 @@ export const ApplyPatchTool = Tool.define(
270
255
  yield* bus.publish(File.Event.Edited, { file: edited })
271
256
  }
272
257
  }
273
-
274
- // Publish file change events
275
258
  for (const update of updates) {
276
259
  yield* bus.publish(FileWatcher.Event.Updated, update)
277
260
  }
278
-
279
- // Notify LSP of file changes and collect diagnostics
280
261
  for (const change of fileChanges) {
281
262
  if (change.type === "delete") continue
282
263
  const target = change.movePath ?? change.filePath
283
264
  yield* lsp.touchFile(target, "document")
284
265
  }
285
266
  const diagnostics = yield* lsp.diagnostics()
286
-
287
- // Generate output summary
288
267
  const summaryLines = fileChanges.map((change) => {
289
268
  if (change.type === "add") {
290
269
  return `A ${path.relative(instance.worktree, change.filePath).replaceAll("\\", "/")}`
@@ -1,4 +1,4 @@
1
- import { levenshtein, SINGLE_CANDIDATE_SIMILARITY_THRESHOLD, MULTIPLE_CANDIDATES_SIMILARITY_THRESHOLD } from "./edit-utils"
1
+ import { levenshtein, SINGLE_CANDIDATE_SIMILARITY_THRESHOLD, MULTIPLE_CANDIDATES_SIMILARITY_THRESHOLD } from "./edit-utils"
2
2
 
3
3
  export type Replacer = (content: string, find: string) => Generator<string, void, unknown>
4
4
 
@@ -151,7 +151,6 @@ export const WhitespaceNormalizedReplacer: Replacer = function* (content, find)
151
151
  const match = line.match(regex)
152
152
  if (match) yield match[0]
153
153
  } catch {
154
- // Invalid regex pattern, skip
155
154
  }
156
155
  }
157
156
  }
@@ -285,4 +284,4 @@ export const ContextAwareReplacer: Replacer = function* (content, find) {
285
284
  }
286
285
  }
287
286
  }
288
- }
287
+ }
@@ -1,4 +1,4 @@
1
- import { Effect, Schema } from "effect"
1
+ import { Effect, Schema } from "effect"
2
2
  import { Npm } from "@saeeol/core/npm"
3
3
  import * as Bus from "@/bus"
4
4
  import * as Tool from "../core/tool"
@@ -98,8 +98,6 @@ export const PackageTool = Tool.define(
98
98
  ]
99
99
  return { title: "Available Providers", output: lines.join("\n"), metadata: {} }
100
100
  }
101
-
102
- // action === "install"
103
101
  const packages = params.packages
104
102
  if (!packages || packages.length === 0) {
105
103
  return {
@@ -165,4 +163,4 @@ export const PackageTool = Tool.define(
165
163
  }),
166
164
  }
167
165
  }),
168
- )
166
+ )
@@ -7,9 +7,6 @@ import { Bus } from "../../bus"
7
7
  import { TuiEvent } from "../../cli/cmd/tui/event"
8
8
  import DESCRIPTION from "./warpgrep.txt"
9
9
 
10
- // FREE_PERIOD_TODO: Remove SAEEOL_WARPGREP_PROXY_URL constant and the proxy
11
- // fallback below. After the free period ends, require MORPH_API_KEY and
12
- // return an error when it is missing.
13
10
  const SAEEOL_WARPGREP_PROXY_URL = "https://api.saeeol.ai/api/gateway"
14
11
 
15
12
  const Parameters = Schema.Struct({
@@ -36,8 +33,6 @@ export const CodebaseSearchTool = Tool.define(
36
33
 
37
34
  const apiKey = process.env["MORPH_API_KEY"]
38
35
 
39
- // FREE_PERIOD_TODO: Remove proxy fallback — require apiKey, error if missing:
40
- // if (!apiKey) return { title: ..., output: "Set MORPH_API_KEY to use codebase search.", metadata: {} }
41
36
  const client = new WarpGrepClient({
42
37
  morphApiKey: apiKey ?? "saeeol-free",
43
38
  ...(apiKey ? {} : { morphApiUrl: SAEEOL_WARPGREP_PROXY_URL }),
@@ -52,9 +47,6 @@ export const CodebaseSearchTool = Tool.define(
52
47
  )
53
48
 
54
49
  if (!result.success || !result.contexts?.length) {
55
- // FREE_PERIOD_TODO: When the proxy stops serving free requests, errors
56
- // from the proxy (401/402/429) will surface here. The message below
57
- // tells the user exactly what to do.
58
50
  const isAuthOrRateLimit =
59
51
  result.error && /401|402|429|rate.limit|free.period|unauthorized/i.test(result.error)
60
52
  const apiKeyMsg =