Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions typescript/m1/m1.2_scratch_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { model } from "../models.js";

const agent = createDeepAgent({ model });

const result = await agent.invoke({"messages": [{"role": "user", "content": "What is an LLM?"}]});
const result = await agent.invoke({
messages: [{ role: "user", content: "What is an LLM?" }]
});

console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
15 changes: 8 additions & 7 deletions typescript/m1/m1.4_scratch_agent_butler.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { context } from "langchain";
import { createDeepAgent } from "deepagents";

import { model } from "../models.js";

const SYSTEM_PROMPT =
"YOU ARE AN EXTREMELY POSH BRITISH BUTLER. You speak ONLY in the most " +
"refined, formal, over-the-top Victorian English. You say 'indeed', 'quite', " +
"'I dare say', 'one simply must' constantly. You find all things common or " +
"nautical to be utterly beneath you. You NEVER break character under ANY " +
"circumstances.";
const SYSTEM_PROMPT = context`
YOU ARE AN EXTREMELY POSH BRITISH BUTLER. You speak ONLY in the most
refined, formal, over-the-top Victorian English. You say 'indeed', 'quite',
'I dare say', 'one simply must' constantly. You find all things common or
nautical to be utterly beneath you. You NEVER break character under ANY
circumstances.`;

const agent = createDeepAgent({
model,
Expand All @@ -19,4 +20,4 @@ const result = await agent.invoke({
messages: [{ role: "user", content: "What is an LLM?" }],
});

console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
5 changes: 3 additions & 2 deletions typescript/m1/m1.5_scratch_agent_tools.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DatabaseSync } from "node:sqlite";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { tool } from "@langchain/core/tools";

import { z } from "zod";
import { tool } from "langchain";
import { createDeepAgent } from "deepagents";

import { model } from "../models.js";
Expand Down Expand Up @@ -47,4 +48,4 @@ const result = await agent.invoke({
messages: [{ role: "user", content: "Which five genres have the most tracks?" }],
});

console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
52 changes: 27 additions & 25 deletions typescript/m1/m1.6_agent_mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,30 @@ const client = new MultiServerMCPClient({
},
});

let tools = await client.getTools();

console.log(`\ndocs-langchain: ${tools.length} tool(s)`);
for (const t of tools) {
console.log(` ${t.name}`);
console.log(` ${t.description?.slice(0, 90)}`);
}

tools = tools.filter((t) => ALLOWED.has(t.name));

const agent = createDeepAgent({ model, tools });

const result = await agent.invoke({
messages: [
{
role: "user",
content:
"Use the LangChain docs MCP tool to explain what MCP is and how LangChain uses MCP tools.",
},
],
});

console.log(result.messages[result.messages.length - 1].content);

await client.close();
try {
let tools = await client.getTools();

console.log(`\ndocs-langchain: ${tools.length} tool(s)`);
for (const t of tools) {
console.log(` ${t.name}`);
console.log(` ${t.description?.slice(0, 90)}`);
}

tools = tools.filter((t) => ALLOWED.has(t.name));

const agent = createDeepAgent({ model, tools });

const result = await agent.invoke({
messages: [
{
role: "user",
content:
"Use the LangChain docs MCP tool to explain what MCP is and how LangChain uses MCP tools.",
},
],
});

console.log(result.messages.at(-1)?.content);
} finally {
await client.close();
}
6 changes: 3 additions & 3 deletions typescript/m1/m1.7_messages_threads_checkpointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ let result = await agent.invoke(
threadA
);
console.log("Thread A, turn 1:");
console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);

result = await agent.invoke(
{ messages: [{ role: "user", content: "What is my favorite color?" }] },
threadA
);
console.log("\nThread A, turn 2:");
console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);

result = await agent.invoke(
{ messages: [{ role: "user", content: "What is my favorite color?" }] },
threadB
);
console.log("\nThread B, turn 1:");
console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
9 changes: 4 additions & 5 deletions typescript/m1/m1.8_hitl.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { createInterface } from "node:readline/promises";
import { tool } from "@langchain/core/tools";
import { isToolMessage } from "@langchain/core/messages";
import { z } from "zod";
import { MemorySaver } from "@langchain/langgraph";
import { Command, INTERRUPT, isInterrupted } from "@langchain/langgraph";

