test: add live effect helper mode
Default the shared effect test helper to support both test-clock and live execution, and switch the current opencode effect tests to the live path for real integration behavior.pull/20304/head
parent
459fbc99a8
commit
6ea467b0ac
|
|
@ -16,21 +16,21 @@ const truncate = Layer.effectDiscard(
|
|||
|
||||
const it = testEffect(Layer.merge(AccountRepo.layer, truncate))
|
||||
|
||||
it.effect("list returns empty when no accounts exist", () =>
|
||||
it.live("list returns empty when no accounts exist", () =>
|
||||
Effect.gen(function* () {
|
||||
const accounts = yield* AccountRepo.use((r) => r.list())
|
||||
expect(accounts).toEqual([])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("active returns none when no accounts exist", () =>
|
||||
it.live("active returns none when no accounts exist", () =>
|
||||
Effect.gen(function* () {
|
||||
const active = yield* AccountRepo.use((r) => r.active())
|
||||
expect(Option.isNone(active)).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("persistAccount inserts and getRow retrieves", () =>
|
||||
it.live("persistAccount inserts and getRow retrieves", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
yield* AccountRepo.use((r) =>
|
||||
|
|
@ -56,7 +56,7 @@ it.effect("persistAccount inserts and getRow retrieves", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("persistAccount sets the active account and org", () =>
|
||||
it.live("persistAccount sets the active account and org", () =>
|
||||
Effect.gen(function* () {
|
||||
const id1 = AccountID.make("user-1")
|
||||
const id2 = AccountID.make("user-2")
|
||||
|
|
@ -93,7 +93,7 @@ it.effect("persistAccount sets the active account and org", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("list returns all accounts", () =>
|
||||
it.live("list returns all accounts", () =>
|
||||
Effect.gen(function* () {
|
||||
const id1 = AccountID.make("user-1")
|
||||
const id2 = AccountID.make("user-2")
|
||||
|
|
@ -128,7 +128,7 @@ it.effect("list returns all accounts", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("remove deletes an account", () =>
|
||||
it.live("remove deletes an account", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ it.effect("remove deletes an account", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("use stores the selected org and marks the account active", () =>
|
||||
it.live("use stores the selected org and marks the account active", () =>
|
||||
Effect.gen(function* () {
|
||||
const id1 = AccountID.make("user-1")
|
||||
const id2 = AccountID.make("user-2")
|
||||
|
|
@ -191,7 +191,7 @@ it.effect("use stores the selected org and marks the account active", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("persistToken updates token fields", () =>
|
||||
it.live("persistToken updates token fields", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -225,7 +225,7 @@ it.effect("persistToken updates token fields", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("persistToken with no expiry sets token_expiry to null", () =>
|
||||
it.live("persistToken with no expiry sets token_expiry to null", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ it.effect("persistToken with no expiry sets token_expiry to null", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("persistAccount upserts on conflict", () =>
|
||||
it.live("persistAccount upserts on conflict", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ it.effect("persistAccount upserts on conflict", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("remove clears active state when deleting the active account", () =>
|
||||
it.live("remove clears active state when deleting the active account", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ it.effect("remove clears active state when deleting the active account", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("getRow returns none for nonexistent account", () =>
|
||||
it.live("getRow returns none for nonexistent account", () =>
|
||||
Effect.gen(function* () {
|
||||
const row = yield* AccountRepo.use((r) => r.getRow(AccountID.make("nope")))
|
||||
expect(Option.isNone(row)).toBe(true)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ const deviceTokenClient = (body: unknown, status = 400) =>
|
|||
const poll = (body: unknown, status = 400) =>
|
||||
Account.Service.use((s) => s.poll(login())).pipe(Effect.provide(live(deviceTokenClient(body, status))))
|
||||
|
||||
it.effect("orgsByAccount groups orgs per account", () =>
|
||||
it.live("orgsByAccount groups orgs per account", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* AccountRepo.use((r) =>
|
||||
r.persistAccount({
|
||||
|
|
@ -107,7 +107,7 @@ it.effect("orgsByAccount groups orgs per account", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("token refresh persists the new token", () =>
|
||||
it.live("token refresh persists the new token", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ it.effect("token refresh persists the new token", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("config sends the selected org header", () =>
|
||||
it.live("config sends the selected org header", () =>
|
||||
Effect.gen(function* () {
|
||||
const id = AccountID.make("user-1")
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ it.effect("config sends the selected org header", () =>
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("poll stores the account and first org on success", () =>
|
||||
it.live("poll stores the account and first org on success", () =>
|
||||
Effect.gen(function* () {
|
||||
const client = HttpClient.make((req) =>
|
||||
Effect.succeed(
|
||||
|
|
@ -259,7 +259,7 @@ for (const [name, body, expectedTag] of [
|
|||
"PollExpired",
|
||||
],
|
||||
] as const) {
|
||||
it.effect(`poll returns ${name} for ${body.error}`, () =>
|
||||
it.live(`poll returns ${name} for ${body.error}`, () =>
|
||||
Effect.gen(function* () {
|
||||
const result = yield* poll(body)
|
||||
expect(result._tag).toBe(expectedTag)
|
||||
|
|
@ -267,7 +267,7 @@ for (const [name, body, expectedTag] of [
|
|||
)
|
||||
}
|
||||
|
||||
it.effect("poll returns poll error for other OAuth errors", () =>
|
||||
it.live("poll returns poll error for other OAuth errors", () =>
|
||||
Effect.gen(function* () {
|
||||
const result = yield* poll({
|
||||
error: "server_error",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const live = Layer.mergeAll(Bus.layer, node)
|
|||
const it = testEffect(live)
|
||||
|
||||
describe("Bus (Effect-native)", () => {
|
||||
it.effect("publish + subscribe stream delivers events", () =>
|
||||
it.live("publish + subscribe stream delivers events", () =>
|
||||
provideTmpdirInstance(() =>
|
||||
Effect.gen(function* () {
|
||||
const bus = yield* Bus.Service
|
||||
|
|
@ -46,7 +46,7 @@ describe("Bus (Effect-native)", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("subscribe filters by event type", () =>
|
||||
it.live("subscribe filters by event type", () =>
|
||||
provideTmpdirInstance(() =>
|
||||
Effect.gen(function* () {
|
||||
const bus = yield* Bus.Service
|
||||
|
|
@ -70,7 +70,7 @@ describe("Bus (Effect-native)", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("subscribeAll receives all types", () =>
|
||||
it.live("subscribeAll receives all types", () =>
|
||||
provideTmpdirInstance(() =>
|
||||
Effect.gen(function* () {
|
||||
const bus = yield* Bus.Service
|
||||
|
|
@ -95,7 +95,7 @@ describe("Bus (Effect-native)", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("multiple subscribers each receive the event", () =>
|
||||
it.live("multiple subscribers each receive the event", () =>
|
||||
provideTmpdirInstance(() =>
|
||||
Effect.gen(function* () {
|
||||
const bus = yield* Bus.Service
|
||||
|
|
@ -129,7 +129,7 @@ describe("Bus (Effect-native)", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("subscribeAll stream sees InstanceDisposed on disposal", () =>
|
||||
it.live("subscribeAll stream sees InstanceDisposed on disposal", () =>
|
||||
Effect.gen(function* () {
|
||||
const dir = yield* tmpdirScoped()
|
||||
const types: string[] = []
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { it } from "../lib/effect"
|
|||
describe("Runner", () => {
|
||||
// --- ensureRunning semantics ---
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"ensureRunning starts work and returns result",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -18,7 +18,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"ensureRunning propagates work failures",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -29,7 +29,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"concurrent callers share the same run",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -51,7 +51,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"concurrent callers all receive same error",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -71,7 +71,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"ensureRunning can be called again after previous run completes",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -81,7 +81,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"second ensureRunning ignores new work if already running",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -110,7 +110,7 @@ describe("Runner", () => {
|
|||
|
||||
// --- cancel semantics ---
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel interrupts running work",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -128,7 +128,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel on idle is a no-op",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -138,7 +138,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel with onInterrupt resolves callers gracefully",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -154,7 +154,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel with queued callers resolves all",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -175,7 +175,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"work can be started after cancel",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -245,7 +245,7 @@ describe("Runner", () => {
|
|||
|
||||
// --- shell semantics ---
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"shell runs exclusively",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -256,7 +256,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"shell rejects when run is active",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -272,7 +272,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"shell rejects when another shell is running",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -292,7 +292,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"shell rejects via busy callback and cancel still stops the first shell",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -323,7 +323,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel interrupts shell that ignores abort signal",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -349,7 +349,7 @@ describe("Runner", () => {
|
|||
|
||||
// --- shell→run handoff ---
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"ensureRunning queues behind shell then runs after",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -376,7 +376,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"multiple ensureRunning callers share the queued run behind shell",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -407,7 +407,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel during shell_then_run cancels both",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -441,7 +441,7 @@ describe("Runner", () => {
|
|||
|
||||
// --- lifecycle callbacks ---
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"onIdle fires when returning to idle from running",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -454,7 +454,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"onIdle fires on cancel",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -470,7 +470,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"onBusy fires when shell starts",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -485,7 +485,7 @@ describe("Runner", () => {
|
|||
|
||||
// --- busy flag ---
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"busy is true during run",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
@ -502,7 +502,7 @@ describe("Runner", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"busy is true during shell",
|
||||
Effect.gen(function* () {
|
||||
const s = yield* Scope.Scope
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import * as Formatter from "../../src/format/formatter"
|
|||
const it = testEffect(Layer.mergeAll(Format.defaultLayer, CrossSpawnSpawner.defaultLayer, NodeFileSystem.layer))
|
||||
|
||||
describe("Format", () => {
|
||||
it.effect("status() returns built-in formatters when no config overrides", () =>
|
||||
it.live("status() returns built-in formatters when no config overrides", () =>
|
||||
provideTmpdirInstance(() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -32,7 +32,7 @@ describe("Format", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("status() returns empty list when formatter is disabled", () =>
|
||||
it.live("status() returns empty list when formatter is disabled", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
|
|
@ -44,7 +44,7 @@ describe("Format", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("status() excludes formatters marked as disabled in config", () =>
|
||||
it.live("status() excludes formatters marked as disabled in config", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
|
|
@ -64,11 +64,11 @@ describe("Format", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("service initializes without error", () =>
|
||||
it.live("service initializes without error", () =>
|
||||
provideTmpdirInstance(() => Format.Service.use(() => Effect.void)),
|
||||
)
|
||||
|
||||
it.effect("status() initializes formatter state per directory", () =>
|
||||
it.live("status() initializes formatter state per directory", () =>
|
||||
Effect.gen(function* () {
|
||||
const a = yield* provideTmpdirInstance(() => Format.Service.use((fmt) => fmt.status()), {
|
||||
config: { formatter: false },
|
||||
|
|
@ -80,7 +80,7 @@ describe("Format", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("runs enabled checks for matching formatters in parallel", () =>
|
||||
it.live("runs enabled checks for matching formatters in parallel", () =>
|
||||
provideTmpdirInstance((path) =>
|
||||
Effect.gen(function* () {
|
||||
const file = `${path}/test.parallel`
|
||||
|
|
@ -144,7 +144,7 @@ describe("Format", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("runs matching formatters sequentially for the same file", () =>
|
||||
it.live("runs matching formatters sequentially for the same file", () =>
|
||||
provideTmpdirInstance(
|
||||
(path) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { test, type TestOptions } from "bun:test"
|
||||
import { Cause, Effect, Exit, Layer } from "effect"
|
||||
import type * as Scope from "effect/Scope"
|
||||
import * as TestClock from "effect/testing/TestClock"
|
||||
import * as TestConsole from "effect/testing/TestConsole"
|
||||
|
||||
type Body<A, E, R> = Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>)
|
||||
const env = TestConsole.layer
|
||||
|
||||
const body = <A, E, R>(value: Body<A, E, R>) => Effect.suspend(() => (typeof value === "function" ? value() : value))
|
||||
|
||||
|
|
@ -19,19 +19,35 @@ const run = <A, E, R, E2>(value: Body<A, E, R | Scope.Scope>, layer: Layer.Layer
|
|||
return yield* exit
|
||||
}).pipe(Effect.runPromise)
|
||||
|
||||
const make = <R, E>(layer: Layer.Layer<R, E, never>) => {
|
||||
const make = <R, E>(testLayer: Layer.Layer<R, E, never>, liveLayer: Layer.Layer<R, E, never>) => {
|
||||
const effect = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) =>
|
||||
test(name, () => run(value, layer), opts)
|
||||
test(name, () => run(value, testLayer), opts)
|
||||
|
||||
effect.only = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) =>
|
||||
test.only(name, () => run(value, layer), opts)
|
||||
test.only(name, () => run(value, testLayer), opts)
|
||||
|
||||
effect.skip = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) =>
|
||||
test.skip(name, () => run(value, layer), opts)
|
||||
test.skip(name, () => run(value, testLayer), opts)
|
||||
|
||||
return { effect }
|
||||
const live = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) =>
|
||||
test(name, () => run(value, liveLayer), opts)
|
||||
|
||||
live.only = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) =>
|
||||
test.only(name, () => run(value, liveLayer), opts)
|
||||
|
||||
live.skip = <A, E2>(name: string, value: Body<A, E2, R | Scope.Scope>, opts?: number | TestOptions) =>
|
||||
test.skip(name, () => run(value, liveLayer), opts)
|
||||
|
||||
return { effect, live }
|
||||
}
|
||||
|
||||
export const it = make(env)
|
||||
// Test environment with TestClock and TestConsole
|
||||
const testEnv = Layer.mergeAll(TestConsole.layer, TestClock.layer())
|
||||
|
||||
export const testEffect = <R, E>(layer: Layer.Layer<R, E, never>) => make(Layer.provideMerge(layer, env))
|
||||
// Live environment - uses real clock, but keeps TestConsole for output capture
|
||||
const liveEnv = TestConsole.layer
|
||||
|
||||
export const it = make(testEnv, liveEnv)
|
||||
|
||||
export const testEffect = <R, E>(layer: Layer.Layer<R, E, never>) =>
|
||||
make(Layer.provideMerge(layer, testEnv), Layer.provideMerge(layer, liveEnv))
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ const env = SessionProcessor.layer.pipe(Layer.provideMerge(deps))
|
|||
|
||||
const it = testEffect(env)
|
||||
|
||||
it.effect("session.processor effect tests capture llm input cleanly", () => {
|
||||
it.live("session.processor effect tests capture llm input cleanly", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -316,7 +316,7 @@ it.effect("session.processor effect tests capture llm input cleanly", () => {
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests stop after token overflow requests compaction", () => {
|
||||
it.live("session.processor effect tests stop after token overflow requests compaction", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -376,7 +376,7 @@ it.effect("session.processor effect tests stop after token overflow requests com
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests reset reasoning state across retries", () => {
|
||||
it.live("session.processor effect tests reset reasoning state across retries", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -449,7 +449,7 @@ it.effect("session.processor effect tests reset reasoning state across retries",
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests do not retry unknown json errors", () => {
|
||||
it.live("session.processor effect tests do not retry unknown json errors", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -495,7 +495,7 @@ it.effect("session.processor effect tests do not retry unknown json errors", ()
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests retry recognized structured json errors", () => {
|
||||
it.live("session.processor effect tests retry recognized structured json errors", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -544,7 +544,7 @@ it.effect("session.processor effect tests retry recognized structured json error
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests publish retry status updates", () => {
|
||||
it.live("session.processor effect tests publish retry status updates", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -611,7 +611,7 @@ it.effect("session.processor effect tests publish retry status updates", () => {
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests compact on structured context overflow", () => {
|
||||
it.live("session.processor effect tests compact on structured context overflow", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -656,7 +656,7 @@ it.effect("session.processor effect tests compact on structured context overflow
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests mark pending tools as aborted on cleanup", () => {
|
||||
it.live("session.processor effect tests mark pending tools as aborted on cleanup", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -725,7 +725,7 @@ it.effect("session.processor effect tests mark pending tools as aborted on clean
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests record aborted errors and idle state", () => {
|
||||
it.live("session.processor effect tests record aborted errors and idle state", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -807,7 +807,7 @@ it.effect("session.processor effect tests record aborted errors and idle state",
|
|||
)
|
||||
})
|
||||
|
||||
it.effect("session.processor effect tests mark interruptions aborted without manual abort", () => {
|
||||
it.live("session.processor effect tests mark interruptions aborted without manual abort", () => {
|
||||
return provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ const boot = Effect.fn("test.boot")(function* (input?: { title?: string }) {
|
|||
|
||||
// Loop semantics
|
||||
|
||||
it.effect("loop exits immediately when last assistant has stop finish", () =>
|
||||
it.live("loop exits immediately when last assistant has stop finish", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -432,7 +432,7 @@ it.effect("loop exits immediately when last assistant has stop finish", () =>
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("loop calls LLM and returns assistant message", () =>
|
||||
it.live("loop calls LLM and returns assistant message", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -450,7 +450,7 @@ it.effect("loop calls LLM and returns assistant message", () =>
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("loop continues when finish is tool-calls", () =>
|
||||
it.live("loop continues when finish is tool-calls", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -471,7 +471,7 @@ it.effect("loop continues when finish is tool-calls", () =>
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("failed subtask preserves metadata on error tool state", () =>
|
||||
it.live("failed subtask preserves metadata on error tool state", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -532,7 +532,7 @@ it.effect("failed subtask preserves metadata on error tool state", () =>
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("loop sets status to busy then idle", () =>
|
||||
it.live("loop sets status to busy then idle", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -567,7 +567,7 @@ it.effect("loop sets status to busy then idle", () =>
|
|||
|
||||
// Cancel semantics
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel interrupts loop and resolves with an assistant message",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
@ -598,7 +598,7 @@ it.effect(
|
|||
30_000,
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel records MessageAbortedError on interrupted process",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
@ -632,7 +632,7 @@ it.effect(
|
|||
30_000,
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel finalizes subtask tool state",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
@ -695,7 +695,7 @@ it.effect(
|
|||
30_000,
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"cancel with queued callers resolves all cleanly",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
@ -733,7 +733,7 @@ it.effect(
|
|||
|
||||
// Queue semantics
|
||||
|
||||
it.effect("concurrent loop callers get same result", () =>
|
||||
it.live("concurrent loop callers get same result", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -752,7 +752,7 @@ it.effect("concurrent loop callers get same result", () =>
|
|||
),
|
||||
)
|
||||
|
||||
it.effect("concurrent loop callers all receive same error result", () =>
|
||||
it.live("concurrent loop callers all receive same error result", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -780,7 +780,7 @@ it.effect("concurrent loop callers all receive same error result", () =>
|
|||
),
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"prompt submitted during an active run is included in the next LLM input",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
@ -860,7 +860,7 @@ it.effect(
|
|||
30_000,
|
||||
)
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"assertNotBusy throws BusyError when loop running",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
@ -897,7 +897,7 @@ it.effect(
|
|||
30_000,
|
||||
)
|
||||
|
||||
it.effect("assertNotBusy succeeds when idle", () =>
|
||||
it.live("assertNotBusy succeeds when idle", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -914,7 +914,7 @@ it.effect("assertNotBusy succeeds when idle", () =>
|
|||
|
||||
// Shell semantics
|
||||
|
||||
it.effect(
|
||||
it.live(
|
||||
"shell rejects with BusyError when loop running",
|
||||
() =>
|
||||
provideTmpdirInstance(
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function makeConfig(url: string) {
|
|||
}
|
||||
|
||||
describe("session.prompt provider integration", () => {
|
||||
it.effect("loop returns assistant text through local provider", () =>
|
||||
it.live("loop returns assistant text through local provider", () =>
|
||||
Effect.gen(function* () {
|
||||
const llm = yield* TestLLMServer
|
||||
return yield* provideTmpdirInstance(
|
||||
|
|
@ -87,7 +87,7 @@ describe("session.prompt provider integration", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("loop consumes queued replies across turns", () =>
|
||||
it.live("loop consumes queued replies across turns", () =>
|
||||
Effect.gen(function* () {
|
||||
const llm = yield* TestLLMServer
|
||||
return yield* provideTmpdirInstance(
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ describe("Truncate", () => {
|
|||
const DAY_MS = 24 * 60 * 60 * 1000
|
||||
const it = testEffect(Layer.mergeAll(TruncateSvc.defaultLayer, NodeFileSystem.layer))
|
||||
|
||||
it.effect("deletes files older than 7 days and preserves recent files", () =>
|
||||
it.live("deletes files older than 7 days and preserves recent files", () =>
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* FileSystem.FileSystem
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue