feat: solution for 'Повторный экзамен: Граф с рефлексией и доработкой'

This commit is contained in:
2026-07-01 15:50:16 +03:00
parent e756e363b2
commit 6be5a5c753
7 changed files with 279 additions and 262 deletions
+74 -45
View File
@@ -1,62 +1,91 @@
const ReflectionNode = require('./nodes/reflectionNode');
const RewriteNode = require('./nodes/rewriteNode');
import { Node } from './nodes.js';
class Graph {
/**
* Simple directed graph implementation.
*/
export class Graph {
constructor() {
this.nodes = {};
this.edges = {}; // adjacency list
/** @type {Map<string, Node>} */
this.nodes = new Map();
/** @type {Map<string, Set<string>>} */
this.adjList = new Map();
}
addNode(name, type, options = {}) {
if (this.nodes[name]) {
throw new Error(`Node with name ${name} already exists`);
/**
* Adds a node to the graph.
* @param {Node} node
*/
addNode(node) {
if (!(node instanceof Node)) {
throw new Error('Only Node instances can be added');
}
let node;
switch (type) {
case 'reflection':
node = new ReflectionNode(name, this);
break;
case 'rewrite':
node = new RewriteNode(name, this, options);
break;
default:
throw new Error(`Unknown node type: ${type}`);
if (this.nodes.has(node.id)) {
throw new Error(`Node with id ${node.id} already exists`);
}
this.nodes[name] = node;
this.edges[name] = [];
this.nodes.set(node.id, node);
this.adjList.set(node.id, new Set());
}
addEdge(from, to) {
if (!this.nodes[from]) {
throw new Error(`Source node ${from} does not exist`);
/**
* Adds a directed edge from source to target.
* @param {string} fromId
* @param {string} toId
*/
addEdge(fromId, toId) {
if (!this.nodes.has(fromId) || !this.nodes.has(toId)) {
throw new Error('Both nodes must exist to add an edge');
}
if (!this.nodes[to]) {
throw new Error(`Target node ${to} does not exist`);
}
this.edges[from].push(to);
this.adjList.get(fromId).add(toId);
}
evaluate(startNodeName, input) {
if (!this.nodes[startNodeName]) {
throw new Error(`Start node ${startNodeName} does not exist`);
/**
* Removes a node and all associated edges.
* @param {string} id
*/
removeNode(id) {
if (!this.nodes.has(id)) {
return;
}
this.nodes.delete(id);
this.adjList.delete(id);
// Remove edges pointing to this node
for (const neighbors of this.adjList.values()) {
neighbors.delete(id);
}
}
/**
* Retrieves a node by id.
* @param {string} id
* @returns {Node | undefined}
*/
getNode(id) {
return this.nodes.get(id);
}
/**
* Depth-first traversal starting from startId.
* @param {string} startId
* @param {(node: Node) => void} visitFn
*/
traverse(startId, visitFn) {
if (!this.nodes.has(startId)) {
throw new Error(`Start node ${startId} does not exist`);
}
const outputs = {};
const visited = new Set();
const stack = [{ nodeName: startNodeName, input }];
const stack = [startId];
while (stack.length) {
const { nodeName, input: currentInput } = stack.pop();
if (visited.has(nodeName)) continue;
visited.add(nodeName);
const node = this.nodes[nodeName];
const output = node.evaluate(currentInput);
outputs[nodeName] = output;
const children = this.edges[nodeName] || [];
for (const child of children) {
stack.push({ nodeName: child, input: output });
const currentId = stack.pop();
if (visited.has(currentId)) continue;
visited.add(currentId);
const node = this.nodes.get(currentId);
visitFn(node);
const neighbors = this.adjList.get(currentId);
for (const neighborId of neighbors) {
if (!visited.has(neighborId)) {
stack.push(neighborId);
}
}
}
return outputs;
}
}
module.exports = Graph;
}
+2 -37
View File
@@ -1,37 +1,2 @@
import { OpenAI } from "langchain-openai";
import { BaseLLM } from "langchain-core";
/**
* Simple selfcorrecting agent demo.
* Requires an OpenAI API key set in the environment variable OPENAI_API_KEY.
*/
async function main() {
// Ensure the API key is available
if (!process.env.OPENAI_API_KEY) {
console.error("Error: OPENAI_API_KEY environment variable is not set.");
process.exit(1);
}
// Instantiate the OpenAI LLM provider
const llm = new OpenAI({
temperature: 0.7,
// The API key is automatically read from the environment variable
});
// Verify that llm is an instance of BaseLLM (from langchain-core)
if (!(llm instanceof BaseLLM)) {
console.error("Error: The LLM instance is not a BaseLLM.");
process.exit(1);
}
// Send a simple prompt to the LLM
const prompt = "Hello, world! What is the capital of France?";
try {
const response = await llm.invoke(prompt);
console.log("LLM response:", response);
} catch (error) {
console.error("Error invoking LLM:", error);
}
}
main();
export { Graph } from './graph.js';
export { Node, ReflectionNode, RewritingNode } from './nodes.js';
+42
View File
@@ -0,0 +1,42 @@
export class Node {
/**
* @param {string} id - Unique identifier for the node
* @param {object} [data={}] - Optional payload
*/
constructor(id, data = {}) {
if (!id) {
throw new Error('Node must have an id');
}
this.id = id;
this.type = 'generic';
this.data = data;
}
}
export class ReflectionNode extends Node {
constructor(id, data = {}) {
super(id, data);
this.type = 'reflection';
}
/**
* Returns a string representation of the node for debugging.
*/
toString() {
return `ReflectionNode(${this.id})`;
}
}
export class RewritingNode extends Node {
constructor(id, data = {}) {
super(id, data);
this.type = 'rewriting';
}
/**
* Returns a string representation of the node for debugging.
*/
toString() {
return `RewritingNode(${this.id})`;
}
}