Skip to content

Commit

Permalink
refactor orchestrator workflow to be instantiable with tools and prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
jfrank-summit committed Jan 31, 2025
1 parent 0fcb1f2 commit 121d6e3
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 51 deletions.
55 changes: 28 additions & 27 deletions src/agents/workflows/orchestrator/orchestratorWorkflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,28 @@ import { createLogger } from '../../../utils/logger.js';
import { LLMFactory } from '../../../services/llm/factory.js';
import { config } from '../../../config/index.js';
import { ToolNode } from '@langchain/langgraph/prebuilt';
import { createTools } from './tools.js';
import { createNodes } from './nodes.js';
import { OrchestratorConfig, OrchestratorInput, OrchestratorState } from './types.js';
import { createPrompts } from './prompts.js';
import { BaseMessage, HumanMessage } from '@langchain/core/messages';
import { createTwitterApi } from '../../../services/twitter/client.js';
import {
OrchestratorConfig,
OrchestratorInput,
OrchestratorPrompts,
OrchestratorState,
} from './types.js';
import { BaseMessage } from '@langchain/core/messages';
import { workflowControlParser } from './prompts.js';
import { VectorDB } from '../../../services/vectorDb/VectorDB.js';
import { StructuredToolInterface } from '@langchain/core/tools';
import { RunnableToolLike } from '@langchain/core/runnables';

const logger = createLogger('orchestrator-workflow');

