-
-
Notifications
You must be signed in to change notification settings - Fork 24.2k
feat(agentflow) Create Async Data Fetching Infrastructure in agentflow #5937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
24e923b
initial flow
j-sanaa edcda05
Fixed export types and added example application to test end to end …
j-sanaa 7406441
Fix build errors
j-sanaa b16878c
Merge branch 'main' into feat/agentflow-create-async-infra
j-sanaa ce06ee7
fix gemini comments
j-sanaa 14aab97
Merge branch 'main' into feat/agentflow-create-async-infra
j-sanaa 71b457a
Test bug fix
j-sanaa f01e9dd
Merge branch 'main' into feat/agentflow-create-async-infra
j-sanaa 4bf7cb8
Fixed comments
j-sanaa c3acc10
Removed API inspector example
j-sanaa 1cce67c
Refactor imports in index.ts for clarity
j-sanaa 6ef9497
Refactor exports and update type definitions
j-sanaa 06593a0
Remove empty line in index.ts
j-sanaa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
packages/agentflow/src/infrastructure/api/credentials.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import type { AxiosInstance } from 'axios' | ||
|
|
||
| import { bindCredentialsApi } from './credentials' | ||
|
|
||
| const mockClient = { | ||
| get: jest.fn() | ||
| } as unknown as jest.Mocked<AxiosInstance> | ||
|
|
||
| beforeEach(() => { | ||
| jest.clearAllMocks() | ||
| }) | ||
|
|
||
| describe('bindCredentialsApi', () => { | ||
| const api = bindCredentialsApi(mockClient) | ||
|
|
||
| describe('getAllCredentials', () => { | ||
| it('should call GET /credentials', async () => { | ||
| const mockCredentials = [{ id: '1', name: 'My OpenAI Key', credentialName: 'openAIApi' }] | ||
| ;(mockClient.get as jest.Mock).mockResolvedValue({ data: mockCredentials }) | ||
|
|
||
| const result = await api.getAllCredentials() | ||
| expect(mockClient.get).toHaveBeenCalledWith('/credentials') | ||
| expect(result).toEqual(mockCredentials) | ||
| }) | ||
| }) | ||
|
|
||
| describe('getCredentialsByName', () => { | ||
| it('should call GET /credentials with credentialName param', async () => { | ||
| const mockCredentials = [{ id: '1', name: 'My OpenAI Key', credentialName: 'openAIApi' }] | ||
| ;(mockClient.get as jest.Mock).mockResolvedValue({ data: mockCredentials }) | ||
|
|
||
| const result = await api.getCredentialsByName('openAIApi') | ||
| expect(mockClient.get).toHaveBeenCalledWith('/credentials', { params: { credentialName: 'openAIApi' } }) | ||
| expect(result).toEqual(mockCredentials) | ||
| }) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import type { AxiosInstance } from 'axios' | ||
|
|
||
| import type { Credential } from '@/core/types' | ||
|
|
||
| /** | ||
| * Create credentials API functions bound to a client instance | ||
| */ | ||
| export function bindCredentialsApi(client: AxiosInstance) { | ||
| return { | ||
| /** | ||
| * Get all credentials | ||
| */ | ||
| getAllCredentials: async (): Promise<Credential[]> => { | ||
| const response = await client.get('/credentials') | ||
| return response.data | ||
| }, | ||
|
|
||
| /** | ||
| * Get credentials filtered by component credential name | ||
| */ | ||
| getCredentialsByName: async (credentialName: string): Promise<Credential[]> => { | ||
| const response = await client.get('/credentials', { params: { credentialName } }) | ||
| return response.data | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export type CredentialsApi = ReturnType<typeof bindCredentialsApi> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,8 @@ | ||
| // API infrastructure - External data layer | ||
| export { type ChatflowsApi, createChatflowsApi } from './chatflows' | ||
| export { createApiClient } from './client' | ||
| export { bindCredentialsApi, type CredentialsApi } from './credentials' | ||
| export { type ApiServices, getLoadMethod, loadMethodRegistry } from './loadMethodRegistry' | ||
| export { bindChatModelsApi, type ChatModelsApi } from './models' | ||
| export { createNodesApi, type NodesApi } from './nodes' | ||
| export { bindToolsApi, type ToolsApi } from './tools' |
80 changes: 80 additions & 0 deletions
80
packages/agentflow/src/infrastructure/api/loadMethodRegistry.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import type { ApiServices } from './loadMethodRegistry' | ||
| import { getLoadMethod, loadMethodRegistry } from './loadMethodRegistry' | ||
|
|
||
| const mockApis: ApiServices = { | ||
| chatModelsApi: { | ||
| getChatModels: jest.fn(), | ||
| getModelsByProvider: jest.fn() | ||
| }, | ||
| toolsApi: { | ||
| getAllTools: jest.fn() | ||
| }, | ||
| credentialsApi: { | ||
| getAllCredentials: jest.fn(), | ||
| getCredentialsByName: jest.fn() | ||
| } | ||
| } | ||
|
|
||
| beforeEach(() => { | ||
| jest.clearAllMocks() | ||
| }) | ||
|
|
||
| describe('loadMethodRegistry', () => { | ||
| describe('listChatModels', () => { | ||
| it('should call chatModelsApi.getChatModels()', async () => { | ||
| const mockModels = [{ name: 'gpt-4', label: 'GPT-4' }] | ||
| ;(mockApis.chatModelsApi.getChatModels as jest.Mock).mockResolvedValue(mockModels) | ||
|
|
||
| const result = await loadMethodRegistry['listChatModels'](mockApis) | ||
| expect(mockApis.chatModelsApi.getChatModels).toHaveBeenCalled() | ||
| expect(result).toEqual(mockModels) | ||
| }) | ||
| }) | ||
|
|
||
| describe('listTools', () => { | ||
| it('should call toolsApi.getAllTools()', async () => { | ||
| const mockTools = [{ id: '1', name: 'Calculator' }] | ||
| ;(mockApis.toolsApi.getAllTools as jest.Mock).mockResolvedValue(mockTools) | ||
|
|
||
| const result = await loadMethodRegistry['listTools'](mockApis) | ||
| expect(mockApis.toolsApi.getAllTools).toHaveBeenCalled() | ||
| expect(result).toEqual(mockTools) | ||
| }) | ||
| }) | ||
|
|
||
| describe('listCredentials', () => { | ||
| it('should call credentialsApi.getCredentialsByName() with params.name', async () => { | ||
| const mockCredentials = [{ id: '1', name: 'My Key', credentialName: 'openAIApi' }] | ||
| ;(mockApis.credentialsApi.getCredentialsByName as jest.Mock).mockResolvedValue(mockCredentials) | ||
|
|
||
| const result = await loadMethodRegistry['listCredentials'](mockApis, { name: 'openAIApi' }) | ||
| expect(mockApis.credentialsApi.getCredentialsByName).toHaveBeenCalledWith('openAIApi') | ||
| expect(result).toEqual(mockCredentials) | ||
| }) | ||
| }) | ||
| }) | ||
|
|
||
| describe('getLoadMethod', () => { | ||
| it('should return the registry function for a known key', () => { | ||
| const fn = getLoadMethod('listChatModels') | ||
| expect(fn).toBeDefined() | ||
| expect(typeof fn).toBe('function') | ||
| }) | ||
|
|
||
| it('should return the registry function for listTools', () => { | ||
| const fn = getLoadMethod('listTools') | ||
| expect(fn).toBeDefined() | ||
| expect(typeof fn).toBe('function') | ||
| }) | ||
|
|
||
| it('should return the registry function for listCredentials', () => { | ||
| const fn = getLoadMethod('listCredentials') | ||
| expect(fn).toBeDefined() | ||
| expect(typeof fn).toBe('function') | ||
| }) | ||
|
|
||
| it('should return undefined for an unknown key', () => { | ||
| const fn = getLoadMethod('unknownMethod') | ||
| expect(fn).toBeUndefined() | ||
| }) | ||
| }) |
48 changes: 48 additions & 0 deletions
48
packages/agentflow/src/infrastructure/api/loadMethodRegistry.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import type { CredentialsApi } from './credentials' | ||
| import type { ChatModelsApi } from './models' | ||
| import type { ToolsApi } from './tools' | ||
|
|
||
| export interface ApiServices { | ||
| chatModelsApi: ChatModelsApi | ||
| toolsApi: ToolsApi | ||
| credentialsApi: CredentialsApi | ||
| } | ||
|
|
||
| /** | ||
| * Registry that maps `loadMethod` string keys — as declared on node `InputParam` definitions | ||
| * (e.g. `{ loadMethod: 'listTools' }`) — to functions that fetch the corresponding options | ||
| * from the Flowise API. | ||
| * | ||
| * Each entry receives the shared {@link ApiServices} instance and an optional `params` object, | ||
| * and must return a `Promise` of the option values to populate the node's dropdown. | ||
| * | ||
| * ### Built-in entries | ||
| * - `listChatModels` — fetches available chat models via `GET /assistants/components/chatmodels` | ||
| * - `listTools` — fetches available tool components via `POST /node-load-method/toolAgentflow` | ||
| * - `listCredentials` — fetches credentials filtered by `params.name` (credential component name) | ||
| * via `GET /credentials?credentialName=<name>` | ||
| * | ||
| */ | ||
| export const loadMethodRegistry: Record<string, (_apis: ApiServices, _params?: Record<string, unknown>) => Promise<unknown>> = { | ||
| listChatModels: (apis) => apis.chatModelsApi.getChatModels(), | ||
| listTools: (apis) => apis.toolsApi.getAllTools(), | ||
| listCredentials: (apis, params) => { | ||
| const name = params?.name | ||
| if (typeof name !== 'string') { | ||
| return Promise.reject(new Error('`listCredentials` requires a string `name` parameter.')) | ||
| } | ||
| return apis.credentialsApi.getCredentialsByName(name) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Looks up a load method handler by its string key. | ||
| * | ||
| * Returns `undefined` if no handler is registered for the given name, | ||
| * which callers should treat as a no-op or fallback. | ||
| * | ||
| * @param name - The `loadMethod` key declared on a node `InputParam` | ||
| */ | ||
| export function getLoadMethod(name: string): ((_apis: ApiServices, _params?: Record<string, unknown>) => Promise<unknown>) | undefined { | ||
| return loadMethodRegistry[name] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import type { AxiosInstance } from 'axios' | ||
|
|
||
| import { bindChatModelsApi } from './models' | ||
|
|
||
| const mockClient = { | ||
| get: jest.fn() | ||
| } as unknown as jest.Mocked<AxiosInstance> | ||
|
|
||
| beforeEach(() => { | ||
| jest.clearAllMocks() | ||
| }) | ||
|
|
||
| describe('bindChatModelsApi', () => { | ||
| const api = bindChatModelsApi(mockClient) | ||
|
|
||
| describe('getChatModels', () => { | ||
| it('should call GET /assistants/components/chatmodels', async () => { | ||
| const mockModels = [{ name: 'gpt-4', label: 'GPT-4' }] | ||
| ;(mockClient.get as jest.Mock).mockResolvedValue({ data: mockModels }) | ||
|
|
||
| const result = await api.getChatModels() | ||
| expect(mockClient.get).toHaveBeenCalledWith('/assistants/components/chatmodels') | ||
| expect(result).toEqual(mockModels) | ||
| }) | ||
| }) | ||
|
|
||
| describe('getModelsByProvider', () => { | ||
| it('should call GET /assistants/components/chatmodels with provider param', async () => { | ||
| const mockModels = [{ name: 'gpt-4', label: 'GPT-4' }] | ||
| ;(mockClient.get as jest.Mock).mockResolvedValue({ data: mockModels }) | ||
|
|
||
| const result = await api.getModelsByProvider('openai') | ||
| expect(mockClient.get).toHaveBeenCalledWith('/assistants/components/chatmodels', { params: { provider: 'openai' } }) | ||
| expect(result).toEqual(mockModels) | ||
| }) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import type { AxiosInstance } from 'axios' | ||
|
|
||
| import type { ChatModel } from '@/core/types' | ||
|
|
||
| /** | ||
| * Create models API functions bound to a client instance | ||
| */ | ||
| export function bindChatModelsApi(client: AxiosInstance) { | ||
| return { | ||
| /** | ||
| * Get all available chat models | ||
| */ | ||
| getChatModels: async (): Promise<ChatModel[]> => { | ||
| const response = await client.get('/assistants/components/chatmodels') | ||
| return response.data | ||
| }, | ||
|
|
||
| /** | ||
| * Get chat models filtered by provider | ||
| */ | ||
| getModelsByProvider: async (provider: string): Promise<ChatModel[]> => { | ||
| const response = await client.get('/assistants/components/chatmodels', { params: { provider } }) | ||
| return response.data | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export type ChatModelsApi = ReturnType<typeof bindChatModelsApi> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import type { AxiosInstance } from 'axios' | ||
|
|
||
| import { bindToolsApi } from './tools' | ||
|
|
||
| const mockClient = { | ||
| post: jest.fn() | ||
| } as unknown as jest.Mocked<AxiosInstance> | ||
|
|
||
| beforeEach(() => { | ||
| jest.clearAllMocks() | ||
| }) | ||
|
|
||
| describe('bindToolsApi', () => { | ||
| const api = bindToolsApi(mockClient) | ||
|
|
||
| describe('getAllTools', () => { | ||
| it('should POST to /node-load-method/toolAgentflow with listTools loadMethod', async () => { | ||
| const mockTools = [{ label: 'Calculator', name: 'calculator' }] | ||
| ;(mockClient.post as jest.Mock).mockResolvedValue({ data: mockTools }) | ||
|
|
||
| const result = await api.getAllTools() | ||
| expect(mockClient.post).toHaveBeenCalledWith('/node-load-method/toolAgentflow', { loadMethod: 'listTools' }) | ||
| expect(result).toEqual(mockTools) | ||
| }) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import type { AxiosInstance } from 'axios' | ||
|
|
||
| import type { Tool } from '@/core/types' | ||
|
|
||
| /** | ||
| * Create tools API functions bound to a client instance | ||
|
j-sanaa marked this conversation as resolved.
|
||
| */ | ||
| export function bindToolsApi(client: AxiosInstance) { | ||
| return { | ||
| /** | ||
| * Get all available tools | ||
| */ | ||
| getAllTools: async (): Promise<Tool[]> => { | ||
| const response = await client.post('/node-load-method/toolAgentflow', { loadMethod: 'listTools' }) | ||
| return response.data | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export type ToolsApi = ReturnType<typeof bindToolsApi> | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.