open-swe/apps/open-swe-v2/src/state.ts
Palash Shah 46d795c41b
feat: open swe v2 in js! (#797)
* feat: openswe v2

* feat: yarn lock

* update: add eslint

* update: working build & lint

* chore: update types

* chore: format

* reorg agent v2

* cleanup

* fixes

* nits: modifications

* feat: updates

* nit: update yarn lock

* nit: don't add dep to root

* chore: update yarn

* chore: update langgraph.json

* nit: update names

* chore: update functions

* nit: update

---------

Co-authored-by: bracesproul <braceasproul@gmail.com>
2025-08-27 09:49:54 -04:00

103 lines
2.9 KiB
TypeScript

import "@langchain/langgraph/zod";
import { z } from "zod";
import { withLangGraph } from "@langchain/langgraph/zod";
import * as path from "path";
import { DeepAgentState } from "deepagents";
import { FILE_EDIT_COMMANDS } from "./constants.js";
import {
Command,
CommandArgs,
ApprovalKey,
FileEditCommandArgs,
ExecuteBashCommandArgs,
FileSystemCommandArgs,
ApprovedOperations,
} from "./types.js";
export const CodingAgentState: any = DeepAgentState.extend({
approved_operations: withLangGraph(
z.custom<ApprovedOperations>().optional(),
{
reducer: {
schema: z.custom<ApprovedOperations>().optional(),
fn: (
_state: ApprovedOperations | undefined,
update: ApprovedOperations | undefined,
) => update,
},
default: () => ({ cached_approvals: new Set<string>() }),
},
),
});
export type CodingAgentStateType = z.infer<typeof CodingAgentState>;
/**
* Helper functions for the coding agent state
*/
export class AgentStateHelpers {
static getApprovalKey(command: Command, args: CommandArgs): ApprovalKey {
let targetDir: string | null = null;
if (FILE_EDIT_COMMANDS.has(command)) {
const fileArgs = args as FileEditCommandArgs;
const filePath = fileArgs.file_path || fileArgs.path;
if (filePath) {
targetDir = path.dirname(path.resolve(filePath));
}
} else if (command === "execute_bash") {
const bashArgs = args as ExecuteBashCommandArgs;
targetDir = bashArgs.cwd || process.cwd();
} else if (["ls", "glob", "grep"].includes(command)) {
const fsArgs = args as FileSystemCommandArgs;
targetDir = fsArgs.path || fsArgs.directory || process.cwd();
}
if (!targetDir) {
targetDir = process.cwd();
}
// Create a cache key: command_type:normalized_directory
const normalizedDir = path.normalize(targetDir);
return `${command}:${normalizedDir}`;
}
/**
* Check if a command/directory combination has been previously approved.
*/
static isOperationApproved(
state: CodingAgentStateType,
command: Command,
args: CommandArgs,
): boolean {
if (
!state.approved_operations ||
!state.approved_operations.cached_approvals
) {
return false;
}
const approvalKey = this.getApprovalKey(command, args);
return state.approved_operations.cached_approvals.has(approvalKey);
}
/**
* Add a command/directory combination to the approved operations cache.
*/
static addApprovedOperation(
state: CodingAgentStateType,
command: Command,
args: CommandArgs,
): void {
if (!state.approved_operations) {
state.approved_operations = { cached_approvals: new Set<string>() };
}
if (!state.approved_operations.cached_approvals) {
state.approved_operations.cached_approvals = new Set<string>();
}
const approvalKey = this.getApprovalKey(command, args);
state.approved_operations.cached_approvals.add(approvalKey);
}
}