export const createWorkflowConfig = async (): Promise<OrchestratorConfig> => {
const { USERNAME, PASSWORD, COOKIES_PATH } = config.twitterConfig;
const twitterApi = await createTwitterApi(USERNAME, PASSWORD, COOKIES_PATH);
const vectorDb = new VectorDB('data/orchestrator');

const { tools } = createTools(twitterApi, vectorDb);
const createWorkflowConfig = async (
tools: (StructuredToolInterface | RunnableToolLike)[],
prompts: OrchestratorPrompts,
): Promise<OrchestratorConfig> => {
const toolNode = new ToolNode(tools);
const orchestratorModel = LLMFactory.createModel(config.llmConfig.nodes.orchestrator).bind({
tools,
});
const prompts = await createPrompts();
return { orchestratorModel, toolNode, prompts };
};

Expand Down Expand Up @@ -78,12 +78,15 @@ const createOrchestratorWorkflow = async (nodes: Awaited<ReturnType<typeof creat
return workflow;
};

type OrchestratorRunner = Readonly<{
export type OrchestratorRunner = Readonly<{
runWorkflow: (input?: OrchestratorInput) => Promise<unknown>;
}>;

const createOrchestratorRunner = async (): Promise<OrchestratorRunner> => {
const workflowConfig = await createWorkflowConfig();
export const createOrchestratorRunner = async (
tools: (StructuredToolInterface | RunnableToolLike)[],
prompts: OrchestratorPrompts,
): Promise<OrchestratorRunner> => {
const workflowConfig = await createWorkflowConfig(tools, prompts);
const nodes = await createNodes(workflowConfig);
const workflow = await createOrchestratorWorkflow(nodes);
const memoryStore = new MemorySaver();
Expand Down Expand Up @@ -116,20 +119,18 @@ const createOrchestratorRunner = async (): Promise<OrchestratorRunner> => {
};
};

// Create workflow runner with caching
export const getOrchestratorRunner = (() => {
let runnerPromise: Promise<OrchestratorRunner> | null = null;

return () => {
let runnerPromise: Promise<OrchestratorRunner> | undefined = undefined;
return ({
prompts,
tools,
}: {
prompts: OrchestratorPrompts;
tools: (StructuredToolInterface | RunnableToolLike)[];
}) => {
if (!runnerPromise) {
runnerPromise = createOrchestratorRunner();
runnerPromise = createOrchestratorRunner(tools, prompts);
}
return runnerPromise;
};
})();

export const runOrchestratorWorkflow = async (input: string) => {
const messages = [new HumanMessage({ content: input })];
const runner = await getOrchestratorRunner();
return runner.runWorkflow({ messages });
};
17 changes: 2 additions & 15 deletions src/agents/workflows/orchestrator/tools.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
import { createTwitterWorkflowTool } from './workflowTools/twitterWorkflowTool.js';
import { createAllTwitterTools } from '../../tools/twitterTools.js';
import { createVectorDbInsertTool, createVectorDbSearchTool } from '../../tools/vectorDbTools.js';
import { TwitterApi } from '../../../services/twitter/types.js';
import { VectorDB } from '../../../services/vectorDb/VectorDB.js';
import { createSaveExperienceTool } from '../../tools/saveExperienceTool.js';
import { createGetCurrentTimeTool } from '../../tools/getTimeTool.js';
export const createTools = (twitterApi: TwitterApi, vectorDb: VectorDB) => {
export const createTools = (twitterApi: TwitterApi) => {
const twitterWorkflowTool = createTwitterWorkflowTool();
const twitterTools = createAllTwitterTools(twitterApi);
const vectorDbSearchTool = createVectorDbSearchTool(vectorDb);
const vectorDbInsertTool = createVectorDbInsertTool(vectorDb);
const saveExperienceTool = createSaveExperienceTool();
const getCurrentTimeTool = createGetCurrentTimeTool();

return {
...twitterTools,
twitterWorkflowTool,
vectorDbSearchTool,
vectorDbInsertTool,
saveExperienceTool,
getCurrentTimeTool,
tools: [
...twitterTools.tools,
twitterWorkflowTool,
vectorDbSearchTool,
vectorDbInsertTool,
saveExperienceTool,
getCurrentTimeTool,
],
tools: [...twitterTools.tools, twitterWorkflowTool, saveExperienceTool, getCurrentTimeTool],
};
};
8 changes: 5 additions & 3 deletions src/agents/workflows/orchestrator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { AIMessageChunk } from '@langchain/core/messages';
import { ToolNode } from '@langchain/langgraph/prebuilt';
import { ChatPromptTemplate } from '@langchain/core/prompts';

export type OrchestratorPrompts = {
inputPrompt: ChatPromptTemplate;
};

export type OrchestratorConfig = {
orchestratorModel: Runnable<BaseLanguageModelInput, AIMessageChunk>;
toolNode: ToolNode;
prompts: {
inputPrompt: ChatPromptTemplate;
};
prompts: OrchestratorPrompts;
};

export type OrchestratorInput = {
Expand Down
28 changes: 22 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { config } from './config/index.js';
import { createLogger } from './utils/logger.js';
import { runOrchestratorWorkflow } from './agents/workflows/orchestrator/orchestratorWorkflow.js';
import { getOrchestratorRunner } from './agents/workflows/orchestrator/orchestratorWorkflow.js';
import { validateLocalHash } from './agents/tools/utils/localHashStorage.js';

const logger = createLogger('app');
import { createTools } from './agents/workflows/orchestrator/tools.js';
import { createPrompts } from './agents/workflows/orchestrator/prompts.js';
import { createTwitterApi } from './services/twitter/client.js';
import { HumanMessage } from '@langchain/core/messages';
export const logger = createLogger('app');

process.on('SIGINT', () => {
logger.info('Received SIGINT. Gracefully shutting down...');
Expand All @@ -15,11 +18,24 @@ process.on('SIGTERM', () => {
process.exit(0);
});

export const orchestatorConfig = async () => {
const { USERNAME, PASSWORD, COOKIES_PATH } = config.twitterConfig;
const twitterApi = await createTwitterApi(USERNAME, PASSWORD, COOKIES_PATH);
const { tools } = createTools(twitterApi);

const prompts = await createPrompts();
return { prompts, tools };
};
const orchestratorConfig = await orchestatorConfig();
const orchestratorRunner = await getOrchestratorRunner(orchestratorConfig);

const startWorkflowPolling = async () => {
try {
const _result = await runOrchestratorWorkflow(
`You are expected to run the twitter workflow periodically in order to maintain social engagement.`,
);
const initalMessage = new HumanMessage(`
You are expected to run the twitter workflow periodically in order to maintain social engagement.
`);

const result = await orchestratorRunner.runWorkflow({ messages: [initalMessage] });

Check warning on line 38 in src/index.ts

View workflow job for this annotation

GitHub Actions / Lint & Format Check

'result' is assigned a value but never used. Allowed unused vars must match /^_/u

logger.info('Workflow execution completed successfully for character:', {
charcterName: config.characterConfig.name,
Expand Down

0 comments on commit 121d6e3

Please sign in to comment.