@flink-app/flink 1.0.0 → 2.0.0-alpha.48
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 +6 -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 +346 -4
- 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 +398 -7
- 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
|
@@ -57,11 +57,48 @@ type Params = Record<string, string>;
|
|
|
57
57
|
*/
|
|
58
58
|
type Query = Record<string, string | string[]>;
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* Stream format for streaming handlers.
|
|
61
|
+
* - sse: Server-Sent Events (text/event-stream)
|
|
62
|
+
* - ndjson: Newline-Delimited JSON (application/x-ndjson)
|
|
63
|
+
*/
|
|
64
|
+
export type StreamFormat = "sse" | "ndjson";
|
|
65
|
+
/**
|
|
66
|
+
* Stream writer interface for SSE/NDJSON streaming.
|
|
67
|
+
*
|
|
68
|
+
* Provides methods to write data chunks, handle errors, and manage the stream lifecycle.
|
|
69
|
+
* Only available in handlers where streamFormat is specified in RouteProps.
|
|
70
|
+
*/
|
|
71
|
+
export interface StreamWriter<T = any> {
|
|
72
|
+
/**
|
|
73
|
+
* Write data to the stream.
|
|
74
|
+
* Data is automatically JSON-stringified and formatted according to streamFormat.
|
|
75
|
+
*/
|
|
76
|
+
write(data: T): void;
|
|
77
|
+
/**
|
|
78
|
+
* Send error to client and close the stream.
|
|
79
|
+
*/
|
|
80
|
+
error(error: Error | string): void;
|
|
81
|
+
/**
|
|
82
|
+
* Close the stream gracefully.
|
|
83
|
+
*/
|
|
84
|
+
end(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Check if stream is still open (client connected).
|
|
87
|
+
* Returns false if client has disconnected.
|
|
88
|
+
*/
|
|
89
|
+
isOpen(): boolean;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Flink request extends express Request but adds reqId, user object, and userPermissions.
|
|
93
|
+
*
|
|
94
|
+
* userPermissions is populated by auth plugins during authentication and contains
|
|
95
|
+
* the resolved permissions array based on the plugin's configuration (roles, dynamic
|
|
96
|
+
* roles, custom permissions, etc.)
|
|
61
97
|
*/
|
|
62
98
|
export type FlinkRequest<T = any, P = Params, Q = Query> = Request<P, any, T, Q> & {
|
|
63
99
|
reqId: string;
|
|
64
100
|
user?: any;
|
|
101
|
+
userPermissions?: string[];
|
|
65
102
|
};
|
|
66
103
|
/**
|
|
67
104
|
* Route props to control routing.
|
|
@@ -93,6 +130,27 @@ export interface RouteProps {
|
|
|
93
130
|
mockApi?: boolean;
|
|
94
131
|
/**
|
|
95
132
|
* Set permissions needed to access route if route requires authentication.
|
|
133
|
+
*
|
|
134
|
+
* When an array is provided, the user must have **ALL** permissions in the array (AND logic).
|
|
135
|
+
* To require any one of multiple permissions (OR logic), implement custom permission
|
|
136
|
+
* checking in the handler using the `user.permissions` array.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Single permission
|
|
141
|
+
* permissions: "car:create"
|
|
142
|
+
*
|
|
143
|
+
* // Multiple permissions (user must have ALL)
|
|
144
|
+
* permissions: ["car:create", "car:premium"]
|
|
145
|
+
*
|
|
146
|
+
* // OR logic requires custom implementation
|
|
147
|
+
* const handler = async ({ ctx, user }) => {
|
|
148
|
+
* if (!user.permissions.includes("car:admin") && !user.permissions.includes("car:moderator")) {
|
|
149
|
+
* throw forbidden("Need admin or moderator permission");
|
|
150
|
+
* }
|
|
151
|
+
* // ... handler logic
|
|
152
|
+
* };
|
|
153
|
+
* ```
|
|
96
154
|
*/
|
|
97
155
|
permissions?: string | string[];
|
|
98
156
|
/**
|
|
@@ -136,15 +194,46 @@ export interface RouteProps {
|
|
|
136
194
|
* @default ValidationMode.Validate
|
|
137
195
|
*/
|
|
138
196
|
validation?: ValidationMode;
|
|
197
|
+
/**
|
|
198
|
+
* Stream format for streaming handlers (SSE or NDJSON).
|
|
199
|
+
*
|
|
200
|
+
* When specified, the handler becomes a streaming handler and receives a `stream`
|
|
201
|
+
* parameter for writing data chunks. Response validation is automatically skipped
|
|
202
|
+
* for streaming handlers (chunks are progressive, not a final JSON response).
|
|
203
|
+
*
|
|
204
|
+
* **Formats:**
|
|
205
|
+
* - sse: Server-Sent Events (text/event-stream) - ideal for browser EventSource API
|
|
206
|
+
* - ndjson: Newline-Delimited JSON (application/x-ndjson) - ideal for LLM text streaming
|
|
207
|
+
*
|
|
208
|
+
* **Example:**
|
|
209
|
+
* ```typescript
|
|
210
|
+
* export const Route: RouteProps = {
|
|
211
|
+
* path: "/ai/stream",
|
|
212
|
+
* streamFormat: "sse"
|
|
213
|
+
* };
|
|
214
|
+
*
|
|
215
|
+
* const handler: GetHandler<{}, void> = async ({ ctx, stream }) => {
|
|
216
|
+
* if (!stream) throw new Error("Stream not available");
|
|
217
|
+
* stream.write({ message: "Hello" });
|
|
218
|
+
* stream.end();
|
|
219
|
+
* };
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
streamFormat?: StreamFormat;
|
|
139
223
|
}
|
|
140
224
|
/**
|
|
141
225
|
* Http handler function that handlers implements in order to
|
|
142
226
|
* handle HTTP requests and return a JSON response.
|
|
227
|
+
*
|
|
228
|
+
* For streaming handlers (when streamFormat is specified in RouteProps),
|
|
229
|
+
* the stream parameter is available. Streaming handlers should still return
|
|
230
|
+
* a FlinkResponse (can be empty), but it will be ignored by the framework.
|
|
143
231
|
*/
|
|
144
232
|
export type Handler<Ctx extends FlinkContext, ReqSchema = any, ResSchema = any, P extends Params = Params, Q extends Query = Query> = (props: {
|
|
145
233
|
req: FlinkRequest<ReqSchema, P, Q>;
|
|
146
234
|
ctx: Ctx;
|
|
147
235
|
origin?: string;
|
|
236
|
+
stream?: StreamWriter;
|
|
148
237
|
}) => Promise<FlinkResponse<ResSchema | FlinkError>>;
|
|
149
238
|
/**
|
|
150
239
|
* Http handler function specifically for GET requests as those does
|
|
@@ -18,6 +18,28 @@ declare class TypeScriptCompiler {
|
|
|
18
18
|
*/
|
|
19
19
|
private tsSchemasSymbolsToImports;
|
|
20
20
|
constructor(cwd: string);
|
|
21
|
+
/**
|
|
22
|
+
* Loads additional source paths from tsconfig.json's flink configuration.
|
|
23
|
+
* Allows projects to specify extra directories to include in compilation.
|
|
24
|
+
*
|
|
25
|
+
* Example tsconfig.json:
|
|
26
|
+
* {
|
|
27
|
+
* "flink": {
|
|
28
|
+
* "sourcePaths": ["src/custom-types/**\/*.ts", "src/utils/**\/*.ts"]
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
private getFlinkSourcePaths;
|
|
33
|
+
/**
|
|
34
|
+
* Recursively resolves and adds imported files to the project.
|
|
35
|
+
* This ensures that files imported by handlers, schemas, etc. are available for type resolution.
|
|
36
|
+
*
|
|
37
|
+
* Handles three types of imports:
|
|
38
|
+
* 1. Relative imports (./foo, ../bar) - always resolved
|
|
39
|
+
* 2. Workspace package imports (@mycompany/shared) - resolved if symlinked outside node_modules
|
|
40
|
+
* 3. External packages (lodash, express) - skipped to avoid loading entire dependency trees
|
|
41
|
+
*/
|
|
42
|
+
private resolveImportedFiles;
|
|
21
43
|
/**
|
|
22
44
|
* Detects if the project is using ESM (ECMAScript Modules)
|
|
23
45
|
* by checking type in package.json.
|
|
@@ -41,6 +63,15 @@ declare class TypeScriptCompiler {
|
|
|
41
63
|
* exists. Warnings will be passed thru but logged.
|
|
42
64
|
*/
|
|
43
65
|
getPreEmitDiagnostics(): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Finds a variable declaration by its TypeScript type name.
|
|
68
|
+
* This allows finding variables based on their type annotation rather than variable name.
|
|
69
|
+
*
|
|
70
|
+
* @param sf Source file to search in
|
|
71
|
+
* @param typeName Name of the type to search for (e.g., "FlinkToolProps", "FlinkAgentProps")
|
|
72
|
+
* @returns The first matching variable declaration, or undefined if not found
|
|
73
|
+
*/
|
|
74
|
+
private findVariableDeclarationByType;
|
|
44
75
|
/**
|
|
45
76
|
* Scans project for handlers and add those to Flink
|
|
46
77
|
* "singleton" property `autoRegisteredHandlers` so they can
|
|
@@ -55,6 +86,17 @@ declare class TypeScriptCompiler {
|
|
|
55
86
|
*/
|
|
56
87
|
private parseHandlerDir;
|
|
57
88
|
parseRepos(): Promise<SourceFile>;
|
|
89
|
+
/**
|
|
90
|
+
* Scans project for tools and adds those to Flink
|
|
91
|
+
* "singleton" property `autoRegisteredTools` so they can
|
|
92
|
+
* be registered during start.
|
|
93
|
+
*/
|
|
94
|
+
parseTools(): Promise<SourceFile>;
|
|
95
|
+
/**
|
|
96
|
+
* Scans project for agents and validates tool references.
|
|
97
|
+
* Agents are declarative (no default function).
|
|
98
|
+
*/
|
|
99
|
+
parseAgents(): Promise<SourceFile>;
|
|
58
100
|
/**
|
|
59
101
|
* Generates a start script that will import references to handlers, repos and the
|
|
60
102
|
* actual Flink app to start.
|
|
@@ -130,11 +130,100 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
130
130
|
this.project = new ts_morph_1.Project({
|
|
131
131
|
tsConfigFilePath: tsConfigPath,
|
|
132
132
|
compilerOptions: compilerOptions,
|
|
133
|
+
skipAddingFilesFromTsConfig: true, // Don't auto-load all files - we'll add specific directories we need
|
|
133
134
|
});
|
|
135
|
+
// Load Flink-specific source paths from tsconfig.json if available
|
|
136
|
+
var additionalSourcePaths = this.getFlinkSourcePaths(tsConfigPath);
|
|
137
|
+
// Only add source files from directories we actually need to process
|
|
138
|
+
// This prevents loading all files from tsconfig include patterns and reduces memory usage
|
|
139
|
+
var defaultSourcePaths = [
|
|
140
|
+
(0, path_1.join)(cwd, "src/handlers/**/*.ts"),
|
|
141
|
+
(0, path_1.join)(cwd, "src/repos/**/*.ts"),
|
|
142
|
+
(0, path_1.join)(cwd, "src/tools/**/*.ts"),
|
|
143
|
+
(0, path_1.join)(cwd, "src/agents/**/*.ts"),
|
|
144
|
+
(0, path_1.join)(cwd, "src/jobs/**/*.ts"),
|
|
145
|
+
(0, path_1.join)(cwd, "src/index.ts"),
|
|
146
|
+
(0, path_1.join)(cwd, "src/schemas/**/*.ts"), // Include schemas for type resolution
|
|
147
|
+
];
|
|
148
|
+
var allSourcePaths = __spreadArray(__spreadArray([], defaultSourcePaths, true), additionalSourcePaths, true);
|
|
149
|
+
this.project.addSourceFilesAtPaths(allSourcePaths);
|
|
150
|
+
// Resolve imports: add any files imported by our source files
|
|
151
|
+
// This ensures schemas that import types from other locations work correctly
|
|
152
|
+
this.resolveImportedFiles();
|
|
134
153
|
console.log("Loaded", this.project.getSourceFiles().length, "source file(s) from", cwd);
|
|
135
154
|
console.log("Module system:", this.isEsm ? "ESM" : "CommonJS");
|
|
136
155
|
console.log("Using module:", compilerOptions.module === ts_morph_1.ts.ModuleKind.ESNext ? "ESNext" : "CommonJS");
|
|
137
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Loads additional source paths from tsconfig.json's flink configuration.
|
|
159
|
+
* Allows projects to specify extra directories to include in compilation.
|
|
160
|
+
*
|
|
161
|
+
* Example tsconfig.json:
|
|
162
|
+
* {
|
|
163
|
+
* "flink": {
|
|
164
|
+
* "sourcePaths": ["src/custom-types/**\/*.ts", "src/utils/**\/*.ts"]
|
|
165
|
+
* }
|
|
166
|
+
* }
|
|
167
|
+
*/
|
|
168
|
+
TypeScriptCompiler.prototype.getFlinkSourcePaths = function (tsConfigPath) {
|
|
169
|
+
var _this = this;
|
|
170
|
+
try {
|
|
171
|
+
if (fs_1.default.existsSync(tsConfigPath)) {
|
|
172
|
+
var tsConfigContent = fs_1.default.readFileSync(tsConfigPath, "utf8");
|
|
173
|
+
var tsConfig = JSON.parse(tsConfigContent);
|
|
174
|
+
if (tsConfig.flink && Array.isArray(tsConfig.flink.sourcePaths)) {
|
|
175
|
+
console.log("Found Flink-specific source paths:", tsConfig.flink.sourcePaths);
|
|
176
|
+
return tsConfig.flink.sourcePaths.map(function (path) { return (0, path_1.join)(_this.cwd, path); });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.warn("Error reading Flink source paths from tsconfig.json:", error);
|
|
182
|
+
}
|
|
183
|
+
return [];
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Recursively resolves and adds imported files to the project.
|
|
187
|
+
* This ensures that files imported by handlers, schemas, etc. are available for type resolution.
|
|
188
|
+
*
|
|
189
|
+
* Handles three types of imports:
|
|
190
|
+
* 1. Relative imports (./foo, ../bar) - always resolved
|
|
191
|
+
* 2. Workspace package imports (@mycompany/shared) - resolved if symlinked outside node_modules
|
|
192
|
+
* 3. External packages (lodash, express) - skipped to avoid loading entire dependency trees
|
|
193
|
+
*/
|
|
194
|
+
TypeScriptCompiler.prototype.resolveImportedFiles = function () {
|
|
195
|
+
var processedFiles = new Set();
|
|
196
|
+
var filesToProcess = __spreadArray([], this.project.getSourceFiles(), true);
|
|
197
|
+
while (filesToProcess.length > 0) {
|
|
198
|
+
var sourceFile = filesToProcess.pop();
|
|
199
|
+
var filePath = sourceFile.getFilePath();
|
|
200
|
+
if (processedFiles.has(filePath)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
processedFiles.add(filePath);
|
|
204
|
+
// Get all import declarations
|
|
205
|
+
var importDeclarations = sourceFile.getImportDeclarations();
|
|
206
|
+
for (var _i = 0, importDeclarations_1 = importDeclarations; _i < importDeclarations_1.length; _i++) {
|
|
207
|
+
var importDecl = importDeclarations_1[_i];
|
|
208
|
+
var moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
209
|
+
// Try to resolve the imported file
|
|
210
|
+
var moduleSourceFile = importDecl.getModuleSpecifierSourceFile();
|
|
211
|
+
if (moduleSourceFile) {
|
|
212
|
+
var importedPath = moduleSourceFile.getFilePath();
|
|
213
|
+
// For relative imports (./foo, ../bar), always include
|
|
214
|
+
var isRelativeImport = moduleSpecifier.startsWith(".") || moduleSpecifier.startsWith("/");
|
|
215
|
+
// For package imports (@foo/bar, foo), check if resolved path is outside node_modules
|
|
216
|
+
// This handles workspace packages that are symlinked (pnpm, yarn workspaces)
|
|
217
|
+
var isWorkspacePackage = !isRelativeImport && !importedPath.includes("node_modules");
|
|
218
|
+
// Skip if it's in node_modules (external package) or already processed
|
|
219
|
+
if ((isRelativeImport || isWorkspacePackage) && !processedFiles.has(importedPath)) {
|
|
220
|
+
filesToProcess.push(moduleSourceFile);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
console.log("Resolved imports, total files loaded:", processedFiles.size);
|
|
226
|
+
};
|
|
138
227
|
/**
|
|
139
228
|
* Detects if the project is using ESM (ECMAScript Modules)
|
|
140
229
|
* by checking type in package.json.
|
|
@@ -244,6 +333,48 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
244
333
|
}
|
|
245
334
|
return true;
|
|
246
335
|
};
|
|
336
|
+
/**
|
|
337
|
+
* Finds a variable declaration by its TypeScript type name.
|
|
338
|
+
* This allows finding variables based on their type annotation rather than variable name.
|
|
339
|
+
*
|
|
340
|
+
* @param sf Source file to search in
|
|
341
|
+
* @param typeName Name of the type to search for (e.g., "FlinkToolProps", "FlinkAgentProps")
|
|
342
|
+
* @returns The first matching variable declaration, or undefined if not found
|
|
343
|
+
*/
|
|
344
|
+
TypeScriptCompiler.prototype.findVariableDeclarationByType = function (sf, typeName) {
|
|
345
|
+
var _a;
|
|
346
|
+
// Get all variable declarations from the source file
|
|
347
|
+
var variableDeclarations = sf.getVariableDeclarations();
|
|
348
|
+
for (var _i = 0, variableDeclarations_1 = variableDeclarations; _i < variableDeclarations_1.length; _i++) {
|
|
349
|
+
var varDecl = variableDeclarations_1[_i];
|
|
350
|
+
// Check if the variable is exported
|
|
351
|
+
var variableStatement = varDecl.getVariableStatement();
|
|
352
|
+
if (!(variableStatement === null || variableStatement === void 0 ? void 0 : variableStatement.isExported())) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
// Check if it's a const declaration
|
|
356
|
+
if (((_a = varDecl.getVariableStatement()) === null || _a === void 0 ? void 0 : _a.getDeclarationKind()) !== ts_morph_1.VariableDeclarationKind.Const) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
// Get the type node (explicit type annotation)
|
|
360
|
+
var typeNode = varDecl.getTypeNode();
|
|
361
|
+
if (!typeNode) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
// Check if it's a type reference
|
|
365
|
+
if (typeNode.getKind() === ts_morph_1.SyntaxKind.TypeReference) {
|
|
366
|
+
var typeRef = typeNode;
|
|
367
|
+
var typeRefName = typeRef.getTypeName();
|
|
368
|
+
// Handle both simple type references (FlinkToolProps) and qualified names (flink.FlinkToolProps)
|
|
369
|
+
var typeRefText = typeRefName.getText();
|
|
370
|
+
// Check if the type name matches (either exact match or ends with the type name for qualified references)
|
|
371
|
+
if (typeRefText === typeName || typeRefText.endsWith(".".concat(typeName))) {
|
|
372
|
+
return varDecl;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return undefined;
|
|
377
|
+
};
|
|
247
378
|
/**
|
|
248
379
|
* Scans project for handlers and add those to Flink
|
|
249
380
|
* "singleton" property `autoRegisteredHandlers` so they can
|
|
@@ -408,6 +539,217 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
408
539
|
});
|
|
409
540
|
});
|
|
410
541
|
};
|
|
542
|
+
/**
|
|
543
|
+
* Scans project for tools and adds those to Flink
|
|
544
|
+
* "singleton" property `autoRegisteredTools` so they can
|
|
545
|
+
* be registered during start.
|
|
546
|
+
*/
|
|
547
|
+
TypeScriptCompiler.prototype.parseTools = function () {
|
|
548
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
549
|
+
var generatedFile, toolsArr, imports, i, _i, _a, sf, namespaceImport, toolPropsVar, toolPropsExportName, existingFile;
|
|
550
|
+
return __generator(this, function (_b) {
|
|
551
|
+
switch (_b.label) {
|
|
552
|
+
case 0:
|
|
553
|
+
generatedFile = this.createSourceFile(["generatedTools.ts"], "// Generated ".concat(new Date(), "\nimport { autoRegisteredTools } from \"@flink-app/flink\";\nexport const tools = [];\nautoRegisteredTools.push(...tools);\n "));
|
|
554
|
+
toolsArr = generatedFile.getVariableDeclarationOrThrow("tools").getFirstDescendantByKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
555
|
+
imports = [];
|
|
556
|
+
i = 0;
|
|
557
|
+
for (_i = 0, _a = this.project.getSourceFiles(); _i < _a.length; _i++) {
|
|
558
|
+
sf = _a[_i];
|
|
559
|
+
if (!sf.getFilePath().includes("src/tools/")) {
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
console.log("Detected tool ".concat(sf.getBaseName()));
|
|
563
|
+
namespaceImport = sf.getBaseNameWithoutExtension().replace(/\./g, "_") + "_" + i;
|
|
564
|
+
imports.push({
|
|
565
|
+
defaultImport: "* as " + namespaceImport,
|
|
566
|
+
moduleSpecifier: this.getModuleSpecifier(generatedFile, sf),
|
|
567
|
+
});
|
|
568
|
+
toolPropsVar = this.findVariableDeclarationByType(sf, "FlinkToolProps");
|
|
569
|
+
toolPropsExportName = (toolPropsVar === null || toolPropsVar === void 0 ? void 0 : toolPropsVar.getName()) || "Tool";
|
|
570
|
+
existingFile = sf.getVariableStatements().filter(function (vs) {
|
|
571
|
+
var varNames = vs.getDeclarations().map(function (d) { return d.getName(); });
|
|
572
|
+
return varNames.includes("__file");
|
|
573
|
+
});
|
|
574
|
+
existingFile.forEach(function (v) { return v.remove(); });
|
|
575
|
+
// Append metadata to source file
|
|
576
|
+
sf.addVariableStatement({
|
|
577
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
578
|
+
isExported: true,
|
|
579
|
+
declarations: [
|
|
580
|
+
{
|
|
581
|
+
name: "__file",
|
|
582
|
+
initializer: "\"".concat(sf.getBaseName(), "\""),
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
});
|
|
586
|
+
// Create an object that wraps the namespace and provides named access to the tool props
|
|
587
|
+
toolsArr.insertElement(i, "{...".concat(namespaceImport, ", Tool: ").concat(namespaceImport, ".").concat(toolPropsExportName, "}"));
|
|
588
|
+
i++;
|
|
589
|
+
}
|
|
590
|
+
generatedFile.addImportDeclarations(imports);
|
|
591
|
+
return [4 /*yield*/, generatedFile.save()];
|
|
592
|
+
case 1:
|
|
593
|
+
_b.sent();
|
|
594
|
+
return [2 /*return*/, generatedFile];
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
};
|
|
599
|
+
/**
|
|
600
|
+
* Scans project for agents and validates tool references.
|
|
601
|
+
* Agents are declarative (no default function).
|
|
602
|
+
*/
|
|
603
|
+
TypeScriptCompiler.prototype.parseAgents = function () {
|
|
604
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
605
|
+
var generatedFile, agentsArr, imports, registeredToolIds, _i, _a, sf, toolExport, props, idProp, idValue, i, _b, _c, sf, agentClass, toolsProperty, initializer, toolsArray, toolElements, _loop_1, _d, toolElements_1, toolElement, className, existingFile;
|
|
606
|
+
var _e;
|
|
607
|
+
return __generator(this, function (_f) {
|
|
608
|
+
switch (_f.label) {
|
|
609
|
+
case 0:
|
|
610
|
+
generatedFile = this.createSourceFile(["generatedAgents.ts"], "// Generated ".concat(new Date(), "\nimport { autoRegisteredAgents } from \"@flink-app/flink\";\nexport const agents = [];\nautoRegisteredAgents.push(...agents);\n "));
|
|
611
|
+
agentsArr = generatedFile.getVariableDeclarationOrThrow("agents").getFirstDescendantByKindOrThrow(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
612
|
+
imports = [];
|
|
613
|
+
registeredToolIds = new Set();
|
|
614
|
+
for (_i = 0, _a = this.project.getSourceFiles(); _i < _a.length; _i++) {
|
|
615
|
+
sf = _a[_i];
|
|
616
|
+
if (sf.getFilePath().includes("src/tools/")) {
|
|
617
|
+
toolExport = this.findVariableDeclarationByType(sf, "FlinkToolProps");
|
|
618
|
+
if (toolExport) {
|
|
619
|
+
props = toolExport.getFirstDescendantByKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
620
|
+
idProp = (props === null || props === void 0 ? void 0 : props.getProperty("id")) || (props === null || props === void 0 ? void 0 : props.getProperty("name"));
|
|
621
|
+
if (idProp) {
|
|
622
|
+
idValue = idProp.getLastChildByKind(ts_morph_1.SyntaxKind.StringLiteral);
|
|
623
|
+
if (idValue) {
|
|
624
|
+
registeredToolIds.add(idValue.getLiteralText());
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
i = 0;
|
|
631
|
+
for (_b = 0, _c = this.project.getSourceFiles(); _b < _c.length; _b++) {
|
|
632
|
+
sf = _c[_b];
|
|
633
|
+
if (!sf.getFilePath().includes("src/agents/")) {
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
agentClass = sf.getClasses().find(function (cls) {
|
|
637
|
+
var baseClass = cls.getBaseClass();
|
|
638
|
+
return (baseClass === null || baseClass === void 0 ? void 0 : baseClass.getName()) === "FlinkAgent";
|
|
639
|
+
});
|
|
640
|
+
if (!agentClass) {
|
|
641
|
+
// Skip files without FlinkAgent class
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
console.log("Detected agent ".concat(sf.getBaseName()));
|
|
645
|
+
toolsProperty = agentClass.getProperty("tools");
|
|
646
|
+
if (toolsProperty) {
|
|
647
|
+
initializer = toolsProperty.getInitializer();
|
|
648
|
+
if (initializer && initializer.getKind() === ts_morph_1.SyntaxKind.ArrayLiteralExpression) {
|
|
649
|
+
toolsArray = initializer;
|
|
650
|
+
toolElements = toolsArray.getElements();
|
|
651
|
+
_loop_1 = function (toolElement) {
|
|
652
|
+
var toolName = void 0;
|
|
653
|
+
// Handle string literals, method calls, and identifier references (tool imports)
|
|
654
|
+
if (toolElement.getKind() === ts_morph_1.SyntaxKind.StringLiteral) {
|
|
655
|
+
// Direct string: "tool-name"
|
|
656
|
+
toolName = toolElement.getText().replace(/['"]/g, "");
|
|
657
|
+
}
|
|
658
|
+
else if (toolElement.getKind() === ts_morph_1.SyntaxKind.CallExpression) {
|
|
659
|
+
// Method call: this.useTool("tool-name")
|
|
660
|
+
var args = toolElement.getArguments();
|
|
661
|
+
if (args.length > 0 && args[0].getKind() === ts_morph_1.SyntaxKind.StringLiteral) {
|
|
662
|
+
toolName = args[0].getText().replace(/['"]/g, "");
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
console.warn("Agent ".concat(sf.getBaseName(), " has non-string tool reference, skipping validation"));
|
|
666
|
+
return "continue";
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else if (toolElement.getKind() === ts_morph_1.SyntaxKind.Identifier) {
|
|
670
|
+
// Tool file reference (imported): SearchCarsByBrandTool
|
|
671
|
+
// Look up the import to find the actual tool file
|
|
672
|
+
var importName_1 = toolElement.getText();
|
|
673
|
+
var importDecl = sf.getImportDeclarations().find(function (imp) {
|
|
674
|
+
var namedImports = imp.getNamedImports();
|
|
675
|
+
return namedImports.some(function (ni) { return ni.getName() === importName_1; });
|
|
676
|
+
});
|
|
677
|
+
if (!importDecl) {
|
|
678
|
+
// Try namespace import (* as Foo)
|
|
679
|
+
var namespaceImport = sf.getImportDeclarations().find(function (imp) {
|
|
680
|
+
var _a;
|
|
681
|
+
return ((_a = imp.getNamespaceImport()) === null || _a === void 0 ? void 0 : _a.getText()) === importName_1;
|
|
682
|
+
});
|
|
683
|
+
if (namespaceImport) {
|
|
684
|
+
var moduleSpecifier = namespaceImport.getModuleSpecifierValue();
|
|
685
|
+
// Extract tool ID from the tool file path
|
|
686
|
+
// e.g., "../tools/SearchCarsByBrandTool" -> find in registeredToolIds
|
|
687
|
+
var toolFileName = (_e = moduleSpecifier.split("/").pop()) === null || _e === void 0 ? void 0 : _e.replace(/\.ts$/, "");
|
|
688
|
+
var matchingTool = Array.from(registeredToolIds).find(function (id) {
|
|
689
|
+
// Try to match by searching for the tool ID
|
|
690
|
+
// This is a heuristic - we'll validate it exists
|
|
691
|
+
return true; // Skip validation for imported tools for now
|
|
692
|
+
});
|
|
693
|
+
return "continue";
|
|
694
|
+
}
|
|
695
|
+
console.warn("Agent ".concat(sf.getBaseName(), " references tool \"").concat(importName_1, "\" but it's not imported, skipping validation"));
|
|
696
|
+
return "continue";
|
|
697
|
+
}
|
|
698
|
+
return "continue";
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
console.warn("Agent ".concat(sf.getBaseName(), " has unexpected tool reference format: ").concat(toolElement.getText()));
|
|
702
|
+
return "continue";
|
|
703
|
+
}
|
|
704
|
+
if (!registeredToolIds.has(toolName)) {
|
|
705
|
+
console.error("Agent ".concat(sf.getBaseName(), " references tool \"").concat(toolName, "\" which does not exist"));
|
|
706
|
+
throw new Error("Invalid tool reference in agent ".concat(sf.getBaseName()));
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
for (_d = 0, toolElements_1 = toolElements; _d < toolElements_1.length; _d++) {
|
|
710
|
+
toolElement = toolElements_1[_d];
|
|
711
|
+
_loop_1(toolElement);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
className = agentClass.getName();
|
|
716
|
+
if (!className) {
|
|
717
|
+
console.error("Agent class in ".concat(sf.getBaseName(), " has no name"));
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
imports.push({
|
|
721
|
+
defaultImport: className,
|
|
722
|
+
moduleSpecifier: this.getModuleSpecifier(generatedFile, sf),
|
|
723
|
+
});
|
|
724
|
+
existingFile = sf.getVariableStatements().filter(function (vs) {
|
|
725
|
+
var varNames = vs.getDeclarations().map(function (d) { return d.getName(); });
|
|
726
|
+
return varNames.includes("__file");
|
|
727
|
+
});
|
|
728
|
+
existingFile.forEach(function (v) { return v.remove(); });
|
|
729
|
+
// Append metadata
|
|
730
|
+
sf.addVariableStatement({
|
|
731
|
+
declarationKind: ts_morph_1.VariableDeclarationKind.Const,
|
|
732
|
+
isExported: true,
|
|
733
|
+
declarations: [
|
|
734
|
+
{
|
|
735
|
+
name: "__file",
|
|
736
|
+
initializer: "\"".concat(sf.getBaseName(), "\""),
|
|
737
|
+
},
|
|
738
|
+
],
|
|
739
|
+
});
|
|
740
|
+
// Register the agent class
|
|
741
|
+
agentsArr.insertElement(i, "{ default: ".concat(className, ", __file: \"").concat(sf.getBaseName(), "\" }"));
|
|
742
|
+
i++;
|
|
743
|
+
}
|
|
744
|
+
generatedFile.addImportDeclarations(imports);
|
|
745
|
+
return [4 /*yield*/, generatedFile.save()];
|
|
746
|
+
case 1:
|
|
747
|
+
_f.sent();
|
|
748
|
+
return [2 /*return*/, generatedFile];
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
});
|
|
752
|
+
};
|
|
411
753
|
/**
|
|
412
754
|
* Generates a start script that will import references to handlers, repos and the
|
|
413
755
|
* actual Flink app to start.
|
|
@@ -426,7 +768,7 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
426
768
|
console.error("Cannot find entry script '".concat(appEntryScript, "'"));
|
|
427
769
|
return [2 /*return*/, process.exit(1)];
|
|
428
770
|
}
|
|
429
|
-
sf = this.createSourceFile(["start.ts"], "// Generated ".concat(new Date(), "\nimport \"./generatedHandlers").concat(this.isEsm ? ".js" : "", "\";\nimport \"./generatedRepos").concat(this.isEsm ? ".js" : "", "\";\nimport \"./generatedJobs").concat(this.isEsm ? ".js" : "", "\";\nimport \"..").concat(appEntryScript.replace(/\.ts/g, "")).concat(this.isEsm ? ".js" : "", "\";\nexport default {}; // Export an empty object to make it a module\n"));
|
|
771
|
+
sf = this.createSourceFile(["start.ts"], "// Generated ".concat(new Date(), "\nimport \"./generatedHandlers").concat(this.isEsm ? ".js" : "", "\";\nimport \"./generatedRepos").concat(this.isEsm ? ".js" : "", "\";\nimport \"./generatedTools").concat(this.isEsm ? ".js" : "", "\";\nimport \"./generatedAgents").concat(this.isEsm ? ".js" : "", "\";\nimport \"./generatedJobs").concat(this.isEsm ? ".js" : "", "\";\nimport \"..").concat(appEntryScript.replace(/\.ts/g, "")).concat(this.isEsm ? ".js" : "", "\";\nexport default {}; // Export an empty object to make it a module\n"));
|
|
430
772
|
return [4 /*yield*/, sf.save()];
|
|
431
773
|
case 1:
|
|
432
774
|
_a.sent();
|
|
@@ -528,7 +870,7 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
528
870
|
return [2 /*return*/]; // 'any' indicates that no schema is used
|
|
529
871
|
}
|
|
530
872
|
schemaText = schema.getText();
|
|
531
|
-
if (schemaText ===
|
|
873
|
+
if (schemaText === "void" || schemaText === "undefined") {
|
|
532
874
|
return [2 /*return*/];
|
|
533
875
|
}
|
|
534
876
|
handlerFileName = handlerFile.getBaseNameWithoutExtension().replace(/\./g, "_");
|
|
@@ -564,7 +906,7 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
564
906
|
if (interfaceNameMatches) {
|
|
565
907
|
for (_d = 0, interfaceNameMatches_1 = interfaceNameMatches; _d < interfaceNameMatches_1.length; _d++) {
|
|
566
908
|
match = interfaceNameMatches_1[_d];
|
|
567
|
-
referencedInterfaceName = match.replace(/\s*\[$/,
|
|
909
|
+
referencedInterfaceName = match.replace(/\s*\[$/, "").trim();
|
|
568
910
|
referencedInterfaceDecl = handlerFile.getInterface(referencedInterfaceName) || handlerFile.getTypeAlias(referencedInterfaceName);
|
|
569
911
|
if (referencedInterfaceDecl) {
|
|
570
912
|
// Interface is in same file - copy it and all its dependencies recursively
|
|
@@ -663,7 +1005,7 @@ var TypeScriptCompiler = /** @class */ (function () {
|
|
|
663
1005
|
if (interfaceNameMatches) {
|
|
664
1006
|
for (_j = 0, interfaceNameMatches_2 = interfaceNameMatches; _j < interfaceNameMatches_2.length; _j++) {
|
|
665
1007
|
match = interfaceNameMatches_2[_j];
|
|
666
|
-
interfaceName = match.replace(/\s*\[$/,
|
|
1008
|
+
interfaceName = match.replace(/\s*\[$/, "").trim();
|
|
667
1009
|
interfaceDecl = handlerFile.getInterface(interfaceName) || handlerFile.getTypeAlias(interfaceName);
|
|
668
1010
|
if (interfaceDecl) {
|
|
669
1011
|
// Interface is in same file - copy it and all its dependencies recursively
|
|
@@ -191,6 +191,10 @@ function getTypeMetadata(type) {
|
|
|
191
191
|
if (!type || ["void", "any"].includes(type.getText())) {
|
|
192
192
|
return [];
|
|
193
193
|
}
|
|
194
|
+
// Handle empty object literal {} (used in streaming handlers)
|
|
195
|
+
if (type.getText() === "{}") {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
194
198
|
var symbol = getSymbolOrAlias(type);
|
|
195
199
|
if (!symbol) {
|
|
196
200
|
throw new Error("Could not get type symbol for type: " + type.getText());
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FlinkAgentProps, AgentExecuteInput, StreamChunk } from "./FlinkAgent";
|
|
2
|
+
import { ToolExecutor } from "./ToolExecutor";
|
|
3
|
+
import { LLMAdapter } from "./LLMAdapter";
|
|
4
|
+
export declare class AgentRunner {
|
|
5
|
+
private agentProps;
|
|
6
|
+
private tools;
|
|
7
|
+
private agentName?;
|
|
8
|
+
private llmAdapter;
|
|
9
|
+
private maxTokens;
|
|
10
|
+
private temperature;
|
|
11
|
+
private maxSteps;
|
|
12
|
+
private timeoutMs;
|
|
13
|
+
private maxSubAgentDepth;
|
|
14
|
+
constructor(agentProps: FlinkAgentProps, tools: Map<string, ToolExecutor<any>>, llmAdapters: Map<string, LLMAdapter>, agentName?: string | undefined);
|
|
15
|
+
/**
|
|
16
|
+
* Phase 1: Stream generator that yields complete event on finish
|
|
17
|
+
* Phase 2: Will yield text_delta and tool events during execution
|
|
18
|
+
*/
|
|
19
|
+
streamGenerator(input: AgentExecuteInput): AsyncGenerator<StreamChunk>;
|
|
20
|
+
/**
|
|
21
|
+
* Convert Message[] to LLM message format
|
|
22
|
+
* Supports multi-turn conversations with history
|
|
23
|
+
*/
|
|
24
|
+
private convertMessages;
|
|
25
|
+
private getToolSchemas;
|
|
26
|
+
/**
|
|
27
|
+
* Filter tools based on user permissions
|
|
28
|
+
* Only returns schemas for tools the user has permission to use
|
|
29
|
+
*
|
|
30
|
+
* @param user - User object
|
|
31
|
+
* @param userPermissions - Optional resolved permissions from auth plugin (preferred)
|
|
32
|
+
*/
|
|
33
|
+
private filterToolsByPermissions;
|
|
34
|
+
/**
|
|
35
|
+
* Build delegation chain from metadata for error messages
|
|
36
|
+
* Extracts parent agent IDs to show the full call stack
|
|
37
|
+
*/
|
|
38
|
+
private buildDelegationChain;
|
|
39
|
+
}
|