@x12i/ai-gateway 7.9.1
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/README.md +4259 -0
- package/config.defaults.json +31 -0
- package/dist/activity-manager.d.ts +206 -0
- package/dist/activity-manager.js +1051 -0
- package/dist/config/activity-tracking-config.d.ts +11 -0
- package/dist/config/activity-tracking-config.js +15 -0
- package/dist/config.defaults.json +31 -0
- package/dist/content-normalizer/content-normalizer.d.ts +46 -0
- package/dist/content-normalizer/content-normalizer.js +393 -0
- package/dist/content-normalizer/index.d.ts +7 -0
- package/dist/content-normalizer/index.js +6 -0
- package/dist/content-normalizer/types.d.ts +33 -0
- package/dist/content-normalizer/types.js +4 -0
- package/dist/defaults/instructions-blocks.json +61 -0
- package/dist/defaults/model-config.json +16 -0
- package/dist/defaults/template-rendering.json +6 -0
- package/dist/flex-md-loader.d.ts +109 -0
- package/dist/flex-md-loader.js +940 -0
- package/dist/gateway-config.d.ts +49 -0
- package/dist/gateway-config.js +292 -0
- package/dist/gateway-conversion.d.ts +29 -0
- package/dist/gateway-conversion.js +174 -0
- package/dist/gateway-instructions.d.ts +30 -0
- package/dist/gateway-instructions.js +62 -0
- package/dist/gateway-memory.d.ts +51 -0
- package/dist/gateway-memory.js +207 -0
- package/dist/gateway-messages.d.ts +23 -0
- package/dist/gateway-messages.js +83 -0
- package/dist/gateway-meta.d.ts +25 -0
- package/dist/gateway-meta.js +87 -0
- package/dist/gateway-provider-auto-register.d.ts +17 -0
- package/dist/gateway-provider-auto-register.js +159 -0
- package/dist/gateway-provider.d.ts +54 -0
- package/dist/gateway-provider.js +202 -0
- package/dist/gateway-rate-limiter-constants.d.ts +16 -0
- package/dist/gateway-rate-limiter-constants.js +16 -0
- package/dist/gateway-rate-limiter.d.ts +56 -0
- package/dist/gateway-rate-limiter.js +107 -0
- package/dist/gateway-retry.d.ts +49 -0
- package/dist/gateway-retry.js +204 -0
- package/dist/gateway-utils.d.ts +21 -0
- package/dist/gateway-utils.js +181 -0
- package/dist/gateway-validation.d.ts +13 -0
- package/dist/gateway-validation.js +50 -0
- package/dist/gateway.d.ts +39 -0
- package/dist/gateway.js +430 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +55 -0
- package/dist/instruction-errors.d.ts +16 -0
- package/dist/instruction-errors.js +29 -0
- package/dist/instruction-optimizer.d.ts +113 -0
- package/dist/instruction-optimizer.js +293 -0
- package/dist/instructions-parser.d.ts +31 -0
- package/dist/instructions-parser.js +56 -0
- package/dist/logger-factory.d.ts +17 -0
- package/dist/logger-factory.js +42 -0
- package/dist/message-builder.d.ts +41 -0
- package/dist/message-builder.js +522 -0
- package/dist/object-types-library-integration.d.ts +22 -0
- package/dist/object-types-library-integration.js +27 -0
- package/dist/object-types-library.d.ts +351 -0
- package/dist/object-types-library.js +210 -0
- package/dist/output-auditor.d.ts +44 -0
- package/dist/output-auditor.js +49 -0
- package/dist/request-report-generator.d.ts +60 -0
- package/dist/request-report-generator.js +169 -0
- package/dist/response-analyzer/format-type-detector.d.ts +35 -0
- package/dist/response-analyzer/format-type-detector.js +115 -0
- package/dist/response-analyzer/index.d.ts +9 -0
- package/dist/response-analyzer/index.js +8 -0
- package/dist/response-analyzer/object-type-detector.d.ts +42 -0
- package/dist/response-analyzer/object-type-detector.js +95 -0
- package/dist/response-analyzer/response-analyzer.d.ts +38 -0
- package/dist/response-analyzer/response-analyzer.js +97 -0
- package/dist/response-analyzer/types.d.ts +97 -0
- package/dist/response-analyzer/types.js +4 -0
- package/dist/response-fallback-fixer.d.ts +11 -0
- package/dist/response-fallback-fixer.js +123 -0
- package/dist/runtime-objects.d.ts +52 -0
- package/dist/runtime-objects.js +46 -0
- package/dist/template-parser.d.ts +58 -0
- package/dist/template-parser.js +99 -0
- package/dist/template-render-merge.d.ts +9 -0
- package/dist/template-render-merge.js +40 -0
- package/dist/troubleshooting-helper.d.ts +123 -0
- package/dist/troubleshooting-helper.js +596 -0
- package/dist/types.d.ts +1173 -0
- package/dist/types.js +6 -0
- package/dist/usage-tracker.d.ts +78 -0
- package/dist/usage-tracker.js +79 -0
- package/dist-cjs/activity-manager.cjs +1056 -0
- package/dist-cjs/activity-manager.d.ts +206 -0
- package/dist-cjs/config/activity-tracking-config.cjs +18 -0
- package/dist-cjs/config/activity-tracking-config.d.ts +11 -0
- package/dist-cjs/config.defaults.json +31 -0
- package/dist-cjs/content-normalizer/content-normalizer.cjs +398 -0
- package/dist-cjs/content-normalizer/content-normalizer.d.ts +46 -0
- package/dist-cjs/content-normalizer/index.cjs +12 -0
- package/dist-cjs/content-normalizer/index.d.ts +7 -0
- package/dist-cjs/content-normalizer/types.cjs +5 -0
- package/dist-cjs/content-normalizer/types.d.ts +33 -0
- package/dist-cjs/defaults/instructions-blocks.json +61 -0
- package/dist-cjs/defaults/model-config.json +16 -0
- package/dist-cjs/defaults/template-rendering.json +6 -0
- package/dist-cjs/flex-md-loader.cjs +986 -0
- package/dist-cjs/flex-md-loader.d.ts +109 -0
- package/dist-cjs/gateway-config.cjs +331 -0
- package/dist-cjs/gateway-config.d.ts +49 -0
- package/dist-cjs/gateway-conversion.cjs +212 -0
- package/dist-cjs/gateway-conversion.d.ts +29 -0
- package/dist-cjs/gateway-instructions.cjs +67 -0
- package/dist-cjs/gateway-instructions.d.ts +30 -0
- package/dist-cjs/gateway-memory.cjs +211 -0
- package/dist-cjs/gateway-memory.d.ts +51 -0
- package/dist-cjs/gateway-messages.cjs +86 -0
- package/dist-cjs/gateway-messages.d.ts +23 -0
- package/dist-cjs/gateway-meta.cjs +90 -0
- package/dist-cjs/gateway-meta.d.ts +25 -0
- package/dist-cjs/gateway-provider-auto-register.cjs +195 -0
- package/dist-cjs/gateway-provider-auto-register.d.ts +17 -0
- package/dist-cjs/gateway-provider.cjs +214 -0
- package/dist-cjs/gateway-provider.d.ts +54 -0
- package/dist-cjs/gateway-rate-limiter-constants.cjs +19 -0
- package/dist-cjs/gateway-rate-limiter-constants.d.ts +16 -0
- package/dist-cjs/gateway-rate-limiter.cjs +111 -0
- package/dist-cjs/gateway-rate-limiter.d.ts +56 -0
- package/dist-cjs/gateway-retry.cjs +212 -0
- package/dist-cjs/gateway-retry.d.ts +49 -0
- package/dist-cjs/gateway-utils.cjs +219 -0
- package/dist-cjs/gateway-utils.d.ts +21 -0
- package/dist-cjs/gateway-validation.cjs +54 -0
- package/dist-cjs/gateway-validation.d.ts +13 -0
- package/dist-cjs/gateway.cjs +434 -0
- package/dist-cjs/gateway.d.ts +39 -0
- package/dist-cjs/index.cjs +108 -0
- package/dist-cjs/index.d.ts +36 -0
- package/dist-cjs/instruction-errors.cjs +34 -0
- package/dist-cjs/instruction-errors.d.ts +16 -0
- package/dist-cjs/instruction-optimizer.cjs +299 -0
- package/dist-cjs/instruction-optimizer.d.ts +113 -0
- package/dist-cjs/instructions-parser.cjs +61 -0
- package/dist-cjs/instructions-parser.d.ts +31 -0
- package/dist-cjs/logger-factory.cjs +45 -0
- package/dist-cjs/logger-factory.d.ts +17 -0
- package/dist-cjs/message-builder.cjs +558 -0
- package/dist-cjs/message-builder.d.ts +41 -0
- package/dist-cjs/object-types-library-integration.cjs +32 -0
- package/dist-cjs/object-types-library-integration.d.ts +22 -0
- package/dist-cjs/object-types-library.cjs +215 -0
- package/dist-cjs/object-types-library.d.ts +351 -0
- package/dist-cjs/output-auditor.cjs +52 -0
- package/dist-cjs/output-auditor.d.ts +44 -0
- package/dist-cjs/request-report-generator.cjs +172 -0
- package/dist-cjs/request-report-generator.d.ts +60 -0
- package/dist-cjs/response-analyzer/format-type-detector.cjs +119 -0
- package/dist-cjs/response-analyzer/format-type-detector.d.ts +35 -0
- package/dist-cjs/response-analyzer/index.cjs +14 -0
- package/dist-cjs/response-analyzer/index.d.ts +9 -0
- package/dist-cjs/response-analyzer/object-type-detector.cjs +99 -0
- package/dist-cjs/response-analyzer/object-type-detector.d.ts +42 -0
- package/dist-cjs/response-analyzer/response-analyzer.cjs +101 -0
- package/dist-cjs/response-analyzer/response-analyzer.d.ts +38 -0
- package/dist-cjs/response-analyzer/types.cjs +5 -0
- package/dist-cjs/response-analyzer/types.d.ts +97 -0
- package/dist-cjs/response-fallback-fixer.cjs +126 -0
- package/dist-cjs/response-fallback-fixer.d.ts +11 -0
- package/dist-cjs/runtime-objects.cjs +52 -0
- package/dist-cjs/runtime-objects.d.ts +52 -0
- package/dist-cjs/template-parser.cjs +136 -0
- package/dist-cjs/template-parser.d.ts +58 -0
- package/dist-cjs/template-render-merge.cjs +43 -0
- package/dist-cjs/template-render-merge.d.ts +9 -0
- package/dist-cjs/troubleshooting-helper.cjs +611 -0
- package/dist-cjs/troubleshooting-helper.d.ts +123 -0
- package/dist-cjs/types.cjs +7 -0
- package/dist-cjs/types.d.ts +1173 -0
- package/dist-cjs/usage-tracker.cjs +83 -0
- package/dist-cjs/usage-tracker.d.ts +78 -0
- package/package.json +91 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages activity tracking for LLM requests.
|
|
5
|
+
* Wraps the ActivityTracker and provides convenience methods.
|
|
6
|
+
*/
|
|
7
|
+
import { Activix } from '@x12i/activix';
|
|
8
|
+
import type { Logxer } from '@x12i/logxer';
|
|
9
|
+
import type { ActivityIdentity, ChatRequest, AIRequest, FailureType, LLMResponseFailureSubtype, ResponseParsingFailureSubtype } from './types.js';
|
|
10
|
+
type Request = ChatRequest | AIRequest;
|
|
11
|
+
/**
|
|
12
|
+
* Normalizes and attaches the gateway `identity` envelope on the request (Activix + router correlation).
|
|
13
|
+
* Call at the API boundary before the router when activity tracking is off, and used internally when it is on.
|
|
14
|
+
*
|
|
15
|
+
* **Execution context:** treats `request.identity` as received from upstream. Root fields (`sessionId`,
|
|
16
|
+
* `instance`, and any keys already set on that object) are not replaced by gateway defaults; the gateway
|
|
17
|
+
* only fills missing required pieces and adds local context (e.g. graph linkage) where absent.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensureGatewayRequestIdentity(request: ChatRequest | AIRequest, extras?: Partial<ActivityIdentity>): ActivityIdentity;
|
|
20
|
+
type ActivityMetadata = Record<string, any> & {
|
|
21
|
+
activityId?: string;
|
|
22
|
+
recordId?: string;
|
|
23
|
+
aiRequestId: string;
|
|
24
|
+
runContext?: ActivityIdentity;
|
|
25
|
+
status?: string;
|
|
26
|
+
activityType?: string;
|
|
27
|
+
};
|
|
28
|
+
export interface ActivityManagerConfig {
|
|
29
|
+
enableActivityTracking: boolean;
|
|
30
|
+
customTracker?: Activix;
|
|
31
|
+
logger: Logxer;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Manages activity tracking lifecycle
|
|
35
|
+
*/
|
|
36
|
+
export declare class ActivityManager {
|
|
37
|
+
private activix?;
|
|
38
|
+
private initPromise?;
|
|
39
|
+
private mainCollectionName?;
|
|
40
|
+
private skillExecutionsCollectionName;
|
|
41
|
+
private badRequestsCollectionName?;
|
|
42
|
+
private logger;
|
|
43
|
+
constructor(config: ActivityManagerConfig);
|
|
44
|
+
/**
|
|
45
|
+
* Gets upstream-provided AI request ID
|
|
46
|
+
*
|
|
47
|
+
* @param request - Enhanced LLM request
|
|
48
|
+
* @returns AI request ID string
|
|
49
|
+
*/
|
|
50
|
+
generateJobId(request: Request): string;
|
|
51
|
+
/**
|
|
52
|
+
* Starts activity tracking for a request
|
|
53
|
+
*
|
|
54
|
+
* IMPORTANT: This method ONLY sends REQUEST data (no response).
|
|
55
|
+
* The same record will be updated later via logSuccess() or logFailure()
|
|
56
|
+
* with response/timing data.
|
|
57
|
+
*
|
|
58
|
+
* KEY CONCEPT: jobId is NOT the unique identifier!
|
|
59
|
+
* - jobId = entire job (can have 100+ activities sharing the same jobId)
|
|
60
|
+
* - taskId = task within a job (can have multiple activities)
|
|
61
|
+
* - Each activity gets its own unique identifier (_id/recordId) from ActivityTracker
|
|
62
|
+
* - The returned ActivityMetadata contains this unique identifier for later updates
|
|
63
|
+
*
|
|
64
|
+
* This ensures:
|
|
65
|
+
* - On start: Only request data is stored → creates NEW record with unique _id
|
|
66
|
+
* - On finish: Only response data is added → updates SAME record by _id/recordId
|
|
67
|
+
* - No duplication: Request data sent once, response data sent once
|
|
68
|
+
* - Multiple activities per job: Each activity is a separate record, grouped by jobId
|
|
69
|
+
*
|
|
70
|
+
* @param request - Enhanced LLM request
|
|
71
|
+
* @param startTime - Request start timestamp
|
|
72
|
+
* @returns Activity metadata (contains unique _id/recordId) or undefined if tracking is disabled
|
|
73
|
+
*/
|
|
74
|
+
startActivity(request: Request, startTime: number): Promise<ActivityMetadata | undefined>;
|
|
75
|
+
/**
|
|
76
|
+
* Starts skill execution activity tracking
|
|
77
|
+
*
|
|
78
|
+
* Similar to startActivity() but creates a skill-execution activity record instead of gateway-invocation.
|
|
79
|
+
* Skill executions are tracked separately and stored in the 'skill-executions' collection.
|
|
80
|
+
*
|
|
81
|
+
* @param request - Enhanced LLM request (must be a skill execution)
|
|
82
|
+
* @param instructionMetadata - Optional audit fields when caller tracks instruction catalog info
|
|
83
|
+
* @param startTime - Request start timestamp
|
|
84
|
+
* @returns Activity metadata (contains unique _id/recordId) or undefined if tracking is disabled
|
|
85
|
+
*/
|
|
86
|
+
startSkillExecution(request: Request, instructionMetadata: {
|
|
87
|
+
key?: string;
|
|
88
|
+
version?: string;
|
|
89
|
+
rawContent?: string;
|
|
90
|
+
} | undefined, startTime: number): Promise<ActivityMetadata | undefined>;
|
|
91
|
+
/**
|
|
92
|
+
* Logs successful activity completion
|
|
93
|
+
*
|
|
94
|
+
* IMPORTANT: This method ONLY sends RESPONSE/TIMING data (no request data).
|
|
95
|
+
* It updates the SAME record created by startActivity() using the unique record identifier.
|
|
96
|
+
*
|
|
97
|
+
* KEY CONCEPT: jobId is NOT the unique identifier!
|
|
98
|
+
* - jobId = entire job (can have 100+ activities sharing the same jobId)
|
|
99
|
+
* - taskId = task within a job (can have multiple activities)
|
|
100
|
+
* - Each activity has its own unique identifier (_id/recordId) returned by startActivity()
|
|
101
|
+
*
|
|
102
|
+
* This ensures:
|
|
103
|
+
* - On start: Only request data is stored (via startActivity) → creates new record with unique _id
|
|
104
|
+
* - On finish: Only response data is added (via logSuccess) → updates same record by _id/recordId
|
|
105
|
+
* - No duplication: Request data sent once, response data sent once
|
|
106
|
+
* - Same record: Updated by unique identifier (_id/recordId), NOT by jobId
|
|
107
|
+
*
|
|
108
|
+
* Structure sent to ActivityTracker:
|
|
109
|
+
* - response: { content, metadata } (response object)
|
|
110
|
+
* - endTime, duration (timing completion)
|
|
111
|
+
* - cost (cost calculation)
|
|
112
|
+
* - status: 'success' (updated by ActivityTracker)
|
|
113
|
+
* - NO request data (already stored in startActivity)
|
|
114
|
+
* - NO config data (already stored in startActivity)
|
|
115
|
+
*
|
|
116
|
+
* @param activity - Activity metadata from startActivity() (contains unique _id/recordId for record lookup)
|
|
117
|
+
* @param details - Success details (cost, response, timing)
|
|
118
|
+
*/
|
|
119
|
+
logSuccess(activity: ActivityMetadata | undefined, details: {
|
|
120
|
+
cost?: number;
|
|
121
|
+
response: any;
|
|
122
|
+
endTime: number;
|
|
123
|
+
duration: number;
|
|
124
|
+
}): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Logs failed activity
|
|
127
|
+
*
|
|
128
|
+
* IMPORTANT: This method ONLY sends ERROR/TIMING data (no request/response data).
|
|
129
|
+
* It updates the SAME record created by startActivity() using the unique record identifier.
|
|
130
|
+
*
|
|
131
|
+
* KEY CONCEPT: jobId is NOT the unique identifier!
|
|
132
|
+
* - jobId = entire job (can have 100+ activities sharing the same jobId)
|
|
133
|
+
* - taskId = task within a job (can have multiple activities)
|
|
134
|
+
* - Each activity has its own unique identifier (_id/recordId) returned by startActivity()
|
|
135
|
+
*
|
|
136
|
+
* Structure sent to ActivityTracker:
|
|
137
|
+
* - error (error message)
|
|
138
|
+
* - endTime, duration (timing completion)
|
|
139
|
+
* - status: 'failed' (updated by ActivityTracker)
|
|
140
|
+
* - NO request data (already stored in startActivity)
|
|
141
|
+
* - NO response data (request failed)
|
|
142
|
+
*
|
|
143
|
+
* @param activity - Activity metadata from startActivity() (contains unique _id/recordId for record lookup)
|
|
144
|
+
* @param error - Error that occurred
|
|
145
|
+
* @param details - Failure details (timing, error message)
|
|
146
|
+
*/
|
|
147
|
+
logFailure(activity: ActivityMetadata | undefined, error: Error, details: {
|
|
148
|
+
endTime: number;
|
|
149
|
+
duration: number;
|
|
150
|
+
error: string;
|
|
151
|
+
failureType?: FailureType;
|
|
152
|
+
failureSubtype?: LLMResponseFailureSubtype | ResponseParsingFailureSubtype;
|
|
153
|
+
response?: any;
|
|
154
|
+
}): Promise<void>;
|
|
155
|
+
/**
|
|
156
|
+
* Logs a bad request (error that occurred before startActivity)
|
|
157
|
+
*
|
|
158
|
+
* This method creates a new activity record specifically for tracking validation
|
|
159
|
+
* errors, format extraction failures, and other errors that occur before the
|
|
160
|
+
* normal activity lifecycle begins.
|
|
161
|
+
*
|
|
162
|
+
* Uses native ActivityTracker support for bad requests collection via the
|
|
163
|
+
* `collectionName` option in `startActivity()` and `logFailure()` methods.
|
|
164
|
+
* The bad requests collection is configured via `badRequestsCollectionName` in
|
|
165
|
+
* the ActivityTracker constructor (defaults to 'ai-bad-requests').
|
|
166
|
+
*
|
|
167
|
+
* Bad requests are automatically routed to the separate bad requests collection
|
|
168
|
+
* and can be filtered by `failureType` field:
|
|
169
|
+
* - 'validation-failure': Request validation errors
|
|
170
|
+
* - 'format-extraction-failure': Format extraction errors
|
|
171
|
+
* - 'configuration-failure': Configuration errors
|
|
172
|
+
*
|
|
173
|
+
* @param request - The request that failed
|
|
174
|
+
* @param error - The error that occurred
|
|
175
|
+
* @param details - Additional error details
|
|
176
|
+
* @param startTime - When the request started
|
|
177
|
+
*/
|
|
178
|
+
logBadRequest(request: Request, error: Error, details: {
|
|
179
|
+
endTime: number;
|
|
180
|
+
duration: number;
|
|
181
|
+
error: string;
|
|
182
|
+
errorType?: string;
|
|
183
|
+
diagnosticInfo?: Record<string, any>;
|
|
184
|
+
failureType?: 'validation-failure' | 'format-extraction-failure' | 'configuration-failure';
|
|
185
|
+
}, startTime: number): Promise<void>;
|
|
186
|
+
/**
|
|
187
|
+
* Gets the underlying activity tracker instance
|
|
188
|
+
*
|
|
189
|
+
* @returns Activix instance or undefined if not enabled
|
|
190
|
+
*/
|
|
191
|
+
getTracker(): Activix | undefined;
|
|
192
|
+
/**
|
|
193
|
+
* Get status of activity tracker
|
|
194
|
+
*/
|
|
195
|
+
getStatus(): {
|
|
196
|
+
activityTracking: {
|
|
197
|
+
enabled: boolean;
|
|
198
|
+
tracker?: any;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Shutdown tracker
|
|
203
|
+
*/
|
|
204
|
+
shutdown(): Promise<void>;
|
|
205
|
+
}
|
|
206
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Centralized activity tracking configuration.
|
|
4
|
+
* Single source of truth for package-level collection names.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.resolveActivityTrackingConfig = resolveActivityTrackingConfig;
|
|
8
|
+
const ACTIVITY_COLLECTION_NAME = 'ai-activities';
|
|
9
|
+
const BAD_REQUESTS_COLLECTION_NAME = 'bad-requests';
|
|
10
|
+
function resolveActivityTrackingConfig() {
|
|
11
|
+
// Collection names are intentionally hardcoded at package level.
|
|
12
|
+
return {
|
|
13
|
+
mongoUri: '',
|
|
14
|
+
databaseName: '',
|
|
15
|
+
collectionName: ACTIVITY_COLLECTION_NAME,
|
|
16
|
+
badRequestsCollectionName: BAD_REQUESTS_COLLECTION_NAME
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized activity tracking configuration.
|
|
3
|
+
* Single source of truth for package-level collection names.
|
|
4
|
+
*/
|
|
5
|
+
export interface ActivityTrackingConfig {
|
|
6
|
+
mongoUri: string;
|
|
7
|
+
databaseName: string;
|
|
8
|
+
collectionName: string;
|
|
9
|
+
badRequestsCollectionName: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function resolveActivityTrackingConfig(): ActivityTrackingConfig;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contentRegistry": {
|
|
3
|
+
"mode": "dev",
|
|
4
|
+
"localRoot": ".metadata",
|
|
5
|
+
"github": {
|
|
6
|
+
"token": null,
|
|
7
|
+
"repo": null
|
|
8
|
+
},
|
|
9
|
+
"s3": {
|
|
10
|
+
"bucket": null,
|
|
11
|
+
"region": null
|
|
12
|
+
},
|
|
13
|
+
"redis": {
|
|
14
|
+
"host": null,
|
|
15
|
+
"port": null
|
|
16
|
+
},
|
|
17
|
+
"cache": {
|
|
18
|
+
"ttl": 3600000
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"logging": {
|
|
22
|
+
"level": "info",
|
|
23
|
+
"enabled": true
|
|
24
|
+
},
|
|
25
|
+
"templateRendering": {
|
|
26
|
+
"subPathSearch": {
|
|
27
|
+
"enabled": false,
|
|
28
|
+
"roots": ["execution", "input", "inputs"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Content Normalizer
|
|
4
|
+
*
|
|
5
|
+
* Extracts and normalizes content from LLM provider responses.
|
|
6
|
+
* Fixes the "[object Object]" bug by properly handling objects.
|
|
7
|
+
* Preserves both rawText and parsedContent for downstream consumers.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.normalizeContent = normalizeContent;
|
|
11
|
+
exports.isEmptyContent = isEmptyContent;
|
|
12
|
+
exports.getResponseDiagnostics = getResponseDiagnostics;
|
|
13
|
+
/**
|
|
14
|
+
* Extracts content from router response, checking multiple possible locations
|
|
15
|
+
*
|
|
16
|
+
* @param response - Router response object
|
|
17
|
+
* @returns Extracted content value (any type) or null
|
|
18
|
+
*/
|
|
19
|
+
function extractContentValue(response) {
|
|
20
|
+
// Check multiple possible locations
|
|
21
|
+
// CRITICAL: Check outputText FIRST (router's standard field) before other fields
|
|
22
|
+
return response.outputText ?? // Router's standard output field (check first)
|
|
23
|
+
response.content ??
|
|
24
|
+
response.rawText ??
|
|
25
|
+
response.output ??
|
|
26
|
+
response.choices?.[0]?.message?.content ??
|
|
27
|
+
response.choices?.[0]?.text ??
|
|
28
|
+
response.message?.content ??
|
|
29
|
+
response.text ??
|
|
30
|
+
response.result ??
|
|
31
|
+
null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extracts rawText from router response
|
|
35
|
+
*
|
|
36
|
+
* @param response - Router response object
|
|
37
|
+
* @param contentValue - The extracted content value (to avoid re-extraction)
|
|
38
|
+
* @returns Raw text string or undefined
|
|
39
|
+
*/
|
|
40
|
+
function extractRawText(response, contentValue) {
|
|
41
|
+
// Try to get rawText from router response (preferred - original from provider)
|
|
42
|
+
// Check multiple possible locations where router might store rawText
|
|
43
|
+
const rawText = response.rawText || // Direct rawText field (preferred)
|
|
44
|
+
response.outputText || // Router's standard output field (if rawText not available)
|
|
45
|
+
response.raw || // Some providers use 'raw'
|
|
46
|
+
response.rawContent || // Some providers use 'rawContent'
|
|
47
|
+
response.originalText || // Some providers use 'originalText'
|
|
48
|
+
response.originalContent || // Some providers use 'originalContent'
|
|
49
|
+
response.choices?.[0]?.message?.rawText || // OpenAI-style nested rawText
|
|
50
|
+
response.choices?.[0]?.rawText || // OpenAI-style direct rawText
|
|
51
|
+
response.message?.rawText || // Message-level rawText
|
|
52
|
+
response.output?.rawText; // Output-level rawText
|
|
53
|
+
if (typeof rawText === 'string' && rawText.trim().length > 0) {
|
|
54
|
+
return rawText;
|
|
55
|
+
}
|
|
56
|
+
// If no rawText found, but content is a string, use it as rawText
|
|
57
|
+
// This ensures we always have something to work with
|
|
58
|
+
// If content is already a string, check if it's a JSON string with wrapped prose
|
|
59
|
+
if (typeof contentValue === 'string' && contentValue.trim().length > 0) {
|
|
60
|
+
// Check if it's a JSON string that might contain wrapped prose
|
|
61
|
+
const trimmed = contentValue.trim();
|
|
62
|
+
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
63
|
+
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(trimmed);
|
|
66
|
+
// If it's a wrapped prose object (has _wrapped and text fields), extract the text
|
|
67
|
+
if (parsed && typeof parsed === 'object' && parsed._wrapped === true && typeof parsed.text === 'string') {
|
|
68
|
+
return parsed.text;
|
|
69
|
+
}
|
|
70
|
+
// Otherwise, return the original string (it's a valid JSON string)
|
|
71
|
+
return contentValue;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Not valid JSON, return as-is
|
|
75
|
+
return contentValue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Not JSON, return as-is
|
|
79
|
+
return contentValue;
|
|
80
|
+
}
|
|
81
|
+
// If content is an object/array, check for wrapped prose first
|
|
82
|
+
if (contentValue != null && typeof contentValue === 'object') {
|
|
83
|
+
// Check if it's a wrapped prose object (has _wrapped and text fields)
|
|
84
|
+
if (contentValue._wrapped === true && typeof contentValue.text === 'string') {
|
|
85
|
+
return contentValue.text;
|
|
86
|
+
}
|
|
87
|
+
// Otherwise, stringify it to get the JSON string
|
|
88
|
+
// This handles the case where router doesn't preserve rawText but returns parsed object
|
|
89
|
+
try {
|
|
90
|
+
return JSON.stringify(contentValue);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// If stringify fails, return undefined
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Attempts to parse content as JSON
|
|
101
|
+
* Always returns a structure - forces JSON structure even if parsing fails
|
|
102
|
+
*
|
|
103
|
+
* @param value - Value to parse
|
|
104
|
+
* @param forceStructure - If true, always return an object/array structure (default: true)
|
|
105
|
+
* @returns Parsed object/array or forced structure
|
|
106
|
+
*/
|
|
107
|
+
function tryParseJSON(value, forceStructure = true) {
|
|
108
|
+
if (value == null) {
|
|
109
|
+
// Force structure: return empty object instead of undefined
|
|
110
|
+
return forceStructure ? {} : undefined;
|
|
111
|
+
}
|
|
112
|
+
// If already an object or array, return it
|
|
113
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
if (Array.isArray(value)) {
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
// If it's a string, try to parse it
|
|
120
|
+
if (typeof value === 'string') {
|
|
121
|
+
const trimmed = value.trim();
|
|
122
|
+
// Try to parse as JSON
|
|
123
|
+
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
124
|
+
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
125
|
+
try {
|
|
126
|
+
return JSON.parse(trimmed);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Not valid JSON - force structure if requested
|
|
130
|
+
if (forceStructure) {
|
|
131
|
+
// Wrap in object with the text as a value
|
|
132
|
+
return trimmed.startsWith('[') ? [] : { value: trimmed, _parseError: true };
|
|
133
|
+
}
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// If forceStructure and it's not JSON-like, wrap it
|
|
138
|
+
if (forceStructure && trimmed.length > 0) {
|
|
139
|
+
return { text: trimmed, _wrapped: true };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// For other types (number, boolean, etc.), wrap in object if forceStructure
|
|
143
|
+
if (forceStructure && value != null) {
|
|
144
|
+
return { value, _wrapped: true };
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Determines content type
|
|
150
|
+
*
|
|
151
|
+
* @param value - Content value
|
|
152
|
+
* @param parsedContent - Parsed content (if available)
|
|
153
|
+
* @returns Content type classification
|
|
154
|
+
*/
|
|
155
|
+
function determineContentType(value, parsedContent) {
|
|
156
|
+
if (value == null || value === '') {
|
|
157
|
+
return 'null';
|
|
158
|
+
}
|
|
159
|
+
// Use parsedContent if available (more accurate)
|
|
160
|
+
if (parsedContent != null) {
|
|
161
|
+
if (Array.isArray(parsedContent)) {
|
|
162
|
+
return 'array';
|
|
163
|
+
}
|
|
164
|
+
if (typeof parsedContent === 'object') {
|
|
165
|
+
return 'object';
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Fall back to checking value directly
|
|
169
|
+
if (Array.isArray(value)) {
|
|
170
|
+
return 'array';
|
|
171
|
+
}
|
|
172
|
+
if (typeof value === 'object') {
|
|
173
|
+
return 'object';
|
|
174
|
+
}
|
|
175
|
+
return 'string';
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Normalizes content from router response
|
|
179
|
+
*
|
|
180
|
+
* This function:
|
|
181
|
+
* 1. Extracts content from multiple possible locations
|
|
182
|
+
* 2. Preserves rawText if available
|
|
183
|
+
* 3. Attempts to parse flex-md content to JSON
|
|
184
|
+
* 4. Properly stringifies objects (fixes "[object Object]" bug)
|
|
185
|
+
* 5. Determines content type
|
|
186
|
+
*
|
|
187
|
+
* @param response - Router response object
|
|
188
|
+
* @returns Normalized content with metadata
|
|
189
|
+
*/
|
|
190
|
+
function normalizeContent(response) {
|
|
191
|
+
// Extract content value from response
|
|
192
|
+
const contentValue = extractContentValue(response);
|
|
193
|
+
// CRITICAL: Check if router already converted object to "[object Object]" string
|
|
194
|
+
// This happens when router uses String() on objects before returning
|
|
195
|
+
if (typeof contentValue === 'string' && contentValue === '[object Object]') {
|
|
196
|
+
// Router already broke it - try to recover from other fields
|
|
197
|
+
console.error('[content-normalizer] Router returned "[object Object]" string - attempting recovery', {
|
|
198
|
+
responseKeys: Object.keys(response),
|
|
199
|
+
hasOutput: !!response.output,
|
|
200
|
+
hasRawText: !!response.rawText,
|
|
201
|
+
hasChoices: !!response.choices
|
|
202
|
+
});
|
|
203
|
+
// Try to get the original object from other fields
|
|
204
|
+
const output = response.output;
|
|
205
|
+
const choicesContent = response.choices?.[0]?.message?.content;
|
|
206
|
+
const messageContent = response.message?.content;
|
|
207
|
+
// Prefer output (parsed object from provider)
|
|
208
|
+
if (output && typeof output === 'object' && output !== null) {
|
|
209
|
+
const recovered = JSON.stringify(output);
|
|
210
|
+
return {
|
|
211
|
+
content: recovered,
|
|
212
|
+
rawText: recovered,
|
|
213
|
+
parsedContent: output,
|
|
214
|
+
contentType: Array.isArray(output) ? 'array' : 'object'
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Try choices content (might be object)
|
|
218
|
+
if (choicesContent && typeof choicesContent === 'object' && choicesContent !== null) {
|
|
219
|
+
const recovered = JSON.stringify(choicesContent);
|
|
220
|
+
return {
|
|
221
|
+
content: recovered,
|
|
222
|
+
rawText: recovered,
|
|
223
|
+
parsedContent: choicesContent,
|
|
224
|
+
contentType: Array.isArray(choicesContent) ? 'array' : 'object'
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// Try message content (might be object)
|
|
228
|
+
if (messageContent && typeof messageContent === 'object' && messageContent !== null) {
|
|
229
|
+
const recovered = JSON.stringify(messageContent);
|
|
230
|
+
return {
|
|
231
|
+
content: recovered,
|
|
232
|
+
rawText: recovered,
|
|
233
|
+
parsedContent: messageContent,
|
|
234
|
+
contentType: Array.isArray(messageContent) ? 'array' : 'object'
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// If we can't recover, log error and return empty
|
|
238
|
+
console.error('[content-normalizer] Cannot recover from "[object Object]" - no valid object found in response');
|
|
239
|
+
return {
|
|
240
|
+
content: '',
|
|
241
|
+
rawText: undefined,
|
|
242
|
+
parsedContent: undefined,
|
|
243
|
+
contentType: 'null'
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// Extract rawText (original text from provider)
|
|
247
|
+
// Pass contentValue to avoid re-extraction and handle object case
|
|
248
|
+
const rawText = extractRawText(response, contentValue);
|
|
249
|
+
// Always parse flex-md to JSON
|
|
250
|
+
let parsedContent;
|
|
251
|
+
let contentType;
|
|
252
|
+
// Try to parse flex-md content to JSON
|
|
253
|
+
parsedContent = tryParseJSON(contentValue, true);
|
|
254
|
+
contentType = determineContentType(contentValue, parsedContent);
|
|
255
|
+
// Ensure parsedContent matches contentType - force structure consistency
|
|
256
|
+
// JSON is always JSON (object/array), text is always text (string), etc.
|
|
257
|
+
let finalParsedContent = parsedContent;
|
|
258
|
+
if (contentType === 'object') {
|
|
259
|
+
// Force object structure - always return an object
|
|
260
|
+
if (!finalParsedContent || typeof finalParsedContent !== 'object' || Array.isArray(finalParsedContent)) {
|
|
261
|
+
if (typeof contentValue === 'string' && contentValue.trim().length > 0) {
|
|
262
|
+
// Wrap text in object
|
|
263
|
+
finalParsedContent = { text: contentValue, _wrapped: true };
|
|
264
|
+
}
|
|
265
|
+
else if (Array.isArray(contentValue)) {
|
|
266
|
+
// Wrap array in object
|
|
267
|
+
finalParsedContent = { array: contentValue, _wrapped: true };
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
// Empty object
|
|
271
|
+
finalParsedContent = {};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else if (contentType === 'array') {
|
|
276
|
+
// Force array structure - always return an array
|
|
277
|
+
if (!Array.isArray(finalParsedContent)) {
|
|
278
|
+
if (finalParsedContent && typeof finalParsedContent === 'object') {
|
|
279
|
+
// Wrap object in array
|
|
280
|
+
finalParsedContent = [finalParsedContent];
|
|
281
|
+
}
|
|
282
|
+
else if (typeof contentValue === 'string' && contentValue.trim().length > 0) {
|
|
283
|
+
// Wrap text in array
|
|
284
|
+
finalParsedContent = [contentValue];
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// Empty array
|
|
288
|
+
finalParsedContent = [];
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else if (contentType === 'string') {
|
|
293
|
+
// For string type, parsedContent can be undefined (it's just text)
|
|
294
|
+
// But if we have an object, we should keep it for structure preservation
|
|
295
|
+
// Don't force anything - string content doesn't need parsedContent
|
|
296
|
+
finalParsedContent = parsedContent; // Keep as-is (may be undefined, which is fine for strings)
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// null type - no parsedContent
|
|
300
|
+
finalParsedContent = undefined;
|
|
301
|
+
}
|
|
302
|
+
// Normalize content to string (for backward compatibility)
|
|
303
|
+
// CRITICAL: This must NEVER return "[object Object]" - always stringify objects properly
|
|
304
|
+
let normalizedString;
|
|
305
|
+
if (contentValue == null || contentValue === '') {
|
|
306
|
+
normalizedString = '';
|
|
307
|
+
}
|
|
308
|
+
else if (typeof contentValue === 'string') {
|
|
309
|
+
normalizedString = contentValue;
|
|
310
|
+
}
|
|
311
|
+
else if (typeof contentValue === 'object') {
|
|
312
|
+
// Fix "[object Object]" bug: properly stringify objects
|
|
313
|
+
// This is the critical fix - never use String() on objects
|
|
314
|
+
try {
|
|
315
|
+
normalizedString = JSON.stringify(contentValue);
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
// If JSON.stringify fails (circular reference, etc.), try to recover
|
|
319
|
+
// Use rawText if available, otherwise fallback (but log error)
|
|
320
|
+
if (rawText && typeof rawText === 'string') {
|
|
321
|
+
normalizedString = rawText;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
// Last resort: use String() but this should never happen
|
|
325
|
+
normalizedString = String(contentValue);
|
|
326
|
+
// This will be "[object Object]" but we've exhausted all options
|
|
327
|
+
console.error('[content-normalizer] Failed to stringify object and no rawText available', {
|
|
328
|
+
error,
|
|
329
|
+
contentValueType: typeof contentValue,
|
|
330
|
+
isArray: Array.isArray(contentValue)
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
normalizedString = String(contentValue);
|
|
337
|
+
}
|
|
338
|
+
// Final safety check: if normalizedString is "[object Object]", try to recover
|
|
339
|
+
if (normalizedString === '[object Object]') {
|
|
340
|
+
// This should never happen, but if it does, try to recover
|
|
341
|
+
if (rawText && typeof rawText === 'string' && rawText !== '[object Object]') {
|
|
342
|
+
normalizedString = rawText;
|
|
343
|
+
}
|
|
344
|
+
else if (parsedContent) {
|
|
345
|
+
try {
|
|
346
|
+
normalizedString = JSON.stringify(parsedContent);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
// If this also fails, we're stuck with "[object Object]"
|
|
350
|
+
console.error('[content-normalizer] Cannot recover from "[object Object]" - all recovery attempts failed');
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// CRITICAL: Ensure rawText is always set
|
|
355
|
+
// Priority: extracted rawText > normalizedString > contentValue (if string) > empty string
|
|
356
|
+
let finalRawText = rawText;
|
|
357
|
+
if (!finalRawText || typeof finalRawText !== 'string' || finalRawText.trim().length === 0) {
|
|
358
|
+
// Fallback to normalizedString (which is always a string)
|
|
359
|
+
finalRawText = normalizedString;
|
|
360
|
+
}
|
|
361
|
+
// If we still don't have rawText and contentValue is a string, use it
|
|
362
|
+
if ((!finalRawText || finalRawText.trim().length === 0) && typeof contentValue === 'string' && contentValue.trim().length > 0) {
|
|
363
|
+
finalRawText = contentValue;
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
content: normalizedString,
|
|
367
|
+
rawText: finalRawText, // Always set (never undefined)
|
|
368
|
+
parsedContent: finalParsedContent, // Use final parsed content with forced structure
|
|
369
|
+
contentType
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Checks if content is empty
|
|
374
|
+
*
|
|
375
|
+
* @param normalized - Normalized content result
|
|
376
|
+
* @returns True if content is empty
|
|
377
|
+
*/
|
|
378
|
+
function isEmptyContent(normalized) {
|
|
379
|
+
return !normalized.content || normalized.content.trim().length === 0;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Gets diagnostic information about response structure
|
|
383
|
+
* Useful for debugging when content extraction fails
|
|
384
|
+
*
|
|
385
|
+
* @param response - Router response object
|
|
386
|
+
* @returns Diagnostic information
|
|
387
|
+
*/
|
|
388
|
+
function getResponseDiagnostics(response) {
|
|
389
|
+
return {
|
|
390
|
+
responseKeys: Object.keys(response),
|
|
391
|
+
hasMessage: !!(response?.message),
|
|
392
|
+
hasChoices: !!(response?.choices),
|
|
393
|
+
hasOutput: !!(response?.output),
|
|
394
|
+
hasRawText: !!(response?.rawText),
|
|
395
|
+
originalContent: response?.content,
|
|
396
|
+
originalContentType: typeof response?.content
|
|
397
|
+
};
|
|
398
|
+
}
|