mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
Moved tools property out of workflows in block definitions, updated serializer & tests accordingly
This commit is contained in:
@@ -4,42 +4,71 @@ import { SerializedWorkflow } from '../types';
|
||||
import { BlockState } from '@/stores/workflow/types';
|
||||
import { OutputType } from '@/blocks/types';
|
||||
|
||||
// Mock icons
|
||||
jest.mock('@/components/icons', () => ({
|
||||
AgentIcon: () => 'AgentIcon',
|
||||
ApiIcon: () => 'ApiIcon',
|
||||
CodeIcon: () => 'CodeIcon',
|
||||
}));
|
||||
|
||||
// Mock blocks
|
||||
jest.mock('@/blocks', () => ({
|
||||
getBlock: (type: string) => {
|
||||
if (type === 'http') {
|
||||
if (type === 'api') {
|
||||
return {
|
||||
type,
|
||||
toolbar: {
|
||||
title: 'API',
|
||||
description: 'Use any API',
|
||||
bgColor: '#2F55FF',
|
||||
icon: () => null,
|
||||
category: 'basic',
|
||||
},
|
||||
tools: {
|
||||
access: ['http.request']
|
||||
},
|
||||
workflow: {
|
||||
tools: {
|
||||
access: ['http.request'],
|
||||
config: {
|
||||
tool: () => 'http.request'
|
||||
}
|
||||
},
|
||||
outputType: 'json',
|
||||
inputs: {
|
||||
url: 'string',
|
||||
method: 'string'
|
||||
},
|
||||
outputType: 'json'
|
||||
subBlocks: []
|
||||
}
|
||||
};
|
||||
}
|
||||
// Default agent block config
|
||||
return {
|
||||
type,
|
||||
toolbar: {
|
||||
title: 'Agent',
|
||||
description: 'Use any LLM',
|
||||
bgColor: '#7F2FFF',
|
||||
icon: () => null,
|
||||
category: 'basic',
|
||||
},
|
||||
tools: {
|
||||
access: ['openai.chat'],
|
||||
config: {
|
||||
tool: () => 'openai.chat'
|
||||
}
|
||||
},
|
||||
workflow: {
|
||||
tools: {
|
||||
access: ['openai.chat'],
|
||||
config: {
|
||||
tool: () => 'openai.chat'
|
||||
}
|
||||
},
|
||||
outputType: 'string',
|
||||
inputs: {
|
||||
prompt: 'string'
|
||||
},
|
||||
outputType: 'string'
|
||||
subBlocks: []
|
||||
}
|
||||
};
|
||||
},
|
||||
getBlockTypeForTool: (toolId: string) => {
|
||||
const toolToType: Record<string, string> = {
|
||||
'openai.chat': 'agent',
|
||||
'http.request': 'api',
|
||||
'function': 'function'
|
||||
};
|
||||
return toolToType[toolId];
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -79,7 +108,7 @@ describe('Serializer', () => {
|
||||
},
|
||||
'http-1': {
|
||||
id: 'http-1',
|
||||
type: 'http',
|
||||
type: 'api',
|
||||
name: 'API Call',
|
||||
position: { x: 400, y: 100 },
|
||||
subBlocks: {
|
||||
@@ -165,7 +194,7 @@ describe('Serializer', () => {
|
||||
const blocks: Record<string, BlockState> = {
|
||||
'input-1': {
|
||||
id: 'input-1',
|
||||
type: 'http',
|
||||
type: 'api',
|
||||
name: 'Data Input',
|
||||
position: { x: 100, y: 100 },
|
||||
subBlocks: {
|
||||
@@ -203,7 +232,7 @@ describe('Serializer', () => {
|
||||
},
|
||||
'output-1': {
|
||||
id: 'output-1',
|
||||
type: 'http',
|
||||
type: 'api',
|
||||
name: 'Data Output',
|
||||
position: { x: 500, y: 100 },
|
||||
subBlocks: {
|
||||
@@ -321,7 +350,7 @@ describe('Serializer', () => {
|
||||
const { blocks } = serializer.deserializeWorkflow(workflow);
|
||||
const block = blocks['agent-1'];
|
||||
|
||||
expect(block.type).toBe('openai.chat');
|
||||
expect(block.type).toBe('agent');
|
||||
expect(block.subBlocks.model.value).toBe('gpt-4o');
|
||||
expect(block.subBlocks.systemPrompt.value).toBe('You are helpful');
|
||||
expect(block.outputType).toBe('string');
|
||||
|
||||
+18
-15
@@ -1,7 +1,7 @@
|
||||
import { BlockState, SubBlockState } from '@/stores/workflow/types';
|
||||
import { Edge } from 'reactflow';
|
||||
import { SerializedBlock, SerializedConnection, SerializedWorkflow } from './types';
|
||||
import { getBlock } from '@/blocks';
|
||||
import { getBlock, getBlockTypeForTool } from '@/blocks';
|
||||
import { OutputType, SubBlockType } from '@/blocks/types';
|
||||
|
||||
export class Serializer {
|
||||
@@ -25,7 +25,7 @@ export class Serializer {
|
||||
}
|
||||
|
||||
// Get the tool ID from the block's configuration
|
||||
const tools = blockConfig.workflow.tools;
|
||||
const tools = blockConfig.tools;
|
||||
if (!tools?.access || tools.access.length === 0) {
|
||||
throw new Error(`No tools specified for block type: ${block.type}`);
|
||||
}
|
||||
@@ -83,15 +83,28 @@ export class Serializer {
|
||||
}
|
||||
|
||||
private deserializeBlock(serialized: SerializedBlock): BlockState {
|
||||
const toolId = serialized.config.tool;
|
||||
const blockType = getBlockTypeForTool(toolId);
|
||||
|
||||
if (!blockType) {
|
||||
throw new Error(`Could not determine block type for tool: ${toolId}`);
|
||||
}
|
||||
|
||||
const blockConfig = getBlock(blockType);
|
||||
if (!blockConfig) {
|
||||
throw new Error(`Block configuration not found for type: ${blockType}`);
|
||||
}
|
||||
|
||||
return {
|
||||
id: serialized.id,
|
||||
type: serialized.config.tool,
|
||||
name: `${serialized.config.tool} Block`,
|
||||
type: blockType,
|
||||
name: `${blockType} Block`,
|
||||
position: serialized.position,
|
||||
subBlocks: Object.entries(serialized.config.params).reduce((acc, [key, value]) => {
|
||||
const subBlock = blockConfig.workflow.subBlocks?.find(sb => sb.id === key);
|
||||
acc[key] = {
|
||||
id: key,
|
||||
type: this.inferSubBlockType(value),
|
||||
type: subBlock?.type || 'short-input',
|
||||
value: value
|
||||
};
|
||||
return acc;
|
||||
@@ -99,14 +112,4 @@ export class Serializer {
|
||||
outputType: serialized.config.interface.outputs.output as OutputType
|
||||
};
|
||||
}
|
||||
|
||||
private inferSubBlockType(value: any): SubBlockType {
|
||||
if (Array.isArray(value) && Array.isArray(value[0])) {
|
||||
return 'table';
|
||||
}
|
||||
if (typeof value === 'string' && value.length > 100) {
|
||||
return 'long-input';
|
||||
}
|
||||
return 'short-input';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user