@faapi/faapi 6.26.0 → 6.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1835,6 +1835,19 @@ function createTaskRegistry() {
1835
1835
  };
1836
1836
  }
1837
1837
 
1838
+ // src/injection/subAgentToolName.ts
1839
+ var LLM_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
1840
+ var SUB_AGENT_TOOL_PREFIX = "agent-";
1841
+ function subAgentToolName(agentName) {
1842
+ const toolName = SUB_AGENT_TOOL_PREFIX + agentName;
1843
+ if (!LLM_TOOL_NAME_PATTERN.test(toolName)) {
1844
+ throw new Error(
1845
+ `Sub-agent tool name "${toolName}" (from agent name "${agentName}") violates the LLM tool name pattern ${LLM_TOOL_NAME_PATTERN} \u2014 rename the agent (allowed: a-z A-Z 0-9 '-' '_'; file-based agent directory segments allow a-z A-Z 0-9 '-' only, '_' is the nesting separator)`
1846
+ );
1847
+ }
1848
+ return toolName;
1849
+ }
1850
+
1838
1851
  // src/injection/registries.ts
1839
1852
  function createToolRegistry() {
1840
1853
  let registry = /* @__PURE__ */ new Map();
@@ -1882,7 +1895,7 @@ function createAgentRegistry(tool) {
1882
1895
  if (!agent) return void 0;
1883
1896
  return {
1884
1897
  kind: "agent",
1885
- name: `agent.${agent.name}`,
1898
+ name: subAgentToolName(agent.name),
1886
1899
  agentName: agent.name,
1887
1900
  description: agent.description,
1888
1901
  metadata: agent
@@ -2224,7 +2237,6 @@ async function runTaskInWorker(options) {
2224
2237
  payload,
2225
2238
  taskCtx: {
2226
2239
  config: safeConfig(taskCtx.config),
2227
- resourcesDir: taskCtx.resourcesDir,
2228
2240
  job: taskCtx.job
2229
2241
  },
2230
2242
  registries: options.registries,
@@ -2607,7 +2619,6 @@ function createTaskQueue(deps) {
2607
2619
  const taskCtx = {
2608
2620
  signal: job.signal,
2609
2621
  config: deps.config,
2610
- resourcesDir: deps.resourcesDir,
2611
2622
  job: { id: job.id, name: job.name, attempt: job.attempt },
2612
2623
  registries: registriesView,
2613
2624
  log: createLogger(`task:${job.name}`, {
@@ -3687,6 +3698,7 @@ function extractJSDocTagValue(jsDoc, tagName) {
3687
3698
  }
3688
3699
 
3689
3700
  // src/ast/extractToolMetadata.ts
3701
+ init_resolveTypeNode();
3690
3702
  function extractToolMetadata(program, filePath, functionName, pathMeta) {
3691
3703
  const sourceFile = program.getSourceFile(filePath);
3692
3704
  if (!sourceFile) return null;
@@ -3696,6 +3708,14 @@ function extractToolMetadata(program, filePath, functionName, pathMeta) {
3696
3708
  const jsDoc = getJSDocFromNode(jsDocOwner);
3697
3709
  const description = extractDescription(jsDoc);
3698
3710
  const toolNameOverride = extractJSDocTagValue(jsDoc, "tool");
3711
+ if (toolNameOverride !== void 0 && !LLM_TOOL_NAME_PATTERN.test(toolNameOverride)) {
3712
+ throw SchemaExtractionError.at(
3713
+ jsDocOwner,
3714
+ "@tool",
3715
+ `\u8986\u76D6\u540D "${toolNameOverride}" \u542B\u975E\u6CD5\u5B57\u7B26\u2014\u2014\u987B\u6EE1\u8DB3 ${LLM_TOOL_NAME_PATTERN}\uFF08tool \u540D\u76F4\u63A5\u4F5C\u4E3A LLM function.name\uFF0C\u5F3A\u6821\u9A8C\u4E0A\u6E38\u5BF9\u975E\u6CD5\u5B57\u7B26\u6574\u5355 400\uFF09`,
3716
+ sourceFile
3717
+ );
3718
+ }
3699
3719
  const inputTypeName = getFirstParamTypeName(fn, sourceFile);
3700
3720
  return {
3701
3721
  name: toolNameOverride ?? pathMeta.name,
@@ -4296,7 +4316,7 @@ import {
4296
4316
  import { createSecureServer as createHttp2SecureServer } from "http2";
4297
4317
  import { readFileSync } from "fs";
4298
4318
  import { Readable as Readable2 } from "stream";
4299
- import path21 from "path";
4319
+ import path20 from "path";
4300
4320
 
4301
4321
  // src/router/matchRoute.ts
4302
4322
  var httpIndexCache = /* @__PURE__ */ new WeakMap();
@@ -4917,18 +4937,10 @@ function formatSetCookie(name, value, options) {
4917
4937
  if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;
4918
4938
  return cookie;
4919
4939
  }
4920
- function createContext(request, params, config = {}, ip = "", registries, resourcesDir) {
4921
- return createContextFromUrl(
4922
- request,
4923
- new URL(request.url),
4924
- params,
4925
- config,
4926
- ip,
4927
- registries,
4928
- resourcesDir
4929
- );
4940
+ function createContext(request, params, config = {}, ip = "", registries) {
4941
+ return createContextFromUrl(request, new URL(request.url), params, config, ip, registries);
4930
4942
  }
4931
- function createContextFromUrl(request, url, params, config = {}, ip = "", registries, resourcesDir) {
4943
+ function createContextFromUrl(request, url, params, config = {}, ip = "", registries) {
4932
4944
  const meta = { headers: {}, setCookies: [] };
4933
4945
  const parsedCookies = parseCookies(request.headers.get("cookie") ?? "");
4934
4946
  const cookiesObj = {};
@@ -4956,9 +4968,6 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
4956
4968
  ua: request.headers.get("user-agent") ?? "",
4957
4969
  cookies: cookiesObj,
4958
4970
  config,
4959
- // 运行时资源根目录(HTTP/WS 链路由 createServer/handleWsUpgrade 传入;
4960
- // testing 直调未传时为 undefined,见 contextTypes.resourcesDir 注释)
4961
- resourcesDir,
4962
4971
  meta,
4963
4972
  setStatus(status) {
4964
4973
  meta.status = status;
@@ -5776,17 +5785,9 @@ function etag(options = {}) {
5776
5785
  }
5777
5786
 
5778
5787
  // src/server/handleWsUpgrade.ts
5779
- import fs17 from "fs";
5788
+ import fs16 from "fs";
5780
5789
  import { WebSocketServer, WebSocket } from "ws";
5781
- import path20 from "path";
5782
-
5783
- // src/cli/copyResources.ts
5784
5790
  import path19 from "path";
5785
- import fs16 from "fs";
5786
- var RESOURCES_OUTPUT_DIR = "resources";
5787
- function resolveResourcesDir(rootDir, dist) {
5788
- return path19.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
5789
- }
5790
5791
 
5791
5792
  // src/server/serverUtils.ts
5792
5793
  function nodeHttpToWebHeaders(req) {
@@ -5926,7 +5927,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
5926
5927
  const dist = getDevDist();
5927
5928
  if (dist) {
5928
5929
  const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
5929
- if (sourcePath && fs17.existsSync(sourcePath)) {
5930
+ if (sourcePath && fs16.existsSync(sourcePath)) {
5930
5931
  await ensureCompiled(sourcePath, rootDir, dist);
5931
5932
  }
5932
5933
  }
@@ -6024,7 +6025,6 @@ function attachWebSocket(options) {
6024
6025
  trustedProxy = false,
6025
6026
  registries
6026
6027
  } = options;
6027
- const resourcesDir = resolveResourcesDir(rootDir, dist);
6028
6028
  const wss = new WebSocketServer({ noServer: true });
6029
6029
  server.on("upgrade", async (req, socket, head) => {
6030
6030
  try {
@@ -6056,19 +6056,12 @@ function attachWebSocket(options) {
6056
6056
  const host = req.headers.host ?? "localhost";
6057
6057
  const fullUrl = new URL(`http://${host}${req.url ?? "/"}`);
6058
6058
  const request = new Request(fullUrl.toString(), { method: "GET", headers });
6059
- const ctx = createContext(
6060
- request,
6061
- params,
6062
- config,
6063
- getClientIp(req, trustedProxy),
6064
- registries,
6065
- resourcesDir
6066
- );
6059
+ const ctx = createContext(request, params, config, getClientIp(req, trustedProxy), registries);
6067
6060
  const meta = ctx.meta;
6068
6061
  let upgraded = false;
6069
6062
  const finalHandler = async () => {
6070
6063
  const schemaPath = getRuntimeSchemaPath(route.filePath, dist, rootDir);
6071
- if (fs17.existsSync(schemaPath)) {
6064
+ if (fs16.existsSync(schemaPath)) {
6072
6065
  if (isDevOnDemandEnabled()) {
6073
6066
  const devDist = getDevDist();
6074
6067
  if (devDist) {
@@ -6107,7 +6100,7 @@ function attachWebSocket(options) {
6107
6100
  }
6108
6101
  let handlers;
6109
6102
  try {
6110
- const absoluteFilePath = path20.resolve(rootDir, route.filePath);
6103
+ const absoluteFilePath = path19.resolve(rootDir, route.filePath);
6111
6104
  handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
6112
6105
  } catch (err) {
6113
6106
  const reason = err instanceof Error ? err.message : String(err);
@@ -6267,7 +6260,6 @@ function createServer(options) {
6267
6260
  trustedProxy = false
6268
6261
  } = options;
6269
6262
  const routesRef = { current: routes, wsCurrent: wsRoutes ?? [] };
6270
- const resourcesDir = resolveResourcesDir(rootDir, dist);
6271
6263
  const configMiddlewares = [];
6272
6264
  if (compressionOption) {
6273
6265
  const compOpts = typeof compressionOption === "object" ? compressionOption : {};
@@ -6314,8 +6306,7 @@ function createServer(options) {
6314
6306
  bodyLimit,
6315
6307
  trustedProxy,
6316
6308
  registries,
6317
- routesRef.wsCurrent,
6318
- resourcesDir
6309
+ routesRef.wsCurrent
6319
6310
  ).catch((err) => {
6320
6311
  console.error("[faapi] Request pipeline failed after error response attempt:", err);
6321
6312
  try {
@@ -6341,7 +6332,7 @@ function createServer(options) {
6341
6332
  });
6342
6333
  return { server, routesRef };
6343
6334
  }
6344
- function prepareRequest(req, request, url, config, trustedProxy, registries, preMatched, resourcesDir) {
6335
+ function prepareRequest(req, request, url, config, trustedProxy, registries, preMatched) {
6345
6336
  const method = request.method.toUpperCase();
6346
6337
  const urlPath = url.pathname;
6347
6338
  const ctx = createContextFromUrl(
@@ -6350,8 +6341,7 @@ function prepareRequest(req, request, url, config, trustedProxy, registries, pre
6350
6341
  preMatched?.params ?? {},
6351
6342
  config,
6352
6343
  getClientIp(req, trustedProxy),
6353
- registries,
6354
- resourcesDir
6344
+ registries
6355
6345
  );
6356
6346
  const meta = ctx.meta;
6357
6347
  return { request, url, ctx, meta, method, urlPath };
@@ -6370,7 +6360,7 @@ function getRoutePaths(route, rootDir, dist) {
6370
6360
  let cached = routePathCache.get(route);
6371
6361
  if (!cached) {
6372
6362
  cached = {
6373
- absFilePath: path21.resolve(rootDir, route.filePath),
6363
+ absFilePath: path20.resolve(rootDir, route.filePath),
6374
6364
  schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
6375
6365
  };
6376
6366
  routePathCache.set(route, cached);
@@ -6493,7 +6483,7 @@ async function sendErrorResponse(err, meta, res, onError, ctx) {
6493
6483
  }
6494
6484
  }
6495
6485
  }
6496
- async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares, onError, config, globalInjectors, bodyLimit, trustedProxy, registries, wsRoutes, resourcesDir) {
6486
+ async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares, onError, config, globalInjectors, bodyLimit, trustedProxy, registries, wsRoutes) {
6497
6487
  let meta = { headers: {}, setCookies: [] };
6498
6488
  let ctx;
6499
6489
  let sseEarlySent = false;
@@ -6513,8 +6503,7 @@ async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares,
6513
6503
  config,
6514
6504
  trustedProxy,
6515
6505
  registries,
6516
- preMatched,
6517
- resourcesDir
6506
+ preMatched
6518
6507
  );
6519
6508
  ctx = prepared.ctx;
6520
6509
  meta = prepared.meta;
@@ -6590,8 +6579,8 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
6590
6579
  }
6591
6580
 
6592
6581
  // src/cli/generateRoutes.ts
6593
- import fs18 from "fs";
6594
- import path22 from "path";
6582
+ import fs17 from "fs";
6583
+ import path21 from "path";
6595
6584
  async function hydrateRoutes(manifest) {
6596
6585
  const hydrateRoute = (serialized) => ({
6597
6586
  method: serialized.method,
@@ -6635,18 +6624,18 @@ function createIdleTaskDriver() {
6635
6624
  }
6636
6625
 
6637
6626
  // src/cli/loadPlugins.ts
6638
- import path24 from "path";
6639
- import fs20 from "fs";
6627
+ import path23 from "path";
6628
+ import fs19 from "fs";
6640
6629
  import { pathToFileURL as pathToFileURL3 } from "url";
6641
6630
 
6642
6631
  // src/cli/compileConfig.ts
6643
- import path23 from "path";
6644
- import fs19 from "fs";
6632
+ import path22 from "path";
6633
+ import fs18 from "fs";
6645
6634
  async function compileProjectModules(entryPoints, rootDir, dist) {
6646
6635
  const { insideFiles, outsideFiles } = await collectRelativeImports(entryPoints, rootDir);
6647
6636
  const esbuild = await import("esbuild");
6648
6637
  const aliasPlugins = buildAliasPlugins(rootDir);
6649
- const absDist = path23.resolve(rootDir, dist);
6638
+ const absDist = path22.resolve(rootDir, dist);
6650
6639
  await esbuild.build({
6651
6640
  entryPoints: [...entryPoints, ...outsideFiles],
6652
6641
  outdir: absDist,
@@ -6660,7 +6649,7 @@ async function compileProjectModules(entryPoints, rootDir, dist) {
6660
6649
  logLevel: "silent"
6661
6650
  });
6662
6651
  if (insideFiles.length > 0) {
6663
- const appOutbase = path23.resolve(rootDir, "src");
6652
+ const appOutbase = path22.resolve(rootDir, "src");
6664
6653
  await esbuild.build({
6665
6654
  entryPoints: insideFiles,
6666
6655
  outdir: absDist,
@@ -6741,30 +6730,30 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
6741
6730
  var TS_EXTS = /\.(ts|tsx|mts|cts)$/;
6742
6731
  var JS_EXTS = /\.(js|mjs|cjs|jsx)$/;
6743
6732
  function resolveLocalPluginSource(specifier, baseDir) {
6744
- const base = path24.isAbsolute(specifier) ? specifier : path24.resolve(baseDir, specifier);
6745
- if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs20.existsSync(base)) return base;
6733
+ const base = path23.isAbsolute(specifier) ? specifier : path23.resolve(baseDir, specifier);
6734
+ if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs19.existsSync(base)) return base;
6746
6735
  for (const ext of [".ts", ".js"]) {
6747
- if (fs20.existsSync(base + ext)) return base + ext;
6736
+ if (fs19.existsSync(base + ext)) return base + ext;
6748
6737
  }
6749
6738
  for (const indexExt of ["/index.ts", "/index.js"]) {
6750
- if (fs20.existsSync(base + indexExt)) return base + indexExt;
6739
+ if (fs19.existsSync(base + indexExt)) return base + indexExt;
6751
6740
  }
6752
6741
  return null;
6753
6742
  }
6754
6743
  function mirrorProductPath(sourcePath, baseDir, distDir) {
6755
- let rel = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
6744
+ let rel = path23.relative(baseDir, sourcePath).replace(/\\/g, "/");
6756
6745
  if (rel.startsWith("src/")) rel = rel.slice(4);
6757
- return path24.resolve(distDir, rel.replace(TS_EXTS, ".js"));
6746
+ return path23.resolve(distDir, rel.replace(TS_EXTS, ".js"));
6758
6747
  }
6759
6748
  async function importPluginModule(specifier, baseDir, dist) {
6760
6749
  const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
6761
- if (!isRelative && !path24.isAbsolute(specifier)) {
6750
+ if (!isRelative && !path23.isAbsolute(specifier)) {
6762
6751
  return import(specifier);
6763
6752
  }
6764
- const distDir = dist ? path24.resolve(baseDir, dist) : null;
6753
+ const distDir = dist ? path23.resolve(baseDir, dist) : null;
6765
6754
  const sourcePath = resolveLocalPluginSource(specifier, baseDir);
6766
6755
  const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
6767
- if (productPath !== null && fs20.existsSync(productPath) && (sourcePath === null || isProductFresh(sourcePath, productPath))) {
6756
+ if (productPath !== null && fs19.existsSync(productPath) && (sourcePath === null || isProductFresh(sourcePath, productPath))) {
6768
6757
  return import(pathToFileURL3(productPath).href);
6769
6758
  }
6770
6759
  if (sourcePath && TS_EXTS.test(sourcePath)) {
@@ -6773,13 +6762,13 @@ async function importPluginModule(specifier, baseDir, dist) {
6773
6762
  `Local plugin "${specifier}" has no up-to-date build artifact (dist is stale or missing). Run "faapi build" first, or use "faapi dev" for on-demand compilation.`
6774
6763
  );
6775
6764
  }
6776
- const relFromRoot = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
6765
+ const relFromRoot = path23.relative(baseDir, sourcePath).replace(/\\/g, "/");
6777
6766
  if (relFromRoot.startsWith("src/")) {
6778
6767
  await ensureCompiled(sourcePath, baseDir, dist);
6779
6768
  } else {
6780
6769
  await compileProjectModules([sourcePath], baseDir, dist);
6781
6770
  }
6782
- if (productPath && fs20.existsSync(productPath)) {
6771
+ if (productPath && fs19.existsSync(productPath)) {
6783
6772
  return import(pathToFileURL3(productPath).href);
6784
6773
  }
6785
6774
  }
@@ -6791,7 +6780,7 @@ async function importPluginModule(specifier, baseDir, dist) {
6791
6780
  `${specifier}/index.ts`,
6792
6781
  `${specifier}.js`,
6793
6782
  `${specifier}/index.js`
6794
- ].map((c) => path24.isAbsolute(c) ? c : path24.join(baseDir, c));
6783
+ ].map((c) => path23.isAbsolute(c) ? c : path23.join(baseDir, c));
6795
6784
  throw new Error(
6796
6785
  `Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
6797
6786
  ${candidates.join("\n ")}
@@ -6816,11 +6805,11 @@ function resolveDeclaration(decl) {
6816
6805
  }
6817
6806
 
6818
6807
  // src/cli/manifestLoader.ts
6819
- import fs21 from "fs";
6820
- import path27 from "path";
6808
+ import fs20 from "fs";
6809
+ import path26 from "path";
6821
6810
 
6822
6811
  // src/cli/generateAgentArtifacts.ts
6823
- import path25 from "path";
6812
+ import path24 from "path";
6824
6813
 
6825
6814
  // src/ast/extractAgentMetadata.ts
6826
6815
  import ts11 from "typescript";
@@ -6858,6 +6847,14 @@ function extractAgentMetadata(program, filePath, pathMeta) {
6858
6847
  const jsDoc = getJSDocFromNode(configFound.jsDocOwner);
6859
6848
  const description = extractDescription(jsDoc);
6860
6849
  const agentNameOverride = extractJSDocTagValue(jsDoc, "agent");
6850
+ if (agentNameOverride !== void 0 && !LLM_TOOL_NAME_PATTERN.test(agentNameOverride)) {
6851
+ throw SchemaExtractionError.at(
6852
+ configFound.jsDocOwner,
6853
+ "@agent",
6854
+ `\u8986\u76D6\u540D "${agentNameOverride}" \u542B\u975E\u6CD5\u5B57\u7B26\u2014\u2014\u987B\u6EE1\u8DB3 ${LLM_TOOL_NAME_PATTERN}\uFF08\u8986\u76D6\u540D\u6210\u4E3A LLM \u5DE5\u5177\u540D "agent-<\u8986\u76D6\u540D>"\uFF0C\u5F3A\u6821\u9A8C\u4E0A\u6E38\u5BF9\u975E\u6CD5\u5B57\u7B26\u6574\u5355 400\uFF09`,
6855
+ sourceFile
6856
+ );
6857
+ }
6861
6858
  const { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(objectLiteral, sourceFile);
6862
6859
  return {
6863
6860
  name: agentNameOverride ?? pathMeta.name,
@@ -7137,9 +7134,9 @@ function validateAgentList(metadata) {
7137
7134
  }
7138
7135
  async function generateAgentArtifacts(agents, rootDir, dist) {
7139
7136
  const metadata = [];
7140
- const programByFile = createPrograms(agents.map((m) => path25.resolve(rootDir, m.filePath)));
7137
+ const programByFile = createPrograms(agents.map((m) => path24.resolve(rootDir, m.filePath)));
7141
7138
  for (const manifest of agents) {
7142
- const absPath = path25.resolve(rootDir, manifest.filePath);
7139
+ const absPath = path24.resolve(rootDir, manifest.filePath);
7143
7140
  const program = programByFile.get(absPath);
7144
7141
  const result = extractAgentMetadata(program, absPath, {
7145
7142
  name: manifest.name,
@@ -7154,14 +7151,14 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
7154
7151
  }
7155
7152
  validateAgentList(metadata);
7156
7153
  const serialized = serializeAgents(metadata, dist);
7157
- const agentsPath = path25.resolve(rootDir, dist, AGENTS_FILE);
7154
+ const agentsPath = path24.resolve(rootDir, dist, AGENTS_FILE);
7158
7155
  await writeAgentsModule(serialized, agentsPath);
7159
7156
  return metadata;
7160
7157
  }
7161
7158
 
7162
7159
  // src/cli/generateTaskArtifacts.ts
7163
7160
  init_generateZodArtifacts();
7164
- import path26 from "path";
7161
+ import path25 from "path";
7165
7162
  init_createProgram();
7166
7163
  init_atomicWrite();
7167
7164
  init_extractHandlerTypes();
@@ -7199,7 +7196,7 @@ function collectTaskSchemaSources(tasks, rootDir) {
7199
7196
  const tasksByFile = /* @__PURE__ */ new Map();
7200
7197
  for (const task of tasks) {
7201
7198
  if (!task.inputTypeName) continue;
7202
- const absPath = path26.resolve(rootDir, task.filePath);
7199
+ const absPath = path25.resolve(rootDir, task.filePath);
7203
7200
  let list = tasksByFile.get(absPath);
7204
7201
  if (!list) {
7205
7202
  list = [];
@@ -7256,9 +7253,9 @@ function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
7256
7253
  async function generateTaskArtifacts(manifests, rootDir, dist) {
7257
7254
  const metadata = [];
7258
7255
  if (manifests.length > 0) {
7259
- const programByFile = createPrograms(manifests.map((m) => path26.resolve(rootDir, m.filePath)));
7256
+ const programByFile = createPrograms(manifests.map((m) => path25.resolve(rootDir, m.filePath)));
7260
7257
  for (const manifest of manifests) {
7261
- const absPath = path26.resolve(rootDir, manifest.filePath);
7258
+ const absPath = path25.resolve(rootDir, manifest.filePath);
7262
7259
  const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
7263
7260
  name: manifest.name,
7264
7261
  filePath: manifest.filePath
@@ -7269,7 +7266,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
7269
7266
  }
7270
7267
  }
7271
7268
  const serialized = serializeTasks(manifests, dist);
7272
- const tasksPath = path26.resolve(rootDir, dist, TASKS_FILE);
7269
+ const tasksPath = path25.resolve(rootDir, dist, TASKS_FILE);
7273
7270
  await writeTasksModule(serialized, tasksPath);
7274
7271
  if (metadata.length === 0) {
7275
7272
  return hydrateTasks(serialized);
@@ -7291,8 +7288,8 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
7291
7288
  var TOOLS_FILE2 = "faapi-tools.js";
7292
7289
  var AGENTS_FILE2 = "faapi-agents.js";
7293
7290
  async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
7294
- const toolsPath = path27.resolve(rootDir, dist, TOOLS_FILE2);
7295
- if (!fs21.existsSync(toolsPath)) {
7291
+ const toolsPath = path26.resolve(rootDir, dist, TOOLS_FILE2);
7292
+ if (!fs20.existsSync(toolsPath)) {
7296
7293
  return [];
7297
7294
  }
7298
7295
  const serialized = await importWithCacheBust(toolsPath);
@@ -7301,8 +7298,8 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
7301
7298
  return hydrated;
7302
7299
  }
7303
7300
  async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
7304
- const agentsPath = path27.resolve(rootDir, dist, AGENTS_FILE2);
7305
- if (!fs21.existsSync(agentsPath)) {
7301
+ const agentsPath = path26.resolve(rootDir, dist, AGENTS_FILE2);
7302
+ if (!fs20.existsSync(agentsPath)) {
7306
7303
  return [];
7307
7304
  }
7308
7305
  const serialized = await importWithCacheBust(agentsPath);
@@ -7317,8 +7314,8 @@ function getTaskDriverOptions(config) {
7317
7314
  return void 0;
7318
7315
  }
7319
7316
  async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
7320
- const tasksPath = path27.resolve(rootDir, dist, TASKS_FILE);
7321
- if (!fs21.existsSync(tasksPath)) {
7317
+ const tasksPath = path26.resolve(rootDir, dist, TASKS_FILE);
7318
+ if (!fs20.existsSync(tasksPath)) {
7322
7319
  return [];
7323
7320
  }
7324
7321
  const serialized = await importWithCacheBust(tasksPath);
@@ -7449,6 +7446,14 @@ function performInject(server, injectOpts) {
7449
7446
  });
7450
7447
  }
7451
7448
 
7449
+ // src/cli/copyResources.ts
7450
+ import path27 from "path";
7451
+ import fs21 from "fs";
7452
+ var RESOURCES_OUTPUT_DIR = "resources";
7453
+ function resolveResourcesDir(rootDir, dist) {
7454
+ return path27.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
7455
+ }
7456
+
7452
7457
  // src/cli/createAppCore.ts
7453
7458
  var DEFAULT_DIST = "dist";
7454
7459
  var DEFAULT_PORT = 3e3;
@@ -7580,7 +7585,6 @@ async function createAppBase(options) {
7580
7585
  config?.plugins,
7581
7586
  {
7582
7587
  rootDir,
7583
- resourcesDir,
7584
7588
  registries,
7585
7589
  routes: sorted,
7586
7590
  getRoutes: () => sorted,
@@ -7611,8 +7615,7 @@ async function createAppBase(options) {
7611
7615
  routes: sorted,
7612
7616
  server,
7613
7617
  registries,
7614
- tasks: taskQueue,
7615
- resourcesDir
7618
+ tasks: taskQueue
7616
7619
  });
7617
7620
  console.log("- onBoot hook executed");
7618
7621
  } catch (err) {
@@ -7647,8 +7650,7 @@ async function createAppBase(options) {
7647
7650
  routes: sorted,
7648
7651
  server,
7649
7652
  registries,
7650
- tasks: taskQueue,
7651
- resourcesDir
7653
+ tasks: taskQueue
7652
7654
  });
7653
7655
  console.log("- onReady hook executed");
7654
7656
  }
@@ -7672,8 +7674,7 @@ async function createAppBase(options) {
7672
7674
  routes: sorted,
7673
7675
  server,
7674
7676
  registries,
7675
- tasks: taskQueue,
7676
- resourcesDir
7677
+ tasks: taskQueue
7677
7678
  });
7678
7679
  }
7679
7680
  registries.tool.clear();
@@ -7926,11 +7927,20 @@ function extractToolExportsFromSource(source) {
7926
7927
  }
7927
7928
  return names;
7928
7929
  }
7930
+ var TOOL_DIR_SEGMENT_PATTERN = /^[a-zA-Z0-9-]+$/;
7929
7931
  function extractNamespaceFromRelPath(relPath) {
7930
7932
  const lastSlash = relPath.lastIndexOf("/");
7931
7933
  const dirPath = lastSlash === -1 ? "" : relPath.slice(0, lastSlash);
7932
7934
  if (!dirPath) return "";
7933
- return dirPath.split("/").join(".");
7935
+ const segments = dirPath.split("/");
7936
+ for (const segment of segments) {
7937
+ if (!TOOL_DIR_SEGMENT_PATTERN.test(segment)) {
7938
+ throw new Error(
7939
+ `Invalid tool directory segment "${segment}" in "tools/${relPath}": tool directory names allow a-z A-Z 0-9 '-' only ('_' is reserved as the nesting separator, '.' is not allowed \u2014 tool names are sent to LLMs as function.name) \u2014 rename the directory`
7940
+ );
7941
+ }
7942
+ }
7943
+ return segments.join("_");
7934
7944
  }
7935
7945
  function filePathToToolNamespace(filePath) {
7936
7946
  const normalized = filePath.replace(/\\/g, "/");
@@ -7941,7 +7951,13 @@ function filePathToToolNamespace(filePath) {
7941
7951
  return "";
7942
7952
  }
7943
7953
  function buildToolName(namespace, functionName) {
7944
- return namespace ? `${namespace}.${functionName}` : functionName;
7954
+ const name = namespace ? `${namespace}_${functionName}` : functionName;
7955
+ if (!LLM_TOOL_NAME_PATTERN.test(name)) {
7956
+ throw new Error(
7957
+ `Tool name "${name}" (function "${functionName}"${namespace ? ` in namespace "${namespace}"` : ""}) violates the LLM tool name pattern ${LLM_TOOL_NAME_PATTERN} \u2014 rename the function or use a @tool JSDoc override (allowed: a-z A-Z 0-9 '-' '_')`
7958
+ );
7959
+ }
7960
+ return name;
7945
7961
  }
7946
7962
  async function scanTools(rootDir, patterns) {
7947
7963
  const files = await fg4(patterns, {
@@ -7983,6 +7999,7 @@ async function scanTools(rootDir, patterns) {
7983
7999
  // src/agents/scanAgents.ts
7984
8000
  import fg5 from "fast-glob";
7985
8001
  var DEFAULT_AGENT_PATTERNS = ["src/agents/**/handler.ts"];
8002
+ var AGENT_DIR_SEGMENT_PATTERN = /^[a-zA-Z0-9-]+$/;
7986
8003
  function extractAgentNameFromPath(filePath) {
7987
8004
  const normalized = filePath.replace(/\\/g, "/");
7988
8005
  const match = normalized.match(/(?:^|\/)agents\/(.+)\/handler\.ts$/);
@@ -7991,7 +8008,15 @@ function extractAgentNameFromPath(filePath) {
7991
8008
  `Not an agent path: "${filePath}". Expected pattern: src/agents/<name>/handler.ts`
7992
8009
  );
7993
8010
  }
7994
- return match[1].replace(/\//g, ".");
8011
+ const segments = match[1].split("/");
8012
+ for (const segment of segments) {
8013
+ if (!AGENT_DIR_SEGMENT_PATTERN.test(segment)) {
8014
+ throw new Error(
8015
+ `Invalid agent directory segment "${segment}" in "${filePath}": agent directory names allow a-z A-Z 0-9 '-' only ('_' is reserved as the nesting separator, '.' is not allowed \u2014 agent names become LLM tool names "agent-<name>") \u2014 rename the directory`
8016
+ );
8017
+ }
8018
+ }
8019
+ return segments.join("_");
7995
8020
  }
7996
8021
  async function scanAgents(rootDir, patterns) {
7997
8022
  const files = await fg5(patterns, {
@@ -8107,9 +8132,11 @@ async function createProdApp(options) {
8107
8132
  export {
8108
8133
  FaapiError,
8109
8134
  InternalError,
8135
+ LLM_TOOL_NAME_PATTERN,
8110
8136
  MethodNotAllowedError,
8111
8137
  ModuleLoadError,
8112
8138
  RouteNotFoundError,
8139
+ SUB_AGENT_TOOL_PREFIX,
8113
8140
  SchemaExtractionError,
8114
8141
  TASK_PATTERNS,
8115
8142
  ValidationError,
@@ -8154,6 +8181,7 @@ export {
8154
8181
  resolveSubAgents,
8155
8182
  resolveTypeNode,
8156
8183
  scanTasks,
8184
+ subAgentToolName,
8157
8185
  upsertSkill
8158
8186
  };
8159
8187
  //# sourceMappingURL=index.js.map