Skip to content

Commit

Permalink
Fix issues with named nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
blindmansion committed Sep 8, 2024
1 parent 9dd6ec3 commit 123f3f0
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 134 deletions.
9 changes: 4 additions & 5 deletions packages/cannoli-core/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
AllVerifiedCannoliCanvasNodeData,
VerifiedCannoliCanvasEdgeData,
} from "./graph";
import { parseNamedNode } from "./utility";

export enum IndicatedNodeType {
Call = "call",
Expand Down Expand Up @@ -1369,13 +1370,11 @@ export class CannoliFactory {

isFloatingNode(id: string): boolean {
const node = this.getNode(id);
// Check if the first line starts with [ and ends with ]
const firstLine = node?.text?.split("\n")[0];
if (firstLine?.startsWith("[") && firstLine?.endsWith("]")) {
return true;
} else {
if (!node?.text) {
return false;
}
const { name } = parseNamedNode(node.text);
return name !== null;
}

createRectangle(x: number, y: number, width: number, height: number) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ChatResponseEdge } from "../../edges/ChatResponseEdge";
import { LoggingEdge } from "../../edges/LoggingEdge";
import { CannoliGroup } from "../CannoliGroup";
import { CannoliNode, VersionedContent } from "../CannoliNode";
import { parseNamedNode } from "src/utility";

export class ContentNode extends CannoliNode {
reset(): void {
Expand All @@ -24,44 +25,25 @@ export class ContentNode extends CannoliNode {
}

getName(content?: string): string | null {
let contentToCheck = content;
const contentToCheck = content || this.text;

if (!contentToCheck) {
contentToCheck = this.text;
if (this.type === ContentNodeType.StandardContent) {
return null;
}

const firstLine = contentToCheck.split("\n")[0].trim();
if (
firstLine.startsWith("[") &&
firstLine.endsWith("]") &&
this.type !== ContentNodeType.StandardContent
) {
try {
// Check if the first line is a valid JSON array
JSON.parse(firstLine);
return null; // If it's a valid JSON array, return null
} catch (e) {
// If it's not a valid JSON array, proceed to extract the name
return firstLine.substring(1, firstLine.length - 1);
}
}
return null;
const { name } = parseNamedNode(contentToCheck);
return name;
}

// Content is everything after the first line
getContentCheckName(content?: string): string {
let contentToCheck = content;

if (!contentToCheck) {
contentToCheck = this.text;
}
const contentToCheck = content || this.text;
const { name, content: parsedContent } = parseNamedNode(contentToCheck);

const name = this.getName(contentToCheck);
if (name !== null) {
const firstLine = contentToCheck.split("\n")[0];
return contentToCheck.substring(firstLine.length + 1);
return parsedContent;
}
return this.text;
return contentToCheck;
}

editContentCheckName(newContent: string): void {
Expand Down
108 changes: 38 additions & 70 deletions packages/cannoli-core/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { CannoliObject } from "./graph/CannoliObject";
import { CannoliVertex } from "./graph/objects/CannoliVertex";
import { CannoliGroup } from "./graph/objects/vertices/CannoliGroup";
import { CannoliNode } from "./graph/objects/vertices/CannoliNode";
import { parseNamedNode } from "./utility";

export interface HttpTemplate {
id: string;
Expand Down Expand Up @@ -237,14 +238,18 @@ export class Run {
// Find all nodes of type "input"
const argNodes = canvasData.nodes.filter((node) => node.cannoliData.type === "input");

// For each arg, check if the key matches the first line of the text in the input node
for (const arg of Object.entries(this.args ?? {})) {
const [key, value] = arg;
const matchingArgNodes = argNodes.filter((node) => node.cannoliData.text.split("\n")[0] === `[${key}]`);
// For each arg, check if the key matches the name of the input node
for (const [key, value] of Object.entries(this.args ?? {})) {
const matchingArgNodes = argNodes.filter((node) => {
const { name } = parseNamedNode(node.cannoliData.text);
return name === key;
});

if (matchingArgNodes.length > 0) {
// If so, set the text of each matching input node after the first line to the value
// If matching nodes are found, update their content
matchingArgNodes.forEach((argNode) => {
argNode.cannoliData.text = argNode.cannoliData.text.split("\n")[0] + "\n" + value;
const { name } = parseNamedNode(argNode.cannoliData.text);
argNode.cannoliData.text = `[${name}]\n${value}`;
});
} else {
throw new Error(`Argument key "${key}" not found in input nodes.`);
Expand Down Expand Up @@ -306,9 +311,9 @@ export class Run {
}

for (const node of argNodes) {
// Check if the first line of the text contains only a bracketed name
if (/^\[.*?\]$/.test(node.cannoliData.text.split("\n")[0])) {
argNames.add(node.cannoliData.text.split("\n")[0].replace("[", "").replace("]", ""));
const { name } = parseNamedNode(node.cannoliData.text);
if (name !== null) {
argNames.add(name);
}
}

Expand All @@ -325,9 +330,9 @@ export class Run {
}

for (const node of resultNodes) {
// Check if the first line of the text contains only a bracketed name
if (/^\[.*?\]$/.test(node.cannoliData.text.split("\n")[0])) {
resultNames.add(node.cannoliData.text.split("\n")[0].replace("[", "").replace("]", ""));
const { name } = parseNamedNode(node.cannoliData.text);
if (name !== null) {
resultNames.add(name);
}
}

Expand All @@ -345,25 +350,19 @@ export class Run {
return { names, includesDynamicReference };
}

// For each action node, check if it's a single line
for (const node of actionNodes) {
const trimmedText = node.cannoliData.text.trim();

if (trimmedText.split("\n").length === 1) {
names.push(trimmedText);
const { name, content } = parseNamedNode(node.cannoliData.text);

if (trimmedText.includes("{{") && trimmedText.includes("}}")) {
includesDynamicReference = true;
}
continue;
if (name !== null) {
names.push(name);
} else if (content.trim().split("\n").length === 1) {
// If it's a single line without a name, treat the whole content as the name
names.push(content.trim());
}

// If it's not a single line, check if the first line is a bracketed name
const firstLine = trimmedText.split("\n")[0];
const match = firstLine.match(/^\[(.*?)\]$/);
if (match) {
names.push(match[1]); // Push the content inside the brackets
continue;
// Check for dynamic references
if (node.cannoliData.text.includes("{{") && node.cannoliData.text.includes("}}")) {
includesDynamicReference = true;
}
}

Expand All @@ -381,13 +380,13 @@ export class Run {
for (const edge of incomingConfigProviderEdges || []) {
const sourceNode = this.canvasData?.nodes.find((node) => node.id === edge.fromNode);
if (sourceNode && (sourceNode.cannoliData.type === ContentNodeType.StandardContent || sourceNode.cannoliData.type === ContentNodeType.Input)) {
// Check if the source node has a bracketed first line
if (/^\[.*?\]$/.test(sourceNode.cannoliData.text.split("\n")[0])) {
providersReferenced.push(sourceNode.cannoliData.text.split("\n")[0].replace("[", "").replace("]", ""));
const { name, content } = parseNamedNode(sourceNode.cannoliData.text);

if (name !== null) {
providersReferenced.push(name);
includesDynamicReference = true;
} else {
providersReferenced.push(sourceNode.cannoliData.text.trim());

providersReferenced.push(content.trim());
}
} else if (sourceNode) {
includesDynamicReference = true;
Expand Down Expand Up @@ -663,12 +662,15 @@ export class Run {
getResults(): { [key: string]: string } {
const variableNodes = Object.values(this.graph).filter((object) => object.type === "output" && object.kind === "node");
const results: { [key: string]: string } = {};

for (const node of variableNodes) {
// The key should be the first line without the square brackets
const firstLine = node.text.split("\n")[0];
const key = firstLine.substring(1, firstLine.length - 1);
results[key] = node.text.split("\n").slice(1).join("\n");
const { name, content } = parseNamedNode(node.text);

if (name !== null) {
results[name] = content.trim();
}
}

return results;
}

Expand Down Expand Up @@ -998,40 +1000,6 @@ export class Run {
};
}

createHttpTemplate(inputString: string): HttpTemplate {
// Split the input string by newline to separate the name from the JSON
const lines = inputString.split("\n");
const nameLine = lines[0];
let jsonString = lines.slice(1).join("\n");

// If the json string is in a text block, remove the leading and trailing quotes, as well as the language identifier
if (jsonString.startsWith("```")) {
jsonString = jsonString.substring(3, jsonString.length - 3);
}

if (jsonString.startsWith("json")) {
jsonString = jsonString.substring(4, jsonString.length);
}

// Extract the name from the first line
const name = nameLine.substring(1, nameLine.length - 1).trim();

// Parse the JSON string
const json = JSON.parse(jsonString);

// Construct the httpTemplate object
const httpTemplate: HttpTemplate = {
id: "", // Using an empty string for the ID as specified
name: name,
url: json.url,
method: json.method,
headers: json.headers,
bodyTemplate: JSON.stringify(json.bodyTemplate),
};

return httpTemplate;
}

logGraph() {
for (const node of Object.values(this.graph)) {
console.log(node.logDetails());
Expand Down
25 changes: 25 additions & 0 deletions packages/cannoli-core/src/utility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export function parseNamedNode(content: string): {
name: string | null;
content: string;
} {
const lines = content.split('\n');
const firstLine = lines[0].trim();

// Check if the first line is a single-bracketed name
if (firstLine.startsWith('[') && firstLine.endsWith(']') && !firstLine.startsWith('[[')) {
// Try to parse as JSON to ensure it's not a valid JSON array
try {
JSON.parse(firstLine);
// If it's a valid JSON array, don't treat it as a name
return { name: null, content };
} catch {
// Not a valid JSON array, so it's a name
const name = firstLine.slice(1, -1);
const remainingContent = lines.slice(1).join('\n');
return { name, content: remainingContent };
}
}

// If not a single-bracketed name, return null for name and the entire content
return { name: null, content };
}
30 changes: 1 addition & 29 deletions packages/cannoli-plugin/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,35 +572,6 @@ export default class Cannoli extends Plugin {
}
};

getArgsFromCanvas = (canvas: string) => {
// Parse into JSON
const json = JSON.parse(canvas);

// Find all nodes with no attatched edges
// Build array of all node IDs referenced in the edges by "toNode" or "fromNode"
const edges = json.edges;
const nodeIds = edges.map((edge: { toNode: string, fromNode: string }) => {
return [edge.toNode, edge.fromNode];
}).flat();

// Look for nodes that are not in the nodeIds array
const nodes = json.nodes;
const noEdgeNodes = nodes.filter((node: { id: string }) => {
return !nodeIds.includes(node.id);
});

// Look in the floating nodes for ones whose text has a first line like this "[name]\n", and grab the name
const floatingNodeNames = noEdgeNodes.filter((node: { text?: string }) => {
const firstLine = node.text?.split("\n")?.[0];
return firstLine?.trim().startsWith("[") && firstLine?.trim().endsWith("]");
}).map((node: { text: string }) => {
return node.text.trim().slice(1, -1);
});

// Return the array
return floatingNodeNames;
}

startActiveCannoliCommand = () => {
this.startCannoliCommand(false);
};
Expand Down Expand Up @@ -1291,6 +1262,7 @@ export default class Cannoli extends Plugin {
if (this.encloses(groupRectangle, nodeRectangle)) {
nodeIds.push(node.id);
} else if (this.overlaps(groupRectangle, nodeRectangle)) {
new Notice(`Invalid layout: Node with id ${node.id} overlaps with the group but is not fully enclosed. Nodes should be fully inside or outside of each group.`);
throw new Error(
`Invalid layout: Node with id ${node.id} overlaps with the group but is not fully enclosed. Nodes should be fully inside or outside of each group.`
);
Expand Down
4 changes: 2 additions & 2 deletions packages/cannoli-plugin/src/vault_interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export class VaultInterface implements FileManager {

// If includeLink is true, add the markdown link
if (reference.includeLink) {
const link = `[[${file.path}#${reference.subpath}]]`;
const link = `[[${file.path}#${reference.subpath}|${file.basename}]]`;
content = link + "\n\n" + content;
}

Expand Down Expand Up @@ -187,7 +187,7 @@ export class VaultInterface implements FileManager {

// If includeLink is true, add the markdown link
if (reference.includeLink) {
const link = `[[${file.path}]]`;
const link = `[[${file.path}|${file.basename}]]`;
content = link + "\n\n" + content;
}

Expand Down

0 comments on commit 123f3f0

Please sign in to comment.