66 lines
2.2 KiB
TypeScript
66 lines
2.2 KiB
TypeScript
import { Type } from "typebox";
|
|
import { FINALIZE_TOOL_NAME } from "./constants.ts";
|
|
import type { PromptConfig, SubagentFinalizePayload } from "./types.ts";
|
|
import { FinalizeStatus } from "./types.ts";
|
|
|
|
// Resolve Tools - Use exactly one permission mode. approved_tools/allowed_tools
|
|
// is a whitelist; denied_tools is a blacklist over the currently active tools.
|
|
export function resolveTools(
|
|
agent: PromptConfig,
|
|
activeTools: string[],
|
|
): string[] {
|
|
const withoutDelegationTools = (tools: string[]) =>
|
|
tools.filter((tool) => tool !== "subagent" && tool !== FINALIZE_TOOL_NAME);
|
|
|
|
const resolved =
|
|
agent.approvedTools.length > 0
|
|
? withoutDelegationTools([...new Set(agent.approvedTools)])
|
|
: withoutDelegationTools(
|
|
[...new Set(activeTools)].filter(
|
|
(tool) => !new Set(agent.deniedTools).has(tool),
|
|
),
|
|
);
|
|
|
|
return [...new Set([...resolved, FINALIZE_TOOL_NAME])];
|
|
}
|
|
|
|
// Validate Finalize Payload - Keep the parent contract strict and small.
|
|
export function validateFinalizePayload(
|
|
value: unknown,
|
|
): SubagentFinalizePayload | null {
|
|
if (!value || typeof value !== "object") return null;
|
|
const payload = value as Record<string, unknown>;
|
|
if (payload.status === FinalizeStatus.SUCCESS) {
|
|
return typeof payload.result === "string" && payload.result.trim()
|
|
? { status: FinalizeStatus.SUCCESS, result: payload.result }
|
|
: null;
|
|
}
|
|
if (payload.status === FinalizeStatus.ERROR) {
|
|
const result =
|
|
typeof payload.result === "string" ? payload.result : undefined;
|
|
return typeof payload.error === "string" && payload.error.trim()
|
|
? { status: FinalizeStatus.ERROR, error: payload.error, result }
|
|
: null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export const SubagentParams = Type.Object({
|
|
agent: Type.String({
|
|
description: "Name of the prompt-defined subagent to invoke",
|
|
}),
|
|
task: Type.String({ description: "Task to delegate to the subagent" }),
|
|
sessionId: Type.Optional(
|
|
Type.String({
|
|
description:
|
|
"Optional sticky subagent session id. Reuse to continue a previous subagent context.",
|
|
}),
|
|
),
|
|
cwd: Type.Optional(
|
|
Type.String({
|
|
description:
|
|
"Working directory for the subagent process. Defaults to current cwd.",
|
|
}),
|
|
),
|
|
});
|