@faapi/faapi 6.23.0 → 6.25.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/cli/index.js +182 -260
- package/dist/cli/index.js.map +1 -1
- package/dist/{routeTypes-CJV5M90s.d.ts → contextTypes-gYf84EXF.d.ts} +49 -223
- package/dist/index.d.ts +26 -51
- package/dist/index.js +192 -283
- package/dist/index.js.map +1 -1
- package/dist/routeTypes-DlD6nnbT.d.ts +204 -0
- package/dist/testing.d.ts +8 -2
- package/dist/testing.js +185 -168
- package/dist/testing.js.map +1 -1
- package/dist/workerEntry.d.ts +90 -0
- package/dist/workerEntry.js +166 -0
- package/dist/workerEntry.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1662,7 +1662,7 @@ var init_atomicWrite = __esm({
|
|
|
1662
1662
|
|
|
1663
1663
|
// src/cli/generateZodArtifacts.ts
|
|
1664
1664
|
import path11 from "path";
|
|
1665
|
-
import { existsSync } from "fs";
|
|
1665
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1666
1666
|
async function generateZodArtifacts(sources, options) {
|
|
1667
1667
|
const { generateFileSource, resolversByFile, rootDir, dist } = options;
|
|
1668
1668
|
if (sources.length === 0) return;
|
|
@@ -1696,7 +1696,7 @@ async function generateZodArtifacts(sources, options) {
|
|
|
1696
1696
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
1697
1697
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
1698
1698
|
const helpersPath = path11.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
1699
|
-
if (!
|
|
1699
|
+
if (!existsSync2(helpersPath)) {
|
|
1700
1700
|
await atomicWriteFile(helpersPath, generateHelpersFileSource());
|
|
1701
1701
|
}
|
|
1702
1702
|
}
|
|
@@ -2079,8 +2079,16 @@ var PayloadTooLargeError = class extends FaapiError {
|
|
|
2079
2079
|
};
|
|
2080
2080
|
|
|
2081
2081
|
// src/task/taskWorker.ts
|
|
2082
|
+
import { existsSync } from "fs";
|
|
2082
2083
|
import { Worker } from "worker_threads";
|
|
2083
|
-
import { pathToFileURL } from "url";
|
|
2084
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
2085
|
+
var workerEntryUrl;
|
|
2086
|
+
function resolveWorkerEntryUrl() {
|
|
2087
|
+
if (workerEntryUrl) return workerEntryUrl;
|
|
2088
|
+
const js = new URL("./workerEntry.js", import.meta.url);
|
|
2089
|
+
workerEntryUrl = existsSync(fileURLToPath(js)) ? js : new URL("./workerEntry.ts", import.meta.url);
|
|
2090
|
+
return workerEntryUrl;
|
|
2091
|
+
}
|
|
2084
2092
|
var KILL_GRACE_MS = 5e3;
|
|
2085
2093
|
var TaskCancelledError = class extends Error {
|
|
2086
2094
|
constructor(message) {
|
|
@@ -2101,153 +2109,6 @@ function safeConfig(config) {
|
|
|
2101
2109
|
return void 0;
|
|
2102
2110
|
}
|
|
2103
2111
|
}
|
|
2104
|
-
var BUILD_VIEW_SOURCE = `
|
|
2105
|
-
function buildRegistriesView(snapshot) {
|
|
2106
|
-
var agents = new Map(((snapshot && snapshot.agents) || []).map(function (a) { return [a.name, a]; }));
|
|
2107
|
-
var tools = new Map(((snapshot && snapshot.tools) || []).map(function (t) { return [t.name, t]; }));
|
|
2108
|
-
var skills = new Map(((snapshot && snapshot.skills) || []).map(function (s) { return [s.name, s]; }));
|
|
2109
|
-
return {
|
|
2110
|
-
agent: {
|
|
2111
|
-
getAgent: function (name) { return agents.get(name); },
|
|
2112
|
-
getAgentEntry: function (name) { return agents.get(name); },
|
|
2113
|
-
listAgents: function () { return Array.from(agents.values()); },
|
|
2114
|
-
asTool: function (name) {
|
|
2115
|
-
var agent = agents.get(name);
|
|
2116
|
-
if (!agent) return undefined;
|
|
2117
|
-
return {
|
|
2118
|
-
kind: 'agent',
|
|
2119
|
-
name: 'agent.' + agent.name,
|
|
2120
|
-
agentName: agent.name,
|
|
2121
|
-
description: agent.description,
|
|
2122
|
-
metadata: agent,
|
|
2123
|
-
};
|
|
2124
|
-
},
|
|
2125
|
-
resolveAgentTools: function (name) {
|
|
2126
|
-
var agent = agents.get(name);
|
|
2127
|
-
var result = new Map();
|
|
2128
|
-
if (agent && agent.tools) {
|
|
2129
|
-
agent.tools.forEach(function (toolName) {
|
|
2130
|
-
var resolved = tools.get(toolName);
|
|
2131
|
-
if (resolved) result.set(resolved.name, resolved);
|
|
2132
|
-
});
|
|
2133
|
-
}
|
|
2134
|
-
return Array.from(result.values());
|
|
2135
|
-
},
|
|
2136
|
-
resolveSubAgents: function (name) {
|
|
2137
|
-
var agent = agents.get(name);
|
|
2138
|
-
var result = [];
|
|
2139
|
-
if (agent && agent.agents) {
|
|
2140
|
-
agent.agents.forEach(function (subName) {
|
|
2141
|
-
var sub = agents.get(subName);
|
|
2142
|
-
if (sub) result.push(sub);
|
|
2143
|
-
});
|
|
2144
|
-
}
|
|
2145
|
-
return result;
|
|
2146
|
-
},
|
|
2147
|
-
},
|
|
2148
|
-
tool: {
|
|
2149
|
-
get: function (name) { return tools.get(name); },
|
|
2150
|
-
list: function () { return Array.from(tools.values()); },
|
|
2151
|
-
},
|
|
2152
|
-
skill: {
|
|
2153
|
-
get: function (name) { return skills.get(name); },
|
|
2154
|
-
list: function () { return Array.from(skills.values()); },
|
|
2155
|
-
},
|
|
2156
|
-
};
|
|
2157
|
-
}
|
|
2158
|
-
`;
|
|
2159
|
-
var SERIALIZE_ERROR_SOURCE = `
|
|
2160
|
-
function serializeError(err) {
|
|
2161
|
-
if (err instanceof Error) {
|
|
2162
|
-
var props = {};
|
|
2163
|
-
var keys = Object.keys(err);
|
|
2164
|
-
for (var i = 0; i < keys.length; i++) {
|
|
2165
|
-
props[keys[i]] = err[keys[i]];
|
|
2166
|
-
}
|
|
2167
|
-
return { name: err.name, message: err.message, stack: err.stack, props: props };
|
|
2168
|
-
}
|
|
2169
|
-
return { name: 'Error', message: String(err), stack: undefined, props: {} };
|
|
2170
|
-
}
|
|
2171
|
-
`;
|
|
2172
|
-
var BUILD_LOGGER_SOURCE = `
|
|
2173
|
-
var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
2174
|
-
function createTaskLogger(level, scope, fields) {
|
|
2175
|
-
function make(suffix) {
|
|
2176
|
-
function write(lvl, message, callFields) {
|
|
2177
|
-
if (level !== undefined && LOG_RANK[lvl] < LOG_RANK[level]) return;
|
|
2178
|
-
var entry = { level: lvl, message: message, time: new Date().toISOString() };
|
|
2179
|
-
var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
|
|
2180
|
-
if (fullScope !== undefined) entry.scope = fullScope;
|
|
2181
|
-
if (fields !== undefined || callFields !== undefined) {
|
|
2182
|
-
entry.fields = Object.assign({}, fields, callFields);
|
|
2183
|
-
}
|
|
2184
|
-
try {
|
|
2185
|
-
parentPort.postMessage({ type: 'log', entry: entry });
|
|
2186
|
-
} catch (_) {
|
|
2187
|
-
entry.fields = { warning: 'log fields not cloneable across worker boundary, dropped' };
|
|
2188
|
-
parentPort.postMessage({ type: 'log', entry: entry });
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
return {
|
|
2192
|
-
debug: function (m, f) { write('debug', m, f); },
|
|
2193
|
-
info: function (m, f) { write('info', m, f); },
|
|
2194
|
-
warn: function (m, f) { write('warn', m, f); },
|
|
2195
|
-
error: function (m, f) { write('error', m, f); },
|
|
2196
|
-
child: function (cs) { return make(suffix === undefined ? cs : suffix + ':' + cs); },
|
|
2197
|
-
};
|
|
2198
|
-
}
|
|
2199
|
-
return make(undefined);
|
|
2200
|
-
}
|
|
2201
|
-
`;
|
|
2202
|
-
function buildWrapperSource(moduleUrl) {
|
|
2203
|
-
return `
|
|
2204
|
-
import { parentPort } from 'node:worker_threads';
|
|
2205
|
-
import * as mod from '${moduleUrl}';
|
|
2206
|
-
|
|
2207
|
-
${BUILD_VIEW_SOURCE}
|
|
2208
|
-
|
|
2209
|
-
${SERIALIZE_ERROR_SOURCE}
|
|
2210
|
-
|
|
2211
|
-
${BUILD_LOGGER_SOURCE}
|
|
2212
|
-
|
|
2213
|
-
const run = mod.run;
|
|
2214
|
-
if (typeof run !== 'function') {
|
|
2215
|
-
parentPort.postMessage({
|
|
2216
|
-
type: 'error',
|
|
2217
|
-
error: { name: 'Error', message: 'Task module has no run export', stack: undefined, props: {} },
|
|
2218
|
-
});
|
|
2219
|
-
} else {
|
|
2220
|
-
let controller = null;
|
|
2221
|
-
parentPort.on('message', async (msg) => {
|
|
2222
|
-
if (msg?.type === 'abort') {
|
|
2223
|
-
controller?.abort(new Error(msg.reason));
|
|
2224
|
-
return;
|
|
2225
|
-
}
|
|
2226
|
-
if (msg?.type !== 'run') return;
|
|
2227
|
-
controller = new AbortController();
|
|
2228
|
-
const { payload, taskCtx } = msg;
|
|
2229
|
-
try {
|
|
2230
|
-
const registries = buildRegistriesView(msg.registries);
|
|
2231
|
-
const progress = (value) => parentPort.postMessage({ type: 'progress', value });
|
|
2232
|
-
const taskLog = msg.log ? createTaskLogger(msg.log.level, msg.log.scope, msg.log.fields) : undefined;
|
|
2233
|
-
const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress, log: taskLog });
|
|
2234
|
-
parentPort.postMessage({ type: 'done', result });
|
|
2235
|
-
} catch (err) {
|
|
2236
|
-
const serialized = serializeError(err);
|
|
2237
|
-
try {
|
|
2238
|
-
parentPort.postMessage({ type: 'error', error: serialized });
|
|
2239
|
-
} catch (_) {
|
|
2240
|
-
// props \u542B\u4E0D\u53EF\u514B\u9686\u503C\uFF08\u51FD\u6570\u7B49\uFF09\u65F6\u4E22\u5F03 props\uFF0C\u4FDD\u5E95 name/message/stack
|
|
2241
|
-
parentPort.postMessage({
|
|
2242
|
-
type: 'error',
|
|
2243
|
-
error: { name: serialized.name, message: serialized.message, stack: serialized.stack, props: {} },
|
|
2244
|
-
});
|
|
2245
|
-
}
|
|
2246
|
-
}
|
|
2247
|
-
});
|
|
2248
|
-
}
|
|
2249
|
-
`;
|
|
2250
|
-
}
|
|
2251
2112
|
function reviveError(payload) {
|
|
2252
2113
|
const err = new Error(payload?.message ?? "task worker error");
|
|
2253
2114
|
if (payload?.name !== void 0) err.name = payload.name;
|
|
@@ -2268,13 +2129,12 @@ async function runTaskInWorker(options) {
|
|
|
2268
2129
|
);
|
|
2269
2130
|
}
|
|
2270
2131
|
const moduleUrl = pathToFileURL(taskModulePath).href;
|
|
2271
|
-
const wrapperUrl = new URL(
|
|
2272
|
-
`data:text/javascript,${encodeURIComponent(buildWrapperSource(moduleUrl))}`
|
|
2273
|
-
);
|
|
2274
2132
|
return new Promise((resolve, reject) => {
|
|
2275
2133
|
let worker;
|
|
2276
2134
|
try {
|
|
2277
|
-
worker = new Worker(
|
|
2135
|
+
worker = new Worker(resolveWorkerEntryUrl(), {
|
|
2136
|
+
workerData: { moduleUrl, resourcesDir: taskCtx.resourcesDir }
|
|
2137
|
+
});
|
|
2278
2138
|
} catch (err) {
|
|
2279
2139
|
reject(err);
|
|
2280
2140
|
return;
|
|
@@ -2362,7 +2222,11 @@ async function runTaskInWorker(options) {
|
|
|
2362
2222
|
worker.postMessage({
|
|
2363
2223
|
type: "run",
|
|
2364
2224
|
payload,
|
|
2365
|
-
taskCtx: {
|
|
2225
|
+
taskCtx: {
|
|
2226
|
+
config: safeConfig(taskCtx.config),
|
|
2227
|
+
resourcesDir: taskCtx.resourcesDir,
|
|
2228
|
+
job: taskCtx.job
|
|
2229
|
+
},
|
|
2366
2230
|
registries: options.registries,
|
|
2367
2231
|
log: options.log
|
|
2368
2232
|
});
|
|
@@ -2712,6 +2576,7 @@ function createTaskQueue(deps) {
|
|
|
2712
2576
|
payload: job.payload,
|
|
2713
2577
|
taskCtx: {
|
|
2714
2578
|
config: deps.config,
|
|
2579
|
+
resourcesDir: deps.resourcesDir,
|
|
2715
2580
|
job: { id: job.id, name: job.name, attempt: job.attempt }
|
|
2716
2581
|
},
|
|
2717
2582
|
registries: snapshotRegistries(),
|
|
@@ -2742,6 +2607,7 @@ function createTaskQueue(deps) {
|
|
|
2742
2607
|
const taskCtx = {
|
|
2743
2608
|
signal: job.signal,
|
|
2744
2609
|
config: deps.config,
|
|
2610
|
+
resourcesDir: deps.resourcesDir,
|
|
2745
2611
|
job: { id: job.id, name: job.name, attempt: job.attempt },
|
|
2746
2612
|
registries: registriesView,
|
|
2747
2613
|
log: createLogger(`task:${job.name}`, {
|
|
@@ -2991,6 +2857,7 @@ function parseNumericLiteral(raw) {
|
|
|
2991
2857
|
return Number(raw.replace(/_/g, ""));
|
|
2992
2858
|
}
|
|
2993
2859
|
var MIN_ISOLATED_TIMEOUT_MS = 6e4;
|
|
2860
|
+
var MAX_ISOLATED_TIMEOUT_MS = 23 * 60 * 6e4;
|
|
2994
2861
|
function filePathToTaskName(filePath) {
|
|
2995
2862
|
const normalized = filePath.replace(/\\/g, "/");
|
|
2996
2863
|
const match = normalized.match(/(?:^|\/)tasks\/(.+)\/task\.ts$/);
|
|
@@ -3039,6 +2906,11 @@ async function scanTasks(rootDir, patterns) {
|
|
|
3039
2906
|
`[faapi] Task "${name}" timeoutMs ${value} is below the minimum ${MIN_ISOLATED_TIMEOUT_MS}ms (1 minute). Declaring a timeout means this is a long-running task that needs real cancellation \u2014 tasks finishing within a minute do not need one: remove timeoutMs to run in-process (implement your own deadline with Promise.race if needed), or raise it.`
|
|
3040
2907
|
);
|
|
3041
2908
|
}
|
|
2909
|
+
if (value > MAX_ISOLATED_TIMEOUT_MS) {
|
|
2910
|
+
throw new Error(
|
|
2911
|
+
`[faapi] Task "${name}" timeoutMs ${value} exceeds the maximum ${MAX_ISOLATED_TIMEOUT_MS}ms (23 hours). The pg-boss driver budgets expire_in from timeoutMs (execution budget preventing mid-run re-delivery), and pg-boss 10 asserts expire_in strictly below 24h \u2014 larger timeouts would fail at enqueue time. Split the work into a resumable pipeline (persist progress, enqueue the next stage), or use the bullmq driver (Redis has no such cap).`
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
3042
2914
|
manifest.timeoutMs = value;
|
|
3043
2915
|
}
|
|
3044
2916
|
if (graceMs !== void 0) manifest.graceMs = parseNumericLiteral(graceMs);
|
|
@@ -3086,7 +2958,7 @@ function listSkills() {
|
|
|
3086
2958
|
return defaultRegistries.skill.list();
|
|
3087
2959
|
}
|
|
3088
2960
|
|
|
3089
|
-
// src/loader/
|
|
2961
|
+
// src/loader/loadToolModule.ts
|
|
3090
2962
|
import fs12 from "fs";
|
|
3091
2963
|
|
|
3092
2964
|
// src/loader/resolveExports.ts
|
|
@@ -3737,52 +3609,13 @@ function getDevDist() {
|
|
|
3737
3609
|
return state.distDir;
|
|
3738
3610
|
}
|
|
3739
3611
|
|
|
3740
|
-
// src/loader/loadAgentModule.ts
|
|
3741
|
-
async function loadAgentModule(filePath, hasRun, rootDir) {
|
|
3742
|
-
if (isDevOnDemandEnabled() && rootDir) {
|
|
3743
|
-
const dist = getDevDist();
|
|
3744
|
-
if (dist) {
|
|
3745
|
-
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3746
|
-
if (sourcePath && fs12.existsSync(sourcePath)) {
|
|
3747
|
-
try {
|
|
3748
|
-
await ensureCompiled(sourcePath, rootDir, dist);
|
|
3749
|
-
} catch (compileErr) {
|
|
3750
|
-
const reason = compileErr instanceof Error ? compileErr.message : String(compileErr);
|
|
3751
|
-
throw new Error(`Failed to compile agent module "${sourcePath}": ${reason}`, {
|
|
3752
|
-
cause: compileErr
|
|
3753
|
-
});
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
}
|
|
3757
|
-
}
|
|
3758
|
-
let module;
|
|
3759
|
-
try {
|
|
3760
|
-
module = await importWithCacheBust(filePath, isDevOnDemandEnabled());
|
|
3761
|
-
} catch (err) {
|
|
3762
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
3763
|
-
throw new Error(`Failed to load agent module "${filePath}": ${reason}`, { cause: err });
|
|
3764
|
-
}
|
|
3765
|
-
let run;
|
|
3766
|
-
if (hasRun) {
|
|
3767
|
-
const runExport = resolveExport(module, "run");
|
|
3768
|
-
if (typeof runExport !== "function") {
|
|
3769
|
-
throw new Error(
|
|
3770
|
-
`Agent module "${filePath}" does not export a valid "run" function (hasRun=true). Expected a function, got ${runExport === void 0 ? "undefined" : typeof runExport}.`
|
|
3771
|
-
);
|
|
3772
|
-
}
|
|
3773
|
-
run = runExport;
|
|
3774
|
-
}
|
|
3775
|
-
return { run };
|
|
3776
|
-
}
|
|
3777
|
-
|
|
3778
3612
|
// src/loader/loadToolModule.ts
|
|
3779
|
-
import fs13 from "fs";
|
|
3780
3613
|
async function loadToolModule(filePath, functionName, rootDir) {
|
|
3781
3614
|
if (isDevOnDemandEnabled() && rootDir) {
|
|
3782
3615
|
const dist = getDevDist();
|
|
3783
3616
|
if (dist) {
|
|
3784
3617
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3785
|
-
if (sourcePath &&
|
|
3618
|
+
if (sourcePath && fs12.existsSync(sourcePath)) {
|
|
3786
3619
|
try {
|
|
3787
3620
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
3788
3621
|
} catch (compileErr) {
|
|
@@ -3811,7 +3644,7 @@ async function loadToolModule(filePath, functionName, rootDir) {
|
|
|
3811
3644
|
}
|
|
3812
3645
|
|
|
3813
3646
|
// src/loader/loadToolSchema.ts
|
|
3814
|
-
import { existsSync as
|
|
3647
|
+
import { existsSync as existsSync3 } from "fs";
|
|
3815
3648
|
|
|
3816
3649
|
// src/cli/generateToolArtifacts.ts
|
|
3817
3650
|
init_generateZodArtifacts();
|
|
@@ -4045,7 +3878,7 @@ async function loadToolSchema(tool, rootDir) {
|
|
|
4045
3878
|
if (!tool.inputTypeName) return void 0;
|
|
4046
3879
|
const schemaName = `${tool.inputTypeName}Schema`;
|
|
4047
3880
|
const zodPath = getToolSchemaPath(tool, rootDir);
|
|
4048
|
-
if (!
|
|
3881
|
+
if (!existsSync3(zodPath)) return void 0;
|
|
4049
3882
|
try {
|
|
4050
3883
|
const mod = await importWithCacheBust(zodPath, isDevOnDemandEnabled());
|
|
4051
3884
|
const schema = mod[`${tool.inputTypeName}Schema`];
|
|
@@ -4254,15 +4087,15 @@ function helmet(options = {}) {
|
|
|
4254
4087
|
|
|
4255
4088
|
// src/config/loadConfig.ts
|
|
4256
4089
|
import path16 from "path";
|
|
4257
|
-
import
|
|
4090
|
+
import fs13 from "fs";
|
|
4258
4091
|
var CONFIG_PRODUCT_FILE = "faapi-config.js";
|
|
4259
4092
|
async function loadConfig(rootDir, dist) {
|
|
4260
4093
|
const configProductPath = path16.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
|
|
4261
|
-
if (
|
|
4094
|
+
if (fs13.existsSync(configProductPath)) {
|
|
4262
4095
|
const module = await importWithCacheBust(configProductPath);
|
|
4263
4096
|
return module.default ?? {};
|
|
4264
4097
|
}
|
|
4265
|
-
const hasSourceConfig =
|
|
4098
|
+
const hasSourceConfig = fs13.existsSync(path16.join(rootDir, "faapi.config.ts")) || fs13.existsSync(path16.join(rootDir, "faapi.config.js"));
|
|
4266
4099
|
if (hasSourceConfig) {
|
|
4267
4100
|
throw new Error(
|
|
4268
4101
|
`[faapi] ${dist}/${CONFIG_PRODUCT_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
@@ -4272,7 +4105,7 @@ async function loadConfig(rootDir, dist) {
|
|
|
4272
4105
|
}
|
|
4273
4106
|
|
|
4274
4107
|
// src/cli/loadEnv.ts
|
|
4275
|
-
import
|
|
4108
|
+
import fs14 from "fs";
|
|
4276
4109
|
import path17 from "path";
|
|
4277
4110
|
function resolveEnv() {
|
|
4278
4111
|
return process.env.NODE_ENV || "development";
|
|
@@ -4341,8 +4174,8 @@ function loadEnv(rootDir) {
|
|
|
4341
4174
|
const merged = {};
|
|
4342
4175
|
for (const file of files) {
|
|
4343
4176
|
const filePath = path17.join(rootDir, file);
|
|
4344
|
-
if (!
|
|
4345
|
-
const content =
|
|
4177
|
+
if (!fs14.existsSync(filePath)) continue;
|
|
4178
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
4346
4179
|
const parsed = parseEnvFile(content, merged);
|
|
4347
4180
|
Object.assign(merged, parsed);
|
|
4348
4181
|
}
|
|
@@ -4353,9 +4186,53 @@ function loadEnv(rootDir) {
|
|
|
4353
4186
|
}
|
|
4354
4187
|
}
|
|
4355
4188
|
|
|
4189
|
+
// src/utils/readResource.ts
|
|
4190
|
+
import path18 from "path";
|
|
4191
|
+
import fs15 from "fs/promises";
|
|
4192
|
+
var ACTIVE_RESOURCES_DIR_KEY = /* @__PURE__ */ Symbol.for("faapi.resources.dir");
|
|
4193
|
+
function getActiveResourcesDir() {
|
|
4194
|
+
return globalThis[ACTIVE_RESOURCES_DIR_KEY] ?? null;
|
|
4195
|
+
}
|
|
4196
|
+
function setActiveResourcesDir(dir) {
|
|
4197
|
+
if (dir === null) {
|
|
4198
|
+
delete globalThis[ACTIVE_RESOURCES_DIR_KEY];
|
|
4199
|
+
} else {
|
|
4200
|
+
globalThis[ACTIVE_RESOURCES_DIR_KEY] = dir;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
function resolveResourceTarget(resourcesDir, relativePath) {
|
|
4204
|
+
if (typeof relativePath !== "string" || relativePath === "") {
|
|
4205
|
+
throw new Error("[faapi] readResource: relativePath must be a non-empty string");
|
|
4206
|
+
}
|
|
4207
|
+
const root = toRealPath(path18.resolve(resourcesDir));
|
|
4208
|
+
const resolved = path18.resolve(root, relativePath);
|
|
4209
|
+
if (!isInsideDir(resolved, root)) {
|
|
4210
|
+
throw new Error(
|
|
4211
|
+
`[faapi] readResource: "${relativePath}" escapes the resources directory (absolute paths and ".." are not allowed)`
|
|
4212
|
+
);
|
|
4213
|
+
}
|
|
4214
|
+
const realTarget = toRealPath(resolved);
|
|
4215
|
+
if (!isInsideDir(realTarget, root)) {
|
|
4216
|
+
throw new Error(
|
|
4217
|
+
`[faapi] readResource: "${relativePath}" resolves outside the resources directory via a symlink`
|
|
4218
|
+
);
|
|
4219
|
+
}
|
|
4220
|
+
return realTarget;
|
|
4221
|
+
}
|
|
4222
|
+
async function readResource(relativePath, encoding) {
|
|
4223
|
+
const resourcesDir = getActiveResourcesDir();
|
|
4224
|
+
if (!resourcesDir) {
|
|
4225
|
+
throw new Error(
|
|
4226
|
+
"[faapi] readResource: no active app in this process \u2014 resources are bound at app startup (createAppBase); testing direct-call can pass `resourcesDir` to createTestContext to bind"
|
|
4227
|
+
);
|
|
4228
|
+
}
|
|
4229
|
+
const target = resolveResourceTarget(resourcesDir, relativePath);
|
|
4230
|
+
return encoding === void 0 ? fs15.readFile(target) : fs15.readFile(target, encoding);
|
|
4231
|
+
}
|
|
4232
|
+
|
|
4356
4233
|
// src/cli/createAppCore.ts
|
|
4357
4234
|
import fs22 from "fs";
|
|
4358
|
-
import
|
|
4235
|
+
import path28 from "path";
|
|
4359
4236
|
|
|
4360
4237
|
// src/router/sortRoutes.ts
|
|
4361
4238
|
function sortRoutes(routes) {
|
|
@@ -4419,7 +4296,7 @@ import {
|
|
|
4419
4296
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
4420
4297
|
import { readFileSync } from "fs";
|
|
4421
4298
|
import { Readable as Readable2 } from "stream";
|
|
4422
|
-
import
|
|
4299
|
+
import path21 from "path";
|
|
4423
4300
|
|
|
4424
4301
|
// src/router/matchRoute.ts
|
|
4425
4302
|
var httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -5901,14 +5778,14 @@ function etag(options = {}) {
|
|
|
5901
5778
|
// src/server/handleWsUpgrade.ts
|
|
5902
5779
|
import fs17 from "fs";
|
|
5903
5780
|
import { WebSocketServer, WebSocket } from "ws";
|
|
5904
|
-
import
|
|
5781
|
+
import path20 from "path";
|
|
5905
5782
|
|
|
5906
5783
|
// src/cli/copyResources.ts
|
|
5907
|
-
import
|
|
5784
|
+
import path19 from "path";
|
|
5908
5785
|
import fs16 from "fs";
|
|
5909
5786
|
var RESOURCES_OUTPUT_DIR = "resources";
|
|
5910
5787
|
function resolveResourcesDir(rootDir, dist) {
|
|
5911
|
-
return
|
|
5788
|
+
return path19.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
|
|
5912
5789
|
}
|
|
5913
5790
|
|
|
5914
5791
|
// src/server/serverUtils.ts
|
|
@@ -6230,7 +6107,7 @@ function attachWebSocket(options) {
|
|
|
6230
6107
|
}
|
|
6231
6108
|
let handlers;
|
|
6232
6109
|
try {
|
|
6233
|
-
const absoluteFilePath =
|
|
6110
|
+
const absoluteFilePath = path20.resolve(rootDir, route.filePath);
|
|
6234
6111
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
6235
6112
|
} catch (err) {
|
|
6236
6113
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -6493,7 +6370,7 @@ function getRoutePaths(route, rootDir, dist) {
|
|
|
6493
6370
|
let cached = routePathCache.get(route);
|
|
6494
6371
|
if (!cached) {
|
|
6495
6372
|
cached = {
|
|
6496
|
-
absFilePath:
|
|
6373
|
+
absFilePath: path21.resolve(rootDir, route.filePath),
|
|
6497
6374
|
schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
|
|
6498
6375
|
};
|
|
6499
6376
|
routePathCache.set(route, cached);
|
|
@@ -6714,7 +6591,7 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
6714
6591
|
|
|
6715
6592
|
// src/cli/generateRoutes.ts
|
|
6716
6593
|
import fs18 from "fs";
|
|
6717
|
-
import
|
|
6594
|
+
import path22 from "path";
|
|
6718
6595
|
async function hydrateRoutes(manifest) {
|
|
6719
6596
|
const hydrateRoute = (serialized) => ({
|
|
6720
6597
|
method: serialized.method,
|
|
@@ -6758,18 +6635,18 @@ function createIdleTaskDriver() {
|
|
|
6758
6635
|
}
|
|
6759
6636
|
|
|
6760
6637
|
// src/cli/loadPlugins.ts
|
|
6761
|
-
import
|
|
6638
|
+
import path24 from "path";
|
|
6762
6639
|
import fs20 from "fs";
|
|
6763
6640
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
6764
6641
|
|
|
6765
6642
|
// src/cli/compileConfig.ts
|
|
6766
|
-
import
|
|
6643
|
+
import path23 from "path";
|
|
6767
6644
|
import fs19 from "fs";
|
|
6768
6645
|
async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
6769
6646
|
const { insideFiles, outsideFiles } = await collectRelativeImports(entryPoints, rootDir);
|
|
6770
6647
|
const esbuild = await import("esbuild");
|
|
6771
6648
|
const aliasPlugins = buildAliasPlugins(rootDir);
|
|
6772
|
-
const absDist =
|
|
6649
|
+
const absDist = path23.resolve(rootDir, dist);
|
|
6773
6650
|
await esbuild.build({
|
|
6774
6651
|
entryPoints: [...entryPoints, ...outsideFiles],
|
|
6775
6652
|
outdir: absDist,
|
|
@@ -6783,7 +6660,7 @@ async function compileProjectModules(entryPoints, rootDir, dist) {
|
|
|
6783
6660
|
logLevel: "silent"
|
|
6784
6661
|
});
|
|
6785
6662
|
if (insideFiles.length > 0) {
|
|
6786
|
-
const appOutbase =
|
|
6663
|
+
const appOutbase = path23.resolve(rootDir, "src");
|
|
6787
6664
|
await esbuild.build({
|
|
6788
6665
|
entryPoints: insideFiles,
|
|
6789
6666
|
outdir: absDist,
|
|
@@ -6864,7 +6741,7 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
|
|
|
6864
6741
|
var TS_EXTS = /\.(ts|tsx|mts|cts)$/;
|
|
6865
6742
|
var JS_EXTS = /\.(js|mjs|cjs|jsx)$/;
|
|
6866
6743
|
function resolveLocalPluginSource(specifier, baseDir) {
|
|
6867
|
-
const base =
|
|
6744
|
+
const base = path24.isAbsolute(specifier) ? specifier : path24.resolve(baseDir, specifier);
|
|
6868
6745
|
if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs20.existsSync(base)) return base;
|
|
6869
6746
|
for (const ext of [".ts", ".js"]) {
|
|
6870
6747
|
if (fs20.existsSync(base + ext)) return base + ext;
|
|
@@ -6875,16 +6752,16 @@ function resolveLocalPluginSource(specifier, baseDir) {
|
|
|
6875
6752
|
return null;
|
|
6876
6753
|
}
|
|
6877
6754
|
function mirrorProductPath(sourcePath, baseDir, distDir) {
|
|
6878
|
-
let rel =
|
|
6755
|
+
let rel = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
6879
6756
|
if (rel.startsWith("src/")) rel = rel.slice(4);
|
|
6880
|
-
return
|
|
6757
|
+
return path24.resolve(distDir, rel.replace(TS_EXTS, ".js"));
|
|
6881
6758
|
}
|
|
6882
6759
|
async function importPluginModule(specifier, baseDir, dist) {
|
|
6883
6760
|
const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
|
|
6884
|
-
if (!isRelative && !
|
|
6761
|
+
if (!isRelative && !path24.isAbsolute(specifier)) {
|
|
6885
6762
|
return import(specifier);
|
|
6886
6763
|
}
|
|
6887
|
-
const distDir = dist ?
|
|
6764
|
+
const distDir = dist ? path24.resolve(baseDir, dist) : null;
|
|
6888
6765
|
const sourcePath = resolveLocalPluginSource(specifier, baseDir);
|
|
6889
6766
|
const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
|
|
6890
6767
|
if (productPath !== null && fs20.existsSync(productPath) && (sourcePath === null || isProductFresh(sourcePath, productPath))) {
|
|
@@ -6896,7 +6773,7 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
6896
6773
|
`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.`
|
|
6897
6774
|
);
|
|
6898
6775
|
}
|
|
6899
|
-
const relFromRoot =
|
|
6776
|
+
const relFromRoot = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
|
|
6900
6777
|
if (relFromRoot.startsWith("src/")) {
|
|
6901
6778
|
await ensureCompiled(sourcePath, baseDir, dist);
|
|
6902
6779
|
} else {
|
|
@@ -6914,7 +6791,7 @@ async function importPluginModule(specifier, baseDir, dist) {
|
|
|
6914
6791
|
`${specifier}/index.ts`,
|
|
6915
6792
|
`${specifier}.js`,
|
|
6916
6793
|
`${specifier}/index.js`
|
|
6917
|
-
].map((c) =>
|
|
6794
|
+
].map((c) => path24.isAbsolute(c) ? c : path24.join(baseDir, c));
|
|
6918
6795
|
throw new Error(
|
|
6919
6796
|
`Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
|
|
6920
6797
|
${candidates.join("\n ")}
|
|
@@ -6940,10 +6817,10 @@ function resolveDeclaration(decl) {
|
|
|
6940
6817
|
|
|
6941
6818
|
// src/cli/manifestLoader.ts
|
|
6942
6819
|
import fs21 from "fs";
|
|
6943
|
-
import
|
|
6820
|
+
import path27 from "path";
|
|
6944
6821
|
|
|
6945
6822
|
// src/cli/generateAgentArtifacts.ts
|
|
6946
|
-
import
|
|
6823
|
+
import path25 from "path";
|
|
6947
6824
|
|
|
6948
6825
|
// src/ast/extractAgentMetadata.ts
|
|
6949
6826
|
import ts11 from "typescript";
|
|
@@ -6951,12 +6828,21 @@ init_resolveTypeNode();
|
|
|
6951
6828
|
function extractAgentMetadata(program, filePath, pathMeta) {
|
|
6952
6829
|
const sourceFile = program.getSourceFile(filePath);
|
|
6953
6830
|
if (!sourceFile) return null;
|
|
6831
|
+
const runOwner = findRunExportOwner(sourceFile);
|
|
6832
|
+
if (runOwner) {
|
|
6833
|
+
throw SchemaExtractionError.at(
|
|
6834
|
+
runOwner,
|
|
6835
|
+
"run",
|
|
6836
|
+
"agent \u81EA\u5B9A\u4E49 run \u5DF2\u79FB\u9664\u2014\u2014agent \u7EDF\u4E00\u4E3A\u58F0\u660E\u5F0F\u6267\u884C\uFF08config + \u9ED8\u8BA4 reactLoop\uFF09\u3002\u7F16\u6392\u573A\u666F\u8BF7\u6CE8\u518C tool\uFF08src/tools/ \u4E0B\u5BFC\u51FA\u51FD\u6570\uFF0C\u6709 schema/trace/\u9274\u6743\u94A9\u5B50\uFF09\uFF0C\u591A agent \u534F\u4F5C\u7528 config.agents \u58F0\u660E sub-agent",
|
|
6837
|
+
sourceFile
|
|
6838
|
+
);
|
|
6839
|
+
}
|
|
6954
6840
|
const configFound = findConfigExport(sourceFile);
|
|
6955
6841
|
if (!configFound) {
|
|
6956
6842
|
throw SchemaExtractionError.at(
|
|
6957
6843
|
sourceFile,
|
|
6958
6844
|
"config.systemPrompt",
|
|
6959
|
-
"agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E\
|
|
6845
|
+
"agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E systemPrompt\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09\u6216 systemPromptFile\uFF08\u76F8\u5BF9 resources \u76EE\u5F55\u7684\u8DEF\u5F84\u5B57\u9762\u91CF\uFF09\u4E8C\u9009\u4E00",
|
|
6960
6846
|
sourceFile
|
|
6961
6847
|
);
|
|
6962
6848
|
}
|
|
@@ -6972,16 +6858,13 @@ function extractAgentMetadata(program, filePath, pathMeta) {
|
|
|
6972
6858
|
const jsDoc = getJSDocFromNode(configFound.jsDocOwner);
|
|
6973
6859
|
const description = extractDescription(jsDoc);
|
|
6974
6860
|
const agentNameOverride = extractJSDocTagValue(jsDoc, "agent");
|
|
6975
|
-
const { systemPrompt, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(
|
|
6976
|
-
objectLiteral,
|
|
6977
|
-
sourceFile
|
|
6978
|
-
);
|
|
6861
|
+
const { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(objectLiteral, sourceFile);
|
|
6979
6862
|
return {
|
|
6980
6863
|
name: agentNameOverride ?? pathMeta.name,
|
|
6981
6864
|
description,
|
|
6982
6865
|
filePath: pathMeta.filePath,
|
|
6983
|
-
hasRun: pathMeta.hasRun,
|
|
6984
6866
|
systemPrompt,
|
|
6867
|
+
systemPromptFile,
|
|
6985
6868
|
tools,
|
|
6986
6869
|
agents,
|
|
6987
6870
|
model,
|
|
@@ -6989,6 +6872,25 @@ function extractAgentMetadata(program, filePath, pathMeta) {
|
|
|
6989
6872
|
inputDescription
|
|
6990
6873
|
};
|
|
6991
6874
|
}
|
|
6875
|
+
function findRunExportOwner(sourceFile) {
|
|
6876
|
+
let result = null;
|
|
6877
|
+
ts11.forEachChild(sourceFile, (node) => {
|
|
6878
|
+
if (result) return;
|
|
6879
|
+
if (ts11.isFunctionDeclaration(node) && hasExportModifier(node) && node.name?.text === "run") {
|
|
6880
|
+
result = node;
|
|
6881
|
+
return;
|
|
6882
|
+
}
|
|
6883
|
+
if (ts11.isVariableStatement(node) && hasExportModifier(node)) {
|
|
6884
|
+
for (const decl of node.declarationList.declarations) {
|
|
6885
|
+
if (ts11.isIdentifier(decl.name) && decl.name.text === "run") {
|
|
6886
|
+
result = node;
|
|
6887
|
+
return;
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
6890
|
+
}
|
|
6891
|
+
});
|
|
6892
|
+
return result;
|
|
6893
|
+
}
|
|
6992
6894
|
function findConfigExport(sourceFile) {
|
|
6993
6895
|
let result = null;
|
|
6994
6896
|
ts11.forEachChild(sourceFile, (node) => {
|
|
@@ -7031,6 +6933,7 @@ function getReturnObjectLiteral(fn) {
|
|
|
7031
6933
|
}
|
|
7032
6934
|
function extractConfigFields(objLit, sourceFile) {
|
|
7033
6935
|
let systemPrompt;
|
|
6936
|
+
let systemPromptFile;
|
|
7034
6937
|
let tools;
|
|
7035
6938
|
let agents;
|
|
7036
6939
|
let model;
|
|
@@ -7054,6 +6957,9 @@ function extractConfigFields(objLit, sourceFile) {
|
|
|
7054
6957
|
case "systemPrompt":
|
|
7055
6958
|
systemPrompt = requireStringValue(prop, "systemPrompt", sourceFile);
|
|
7056
6959
|
break;
|
|
6960
|
+
case "systemPromptFile":
|
|
6961
|
+
systemPromptFile = requireStringValue(prop, "systemPromptFile", sourceFile);
|
|
6962
|
+
break;
|
|
7057
6963
|
case "tools":
|
|
7058
6964
|
tools = requireStringArrayValue(prop, "tools", sourceFile);
|
|
7059
6965
|
break;
|
|
@@ -7073,20 +6979,28 @@ function extractConfigFields(objLit, sourceFile) {
|
|
|
7073
6979
|
throw SchemaExtractionError.at(
|
|
7074
6980
|
prop,
|
|
7075
6981
|
`config.${propName}`,
|
|
7076
|
-
"\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / tools / agents / model / maxTurns / inputDescription",
|
|
6982
|
+
"\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / systemPromptFile / tools / agents / model / maxTurns / inputDescription",
|
|
7077
6983
|
sourceFile
|
|
7078
6984
|
);
|
|
7079
6985
|
}
|
|
7080
6986
|
}
|
|
7081
|
-
if (systemPrompt
|
|
6987
|
+
if (systemPrompt !== void 0 && systemPromptFile !== void 0) {
|
|
7082
6988
|
throw SchemaExtractionError.at(
|
|
7083
6989
|
objLit,
|
|
7084
6990
|
"config.systemPrompt",
|
|
7085
|
-
"
|
|
6991
|
+
"systemPrompt \u4E0E systemPromptFile \u4E92\u65A5\u2014\u2014\u5185\u8054\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E0E resources \u6587\u4EF6\u4E8C\u9009\u4E00",
|
|
7086
6992
|
sourceFile
|
|
7087
6993
|
);
|
|
7088
6994
|
}
|
|
7089
|
-
|
|
6995
|
+
if (systemPrompt === void 0 && systemPromptFile === void 0) {
|
|
6996
|
+
throw SchemaExtractionError.at(
|
|
6997
|
+
objLit,
|
|
6998
|
+
"config.systemPrompt",
|
|
6999
|
+
"agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E systemPrompt\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09\u6216 systemPromptFile\uFF08\u76F8\u5BF9 resources \u76EE\u5F55\u7684\u8DEF\u5F84\u5B57\u9762\u91CF\uFF09\u4E8C\u9009\u4E00",
|
|
7000
|
+
sourceFile
|
|
7001
|
+
);
|
|
7002
|
+
}
|
|
7003
|
+
return { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription };
|
|
7090
7004
|
}
|
|
7091
7005
|
function getPropertyName(name) {
|
|
7092
7006
|
if (ts11.isIdentifier(name)) return name.text;
|
|
@@ -7169,8 +7083,8 @@ function serializeAgents(agents, dist = "dist") {
|
|
|
7169
7083
|
return agents.map((a) => ({
|
|
7170
7084
|
name: a.name,
|
|
7171
7085
|
description: a.description,
|
|
7172
|
-
hasRun: a.hasRun,
|
|
7173
7086
|
systemPrompt: a.systemPrompt,
|
|
7087
|
+
systemPromptFile: a.systemPromptFile,
|
|
7174
7088
|
tools: a.tools,
|
|
7175
7089
|
agents: a.agents,
|
|
7176
7090
|
model: a.model,
|
|
@@ -7190,8 +7104,8 @@ function hydrateAgents(manifest) {
|
|
|
7190
7104
|
name: a.name,
|
|
7191
7105
|
description: a.description ?? void 0,
|
|
7192
7106
|
filePath: a.filePath,
|
|
7193
|
-
hasRun: a.hasRun,
|
|
7194
7107
|
systemPrompt: a.systemPrompt ?? void 0,
|
|
7108
|
+
systemPromptFile: a.systemPromptFile ?? void 0,
|
|
7195
7109
|
tools: a.tools ?? void 0,
|
|
7196
7110
|
agents: a.agents ?? void 0,
|
|
7197
7111
|
model: a.model ?? void 0,
|
|
@@ -7223,14 +7137,13 @@ function validateAgentList(metadata) {
|
|
|
7223
7137
|
}
|
|
7224
7138
|
async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
7225
7139
|
const metadata = [];
|
|
7226
|
-
const programByFile = createPrograms(agents.map((m) =>
|
|
7140
|
+
const programByFile = createPrograms(agents.map((m) => path25.resolve(rootDir, m.filePath)));
|
|
7227
7141
|
for (const manifest of agents) {
|
|
7228
|
-
const absPath =
|
|
7142
|
+
const absPath = path25.resolve(rootDir, manifest.filePath);
|
|
7229
7143
|
const program = programByFile.get(absPath);
|
|
7230
7144
|
const result = extractAgentMetadata(program, absPath, {
|
|
7231
7145
|
name: manifest.name,
|
|
7232
|
-
filePath: manifest.filePath
|
|
7233
|
-
hasRun: manifest.hasRun
|
|
7146
|
+
filePath: manifest.filePath
|
|
7234
7147
|
});
|
|
7235
7148
|
if (!result) {
|
|
7236
7149
|
throw new Error(
|
|
@@ -7241,14 +7154,14 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
|
|
|
7241
7154
|
}
|
|
7242
7155
|
validateAgentList(metadata);
|
|
7243
7156
|
const serialized = serializeAgents(metadata, dist);
|
|
7244
|
-
const agentsPath =
|
|
7157
|
+
const agentsPath = path25.resolve(rootDir, dist, AGENTS_FILE);
|
|
7245
7158
|
await writeAgentsModule(serialized, agentsPath);
|
|
7246
7159
|
return metadata;
|
|
7247
7160
|
}
|
|
7248
7161
|
|
|
7249
7162
|
// src/cli/generateTaskArtifacts.ts
|
|
7250
7163
|
init_generateZodArtifacts();
|
|
7251
|
-
import
|
|
7164
|
+
import path26 from "path";
|
|
7252
7165
|
init_createProgram();
|
|
7253
7166
|
init_atomicWrite();
|
|
7254
7167
|
init_extractHandlerTypes();
|
|
@@ -7286,7 +7199,7 @@ function collectTaskSchemaSources(tasks, rootDir) {
|
|
|
7286
7199
|
const tasksByFile = /* @__PURE__ */ new Map();
|
|
7287
7200
|
for (const task of tasks) {
|
|
7288
7201
|
if (!task.inputTypeName) continue;
|
|
7289
|
-
const absPath =
|
|
7202
|
+
const absPath = path26.resolve(rootDir, task.filePath);
|
|
7290
7203
|
let list = tasksByFile.get(absPath);
|
|
7291
7204
|
if (!list) {
|
|
7292
7205
|
list = [];
|
|
@@ -7343,9 +7256,9 @@ function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
|
|
|
7343
7256
|
async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
7344
7257
|
const metadata = [];
|
|
7345
7258
|
if (manifests.length > 0) {
|
|
7346
|
-
const programByFile = createPrograms(manifests.map((m) =>
|
|
7259
|
+
const programByFile = createPrograms(manifests.map((m) => path26.resolve(rootDir, m.filePath)));
|
|
7347
7260
|
for (const manifest of manifests) {
|
|
7348
|
-
const absPath =
|
|
7261
|
+
const absPath = path26.resolve(rootDir, manifest.filePath);
|
|
7349
7262
|
const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
|
|
7350
7263
|
name: manifest.name,
|
|
7351
7264
|
filePath: manifest.filePath
|
|
@@ -7356,7 +7269,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
7356
7269
|
}
|
|
7357
7270
|
}
|
|
7358
7271
|
const serialized = serializeTasks(manifests, dist);
|
|
7359
|
-
const tasksPath =
|
|
7272
|
+
const tasksPath = path26.resolve(rootDir, dist, TASKS_FILE);
|
|
7360
7273
|
await writeTasksModule(serialized, tasksPath);
|
|
7361
7274
|
if (metadata.length === 0) {
|
|
7362
7275
|
return hydrateTasks(serialized);
|
|
@@ -7378,7 +7291,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
|
|
|
7378
7291
|
var TOOLS_FILE2 = "faapi-tools.js";
|
|
7379
7292
|
var AGENTS_FILE2 = "faapi-agents.js";
|
|
7380
7293
|
async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
|
|
7381
|
-
const toolsPath =
|
|
7294
|
+
const toolsPath = path27.resolve(rootDir, dist, TOOLS_FILE2);
|
|
7382
7295
|
if (!fs21.existsSync(toolsPath)) {
|
|
7383
7296
|
return [];
|
|
7384
7297
|
}
|
|
@@ -7388,7 +7301,7 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
|
|
|
7388
7301
|
return hydrated;
|
|
7389
7302
|
}
|
|
7390
7303
|
async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
|
|
7391
|
-
const agentsPath =
|
|
7304
|
+
const agentsPath = path27.resolve(rootDir, dist, AGENTS_FILE2);
|
|
7392
7305
|
if (!fs21.existsSync(agentsPath)) {
|
|
7393
7306
|
return [];
|
|
7394
7307
|
}
|
|
@@ -7404,7 +7317,7 @@ function getTaskDriverOptions(config) {
|
|
|
7404
7317
|
return void 0;
|
|
7405
7318
|
}
|
|
7406
7319
|
async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
|
|
7407
|
-
const tasksPath =
|
|
7320
|
+
const tasksPath = path27.resolve(rootDir, dist, TASKS_FILE);
|
|
7408
7321
|
if (!fs21.existsSync(tasksPath)) {
|
|
7409
7322
|
return [];
|
|
7410
7323
|
}
|
|
@@ -7582,8 +7495,7 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
|
|
|
7582
7495
|
if (agents.length > 0) {
|
|
7583
7496
|
console.log(`- Loaded ${agents.length} agent(s):`);
|
|
7584
7497
|
for (const agent of agents) {
|
|
7585
|
-
|
|
7586
|
-
console.log(` ${agent.name} [${exports}] ${agent.filePath}`);
|
|
7498
|
+
console.log(` ${agent.name} ${agent.filePath}`);
|
|
7587
7499
|
}
|
|
7588
7500
|
}
|
|
7589
7501
|
if (taskMetas.length > 0) {
|
|
@@ -7595,10 +7507,16 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
|
|
|
7595
7507
|
}
|
|
7596
7508
|
}
|
|
7597
7509
|
async function createAppBase(options) {
|
|
7510
|
+
if (getCurrentApp()) {
|
|
7511
|
+
throw new Error(
|
|
7512
|
+
"[faapi] createApp: an app is already alive in this process \u2014 faapi supports a single app per process. Close it first (`await app.close()`) or run the second app in a separate process."
|
|
7513
|
+
);
|
|
7514
|
+
}
|
|
7598
7515
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
7599
7516
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
7600
7517
|
const resourcesDir = resolveResourcesDir(rootDir, dist);
|
|
7601
|
-
|
|
7518
|
+
setActiveResourcesDir(resourcesDir);
|
|
7519
|
+
const routesPath = path28.resolve(rootDir, dist, ROUTES_FILE);
|
|
7602
7520
|
if (!fs22.existsSync(routesPath)) {
|
|
7603
7521
|
throw new Error(
|
|
7604
7522
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
@@ -7620,6 +7538,7 @@ async function createAppBase(options) {
|
|
|
7620
7538
|
registry: registries.task,
|
|
7621
7539
|
rootDir,
|
|
7622
7540
|
config,
|
|
7541
|
+
resourcesDir,
|
|
7623
7542
|
registries: createTaskRegistriesView(registries),
|
|
7624
7543
|
driver: taskDriver,
|
|
7625
7544
|
onFailed: config?.task?.onFailed
|
|
@@ -7661,6 +7580,7 @@ async function createAppBase(options) {
|
|
|
7661
7580
|
config?.plugins,
|
|
7662
7581
|
{
|
|
7663
7582
|
rootDir,
|
|
7583
|
+
resourcesDir,
|
|
7664
7584
|
registries,
|
|
7665
7585
|
routes: sorted,
|
|
7666
7586
|
getRoutes: () => sorted,
|
|
@@ -7762,6 +7682,7 @@ async function createAppBase(options) {
|
|
|
7762
7682
|
registries.task.clear();
|
|
7763
7683
|
registries.agentHandle.clear();
|
|
7764
7684
|
registries.taskHandle.clear();
|
|
7685
|
+
setActiveResourcesDir(null);
|
|
7765
7686
|
if (!server.listening) {
|
|
7766
7687
|
app.server = null;
|
|
7767
7688
|
if (getCurrentApp() === app) setCurrentApp(null);
|
|
@@ -7819,7 +7740,7 @@ import path31 from "path";
|
|
|
7819
7740
|
|
|
7820
7741
|
// src/router/scanRoutes.ts
|
|
7821
7742
|
import fg3 from "fast-glob";
|
|
7822
|
-
import
|
|
7743
|
+
import path29 from "path";
|
|
7823
7744
|
import fs23 from "fs";
|
|
7824
7745
|
|
|
7825
7746
|
// src/router/constants.ts
|
|
@@ -7890,26 +7811,26 @@ function extractExportsFromSource(source) {
|
|
|
7890
7811
|
return names;
|
|
7891
7812
|
}
|
|
7892
7813
|
function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
7893
|
-
const routeDir =
|
|
7894
|
-
const resolvedRoot =
|
|
7814
|
+
const routeDir = path29.dirname(routeFilePath);
|
|
7815
|
+
const resolvedRoot = path29.resolve(rootDir);
|
|
7895
7816
|
const paths = [];
|
|
7896
|
-
let currentDir =
|
|
7817
|
+
let currentDir = path29.resolve(rootDir, routeDir);
|
|
7897
7818
|
while (true) {
|
|
7898
7819
|
if (dist) {
|
|
7899
|
-
const mwTsPath =
|
|
7900
|
-
const mwJsPath =
|
|
7901
|
-
const absTsPath =
|
|
7902
|
-
const absJsPath =
|
|
7820
|
+
const mwTsPath = path29.join(currentDir, "middlewares.ts");
|
|
7821
|
+
const mwJsPath = path29.join(currentDir, "middlewares.js");
|
|
7822
|
+
const absTsPath = path29.resolve(rootDir, mwTsPath);
|
|
7823
|
+
const absJsPath = path29.resolve(rootDir, mwJsPath);
|
|
7903
7824
|
const absMwPath = fs23.existsSync(absTsPath) ? absTsPath : fs23.existsSync(absJsPath) ? absJsPath : null;
|
|
7904
7825
|
if (absMwPath) {
|
|
7905
|
-
const relMwPath =
|
|
7906
|
-
const prodAbsPath =
|
|
7826
|
+
const relMwPath = path29.relative(rootDir, absMwPath);
|
|
7827
|
+
const prodAbsPath = path29.resolve(rootDir, toProdFilePath(relMwPath, dist));
|
|
7907
7828
|
paths.push(prodAbsPath);
|
|
7908
7829
|
}
|
|
7909
7830
|
} else {
|
|
7910
7831
|
for (const ext of [".ts", ".js"]) {
|
|
7911
|
-
const mwPath =
|
|
7912
|
-
const absMwPath =
|
|
7832
|
+
const mwPath = path29.join(currentDir, `middlewares${ext}`);
|
|
7833
|
+
const absMwPath = path29.resolve(rootDir, mwPath);
|
|
7913
7834
|
if (fs23.existsSync(absMwPath)) {
|
|
7914
7835
|
paths.push(absMwPath);
|
|
7915
7836
|
break;
|
|
@@ -7917,7 +7838,7 @@ function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
|
|
|
7917
7838
|
}
|
|
7918
7839
|
}
|
|
7919
7840
|
if (currentDir === resolvedRoot) break;
|
|
7920
|
-
const parentDir =
|
|
7841
|
+
const parentDir = path29.dirname(currentDir);
|
|
7921
7842
|
if (parentDir === currentDir) break;
|
|
7922
7843
|
currentDir = parentDir;
|
|
7923
7844
|
}
|
|
@@ -7936,7 +7857,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7936
7857
|
const normalizedFile = file.replace(/\\/g, "/");
|
|
7937
7858
|
const fileName = normalizedFile.split("/").pop();
|
|
7938
7859
|
if (fileName === "handler.ts" || fileName === "handler.js") {
|
|
7939
|
-
const absPath =
|
|
7860
|
+
const absPath = path29.resolve(rootDir, normalizedFile);
|
|
7940
7861
|
const urlPath = filePathToUrlPath(normalizedFile);
|
|
7941
7862
|
const paramNames = extractParamNames(urlPath);
|
|
7942
7863
|
const isDynamic = paramNames.length > 0;
|
|
@@ -7985,7 +7906,7 @@ async function scanRoutes(rootDir, patterns, dist) {
|
|
|
7985
7906
|
|
|
7986
7907
|
// src/tools/scanTools.ts
|
|
7987
7908
|
import fg4 from "fast-glob";
|
|
7988
|
-
import
|
|
7909
|
+
import path30 from "path";
|
|
7989
7910
|
import fs24 from "fs";
|
|
7990
7911
|
var TOOL_PATTERNS = ["src/tools/**/*.ts"];
|
|
7991
7912
|
var TOOL_EXPORT_RE = new RegExp(
|
|
@@ -8036,7 +7957,7 @@ async function scanTools(rootDir, patterns) {
|
|
|
8036
7957
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
8037
7958
|
continue;
|
|
8038
7959
|
}
|
|
8039
|
-
const absPath =
|
|
7960
|
+
const absPath = path30.resolve(rootDir, normalizedFile);
|
|
8040
7961
|
const source = await fs24.promises.readFile(absPath, "utf8").catch(() => "");
|
|
8041
7962
|
const exportNames = extractToolExportsFromSource(source);
|
|
8042
7963
|
const namespace = filePathToToolNamespace(normalizedFile);
|
|
@@ -8061,10 +7982,7 @@ async function scanTools(rootDir, patterns) {
|
|
|
8061
7982
|
|
|
8062
7983
|
// src/agents/scanAgents.ts
|
|
8063
7984
|
import fg5 from "fast-glob";
|
|
8064
|
-
import path30 from "path";
|
|
8065
|
-
import fs25 from "fs";
|
|
8066
7985
|
var DEFAULT_AGENT_PATTERNS = ["src/agents/**/handler.ts"];
|
|
8067
|
-
var RUN_EXPORT_RE = /export\s+(?:async\s+)?(?:function\s+|const\s+)run\b/;
|
|
8068
7986
|
function extractAgentNameFromPath(filePath) {
|
|
8069
7987
|
const normalized = filePath.replace(/\\/g, "/");
|
|
8070
7988
|
const match = normalized.match(/(?:^|\/)agents\/(.+)\/handler\.ts$/);
|
|
@@ -8075,11 +7993,6 @@ function extractAgentNameFromPath(filePath) {
|
|
|
8075
7993
|
}
|
|
8076
7994
|
return match[1].replace(/\//g, ".");
|
|
8077
7995
|
}
|
|
8078
|
-
function detectAgentExports(source) {
|
|
8079
|
-
return {
|
|
8080
|
-
hasRun: RUN_EXPORT_RE.test(source)
|
|
8081
|
-
};
|
|
8082
|
-
}
|
|
8083
7996
|
async function scanAgents(rootDir, patterns) {
|
|
8084
7997
|
const files = await fg5(patterns, {
|
|
8085
7998
|
cwd: rootDir,
|
|
@@ -8094,9 +8007,6 @@ async function scanAgents(rootDir, patterns) {
|
|
|
8094
8007
|
if (fileName !== "handler.ts" && fileName !== "handler.js") {
|
|
8095
8008
|
continue;
|
|
8096
8009
|
}
|
|
8097
|
-
const absPath = path30.resolve(rootDir, normalizedFile);
|
|
8098
|
-
const source = await fs25.promises.readFile(absPath, "utf8").catch(() => "");
|
|
8099
|
-
const { hasRun } = detectAgentExports(source);
|
|
8100
8010
|
const name = extractAgentNameFromPath(normalizedFile);
|
|
8101
8011
|
const prevFile = seen.get(name);
|
|
8102
8012
|
if (prevFile) {
|
|
@@ -8107,8 +8017,7 @@ async function scanAgents(rootDir, patterns) {
|
|
|
8107
8017
|
seen.set(name, normalizedFile);
|
|
8108
8018
|
agents.push({
|
|
8109
8019
|
name,
|
|
8110
|
-
filePath: normalizedFile
|
|
8111
|
-
hasRun
|
|
8020
|
+
filePath: normalizedFile
|
|
8112
8021
|
});
|
|
8113
8022
|
}
|
|
8114
8023
|
return agents;
|
|
@@ -8232,13 +8141,13 @@ export {
|
|
|
8232
8141
|
hydrateSkillRegistry,
|
|
8233
8142
|
invalidateProgramCache,
|
|
8234
8143
|
listSkills,
|
|
8235
|
-
loadAgentModule,
|
|
8236
8144
|
loadConfig,
|
|
8237
8145
|
loadEnv,
|
|
8238
8146
|
loadTaskDriver,
|
|
8239
8147
|
loadToolModule,
|
|
8240
8148
|
loadToolSchema,
|
|
8241
8149
|
logger,
|
|
8150
|
+
readResource,
|
|
8242
8151
|
registerAgentHandleFactory,
|
|
8243
8152
|
removeSkill,
|
|
8244
8153
|
resolveAgentTools,
|