@faapi/faapi 6.28.0 → 6.30.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.d.ts CHANGED
@@ -480,15 +480,6 @@ interface AgentConfig {
480
480
  * 详见 `@faapi/agent` 的 [trace](../../agent/src/trace.md) 文档。
481
481
  */
482
482
  enableTracing?: boolean;
483
- /**
484
- * 执行守卫(authHooks,见 @faapi/agent 的 authHooks 文档)
485
- *
486
- * 每次 tool / sub-agent 执行前调用(`agent.x` 名称为 sub-agent 递归)。
487
- * 三种返回:`void` 放行;`{ error }` 拒绝(不执行,error 回传 LLM 调整策略);
488
- * `{ args }` 改写后放行(多租户场景强制注入可信值,不信 LLM 传入的标识参数)。
489
- *
490
- * 典型用法:中间件解析 `ctx.workspace` 后在此校验/强制改写 `args.workspaceId`。
491
- */
492
483
  /**
493
484
  * 发送给 LLM 的历史 token 预算(近似估算,未设置 = 不裁剪)
494
485
  *
@@ -498,7 +489,20 @@ interface AgentConfig {
498
489
  * reactLoop 文档历史裁剪章节。
499
490
  */
500
491
  maxHistoryTokens?: number;
501
- beforeToolCall?: (name: string, args: Record<string, unknown>, ctx: FaapiContext | undefined) => void | {
492
+ /**
493
+ * 执行守卫(authHooks,见 @faapi/agent 的 authHooks 文档)
494
+ *
495
+ * 每次 tool / sub-agent 执行前调用(`agent-x` 派发名称为 sub-agent 递归)。
496
+ * 三种返回:`void` 放行;`{ error }` 拒绝(不执行,error 回传 LLM 调整策略);
497
+ * `{ args }` 改写后放行(多租户场景强制注入可信值,不信 LLM 传入的标识参数)。
498
+ *
499
+ * ctx 为请求上下文透传(`Partial<FaapiContext>`,框架零读取):HTTP 请求是完整
500
+ * ctx,任务内组装 Agent 时业务方显式传窄对象(如鉴权硬闸需要的
501
+ * `{ currentUserId }`),编程式直调为 undefined。
502
+ *
503
+ * 典型用法:中间件解析 `ctx.workspace` 后在此校验/强制改写 `args.workspaceId`。
504
+ */
505
+ beforeToolCall?: (name: string, args: Record<string, unknown>, ctx: Partial<FaapiContext> | undefined) => void | {
502
506
  error: string;
503
507
  } | {
504
508
  args: Record<string, unknown>;
@@ -507,7 +511,7 @@ interface AgentConfig {
507
511
  * 审计钩子(authHooks):tool / sub-agent 成功返回后调用,返回值忽略。
508
512
  * 用于日志/审计/计量;异常路径不调用。
509
513
  */
510
- afterToolCall?: (name: string, args: Record<string, unknown>, result: unknown, ctx: FaapiContext | undefined) => void;
514
+ afterToolCall?: (name: string, args: Record<string, unknown>, result: unknown, ctx: Partial<FaapiContext> | undefined) => void;
511
515
  /**
512
516
  * 可见性过滤(authHooks):LLM 可见 tools 清单组装完成后调用,
513
517
  * 返回过滤后的数组(含 agent-as-tool 项)。每次 agent.run / stream 生效——
@@ -523,7 +527,7 @@ interface AgentConfig {
523
527
  description?: string;
524
528
  parameters?: Record<string, unknown>;
525
529
  };
526
- }>, ctx: FaapiContext | undefined) => Array<{
530
+ }>, ctx: Partial<FaapiContext> | undefined) => Array<{
527
531
  type: 'function';
528
532
  function: {
529
533
  name: string;
@@ -1684,14 +1688,6 @@ interface AppBase {
1684
1688
  * 业务方定位任意产物文件时与 rootDir 配合使用。
1685
1689
  */
1686
1690
  dist: string;
1687
- /**
1688
- * 运行时资源根目录绝对路径(<rootDir>/<dist>/resources)
1689
- *
1690
- * `src/resources/` 经 dev/build 复制进产物后的位置,业务方
1691
- * `path.join(app.resourcesDir, 'prompts/foo.md')` 后自行读取。
1692
- * 源码无 `src/resources/` 目录时路径仍指向约定位置(读文件由业务方容错)。
1693
- */
1694
- resourcesDir: string;
1695
1691
  /** 任务队列客户端(入队/查询;app 实例级,close 时随队列停机) */
1696
1692
  tasks: TaskClient;
1697
1693
  /** 启动 HTTP server,打印路由表,执行 onReady 钩子 */
package/dist/index.js CHANGED
@@ -2864,6 +2864,34 @@ var CONCURRENCY_RE = new RegExp(`(?:^|\\n)\\s*concurrency:\\s*${NUM_LITERAL}`);
2864
2864
  var RETRIES_RE = new RegExp(`(?:^|\\n)\\s*retries:\\s*${NUM_LITERAL}`);
2865
2865
  var TIMEOUT_MS_RE = new RegExp(`(?:^|\\n)\\s*timeoutMs:\\s*${NUM_LITERAL}`);
2866
2866
  var GRACE_MS_RE = new RegExp(`(?:^|\\n)\\s*graceMs:\\s*${NUM_LITERAL}`);
2867
+ var NUMERIC_META_FIELDS = ["concurrency", "retries", "timeoutMs", "graceMs"];
2868
+ var STRING_META_FIELDS = ["cron"];
2869
+ var ALL_META_FIELDS = [...NUMERIC_META_FIELDS, ...STRING_META_FIELDS];
2870
+ function detectIgnoredMetaFields(source, strictHit) {
2871
+ const declared = /* @__PURE__ */ new Set();
2872
+ for (const line of source.split("\n")) {
2873
+ const trimmed = line.trim();
2874
+ if (trimmed.startsWith("//")) continue;
2875
+ for (const field of ALL_META_FIELDS) {
2876
+ if (new RegExp(`\\b${field}\\s*:`).test(trimmed)) declared.add(field);
2877
+ }
2878
+ }
2879
+ return ALL_META_FIELDS.filter((field) => declared.has(field) && !strictHit[field]);
2880
+ }
2881
+ function warnIgnoredMetaFields(name, fields) {
2882
+ for (const field of fields) {
2883
+ if (STRING_META_FIELDS.includes(field)) {
2884
+ console.warn(
2885
+ `[faapi] Task "${name}" declares "${field}" but its value is not a string literal \u2014 the declaration was ignored and the task will not be cron-scheduled. Meta values are extracted from source code without importing it, so only literal values are recognized: use a quoted literal (cron: '0 3 * * *'), not an expression or a dynamic value.`
2886
+ );
2887
+ } else {
2888
+ const consequence = field === "timeoutMs" ? " and the task will run in-process with no timeout" : "";
2889
+ console.warn(
2890
+ `[faapi] Task "${name}" declares "${field}" but its value is not a numeric literal \u2014 the declaration was ignored${consequence}. Meta values are extracted from source code without importing it, so only literal values are recognized (underscores allowed, e.g. 1_800_000); expressions like 30 * 60_000 or dynamic values are not supported.`
2891
+ );
2892
+ }
2893
+ }
2894
+ }
2867
2895
  function parseNumericLiteral(raw) {
2868
2896
  return Number(raw.replace(/_/g, ""));
2869
2897
  }
@@ -2925,6 +2953,14 @@ async function scanTasks(rootDir, patterns) {
2925
2953
  manifest.timeoutMs = value;
2926
2954
  }
2927
2955
  if (graceMs !== void 0) manifest.graceMs = parseNumericLiteral(graceMs);
2956
+ const strictHit = {
2957
+ cron: cron !== void 0,
2958
+ concurrency: concurrency !== void 0,
2959
+ retries: retries !== void 0,
2960
+ timeoutMs: timeoutMs !== void 0,
2961
+ graceMs: graceMs !== void 0
2962
+ };
2963
+ warnIgnoredMetaFields(name, detectIgnoredMetaFields(source, strictHit));
2928
2964
  tasks.push(manifest);
2929
2965
  }
2930
2966
  return tasks.sort((a, b) => a.name.localeCompare(b.name));
@@ -7603,7 +7639,6 @@ async function createAppBase(options) {
7603
7639
  wsRoutes,
7604
7640
  rootDir,
7605
7641
  dist,
7606
- resourcesDir,
7607
7642
  tasks: taskQueue,
7608
7643
  async listen(listenPort) {
7609
7644
  const envPort = process.env.PORT ? Number(process.env.PORT) : void 0;