@inspectr/mcplab 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/app/assets/index-DHs9MRuO.css +1 -0
- package/dist/app/assets/index-UuO3yMWK.js +253 -0
- package/dist/app/index.html +2 -2
- package/dist/app-server/app-context.d.ts +129 -75
- package/dist/app-server/oauth-debugger-domain.d.ts +7 -0
- package/dist/app-server/oauth-debugger-domain.d.ts.map +1 -1
- package/dist/app-server/oauth-debugger-domain.js +47 -4
- package/dist/app-server/oauth-debugger-domain.js.map +1 -1
- package/dist/app-server/oauth-runtime-domain.d.ts +53 -42
- package/dist/app-server/oauth-runtime-domain.d.ts.map +1 -1
- package/dist/app-server/oauth-runtime-domain.js +1 -3
- package/dist/app-server/oauth-runtime-domain.js.map +1 -1
- package/dist/app-server/oauth-runtime-routes.d.ts +2 -0
- package/dist/app-server/oauth-runtime-routes.d.ts.map +1 -1
- package/dist/app-server/oauth-runtime-routes.js +27 -1
- package/dist/app-server/oauth-runtime-routes.js.map +1 -1
- package/dist/app-server/oauth-session-manager.d.ts +51 -0
- package/dist/app-server/oauth-session-manager.d.ts.map +1 -0
- package/dist/app-server/oauth-session-manager.js +338 -0
- package/dist/app-server/oauth-session-manager.js.map +1 -0
- package/dist/app-server/router.d.ts.map +1 -1
- package/dist/app-server/router.js +11 -4
- package/dist/app-server/router.js.map +1 -1
- package/dist/app-server/runs-routes.d.ts +3 -4
- package/dist/app-server/runs-routes.d.ts.map +1 -1
- package/dist/app-server/runs-routes.js +229 -28
- package/dist/app-server/runs-routes.js.map +1 -1
- package/dist/app-server/scenario-assistant-domain.d.ts +133 -139
- package/dist/app-server/scenario-assistant-domain.d.ts.map +1 -1
- package/dist/app-server/scenario-assistant-domain.js +270 -5
- package/dist/app-server/scenario-assistant-domain.js.map +1 -1
- package/dist/app-server/scenario-assistant.d.ts +11 -25
- package/dist/app-server/scenario-assistant.d.ts.map +1 -1
- package/dist/app-server/scenario-assistant.js +18 -2
- package/dist/app-server/scenario-assistant.js.map +1 -1
- package/dist/app-server/tool-analysis-domain.d.ts +3 -4
- package/dist/app-server/tool-analysis-domain.d.ts.map +1 -1
- package/dist/app-server/tool-analysis-domain.js +14 -9
- package/dist/app-server/tool-analysis-domain.js.map +1 -1
- package/dist/app-server/tool-analysis.d.ts +3 -3
- package/dist/app-server/tool-analysis.d.ts.map +1 -1
- package/dist/app-server/tool-analysis.js +23 -20
- package/dist/app-server/tool-analysis.js.map +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +4 -4
- package/dist/app/assets/index-CYs1291A.css +0 -1
- package/dist/app/assets/index-Fe4npghI.js +0 -249
|
@@ -3,162 +3,156 @@ import { McpClientManager } from '@inspectr/mcplab-core';
|
|
|
3
3
|
import { readLibraries } from './libraries-store.js';
|
|
4
4
|
export { truncateJson } from './assistant-common.js';
|
|
5
5
|
interface ScenarioAssistantContextInput {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
configSnapshotPolicy?: {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
mode?: 'warn' | 'fail_on_drift';
|
|
9
|
+
baselineSnapshotId?: string;
|
|
10
|
+
};
|
|
11
|
+
scenario: {
|
|
12
|
+
id: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
serverNames: string[];
|
|
16
|
+
evalRules: Array<{
|
|
17
|
+
type: string;
|
|
18
|
+
value?: string;
|
|
19
|
+
path?: string;
|
|
20
|
+
equals?: string | number | boolean;
|
|
21
|
+
}>;
|
|
22
|
+
extractRules: Array<{
|
|
23
|
+
name: string;
|
|
24
|
+
pattern: string;
|
|
25
|
+
}>;
|
|
26
|
+
snapshotEval?: {
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
baselineSnapshotId?: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
availableServers?: Array<{
|
|
32
|
+
name: string;
|
|
33
|
+
url?: string;
|
|
19
34
|
}>;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
availableAgents?: Array<{
|
|
36
|
+
name: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
model: string;
|
|
23
39
|
}>;
|
|
24
|
-
snapshotEval?: {
|
|
25
|
-
enabled?: boolean;
|
|
26
|
-
baselineSnapshotId?: string;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
availableServers?: Array<{
|
|
30
|
-
name: string;
|
|
31
|
-
url?: string;
|
|
32
|
-
}>;
|
|
33
|
-
availableAgents?: Array<{
|
|
34
|
-
name: string;
|
|
35
|
-
provider: string;
|
|
36
|
-
model: string;
|
|
37
|
-
}>;
|
|
38
40
|
}
|
|
39
41
|
interface ScenarioAssistantSuggestionBundle {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
42
|
+
prompt?: {
|
|
43
|
+
replacement: string;
|
|
44
|
+
rationale?: string;
|
|
45
|
+
};
|
|
46
|
+
evalRules?: {
|
|
47
|
+
replacement: Array<{
|
|
48
|
+
type: string;
|
|
49
|
+
value?: string;
|
|
50
|
+
path?: string;
|
|
51
|
+
equals?: string | number | boolean;
|
|
52
|
+
}>;
|
|
53
|
+
rationale?: string;
|
|
54
|
+
};
|
|
55
|
+
extractRules?: {
|
|
56
|
+
replacement: Array<{
|
|
57
|
+
name: string;
|
|
58
|
+
pattern: string;
|
|
59
|
+
}>;
|
|
60
|
+
rationale?: string;
|
|
61
|
+
};
|
|
62
|
+
snapshotEval?: {
|
|
63
|
+
patch: {
|
|
64
|
+
enabled?: boolean;
|
|
65
|
+
baselineSnapshotId?: string;
|
|
66
|
+
};
|
|
67
|
+
rationale?: string;
|
|
62
68
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
notes?: string[];
|
|
70
|
+
}
|
|
71
|
+
interface ScenarioAssistantEvalRuleSuggestion {
|
|
72
|
+
type: string;
|
|
73
|
+
value?: string;
|
|
74
|
+
path?: string;
|
|
75
|
+
equals?: string | number | boolean;
|
|
66
76
|
}
|
|
67
77
|
interface AssistantPendingToolCall {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
id: string;
|
|
79
|
+
server: string;
|
|
80
|
+
tool: string;
|
|
81
|
+
publicToolName: string;
|
|
82
|
+
arguments: unknown;
|
|
83
|
+
status: 'pending' | 'approved' | 'denied' | 'error';
|
|
84
|
+
createdAt: string;
|
|
85
|
+
resultPreview?: string;
|
|
86
|
+
error?: string;
|
|
77
87
|
}
|
|
78
88
|
interface AssistantChatMessage {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
id: string;
|
|
90
|
+
role: 'user' | 'assistant' | 'tool' | 'system';
|
|
91
|
+
text: string;
|
|
92
|
+
createdAt: string;
|
|
93
|
+
suggestions?: ScenarioAssistantSuggestionBundle;
|
|
94
|
+
pendingToolCallId?: string;
|
|
95
|
+
pendingToolCallIds?: string[];
|
|
96
|
+
toolRequestServer?: string;
|
|
97
|
+
toolRequestName?: string;
|
|
98
|
+
toolRequestPublicName?: string;
|
|
89
99
|
}
|
|
90
100
|
export interface ScenarioAssistantSession {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
llmMessages: LlmMessage[];
|
|
110
|
-
warnings: string[];
|
|
111
|
-
systemPromptCache?: string;
|
|
101
|
+
id: string;
|
|
102
|
+
createdAt: number;
|
|
103
|
+
lastTouchedAt: number;
|
|
104
|
+
configPath?: string;
|
|
105
|
+
selectedAssistantAgentName: string;
|
|
106
|
+
context: ScenarioAssistantContextInput;
|
|
107
|
+
agentConfig: AgentConfig;
|
|
108
|
+
mcp: McpClientManager;
|
|
109
|
+
tools: ToolDef[];
|
|
110
|
+
toolPublicMap: Map<string, {
|
|
111
|
+
server: string;
|
|
112
|
+
tool: string;
|
|
113
|
+
}>;
|
|
114
|
+
pendingToolCalls: AssistantPendingToolCall[];
|
|
115
|
+
chatMessages: AssistantChatMessage[];
|
|
116
|
+
llmMessages: LlmMessage[];
|
|
117
|
+
warnings: string[];
|
|
118
|
+
systemPromptCache?: string;
|
|
112
119
|
}
|
|
113
|
-
export declare function cleanupAssistantSessions(
|
|
114
|
-
sessions: Map<string, ScenarioAssistantSession>,
|
|
115
|
-
now?: number
|
|
116
|
-
): void;
|
|
120
|
+
export declare function cleanupAssistantSessions(sessions: Map<string, ScenarioAssistantSession>, now?: number): void;
|
|
117
121
|
export declare function touchAssistantSession(session: ScenarioAssistantSession): void;
|
|
118
122
|
export declare function assistantSessionView(session: ScenarioAssistantSession): {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
id: string;
|
|
124
|
+
createdAt: string;
|
|
125
|
+
updatedAt: string;
|
|
126
|
+
selectedAssistantAgentName: string;
|
|
127
|
+
model: string;
|
|
128
|
+
provider: "openai" | "anthropic" | "azure_openai";
|
|
129
|
+
warnings: string[];
|
|
130
|
+
toolsLoaded: number;
|
|
131
|
+
toolServers: string[];
|
|
132
|
+
messages: AssistantChatMessage[];
|
|
133
|
+
pendingToolCalls: AssistantPendingToolCall[];
|
|
130
134
|
};
|
|
131
|
-
export declare function preloadAssistantTools(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
): Promise<void>;
|
|
135
|
+
export declare function preloadAssistantTools(session: ScenarioAssistantSession, serversByName: Record<string, EvalConfig['servers'][string]>, selectedServerNames: string[], options?: {
|
|
136
|
+
serverAuthHeaders?: Record<string, Record<string, string>>;
|
|
137
|
+
}): Promise<void>;
|
|
138
|
+
export declare function normalizeScenarioAssistantEvalRules(replacement: ScenarioAssistantEvalRuleSuggestion[]): ScenarioAssistantEvalRuleSuggestion[];
|
|
136
139
|
export declare function continueAssistantTurn(session: ScenarioAssistantSession): Promise<{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
session: ReturnType<typeof assistantSessionView>;
|
|
141
|
+
response: {
|
|
142
|
+
type: 'assistant_message' | 'tool_call_request';
|
|
143
|
+
text: string;
|
|
144
|
+
suggestions?: ScenarioAssistantSuggestionBundle;
|
|
145
|
+
pendingToolCall?: AssistantPendingToolCall;
|
|
146
|
+
pendingToolCalls?: AssistantPendingToolCall[];
|
|
147
|
+
};
|
|
145
148
|
}>;
|
|
146
|
-
export declare function executeAssistantToolCall(
|
|
147
|
-
session: ScenarioAssistantSession,
|
|
148
|
-
pending: AssistantPendingToolCall
|
|
149
|
-
): Promise<unknown>;
|
|
149
|
+
export declare function executeAssistantToolCall(session: ScenarioAssistantSession, pending: AssistantPendingToolCall): Promise<unknown>;
|
|
150
150
|
export declare function summarizeToolResultForAssistant(result: unknown): string;
|
|
151
|
-
export declare function resolveAssistantAgentFromConfig(
|
|
152
|
-
|
|
153
|
-
selectedAssistantAgentName: string
|
|
154
|
-
): AgentConfig;
|
|
155
|
-
export declare function resolveAssistantAgentFromLibraries(
|
|
156
|
-
libraries: ReturnType<typeof readLibraries>,
|
|
157
|
-
selectedAssistantAgentName: string
|
|
158
|
-
): AgentConfig;
|
|
151
|
+
export declare function resolveAssistantAgentFromConfig(config: EvalConfig, selectedAssistantAgentName: string): AgentConfig;
|
|
152
|
+
export declare function resolveAssistantAgentFromLibraries(libraries: ReturnType<typeof readLibraries>, selectedAssistantAgentName: string): AgentConfig;
|
|
159
153
|
export declare function pickDefaultAssistantAgentName(params: {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
requested?: string;
|
|
155
|
+
settingsDefault?: string;
|
|
156
|
+
agentNames: string[];
|
|
163
157
|
}): string;
|
|
164
|
-
//# sourceMappingURL=scenario-assistant-domain.d.ts.map
|
|
158
|
+
//# sourceMappingURL=scenario-assistant-domain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-assistant-domain.d.ts","sourceRoot":"","sources":["../../src/app-server/scenario-assistant-domain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAUzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,UAAU,6BAA6B;IACrC,oBAAoB,CAAC,EAAE;QACrB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;QAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"scenario-assistant-domain.d.ts","sourceRoot":"","sources":["../../src/app-server/scenario-assistant-domain.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,12 +44,16 @@ function assistantSystemPrompt(session) {
|
|
|
44
44
|
`{"type":"tool_call_request","text":"...","toolCall":{"name":"PUBLIC_TOOL_NAME","arguments":{}},"suggestions":{...optional...}}`,
|
|
45
45
|
'For suggestions, use keys: prompt, evalRules, extractRules, snapshotEval, notes.',
|
|
46
46
|
'prompt: { replacement: string, rationale?: string }',
|
|
47
|
-
'evalRules: { replacement: [{ type, value }...], rationale?: string }',
|
|
47
|
+
'evalRules: { replacement: [{ type, value?, path?, equals? }...], rationale?: string }',
|
|
48
48
|
'extractRules: { replacement: [{ name, pattern }...], rationale?: string }',
|
|
49
49
|
'snapshotEval: { patch: { enabled?: boolean, baselineSnapshotId?: string }, rationale?: string }',
|
|
50
50
|
'If you propose any edits to the scenario (prompt, Checks, Value Capture Rules, or snapshot settings), you MUST include the corresponding structured suggestions payload.',
|
|
51
51
|
'Do not describe "suggested updates" in text only. Include suggestions so the UI can render Apply actions.',
|
|
52
|
-
'Keep rule types limited to: required_tool, forbidden_tool, response_contains, response_not_contains.',
|
|
52
|
+
'Keep rule types limited to: required_tool, forbidden_tool, response_contains, response_not_contains, response_starts_with, response_ends_with, response_equals, response_regex, response_jsonpath, response_jsonpath_exists, response_jsonpath_not_exists.',
|
|
53
|
+
'Preference policy: prefer non-regex checks first (response_contains, response_not_contains, response_starts_with, response_ends_with, response_equals).',
|
|
54
|
+
'Use response_regex only for genuinely variable/complex patterns (IDs, dates, currency, alternation, optional tokens, quantifiers, character classes).',
|
|
55
|
+
'Never include both response_regex and an equivalent literal check for the same intent.',
|
|
56
|
+
'Prefer concise, positive checks over brittle near-miss negatives. Avoid paired off-by-one guards like "not 8 tags" and "not 10 tags" when "contains 9 tags" captures intent.',
|
|
53
57
|
'IMPORTANT: For required_tool and forbidden_tool eval rules, use the raw MCP tool name (the "tool=" value shown in the tool listing), NOT the prefixed public name. For example, use "value_based_search" not "trendminer__value_based_search".',
|
|
54
58
|
'Ask clarifying questions if the scenario intent is unclear.',
|
|
55
59
|
`Scenario context: ${JSON.stringify({
|
|
@@ -82,7 +86,7 @@ function formatAssistantMcpPreloadError(serverName, error) {
|
|
|
82
86
|
}
|
|
83
87
|
return `Scenario Assistant MCP preload failed for server '${serverName}': ${raw}`;
|
|
84
88
|
}
|
|
85
|
-
export async function preloadAssistantTools(session, serversByName, selectedServerNames) {
|
|
89
|
+
export async function preloadAssistantTools(session, serversByName, selectedServerNames, options) {
|
|
86
90
|
const usedNames = new Set();
|
|
87
91
|
for (const serverName of selectedServerNames) {
|
|
88
92
|
const server = serversByName[serverName];
|
|
@@ -91,7 +95,9 @@ export async function preloadAssistantTools(session, serversByName, selectedServ
|
|
|
91
95
|
continue;
|
|
92
96
|
}
|
|
93
97
|
try {
|
|
94
|
-
await session.mcp.connectAll({ [serverName]: server }
|
|
98
|
+
await session.mcp.connectAll({ [serverName]: server }, undefined, {
|
|
99
|
+
serverAuthHeaders: options?.serverAuthHeaders
|
|
100
|
+
});
|
|
95
101
|
const tools = await session.mcp.listTools(serverName);
|
|
96
102
|
for (const tool of tools) {
|
|
97
103
|
const publicName = makeAssistantToolPublicName(serverName, tool.name, usedNames);
|
|
@@ -112,7 +118,7 @@ function normalizeEvalRuleToolNames(suggestions, toolPublicMap) {
|
|
|
112
118
|
if (!suggestions?.evalRules?.replacement)
|
|
113
119
|
return;
|
|
114
120
|
for (const rule of suggestions.evalRules.replacement) {
|
|
115
|
-
if (rule.type === 'required_tool' || rule.type === 'forbidden_tool') {
|
|
121
|
+
if ((rule.type === 'required_tool' || rule.type === 'forbidden_tool') && rule.value) {
|
|
116
122
|
const mapping = toolPublicMap.get(rule.value);
|
|
117
123
|
if (mapping) {
|
|
118
124
|
rule.value = mapping.tool;
|
|
@@ -120,6 +126,264 @@ function normalizeEvalRuleToolNames(suggestions, toolPublicMap) {
|
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
}
|
|
129
|
+
function tryParseRegexAsLiteral(pattern) {
|
|
130
|
+
const trimmed = pattern.trim();
|
|
131
|
+
if (!trimmed)
|
|
132
|
+
return null;
|
|
133
|
+
const anchoredStart = trimmed.startsWith('^');
|
|
134
|
+
const anchoredEnd = trimmed.endsWith('$');
|
|
135
|
+
const body = anchoredStart || anchoredEnd
|
|
136
|
+
? trimmed.slice(anchoredStart ? 1 : 0, anchoredEnd ? -1 : undefined)
|
|
137
|
+
: trimmed;
|
|
138
|
+
const regexSpecial = new Set(['.', '^', '$', '*', '+', '?', '(', ')', '[', ']', '{', '}', '|']);
|
|
139
|
+
const complexEscapes = new Set(['d', 'D', 's', 'S', 'w', 'W', 'b', 'B', 'p', 'P']);
|
|
140
|
+
let literal = '';
|
|
141
|
+
let escaped = false;
|
|
142
|
+
for (const char of body) {
|
|
143
|
+
if (escaped) {
|
|
144
|
+
if (complexEscapes.has(char))
|
|
145
|
+
return null;
|
|
146
|
+
literal += char;
|
|
147
|
+
escaped = false;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (char === '\\') {
|
|
151
|
+
escaped = true;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (regexSpecial.has(char)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
literal += char;
|
|
158
|
+
}
|
|
159
|
+
if (escaped)
|
|
160
|
+
return null;
|
|
161
|
+
return { literal, anchored: anchoredStart && anchoredEnd };
|
|
162
|
+
}
|
|
163
|
+
function evalRuleKey(rule) {
|
|
164
|
+
return `${rule.type}::${rule.value ?? ''}::${rule.path ?? ''}::${rule.equals === undefined ? '' : String(rule.equals)}`;
|
|
165
|
+
}
|
|
166
|
+
function hasEquivalentLiteralRule(rules, literalValue) {
|
|
167
|
+
return rules.some((rule) => (rule.type === 'response_contains' ||
|
|
168
|
+
rule.type === 'response_not_contains' ||
|
|
169
|
+
rule.type === 'response_starts_with' ||
|
|
170
|
+
rule.type === 'response_ends_with' ||
|
|
171
|
+
rule.type === 'response_equals') &&
|
|
172
|
+
rule.value === literalValue);
|
|
173
|
+
}
|
|
174
|
+
function parseCountWithSuffix(value) {
|
|
175
|
+
const trimmed = value.trim();
|
|
176
|
+
const match = trimmed.match(/^(\d+)(\s+.+)$/);
|
|
177
|
+
if (!match)
|
|
178
|
+
return null;
|
|
179
|
+
return {
|
|
180
|
+
count: Number.parseInt(match[1], 10),
|
|
181
|
+
suffix: match[2]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function collapseOffByOneCountGuards(rules) {
|
|
185
|
+
const removeIndices = new Set();
|
|
186
|
+
const replaceContains = new Map();
|
|
187
|
+
for (let i = 0; i < rules.length; i += 1) {
|
|
188
|
+
const rule = rules[i];
|
|
189
|
+
if (rule.type !== 'response_contains' || !rule.value)
|
|
190
|
+
continue;
|
|
191
|
+
const explicitPositive = parseCountWithSuffix(rule.value);
|
|
192
|
+
const numericOnly = !explicitPositive && rule.value.trim().match(/^\d+$/);
|
|
193
|
+
if (!explicitPositive && !numericOnly)
|
|
194
|
+
continue;
|
|
195
|
+
const count = explicitPositive
|
|
196
|
+
? explicitPositive.count
|
|
197
|
+
: Number.parseInt(rule.value.trim(), 10);
|
|
198
|
+
const preferredSuffix = explicitPositive?.suffix;
|
|
199
|
+
const offByOneCandidates = new Map();
|
|
200
|
+
for (let j = 0; j < rules.length; j += 1) {
|
|
201
|
+
const candidate = rules[j];
|
|
202
|
+
if (candidate.type !== 'response_not_contains' || !candidate.value)
|
|
203
|
+
continue;
|
|
204
|
+
const parsed = parseCountWithSuffix(candidate.value);
|
|
205
|
+
if (!parsed)
|
|
206
|
+
continue;
|
|
207
|
+
if (preferredSuffix && parsed.suffix !== preferredSuffix)
|
|
208
|
+
continue;
|
|
209
|
+
if (parsed.count !== count - 1 && parsed.count !== count + 1)
|
|
210
|
+
continue;
|
|
211
|
+
const bucket = offByOneCandidates.get(parsed.suffix) ?? {};
|
|
212
|
+
if (parsed.count === count - 1)
|
|
213
|
+
bucket.lowerIdx = j;
|
|
214
|
+
if (parsed.count === count + 1)
|
|
215
|
+
bucket.upperIdx = j;
|
|
216
|
+
offByOneCandidates.set(parsed.suffix, bucket);
|
|
217
|
+
}
|
|
218
|
+
const selected = [...offByOneCandidates.entries()].find(([, pair]) => pair.lowerIdx !== undefined && pair.upperIdx !== undefined);
|
|
219
|
+
if (!selected)
|
|
220
|
+
continue;
|
|
221
|
+
const [suffix, pair] = selected;
|
|
222
|
+
removeIndices.add(pair.lowerIdx);
|
|
223
|
+
removeIndices.add(pair.upperIdx);
|
|
224
|
+
if (!explicitPositive) {
|
|
225
|
+
replaceContains.set(i, `${count}${suffix}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const result = [];
|
|
229
|
+
for (let i = 0; i < rules.length; i += 1) {
|
|
230
|
+
if (removeIndices.has(i))
|
|
231
|
+
continue;
|
|
232
|
+
const rule = rules[i];
|
|
233
|
+
const replacement = replaceContains.get(i);
|
|
234
|
+
if (replacement) {
|
|
235
|
+
result.push({ ...rule, value: replacement });
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
result.push(rule);
|
|
239
|
+
}
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
function normalizeIntentValue(value) {
|
|
243
|
+
return value.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
244
|
+
}
|
|
245
|
+
function positiveLiteralRank(type) {
|
|
246
|
+
switch (type) {
|
|
247
|
+
case 'response_equals':
|
|
248
|
+
return 4;
|
|
249
|
+
case 'response_starts_with':
|
|
250
|
+
case 'response_ends_with':
|
|
251
|
+
return 3;
|
|
252
|
+
case 'response_contains':
|
|
253
|
+
return 2;
|
|
254
|
+
default:
|
|
255
|
+
return 1;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function intentDeduplicateEvalRules(rules) {
|
|
259
|
+
const result = [];
|
|
260
|
+
const positiveByIntent = new Map();
|
|
261
|
+
const containsIndices = [];
|
|
262
|
+
for (const rule of rules) {
|
|
263
|
+
if ((rule.type === 'response_contains' ||
|
|
264
|
+
rule.type === 'response_starts_with' ||
|
|
265
|
+
rule.type === 'response_ends_with' ||
|
|
266
|
+
rule.type === 'response_equals') &&
|
|
267
|
+
rule.value) {
|
|
268
|
+
const intent = normalizeIntentValue(rule.value);
|
|
269
|
+
const existingIdx = positiveByIntent.get(intent);
|
|
270
|
+
if (existingIdx !== undefined) {
|
|
271
|
+
const existing = result[existingIdx];
|
|
272
|
+
if (positiveLiteralRank(rule.type) > positiveLiteralRank(existing.type)) {
|
|
273
|
+
result[existingIdx] = rule;
|
|
274
|
+
if (existing.type === 'response_contains' && rule.type !== 'response_contains') {
|
|
275
|
+
const containsIndex = containsIndices.indexOf(existingIdx);
|
|
276
|
+
if (containsIndex >= 0)
|
|
277
|
+
containsIndices.splice(containsIndex, 1);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (rule.type === 'response_contains') {
|
|
283
|
+
const newIntent = intent;
|
|
284
|
+
let droppedAsMoreSpecific = false;
|
|
285
|
+
for (const idx of containsIndices) {
|
|
286
|
+
const existing = result[idx];
|
|
287
|
+
if (!existing?.value)
|
|
288
|
+
continue;
|
|
289
|
+
const existingIntent = normalizeIntentValue(existing.value);
|
|
290
|
+
if (newIntent.includes(existingIntent)) {
|
|
291
|
+
droppedAsMoreSpecific = true;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
if (existingIntent.includes(newIntent)) {
|
|
295
|
+
positiveByIntent.delete(existingIntent);
|
|
296
|
+
result[idx] = rule;
|
|
297
|
+
positiveByIntent.set(newIntent, idx);
|
|
298
|
+
droppedAsMoreSpecific = true;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (droppedAsMoreSpecific) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const idx = result.push(rule) - 1;
|
|
307
|
+
positiveByIntent.set(intent, idx);
|
|
308
|
+
if (rule.type === 'response_contains')
|
|
309
|
+
containsIndices.push(idx);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
result.push(rule);
|
|
313
|
+
}
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
function lintContradictoryEvalRules(rules) {
|
|
317
|
+
const requiredTools = new Set();
|
|
318
|
+
const positiveLiteralIntents = new Set();
|
|
319
|
+
const existingJsonPaths = new Set();
|
|
320
|
+
for (const rule of rules) {
|
|
321
|
+
if (rule.type === 'required_tool' && rule.value) {
|
|
322
|
+
requiredTools.add(rule.value.trim());
|
|
323
|
+
}
|
|
324
|
+
if ((rule.type === 'response_contains' ||
|
|
325
|
+
rule.type === 'response_starts_with' ||
|
|
326
|
+
rule.type === 'response_ends_with' ||
|
|
327
|
+
rule.type === 'response_equals') &&
|
|
328
|
+
rule.value) {
|
|
329
|
+
positiveLiteralIntents.add(normalizeIntentValue(rule.value));
|
|
330
|
+
}
|
|
331
|
+
if (rule.type === 'response_jsonpath_exists' && rule.path) {
|
|
332
|
+
existingJsonPaths.add(rule.path.trim());
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return rules.filter((rule) => {
|
|
336
|
+
if (rule.type === 'forbidden_tool' && rule.value) {
|
|
337
|
+
return !requiredTools.has(rule.value.trim());
|
|
338
|
+
}
|
|
339
|
+
if (rule.type === 'response_not_contains' && rule.value) {
|
|
340
|
+
return !positiveLiteralIntents.has(normalizeIntentValue(rule.value));
|
|
341
|
+
}
|
|
342
|
+
if (rule.type === 'response_jsonpath_not_exists' && rule.path) {
|
|
343
|
+
return !existingJsonPaths.has(rule.path.trim());
|
|
344
|
+
}
|
|
345
|
+
return true;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
export function normalizeScenarioAssistantEvalRules(replacement) {
|
|
349
|
+
const normalized = [];
|
|
350
|
+
for (const rawRule of replacement) {
|
|
351
|
+
const rule = {
|
|
352
|
+
...rawRule,
|
|
353
|
+
...(typeof rawRule.value === 'string' ? { value: rawRule.value.trim() } : {}),
|
|
354
|
+
...(typeof rawRule.path === 'string' ? { path: rawRule.path.trim() } : {})
|
|
355
|
+
};
|
|
356
|
+
if (rule.type === 'response_regex' && rule.value) {
|
|
357
|
+
const parsed = tryParseRegexAsLiteral(rule.value);
|
|
358
|
+
if (parsed) {
|
|
359
|
+
if (hasEquivalentLiteralRule(normalized, parsed.literal)) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
normalized.push({
|
|
363
|
+
type: parsed.anchored ? 'response_equals' : 'response_contains',
|
|
364
|
+
value: parsed.literal
|
|
365
|
+
});
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
normalized.push(rule);
|
|
370
|
+
}
|
|
371
|
+
const deduped = [];
|
|
372
|
+
const seen = new Set();
|
|
373
|
+
for (const rule of normalized) {
|
|
374
|
+
const key = evalRuleKey(rule);
|
|
375
|
+
if (seen.has(key))
|
|
376
|
+
continue;
|
|
377
|
+
seen.add(key);
|
|
378
|
+
deduped.push(rule);
|
|
379
|
+
}
|
|
380
|
+
return lintContradictoryEvalRules(intentDeduplicateEvalRules(collapseOffByOneCountGuards(deduped)));
|
|
381
|
+
}
|
|
382
|
+
function normalizeEvalRuleSuggestions(suggestions) {
|
|
383
|
+
if (!suggestions?.evalRules?.replacement)
|
|
384
|
+
return;
|
|
385
|
+
suggestions.evalRules.replacement = normalizeScenarioAssistantEvalRules(suggestions.evalRules.replacement);
|
|
386
|
+
}
|
|
123
387
|
function parseAssistantModelOutput(text) {
|
|
124
388
|
const cleaned = text.trim();
|
|
125
389
|
let parsed;
|
|
@@ -180,6 +444,7 @@ export async function continueAssistantTurn(session) {
|
|
|
180
444
|
}
|
|
181
445
|
const modelOutput = await assistantChatModel(session);
|
|
182
446
|
normalizeEvalRuleToolNames(modelOutput.suggestions, session.toolPublicMap);
|
|
447
|
+
normalizeEvalRuleSuggestions(modelOutput.suggestions);
|
|
183
448
|
if (modelOutput.type === 'tool_call_request') {
|
|
184
449
|
const requestedCalls = 'toolCalls' in modelOutput && Array.isArray(modelOutput.toolCalls)
|
|
185
450
|
? modelOutput.toolCalls
|