Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/core/src/session/runner/llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import { Snapshot } from "../../snapshot"
import { makeLocationNode } from "../../effect/app-node"
import { llmClient } from "../../effect/app-node-platform"

const MAX_OUTPUT_TOKENS = 32_000

/**
* Runs one durable coding-agent Session until it settles.
*
Expand Down Expand Up @@ -210,6 +212,9 @@ const layer = Layer.effect(
.map(SystemPart.make),
messages: [...toLLMMessages(context, model), ...(isLastStep ? [Message.assistant(MAX_STEPS_PROMPT)] : [])],
tools: toolMaterialization?.definitions ?? [],
generation: {
maxTokens: Math.min(model.route.defaults.limits?.output ?? 0, MAX_OUTPUT_TOKENS) || MAX_OUTPUT_TOKENS,
},
toolChoice: isLastStep ? "none" : undefined,
})
if (yield* compaction.compactIfNeeded({ sessionID: session.id, entries, model, request }))
Expand Down
21 changes: 21 additions & 0 deletions packages/core/test/session-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ const recoveryModel = Model.make({
provider: "fake",
route: OpenAIChat.route.with({ limits: { context: 20_000, output: 1_000 } }),
})
const fullContextOutputModel = Model.make({
id: "full-context-output",
provider: "fake",
route: OpenAIChat.route.with({ limits: { context: 500_000, output: 500_000 } }),
})
const authorizations: Tool.Context[] = []
const executions: string[] = []
const permission = Layer.succeed(
Expand Down Expand Up @@ -655,6 +660,22 @@ describe("SessionRunnerLLM", () => {
}),
)

it.effect("caps output when the catalog output limit consumes the full context window", () =>
Effect.gen(function* () {
yield* setup
const session = yield* SessionV2.Service
currentModel = fullContextOutputModel
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "hi" }), resume: false })
requests.length = 0
response = []

yield* session.resume(sessionID)

expect(requests).toHaveLength(1)
expect(requests[0]?.generation).toEqual({ maxTokens: 32_000 })
}),
)

it.effect("retries the first provider turn after system context becomes available", () =>
Effect.gen(function* () {
yield* setup
Expand Down
Loading