This commit is contained in:
Tat Dat Duong
2025-05-13 11:55:43 -07:00
parent 47e7bcee06
commit 6ec0aaa141
5 changed files with 32 additions and 28 deletions
+4 -6
View File
@@ -1,8 +1,7 @@
/** @type {import('jest').Config} */
/** @type {import('ts-jest').JestConfigWithTsJest} **/
export default {
preset: "ts-jest/presets/js-with-ts-esm",
testEnvironment: "node",
testMatch: ["**/tests-ts/**/*.test.ts"],
testMatch: ["**/tests/**/*.test.ts"],
extensionsToTreatAsEsm: [".ts"],
transform: {
"^.+\\.tsx?$": [
@@ -17,10 +16,9 @@ export default {
"^@/(.*)$": "<rootDir>/$1",
"^(\\.{1,2}/.*)\\.js$": "$1",
},
transformIgnorePatterns: ["node_modules/(?!(@langchain|langchain|@jest)/)"],
rootDir: "../",
setupFilesAfterEnv: ["<rootDir>/tests-ts/setup.mjs"],
setupFilesAfterEnv: ["<rootDir>/tests/setup.mjs"],
testTimeout: 30000, // For LLM calls
moduleDirectories: ["node_modules", "src"],
resolver: "jest-ts-webcompat-resolver",
};
+4 -4
View File
@@ -9,10 +9,10 @@
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"format": "prettier --write .",
"agent": "langgraphjs dev",
"test": "NODE_OPTIONS=--experimental-vm-modules jest --config=tests-ts/jest.config.mjs",
"test:hitl": "cross-env NODE_OPTIONS=--experimental-vm-modules AGENT_MODULE=email_assistant_hitl jest --config=tests-ts/jest.config.mjs hitl_testing",
"test:memory": "cross-env NODE_OPTIONS=--experimental-vm-modules AGENT_MODULE=email_assistant_hitl_memory jest --config=tests-ts/jest.config.mjs memory_testing",
"test:base": "cross-env NODE_OPTIONS=--experimental-vm-modules AGENT_MODULE=email_assistant jest --config=tests-ts/jest.config.mjs test_response"
"test": "NODE_OPTIONS=--experimental-vm-modules jest --config=jest.config.mjs",
"test:hitl": "cross-env NODE_OPTIONS=--experimental-vm-modules AGENT_MODULE=email_assistant_hitl jest --config=jest.config.mjs hitl.test.ts",
"test:memory": "cross-env NODE_OPTIONS=--experimental-vm-modules AGENT_MODULE=email_assistant_hitl_memory jest --config=jest.config.mjs memory.test.ts",
"test:base": "cross-env NODE_OPTIONS=--experimental-vm-modules AGENT_MODULE=email_assistant jest --config=jest.config.mjs response.test.ts"
},
"dependencies": {
"@jest/globals": "^29.7.0",
+4 -4
View File
@@ -1,5 +1,5 @@
import { z } from "zod";
import { DynamicStructuredTool, tool } from "@langchain/core/tools";
import { tool } from "@langchain/core/tools";
/**
* Schema for writing an email
@@ -32,7 +32,7 @@ ${content}
description:
"Write an email draft based on provided information. Use this when the user wants to compose a new email message.",
schema: emailSchema,
},
}
);
/**
@@ -76,7 +76,7 @@ Recommended action: ${priority === "High" ? "Respond immediately" : "Review when
description:
"Analyze and categorize an email by importance and type. Use this when evaluating how to handle incoming messages.",
schema: triageSchema,
},
}
);
/**
@@ -99,5 +99,5 @@ export const Done = tool(
description:
"Signal that you've completed the current task and no further actions are needed.",
schema: doneSchema,
},
}
);
+5 -5
View File
@@ -20,7 +20,7 @@ export const backgroundTool = tool(
name: "background",
description: "Get background information about the user",
schema: z.object({}).describe("This tool doesn't take any arguments"),
},
}
);
/**
@@ -36,7 +36,7 @@ export const calPreferencesTool = tool(
name: "cal_preferences",
description: "Get the user's calendar preferences",
schema: z.object({}).describe("This tool doesn't take any arguments"),
},
}
);
/**
@@ -52,14 +52,14 @@ export const responsePreferencesTool = tool(
name: "response_preferences",
description: "Get the user's response style preferences",
schema: z.object({}).describe("This tool doesn't take any arguments"),
},
}
);
/**
* Tool to ask a question to the user
*/
export const questionTool = tool(
async ({ content }: { content: string }) => {
async ({ content }) => {
return `The user will see and can answer this question: ${content}`;
},
{
@@ -68,5 +68,5 @@ export const questionTool = tool(
schema: z.object({
content: z.string().describe("The question to ask the user"),
}),
},
}
);
+15 -9
View File
@@ -1,6 +1,11 @@
import { EmailData } from "./schemas.js";
import { AIMessage, type BaseMessage } from "@langchain/core/messages";
import {
AIMessage,
isAIMessage,
coerceMessageLikeToMessage,
type BaseMessage,
} from "@langchain/core/messages";
import type { ToolCall } from "@langchain/core/messages/tool";
/**
@@ -53,7 +58,7 @@ export function formatEmailMarkdown(
subject: string,
author: string,
to: string,
emailThread: string,
emailThread: string
): string {
return `## Email: ${subject}
@@ -201,13 +206,13 @@ export function extractToolCalls(messages: any[]): string[] {
// Handle plain objects
if (message.tool_calls && Array.isArray(message.tool_calls)) {
toolCallNames.push(
...message.tool_calls.map((call: any) => call.name.toLowerCase()),
...message.tool_calls.map((call: any) => call.name.toLowerCase())
);
}
// Handle class instances with toolCalls property
else if ("toolCalls" in message && Array.isArray(message.toolCalls)) {
toolCallNames.push(
...message.toolCalls.map((call: any) => call.name.toLowerCase()),
...message.toolCalls.map((call: any) => call.name.toLowerCase())
);
}
}
@@ -222,8 +227,9 @@ export function extractToolCalls(messages: any[]): string[] {
*/
export function formatMessagesString(messages: BaseMessage[]): string {
return messages
.map((message) => {
.map((messageLike) => {
let prefix = "";
const message = coerceMessageLikeToMessage(messageLike);
// Determine prefix based on role
if ("role" in message && message.role) {
@@ -252,13 +258,13 @@ export function formatMessagesString(messages: BaseMessage[]): string {
: JSON.stringify(message.content);
// Only AIMessage can have tool_calls
if (message._getType() === "ai") {
if (isAIMessage(message)) {
const aiMessage = message as AIMessage; // Cast to AIMessage from @langchain/core/messages
if (aiMessage.tool_calls && aiMessage.tool_calls.length > 0) {
const toolCallsStr = aiMessage.tool_calls
.map(
(tc: ToolCall) =>
`\n Tool: ${tc.name}\n Args: ${JSON.stringify(tc.args, null, 2)}`,
`\n Tool: ${tc.name}\n Args: ${JSON.stringify(tc.args, null, 2)}`
)
.join("\n");
content += `\n[Tool Calls: ${toolCallsStr}]`;
@@ -277,12 +283,12 @@ export function formatEmailOptional(
subject?: string,
author?: string,
to?: string,
emailThread?: string,
emailThread?: string
): string {
return formatEmailMarkdown(
subject ?? "No Subject",
author ?? "Unknown Sender",
to ?? "Unknown Recipient",
emailThread ?? "",
emailThread ?? ""
);
}