Skip to content

Commit ca6884c

Browse files
authored
fix(memories): simplified memories, added memories subblock for agent (#432)
* fix(memories): simplified memories, added memories subblock for agent * removed raw data from memory block, simplified memory config * fix(persistence): persist collapsed state for responseFormat code subblock (#429) * fix(persistence): persist collapsed state for responseFormat code subblock * add additional type safety * acknowledged PR comments
1 parent 2fb0894 commit ca6884c

File tree

13 files changed

+669
-475
lines changed

13 files changed

+669
-475
lines changed

apps/docs/content/docs/tools/memory.mdx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,15 @@ Create persistent storage for data that needs to be accessed across multiple wor
4343

4444
### `memory_add`
4545

46-
Add a new memory to the database or append to existing memory with the same ID. When appending to existing memory, the memory types must match.
46+
Add a new memory to the database or append to existing memory with the same ID.
4747

4848
#### Input
4949

5050
| Parameter | Type | Required | Description |
5151
| --------- | ---- | -------- | ----------- |
5252
| `id` | string | Yes | Identifier for the memory. If a memory with this ID already exists, the new data will be appended to it. |
53-
| `type` | string | Yes | Type of memory \(agent or raw\) |
54-
| `role` | string | No | Role for agent memory \(user, assistant, or system\) |
55-
| `content` | string | No | Content for agent memory |
56-
| `rawData` | json | No | Raw data to store \(JSON format\) |
53+
| `role` | string | Yes | Role for agent memory \(user, assistant, or system\) |
54+
| `content` | string | Yes | Content for agent memory |
5755

5856
#### Output
5957

apps/sim/app/api/memory/route.ts

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ export async function GET(request: NextRequest) {
9696
* POST handler for creating new memories
9797
* Requires:
9898
* - key: Unique identifier for the memory (within workflow scope)
99-
* - type: Memory type ('agent' or 'raw')
100-
* - data: Memory content (varies by type)
99+
* - type: Memory type ('agent')
100+
* - data: Memory content (agent message with role and content)
101101
* - workflowId: ID of the workflow this memory belongs to
102102
*/
103103
export async function POST(request: NextRequest) {
@@ -124,13 +124,13 @@ export async function POST(request: NextRequest) {
124124
)
125125
}
126126

127-
if (!type || !['agent', 'raw'].includes(type)) {
127+
if (!type || type !== 'agent') {
128128
logger.warn(`[${requestId}] Invalid memory type: ${type}`)
129129
return NextResponse.json(
130130
{
131131
success: false,
132132
error: {
133-
message: 'Valid memory type (agent or raw) is required',
133+
message: 'Memory type must be "agent"',
134134
},
135135
},
136136
{ status: 400 }
@@ -220,30 +220,20 @@ export async function POST(request: NextRequest) {
220220
)
221221
}
222222

223-
// Handle appending based on memory type
223+
// Handle appending for agent type
224224
let updatedData
225225

226-
if (type === 'agent') {
227-
// For agent type
228-
const newMessage = data
229-
const existingData = existingMemory[0].data
230-
231-
// If existing data is an array, append to it
232-
if (Array.isArray(existingData)) {
233-
updatedData = [...existingData, newMessage]
234-
}
235-
// If existing data is a single message object, convert to array
236-
else {
237-
updatedData = [existingData, newMessage]
238-
}
239-
} else {
240-
// For raw type
241-
// Merge objects if they're objects, otherwise use the new data
242-
if (typeof existingMemory[0].data === 'object' && typeof data === 'object') {
243-
updatedData = { ...existingMemory[0].data, ...data }
244-
} else {
245-
updatedData = data
246-
}
226+
// For agent type
227+
const newMessage = data
228+
const existingData = existingMemory[0].data
229+
230+
// If existing data is an array, append to it
231+
if (Array.isArray(existingData)) {
232+
updatedData = [...existingData, newMessage]
233+
}
234+
// If existing data is a single message object, convert to array
235+
else {
236+
updatedData = [existingData, newMessage]
247237
}
248238

249239
// Update the existing memory with appended data
@@ -263,7 +253,7 @@ export async function POST(request: NextRequest) {
263253
workflowId,
264254
key,
265255
type,
266-
data: type === 'agent' ? (Array.isArray(data) ? data : [data]) : data,
256+
data: Array.isArray(data) ? data : [data],
267257
createdAt: new Date(),
268258
updatedAt: new Date(),
269259
}

apps/sim/app/w/[id]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import { Input } from '@/components/ui/input'
3030
import { Label } from '@/components/ui/label'
3131
import { Skeleton } from '@/components/ui/skeleton'
3232
import { Textarea } from '@/components/ui/textarea'
33-
import { getNodeEnv } from '@/lib/environment'
3433
import { createLogger } from '@/lib/logs/console-logger'
3534
import { getBaseDomain } from '@/lib/urls/utils'
3635
import { cn } from '@/lib/utils'
@@ -54,10 +53,8 @@ interface ChatDeployProps {
5453

5554
type AuthType = 'public' | 'password' | 'email'
5655

57-
const isDevelopment = getNodeEnv() === 'development'
58-
5956
const getDomainSuffix = (() => {
60-
const suffix = isDevelopment ? `.${getBaseDomain()}` : '.simstudio.ai'
57+
const suffix = process.env.NODE_ENV === 'development' ? `.${getBaseDomain()}` : '.simstudio.ai'
6158
return () => suffix
6259
})()
6360

apps/sim/app/w/[id]/components/workflow-block/components/sub-block/hooks/use-sub-block-value.ts

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ function handleProviderBasedApiKey(
1313
blockId: string,
1414
subBlockId: string,
1515
modelValue: string | null | undefined,
16-
storeValue: any
16+
storeValue: any,
17+
isModelChange = false
1718
) {
1819
// Only proceed if we have a model selected
1920
if (!modelValue) return
@@ -25,20 +26,25 @@ function handleProviderBasedApiKey(
2526
if (!provider || provider === 'ollama') return
2627

2728
const subBlockStore = useSubBlockStore.getState()
29+
const isAutoFillEnabled = useGeneralStore.getState().isAutoFillEnvVarsEnabled
2830

29-
// Try to get a saved API key for this provider
30-
const savedValue = subBlockStore.resolveToolParamValue(provider, 'apiKey', blockId)
31+
// Try to get a saved API key for this provider (only if auto-fill is enabled)
32+
const savedValue = isAutoFillEnabled
33+
? subBlockStore.resolveToolParamValue(provider, 'apiKey', blockId)
34+
: null
3135

32-
// If we have a valid API key, use it
33-
if (savedValue && savedValue !== '') {
34-
// Always update the value when switching models, even if it appears the same
35-
// This handles cases where the field shows masked values but needs to update
36-
subBlockStore.setValue(blockId, subBlockId, savedValue)
37-
} else {
38-
// Always clear the field when switching to a model with no API key
39-
// Don't wait for user interaction to clear it
36+
// If we have a valid saved API key and auto-fill is enabled, use it
37+
if (savedValue && savedValue !== '' && isAutoFillEnabled) {
38+
// Only update if the current value is different to avoid unnecessary updates
39+
if (storeValue !== savedValue) {
40+
subBlockStore.setValue(blockId, subBlockId, savedValue)
41+
}
42+
} else if (isModelChange && (!storeValue || storeValue === '')) {
43+
// Only clear the field when switching models AND the field is already empty
44+
// Don't clear existing user-entered values on initial load
4045
subBlockStore.setValue(blockId, subBlockId, '')
4146
}
47+
// If no saved value and this is initial load, preserve existing value
4248
}
4349

4450
/**
@@ -237,7 +243,7 @@ export function useSubBlockValue<T = any>(
237243

238244
// Handle different block types
239245
if (isProviderBasedBlock) {
240-
handleProviderBasedApiKey(blockId, subBlockId, modelValue, storeValue)
246+
handleProviderBasedApiKey(blockId, subBlockId, modelValue, storeValue, false)
241247
} else {
242248
// Normal handling for non-provider blocks
243249
handleStandardBlockApiKey(blockId, subBlockId, blockType, storeValue)
@@ -263,27 +269,12 @@ export function useSubBlockValue<T = any>(
263269
// Update the previous model reference
264270
prevModelRef.current = modelValue
265271

266-
// For provider-based blocks, always clear the field if needed
267-
// But only fill with saved values if auto-fill is enabled
272+
// Handle API key auto-fill for model changes
268273
if (modelValue) {
269-
const provider = getProviderFromModel(modelValue)
270-
271-
// Skip if we couldn't determine a provider
272-
if (!provider || provider === 'ollama') return
273-
274-
const subBlockStore = useSubBlockStore.getState()
275-
276-
// Check if there's a saved value for this provider
277-
const savedValue = subBlockStore.resolveToolParamValue(provider, 'apiKey', blockId)
278-
279-
if (savedValue && savedValue !== '' && isAutoFillEnvVarsEnabled) {
280-
// Only auto-fill if the feature is enabled
281-
subBlockStore.setValue(blockId, subBlockId, savedValue)
282-
} else {
283-
// Always clear immediately when switching to a model with no saved key
284-
// or when auto-fill is disabled
285-
subBlockStore.setValue(blockId, subBlockId, '')
286-
}
274+
handleProviderBasedApiKey(blockId, subBlockId, modelValue, storeValue, true)
275+
} else {
276+
// If no model is selected, clear the API key field
277+
useSubBlockStore.getState().setValue(blockId, subBlockId, '')
287278
}
288279
}
289280
}, [

apps/sim/blocks/blocks/agent.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,25 +61,22 @@ export const AgentBlock: BlockConfig<AgentResponse> = {
6161
layout: 'full',
6262
placeholder: 'Enter system prompt...',
6363
rows: 5,
64-
mode: 'basic',
6564
},
6665
{
67-
id: 'context',
66+
id: 'userPrompt',
6867
title: 'User Prompt',
6968
type: 'long-input',
7069
layout: 'full',
7170
placeholder: 'Enter context or user message...',
7271
rows: 3,
73-
mode: 'basic',
7472
},
7573
{
76-
id: 'messages',
77-
title: 'Messages',
78-
type: 'code',
74+
id: 'memories',
75+
title: 'Memories',
76+
type: 'short-input',
7977
layout: 'full',
78+
placeholder: 'Connect memory block output...',
8079
mode: 'advanced',
81-
language: 'javascript',
82-
placeholder: '[{"role": "user", "content": "Hello, can you help me with a question?"}]',
8380
},
8481
{
8582
id: 'model',
@@ -236,15 +233,10 @@ export const AgentBlock: BlockConfig<AgentResponse> = {
236233
},
237234
inputs: {
238235
systemPrompt: { type: 'string', required: false },
239-
context: { type: 'string', required: false },
236+
userPrompt: { type: 'string', required: false },
237+
memories: { type: 'json', required: false },
240238
model: { type: 'string', required: true },
241239
apiKey: { type: 'string', required: true },
242-
messages: {
243-
type: 'json',
244-
required: false,
245-
description:
246-
'Array of message objects with role and content fields for advanced chat history control.',
247-
},
248240
responseFormat: {
249241
type: 'json',
250242
required: false,

apps/sim/blocks/blocks/memory.ts

Lines changed: 12 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,11 @@ export const MemoryBlock: BlockConfig = {
4848
}
4949

5050
if (params.operation === 'add') {
51-
if (!params.type) {
52-
errors.push('Memory type is required for add operation')
53-
} else if (params.type === 'agent') {
54-
if (!params.role) {
55-
errors.push('Role is required for agent memory')
56-
}
57-
if (!params.content) {
58-
errors.push('Content is required for agent memory')
59-
}
60-
} else if (params.type === 'raw') {
61-
if (!params.rawData) {
62-
errors.push('Raw data is required for raw memory')
63-
}
51+
if (!params.role) {
52+
errors.push('Role is required for agent memory')
53+
}
54+
if (!params.content) {
55+
errors.push('Content is required for agent memory')
6456
}
6557
}
6658

@@ -77,14 +69,9 @@ export const MemoryBlock: BlockConfig = {
7769
const result: Record<string, any> = {
7870
...baseResult,
7971
id: params.id,
80-
type: params.type,
81-
}
82-
83-
if (params.type === 'agent') {
84-
result.role = params.role
85-
result.content = params.content
86-
} else if (params.type === 'raw') {
87-
result.rawData = params.rawData
72+
type: 'agent', // Always agent type
73+
role: params.role,
74+
content: params.content,
8875
}
8976

9077
return result
@@ -114,10 +101,8 @@ export const MemoryBlock: BlockConfig = {
114101
inputs: {
115102
operation: { type: 'string', required: true },
116103
id: { type: 'string', required: true },
117-
type: { type: 'string', required: false },
118104
role: { type: 'string', required: false },
119105
content: { type: 'string', required: false },
120-
rawData: { type: 'json', required: false },
121106
},
122107
outputs: {
123108
response: {
@@ -174,21 +159,6 @@ export const MemoryBlock: BlockConfig = {
174159
value: 'delete',
175160
},
176161
},
177-
{
178-
id: 'type',
179-
title: 'Type',
180-
type: 'dropdown',
181-
layout: 'full',
182-
options: [
183-
{ label: 'Agent', id: 'agent' },
184-
{ label: 'Raw', id: 'raw' },
185-
],
186-
placeholder: 'Select memory type',
187-
condition: {
188-
field: 'operation',
189-
value: 'add',
190-
},
191-
},
192162
{
193163
id: 'role',
194164
title: 'Role',
@@ -201,12 +171,8 @@ export const MemoryBlock: BlockConfig = {
201171
],
202172
placeholder: 'Select agent role',
203173
condition: {
204-
field: 'type',
205-
value: 'agent',
206-
and: {
207-
field: 'operation',
208-
value: 'add',
209-
},
174+
field: 'operation',
175+
value: 'add',
210176
},
211177
},
212178
{
@@ -216,28 +182,8 @@ export const MemoryBlock: BlockConfig = {
216182
layout: 'full',
217183
placeholder: 'Enter message content',
218184
condition: {
219-
field: 'type',
220-
value: 'agent',
221-
and: {
222-
field: 'operation',
223-
value: 'add',
224-
},
225-
},
226-
},
227-
{
228-
id: 'rawData',
229-
title: 'Raw Data',
230-
type: 'code',
231-
layout: 'full',
232-
language: 'json',
233-
placeholder: '{"key": "value"}',
234-
condition: {
235-
field: 'type',
236-
value: 'raw',
237-
and: {
238-
field: 'operation',
239-
value: 'add',
240-
},
185+
field: 'operation',
186+
value: 'add',
241187
},
242188
},
243189
],

0 commit comments

Comments
 (0)