Skip to content
Open
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
3 changes: 2 additions & 1 deletion agents/base-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ End every response by calling the suggest_followups tool with exactly 3 followup

// `model` is absent only when the generator is driven directly (tests) or
// by a runtime predating AgentStepContext.model.
const contextWindow = CONTEXT_WINDOWS[model ?? ''] ?? DEFAULT_CONTEXT_WINDOW
const contextWindow =
(model && CONTEXT_WINDOWS[model]) ?? DEFAULT_CONTEXT_WINDOW
const maxContextLength = Math.floor(contextWindow * CONTEXT_BUDGET_FRACTION)

while (true) {
Expand Down
124 changes: 123 additions & 1 deletion common/src/util/__tests__/string.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'bun:test'

import { pluralize } from '../string'
import { pluralize, truncateStringWithMessage } from '../string'

describe('pluralize', () => {
it('should handle singular and plural cases correctly', () => {
Expand Down Expand Up @@ -235,5 +235,127 @@ describe('pluralize', () => {
expect(pluralize(2, 'query')).toBe('2 queries')
expect(pluralize(2, 'dependency')).toBe('2 dependencies')
})

describe('truncateStringWithMessage', () => {
it('should truncate from end by default', () => {
const result = truncateStringWithMessage({
str: 'Hello world, this is a test string',
maxLength: 20
})
expect(result).toContain('TRUNCATED')
expect(result.startsWith('Hello')).toBe(true)
})

it('should handle negative available length for END truncation', () => {
const result = truncateStringWithMessage({
str: 'Hello',
maxLength: 5,
remove: 'END'
})
expect(result).toBe('\n[TRUNCATED DUE TO LENGTH...]')
})

it('should handle zero available length for END truncation', () => {
const result = truncateStringWithMessage({
str: 'Hello world',
maxLength: 10,
remove: 'END'
})
expect(result).toBe('\n[TRUNCATED DUE TO LENGTH...]')
})

it('should truncate from start correctly', () => {
const result = truncateStringWithMessage({
str: 'Hello world, this is a test string',
maxLength: 50,
remove: 'START'
})
expect(result).toContain('TRUNCATED DUE TO LENGTH')
expect(result.endsWith('string')).toBe(true)
})

it('should handle negative available length for START truncation', () => {
const result = truncateStringWithMessage({
str: 'Hello world',
maxLength: 5,
remove: 'START'
})
expect(result).toBe('[...TRUNCATED DUE TO LENGTH]\n')
})

it('should handle zero available length for START truncation', () => {
const result = truncateStringWithMessage({
str: 'Hello world',
maxLength: 10,
remove: 'START'
})
expect(result).toBe('[...TRUNCATED DUE TO LENGTH]\n')
})

it('should truncate from middle correctly', () => {
const result = truncateStringWithMessage({
str: 'Hello world, this is a test string',
maxLength: 20,
remove: 'MIDDLE'
})
expect(result).toContain('TRUNCATED')
expect(result.startsWith('Hello')).toBe(true)
expect(result.endsWith('string')).toBe(true)
})

it('should truncate from start correctly', () => {
const result = truncateStringWithMessage({
str: 'Hello world, this is a test string',
maxLength: 50,
remove: 'START'
})
expect(result).toContain('TRUNCATED DUE TO LENGTH')
expect(result.endsWith('string')).toBe(true)
})

it('should handle negative available length for MIDDLE truncation', () => {
const result = truncateStringWithMessage({
str: 'Hello world',
maxLength: 5,
remove: 'MIDDLE'
})
expect(result).toBe('\n[...TRUNCATED DUE TO LENGTH...]\n')
})

it('should handle zero available length for MIDDLE truncation', () => {
const result = truncateStringWithMessage({
str: 'Hello world',
maxLength: 10,
remove: 'MIDDLE'
})
expect(result).toBe('\n[...TRUNCATED DUE TO LENGTH...]\n')
})

it('should return original string when within maxLength', () => {
const result = truncateStringWithMessage({
str: 'Short',
maxLength: 100
})
expect(result).toBe('Short')
})

it('should use custom message when provided', () => {
const result = truncateStringWithMessage({
str: 'Hello world, this is a test string',
maxLength: 20,
message: 'CUSTOM MSG'
})
expect(result).toContain('CUSTOM MSG')
expect(result.startsWith('Hello')).toBe(true)
})

it('should handle empty string', () => {
const result = truncateStringWithMessage({
str: '',
maxLength: 10
})
expect(result).toBe('')
})
})
})

8 changes: 5 additions & 3 deletions common/src/util/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ export const truncateStringWithMessage = ({

if (remove === 'END') {
const suffix = `\n[${message}...]`
return str.slice(0, maxLength - suffix.length) + suffix
const availableLength = Math.max(0, maxLength - suffix.length)
return str.slice(0, availableLength) + suffix
}
if (remove === 'START') {
const prefix = `[...${message}]\n`
return prefix + str.slice(str.length - maxLength + prefix.length)
const availableLength = Math.max(0, maxLength - prefix.length)
return prefix + str.slice(str.length - availableLength)
}

const middle = `\n[...${message}...]\n`
const length = Math.floor((maxLength - middle.length) / 2)
const length = Math.max(0, Math.floor((maxLength - middle.length) / 2))
return str.slice(0, length) + middle + str.slice(-length)
}

Expand Down
Loading