import { tool, ToolMessage } from "langchain";
import { Command, INTERRUPT, isInterrupted, MemorySaver } from "@langchain/langgraph";
import { createDeepAgent } from "deepagents";

import { model } from "../models.js";
Expand Down Expand Up @@ -97,7 +96,7 @@ while (isInterrupted<ApprovalRequest>(result) && result[INTERRUPT].length) {

rl.close();
for (const msg of result.messages) {
if (isToolMessage(msg) && msg.name === "send_email") {
if (ToolMessage.isInstance(msg) && msg.name === "send_email") {
console.log(msg.content);
break;
}
Expand Down
9 changes: 5 additions & 4 deletions typescript/m2/m2.2_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { dirname, join } from "node:path";
import { mkdirSync, writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url";

import { context } from "langchain";
import {
CompositeBackend,
FilesystemBackend,
Expand Down Expand Up @@ -59,15 +60,15 @@ try {
messages: [
{
role: "user",
content:
"Read /reference/chinook-sales.md, then add this note to it: " +
"'Current promotion: 20% off all Jazz albums through end of month.'",
content: context`
Read /reference/chinook-sales.md, then add this note to it:
'Current promotion: 20% off all Jazz albums through end of month.'`,
},
],
},
{ configurable: { thread_id: "lab-m2.2" } }
);
console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
} catch (e) {
const err = e instanceof Error ? e : new Error(String(e));
const cause = err.cause instanceof Error ? err.cause : undefined;
Expand Down
35 changes: 18 additions & 17 deletions typescript/m2/m2.3_sales_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { writeFileSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";

import { context } from "langchain";
import { LangSmithSandbox, createDeepAgent } from "deepagents";
import { SandboxClient } from "langsmith/sandbox";

Expand Down Expand Up @@ -34,33 +35,33 @@ for (const result of uploadResults) {
const agent = createDeepAgent({
model,
backend,
systemPrompt:
"You are a sales data analyst with access to the Chinook music store database " +
"at /chinook.db. Use sqlite3 and matplotlib to answer questions with charts. " +
"Install any packages you need with pip before importing them. " +
"When asked to produce a chart, write a Python script, execute it, and confirm " +
"the output file was created.",
systemPrompt: context`
You are a sales data analyst with access to the Chinook music store database
at /chinook.db. Use sqlite3 and matplotlib to answer questions with charts.
Install any packages you need with pip before importing them.
When asked to produce a chart, write a Python script, execute it, and confirm
the output file was created.`,
});

try {
const result = await agent.invoke({
messages: [
{
role: "user",
content:
"Query the Chinook database at /chinook.db to get total revenue " +
"by genre. Create a clean donut chart showing each genre's share " +
"of total sales revenue. Group any genres that individually " +
"account for less than 3% of total revenue into a single 'Other' " +
"slice. Label each slice with the genre name and percentage. " +
"Use a visually distinct color palette, leave a white center hole, " +
"and make sure no labels overlap with each other or with the title. " +
"Add enough top padding so the title is fully visible. " +
"Save the chart to /genre_revenue.png.",
content: context`
Query the Chinook database at /chinook.db to get total revenue
by genre. Create a clean donut chart showing each genre's share
of total sales revenue. Group any genres that individually
account for less than 3% of total revenue into a single 'Other'
slice. Label each slice with the genre name and percentage.
Use a visually distinct color palette, leave a white center hole,
and make sure no labels overlap with each other or with the title.
Add enough top padding so the title is fully visible.
Save the chart to /genre_revenue.png.`,
},
],
});
console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);

const pngBytes = await ls_sandbox.read("/genre_revenue.png");
const outPath = join(__dirname, "genre_revenue.png");
Expand Down
15 changes: 8 additions & 7 deletions typescript/m2/m2.3_sandbox_agent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// typescript/m2/m2.3_sandbox_agent.ts
import { randomUUID } from "node:crypto";

import { context } from "langchain";
import { LangSmithSandbox, createDeepAgent } from "deepagents";
import { SandboxClient } from "langsmith/sandbox";

Expand All @@ -16,23 +17,23 @@ const backend = new LangSmithSandbox({ sandbox: ls_sandbox });
const agent = createDeepAgent({
model,
backend,
systemPrompt:
"You are a coding assistant. When asked to run code, write the script " +
"to a file first, then execute it. Show the output in your final answer.",
systemPrompt: context`
You are a coding assistant. When asked to run code, write the script
to a file first, then execute it. Show the output in your final answer.`,
});

try {
const result = await agent.invoke({
messages: [
{
role: "user",
content:
"Write a Python script that prints the first 15 Fibonacci numbers, " +
"save it to fib.py, and run it.",
content: context`
Write a Python script that prints the first 15 Fibonacci numbers,
save it to fib.py, and run it.`,
},
],
});
console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
} finally {
await client.deleteSandbox(ls_sandbox.name);
}
2 changes: 1 addition & 1 deletion typescript/m2/m2.4_eval_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ const result = await agent.invoke({
],
});

console.log(result.messages[result.messages.length - 1].content);
console.log(result.messages.at(-1)?.content);
44 changes: 22 additions & 22 deletions typescript/m2/m2.4_interpreter_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@ import { DatabaseSync } from "node:sqlite";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

import { createCodeInterpreterMiddleware } from "@langchain/quickjs";
import { tool } from "@langchain/core/tools";
import { createDeepAgent } from "deepagents";
import { z } from "zod";
import { context, tool } from "langchain";
import { createDeepAgent } from "deepagents";
import { createCodeInterpreterMiddleware } from "@langchain/quickjs";

import { model } from "../models.js";

const __dirname = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(__dirname, "chinook.db");

const TASK =
"Who is our top-selling artist, what is their best-selling album, " +
"what is the most-purchased track on that album, " +
"and how many distinct customers have bought that track? " +
"Each answer depends on the result of the previous query.";
const TASK = context`
Who is our top-selling artist, what is their best-selling album,
what is the most-purchased track on that album,
and how many distinct customers have bought that track?
Each answer depends on the result of the previous query.`;

const SYSTEM =
"You are a sales analyst for Chinook Digital Music Store. " +
"Use the query_chinook tool to query the database. " +
"Key tables: Artist(ArtistId, Name), Album(AlbumId, Title, ArtistId), " +
"Track(TrackId, Name, AlbumId), " +
"InvoiceLine(InvoiceLineId, InvoiceId, TrackId, UnitPrice, Quantity). " +
"Revenue is InvoiceLine.UnitPrice * InvoiceLine.Quantity.";
const SYSTEM = context`
You are a sales analyst for Chinook Digital Music Store.
Use the query_chinook tool to query the database.
Key tables: Artist(ArtistId, Name), Album(AlbumId, Title, ArtistId),
Track(TrackId, Name, AlbumId),
InvoiceLine(InvoiceLineId, InvoiceId, TrackId, UnitPrice, Quantity).
Revenue is InvoiceLine.UnitPrice * InvoiceLine.Quantity.`;

const queryChinook = tool(
({ sql }) => {
Expand All @@ -53,13 +53,13 @@ const agentWith = createDeepAgent({
model,
tools: [queryChinook],
middleware: [createCodeInterpreterMiddleware({ ptc: ["query_chinook"] })],
systemPrompt:
SYSTEM +
" The eval tool supports Programmatic Tool Calling (PTC): JavaScript" +
" running inside eval() can call query_chinook via tools.queryChinook()." +
" For dependent queries where each answer requires a result from the" +
" previous, prefer a single eval() call that chains all queries in" +
" JavaScript — intermediate values stay in variables and never return to the model.",
systemPrompt: context`
${SYSTEM}
The eval tool supports Programmatic Tool Calling (PTC): JavaScript
running inside eval() can call query_chinook via tools.queryChinook().
For dependent queries where each answer requires a result from the
previous, prefer a single eval() call that chains all queries in
JavaScript — intermediate values stay in variables and never return to the model.`,
});

const resultWith = await agentWith.invoke(
Expand Down
4 changes: 2 additions & 2 deletions typescript/m3/m3.1_summarization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// npx tsx m3/m3.1_summarization.ts

import { createDeepAgent } from "deepagents";
import { HumanMessage } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
import { HumanMessage } from "@langchain/core/messages";

import { model } from "../models.js";

Expand Down Expand Up @@ -47,7 +47,7 @@ async function turn(message: string): Promise<unknown> {
{ messages: [new HumanMessage(message)] },
THREAD
);
return result.messages[result.messages.length - 1].content;
return result.messages.at(-1)?.content;
}

async function showState(): Promise<void> {
Expand Down
Loading