Skip to content
Merged
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
8 changes: 6 additions & 2 deletions packages/core/src/services/prompt_renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,12 @@ export class ChatLunaPromptRenderService {
return selectFromList(args.join(','), false)
})

this.registerFunctionProvider('pick', (args) => {
return selectFromList(args.join(','), true)
this.registerFunctionProvider('pick', (args, _variables, cfg) => {
return selectFromList(
args.join(','),
true,
cfg?.conversationId ?? ''
)
})

this.registerFunctionProvider('roll', (args) => {
Expand Down
13 changes: 10 additions & 3 deletions packages/core/src/utils/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,18 @@ export const getTimeDiff = (time1: string, time2: string): string => {
)
}

export const selectFromList = (args: string, isPick: boolean): string => {
export const selectFromList = (
args: string,
isPick: boolean,
seed: string = ''
): string => {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const items = args.split(',').map((item) => item.trim())
if (isPick) {
// TODO: Implement stable selection for 'pick'
return items[Math.floor(Math.random() * items.length)]
const hash = crypto
.createHash('sha1')
.update(`${seed}:${args}`)
.digest()
return items[hash.readUInt32BE(0) % items.length]
}
return items[Math.floor(Math.random() * items.length)]
}
Expand Down
33 changes: 33 additions & 0 deletions packages/core/tests/conversation-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import {
getMessageContent,
parsePresetLaneInput
} from '../src/utils/message_content'
import { ChatLunaPromptRenderService } from '../src/services/prompt_renderer'
import {
applyPresetLane,
computeBaseBindingKey
} from '../src/types'
import { usageSourceFromStack } from '../src/utils/usage_source'
import { selectFromList } from '../src/utils/string'
import {
createMessage,
type BindingSessionShape,
Expand Down Expand Up @@ -192,6 +194,37 @@ it('usageSourceFromStack reads package names instead of folder names', () => {
)
})

it('selectFromList keeps pick stable for a seed', () => {
assert.equal(selectFromList('red,green,blue', true, 'stable'), 'blue')
assert.equal(selectFromList('red,green,blue', true, 'stable'), 'blue')
assert.equal(
selectFromList('red,green,blue', true, 'conversation-b'),
'green'
)
})

it('prompt pick renders without configurable options', async () => {
const service = new ChatLunaPromptRenderService()
const result = await service.renderTemplate('{pick("red","green","blue")}')

assert.equal(result.text, 'green')
})

it('prompt pick uses conversation id as stable seed', async () => {
const service = new ChatLunaPromptRenderService()
const result = await service.renderTemplate(
'{pick("red","green","blue")}',
{},
{
configurable: {
conversationId: 'conversation-b'
}
}
)

assert.equal(result.text, 'green')
})

it('getMessageContent flattens structured text parts', () => {
assert.equal(
getMessageContent([
Expand Down