mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: name the memory setting in ignored-input notes and keep conversions honest
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4e2eec4c64
commit
24feb11cef
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { AI_AGENT_SCHEMA, memoryPropertyFor } from './flowInfers'
|
||||
import { AI_AGENT_SCHEMA, memoryOptionLabel, memoryPropertyFor } from './flowInfers'
|
||||
import {
|
||||
AGENT_FIELD_BY_KEY,
|
||||
AGENT_FIELDS,
|
||||
@@ -94,6 +94,7 @@ describe('historyInputApplies', () => {
|
||||
expect(agentMemoryMode({ kind: 'window', context_length: 10 })).toBe('managed')
|
||||
expect(agentMemoryMode({ kind: 'manual', messages: [] })).toBe('legacy')
|
||||
expect(agentMemoryMode({ kind: 'auto', context_length: 4, memory_id: 'x' })).toBe('legacy')
|
||||
expect(agentMemoryMode({ kind: 'auto' })).toBe('off')
|
||||
expect(historyInputApplies('memory_id', 'managed')).toBe(true)
|
||||
expect(historyInputApplies('previous_messages', 'managed')).toBe(false)
|
||||
expect(historyInputApplies('memory_id', 'off')).toBe(false)
|
||||
@@ -104,6 +105,16 @@ describe('historyInputApplies', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('memoryOptionLabel', () => {
|
||||
// The ignored-input note names the setting by the same label its own button carries.
|
||||
it('names each memory option the way the field renders it', () => {
|
||||
expect(memoryOptionLabel({ kind: 'manual', messages: [] })).toBe('Previous messages (legacy)')
|
||||
expect(memoryOptionLabel({ kind: 'auto', context_length: 4 })).toBe('On (legacy)')
|
||||
expect(memoryOptionLabel({ kind: 'window', context_length: 10 })).toBe('On')
|
||||
expect(memoryOptionLabel(undefined)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('memoryPropertyFor', () => {
|
||||
const property = schemaProperties.memory
|
||||
const kinds = (value: unknown) =>
|
||||
|
||||
@@ -45,9 +45,12 @@ export function keepsManagedMemory(memory: any): boolean {
|
||||
|
||||
export type AgentMemoryMode = 'legacy' | 'managed' | 'off'
|
||||
|
||||
/** Which shape the step's memory holds: an older `auto`/`manual` setting, or the current one. */
|
||||
/** Which shape a run reads this memory as: an older `auto`/`manual` setting, or the current one. */
|
||||
export function agentMemoryMode(memory: any): AgentMemoryMode {
|
||||
if (memory?.kind === 'auto' || memory?.kind === 'manual') return 'legacy'
|
||||
if (memory?.kind === 'manual') return 'legacy'
|
||||
// The worker reads an `auto` that keeps no messages as off, history inputs included, so the form
|
||||
// offers what that run would read.
|
||||
if (memory?.kind === 'auto') return memory.context_length ? 'legacy' : 'off'
|
||||
return keepsManagedMemory(memory) ? 'managed' : 'off'
|
||||
}
|
||||
|
||||
@@ -66,7 +69,7 @@ export function historyInputApplies(
|
||||
/** A memory setting in words, for a linked agent's summary. */
|
||||
export function describeMemoryPolicy(memory: any): string {
|
||||
if (keepsManagedMemory(memory)) return `Last ${memory.context_length} messages`
|
||||
if (memory?.kind === 'manual') return 'Off, sends a fixed list of messages'
|
||||
if (memory?.kind === 'manual') return 'Off, sends previous messages saved with the agent'
|
||||
return 'Off'
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,10 @@
|
||||
// state, so switching to that setting is the only choice.
|
||||
let legacyEquivalent = $derived(memory?.kind === 'auto' && !legacyMemoryId)
|
||||
|
||||
// The older setting never read the step's own memory id, so a conversion that promises the same
|
||||
// behaviour, or the run's id, drops it rather than bringing it to life. Off keeps ignoring it.
|
||||
function switchToEquivalent() {
|
||||
if (on) delete args.memory_id
|
||||
args.memory = {
|
||||
type: 'static',
|
||||
value: on ? { kind: 'window', context_length: memory?.context_length } : { kind: 'off' }
|
||||
@@ -52,6 +55,8 @@
|
||||
function convertLegacyMemoryId(keepAsMemoryId: boolean) {
|
||||
if (keepAsMemoryId && legacyMemoryId) {
|
||||
args.memory_id = { type: 'static', value: legacyMemoryId }
|
||||
} else {
|
||||
delete args.memory_id
|
||||
}
|
||||
args.memory = {
|
||||
type: 'static',
|
||||
@@ -74,8 +79,8 @@
|
||||
<Alert type="info" title="Older memory setting" class="mt-2">
|
||||
<div class="flex flex-col gap-2">
|
||||
<span>
|
||||
An earlier version of the editor saved a fixed list of messages here, which this agent still
|
||||
sends.
|
||||
An earlier version of the editor saved these previous messages inside the memory setting,
|
||||
and this agent still sends them.
|
||||
</span>
|
||||
{#if historyOnStep}
|
||||
<div class="flex">
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
} from '../agentFormFields'
|
||||
import AgentToolRoster from './AgentToolRoster.svelte'
|
||||
import AgentMemoryNotes from './AgentMemoryNotes.svelte'
|
||||
import { memoryPropertyFor } from '../flowInfers'
|
||||
import { memoryOptionLabel, memoryPropertyFor } from '../flowInfers'
|
||||
|
||||
interface Props {
|
||||
schema: Schema | { properties?: Record<string, any> }
|
||||
@@ -241,6 +241,22 @@
|
||||
'memory' in schemaProperties &&
|
||||
(args?.memory?.type === 'javascript' || args?.memory?.type === 'ai')
|
||||
)
|
||||
// Names the legacy value the way the memory field's own button does, reading it wherever the mode
|
||||
// came from, so the row and the setting it points at cannot name it differently.
|
||||
let legacyMemoryNote = $derived.by(() => {
|
||||
const onThisForm = 'memory' in schemaProperties
|
||||
const label = memoryOptionLabel(
|
||||
onThisForm
|
||||
? args?.memory?.type === 'static'
|
||||
? args.memory.value
|
||||
: undefined
|
||||
: linkedMemory?.memory
|
||||
)
|
||||
return onThisForm
|
||||
? `Ignored while memory is set to ${label}.`
|
||||
: `Ignored while the agent's memory is set to ${label}.`
|
||||
})
|
||||
|
||||
let memoryIdOffered = $derived(
|
||||
(memoryMode === 'managed' || memoryIsExpression) &&
|
||||
scopedFields.some((spec) => spec.key === 'memory_id')
|
||||
@@ -582,7 +598,7 @@
|
||||
{#if isHistoryKey(spec.key) && !historyInputApplies(spec.key, memoryMode)}
|
||||
<p class="mt-1 text-2xs text-hint">
|
||||
{memoryMode === 'legacy'
|
||||
? 'Not read by the older memory setting on this step.'
|
||||
? legacyMemoryNote
|
||||
: `Ignored while managed memory is ${memoryMode === 'managed' ? 'on' : 'off'}.`}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
@@ -6,6 +6,19 @@ import type { FlowModule, InputTransform } from '$lib/gen'
|
||||
import { AGENT_FLOW_LOCAL_KEYS } from './agentResourceUtils'
|
||||
import { AGENT_HISTORY_KEYS } from './agentFormFields'
|
||||
|
||||
/** Display names for the memory field's options, so anything else naming the setting an author
|
||||
* picked cannot drift from the button they see. */
|
||||
export const MEMORY_OPTION_LABELS: Record<string, string> = {
|
||||
off: 'Off',
|
||||
window: 'On',
|
||||
auto: 'On (legacy)',
|
||||
manual: 'Previous messages (legacy)'
|
||||
}
|
||||
|
||||
export function memoryOptionLabel(memory: any): string | undefined {
|
||||
return memory?.kind ? MEMORY_OPTION_LABELS[memory.kind] : undefined
|
||||
}
|
||||
|
||||
export const AI_AGENT_SCHEMA: Schema = {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
properties: {
|
||||
@@ -42,12 +55,7 @@ export const AI_AGENT_SCHEMA: Schema = {
|
||||
type: 'object',
|
||||
description:
|
||||
'Windmill stores the conversation and sends its last messages with each request.',
|
||||
enumLabels: {
|
||||
off: 'Off',
|
||||
window: 'On',
|
||||
auto: 'On (legacy)',
|
||||
manual: 'Previous messages (legacy)'
|
||||
},
|
||||
enumLabels: MEMORY_OPTION_LABELS,
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
|
||||
Reference in New Issue
Block a user