Skip to content

Commit 643b7f9

Browse files
committed
refactor(appkit): dedup agent folder-listing + make code-agent detection .ts-only
From the /simplify pass: - Extract agentDirNames() so both loaders share one folder-selection policy (dir + symlink) instead of duplicating the subtle filter + comment. - Code-agent source detection is .ts-only (resolveCodeAgentsDir source exts + hasCodeAgentSources), matching the build entry glob — an agent.tsx would otherwise load in dev but never be emitted for a prod bundle. Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
1 parent c715b6a commit 643b7f9

5 files changed

Lines changed: 30 additions & 21 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { Dirent } from "node:fs";
2+
3+
/**
4+
* Agent-folder names from a directory listing, sorted. An agent lives in a
5+
* subfolder, so directories count — and symlinks-to-directories too (a shared
6+
* agent folder linked into the agents dir). Single-sourced so the markdown and
7+
* code loaders keep the same folder-selection policy.
8+
*/
9+
export function agentDirNames(entries: Dirent[]): string[] {
10+
return entries
11+
.filter((e) => e.isDirectory() || e.isSymbolicLink())
12+
.map((e) => e.name)
13+
.sort();
14+
}

‎packages/appkit/src/core/agent/load-agents.ts‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
} from "../../core/agent/types";
1616
import { isToolkitEntry } from "../../core/agent/types";
1717
import { createLogger } from "../../logging/logger";
18+
import { agentDirNames } from "./agent-dirs";
1819

1920
const logger = createLogger("agents:loader");
2021

@@ -206,12 +207,8 @@ export async function loadAgentsFromDir(
206207
);
207208
}
208209

209-
const agentIds = entries
210-
// Symlinked agent folders count; a symlink to a file is filtered out below
211-
// when reading agent.md (ENOTDIR).
212-
.filter((e) => e.isDirectory() || e.isSymbolicLink())
213-
.map((e) => e.name)
214-
.sort();
210+
// A symlink to a file is filtered out below when reading agent.md (ENOTDIR).
211+
const agentIds = agentDirNames(entries);
215212

216213
const defs: Record<string, AgentDefinition> = {};
217214
const subAgentRefs: Record<string, string[]> = {};

‎packages/appkit/src/core/agent/load-code-agents.ts‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "node:path";
44
import { pathToFileURL } from "node:url";
55

66
import { createLogger } from "../../logging/logger";
7+
import { agentDirNames } from "./agent-dirs";
78
import { isCreatedAgent } from "./create-agent";
89
import type { AgentDefinition } from "./types";
910

@@ -44,7 +45,9 @@ export function resolveCodeAgentsDir(opts: {
4445
const name = path.basename(sourceRel);
4546
const source: ResolvedCodeAgentsDir = {
4647
dir: path.resolve(opts.cwd, sourceRel),
47-
extensions: [".ts", ".tsx"],
48+
// `.ts` only: the build entry glob is `<dir>/*/agent.ts`, so an `agent.tsx`
49+
// would load in dev but never be emitted for a prod bundle.
50+
extensions: [".ts"],
4851
};
4952
const built: ResolvedCodeAgentsDir[] = CODE_AGENTS_BUILT_ROOTS.map(
5053
(root) => ({
@@ -130,12 +133,9 @@ export async function loadCodeAgentsFromDir(
130133
throw err;
131134
}
132135

133-
const folders = entries
134-
// Include symlinked agent folders; findEntryFile's readdir follows the link
135-
// and returns null for anything that isn't a real directory.
136-
.filter((e) => e.isDirectory() || e.isSymbolicLink())
137-
.map((e) => e.name)
138-
.sort();
136+
// findEntryFile's readdir follows a symlinked folder and returns null for
137+
// anything that isn't a real directory.
138+
const folders = agentDirNames(entries);
139139

140140
const agents: Record<string, AgentDefinition> = {};
141141

‎packages/appkit/src/plugins/agents/agents.ts‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -539,15 +539,13 @@ export class AgentsPlugin extends Plugin implements ToolProvider {
539539
return discovered;
540540
}
541541

542-
/** True when `dir` holds at least one `<id>/agent.{ts,tsx}` folder. */
542+
/** True when `dir` holds at least one `<id>/agent.ts` folder. */
543543
private hasCodeAgentSources(dir: string): boolean {
544544
try {
545545
return readdirSync(dir, { withFileTypes: true }).some((e) => {
546546
if (!e.isDirectory() && !e.isSymbolicLink()) return false;
547547
try {
548-
return readdirSync(path.join(dir, e.name)).some(
549-
(f) => f === "agent.ts" || f === "agent.tsx",
550-
);
548+
return readdirSync(path.join(dir, e.name)).includes("agent.ts");
551549
} catch {
552550
return false;
553551
}

‎packages/appkit/src/plugins/agents/tests/load-code-agents.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
const fixtureDir = (name: string) =>
1212
fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url));
1313

14-
const TS = { extensions: [".ts", ".tsx"] };
14+
const TS = { extensions: [".ts"] };
1515

1616
describe("loadCodeAgentsFromDir", () => {
1717
it("returns an empty record when the directory does not exist", async () => {
@@ -91,7 +91,7 @@ describe("resolveCodeAgentsDir", () => {
9191
// No built output → falls back to the source `.ts` dir.
9292
expect(
9393
resolveCodeAgentsDir({ cwd, override: "my-agents", exists: () => false }),
94-
).toEqual({ dir: customSrc, extensions: [".ts", ".tsx"] });
94+
).toEqual({ dir: customSrc, extensions: [".ts"] });
9595
});
9696

9797
it("stays built-first when dir is set to the default value explicitly", () => {
@@ -117,11 +117,11 @@ describe("resolveCodeAgentsDir", () => {
117117

118118
it("uses server/agents (.ts) only when no built dir exists", () => {
119119
const r = resolveCodeAgentsDir({ cwd, exists: existsIn(source) });
120-
expect(r).toEqual({ dir: source, extensions: [".ts", ".tsx"] });
120+
expect(r).toEqual({ dir: source, extensions: [".ts"] });
121121
});
122122

123123
it("targets server/agents when nothing exists (empty scan downstream)", () => {
124124
const r = resolveCodeAgentsDir({ cwd, exists: () => false });
125-
expect(r).toEqual({ dir: source, extensions: [".ts", ".tsx"] });
125+
expect(r).toEqual({ dir: source, extensions: [".ts"] });
126126
});
127127
});

0 commit comments

Comments
 (0)