mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-25 05:44:37 +00:00
feat(truncate): allow configuring tool output truncation limits (#23770)
Co-authored-by: rgs_ramp <rgs@ramp.com> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, test, expect } from "bun:test"
|
||||
import { NodeFileSystem } from "@effect/platform-node"
|
||||
import { Effect, FileSystem, Layer } from "effect"
|
||||
import { Truncate } from "../../src/tool"
|
||||
import { Config } from "../../src/config"
|
||||
import { Identifier } from "../../src/id/id"
|
||||
import { Process } from "../../src/util"
|
||||
import { Filesystem } from "../../src/util"
|
||||
@@ -14,6 +15,14 @@ const ROOT = path.resolve(import.meta.dir, "..", "..")
|
||||
|
||||
const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, NodeFileSystem.layer))
|
||||
|
||||
const configuredLayer = (cfg: Config.Info) =>
|
||||
Layer.mergeAll(
|
||||
Truncate.defaultLayer,
|
||||
NodeFileSystem.layer,
|
||||
Layer.mock(Config.Service)({ get: () => Effect.succeed(cfg) }),
|
||||
)
|
||||
const configuredIt = (cfg: Config.Info) => testEffect(configuredLayer(cfg))
|
||||
|
||||
describe("Truncate", () => {
|
||||
describe("output", () => {
|
||||
it.live("truncates large json file by bytes", () =>
|
||||
@@ -94,6 +103,61 @@ describe("Truncate", () => {
|
||||
expect(Truncate.MAX_BYTES).toBe(50 * 1024)
|
||||
})
|
||||
|
||||
it.live("limits() falls back to MAX_LINES/MAX_BYTES when Config is not provided", () =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Truncate.Service
|
||||
const resolved = yield* svc.limits()
|
||||
expect(resolved.maxLines).toBe(Truncate.MAX_LINES)
|
||||
expect(resolved.maxBytes).toBe(Truncate.MAX_BYTES)
|
||||
}),
|
||||
)
|
||||
|
||||
describe("with tool_output config", () => {
|
||||
const limitsIt = configuredIt({ tool_output: { max_lines: 123, max_bytes: 456 } })
|
||||
limitsIt.live("limits() reflects config overrides", () =>
|
||||
Effect.gen(function* () {
|
||||
const resolved = yield* (yield* Truncate.Service).limits()
|
||||
expect(resolved.maxLines).toBe(123)
|
||||
expect(resolved.maxBytes).toBe(456)
|
||||
}),
|
||||
)
|
||||
|
||||
// Huge byte budget isolates line truncation. 100 lines against max_lines: 10
|
||||
// proves the configured line limit is what `output()` enforces.
|
||||
const lineIt = configuredIt({ tool_output: { max_lines: 10, max_bytes: 1024 * 1024 } })
|
||||
lineIt.live("output() truncates to configured max_lines", () =>
|
||||
Effect.gen(function* () {
|
||||
const content = Array.from({ length: 100 }, (_, i) => `line${i}`).join("\n")
|
||||
const result = yield* (yield* Truncate.Service).output(content)
|
||||
expect(result.truncated).toBe(true)
|
||||
expect(result.content).toContain("...90 lines truncated...")
|
||||
}),
|
||||
)
|
||||
|
||||
// Huge line budget isolates byte truncation.
|
||||
const byteIt = configuredIt({ tool_output: { max_lines: 1_000_000, max_bytes: 100 } })
|
||||
byteIt.live("output() truncates to configured max_bytes", () =>
|
||||
Effect.gen(function* () {
|
||||
const content = "a".repeat(1000)
|
||||
const result = yield* (yield* Truncate.Service).output(content)
|
||||
expect(result.truncated).toBe(true)
|
||||
expect(result.content).toContain("bytes truncated...")
|
||||
}),
|
||||
)
|
||||
|
||||
const overrideIt = configuredIt({ tool_output: { max_lines: 10, max_bytes: 100 } })
|
||||
overrideIt.live("per-call options still override config", () =>
|
||||
Effect.gen(function* () {
|
||||
const content = Array.from({ length: 50 }, (_, i) => `line${i}`).join("\n")
|
||||
const result = yield* (yield* Truncate.Service).output(content, {
|
||||
maxLines: 1000,
|
||||
maxBytes: 1024 * 1024,
|
||||
})
|
||||
expect(result.truncated).toBe(false)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it.live("large single-line file truncates with byte message", () =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Truncate.Service
|
||||
|
||||
Reference in New Issue
Block a user