Skip to content

Commit

Permalink
feat: Add uuid npm dependency for unique identifier generation (#48)
Browse files Browse the repository at this point in the history
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
Sma1lboy and autofix-ci[bot] authored Nov 17, 2024
1 parent 2ae3b0b commit c7aa3a2
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 56 deletions.
3 changes: 2 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"rxjs": "^7.8.1",
"sqlite3": "^5.1.7",
"subscriptions-transport-ws": "^0.11.0",
"typeorm": "^0.3.20"
"typeorm": "^0.3.20",
"uuid": "^10.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
Expand Down
37 changes: 28 additions & 9 deletions backend/src/build-system/context.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ModelProvider } from 'src/common/model-provider';
import { BuildHandlerManager } from './hanlder-manager';
import {
BuildExecutionState,
BuildNode,
BuildResult,
BuildSequence,
BuildStep,
} from './types';
import { Logger } from '@nestjs/common';

export class BuilderContext {
private state: BuildExecutionState = {
Expand All @@ -14,12 +15,19 @@ export class BuilderContext {
failed: new Set(),
waiting: new Set(),
};

private logger;
private data: Record<string, any> = {};
// Store the results of the nodes
private results: Map<string, BuildResult> = new Map();
private handlerManager: BuildHandlerManager;
public model: ModelProvider;

constructor(private sequence: BuildSequence) {
constructor(
private sequence: BuildSequence,
id: string,
) {
this.handlerManager = BuildHandlerManager.getInstance();
new Logger(`builder-context-${id}`);
}

canExecute(nodeId: string): boolean {
Expand All @@ -41,7 +49,7 @@ export class BuilderContext {
return null;
}

async run(nodeId: string): Promise<BuildResult> {
async run(nodeId: string, args: unknown | undefined): Promise<BuildResult> {
const node = this.findNode(nodeId);
if (!node) {
throw new Error(`Node not found: ${nodeId}`);
Expand All @@ -53,9 +61,13 @@ export class BuilderContext {

try {
this.state.pending.add(nodeId);
const result = await this.executeNode(node);
const result = await this.executeNode(node, args);
this.state.completed.add(nodeId);
this.state.pending.delete(nodeId);

// Store the result for future use
this.results.set(nodeId, result);

return result;
} catch (error) {
this.state.failed.add(nodeId);
Expand All @@ -76,17 +88,24 @@ export class BuilderContext {
return this.data[key];
}

private async executeNode(node: BuildNode): Promise<BuildResult> {
getResult(nodeId: string): BuildResult | undefined {
return this.results.get(nodeId);
}

private async executeNode(
node: BuildNode,
args: unknown,
): Promise<BuildResult> {
if (process.env.NODE_ENV === 'test') {
console.log(`[TEST] Executing node: ${node.id}`);
this.logger.log(`[TEST] Executing node: ${node.id}`);
return { success: true, data: { nodeId: node.id } };
}

console.log(`Executing node: ${node.id}`);
this.logger.log(`Executing node: ${node.id}`);
const handler = this.handlerManager.getHandler(node.id);
if (!handler) {
throw new Error(`No handler found for node: ${node.id}`);
}
return handler.run(this);
return handler.run(this, args);
}
}
34 changes: 24 additions & 10 deletions backend/src/build-system/executor.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
import { Logger } from '@nestjs/common';
import { BuilderContext } from './context';
import { BuildNode, BuildSequence, BuildStep } from './types';
import { v4 as uuidv4 } from 'uuid';

export class BuildSequenceExecutor {
constructor(private context: BuilderContext) {}

private logger: Logger = new Logger(`BuildSequenceExecutor-${uuidv4()}`);
private async executeNode(node: BuildNode): Promise<void> {
try {
if (this.context.getState().completed.has(node.id)) {
return;
}

if (!this.context.canExecute(node.id)) {
console.log(`Waiting for dependencies: ${node.requires?.join(', ')}`);
await new Promise((resolve) => setTimeout(resolve, 100)); // 添加小延迟
this.logger.log(
`Waiting for dependencies: ${node.requires?.join(', ')}`,
);
await new Promise((resolve) => setTimeout(resolve, 100));
return;
}

await this.context.run(node.id);
const dependenciesResults = node.requires?.map((depId) =>
this.context.getResult(depId),
);

this.logger.log(
`Executing node ${node.id} with dependencies:`,
dependenciesResults,
);

await this.context.run(node.id, dependenciesResults);
} catch (error) {
console.error(`Error executing node ${node.id}:`, error);
this.logger.error(`Error executing node ${node.id}:`, error);
throw error;
}
}

private async executeStep(step: BuildStep): Promise<void> {
console.log(`Executing build step: ${step.id}`);
this.logger.log(`Executing build step: ${step.id}`);

if (step.parallel) {
let remainingNodes = [...step.nodes];
Expand Down Expand Up @@ -84,7 +98,7 @@ export class BuildSequenceExecutor {

if (!this.context.getState().completed.has(node.id)) {
// TODO: change to error log
console.warn(
this.logger.warn(
`Failed to execute node ${node.id} after ${maxRetries} attempts`,
);
}
Expand All @@ -93,7 +107,7 @@ export class BuildSequenceExecutor {
}

async executeSequence(sequence: BuildSequence): Promise<void> {
console.log(`Starting build sequence: ${sequence.id}`);
this.logger.log(`Starting build sequence: ${sequence.id}`);

for (const step of sequence.steps) {
await this.executeStep(step);
Expand All @@ -104,7 +118,7 @@ export class BuildSequenceExecutor {

if (incompletedNodes.length > 0) {
// TODO: change to error log
console.warn(
this.logger.warn(
`Step ${step.id} failed to complete nodes: ${incompletedNodes
.map((n) => n.id)
.join(', ')}`,
Expand All @@ -113,7 +127,7 @@ export class BuildSequenceExecutor {
}
}

console.log(`Build sequence completed: ${sequence.id}`);
console.log('Final state:', this.context.getState());
this.logger.log(`Build sequence completed: ${sequence.id}`);
this.logger.log('Final state:', this.context.getState());
}
}
26 changes: 5 additions & 21 deletions backend/src/build-system/node/product_requirements_document/prd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import { BuildHandler, BuildResult } from 'src/build-system/types';
import { BuilderContext } from 'src/build-system/context';
import { prompts } from './prompt/prompt';
import { ModelProvider } from 'src/common/model-provider';
import { StreamStatus } from 'src/chat/chat.model';
import * as fs from 'fs';
import * as path from 'path';
import { Logger } from '@nestjs/common';

export class PRDHandler implements BuildHandler {
readonly id = 'op:PRD::STATE:GENERATE';

readonly logger: Logger = new Logger('PRDHandler');
async run(context: BuilderContext): Promise<BuildResult> {
console.log('Generating PRD...');
this.logger.log('Generating PRD...');

// Extract project data from the context
const projectName =
Expand All @@ -28,9 +26,6 @@ export class PRDHandler implements BuildHandler {
// Send the prompt to the LLM server and process the response
const prdContent = await this.generatePRDFromLLM(prompt);

// Save the PRD content to context for further use
context.setData('prdDocument', prdContent);

return {
success: true,
data: prdContent,
Expand All @@ -39,20 +34,9 @@ export class PRDHandler implements BuildHandler {

private async generatePRDFromLLM(prompt: string): Promise<string> {
const modelProvider = ModelProvider.getInstance();

const model = 'gpt-3.5-turbo';

// Call the chat method with the model specified
const chatStream = modelProvider.chat(
{
content: prompt,
},
model,
); // Pass the model here

const prdContent = modelProvider.chunkSync(chatStream);

console.log('Received full PRD content from LLM server.');
const prdContent = await modelProvider.chatSync({ content: prompt }, model);
this.logger.log('Received full PRD content from LLM server.');
return prdContent;
}
}
11 changes: 10 additions & 1 deletion backend/src/build-system/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ModelProvider } from 'src/common/model-provider';
import { BuilderContext } from './context';

export type BuildNodeType =
Expand Down Expand Up @@ -74,6 +75,14 @@ export interface BuildExecutionState {
}

export interface BuildHandler {
// Unique identifier for the handler
id: string;
run(context: BuilderContext): Promise<BuildResult>;

/**
*
* @param context the context object for the build
* @param model model provider for the build
* @param args the request arguments
*/
run(context: BuilderContext, args: unknown): Promise<BuildResult>;
}
31 changes: 18 additions & 13 deletions backend/src/common/model-provider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ export class ModelProvider {
private readonly config: ModelProviderConfig,
) {}

async chatSync(
input: ChatInput | string,
model: string,
chatId?: string,
): Promise<string> {
const chatStream = this.chat(input, model, chatId);
let content = '';
for await (const chunk of chatStream) {
if (chunk.status === StreamStatus.STREAMING) {
content += chunk.choices
.map((choice) => choice.delta?.content || '')
.join('');
}
}
this.logger.log('Aggregated content from chat stream:', content);
return content;
}

chat(
input: ChatInput | string,
model: string,
Expand Down Expand Up @@ -199,19 +217,6 @@ export class ModelProvider {
}
}

async chunkSync(chatStream: AsyncIterableIterator<any>): Promise<string> {
let aggregatedContent = '';
for await (const chunk of chatStream) {
if (chunk.status === StreamStatus.STREAMING) {
aggregatedContent += chunk.choices
.map((choice) => choice.delta?.content || '')
.join('');
}
}
this.logger.log('Aggregated content from chat stream:', aggregatedContent);
return aggregatedContent;
}

private startChat(input: ChatInput, model: string, chatId?: string) {
const payload = this.createRequestPayload(input, model, chatId);

Expand Down
7 changes: 6 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c7aa3a2

Please sign in to comment.