From 06690aa7bf407808f79201803a4eab22befe9cea Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Tue, 28 Jan 2025 14:57:15 +1100 Subject: [PATCH 1/2] refactor --- .../src/components/sidebar-right.tsx | 2 +- clients/example-ui/src/routes/__root.tsx | 10 +- examples/example-basic.ts | 15 +- examples/example-goal.ts | 2 +- packages/core/src/core/chain-of-thought.ts | 675 +++++++++--------- packages/core/src/core/goal-manager.ts | 49 +- 6 files changed, 399 insertions(+), 354 deletions(-) diff --git a/clients/example-ui/src/components/sidebar-right.tsx b/clients/example-ui/src/components/sidebar-right.tsx index e7f27c53..d6dbdc60 100644 --- a/clients/example-ui/src/components/sidebar-right.tsx +++ b/clients/example-ui/src/components/sidebar-right.tsx @@ -110,7 +110,7 @@ export function SidebarRight({ return ( diff --git a/clients/example-ui/src/routes/__root.tsx b/clients/example-ui/src/routes/__root.tsx index 7447df02..16dd3dc8 100644 --- a/clients/example-ui/src/routes/__root.tsx +++ b/clients/example-ui/src/routes/__root.tsx @@ -18,10 +18,10 @@ export const Route = createRootRoute({ component: () => ( <> - - - -
+ + + +
@@ -42,7 +42,7 @@ export const Route = createRootRoute({
- +
diff --git a/examples/example-basic.ts b/examples/example-basic.ts index 4f46f2f1..871083d6 100644 --- a/examples/example-basic.ts +++ b/examples/example-basic.ts @@ -19,7 +19,7 @@ import chalk from "chalk"; import { ChromaVectorDB } from "../packages/core/src/core/vector-db"; import { z } from "zod"; import { env } from "../packages/core/src/core/env"; -import { HandlerRole } from "../packages/core/src/core/types"; +import { HandlerRole, LogLevel } from "../packages/core/src/core/types"; /** * Helper function to get user input from CLI @@ -71,9 +71,16 @@ async function main() { }); // Initialize the main reasoning engine - const dreams = new ChainOfThought(llmClient, memory, { - worldState: ETERNUM_CONTEXT, - }); + const dreams = new ChainOfThought( + llmClient, + memory, + { + worldState: ETERNUM_CONTEXT, + }, + { + logLevel: LogLevel.DEBUG, + } + ); // Register available outputs dreams.registerOutput({ diff --git a/examples/example-goal.ts b/examples/example-goal.ts index 53d58f38..f1c5ae92 100644 --- a/examples/example-goal.ts +++ b/examples/example-goal.ts @@ -59,7 +59,7 @@ function printGoalStatus(status: GoalStatus): string { async function main() { // Initialize core components const llmClient = new LLMClient({ - model: "deepseek/deepseek-r1", // High performance model + model: "openrouter:deepseek/deepseek-r1", // High performance model }); const starknetChain = new StarknetChain({ diff --git a/packages/core/src/core/chain-of-thought.ts b/packages/core/src/core/chain-of-thought.ts index c4587a94..165ccae5 100644 --- a/packages/core/src/core/chain-of-thought.ts +++ b/packages/core/src/core/chain-of-thought.ts @@ -79,12 +79,33 @@ export class ChainOfThought extends EventEmitter { this.logger.debug( "decomposeObjectiveIntoGoals", "Planning strategy for objective", - { - objective, - } + { objective } + ); + + const context = await this.gatherRelevantContext(objective); + this.logger.info( + "decomposeObjectiveIntoGoals", + "Gathered relevant context", + { context } + ); + + const goals = await this.generateGoalHierarchy(objective, context); + this.logger.info( + "decomposeObjectiveIntoGoals", + "Generated goal hierarchy", + { goals } ); - // Fetch relevant documents and experiences related to the objective + await this.createAndLinkGoals(goals); + this.recordReasoningStep( + `Strategy planned for objective: ${objective}`, + "planning", + ["strategy-planning"], + { goals: this.getCreatedGoals() } + ); + } + + private async gatherRelevantContext(objective: string) { const [relevantDocs, relevantExperiences] = await Promise.all([ this.memory.findSimilarDocuments(objective, 5), this.memory.findSimilarEpisodes(objective, 3), @@ -99,7 +120,6 @@ export class ChainOfThought extends EventEmitter { } ); - // Build context from relevant documents const gameStateContext = relevantDocs .map( (doc) => ` @@ -111,7 +131,6 @@ export class ChainOfThought extends EventEmitter { ) .join("\n\n"); - // Build context from past experiences const experienceContext = relevantExperiences .map( (exp) => ` @@ -124,16 +143,23 @@ export class ChainOfThought extends EventEmitter { ) .join("\n\n"); + return { gameStateContext, experienceContext }; + } + + private async generateGoalHierarchy( + objective: string, + context: { gameStateContext: string; experienceContext: string } + ) { const prompt = ` "${objective}" - ${gameStateContext} + ${context.gameStateContext} - ${experienceContext} + ${context.experienceContext} @@ -181,7 +207,7 @@ export class ChainOfThought extends EventEmitter { }); try { - const goals = await validateLLMResponseSchema({ + return await validateLLMResponseSchema({ prompt, systemPrompt: "You are a strategic planning system that creates hierarchical goal structures.", @@ -191,91 +217,12 @@ export class ChainOfThought extends EventEmitter { this.logger.error( "decomposeObjectiveIntoGoals", `Attempt ${attempt} failed`, - { - error, - } + { error } ); }, llmClient: this.llmClient, logger: this.logger, }); - - const allLLMGoals = [ - ...goals.long_term.map((g) => ({ - horizon: "long" as const, - ...g, - })), - ...goals.medium_term.map((g) => ({ - horizon: "medium" as const, - ...g, - })), - ...goals.short_term.map((g) => ({ - horizon: "short" as const, - ...g, - })), - ]; - - // Link: LLM’s "id" -> goal manager’s "goal-xyz" ID - const llmIdToRealId = new Map(); - - // Keep track of newly created goal IDs so we can fetch them after pass #2 - const createdGoalIds: string[] = []; - - // Pass #1: Create each goal (with empty dependencies) - for (const llmGoal of allLLMGoals) { - const { - id: llmId, - horizon, - dependencies: _, - ...rest - } = llmGoal; - - // Create a new goal, letting GoalManager generate the random ID - const newGoal = this.goalManager.addGoal({ - horizon, - status: "pending", - created_at: Date.now(), - dependencies: [], // empty for now, will fill in pass #2 - ...rest, - }); - - // Map LLM’s temp ID -> our new random ID - llmIdToRealId.set(llmId, newGoal.id); - createdGoalIds.push(newGoal.id); - - this.emit("goal:created", { - id: newGoal.id, - description: newGoal.description, - priority: newGoal.priority, - }); - } - - // PASS #2: Update dependencies with real IDs - for (const llmGoal of allLLMGoals) { - // Grab the real ID for this LLM goal - const realGoalId = llmIdToRealId.get(llmGoal.id); - if (!realGoalId) continue; - - // Convert LLM dependencies to our manager IDs - const realDeps = llmGoal.dependencies - .map((dep) => llmIdToRealId.get(dep)) - .filter((id): id is string => !!id); - - this.goalManager.updateGoalDependencies(realGoalId, realDeps); - } - - // Get all the goals we just created - const finalGoals = createdGoalIds - .map((id) => this.goalManager.getGoalById(id)) - .filter((g): g is Goal => !!g); - - // Add a planning step - this.recordReasoningStep( - `Strategy planned for objective: ${objective}`, - "planning", - ["strategy-planning"], - { goals: finalGoals } - ); } catch (error) { this.logger.error( "decomposeObjectiveIntoGoals", @@ -286,30 +233,62 @@ export class ChainOfThought extends EventEmitter { } } - /** - * Gets a prioritized list of goals that are ready to be worked on. - * Goals are sorted first by horizon (short-term > medium-term > long-term) - * and then by their individual priority values. - * - * @returns An array of Goal objects sorted by priority - * @internal - */ - private getReadyGoalsByPriority(): Goal[] { - const readyGoals = this.goalManager.getReadyGoals(); - const horizonPriority: Record = { - short: 3, - medium: 2, - long: 1, - }; + private async createAndLinkGoals(goals: { + long_term: any[]; + medium_term: any[]; + short_term: any[]; + }) { + const allLLMGoals = [ + ...goals.long_term.map((g) => ({ horizon: "long" as const, ...g })), + ...goals.medium_term.map((g) => ({ + horizon: "medium" as const, + ...g, + })), + ...goals.short_term.map((g) => ({ + horizon: "short" as const, + ...g, + })), + ]; + + const llmIdToRealId = new Map(); + const createdGoalIds: string[] = []; + + // Pass #1: Create goals + for (const llmGoal of allLLMGoals) { + const { id: llmId, horizon, dependencies: _, ...rest } = llmGoal; + const newGoal = this.goalManager.addGoal({ + horizon, + status: "pending", + created_at: Date.now(), + dependencies: [], + ...rest, + }); - return readyGoals.sort((a, b) => { - const horizonDiff = - horizonPriority[a.horizon] - horizonPriority[b.horizon]; - if (horizonDiff !== 0) { - return -horizonDiff; - } - return (b.priority ?? 0) - (a.priority ?? 0); - }); + llmIdToRealId.set(llmId, newGoal.id); + createdGoalIds.push(newGoal.id); + + this.emit("goal:created", { + id: newGoal.id, + description: newGoal.description, + priority: newGoal.priority, + }); + } + + // Pass #2: Link dependencies + for (const llmGoal of allLLMGoals) { + const realGoalId = llmIdToRealId.get(llmGoal.id); + if (!realGoalId) continue; + + const realDeps = llmGoal.dependencies + .map((dep: string) => llmIdToRealId.get(dep)) + .filter((id: string | undefined): id is string => !!id); + + this.goalManager.updateGoalDependencies(realGoalId, realDeps); + } + } + + private getCreatedGoals(): Goal[] { + return Array.from(this.goalManager.goals.values()); } /** @@ -331,55 +310,14 @@ export class ChainOfThought extends EventEmitter { missing_requirements: string[]; incompleteState?: boolean; }> { - const [relevantDocs, relevantExperiences, blackboardState] = - await Promise.all([ - this.memory.findSimilarDocuments(goal.description, 5), - this.memory.findSimilarEpisodes(goal.description, 3), - this.getBlackboardState(), - ]); - - const prompt = ` - - - - ${goal.description} - - - - ${relevantDocs - .map((doc) => `Document: ${doc.title}\n${doc.content}`) - .join("\n\n")} - - - - ${relevantExperiences - .map((exp) => `Experience: ${exp.action}\n${exp.outcome}`) - .join("\n\n")} - - - - ${JSON.stringify(blackboardState, null, 2)} - - - # Required dependencies: - ${JSON.stringify(goal.dependencies || {}, null, 2)} - - # Analyze if this goal can be executed right now. Consider: - - 1. Are all required resources available in the current game state? - 2. Are environmental conditions met? - 3. Are there any blocking conditions? - 4. Do we have the necessary game state requirements? - - If you need to query then you could potentially complete the goal. - - - Think about this goal and the context here. - - - `; - try { + const [relevantDocs, relevantExperiences, blackboardState] = + await Promise.all([ + this.memory.findSimilarDocuments(goal.description, 5), + this.memory.findSimilarEpisodes(goal.description, 3), + this.getBlackboardState(), + ]); + const schema = z .object({ possible: z.boolean(), @@ -394,6 +332,13 @@ export class ChainOfThought extends EventEmitter { }) .strict(); + const prompt = this.buildValidationPrompt( + goal, + relevantDocs, + relevantExperiences, + blackboardState + ); + const response = await validateLLMResponseSchema<{ possible: boolean; reason: string; @@ -408,9 +353,7 @@ export class ChainOfThought extends EventEmitter { this.logger.warn( "validateGoalPrerequisites", `Retry attempt ${attempt}`, - { - error, - } + { error } ); }, llmClient: this.llmClient, @@ -438,6 +381,52 @@ export class ChainOfThought extends EventEmitter { }; } } + + private buildValidationPrompt( + goal: Goal, + relevantDocs: any[], + relevantExperiences: any[], + blackboardState: any + ): string { + return ` + + ${goal.description} + + + + ${relevantDocs + .map((doc) => `Document: ${doc.title}\n${doc.content}`) + .join("\n\n")} + + + + ${relevantExperiences + .map((exp) => `Experience: ${exp.action}\n${exp.outcome}`) + .join("\n\n")} + + + + ${JSON.stringify(blackboardState, null, 2)} + + + # Required dependencies: + ${JSON.stringify(goal.dependencies || {}, null, 2)} + + # Analyze if this goal can be executed right now. Consider: + + 1. Are all required resources available in the current game state? + 2. Are environmental conditions met? + 3. Are there any blocking conditions? + 4. Do we have the necessary game state requirements? + + If you need to query then you could potentially complete the goal. + + + Think about this goal and the context here. + + `; + } + /** * Refines a high-level goal into more specific, actionable sub-goals by analyzing relevant context. * @@ -573,9 +562,9 @@ export class ChainOfThought extends EventEmitter { * @returns Promise that resolves when execution is complete */ public async processHighestPriorityGoal(): Promise { - const prioritizedGoals = this.getReadyGoalsByPriority().filter( - (goal) => goal.status !== "completed" - ); + const prioritizedGoals = this.goalManager + .getReadyGoalsByPriority() + .filter((goal) => goal.status !== "completed"); if (!prioritizedGoals.length) { this.logger.debug( @@ -681,7 +670,12 @@ export class ChainOfThought extends EventEmitter { error, } ); - await this.processGoalFailure(currentGoal, error); + await this.goalManager.processGoalFailure(currentGoal); + + this.emit("goal:failed", { + id: currentGoal.id, + error, + }); // Go on to the next goal continue; } @@ -791,35 +785,6 @@ export class ChainOfThought extends EventEmitter { } } - /** - * Handles the failure of a goal by updating its status and notifying relevant systems. - * - * This method: - * 1. Updates the failed goal's status - * 2. If the goal has a parent, marks the parent as blocked - * 3. Emits a goal:failed event - * - * @param goal - The goal that failed - * @param error - The error that caused the failure - * @internal - */ - private async processGoalFailure( - goal: Goal, - error: Error | unknown - ): Promise { - this.goalManager.updateGoalStatus(goal.id, "failed"); - - // If this was a sub-goal, mark parent as blocked - if (goal.parentGoal) { - this.goalManager.updateGoalStatus(goal.parentGoal, "blocked"); - } - - this.emit("goal:failed", { - id: goal.id, - error, - }); - } - /** * Validates whether a goal has been successfully achieved by analyzing the current context * against the goal's success criteria. @@ -1271,64 +1236,12 @@ ${availableOutputs this.emit("think:start", { query: userQuery }); try { - // Consult single memory instance for both types of memories - const [similarExperiences, relevantDocs] = await Promise.all([ - this.memory.findSimilarEpisodes(userQuery, 1), - this.memory.findSimilarDocuments(userQuery, 1), - ]); - - this.logger.debug("think", "Retrieved memory context", { - experienceCount: similarExperiences.length, - docCount: relevantDocs.length, - }); - - this.logger.debug("think", "Beginning to think", { - userQuery, - maxIterations, - }); - - // Initialize with user query - this.recordReasoningStep(`User Query: ${userQuery}`, "task", [ - "user-query", - ]); + await this.initializeThinkingContext(userQuery); + let pendingActions = await this.getInitialActions(userQuery); let currentIteration = 0; let isComplete = false; - // Get initial plan and actions - const initialResponse = await validateLLMResponseSchema({ - prompt: this.buildPrompt({ query: userQuery }), - schema: z.object({ - plan: z.string().optional(), - meta: z.any().optional(), - actions: z.array( - z.object({ - type: z.string(), - payload: z.any(), - }) - ), - }), - systemPrompt: - "You are a reasoning system that outputs structured JSON only.", - maxRetries: 3, - llmClient: this.llmClient, - logger: this.logger, - }); - - // Initialize pending actions queue with initial actions - let pendingActions: CoTAction[] = [ - ...initialResponse.actions, - ] as CoTAction[]; - - // Add initial plan as a step if provided - if (initialResponse.plan) { - this.recordReasoningStep( - `Initial plan: ${initialResponse.plan}`, - "planning", - ["initial-plan"] - ); - } - while ( !isComplete && currentIteration < maxIterations && @@ -1339,31 +1252,162 @@ ${availableOutputs pendingActionsCount: pendingActions.length, }); - // Process one action at a time const currentAction = pendingActions.shift()!; - this.logger.debug("think", "Processing action", { - action: currentAction, - remainingActions: pendingActions.length, - }); try { const result = await this.executeAction(currentAction); + await this.handleActionResult(currentAction, result); - // Store the experience - await this.storeEpisode(currentAction.type, result); + const completion = await this.verifyCompletion( + userQuery, + result, + currentAction + ); + + isComplete = completion.complete; + + if (completion.newActions?.length > 0) { + pendingActions.push( + ...this.extractNewActions(completion.newActions) + ); + } - // If the result seems important, store as knowledge - if (calculateImportance(result) > 0.7) { - await this.storeKnowledge( - `Learning from ${currentAction.type}`, - result, - "action_learning", - [currentAction.type, "automated_learning"] + if (isComplete || !completion.shouldContinue) { + await this.handleCompletion( + isComplete, + completion.reason, + userQuery ); + return; } - const completion = await validateLLMResponseSchema({ - prompt: `${this.buildPrompt({ result })} + this.recordReasoningStep( + `Action completed, continuing execution: ${completion.reason}`, + "system", + ["continuation"] + ); + } catch (error) { + this.emit("think:error", { query: userQuery, error }); + throw error; + } + + currentIteration++; + } + + if (currentIteration >= maxIterations) { + const error = `Failed to solve query "${userQuery}" within ${maxIterations} iterations`; + this.logger.error("think", error); + this.emit("think:timeout", { query: userQuery }); + } + } catch (error) { + this.emit("think:error", { query: userQuery, error }); + throw error; + } + } + + private async initializeThinkingContext(userQuery: string): Promise { + const [similarExperiences, relevantDocs] = await Promise.all([ + this.memory.findSimilarEpisodes(userQuery, 1), + this.memory.findSimilarDocuments(userQuery, 1), + ]); + + this.logger.debug("think", "Retrieved memory context", { + experienceCount: similarExperiences.length, + docCount: relevantDocs.length, + }); + + this.logger.debug("think", "Beginning to think", { + userQuery, + }); + + this.recordReasoningStep(`User Query: ${userQuery}`, "task", [ + "user-query", + ]); + } + + private async getInitialActions(userQuery: string): Promise { + const initialResponse = await validateLLMResponseSchema({ + prompt: this.buildPrompt({ query: userQuery }), + schema: z.object({ + plan: z.string().optional(), + meta: z.any().optional(), + actions: z.array( + z.object({ + type: z.string(), + payload: z.any(), + }) + ), + }), + systemPrompt: + "You are a reasoning system that outputs structured JSON only.", + maxRetries: 3, + llmClient: this.llmClient, + logger: this.logger, + }); + + if (initialResponse.plan) { + this.recordReasoningStep( + `Initial plan: ${initialResponse.plan}`, + "planning", + ["initial-plan"] + ); + } + + return [...initialResponse.actions] as CoTAction[]; + } + + private async handleActionResult( + currentAction: CoTAction, + result: any + ): Promise { + await this.storeEpisode(currentAction.type, result); + + if (calculateImportance(result) > 0.7) { + await this.storeKnowledge( + `Learning from ${currentAction.type}`, + result, + "action_learning", + [currentAction.type, "automated_learning"] + ); + } + } + + private async verifyCompletion( + userQuery: string, + result: any, + currentAction: CoTAction + ): Promise<{ + complete: boolean; + reason: string; + shouldContinue: boolean; + newActions: any[]; + }> { + return await validateLLMResponseSchema({ + prompt: this.buildVerificationPrompt( + userQuery, + result, + currentAction + ), + schema: z.object({ + complete: z.boolean(), + reason: z.string(), + shouldContinue: z.boolean(), + newActions: z.array(z.any()), + }), + systemPrompt: + "You are a goal completion analyzer using Chain of Verification...", + maxRetries: 3, + llmClient: this.llmClient, + logger: this.logger, + }); + } + + private buildVerificationPrompt( + userQuery: string, + result: any, + currentAction: CoTAction + ): string { + return `${this.buildPrompt({ result })} ${JSON.stringify({ query: userQuery, currentSteps: this.stepManager.getSteps(), @@ -1401,86 +1445,33 @@ ${availableOutputs Think in detail here - - `, - schema: z.object({ - complete: z.boolean(), - reason: z.string(), - shouldContinue: z.boolean(), - newActions: z.array(z.any()), - }), - systemPrompt: - "You are a goal completion analyzer using Chain of Verification...", - maxRetries: 3, - llmClient: this.llmClient, - logger: this.logger, - }); + `; + } - try { - isComplete = completion.complete; - - if (completion.newActions?.length > 0) { - // Add new actions to the end of the pending queue - const extractedActions = - completion.newActions.flatMap( - (plan: any) => plan.actions || [] - ); - pendingActions.push(...extractedActions); - - this.logger.debug("think", "Added new actions", { - newActionsCount: extractedActions.length, - totalPendingCount: pendingActions.length, - }); - } + private extractNewActions(newActions: any[]): CoTAction[] { + const extractedActions = newActions.flatMap( + (plan: any) => plan.actions || [] + ); - if (isComplete || !completion.shouldContinue) { - this.recordReasoningStep( - `Goal ${isComplete ? "achieved" : "failed"}: ${ - completion.reason - }`, - "system", - ["completion"] - ); - this.emit("think:complete", { query: userQuery }); - return; - } else { - this.recordReasoningStep( - `Action completed, continuing execution: ${completion.reason}`, - "system", - ["continuation"] - ); - } - } catch (error) { - this.logger.error( - "think", - "Error parsing completion check", - { - error: - error instanceof Error - ? error.message - : String(error), - completion, - } - ); - continue; - } - } catch (error) { - this.emit("think:error", { query: userQuery, error }); - throw error; - } + this.logger.debug("think", "Added new actions", { + newActionsCount: extractedActions.length, + totalPendingCount: extractedActions.length, + }); - currentIteration++; - } + return extractedActions; + } - if (currentIteration >= maxIterations) { - const error = `Failed to solve query "${userQuery}" within ${maxIterations} iterations`; - this.logger.error("think", error); - this.emit("think:timeout", { query: userQuery }); - } - } catch (error) { - this.emit("think:error", { query: userQuery, error }); - throw error; - } + private async handleCompletion( + isComplete: boolean, + reason: string, + userQuery: string + ): Promise { + this.recordReasoningStep( + `Goal ${isComplete ? "achieved" : "failed"}: ${reason}`, + "system", + ["completion"] + ); + this.emit("think:complete", { query: userQuery }); } /** diff --git a/packages/core/src/core/goal-manager.ts b/packages/core/src/core/goal-manager.ts index bae9df3d..1f8359a1 100644 --- a/packages/core/src/core/goal-manager.ts +++ b/packages/core/src/core/goal-manager.ts @@ -5,7 +5,7 @@ import type { Goal, GoalStatus, HorizonType } from "./types"; */ export class GoalManager { /** Internal map storing all goals indexed by their IDs */ - private goals: Map = new Map(); + goals: Map = new Map(); /** * Creates a new goal and adds it to the goal collection. @@ -30,6 +30,53 @@ export class GoalManager { return newGoal; } + /** + * Handles the failure of a goal by updating its status and notifying relevant systems. + * + * This method: + * 1. Updates the failed goal's status + * 2. If the goal has a parent, marks the parent as blocked + * 3. Emits a goal:failed event + * + * @param goal - The goal that failed + * @param error - The error that caused the failure + * @internal + */ + public async processGoalFailure(goal: Goal): Promise { + this.updateGoalStatus(goal.id, "failed"); + + // If this was a sub-goal, mark parent as blocked + if (goal.parentGoal) { + this.updateGoalStatus(goal.parentGoal, "blocked"); + } + } + + /** + * Gets a prioritized list of goals that are ready to be worked on. + * Goals are sorted first by horizon (short-term > medium-term > long-term) + * and then by their individual priority values. + * + * @returns An array of Goal objects sorted by priority + * @internal + */ + public getReadyGoalsByPriority(): Goal[] { + const readyGoals = this.getReadyGoals(); + const horizonPriority: Record = { + short: 3, + medium: 2, + long: 1, + }; + + return readyGoals.sort((a, b) => { + const horizonDiff = + horizonPriority[a.horizon] - horizonPriority[b.horizon]; + if (horizonDiff !== 0) { + return -horizonDiff; + } + return (b.priority ?? 0) - (a.priority ?? 0); + }); + } + /** * Updates an existing goal with new dependencies. * Used to map generated thought IDs to goal IDs. From 6e6b69aeae8092b9fd6b71159cae2e176e3b6d53 Mon Sep 17 00:00:00 2001 From: ponderingdemocritus Date: Tue, 28 Jan 2025 16:00:55 +1100 Subject: [PATCH 2/2] throw --- packages/core/src/core/chain-of-thought.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/core/src/core/chain-of-thought.ts b/packages/core/src/core/chain-of-thought.ts index 165ccae5..fa592721 100644 --- a/packages/core/src/core/chain-of-thought.ts +++ b/packages/core/src/core/chain-of-thought.ts @@ -444,7 +444,7 @@ export class ChainOfThought extends EventEmitter { private async breakdownGoalIntoSubtasks( goal: Goal, maxRetries: number = 3 - ): Promise { + ): Promise { const [relevantDocs, relevantExperiences, blackboardState] = await Promise.all([ this.memory.findSimilarDocuments(goal.description, 5), @@ -539,9 +539,13 @@ export class ChainOfThought extends EventEmitter { // Update original goal status this.goalManager.updateGoalStatus(goal.id, "active"); } catch (error) { - throw new Error( - `Failed to refine goal after ${maxRetries} attempts: ${error}` + this.logger.error( + "breakdownGoalIntoSubtasks", + "Failed to refine goal", + { error } ); + + return JSON.stringify({ error }); } } @@ -1232,7 +1236,7 @@ ${availableOutputs public async think( userQuery: string, maxIterations: number = 10 - ): Promise { + ): Promise { this.emit("think:start", { query: userQuery }); try { @@ -1288,7 +1292,7 @@ ${availableOutputs ); } catch (error) { this.emit("think:error", { query: userQuery, error }); - throw error; + return JSON.stringify({ error }); } currentIteration++; @@ -1301,7 +1305,7 @@ ${availableOutputs } } catch (error) { this.emit("think:error", { query: userQuery, error }); - throw error; + return JSON.stringify({ error }); } }