@juspay/neurolink 12.12.5 → 12.12.7
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 +2 -2
- package/dist/browser/neurolink.min.js +399 -401
- package/dist/cli/commands/proxy.js +62 -24
- package/dist/cli/commands/proxyAnalyze.js +4 -1
- package/dist/core/baseProvider.d.ts +10 -0
- package/dist/core/baseProvider.js +12 -2
- package/dist/middleware/builtin/guardrails.js +23 -13
- package/dist/middleware/utils/guardrailsUtils.d.ts +3 -15
- package/dist/middleware/utils/guardrailsUtils.js +14 -7
- package/dist/middleware/wrapLanguageModel.d.ts +3 -4
- package/dist/middleware/wrapLanguageModel.js +3 -4
- package/dist/providers/openaiChatCompletionsBase.js +214 -24
- package/dist/proxy/codexUsage.d.ts +2 -1
- package/dist/proxy/codexUsage.js +82 -33
- package/dist/proxy/proxyActivity.d.ts +4 -1
- package/dist/proxy/proxyActivity.js +40 -14
- package/dist/proxy/proxyAnalysis.js +184 -59
- package/dist/proxy/proxyLifecycle.d.ts +1 -1
- package/dist/proxy/proxyLifecycle.js +54 -8
- package/dist/proxy/requestLogger.d.ts +2 -1
- package/dist/proxy/requestLogger.js +87 -29
- package/dist/proxy/sseInterceptor.js +36 -18
- package/dist/proxy/streamOutcome.d.ts +1 -1
- package/dist/proxy/streamOutcome.js +7 -1
- package/dist/server/routes/claudeProxyRoutes.js +70 -16
- package/dist/server/routes/codexProxyRoutes.js +73 -8
- package/dist/types/proxy.d.ts +69 -3
- package/package.json +3 -1
|
@@ -26,7 +26,7 @@ import { ProxyRuntimeConfigStore } from "../../proxy/runtimeConfig.js";
|
|
|
26
26
|
import { startProxyLogCleanupScheduler } from "../../proxy/logCleanupScheduler.js";
|
|
27
27
|
import { anthropicAccountKeysEqual, createAccountAllowlist, isAccountAllowed, LEGACY_ANTHROPIC_ACCOUNT_KEY, normalizeAnthropicAccountKey, shouldLoadFallbackCredential, } from "../../proxy/accountSelection.js";
|
|
28
28
|
import { resolveProxyStatusAccountIdentity } from "../../proxy/codexAccountUsage.js";
|
|
29
|
-
import { beginProxyRequest, getProxyActivitySnapshot, takeProxyResponseObservers, trackProxyResponse, } from "../../proxy/proxyActivity.js";
|
|
29
|
+
import { beginProxyRequest, getProxyActivitySnapshot, observeProxyFinalLog, takeProxyResponseObservers, trackProxyResponse, } from "../../proxy/proxyActivity.js";
|
|
30
30
|
import { flushProxyLifecycleEvents, getProxyLifecycleLoggerSnapshot, hashProxyLifecycleSessionId, logProxyLifecycleEvent, } from "../../proxy/proxyLifecycle.js";
|
|
31
31
|
import { describeInstallFailure, getGlobalInstallArgs, isTransientInstallFailure, resolveGlobalInstaller, validateInstalledVersion, } from "../../proxy/globalInstaller.js";
|
|
32
32
|
import { startUpdaterWorkerSupervisor } from "../../proxy/updaterSupervisor.js";
|
|
@@ -1079,10 +1079,14 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1079
1079
|
rejectForUpdate: readiness.drainingForUpdate,
|
|
1080
1080
|
};
|
|
1081
1081
|
requestMetadata.set(c.req.raw, metadata);
|
|
1082
|
+
const stopObservingFinalLog = observeProxyFinalLog(metadata.requestId, (entry) => {
|
|
1083
|
+
metadata.terminalResult = entry;
|
|
1084
|
+
});
|
|
1082
1085
|
const finishActivity = metadata.rejectForUpdate
|
|
1083
1086
|
? () => undefined
|
|
1084
1087
|
: beginProxyRequest();
|
|
1085
1088
|
const finish = () => {
|
|
1089
|
+
stopObservingFinalLog();
|
|
1086
1090
|
finishActivity();
|
|
1087
1091
|
// Borrowed traffic holds a concurrency slot for the lifetime of the
|
|
1088
1092
|
// response body, so it is released here rather than when the handler
|
|
@@ -1130,15 +1134,9 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1130
1134
|
}
|
|
1131
1135
|
}
|
|
1132
1136
|
};
|
|
1133
|
-
const notifyRouteTerminal = (details) => {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
observer.onTerminal?.(details);
|
|
1137
|
-
}
|
|
1138
|
-
catch {
|
|
1139
|
-
// Route-level accounting must never interfere with the relay.
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1137
|
+
const notifyRouteTerminal = async (details) => {
|
|
1138
|
+
const results = await withTimeout(Promise.allSettled(routeResponseObservers.map(async (observer) => observer.onTerminal?.(details))), 2_000, "Timed out joining proxy response accounting");
|
|
1139
|
+
return results.some((result) => result.status === "rejected");
|
|
1142
1140
|
};
|
|
1143
1141
|
c.res = trackProxyResponse(c.res, finish, {
|
|
1144
1142
|
onFirstChunk: ({ observedBodyBytes, responseChunks }) => {
|
|
@@ -1162,13 +1160,39 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1162
1160
|
responseChunks,
|
|
1163
1161
|
});
|
|
1164
1162
|
},
|
|
1165
|
-
onTerminal: ({ outcome, observedBodyBytes, responseChunks }) => {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1163
|
+
onTerminal: async ({ outcome, error, observedBodyBytes, responseChunks, }) => {
|
|
1164
|
+
const terminalMonotonicMs = performance.now();
|
|
1165
|
+
const terminalTimestampMs = Date.now();
|
|
1166
|
+
// Route accounting may await SSE parsing/cancellation. Join it before
|
|
1167
|
+
// publishing the semantic terminal record; transport EOF alone is not
|
|
1168
|
+
// evidence of a successful model response.
|
|
1169
|
+
let accountingTimedOut = false;
|
|
1170
|
+
let accountingFailed = false;
|
|
1171
|
+
try {
|
|
1172
|
+
accountingFailed = await notifyRouteTerminal({
|
|
1173
|
+
outcome,
|
|
1174
|
+
error,
|
|
1175
|
+
observedBodyBytes,
|
|
1176
|
+
responseChunks,
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
catch {
|
|
1180
|
+
accountingTimedOut = true;
|
|
1169
1181
|
}
|
|
1182
|
+
const final = metadata.terminalResult;
|
|
1183
|
+
const terminalOutcome = final?.terminalOutcome ??
|
|
1184
|
+
(outcome === "stream_error" ||
|
|
1185
|
+
metadata.terminalErrorType === "stream_error"
|
|
1186
|
+
? "stream_error"
|
|
1187
|
+
: outcome === "client_cancelled"
|
|
1188
|
+
? "client_cancelled"
|
|
1189
|
+
: responseStatus >= 400
|
|
1190
|
+
? "handler_error"
|
|
1191
|
+
: "unknown");
|
|
1170
1192
|
logProxyLifecycleEvent({
|
|
1171
1193
|
event: "request_terminal",
|
|
1194
|
+
timestampMs: terminalTimestampMs,
|
|
1195
|
+
monotonicMs: terminalMonotonicMs,
|
|
1172
1196
|
requestId: metadata.requestId,
|
|
1173
1197
|
method: metadata.method,
|
|
1174
1198
|
path: metadata.path,
|
|
@@ -1180,20 +1204,33 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1180
1204
|
responseStatus,
|
|
1181
1205
|
observedBodyBytes,
|
|
1182
1206
|
responseChunks,
|
|
1183
|
-
elapsedMs:
|
|
1184
|
-
terminalOutcome
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1207
|
+
elapsedMs: terminalMonotonicMs - startedMonotonicMs,
|
|
1208
|
+
terminalOutcome,
|
|
1209
|
+
finalStatus: final?.responseStatus,
|
|
1210
|
+
transportOutcome: outcome,
|
|
1211
|
+
outcomeSource: final
|
|
1212
|
+
? "final_request"
|
|
1213
|
+
: responseStatus >= 400
|
|
1214
|
+
? "http_status"
|
|
1215
|
+
: terminalOutcome === "unknown"
|
|
1216
|
+
? "unknown"
|
|
1217
|
+
: "transport_error",
|
|
1218
|
+
telemetryStatus: accountingTimedOut
|
|
1219
|
+
? "timeout"
|
|
1220
|
+
: accountingFailed
|
|
1221
|
+
? "observer_error"
|
|
1222
|
+
: final
|
|
1223
|
+
? "complete"
|
|
1224
|
+
: "missing_final",
|
|
1225
|
+
errorType: final?.errorType ?? metadata.terminalErrorType,
|
|
1226
|
+
errorCode: final?.errorCode ?? metadata.terminalErrorCode,
|
|
1192
1227
|
});
|
|
1228
|
+
stopObservingFinalLog();
|
|
1193
1229
|
},
|
|
1194
1230
|
});
|
|
1195
1231
|
}
|
|
1196
1232
|
catch (error) {
|
|
1233
|
+
stopObservingFinalLog();
|
|
1197
1234
|
// Keep metadata available to app.onError, which records the client-facing
|
|
1198
1235
|
// failure with the same request ID before deleting the WeakMap entry.
|
|
1199
1236
|
finishActivity();
|
|
@@ -1238,7 +1275,7 @@ export async function createProxyStartApp(params) {
|
|
|
1238
1275
|
const { createOpenAIProxyRoutes } = await import("../../server/routes/openaiProxyRoutes.js");
|
|
1239
1276
|
const { createCodexProxyRoutes } = await import("../../server/routes/codexProxyRoutes.js");
|
|
1240
1277
|
const { createGeminiProxyRoutes } = await import("../../server/routes/geminiProxyRoutes.js");
|
|
1241
|
-
const { logBodyCapture, logRequest } = await import("../../proxy/requestLogger.js");
|
|
1278
|
+
const { logBodyCapture, logRequest, getRequestLoggerSnapshot } = await import("../../proxy/requestLogger.js");
|
|
1242
1279
|
const { recordFinalError } = await import("../../proxy/usageStats.js");
|
|
1243
1280
|
const { admitInboundShareRequest, isGrantRequiredByEnv } = await import("../../proxy/shareGate.js");
|
|
1244
1281
|
const { runWithShareContext } = await import("../../proxy/shareContext.js");
|
|
@@ -1978,6 +2015,7 @@ export async function createProxyStartApp(params) {
|
|
|
1978
2015
|
})(),
|
|
1979
2016
|
observability: {
|
|
1980
2017
|
lifecycle: getProxyLifecycleLoggerSnapshot(),
|
|
2018
|
+
requestLogs: getRequestLoggerSnapshot(),
|
|
1981
2019
|
},
|
|
1982
2020
|
autoUpdate: {
|
|
1983
2021
|
enabled: isProxyAutoUpdateEnabled(),
|
|
@@ -70,6 +70,7 @@ function printAnalysis(report) {
|
|
|
70
70
|
for (const [label, summary] of [
|
|
71
71
|
["Response headers", report.latencyMs.headers],
|
|
72
72
|
["First chunk", report.latencyMs.firstChunk],
|
|
73
|
+
["First useful output", report.latencyMs.firstUsefulOutput],
|
|
73
74
|
["Terminal", report.latencyMs.terminal],
|
|
74
75
|
["Final request log", report.latencyMs.finalRequest],
|
|
75
76
|
["Account attempt", report.latencyMs.attempt],
|
|
@@ -100,7 +101,9 @@ function printAnalysis(report) {
|
|
|
100
101
|
if (!report.coverage.comparableRequestAttempts) {
|
|
101
102
|
logger.always(chalk.yellow(" WARNING: request and attempt totals do not cover a comparable full window; do not reconcile them as one cohort"));
|
|
102
103
|
}
|
|
103
|
-
logger.always(` ${report.dataQuality.linesRead} lines scanned, ${report.dataQuality.malformedLines} malformed, ${report.dataQuality.unsupportedLifecycleLines} unsupported lifecycle, ${report.dataQuality.lifecycleSequenceGaps} sequence gaps, ${report.dataQuality.lifecycleSequenceDuplicates} duplicates`);
|
|
104
|
+
logger.always(` ${report.dataQuality.linesRead} lines scanned, ${report.dataQuality.malformedLines} malformed, ${report.dataQuality.unsupportedLifecycleLines} unsupported lifecycle, ${report.dataQuality.lifecycleSequenceGaps} sequence gaps, ${report.dataQuality.lifecycleSequenceDuplicates} duplicates (${report.dataQuality.conflictingLifecycleDuplicates} conflicting)`);
|
|
105
|
+
logger.always(` Outcome evidence: ${report.dataQuality.finalOutcomeConflicts} conflicts reconciled, ${report.dataQuality.acceptedWithoutFinal} accepted without a final record, ${report.dataQuality.terminalWithoutFinal} transport terminals without a final record`);
|
|
106
|
+
logger.always(` Repeated attempt records merged: ${report.dataQuality.duplicateAttempts}`);
|
|
104
107
|
logger.always(` Routing decisions: ${report.dataQuality.routingDecisions.valid} valid, ${report.dataQuality.routingDecisions.invalid} invalid, ${report.dataQuality.routingDecisions.absent} absent`);
|
|
105
108
|
for (const [stream, range] of Object.entries(report.dataQuality.streams)) {
|
|
106
109
|
if (range.observedFrom) {
|
|
@@ -468,6 +468,16 @@ export declare abstract class BaseProvider implements AIProvider {
|
|
|
468
468
|
* TODO(#1576): Implement global level middlewares that can be used
|
|
469
469
|
*/
|
|
470
470
|
protected getAISDKModelWithMiddleware(options?: TextGenerationOptions | StreamOptions): Promise<LanguageModel>;
|
|
471
|
+
/**
|
|
472
|
+
* Apply the configured middleware chain to a caller-supplied base model.
|
|
473
|
+
*
|
|
474
|
+
* `getAISDKModelWithMiddleware()` always wraps `getAISDKModel()`, which is
|
|
475
|
+
* the model the non-streaming path drives. Streaming paths build a
|
|
476
|
+
* different base — one whose `doStream` starts the provider's own stream
|
|
477
|
+
* loop — and need the same chain applied to it, so the wrapping is split
|
|
478
|
+
* out here rather than duplicated per provider.
|
|
479
|
+
*/
|
|
480
|
+
protected applyMiddlewareToModel(baseModel: LanguageModel, options?: TextGenerationOptions | StreamOptions): Promise<LanguageModel>;
|
|
471
481
|
/**
|
|
472
482
|
* Extract middleware options - delegated to Utilities
|
|
473
483
|
*/
|
|
@@ -2014,8 +2014,18 @@ export class BaseProvider {
|
|
|
2014
2014
|
* TODO(#1576): Implement global level middlewares that can be used
|
|
2015
2015
|
*/
|
|
2016
2016
|
async getAISDKModelWithMiddleware(options = {}) {
|
|
2017
|
-
|
|
2018
|
-
|
|
2017
|
+
return this.applyMiddlewareToModel(await this.getAISDKModel(), options);
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* Apply the configured middleware chain to a caller-supplied base model.
|
|
2021
|
+
*
|
|
2022
|
+
* `getAISDKModelWithMiddleware()` always wraps `getAISDKModel()`, which is
|
|
2023
|
+
* the model the non-streaming path drives. Streaming paths build a
|
|
2024
|
+
* different base — one whose `doStream` starts the provider's own stream
|
|
2025
|
+
* loop — and need the same chain applied to it, so the wrapping is split
|
|
2026
|
+
* out here rather than duplicated per provider.
|
|
2027
|
+
*/
|
|
2028
|
+
async applyMiddlewareToModel(baseModel, options = {}) {
|
|
2019
2029
|
logger.debug(`Retrieved base model for ${this.providerName}`, {
|
|
2020
2030
|
provider: this.providerName,
|
|
2021
2031
|
model: this.modelName,
|
|
@@ -43,7 +43,6 @@ export function createGuardrailsMiddleware(config = {}) {
|
|
|
43
43
|
const blockingState = new WeakMap();
|
|
44
44
|
const middleware = {
|
|
45
45
|
specificationVersion: "v3",
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
46
|
transformParams: async ({ params }) => {
|
|
48
47
|
if (config.precallEvaluation?.enabled) {
|
|
49
48
|
const { shouldBlock, transformedParams } = await handlePrecallGuardrails(params, config.precallEvaluation);
|
|
@@ -53,7 +52,6 @@ export function createGuardrailsMiddleware(config = {}) {
|
|
|
53
52
|
}
|
|
54
53
|
return params;
|
|
55
54
|
},
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
55
|
wrapGenerate: async ({ doGenerate, params }) => {
|
|
58
56
|
logger.debug(`[GuardrailsMiddleware] Applying to generate call.`);
|
|
59
57
|
// Check if this request should be blocked (set by transformParams)
|
|
@@ -61,14 +59,23 @@ export function createGuardrailsMiddleware(config = {}) {
|
|
|
61
59
|
return createBlockedResponse();
|
|
62
60
|
}
|
|
63
61
|
let result = await doGenerate();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
result
|
|
67
|
-
|
|
62
|
+
result = {
|
|
63
|
+
...result,
|
|
64
|
+
content: result.content.map((part) => part.type === "text"
|
|
65
|
+
? {
|
|
66
|
+
...part,
|
|
67
|
+
text: applyContentFiltering(part.text, config.badWords, "generate").filteredText,
|
|
68
|
+
}
|
|
69
|
+
: part),
|
|
70
|
+
};
|
|
68
71
|
if (config.modelFilter?.enabled && config.modelFilter.filterModel) {
|
|
69
72
|
logger.debug(`[GuardrailsMiddleware] Invoking model-based filter.`);
|
|
70
73
|
try {
|
|
71
|
-
const
|
|
74
|
+
const text = result.content
|
|
75
|
+
.filter((part) => part.type === "text")
|
|
76
|
+
.map((part) => part.text)
|
|
77
|
+
.join("");
|
|
78
|
+
const filterPrompt = `Is the following text safe? Respond with only "safe" or "unsafe".\n\nText: "${text}"`;
|
|
72
79
|
// `ModelFilterConfig.filterModel` is typed `LanguageModel`, which
|
|
73
80
|
// admits a bare model id, and the documented examples used one.
|
|
74
81
|
// `generateOnceNative` needs a handle exposing doGenerate, so a
|
|
@@ -78,7 +85,12 @@ export function createGuardrailsMiddleware(config = {}) {
|
|
|
78
85
|
const { text: filterResponse } = await generateOnceNative(filterModel, { prompt: filterPrompt });
|
|
79
86
|
if (filterResponse.toLowerCase().trim() === "unsafe") {
|
|
80
87
|
logger.warn(`[GuardrailsMiddleware] Model-based filter flagged content as unsafe.`);
|
|
81
|
-
result = {
|
|
88
|
+
result = {
|
|
89
|
+
...result,
|
|
90
|
+
content: result.content.map((part) => part.type === "text"
|
|
91
|
+
? { ...part, text: "<REDACTED BY AI GUARDRAIL>" }
|
|
92
|
+
: part),
|
|
93
|
+
};
|
|
82
94
|
}
|
|
83
95
|
}
|
|
84
96
|
catch (error) {
|
|
@@ -89,7 +101,6 @@ export function createGuardrailsMiddleware(config = {}) {
|
|
|
89
101
|
}
|
|
90
102
|
return result;
|
|
91
103
|
},
|
|
92
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
104
|
wrapStream: async ({ doStream, params }) => {
|
|
94
105
|
logger.debug(`[GuardrailsMiddleware] Applying to stream call.`);
|
|
95
106
|
// Check if this request should be blocked (set by transformParams)
|
|
@@ -106,13 +117,12 @@ export function createGuardrailsMiddleware(config = {}) {
|
|
|
106
117
|
transform(chunk, controller) {
|
|
107
118
|
hasYieldedChunks = true;
|
|
108
119
|
let filteredChunk = chunk;
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
const filterResult = applyContentFiltering(filteredChunk.textDelta, config.badWords, "stream");
|
|
120
|
+
if (filteredChunk.type === "text-delta") {
|
|
121
|
+
const filterResult = applyContentFiltering(filteredChunk.delta, config.badWords, "stream");
|
|
112
122
|
if (filterResult.hasChanges) {
|
|
113
123
|
filteredChunk = {
|
|
114
124
|
...filteredChunk,
|
|
115
|
-
|
|
125
|
+
delta: filterResult.filteredText,
|
|
116
126
|
};
|
|
117
127
|
}
|
|
118
128
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BadWordsConfig, ContentFilteringResult, EvaluationActionResult, PrecallEvaluationConfig, PrecallEvaluationResult } from "../../types/index.js";
|
|
1
|
+
import type { BadWordsConfig, LanguageModelV3GenerateResult, LanguageModelV3StreamPart, ContentFilteringResult, EvaluationActionResult, PrecallEvaluationConfig, PrecallEvaluationResult } from "../../types/index.js";
|
|
2
2
|
export declare const DEFAULT_EVALUATION_PROMPT = "\nEvaluate the following user input for safety and appropriateness. Respond ONLY with valid JSON:\n\n{\n \"overall\": \"safe|unsafe|suspicious|inappropriate\",\n \"safetyScore\": <1-10>,\n \"appropriatenessScore\": <1-10>,\n \"confidenceLevel\": <1-10>,\n \"issues\": [\n {\n \"category\": \"explicit_content|hate_speech|violence|personal_info|spam|other\",\n \"severity\": \"low|medium|high|critical\",\n \"description\": \"Brief description\"\n }\n ],\n \"suggestedAction\": \"allow|block|sanitize|warn\",\n \"reasoning\": \"Brief explanation\"\n}\n\nUser Input: \"{USER_INPUT}\"\n";
|
|
3
3
|
/**
|
|
4
4
|
* Extract user input from middleware params
|
|
@@ -25,20 +25,8 @@ export declare function applyEvaluationActions(evaluation: PrecallEvaluationResu
|
|
|
25
25
|
*/
|
|
26
26
|
export declare function applySanitization(params: any, sanitizedInput: string): any;
|
|
27
27
|
export declare function escapeRegExp(string: string): string;
|
|
28
|
-
export declare function createBlockedResponse():
|
|
29
|
-
|
|
30
|
-
usage: {
|
|
31
|
-
promptTokens: number;
|
|
32
|
-
completionTokens: number;
|
|
33
|
-
};
|
|
34
|
-
finishReason: "stop";
|
|
35
|
-
warnings: never[];
|
|
36
|
-
rawCall: {
|
|
37
|
-
rawPrompt: null;
|
|
38
|
-
rawSettings: {};
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
export declare function createBlockedStream(): ReadableStream<any>;
|
|
28
|
+
export declare function createBlockedResponse(): LanguageModelV3GenerateResult;
|
|
29
|
+
export declare function createBlockedStream(): ReadableStream<LanguageModelV3StreamPart>;
|
|
42
30
|
/**
|
|
43
31
|
* Apply content filtering using bad words configuration
|
|
44
32
|
* Handles both regex patterns and string lists with proper priority
|
|
@@ -258,24 +258,31 @@ export function escapeRegExp(string) {
|
|
|
258
258
|
}
|
|
259
259
|
export function createBlockedResponse() {
|
|
260
260
|
return {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
261
|
+
content: [
|
|
262
|
+
{
|
|
263
|
+
type: "text",
|
|
264
|
+
text: "Request contains inappropriate content and has been blocked.",
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
usage: { inputTokens: { total: 0 }, outputTokens: { total: 0 } },
|
|
268
|
+
finishReason: { unified: "stop" },
|
|
264
269
|
warnings: [],
|
|
265
|
-
rawCall: { rawPrompt: null, rawSettings: {} },
|
|
266
270
|
};
|
|
267
271
|
}
|
|
268
272
|
export function createBlockedStream() {
|
|
269
273
|
return new ReadableStream({
|
|
270
274
|
start(controller) {
|
|
275
|
+
controller.enqueue({ type: "text-start", id: "blocked" });
|
|
271
276
|
controller.enqueue({
|
|
272
277
|
type: "text-delta",
|
|
273
|
-
|
|
278
|
+
id: "blocked",
|
|
279
|
+
delta: "Request contains inappropriate content and has been blocked.",
|
|
274
280
|
});
|
|
281
|
+
controller.enqueue({ type: "text-end", id: "blocked" });
|
|
275
282
|
controller.enqueue({
|
|
276
283
|
type: "finish",
|
|
277
|
-
finishReason: "stop",
|
|
278
|
-
usage: {
|
|
284
|
+
finishReason: { unified: "stop" },
|
|
285
|
+
usage: { inputTokens: { total: 0 }, outputTokens: { total: 0 } },
|
|
279
286
|
});
|
|
280
287
|
controller.close();
|
|
281
288
|
},
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
* `wrapGenerate` / `wrapStream` hooks. Reproduced here so the middleware
|
|
7
7
|
* factory no longer needs the ai package.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* streaming
|
|
11
|
-
*
|
|
12
|
-
* introduced.
|
|
9
|
+
* The OpenAI-compatible streaming path also uses this wrapper. Other native
|
|
10
|
+
* streaming implementations must opt in explicitly; exposing a middleware
|
|
11
|
+
* option or a model-shaped handle alone does not apply the chain.
|
|
13
12
|
*/
|
|
14
13
|
import type { LanguageModelV3, LanguageModelV3Middleware } from "../types/index.js";
|
|
15
14
|
export declare const wrapLanguageModel: ({ model, middleware, }: {
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
* `wrapGenerate` / `wrapStream` hooks. Reproduced here so the middleware
|
|
7
7
|
* factory no longer needs the ai package.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* streaming
|
|
11
|
-
*
|
|
12
|
-
* introduced.
|
|
9
|
+
* The OpenAI-compatible streaming path also uses this wrapper. Other native
|
|
10
|
+
* streaming implementations must opt in explicitly; exposing a middleware
|
|
11
|
+
* option or a model-shaped handle alone does not apply the chain.
|
|
13
12
|
*/
|
|
14
13
|
const doWrap = (model, middleware) => {
|
|
15
14
|
const transform = async (params, type) => middleware.transformParams
|