@flink-app/flink 1.0.0 → 2.0.0-alpha.49
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/CHANGELOG.md +12 -0
- package/cli/build.ts +8 -1
- package/cli/run.ts +8 -1
- package/dist/cli/build.js +8 -1
- package/dist/cli/run.js +8 -1
- package/dist/src/FlinkApp.d.ts +33 -0
- package/dist/src/FlinkApp.js +247 -27
- package/dist/src/FlinkContext.d.ts +21 -0
- package/dist/src/FlinkHttpHandler.d.ts +90 -1
- package/dist/src/TypeScriptCompiler.d.ts +42 -0
- package/dist/src/TypeScriptCompiler.js +366 -8
- package/dist/src/TypeScriptUtils.js +4 -0
- package/dist/src/ai/AgentRunner.d.ts +39 -0
- package/dist/src/ai/AgentRunner.js +625 -0
- package/dist/src/ai/FlinkAgent.d.ts +446 -0
- package/dist/src/ai/FlinkAgent.js +633 -0
- package/dist/src/ai/FlinkTool.d.ts +37 -0
- package/dist/src/ai/FlinkTool.js +2 -0
- package/dist/src/ai/LLMAdapter.d.ts +119 -0
- package/dist/src/ai/LLMAdapter.js +2 -0
- package/dist/src/ai/SubAgentExecutor.d.ts +36 -0
- package/dist/src/ai/SubAgentExecutor.js +220 -0
- package/dist/src/ai/ToolExecutor.d.ts +35 -0
- package/dist/src/ai/ToolExecutor.js +237 -0
- package/dist/src/ai/index.d.ts +5 -0
- package/dist/src/ai/index.js +21 -0
- package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
- package/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +4 -0
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.js +52 -0
- package/package.json +14 -2
- package/readme.md +425 -0
- package/spec/AgentDuplicateDetection.spec.ts +112 -0
- package/spec/AgentRunner.spec.ts +527 -0
- package/spec/ConversationHooks.spec.ts +290 -0
- package/spec/FlinkAgent.spec.ts +310 -0
- package/spec/FlinkApp.onError.spec.ts +1 -2
- package/spec/StreamingIntegration.spec.ts +138 -0
- package/spec/SubAgentSupport.spec.ts +941 -0
- package/spec/ToolExecutor.spec.ts +360 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +59 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +76 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +59 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +59 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +56 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
- package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
- package/spec/mock-project/dist/src/FlinkApp.js +1012 -0
- package/spec/mock-project/dist/src/FlinkContext.js +2 -0
- package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
- package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
- package/spec/mock-project/dist/src/FlinkJob.js +2 -0
- package/spec/mock-project/dist/src/FlinkLog.js +26 -0
- package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
- package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
- package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
- package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
- package/spec/mock-project/dist/src/ai/AgentRunner.js +625 -0
- package/spec/mock-project/dist/src/ai/FlinkAgent.js +633 -0
- package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
- package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
- package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +220 -0
- package/spec/mock-project/dist/src/ai/ToolExecutor.js +237 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
- package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/spec/mock-project/dist/src/index.js +17 -69
- package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
- package/spec/mock-project/dist/src/utils.js +290 -0
- package/spec/mock-project/tsconfig.json +6 -1
- package/spec/testHelpers.ts +49 -0
- package/spec/utils.caseConversion.spec.ts +80 -0
- package/spec/utils.spec.ts +13 -13
- package/src/FlinkApp.ts +251 -7
- package/src/FlinkContext.ts +22 -0
- package/src/FlinkHttpHandler.ts +100 -2
- package/src/TypeScriptCompiler.ts +420 -9
- package/src/TypeScriptUtils.ts +5 -0
- package/src/ai/AgentRunner.ts +549 -0
- package/src/ai/FlinkAgent.ts +770 -0
- package/src/ai/FlinkTool.ts +40 -0
- package/src/ai/LLMAdapter.ts +96 -0
- package/src/ai/SubAgentExecutor.ts +199 -0
- package/src/ai/ToolExecutor.ts +193 -0
- package/src/ai/index.ts +5 -0
- package/src/handlers/StreamWriterFactory.ts +84 -0
- package/src/index.ts +4 -0
- package/src/utils.ts +52 -0
- package/tsconfig.json +6 -1
package/CHANGELOG.md
CHANGED
package/cli/build.ts
CHANGED
|
@@ -40,7 +40,14 @@ module.exports = async function run(args: string[]) {
|
|
|
40
40
|
process.exit(1);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
await Promise.all([
|
|
43
|
+
await Promise.all([
|
|
44
|
+
compiler.parseRepos(),
|
|
45
|
+
compiler.parseHandlers(exclude.split(",")),
|
|
46
|
+
compiler.parseTools(),
|
|
47
|
+
compiler.parseAgents(),
|
|
48
|
+
compiler.parseJobs(),
|
|
49
|
+
compiler.generateStartScript(),
|
|
50
|
+
]);
|
|
44
51
|
|
|
45
52
|
console.log(`Compilation done, took ${Date.now() - startTime}ms`);
|
|
46
53
|
|
package/cli/run.ts
CHANGED
|
@@ -63,7 +63,14 @@ module.exports = async function run(args: string[]) {
|
|
|
63
63
|
process.exit(1);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
await Promise.all([
|
|
66
|
+
await Promise.all([
|
|
67
|
+
compiler.parseRepos(),
|
|
68
|
+
compiler.parseHandlers(),
|
|
69
|
+
compiler.parseTools(),
|
|
70
|
+
compiler.parseAgents(),
|
|
71
|
+
compiler.parseJobs(),
|
|
72
|
+
compiler.generateStartScript(entry)
|
|
73
|
+
]);
|
|
67
74
|
|
|
68
75
|
console.log(`Compilation done, took ${Date.now() - startTime}ms`);
|
|
69
76
|
|
package/dist/cli/build.js
CHANGED
|
@@ -65,7 +65,14 @@ module.exports = function run(args) {
|
|
|
65
65
|
if (!compiler.getPreEmitDiagnostics()) {
|
|
66
66
|
process.exit(1);
|
|
67
67
|
}
|
|
68
|
-
return [4 /*yield*/, Promise.all([
|
|
68
|
+
return [4 /*yield*/, Promise.all([
|
|
69
|
+
compiler.parseRepos(),
|
|
70
|
+
compiler.parseHandlers(exclude.split(",")),
|
|
71
|
+
compiler.parseTools(),
|
|
72
|
+
compiler.parseAgents(),
|
|
73
|
+
compiler.parseJobs(),
|
|
74
|
+
compiler.generateStartScript(),
|
|
75
|
+
])];
|
|
69
76
|
case 2:
|
|
70
77
|
_a.sent();
|
|
71
78
|
console.log("Compilation done, took ".concat(Date.now() - startTime, "ms"));
|
package/dist/cli/run.js
CHANGED
|
@@ -83,7 +83,14 @@ module.exports = function run(args) {
|
|
|
83
83
|
if (!compiler.getPreEmitDiagnostics()) {
|
|
84
84
|
process.exit(1);
|
|
85
85
|
}
|
|
86
|
-
return [4 /*yield*/, Promise.all([
|
|
86
|
+
return [4 /*yield*/, Promise.all([
|
|
87
|
+
compiler.parseRepos(),
|
|
88
|
+
compiler.parseHandlers(),
|
|
89
|
+
compiler.parseTools(),
|
|
90
|
+
compiler.parseAgents(),
|
|
91
|
+
compiler.parseJobs(),
|
|
92
|
+
compiler.generateStartScript(entry)
|
|
93
|
+
])];
|
|
87
94
|
case 2:
|
|
88
95
|
_a.sent();
|
|
89
96
|
console.log("Compilation done, took ".concat(Date.now() - startTime, "ms"));
|
package/dist/src/FlinkApp.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import express, { Express } from "express";
|
|
|
3
3
|
import { JSONSchema7 } from "json-schema";
|
|
4
4
|
import { Db, MongoClient } from "mongodb";
|
|
5
5
|
import { ToadScheduler } from "toad-scheduler";
|
|
6
|
+
import { FlinkAgentFile } from "./ai/FlinkAgent";
|
|
7
|
+
import { FlinkToolFile } from "./ai/FlinkTool";
|
|
8
|
+
import { LLMAdapter } from "./ai/LLMAdapter";
|
|
6
9
|
import { FlinkAuthPlugin } from "./auth/FlinkAuthPlugin";
|
|
7
10
|
import { FlinkContext } from "./FlinkContext";
|
|
8
11
|
import { FlinkError } from "./FlinkErrors";
|
|
@@ -39,6 +42,16 @@ export declare const autoRegisteredRepos: {
|
|
|
39
42
|
* are picked up by TypeScript compiler
|
|
40
43
|
*/
|
|
41
44
|
export declare const autoRegisteredJobs: FlinkJobFile[];
|
|
45
|
+
/**
|
|
46
|
+
* This will be populated at compile time when the apps tools
|
|
47
|
+
* are picked up by TypeScript compiler
|
|
48
|
+
*/
|
|
49
|
+
export declare const autoRegisteredTools: FlinkToolFile[];
|
|
50
|
+
/**
|
|
51
|
+
* This will be populated at compile time when the apps agents
|
|
52
|
+
* are picked up by TypeScript compiler
|
|
53
|
+
*/
|
|
54
|
+
export declare const autoRegisteredAgents: FlinkAgentFile[];
|
|
42
55
|
export interface FlinkOptions {
|
|
43
56
|
/**
|
|
44
57
|
* Name of application, will only show in logs and in HTTP header.
|
|
@@ -118,6 +131,16 @@ export interface FlinkOptions {
|
|
|
118
131
|
*/
|
|
119
132
|
enabled?: boolean;
|
|
120
133
|
};
|
|
134
|
+
/**
|
|
135
|
+
* AI configuration for agents and tools
|
|
136
|
+
* Register LLM adapters with custom IDs (e.g., "anthropic", "openai", "anthropic-eu", etc.)
|
|
137
|
+
* This allows multiple adapters of the same type with different configurations
|
|
138
|
+
*/
|
|
139
|
+
ai?: {
|
|
140
|
+
llms?: {
|
|
141
|
+
[id: string]: LLMAdapter;
|
|
142
|
+
};
|
|
143
|
+
};
|
|
121
144
|
/**
|
|
122
145
|
* If true, the HTTP server will be disabled.
|
|
123
146
|
* Only useful when starting a Flink app for testing purposes.
|
|
@@ -226,6 +249,9 @@ export declare class FlinkApp<C extends FlinkContext> {
|
|
|
226
249
|
private expressServer;
|
|
227
250
|
private onError?;
|
|
228
251
|
private repos;
|
|
252
|
+
private llmAdapters;
|
|
253
|
+
private tools;
|
|
254
|
+
private agents;
|
|
229
255
|
/**
|
|
230
256
|
* Internal cache used to track registered handlers and potentially any overlapping routes
|
|
231
257
|
*/
|
|
@@ -253,11 +279,18 @@ export declare class FlinkApp<C extends FlinkContext> {
|
|
|
253
279
|
private registerAutoRegisterableHandlers;
|
|
254
280
|
private registerAutoRegisterableJobs;
|
|
255
281
|
addRepo(instanceName: string, repoInstance: FlinkRepo<C, any>): void;
|
|
282
|
+
private registerAutoRegisterableTools;
|
|
283
|
+
private registerAutoRegisterableAgents;
|
|
256
284
|
/**
|
|
257
285
|
* Constructs the app context. Will inject context in all components
|
|
258
286
|
* except for handlers which are handled in later stage.
|
|
259
287
|
*/
|
|
260
288
|
private buildContext;
|
|
289
|
+
/**
|
|
290
|
+
* Initialize agents after they've been registered and context is ready
|
|
291
|
+
* Must be called after registerAutoRegisterableAgents()
|
|
292
|
+
*/
|
|
293
|
+
private initializeAgents;
|
|
261
294
|
/**
|
|
262
295
|
* Connects to database.
|
|
263
296
|
*/
|
package/dist/src/FlinkApp.js
CHANGED
|
@@ -50,7 +50,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
50
50
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
51
|
};
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
-
exports.FlinkApp = exports.autoRegisteredJobs = exports.autoRegisteredRepos = exports.autoRegisteredHandlers = exports.expressFn = void 0;
|
|
53
|
+
exports.FlinkApp = exports.autoRegisteredAgents = exports.autoRegisteredTools = exports.autoRegisteredJobs = exports.autoRegisteredRepos = exports.autoRegisteredHandlers = exports.expressFn = void 0;
|
|
54
54
|
var ajv_1 = __importDefault(require("ajv"));
|
|
55
55
|
var ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
56
56
|
var body_parser_1 = __importDefault(require("body-parser"));
|
|
@@ -64,6 +64,7 @@ var uuid_1 = require("uuid");
|
|
|
64
64
|
var FlinkErrors_1 = require("./FlinkErrors");
|
|
65
65
|
var FlinkHttpHandler_1 = require("./FlinkHttpHandler");
|
|
66
66
|
var FlinkLog_1 = require("./FlinkLog");
|
|
67
|
+
var StreamWriterFactory_1 = require("./handlers/StreamWriterFactory");
|
|
67
68
|
var mock_data_generator_1 = __importDefault(require("./mock-data-generator"));
|
|
68
69
|
var utils_1 = require("./utils");
|
|
69
70
|
var ajv = new ajv_1.default();
|
|
@@ -93,8 +94,19 @@ exports.autoRegisteredRepos = [];
|
|
|
93
94
|
* are picked up by TypeScript compiler
|
|
94
95
|
*/
|
|
95
96
|
exports.autoRegisteredJobs = [];
|
|
97
|
+
/**
|
|
98
|
+
* This will be populated at compile time when the apps tools
|
|
99
|
+
* are picked up by TypeScript compiler
|
|
100
|
+
*/
|
|
101
|
+
exports.autoRegisteredTools = [];
|
|
102
|
+
/**
|
|
103
|
+
* This will be populated at compile time when the apps agents
|
|
104
|
+
* are picked up by TypeScript compiler
|
|
105
|
+
*/
|
|
106
|
+
exports.autoRegisteredAgents = [];
|
|
96
107
|
var FlinkApp = /** @class */ (function () {
|
|
97
108
|
function FlinkApp(opts) {
|
|
109
|
+
var _a;
|
|
98
110
|
this.handlers = [];
|
|
99
111
|
this.started = false;
|
|
100
112
|
this.debug = false;
|
|
@@ -102,6 +114,9 @@ var FlinkApp = /** @class */ (function () {
|
|
|
102
114
|
this.routingConfigured = false;
|
|
103
115
|
this.disableHttpServer = false;
|
|
104
116
|
this.repos = {};
|
|
117
|
+
this.llmAdapters = new Map();
|
|
118
|
+
this.tools = {};
|
|
119
|
+
this.agents = {}; // FlinkAgent<C> instances
|
|
105
120
|
/**
|
|
106
121
|
* Internal cache used to track registered handlers and potentially any overlapping routes
|
|
107
122
|
*/
|
|
@@ -124,6 +139,11 @@ var FlinkApp = /** @class */ (function () {
|
|
|
124
139
|
this.disableHttpServer = !!opts.disableHttpServer;
|
|
125
140
|
this.accessLog = __assign({ enabled: true, format: "dev" }, opts.accessLog);
|
|
126
141
|
this.onError = opts.onError;
|
|
142
|
+
// Register LLM adapters if configured
|
|
143
|
+
if ((_a = opts.ai) === null || _a === void 0 ? void 0 : _a.llms) {
|
|
144
|
+
// Convert plain object to Map for internal use
|
|
145
|
+
this.llmAdapters = new Map(Object.entries(opts.ai.llms));
|
|
146
|
+
}
|
|
127
147
|
}
|
|
128
148
|
Object.defineProperty(FlinkApp.prototype, "ctx", {
|
|
129
149
|
get: function () {
|
|
@@ -152,13 +172,42 @@ var FlinkApp = /** @class */ (function () {
|
|
|
152
172
|
offsetTime = Date.now();
|
|
153
173
|
FlinkLog_1.log.bgColorLog("cyan", "Init db took ".concat(offsetTime - startTime, " ms"));
|
|
154
174
|
}
|
|
175
|
+
// Build initial context (without agents - they'll be added later)
|
|
155
176
|
return [4 /*yield*/, this.buildContext()];
|
|
156
177
|
case 2:
|
|
178
|
+
// Build initial context (without agents - they'll be added later)
|
|
157
179
|
_e.sent();
|
|
158
180
|
if (this.debug) {
|
|
159
181
|
FlinkLog_1.log.bgColorLog("cyan", "Build context took ".concat(Date.now() - offsetTime, " ms"));
|
|
160
182
|
offsetTime = Date.now();
|
|
161
183
|
}
|
|
184
|
+
// Register tools (needs context for ToolExecutor)
|
|
185
|
+
return [4 /*yield*/, this.registerAutoRegisterableTools()];
|
|
186
|
+
case 3:
|
|
187
|
+
// Register tools (needs context for ToolExecutor)
|
|
188
|
+
_e.sent();
|
|
189
|
+
if (this.debug) {
|
|
190
|
+
FlinkLog_1.log.bgColorLog("cyan", "Register tools took ".concat(Date.now() - offsetTime, " ms"));
|
|
191
|
+
offsetTime = Date.now();
|
|
192
|
+
}
|
|
193
|
+
// Register agents (creates agent instances)
|
|
194
|
+
return [4 /*yield*/, this.registerAutoRegisterableAgents()];
|
|
195
|
+
case 4:
|
|
196
|
+
// Register agents (creates agent instances)
|
|
197
|
+
_e.sent();
|
|
198
|
+
if (this.debug) {
|
|
199
|
+
FlinkLog_1.log.bgColorLog("cyan", "Register agents took ".concat(Date.now() - offsetTime, " ms"));
|
|
200
|
+
offsetTime = Date.now();
|
|
201
|
+
}
|
|
202
|
+
// Initialize agents now that context and tools are ready
|
|
203
|
+
return [4 /*yield*/, this.initializeAgents()];
|
|
204
|
+
case 5:
|
|
205
|
+
// Initialize agents now that context and tools are ready
|
|
206
|
+
_e.sent();
|
|
207
|
+
if (this.debug) {
|
|
208
|
+
FlinkLog_1.log.bgColorLog("cyan", "Initialize agents took ".concat(Date.now() - offsetTime, " ms"));
|
|
209
|
+
offsetTime = Date.now();
|
|
210
|
+
}
|
|
162
211
|
if (this.isSchedulingEnabled) {
|
|
163
212
|
this.scheduler = new toad_scheduler_1.ToadScheduler();
|
|
164
213
|
}
|
|
@@ -184,45 +233,45 @@ var FlinkApp = /** @class */ (function () {
|
|
|
184
233
|
});
|
|
185
234
|
}
|
|
186
235
|
_b = 0, _c = this.plugins;
|
|
187
|
-
_e.label =
|
|
188
|
-
case
|
|
189
|
-
if (!(_b < _c.length)) return [3 /*break*/,
|
|
236
|
+
_e.label = 6;
|
|
237
|
+
case 6:
|
|
238
|
+
if (!(_b < _c.length)) return [3 /*break*/, 12];
|
|
190
239
|
plugin = _c[_b];
|
|
191
240
|
db = void 0;
|
|
192
|
-
if (!plugin.db) return [3 /*break*/,
|
|
241
|
+
if (!plugin.db) return [3 /*break*/, 8];
|
|
193
242
|
return [4 /*yield*/, this.initPluginDb(plugin)];
|
|
194
|
-
case
|
|
243
|
+
case 7:
|
|
195
244
|
db = _e.sent();
|
|
196
|
-
_e.label =
|
|
197
|
-
case
|
|
198
|
-
if (!plugin.init) return [3 /*break*/,
|
|
245
|
+
_e.label = 8;
|
|
246
|
+
case 8:
|
|
247
|
+
if (!plugin.init) return [3 /*break*/, 10];
|
|
199
248
|
return [4 /*yield*/, plugin.init(this, db)];
|
|
200
|
-
case
|
|
249
|
+
case 9:
|
|
201
250
|
_e.sent();
|
|
202
|
-
_e.label =
|
|
203
|
-
case
|
|
251
|
+
_e.label = 10;
|
|
252
|
+
case 10:
|
|
204
253
|
FlinkLog_1.log.info("Initialized plugin '".concat(plugin.id, "'"));
|
|
205
|
-
_e.label =
|
|
206
|
-
case
|
|
254
|
+
_e.label = 11;
|
|
255
|
+
case 11:
|
|
207
256
|
_b++;
|
|
208
|
-
return [3 /*break*/,
|
|
209
|
-
case
|
|
210
|
-
case
|
|
257
|
+
return [3 /*break*/, 6];
|
|
258
|
+
case 12: return [4 /*yield*/, this.registerAutoRegisterableHandlers()];
|
|
259
|
+
case 13:
|
|
211
260
|
_e.sent();
|
|
212
261
|
if (this.debug) {
|
|
213
262
|
FlinkLog_1.log.bgColorLog("cyan", "Register handlers took ".concat(Date.now() - offsetTime, " ms"));
|
|
214
263
|
offsetTime = Date.now();
|
|
215
264
|
}
|
|
216
|
-
if (!this.isSchedulingEnabled) return [3 /*break*/,
|
|
265
|
+
if (!this.isSchedulingEnabled) return [3 /*break*/, 15];
|
|
217
266
|
return [4 /*yield*/, this.registerAutoRegisterableJobs()];
|
|
218
|
-
case
|
|
267
|
+
case 14:
|
|
219
268
|
_e.sent();
|
|
220
269
|
if (this.debug) {
|
|
221
270
|
FlinkLog_1.log.bgColorLog("cyan", "Register jobs took ".concat(Date.now() - offsetTime, " ms"));
|
|
222
271
|
offsetTime = Date.now();
|
|
223
272
|
}
|
|
224
|
-
_e.label =
|
|
225
|
-
case
|
|
273
|
+
_e.label = 15;
|
|
274
|
+
case 15:
|
|
226
275
|
// Register 404 with slight delay to allow all manually added routes to be added
|
|
227
276
|
// TODO: Is there a better solution to force this handler to always run last?
|
|
228
277
|
setTimeout(function () {
|
|
@@ -325,7 +374,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
325
374
|
var _this = this;
|
|
326
375
|
this.handlers.push(handlerConfig);
|
|
327
376
|
var routeProps = handlerConfig.routeProps, _a = handlerConfig.schema, schema = _a === void 0 ? {} : _a;
|
|
328
|
-
var method = routeProps.method;
|
|
377
|
+
var method = routeProps.method, streamFormat = routeProps.streamFormat;
|
|
329
378
|
if (!method) {
|
|
330
379
|
FlinkLog_1.log.error("Route ".concat(routeProps.path, " is missing http method"));
|
|
331
380
|
}
|
|
@@ -342,12 +391,12 @@ var FlinkApp = /** @class */ (function () {
|
|
|
342
391
|
if (schema.reqSchema && validationMode !== FlinkHttpHandler_1.ValidationMode.SkipValidation && validationMode !== FlinkHttpHandler_1.ValidationMode.ValidateResponse) {
|
|
343
392
|
validateReq_1 = ajv.compile(schema.reqSchema);
|
|
344
393
|
}
|
|
345
|
-
//
|
|
346
|
-
if (schema.resSchema && validationMode !== FlinkHttpHandler_1.ValidationMode.SkipValidation && validationMode !== FlinkHttpHandler_1.ValidationMode.ValidateRequest) {
|
|
394
|
+
// Skip response validation for streaming handlers (responses are stream chunks, not final JSON)
|
|
395
|
+
if (!streamFormat && schema.resSchema && validationMode !== FlinkHttpHandler_1.ValidationMode.SkipValidation && validationMode !== FlinkHttpHandler_1.ValidationMode.ValidateRequest) {
|
|
347
396
|
validateRes_1 = ajv.compile(schema.resSchema);
|
|
348
397
|
}
|
|
349
398
|
this.expressApp[method](routeProps.path, function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
350
|
-
var valid, formattedErrors, data, normalizedQuery, _i, _a, _b, key, value, handlerRes, err_1, errorResponse, result, valid, formattedErrors;
|
|
399
|
+
var valid, formattedErrors, data, normalizedQuery, _i, _a, _b, key, value, stream, handlerRes, err_1, errorResponse, result, valid, formattedErrors;
|
|
351
400
|
return __generator(this, function (_c) {
|
|
352
401
|
switch (_c.label) {
|
|
353
402
|
case 0:
|
|
@@ -374,7 +423,8 @@ var FlinkApp = /** @class */ (function () {
|
|
|
374
423
|
})];
|
|
375
424
|
}
|
|
376
425
|
}
|
|
377
|
-
|
|
426
|
+
// Skip mock API for streaming handlers
|
|
427
|
+
if (routeProps.mockApi && schema.resSchema && !streamFormat) {
|
|
378
428
|
FlinkLog_1.log.warn("Mock response for ".concat(req.method.toUpperCase(), " ").concat(req.path));
|
|
379
429
|
data = (0, mock_data_generator_1.default)(schema.resSchema);
|
|
380
430
|
res.status(200).json({
|
|
@@ -402,6 +452,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
402
452
|
}
|
|
403
453
|
req.query = normalizedQuery;
|
|
404
454
|
}
|
|
455
|
+
stream = streamFormat ? StreamWriterFactory_1.StreamWriterFactory.create(res, streamFormat) : undefined;
|
|
405
456
|
_c.label = 3;
|
|
406
457
|
case 3:
|
|
407
458
|
_c.trys.push([3, 5, , 6]);
|
|
@@ -409,6 +460,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
409
460
|
req: req,
|
|
410
461
|
ctx: this.ctx,
|
|
411
462
|
origin: routeProps.origin,
|
|
463
|
+
stream: stream,
|
|
412
464
|
})];
|
|
413
465
|
case 4:
|
|
414
466
|
// 👇 This is where the actual handler gets invoked
|
|
@@ -416,6 +468,16 @@ var FlinkApp = /** @class */ (function () {
|
|
|
416
468
|
return [3 /*break*/, 6];
|
|
417
469
|
case 5:
|
|
418
470
|
err_1 = _c.sent();
|
|
471
|
+
// Handle errors for streaming handlers
|
|
472
|
+
if (streamFormat && stream) {
|
|
473
|
+
FlinkLog_1.log.error("Streaming handler error on ".concat(req.method.toUpperCase(), " ").concat(req.path, ": ").concat(err_1.message), {
|
|
474
|
+
error: err_1,
|
|
475
|
+
path: req.path,
|
|
476
|
+
method: req.method,
|
|
477
|
+
});
|
|
478
|
+
stream.error(err_1);
|
|
479
|
+
return [2 /*return*/];
|
|
480
|
+
}
|
|
419
481
|
errorResponse = void 0;
|
|
420
482
|
// duck typing to check if it is a FlinkError
|
|
421
483
|
if (typeof err_1.status === "number" && err_1.status >= 400 && err_1.status < 600 && err_1.error) {
|
|
@@ -456,6 +518,14 @@ var FlinkApp = /** @class */ (function () {
|
|
|
456
518
|
}
|
|
457
519
|
return [2 /*return*/, res.status(errorResponse.status || 500).json(errorResponse)];
|
|
458
520
|
case 6:
|
|
521
|
+
// Skip response handling for streaming handlers (stream controls response lifecycle)
|
|
522
|
+
if (streamFormat) {
|
|
523
|
+
return [2 /*return*/];
|
|
524
|
+
}
|
|
525
|
+
// Ensure handlerRes is defined for non-streaming handlers
|
|
526
|
+
if (!handlerRes) {
|
|
527
|
+
return [2 /*return*/, res.status(204).send()];
|
|
528
|
+
}
|
|
459
529
|
if (validateRes_1 && !(0, utils_1.isError)(handlerRes)) {
|
|
460
530
|
valid = validateRes_1(JSON.parse(JSON.stringify(handlerRes.data)));
|
|
461
531
|
if (!valid) {
|
|
@@ -483,7 +553,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
483
553
|
}
|
|
484
554
|
else {
|
|
485
555
|
this.handlerRouteCache.set(methodAndRoute_1, JSON.stringify(routeProps));
|
|
486
|
-
FlinkLog_1.log.info("Registered route ".concat(methodAndRoute_1));
|
|
556
|
+
FlinkLog_1.log.info("Registered ".concat(streamFormat ? 'streaming ' : '', "route ").concat(methodAndRoute_1).concat(streamFormat ? " (".concat(streamFormat, ")") : ''));
|
|
487
557
|
}
|
|
488
558
|
}
|
|
489
559
|
};
|
|
@@ -625,6 +695,137 @@ var FlinkApp = /** @class */ (function () {
|
|
|
625
695
|
// TODO: Find out if we need to set ctx here or wanted not to if plugin has its own context
|
|
626
696
|
// repoInstance.ctx = this.ctx;
|
|
627
697
|
};
|
|
698
|
+
FlinkApp.prototype.registerAutoRegisterableTools = function () {
|
|
699
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
700
|
+
var ToolExecutor, getRepoInstanceName, _i, autoRegisteredTools_1, toolFile, toolId, toolInstanceName, toolExecutor;
|
|
701
|
+
return __generator(this, function (_a) {
|
|
702
|
+
ToolExecutor = require("./ai/ToolExecutor").ToolExecutor;
|
|
703
|
+
getRepoInstanceName = require("./utils").getRepoInstanceName;
|
|
704
|
+
for (_i = 0, autoRegisteredTools_1 = exports.autoRegisteredTools; _i < autoRegisteredTools_1.length; _i++) {
|
|
705
|
+
toolFile = autoRegisteredTools_1[_i];
|
|
706
|
+
if (!toolFile.Tool) {
|
|
707
|
+
FlinkLog_1.log.error("Missing FlinkToolProps export in tool ".concat(toolFile.__file));
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
if (!toolFile.default) {
|
|
711
|
+
FlinkLog_1.log.error("Missing exported tool function in tool ".concat(toolFile.__file));
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
toolId = toolFile.Tool.id;
|
|
715
|
+
if (!toolId) {
|
|
716
|
+
FlinkLog_1.log.error("Tool ".concat(toolFile.__file, " missing 'id' property"));
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
toolInstanceName = getRepoInstanceName(toolId);
|
|
720
|
+
toolExecutor = new ToolExecutor(toolFile.Tool, toolFile.default, this.ctx);
|
|
721
|
+
this.tools[toolInstanceName] = toolExecutor;
|
|
722
|
+
FlinkLog_1.log.info("Registered tool ".concat(toolInstanceName, " (").concat(toolId, ")"));
|
|
723
|
+
}
|
|
724
|
+
return [2 /*return*/];
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
};
|
|
728
|
+
FlinkApp.prototype.registerAutoRegisterableAgents = function () {
|
|
729
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
730
|
+
var _a, getRepoInstanceName, toKebabCase, SubAgentExecutor, _loop_2, this_2, _i, autoRegisteredAgents_1, agentFile, _b, autoRegisteredAgents_2, agentFile, AgentClass, agentInstance, _c, _d, agentRef, subAgentInstanceName;
|
|
731
|
+
return __generator(this, function (_e) {
|
|
732
|
+
_a = require("./utils"), getRepoInstanceName = _a.getRepoInstanceName, toKebabCase = _a.toKebabCase;
|
|
733
|
+
SubAgentExecutor = require("./ai/SubAgentExecutor").SubAgentExecutor;
|
|
734
|
+
_loop_2 = function (agentFile) {
|
|
735
|
+
// agentFile now exports a class, not a config object
|
|
736
|
+
var AgentClass = agentFile.default;
|
|
737
|
+
if (!AgentClass) {
|
|
738
|
+
FlinkLog_1.log.error("Missing default export in agent ".concat(agentFile.__file));
|
|
739
|
+
return "continue";
|
|
740
|
+
}
|
|
741
|
+
// Instantiate agent (similar to repo instantiation)
|
|
742
|
+
var agentInstance = new AgentClass();
|
|
743
|
+
// Derive instance name from class name (camelCase)
|
|
744
|
+
var agentInstanceName = getRepoInstanceName(AgentClass.name);
|
|
745
|
+
// Get agent ID (kebab-case) - either explicit or derived
|
|
746
|
+
var agentId = agentInstance.id || toKebabCase(AgentClass.name);
|
|
747
|
+
// Check for duplicate instance name
|
|
748
|
+
if (this_2.agents[agentInstanceName]) {
|
|
749
|
+
var existingAgent = this_2.agents[agentInstanceName];
|
|
750
|
+
throw new Error("Duplicate agent instance name: \"".concat(agentInstanceName, "\". ") +
|
|
751
|
+
"Agent class \"".concat(AgentClass.name, "\" conflicts with existing agent \"").concat(existingAgent.constructor.name, "\". ") +
|
|
752
|
+
"Instance names are derived by lowercasing the first letter of the class name. " +
|
|
753
|
+
"Rename one of the classes or use a unique explicit 'id' property.");
|
|
754
|
+
}
|
|
755
|
+
// Check for duplicate agent ID
|
|
756
|
+
var existingAgentWithSameId = Object.values(this_2.agents).find(function (agent) {
|
|
757
|
+
var existingId = agent.id || toKebabCase(agent.constructor.name);
|
|
758
|
+
return existingId === agentId;
|
|
759
|
+
});
|
|
760
|
+
if (existingAgentWithSameId) {
|
|
761
|
+
throw new Error("Duplicate agent ID: \"".concat(agentId, "\". ") +
|
|
762
|
+
"Agent class \"".concat(AgentClass.name, "\" conflicts with existing agent \"").concat(existingAgentWithSameId.constructor.name, "\". ") +
|
|
763
|
+
"Agent IDs are derived from class names using kebab-case (e.g., CarAgent \u2192 car-agent). " +
|
|
764
|
+
"Use an explicit 'id' property to resolve this conflict:\n" +
|
|
765
|
+
" id = \"my-unique-id\";");
|
|
766
|
+
}
|
|
767
|
+
// Validate tools exist
|
|
768
|
+
for (var _f = 0, _g = agentInstance.tools; _f < _g.length; _f++) {
|
|
769
|
+
var toolRef = _g[_f];
|
|
770
|
+
// Handle both string IDs and tool file references
|
|
771
|
+
var toolId = typeof toolRef === "string"
|
|
772
|
+
? toolRef
|
|
773
|
+
: toolRef.Tool.id; // Extract ID from FlinkToolFile
|
|
774
|
+
var tool = this_2.tools[toolId];
|
|
775
|
+
if (!tool) {
|
|
776
|
+
FlinkLog_1.log.error("Agent ".concat(AgentClass.name, " references tool ").concat(toolId, " which is not registered"));
|
|
777
|
+
throw new Error("Invalid tool reference in agent ".concat(AgentClass.name));
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
// Validate and register sub-agents
|
|
781
|
+
if (agentInstance.agents && agentInstance.agents.length > 0) {
|
|
782
|
+
for (var _h = 0, _j = agentInstance.agents; _h < _j.length; _h++) {
|
|
783
|
+
var agentRef = _j[_h];
|
|
784
|
+
// Get instance name directly from class reference or string
|
|
785
|
+
var subAgentInstanceName = typeof agentRef === "string" ? agentRef : getRepoInstanceName(agentRef.name);
|
|
786
|
+
// Validate that sub-agent will exist (will be registered in this loop)
|
|
787
|
+
// For now, just log - actual validation happens at runtime
|
|
788
|
+
FlinkLog_1.log.debug("Agent ".concat(AgentClass.name, " references sub-agent ").concat(subAgentInstanceName));
|
|
789
|
+
// Create a SubAgentExecutor as a special tool
|
|
790
|
+
var subAgentToolName = "ask_".concat(subAgentInstanceName);
|
|
791
|
+
var subAgentExecutor = new SubAgentExecutor(subAgentInstanceName, this_2.ctx);
|
|
792
|
+
// Register as a tool so it appears in the agent's tool list
|
|
793
|
+
this_2.tools[subAgentToolName] = subAgentExecutor;
|
|
794
|
+
FlinkLog_1.log.debug("Created sub-agent tool ".concat(subAgentToolName, " for ").concat(subAgentInstanceName));
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
// Register agent (duplicate checks already performed above)
|
|
798
|
+
this_2.agents[agentInstanceName] = agentInstance;
|
|
799
|
+
FlinkLog_1.log.info("Registered agent ".concat(agentInstanceName, " (").concat(AgentClass.name, ") with ID: ").concat(agentId));
|
|
800
|
+
};
|
|
801
|
+
this_2 = this;
|
|
802
|
+
for (_i = 0, autoRegisteredAgents_1 = exports.autoRegisteredAgents; _i < autoRegisteredAgents_1.length; _i++) {
|
|
803
|
+
agentFile = autoRegisteredAgents_1[_i];
|
|
804
|
+
_loop_2(agentFile);
|
|
805
|
+
}
|
|
806
|
+
// Second pass: validate all sub-agent references
|
|
807
|
+
for (_b = 0, autoRegisteredAgents_2 = exports.autoRegisteredAgents; _b < autoRegisteredAgents_2.length; _b++) {
|
|
808
|
+
agentFile = autoRegisteredAgents_2[_b];
|
|
809
|
+
AgentClass = agentFile.default;
|
|
810
|
+
if (!AgentClass) {
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
813
|
+
agentInstance = new AgentClass();
|
|
814
|
+
if (agentInstance.agents && agentInstance.agents.length > 0) {
|
|
815
|
+
for (_c = 0, _d = agentInstance.agents; _c < _d.length; _c++) {
|
|
816
|
+
agentRef = _d[_c];
|
|
817
|
+
subAgentInstanceName = typeof agentRef === "string" ? agentRef : getRepoInstanceName(agentRef.name);
|
|
818
|
+
if (!this.agents[subAgentInstanceName]) {
|
|
819
|
+
FlinkLog_1.log.error("Agent ".concat(AgentClass.name, " references sub-agent ").concat(subAgentInstanceName, " which is not registered"));
|
|
820
|
+
throw new Error("Invalid sub-agent reference in agent ".concat(AgentClass.name, ": ").concat(subAgentInstanceName));
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
return [2 /*return*/];
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
};
|
|
628
829
|
/**
|
|
629
830
|
* Constructs the app context. Will inject context in all components
|
|
630
831
|
* except for handlers which are handled in later stage.
|
|
@@ -655,6 +856,7 @@ var FlinkApp = /** @class */ (function () {
|
|
|
655
856
|
repos: this.repos,
|
|
656
857
|
plugins: pluginCtx,
|
|
657
858
|
auth: this.auth,
|
|
859
|
+
agents: this.agents,
|
|
658
860
|
};
|
|
659
861
|
for (_b = 0, _c = Object.values(this.repos); _b < _c.length; _b++) {
|
|
660
862
|
repo = _c[_b];
|
|
@@ -664,6 +866,24 @@ var FlinkApp = /** @class */ (function () {
|
|
|
664
866
|
});
|
|
665
867
|
});
|
|
666
868
|
};
|
|
869
|
+
/**
|
|
870
|
+
* Initialize agents after they've been registered and context is ready
|
|
871
|
+
* Must be called after registerAutoRegisterableAgents()
|
|
872
|
+
*/
|
|
873
|
+
FlinkApp.prototype.initializeAgents = function () {
|
|
874
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
875
|
+
var _i, _a, agent;
|
|
876
|
+
return __generator(this, function (_b) {
|
|
877
|
+
// Inject context and initialize agents
|
|
878
|
+
for (_i = 0, _a = Object.values(this.agents); _i < _a.length; _i++) {
|
|
879
|
+
agent = _a[_i];
|
|
880
|
+
agent.ctx = this.ctx;
|
|
881
|
+
agent.__init(this.llmAdapters, this.tools);
|
|
882
|
+
}
|
|
883
|
+
return [2 /*return*/];
|
|
884
|
+
});
|
|
885
|
+
});
|
|
886
|
+
};
|
|
667
887
|
/**
|
|
668
888
|
* Connects to database.
|
|
669
889
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FlinkAuthPlugin } from "./auth/FlinkAuthPlugin";
|
|
2
2
|
import { FlinkRepo } from "./FlinkRepo";
|
|
3
|
+
import { FlinkAgent } from "./ai/FlinkAgent";
|
|
3
4
|
export interface FlinkContext<P = any> {
|
|
4
5
|
repos: {
|
|
5
6
|
[x: string]: FlinkRepo<any, any>;
|
|
@@ -9,4 +10,24 @@ export interface FlinkContext<P = any> {
|
|
|
9
10
|
* Type of authentication, if any.
|
|
10
11
|
*/
|
|
11
12
|
auth?: FlinkAuthPlugin;
|
|
13
|
+
/**
|
|
14
|
+
* AI namespace containing agents
|
|
15
|
+
*
|
|
16
|
+
* Define agents directly in your context interface:
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* interface AppCtx extends FlinkContext<PluginCtx> {
|
|
20
|
+
* auth: JwtAuthPlugin;
|
|
21
|
+
* repos: {
|
|
22
|
+
* carRepo: CarRepo;
|
|
23
|
+
* };
|
|
24
|
+
* agents: {
|
|
25
|
+
* carAgent: CarAgent;
|
|
26
|
+
* userAgent: UserAgent;
|
|
27
|
+
* };
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
agents?: {
|
|
31
|
+
[x: string]: FlinkAgent<any>;
|
|
32
|
+
};
|
|
12
33
|
}
|