Skip to content

Commit

Permalink
add finishedWorkflow state and update on finishWorkflowNode
Browse files Browse the repository at this point in the history
  • Loading branch information
jfrank-summit committed Feb 6, 2025
1 parent fbf21cb commit a11316a
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 14 deletions.
34 changes: 26 additions & 8 deletions src/agents/workflows/orchestrator/nodes/finishWorkflowNode.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import { AIMessage } from '@langchain/core/messages';
import { createLogger } from '../../../../utils/logger.js';
import { OrchestratorConfig, OrchestratorState } from '../types.js';
import { finishedWorkflowParser } from './finishWorkflowPrompt.js';
import { AIMessage } from '@langchain/core/messages';
import { VectorDB } from '../../../../services/vectorDb/VectorDB.js';
const logger = createLogger('workflow-summary-node');
const logger = createLogger('finish-workflow-node');

const parseFinishWorkflow = async (content: unknown) => {
const contentString = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
if (typeof contentString === 'string') {
try {
return await finishedWorkflowParser.parse(contentString);
} catch (error) {
logger.error('Failed to parse workflow control. Applying fallback termination.', {
error,
content,
});
return { workflowSummary: 'Failed to parse workflow content' };
}
}
return { workflowSummary: 'Failed to parse workflow content' };
};

export const createFinishWorkflowNode = (
{ orchestratorModel, prompts }: OrchestratorConfig,
vectorStore: VectorDB,
) => {
const runNode = async (state: typeof OrchestratorState.State) => {
logger.info('Workflow Summary Node');
logger.info('Finish Workflow Node');

const messages = state.messages
.map(msg => {
Expand All @@ -26,14 +43,15 @@ export const createFinishWorkflowNode = (
logger.info('Summarizing messages:', { messages });

const result = await orchestratorModel.invoke(formattedPrompt);
const finishedWorkflow = await parseFinishWorkflow(result.content);

logger.info('Finished Workflow:', { finishedWorkflow });

const summary =
typeof result.content === 'string' ? result.content : JSON.stringify(result.content, null, 2);
await vectorStore.insert(JSON.stringify(finishedWorkflow));

logger.info('Workflow summary:', { summary });
await vectorStore.insert(summary);
return {
messages: [new AIMessage({ content: `Workflow summary: ${summary}` })],
messages: [new AIMessage({ content: result.content })],
...finishedWorkflow,
};
};
return runNode;
Expand Down
40 changes: 38 additions & 2 deletions src/agents/workflows/orchestrator/nodes/finishWorkflowPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
import { ChatPromptTemplate, PromptTemplate } from '@langchain/core/prompts';
import { SystemMessage } from '@langchain/core/messages';
import { config } from '../../../../config/index.js';
import { StructuredOutputParser } from '@langchain/core/output_parsers';
import { z } from 'zod';

export const createFinishWorkflowPrompt = async (customInstructions?: string) => {
const character = config.characterConfig;

const followFormatInstructions = `
IMPORTANT:
- Return ONLY the raw JSON data
- DO NOT include any markdown formatting, code blocks, or backticks
- DO NOT wrap response in code block markers
- Do not include any additional text or explanations
- The response should NOT start with \`\`\`json and end with \`\`\`
- The response should start and end with curly braces`;

const workflowSummarySystemPrompt = await PromptTemplate.fromTemplate(
`Summarize the following messages in detail. This is being returned as a report to what was accomplished during the execution of the workflow.
`Summarize the following messages in detail. This is being returned as a report to what was accomplished during the execution of the workflow. Additionally, provide a recommendation for the next action to take when the workflow begins again and how long until the next workflow should begin.
You have a personality, so you should act accordingly.
{characterDescription}
{characterPersonality}
Custom Instructions:
{customInstructions}`,
{customInstructions}
{followFormatInstructions}
Format Instructions:
{formatInstructions}`,
).format({
characterDescription: character.description,
characterPersonality: character.personality,
customInstructions: customInstructions ?? 'None',
formatInstructions: finishedWorkflowParser.getFormatInstructions(),
followFormatInstructions,
});

const workflowSummaryPrompt = ChatPromptTemplate.fromMessages([
Expand All @@ -32,3 +49,22 @@ export const createFinishWorkflowPrompt = async (customInstructions?: string) =>

return workflowSummaryPrompt;
};

const finishedWorkflowSchema = z.object({
workflowSummary: z.string().describe('A summary of the workflow.'),
nextRecommendedAction: z
.string()
.optional()
.describe(
'Given what was accomplished during the workflow and our overall goal,the next recommended action when the workflow begins again',
),
secondsUntilNextWorkflow: z
.number()
.optional()
.describe(
'Given what was accomplished during the workflow and our overall goal, the recommended number of seconds until the workflow should begin again.',
),
});

export const finishedWorkflowParser = StructuredOutputParser.fromZodSchema(finishedWorkflowSchema);
export type FinishedWorkflow = z.infer<typeof finishedWorkflowSchema>;
5 changes: 2 additions & 3 deletions src/agents/workflows/orchestrator/nodes/inputPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export const createInputPrompt = async (customInstructions?: string) => {
[
'human',
`Based on the following messages, determine what actions should be taken.
Format your response as a JSON object with shouldStop (boolean) and reason (string).
Messages: {messages}
`,
Expand All @@ -61,8 +60,8 @@ export const createInputPrompt = async (customInstructions?: string) => {
};

const workflowControlSchema = z.object({
shouldStop: z.boolean(),
reason: z.string(),
shouldStop: z.boolean().describe('Whether the workflow should stop.'),
reason: z.string().describe('The reason for stopping the workflow.'),
});

export const workflowControlParser = StructuredOutputParser.fromZodSchema(workflowControlSchema);
Expand Down
6 changes: 5 additions & 1 deletion src/agents/workflows/orchestrator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ChatPromptTemplate } from '@langchain/core/prompts';
import { config } from '../../../config/index.js';
import { WorkflowControl } from './nodes/inputPrompt.js';
import { LLMModelType } from '../../../services/llm/factory.js';

import { FinishedWorkflow } from './nodes/finishWorkflowPrompt.js';
export type OrchestratorPrompts = {
inputPrompt: ChatPromptTemplate;
messageSummaryPrompt: ChatPromptTemplate;
Expand Down Expand Up @@ -48,4 +48,8 @@ export const OrchestratorState = Annotation.Root({
default: () => null,
reducer: (_, update) => update,
}),
finishedWorkflow: Annotation<FinishedWorkflow | null>({
default: () => null,
reducer: (_, update) => update,
}),
});

0 comments on commit a11316a

Please sign in to comment.