@arclabs561/ai-visual-test 0.5.1 → 0.7.3
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 +102 -11
- package/DEPLOYMENT.md +225 -9
- package/README.md +71 -80
- package/index.d.ts +862 -3
- package/package.json +10 -51
- package/src/batch-optimizer.mjs +39 -0
- package/src/cache.mjs +241 -16
- package/src/config.mjs +33 -91
- package/src/constants.mjs +54 -0
- package/src/convenience.mjs +113 -10
- package/src/cost-optimization.mjs +1 -0
- package/src/cost-tracker.mjs +134 -2
- package/src/data-extractor.mjs +36 -7
- package/src/dynamic-few-shot.mjs +69 -11
- package/src/errors.mjs +6 -2
- package/src/experience-propagation.mjs +12 -0
- package/src/experience-tracer.mjs +12 -3
- package/src/game-player.mjs +222 -43
- package/src/graceful-shutdown.mjs +126 -0
- package/src/helpers/playwright.mjs +22 -8
- package/src/human-validation-manager.mjs +99 -2
- package/src/index.mjs +48 -3
- package/src/integrations/playwright.mjs +140 -0
- package/src/judge.mjs +697 -24
- package/src/load-env.mjs +2 -1
- package/src/logger.mjs +31 -3
- package/src/model-tier-selector.mjs +1 -221
- package/src/natural-language-specs.mjs +31 -3
- package/src/persona-enhanced.mjs +4 -2
- package/src/persona-experience.mjs +1 -1
- package/src/pricing.mjs +28 -0
- package/src/prompt-composer.mjs +162 -5
- package/src/provider-data.mjs +115 -0
- package/src/render-change-detector.mjs +5 -0
- package/src/research-enhanced-validation.mjs +7 -5
- package/src/retry.mjs +21 -7
- package/src/rubrics.mjs +4 -0
- package/src/safe-logger.mjs +71 -0
- package/src/session-cost-tracker.mjs +320 -0
- package/src/smart-validator.mjs +8 -8
- package/src/spec-templates.mjs +52 -6
- package/src/startup-validation.mjs +127 -0
- package/src/temporal-adaptive.mjs +2 -2
- package/src/temporal-decision-manager.mjs +1 -271
- package/src/temporal-logic.mjs +104 -0
- package/src/temporal-note-pruner.mjs +119 -0
- package/src/temporal-preprocessor.mjs +1 -543
- package/src/temporal.mjs +681 -79
- package/src/utils/action-hallucination-detector.mjs +301 -0
- package/src/utils/baseline-validator.mjs +82 -0
- package/src/utils/cache-stats.mjs +104 -0
- package/src/utils/cached-llm.mjs +164 -0
- package/src/utils/capability-stratifier.mjs +108 -0
- package/src/utils/counterfactual-tester.mjs +83 -0
- package/src/utils/error-recovery.mjs +117 -0
- package/src/utils/explainability-scorer.mjs +119 -0
- package/src/utils/exploratory-automation.mjs +131 -0
- package/src/utils/index.mjs +10 -0
- package/src/utils/intent-recognizer.mjs +201 -0
- package/src/utils/log-sanitizer.mjs +165 -0
- package/src/utils/path-validator.mjs +88 -0
- package/src/utils/performance-logger.mjs +316 -0
- package/src/utils/performance-measurement.mjs +280 -0
- package/src/utils/prompt-sanitizer.mjs +213 -0
- package/src/utils/rate-limiter.mjs +144 -0
- package/src/validation-framework.mjs +24 -20
- package/src/validation-result-normalizer.mjs +27 -1
- package/src/validation.mjs +75 -25
- package/src/validators/accessibility-validator.mjs +144 -0
- package/src/validators/hybrid-validator.mjs +48 -4
- package/api/health.js +0 -34
- package/api/validate.js +0 -252
- package/public/index.html +0 -149
- package/vercel.json +0 -27
package/src/spec-templates.mjs
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* Based on research findings:
|
|
8
8
|
* - Real-world BDD patterns (Cucumber, SpecFlow, Behave)
|
|
9
9
|
* - Real-world usage patterns (200+ tests)
|
|
10
|
-
* -
|
|
10
|
+
* - Practices (scenario independence, domain language, living documentation)
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { log } from './logger.mjs';
|
|
14
|
+
import { ValidationError } from './errors.mjs';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Built-in templates for common patterns
|
|
@@ -221,7 +222,16 @@ export function createSpecFromTemplate(templateName, variables = {}) {
|
|
|
221
222
|
const template = TEMPLATES[templateName];
|
|
222
223
|
|
|
223
224
|
if (!template) {
|
|
224
|
-
throw new
|
|
225
|
+
throw new ValidationError(
|
|
226
|
+
`Template "${templateName}" not found. ` +
|
|
227
|
+
`Available templates: ${Object.keys(TEMPLATES).join(', ')}. ` +
|
|
228
|
+
`Use listTemplates() to see all available templates, or registerTemplate() to create a custom one.`,
|
|
229
|
+
{
|
|
230
|
+
templateName,
|
|
231
|
+
availableTemplates: Object.keys(TEMPLATES),
|
|
232
|
+
function: 'createSpecFromTemplate'
|
|
233
|
+
}
|
|
234
|
+
);
|
|
225
235
|
}
|
|
226
236
|
|
|
227
237
|
// Merge template variables with provided variables
|
|
@@ -251,7 +261,15 @@ export function composeTemplates(templates, composition = 'sequential') {
|
|
|
251
261
|
// Parallel: execute all (would need execution framework support)
|
|
252
262
|
return templates.map(t => t.spec).join('\n\n---\n\n');
|
|
253
263
|
} else {
|
|
254
|
-
throw new
|
|
264
|
+
throw new ValidationError(
|
|
265
|
+
`Unknown composition type: "${composition}". ` +
|
|
266
|
+
`Supported types: "sequential" (execute one after another) or "parallel" (execute all).`,
|
|
267
|
+
{
|
|
268
|
+
composition,
|
|
269
|
+
supportedTypes: ['sequential', 'parallel'],
|
|
270
|
+
function: 'composeTemplates'
|
|
271
|
+
}
|
|
272
|
+
);
|
|
255
273
|
}
|
|
256
274
|
}
|
|
257
275
|
|
|
@@ -262,7 +280,16 @@ export function inheritTemplate(baseTemplateName, overrides = {}) {
|
|
|
262
280
|
const base = TEMPLATES[baseTemplateName];
|
|
263
281
|
|
|
264
282
|
if (!base) {
|
|
265
|
-
throw new
|
|
283
|
+
throw new ValidationError(
|
|
284
|
+
`Base template "${baseTemplateName}" not found. ` +
|
|
285
|
+
`Available templates: ${Object.keys(TEMPLATES).join(', ')}. ` +
|
|
286
|
+
`Use listTemplates() to see all available templates.`,
|
|
287
|
+
{
|
|
288
|
+
baseTemplateName,
|
|
289
|
+
availableTemplates: Object.keys(TEMPLATES),
|
|
290
|
+
function: 'inheritTemplate'
|
|
291
|
+
}
|
|
292
|
+
);
|
|
266
293
|
}
|
|
267
294
|
|
|
268
295
|
return {
|
|
@@ -280,7 +307,17 @@ export function inheritTemplate(baseTemplateName, overrides = {}) {
|
|
|
280
307
|
*/
|
|
281
308
|
export function registerTemplate(name, template) {
|
|
282
309
|
if (!template.name || !template.spec || !template.variables) {
|
|
283
|
-
throw new
|
|
310
|
+
throw new ValidationError(
|
|
311
|
+
'Template must have name, spec, and variables properties. ' +
|
|
312
|
+
'Template structure: { name: string, spec: string, variables: object }. ' +
|
|
313
|
+
'All three properties are required for template registration.',
|
|
314
|
+
{
|
|
315
|
+
hasName: !!template.name,
|
|
316
|
+
hasSpec: !!template.spec,
|
|
317
|
+
hasVariables: !!template.variables,
|
|
318
|
+
function: 'registerTemplate'
|
|
319
|
+
}
|
|
320
|
+
);
|
|
284
321
|
}
|
|
285
322
|
|
|
286
323
|
TEMPLATES[name] = template;
|
|
@@ -304,7 +341,16 @@ export function getTemplate(name) {
|
|
|
304
341
|
const template = TEMPLATES[name];
|
|
305
342
|
|
|
306
343
|
if (!template) {
|
|
307
|
-
throw new
|
|
344
|
+
throw new ValidationError(
|
|
345
|
+
`Template "${name}" not found. ` +
|
|
346
|
+
`Available templates: ${Object.keys(TEMPLATES).join(', ')}. ` +
|
|
347
|
+
`Use listTemplates() to see all available templates, or registerTemplate() to create a custom one.`,
|
|
348
|
+
{
|
|
349
|
+
templateName: name,
|
|
350
|
+
availableTemplates: Object.keys(TEMPLATES),
|
|
351
|
+
function: 'getTemplate'
|
|
352
|
+
}
|
|
353
|
+
);
|
|
308
354
|
}
|
|
309
355
|
|
|
310
356
|
return template;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup Validation
|
|
3
|
+
*
|
|
4
|
+
* Validates required environment variables and configuration at startup.
|
|
5
|
+
* Provides clear error messages if required configuration is missing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ConfigError } from './errors.mjs';
|
|
9
|
+
import { getConfig } from './config.mjs';
|
|
10
|
+
import { warn, error } from './logger.mjs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Required environment variables for each provider
|
|
14
|
+
*/
|
|
15
|
+
const REQUIRED_ENV_VARS = {
|
|
16
|
+
gemini: ['GEMINI_API_KEY'],
|
|
17
|
+
openai: ['OPENAI_API_KEY'],
|
|
18
|
+
anthropic: ['ANTHROPIC_API_KEY'],
|
|
19
|
+
claude: ['ANTHROPIC_API_KEY'], // Claude uses Anthropic API key
|
|
20
|
+
groq: ['GROQ_API_KEY']
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validate startup configuration
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} [options={}] - Validation options
|
|
27
|
+
* @param {boolean} [options.strict=true] - If true, throw on missing required vars. If false, warn only.
|
|
28
|
+
* @param {string} [options.provider=null] - Provider to validate (auto-detects if null)
|
|
29
|
+
* @throws {ConfigError} If strict mode and required vars are missing
|
|
30
|
+
*/
|
|
31
|
+
export function validateStartup(options = {}) {
|
|
32
|
+
const { strict = true, provider = null } = options;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const config = getConfig();
|
|
36
|
+
const providerToCheck = provider || config.provider;
|
|
37
|
+
|
|
38
|
+
if (!providerToCheck) {
|
|
39
|
+
if (strict) {
|
|
40
|
+
throw new ConfigError(
|
|
41
|
+
'No provider configured. Set VLM_PROVIDER environment variable or provide provider in config. ' +
|
|
42
|
+
'Supported providers: gemini, openai, claude, groq. ' +
|
|
43
|
+
'At least one API key must be set: GEMINI_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, or GROQ_API_KEY.',
|
|
44
|
+
{
|
|
45
|
+
supportedProviders: ['gemini', 'openai', 'claude', 'groq'],
|
|
46
|
+
requiredEnvVars: ['GEMINI_API_KEY', 'OPENAI_API_KEY', 'ANTHROPIC_API_KEY', 'GROQ_API_KEY']
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
} else {
|
|
50
|
+
warn('[StartupValidation] No provider configured. Some features may not work.');
|
|
51
|
+
return { valid: false, warnings: ['No provider configured'] };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check if provider is valid
|
|
56
|
+
const validProviders = ['gemini', 'openai', 'claude', 'anthropic', 'groq'];
|
|
57
|
+
if (!validProviders.includes(providerToCheck.toLowerCase())) {
|
|
58
|
+
if (strict) {
|
|
59
|
+
throw new ConfigError(
|
|
60
|
+
`Invalid provider: ${providerToCheck}. Supported providers: ${validProviders.join(', ')}.`,
|
|
61
|
+
{
|
|
62
|
+
provided: providerToCheck,
|
|
63
|
+
supported: validProviders
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
warn(`[StartupValidation] Invalid provider: ${providerToCheck}`);
|
|
68
|
+
return { valid: false, warnings: [`Invalid provider: ${providerToCheck}`] };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check required API keys for the provider
|
|
73
|
+
const requiredVars = REQUIRED_ENV_VARS[providerToCheck.toLowerCase()] || [];
|
|
74
|
+
const missingVars = requiredVars.filter(key => !process.env[key]);
|
|
75
|
+
|
|
76
|
+
if (missingVars.length > 0) {
|
|
77
|
+
const errorMsg = `Missing required environment variables for provider '${providerToCheck}': ${missingVars.join(', ')}. ` +
|
|
78
|
+
`Set these in your .env file or as environment variables. ` +
|
|
79
|
+
`Example: ${missingVars[0]}=your-api-key-here`;
|
|
80
|
+
|
|
81
|
+
if (strict) {
|
|
82
|
+
throw new ConfigError(errorMsg, {
|
|
83
|
+
provider: providerToCheck,
|
|
84
|
+
missingVars,
|
|
85
|
+
requiredVars
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
warn(`[StartupValidation] ${errorMsg}`);
|
|
89
|
+
return { valid: false, warnings: [errorMsg] };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check if config is enabled
|
|
94
|
+
if (!config.enabled) {
|
|
95
|
+
warn('[StartupValidation] VLLM validation is disabled. Set enabled: true in config to enable.');
|
|
96
|
+
return { valid: true, warnings: ['VLLM validation is disabled'] };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { valid: true, warnings: [] };
|
|
100
|
+
} catch (err) {
|
|
101
|
+
if (err instanceof ConfigError) {
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Unexpected error
|
|
106
|
+
error('[StartupValidation] Unexpected error during validation:', err);
|
|
107
|
+
if (strict) {
|
|
108
|
+
throw new ConfigError(
|
|
109
|
+
`Startup validation failed: ${err.message}`,
|
|
110
|
+
{ originalError: err.message }
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return { valid: false, warnings: [`Validation error: ${err.message}`] };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Validate startup configuration (non-strict, returns warnings)
|
|
119
|
+
*
|
|
120
|
+
* @param {Object} [options={}] - Validation options
|
|
121
|
+
* @returns {Object} Validation result with valid flag and warnings array
|
|
122
|
+
*/
|
|
123
|
+
export function validateStartupSoft(options = {}) {
|
|
124
|
+
return validateStartup({ ...options, strict: false });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
@@ -127,7 +127,7 @@ export function detectActivityPattern(notes) {
|
|
|
127
127
|
* }} [options={}] - Aggregation options
|
|
128
128
|
* @returns {import('./index.mjs').AggregatedTemporalNotes} Aggregated temporal notes
|
|
129
129
|
*/
|
|
130
|
-
export function aggregateTemporalNotesAdaptive(notes, options = {}) {
|
|
130
|
+
export async function aggregateTemporalNotesAdaptive(notes, options = {}) {
|
|
131
131
|
const {
|
|
132
132
|
adaptive = true,
|
|
133
133
|
windowSize,
|
|
@@ -152,7 +152,7 @@ export function aggregateTemporalNotesAdaptive(notes, options = {}) {
|
|
|
152
152
|
finalWindowSize = 10000; // Default
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
return aggregateTemporalNotes(notes, {
|
|
155
|
+
return await aggregateTemporalNotes(notes, {
|
|
156
156
|
windowSize: finalWindowSize,
|
|
157
157
|
decayFactor,
|
|
158
158
|
coherenceThreshold
|
|
@@ -1,271 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Temporal Decision Manager
|
|
3
|
-
*
|
|
4
|
-
* Implements decision logic for WHEN to prompt based on temporal context.
|
|
5
|
-
*
|
|
6
|
-
* Research: arXiv:2406.12125 - "Efficient Sequential Decision Making"
|
|
7
|
-
* - Paper's core finding: Don't prompt on every state change, prompt when decision is needed
|
|
8
|
-
* - Online model selection achieves 6x gains with 1.5% LLM calls
|
|
9
|
-
*
|
|
10
|
-
* This module implements the decision logic (when to prompt) that was missing from
|
|
11
|
-
* our temporal aggregation system. It complements temporal-decision.mjs which handles
|
|
12
|
-
* HOW to aggregate temporal context, while this handles WHEN to use it.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { aggregateTemporalNotes } from './temporal.mjs';
|
|
16
|
-
import { aggregateMultiScale } from './temporal-decision.mjs';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Temporal Decision Manager
|
|
20
|
-
*
|
|
21
|
-
* Decides when context is sufficient to prompt, when to wait, and when to prompt immediately.
|
|
22
|
-
*/
|
|
23
|
-
export class TemporalDecisionManager {
|
|
24
|
-
constructor(options = {}) {
|
|
25
|
-
this.minNotesForPrompt = options.minNotesForPrompt || 3; // Minimum notes before prompting
|
|
26
|
-
this.coherenceThreshold = options.coherenceThreshold || 0.5; // Minimum coherence to prompt
|
|
27
|
-
this.urgencyThreshold = options.urgencyThreshold || 0.3; // Coherence drop triggers urgency
|
|
28
|
-
this.maxWaitTime = options.maxWaitTime || 10000; // Max time to wait (10s)
|
|
29
|
-
this.stateChangeThreshold = options.stateChangeThreshold || 0.2; // Significant state change
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Decide if we should prompt now or wait for more context
|
|
34
|
-
*
|
|
35
|
-
* @param {Object} currentState - Current state
|
|
36
|
-
* @param {Object} previousState - Previous state (if any)
|
|
37
|
-
* @param {import('./index.mjs').TemporalNote[]} temporalNotes - Temporal notes so far
|
|
38
|
-
* @param {Object} context - Additional context
|
|
39
|
-
* @returns {{shouldPrompt: boolean, reason: string, urgency: 'low'|'medium'|'high'}}
|
|
40
|
-
*/
|
|
41
|
-
shouldPrompt(currentState, previousState, temporalNotes, context = {}) {
|
|
42
|
-
// 1. Check if we have minimum notes
|
|
43
|
-
if (temporalNotes.length < this.minNotesForPrompt) {
|
|
44
|
-
return {
|
|
45
|
-
shouldPrompt: false,
|
|
46
|
-
reason: `Insufficient notes (${temporalNotes.length} < ${this.minNotesForPrompt})`,
|
|
47
|
-
urgency: 'low'
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 2. Calculate temporal coherence
|
|
52
|
-
const aggregated = aggregateTemporalNotes(temporalNotes);
|
|
53
|
-
const coherence = aggregated.coherence || 0;
|
|
54
|
-
|
|
55
|
-
// 3. Check for significant state change
|
|
56
|
-
const stateChange = this.calculateStateChange(currentState, previousState);
|
|
57
|
-
|
|
58
|
-
// 4. Check for user action
|
|
59
|
-
const hasUserAction = this.hasRecentUserAction(temporalNotes, context);
|
|
60
|
-
|
|
61
|
-
// 5. Check for decision point
|
|
62
|
-
const isDecisionPoint = this.isDecisionPoint(currentState, context);
|
|
63
|
-
|
|
64
|
-
// 6. Check for coherence drop (urgency signal)
|
|
65
|
-
const coherenceDrop = this.detectCoherenceDrop(temporalNotes, aggregated);
|
|
66
|
-
|
|
67
|
-
// Decision logic (from research: prompt when decision needed, not on every change)
|
|
68
|
-
if (isDecisionPoint) {
|
|
69
|
-
return {
|
|
70
|
-
shouldPrompt: true,
|
|
71
|
-
reason: 'Decision point reached',
|
|
72
|
-
urgency: 'high'
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (coherenceDrop) {
|
|
77
|
-
return {
|
|
78
|
-
shouldPrompt: true,
|
|
79
|
-
reason: 'Coherence drop detected (quality issue)',
|
|
80
|
-
urgency: 'high'
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (hasUserAction && stateChange > this.stateChangeThreshold) {
|
|
85
|
-
return {
|
|
86
|
-
shouldPrompt: true,
|
|
87
|
-
reason: 'User action with significant state change',
|
|
88
|
-
urgency: 'medium'
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (coherence >= this.coherenceThreshold && stateChange > this.stateChangeThreshold) {
|
|
93
|
-
return {
|
|
94
|
-
shouldPrompt: true,
|
|
95
|
-
reason: 'Stable context with significant state change',
|
|
96
|
-
urgency: 'medium'
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Wait for more context
|
|
101
|
-
return {
|
|
102
|
-
shouldPrompt: false,
|
|
103
|
-
reason: `Context not sufficient (coherence: ${coherence.toFixed(2)}, stateChange: ${stateChange.toFixed(2)})`,
|
|
104
|
-
urgency: 'low'
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Calculate state change magnitude
|
|
110
|
-
*/
|
|
111
|
-
calculateStateChange(currentState, previousState) {
|
|
112
|
-
if (!previousState) return 1.0; // First state = maximum change
|
|
113
|
-
|
|
114
|
-
// Simple state change calculation (can be enhanced)
|
|
115
|
-
let change = 0.0;
|
|
116
|
-
let comparisons = 0;
|
|
117
|
-
|
|
118
|
-
// Compare scores if available
|
|
119
|
-
if (currentState.score !== undefined && previousState.score !== undefined) {
|
|
120
|
-
const scoreChange = Math.abs(currentState.score - previousState.score) / 10; // Normalize to 0-1
|
|
121
|
-
change += scoreChange;
|
|
122
|
-
comparisons++;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Compare issues if available
|
|
126
|
-
if (currentState.issues && previousState.issues) {
|
|
127
|
-
const currentIssues = new Set(currentState.issues);
|
|
128
|
-
const previousIssues = new Set(previousState.issues);
|
|
129
|
-
const added = [...currentIssues].filter(i => !previousIssues.has(i)).length;
|
|
130
|
-
const removed = [...previousIssues].filter(i => !currentIssues.has(i)).length;
|
|
131
|
-
const issueChange = (added + removed) / Math.max(currentIssues.size + previousIssues.size, 1);
|
|
132
|
-
change += issueChange;
|
|
133
|
-
comparisons++;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Compare game state if available
|
|
137
|
-
if (currentState.gameState && previousState.gameState) {
|
|
138
|
-
const gameStateChange = this.calculateGameStateChange(currentState.gameState, previousState.gameState);
|
|
139
|
-
change += gameStateChange;
|
|
140
|
-
comparisons++;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return comparisons > 0 ? change / comparisons : 0.0;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Calculate game state change
|
|
148
|
-
*/
|
|
149
|
-
calculateGameStateChange(current, previous) {
|
|
150
|
-
// Simple comparison (can be enhanced)
|
|
151
|
-
const currentKeys = Object.keys(current || {});
|
|
152
|
-
const previousKeys = Object.keys(previous || {});
|
|
153
|
-
|
|
154
|
-
const added = currentKeys.filter(k => !previousKeys.includes(k)).length;
|
|
155
|
-
const removed = previousKeys.filter(k => !currentKeys.includes(k)).length;
|
|
156
|
-
const changed = currentKeys.filter(k =>
|
|
157
|
-
previousKeys.includes(k) &&
|
|
158
|
-
JSON.stringify(current[k]) !== JSON.stringify(previous[k])
|
|
159
|
-
).length;
|
|
160
|
-
|
|
161
|
-
const totalKeys = new Set([...currentKeys, ...previousKeys]).size;
|
|
162
|
-
return totalKeys > 0 ? (added + removed + changed) / totalKeys : 0.0;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Check for recent user action
|
|
167
|
-
*/
|
|
168
|
-
hasRecentUserAction(temporalNotes, context) {
|
|
169
|
-
if (context.recentAction) return true;
|
|
170
|
-
|
|
171
|
-
// Check last few notes for interactions
|
|
172
|
-
const recentNotes = temporalNotes.slice(-3);
|
|
173
|
-
return recentNotes.some(note =>
|
|
174
|
-
note.step?.includes('interaction') ||
|
|
175
|
-
note.step?.includes('click') ||
|
|
176
|
-
note.step?.includes('action') ||
|
|
177
|
-
note.observation?.includes('user') ||
|
|
178
|
-
note.observation?.includes('clicked')
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Check if this is a decision point
|
|
184
|
-
*/
|
|
185
|
-
isDecisionPoint(currentState, context) {
|
|
186
|
-
// Decision points based on context
|
|
187
|
-
if (context.stage === 'decision' || context.stage === 'evaluation') return true;
|
|
188
|
-
if (context.testType === 'critical' || context.critical) return true;
|
|
189
|
-
if (context.goal && context.goalCompleted) return true;
|
|
190
|
-
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Detect coherence drop (quality issue signal)
|
|
196
|
-
*/
|
|
197
|
-
detectCoherenceDrop(temporalNotes, currentAggregated) {
|
|
198
|
-
if (temporalNotes.length < 4) return false; // Need history to detect drop
|
|
199
|
-
|
|
200
|
-
// Get previous coherence (from notes without last one)
|
|
201
|
-
const previousNotes = temporalNotes.slice(0, -1);
|
|
202
|
-
const previousAggregated = aggregateTemporalNotes(previousNotes);
|
|
203
|
-
const previousCoherence = previousAggregated.coherence || 1.0;
|
|
204
|
-
const currentCoherence = currentAggregated.coherence || 1.0;
|
|
205
|
-
|
|
206
|
-
// Drop detected if coherence decreased significantly
|
|
207
|
-
const drop = previousCoherence - currentCoherence;
|
|
208
|
-
return drop > this.urgencyThreshold;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Calculate prompt urgency
|
|
213
|
-
*/
|
|
214
|
-
calculatePromptUrgency(temporalContext, decision) {
|
|
215
|
-
if (decision.urgency === 'high') return 1.0;
|
|
216
|
-
if (decision.urgency === 'medium') return 0.6;
|
|
217
|
-
|
|
218
|
-
// Low urgency, but check if we should wait
|
|
219
|
-
const coherence = temporalContext.coherence || 0;
|
|
220
|
-
const timeSinceLastPrompt = temporalContext.timeSinceLastPrompt || 0;
|
|
221
|
-
|
|
222
|
-
// Increase urgency if coherence is good and it's been a while
|
|
223
|
-
if (coherence > 0.7 && timeSinceLastPrompt > 5000) {
|
|
224
|
-
return 0.4; // Medium-low
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return 0.2; // Low
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Select optimal timing for requests
|
|
232
|
-
*/
|
|
233
|
-
selectOptimalTiming(requests, temporalContext) {
|
|
234
|
-
const decisions = requests.map(req => ({
|
|
235
|
-
request: req,
|
|
236
|
-
decision: this.shouldPrompt(
|
|
237
|
-
req.currentState,
|
|
238
|
-
req.previousState,
|
|
239
|
-
req.temporalNotes || [],
|
|
240
|
-
req.context || {}
|
|
241
|
-
)
|
|
242
|
-
}));
|
|
243
|
-
|
|
244
|
-
// Separate by urgency
|
|
245
|
-
const urgent = decisions.filter(d => d.decision.urgency === 'high');
|
|
246
|
-
const medium = decisions.filter(d => d.decision.urgency === 'medium');
|
|
247
|
-
const low = decisions.filter(d => d.decision.urgency === 'low');
|
|
248
|
-
|
|
249
|
-
// Urgent: prompt immediately
|
|
250
|
-
// Medium: batch if context stable, otherwise prompt
|
|
251
|
-
// Low: wait or batch
|
|
252
|
-
|
|
253
|
-
const stable = temporalContext.coherence > 0.7;
|
|
254
|
-
const shouldBatch = stable && medium.length + low.length > 1;
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
promptNow: urgent.map(d => d.request),
|
|
258
|
-
batch: shouldBatch ? [...medium, ...low].map(d => d.request) : medium.map(d => d.request),
|
|
259
|
-
wait: shouldBatch ? [] : low.map(d => d.request),
|
|
260
|
-
decisions
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Create a temporal decision manager with default options
|
|
267
|
-
*/
|
|
268
|
-
export function createTemporalDecisionManager(options = {}) {
|
|
269
|
-
return new TemporalDecisionManager(options);
|
|
270
|
-
}
|
|
271
|
-
|
|
1
|
+
function _0x2d4d(_0x367a17,_0x47eaad){const _0x5adfe0=_0x1330();return _0x2d4d=function(_0x1196b0,_0x151439){_0x1196b0=_0x1196b0-0xc3;let _0x133077=_0x5adfe0[_0x1196b0];if(_0x2d4d['XbgOSk']===undefined){var _0x2d4df6=function(_0x3769fe){const _0x32d6ed='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x57097e='',_0x5dee23='',_0x59d90b=_0x57097e+_0x2d4df6;for(let _0x172e6e=0x0,_0x4c7830,_0x3ebc52,_0x185993=0x0;_0x3ebc52=_0x3769fe['charAt'](_0x185993++);~_0x3ebc52&&(_0x4c7830=_0x172e6e%0x4?_0x4c7830*0x40+_0x3ebc52:_0x3ebc52,_0x172e6e++%0x4)?_0x57097e+=_0x59d90b['charCodeAt'](_0x185993+0xa)-0xa!==0x0?String['fromCharCode'](0xff&_0x4c7830>>(-0x2*_0x172e6e&0x6)):_0x172e6e:0x0){_0x3ebc52=_0x32d6ed['indexOf'](_0x3ebc52);}for(let _0x29fdfd=0x0,_0x28c0d8=_0x57097e['length'];_0x29fdfd<_0x28c0d8;_0x29fdfd++){_0x5dee23+='%'+('00'+_0x57097e['charCodeAt'](_0x29fdfd)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x5dee23);};_0x2d4d['acpqJo']=_0x2d4df6,_0x367a17=arguments,_0x2d4d['XbgOSk']=!![];}const _0x324b05=_0x5adfe0[0x0],_0x2f9dcc=_0x1196b0+_0x324b05,_0x2c4bad=_0x367a17[_0x2f9dcc];if(!_0x2c4bad){const _0x18f69e=function(_0x42b6fe){this['dTptnW']=_0x42b6fe,this['ILbMRF']=[0x1,0x0,0x0],this['ksCCBd']=function(){return'newState';},this['NruUXV']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['UWVNZS']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x18f69e['prototype']['GEBCWe']=function(){const _0x223615=new RegExp(this['NruUXV']+this['UWVNZS']),_0x12f757=_0x223615['test'](this['ksCCBd']['toString']())?--this['ILbMRF'][0x1]:--this['ILbMRF'][0x0];return this['QXjGly'](_0x12f757);},_0x18f69e['prototype']['QXjGly']=function(_0x4052bb){if(!Boolean(~_0x4052bb))return _0x4052bb;return this['NbqPoa'](this['dTptnW']);},_0x18f69e['prototype']['NbqPoa']=function(_0x3c146f){for(let _0x2df29d=0x0,_0x2e8d8f=this['ILbMRF']['length'];_0x2df29d<_0x2e8d8f;_0x2df29d++){this['ILbMRF']['push'](Math['round'](Math['random']())),_0x2e8d8f=this['ILbMRF']['length'];}return _0x3c146f(this['ILbMRF'][0x0]);},new _0x18f69e(_0x2d4d)['GEBCWe'](),_0x133077=_0x2d4d['acpqJo'](_0x133077),_0x367a17[_0x2f9dcc]=_0x133077;}else _0x133077=_0x2c4bad;return _0x133077;},_0x2d4d(_0x367a17,_0x47eaad);}const _0x15d7dc=_0x2d4d;(function(_0x44ceef,_0x1d47b4){const _0xda4ac2=_0x2d4d,_0x52d929=_0x44ceef();while(!![]){try{const _0x2dbb88=-parseInt(_0xda4ac2(0x162))/0x1+parseInt(_0xda4ac2(0xc8))/0x2*(-parseInt(_0xda4ac2(0xfa))/0x3)+parseInt(_0xda4ac2(0xe0))/0x4+-parseInt(_0xda4ac2(0x108))/0x5+parseInt(_0xda4ac2(0x163))/0x6+-parseInt(_0xda4ac2(0xd0))/0x7+parseInt(_0xda4ac2(0xf2))/0x8*(parseInt(_0xda4ac2(0x152))/0x9);if(_0x2dbb88===_0x1d47b4)break;else _0x52d929['push'](_0x52d929['shift']());}catch(_0x4a003a){_0x52d929['push'](_0x52d929['shift']());}}}(_0x1330,0x5264a));const _0x151439=(function(){let _0x18f69e=!![];return function(_0x42b6fe,_0x223615){const _0x12f757=_0x18f69e?function(){if(_0x223615){const _0x4052bb=_0x223615['apply'](_0x42b6fe,arguments);return _0x223615=null,_0x4052bb;}}:function(){};return _0x18f69e=![],_0x12f757;};}()),_0x1196b0=_0x151439(this,function(){const _0x370a29=_0x2d4d;return _0x1196b0[_0x370a29(0xcf)+'ing']()['searc'+'h']('(((.+'+_0x370a29(0x10e)+'+$')[_0x370a29(0xcf)+_0x370a29(0xe8)]()[_0x370a29(0xde)+'ructo'+'r'](_0x1196b0)['searc'+'h']('(((.+'+_0x370a29(0x10e)+'+$');});_0x1196b0();import{aggregateTemporalNotes}from'./temporal.mjs';import{aggregateMultiScale}from'./temporal-decision.mjs';export class TemporalDecisionManager{constructor(_0x3c146f={}){const _0x553017=_0x2d4d,_0x2df29d=_0x3c146f[_0x553017(0x126)+'tesFo'+'rProm'+'pt']??0x3,_0x2e8d8f=_0x3c146f['coher'+'enceT'+_0x553017(0xc3)+_0x553017(0x10d)]??0.5,_0x278243=_0x3c146f['urgen'+_0x553017(0x167)+'eshol'+'d']??0.3,_0x397e5f=_0x3c146f['maxWa'+'itTim'+'e']??0x2710,_0x2dd172=_0x3c146f[_0x553017(0x15a)+'Chang'+'eThre'+'shold']??0.2;if(_0x2df29d<0x1||!Number['isInt'+'eger'](_0x2df29d))throw new RangeError('minNo'+_0x553017(0x115)+'rProm'+'pt\x20mu'+'st\x20be'+'\x20a\x20po'+'sitiv'+_0x553017(0xf7)+'eger,'+_0x553017(0x13d)+'\x20'+_0x2df29d);if(_0x2e8d8f<0x0||_0x2e8d8f>0x1)throw new RangeError('coher'+_0x553017(0xdf)+_0x553017(0xc3)+_0x553017(0x13f)+'ust\x20b'+'e\x20in\x20'+'[0,\x201'+_0x553017(0x118)+_0x553017(0xe6)+_0x2e8d8f);if(_0x278243<0x0||_0x278243>0x1)throw new RangeError('urgen'+'cyThr'+'eshol'+'d\x20mus'+'t\x20be\x20'+_0x553017(0x133)+',\x201],'+_0x553017(0x13d)+'\x20'+_0x278243);if(_0x397e5f<=0x0||!isFinite(_0x397e5f))throw new RangeError('maxWa'+_0x553017(0xf6)+_0x553017(0x112)+_0x553017(0xd2)+'a\x20pos'+'itive'+_0x553017(0x151)+_0x553017(0x11b)+_0x553017(0x161)+'\x20got:'+'\x20'+_0x397e5f);if(_0x2dd172<0x0||_0x2dd172>0x1)throw new RangeError('state'+_0x553017(0xfb)+'eThre'+'shold'+_0x553017(0xdb)+'\x20be\x20i'+'n\x20[0,'+'\x201],\x20'+'got:\x20'+_0x2dd172);this['minNo'+_0x553017(0x115)+_0x553017(0x168)+'pt']=_0x2df29d,this[_0x553017(0x107)+'enceT'+_0x553017(0xc3)+_0x553017(0x10d)]=_0x2e8d8f,this[_0x553017(0xe4)+_0x553017(0x167)+_0x553017(0x103)+'d']=_0x278243,this[_0x553017(0xce)+'itTim'+'e']=_0x397e5f,this[_0x553017(0x15a)+_0x553017(0xfb)+_0x553017(0x106)+_0x553017(0x147)]=_0x2dd172,this['warmS'+'tartS'+'teps']=_0x3c146f['warmS'+_0x553017(0xdd)+'teps']||0xa,this['adapt'+_0x553017(0xe9)+_0x553017(0x145)+'g']=_0x3c146f[_0x553017(0xd6)+'iveSa'+_0x553017(0x145)+'g']!==![],this[_0x553017(0x127)+_0x553017(0x11a)]=0x0,this[_0x553017(0xc9)+_0x553017(0xe3)+'Time']=null;}async[_0x15d7dc(0x111)+'dProm'+'pt'](_0x106ae2,_0x11a051,_0x5a7512,_0x49ff46={}){const _0x5d7d13=_0x15d7dc;if(!Array['isArr'+'ay'](_0x5a7512))throw new TypeError('tempo'+'ralNo'+_0x5d7d13(0xd5)+'ust\x20b'+'e\x20an\x20'+_0x5d7d13(0xe5));if(_0x106ae2===null||_0x106ae2===undefined)throw new TypeError('curre'+'ntSta'+'te\x20is'+_0x5d7d13(0xfe)+'ired');this[_0x5d7d13(0x127)+_0x5d7d13(0x11a)]++;if(this[_0x5d7d13(0xd6)+_0x5d7d13(0xe9)+_0x5d7d13(0x145)+'g']&&this['stepC'+_0x5d7d13(0x11a)]<=this[_0x5d7d13(0x153)+_0x5d7d13(0xdd)+'teps']){const _0x68c2de={};return _0x68c2de['shoul'+_0x5d7d13(0x157)+'pt']=!![],_0x68c2de[_0x5d7d13(0x14b)+'n']=_0x5d7d13(0x139)+'start'+'\x20step'+'\x20'+this['stepC'+_0x5d7d13(0x11a)]+'/'+this[_0x5d7d13(0x153)+_0x5d7d13(0xdd)+_0x5d7d13(0xe7)]+('\x20(res'+'earch'+':\x20LLM'+'s\x20goo'+'d\x20ear'+'ly)'),_0x68c2de['urgen'+'cy']=_0x5d7d13(0x128)+'m',_0x68c2de;}if(this[_0x5d7d13(0xd6)+_0x5d7d13(0xe9)+_0x5d7d13(0x145)+'g']&&this[_0x5d7d13(0xc9)+'rompt'+_0x5d7d13(0xd1)]){const _0x55f026=0.1,_0x2b724c=0x1,_0x1d73e6=0.1,_0x3db3bd=Math[_0x5d7d13(0xcc)](0x0,this['stepC'+'ount']-this[_0x5d7d13(0x153)+_0x5d7d13(0xdd)+_0x5d7d13(0xe7)]),_0x5ca631=Math[_0x5d7d13(0xf8)](_0x2b724c,Math[_0x5d7d13(0xcc)](_0x1d73e6,Math[_0x5d7d13(0x12f)](-_0x55f026*_0x3db3bd)));this['_last'+'Promp'+_0x5d7d13(0x16d)+'abili'+'ty']=_0x5ca631;}if(_0x5a7512[_0x5d7d13(0xd3)+'h']<this['minNo'+'tesFo'+_0x5d7d13(0x168)+'pt']){const _0x173af1={};return _0x173af1[_0x5d7d13(0x111)+_0x5d7d13(0x157)+'pt']=![],_0x173af1['reaso'+'n']='Insuf'+'ficie'+_0x5d7d13(0xf1)+_0x5d7d13(0x105)+_0x5a7512[_0x5d7d13(0xd3)+'h']+_0x5d7d13(0x132)+this['minNo'+'tesFo'+'rProm'+'pt']+')',_0x173af1[_0x5d7d13(0xe4)+'cy']='low',_0x173af1;}let _0x92df28;this['prepr'+_0x5d7d13(0x141)+'or']?_0x92df28=await this['prepr'+'ocess'+'or']['getFa'+'stAgg'+'regat'+'ion'](_0x5a7512):_0x92df28=await aggregateTemporalNotes(_0x5a7512);const _0x1ed9d4=_0x92df28[_0x5d7d13(0x107)+'ence']||0x0,_0x2b7221=this[_0x5d7d13(0xe1)+_0x5d7d13(0xca)+'tateC'+_0x5d7d13(0x150)](_0x106ae2,_0x11a051),_0x20dc99=this[_0x5d7d13(0xec)+'centU'+_0x5d7d13(0x156)+_0x5d7d13(0x12d)](_0x5a7512,_0x49ff46),_0x17bfdc=this[_0x5d7d13(0x100)+'ision'+_0x5d7d13(0xd9)](_0x106ae2,_0x49ff46),_0x3782ed=await this[_0x5d7d13(0x14c)+_0x5d7d13(0xf4)+'rence'+_0x5d7d13(0x101)](_0x5a7512,_0x92df28);if(_0x17bfdc){this[_0x5d7d13(0xc9)+'rompt'+_0x5d7d13(0xd1)]=Date[_0x5d7d13(0x124)]();const _0x537d48={};_0x537d48['shoul'+_0x5d7d13(0x157)+'pt']=!![],_0x537d48['reaso'+'n']=_0x5d7d13(0xcd)+_0x5d7d13(0x11f)+'oint\x20'+_0x5d7d13(0x134)+'ed',_0x537d48[_0x5d7d13(0xe4)+'cy']='high';const _0x2e69fe=_0x537d48;return import('./uti'+'ls/pe'+'rform'+'ance-'+_0x5d7d13(0x140)+'r.mjs')[_0x5d7d13(0x12c)](({logTemporalDecision:_0x3f22ce})=>{const _0x89713e=_0x5d7d13,_0x4834c4={};_0x4834c4['shoul'+_0x89713e(0x157)+'pt']=_0x2e69fe['shoul'+_0x89713e(0x157)+'pt'],_0x4834c4['reaso'+'n']=_0x2e69fe['reaso'+'n'],_0x4834c4['urgen'+'cy']=_0x2e69fe[_0x89713e(0xe4)+'cy'],_0x4834c4['coher'+'ence']=_0x1ed9d4,_0x4834c4[_0x89713e(0x15a)+_0x89713e(0xfb)+'e']=_0x2b7221,_0x4834c4['noteC'+_0x89713e(0x11a)]=_0x5a7512[_0x89713e(0xd3)+'h'],_0x4834c4['isDec'+_0x89713e(0x14f)+_0x89713e(0xd9)]=!![],_0x4834c4['hasUs'+'erAct'+'ion']=_0x20dc99,_0x3f22ce(_0x4834c4);})[_0x5d7d13(0xd7)](async importError=>{const _0xb58db7=_0x5d7d13;if(process[_0xb58db7(0x131)][_0xb58db7(0x155)+'_TEMP'+_0xb58db7(0x165)])try{const {warn:_0x508a5d}=await import(_0xb58db7(0x12b)+'ger.m'+'js');_0x508a5d('[Temp'+_0xb58db7(0x143)+'ecisi'+_0xb58db7(0x16c)+_0xb58db7(0xc7)+_0xb58db7(0x13e)+_0xb58db7(0xef)+'er\x20un'+_0xb58db7(0xc6)+'able:'+'\x20'+importError[_0xb58db7(0x119)+'ge']);}catch{console[_0xb58db7(0xeb)](_0xb58db7(0x160)+_0xb58db7(0x143)+'ecisi'+_0xb58db7(0x16c)+'erfor'+_0xb58db7(0x13e)+_0xb58db7(0xef)+_0xb58db7(0x16f)+'avail'+'able:'+'\x20'+importError['messa'+'ge']);}}),_0x2e69fe;}if(_0x3782ed){this['lastP'+_0x5d7d13(0xe3)+_0x5d7d13(0xd1)]=Date[_0x5d7d13(0x124)]();const _0x2e50c6={};_0x2e50c6['shoul'+'dProm'+'pt']=!![],_0x2e50c6['reaso'+'n']=_0x5d7d13(0x164)+'ence\x20'+'drop\x20'+'detec'+'ted\x20('+_0x5d7d13(0xcb)+'ty\x20is'+_0x5d7d13(0xda),_0x2e50c6['urgen'+'cy']='high';const _0x3b4609=_0x2e50c6;return import(_0x5d7d13(0x166)+_0x5d7d13(0x15b)+_0x5d7d13(0x109)+'ance-'+_0x5d7d13(0x140)+'r.mjs')['then'](({logTemporalDecision:_0x5b0994})=>{const _0x12ace0=_0x5d7d13,_0x4b1d01={};_0x4b1d01['shoul'+_0x12ace0(0x157)+'pt']=_0x3b4609['shoul'+'dProm'+'pt'],_0x4b1d01[_0x12ace0(0x14b)+'n']=_0x3b4609['reaso'+'n'],_0x4b1d01['urgen'+'cy']=_0x3b4609[_0x12ace0(0xe4)+'cy'],_0x4b1d01['coher'+'ence']=_0x1ed9d4,_0x4b1d01[_0x12ace0(0x15a)+'Chang'+'e']=_0x2b7221,_0x4b1d01['noteC'+_0x12ace0(0x11a)]=_0x5a7512[_0x12ace0(0xd3)+'h'],_0x4b1d01['isDec'+'ision'+'Point']=![],_0x4b1d01[_0x12ace0(0xff)+'erAct'+_0x12ace0(0xf9)]=_0x20dc99,_0x5b0994(_0x4b1d01);})['catch'](async importError=>{const _0x5d8d8b=_0x5d7d13;if(process['env'][_0x5d8d8b(0x155)+_0x5d8d8b(0x114)+_0x5d8d8b(0x165)])try{const {warn:_0x343cee}=await import(_0x5d8d8b(0x12b)+_0x5d8d8b(0x154)+'js');_0x343cee(_0x5d8d8b(0x160)+'oralD'+_0x5d8d8b(0x135)+'on]\x20P'+_0x5d8d8b(0xc7)+'mance'+_0x5d8d8b(0xef)+_0x5d8d8b(0x16f)+'avail'+_0x5d8d8b(0x146)+'\x20'+importError[_0x5d8d8b(0x119)+'ge']);}catch{console['warn'](_0x5d8d8b(0x160)+'oralD'+_0x5d8d8b(0x135)+_0x5d8d8b(0x16c)+'erfor'+'mance'+'\x20logg'+_0x5d8d8b(0x16f)+'avail'+'able:'+'\x20'+importError[_0x5d8d8b(0x119)+'ge']);}}),_0x3b4609;}if(_0x20dc99&&_0x2b7221>this[_0x5d7d13(0x15a)+'Chang'+'eThre'+'shold']){this[_0x5d7d13(0xc9)+_0x5d7d13(0xe3)+_0x5d7d13(0xd1)]=Date['now']();const _0x11ff19={};return _0x11ff19[_0x5d7d13(0x111)+'dProm'+'pt']=!![],_0x11ff19[_0x5d7d13(0x14b)+'n']=_0x5d7d13(0xf0)+_0x5d7d13(0xea)+_0x5d7d13(0x122)+'h\x20sig'+_0x5d7d13(0x159)+'ant\x20s'+_0x5d7d13(0x16a)+_0x5d7d13(0xfc)+'e',_0x11ff19['urgen'+'cy']='mediu'+'m',_0x11ff19;}if(_0x1ed9d4>=this[_0x5d7d13(0x107)+'enceT'+_0x5d7d13(0xc3)+_0x5d7d13(0x10d)]&&_0x2b7221>this[_0x5d7d13(0x15a)+'Chang'+'eThre'+'shold']){this['lastP'+_0x5d7d13(0xe3)+'Time']=Date[_0x5d7d13(0x124)]();const _0x2bd6b8={};return _0x2bd6b8['shoul'+'dProm'+'pt']=!![],_0x2bd6b8[_0x5d7d13(0x14b)+'n']=_0x5d7d13(0x129)+'e\x20con'+_0x5d7d13(0x142)+_0x5d7d13(0x10c)+_0x5d7d13(0x110)+'fican'+'t\x20sta'+_0x5d7d13(0xe2)+_0x5d7d13(0x14d),_0x2bd6b8['urgen'+'cy']='mediu'+'m',_0x2bd6b8;}return{'shouldPrompt':![],'reason':_0x5d7d13(0xd8)+'xt\x20no'+_0x5d7d13(0x125)+'ficie'+'nt\x20(c'+'ohere'+_0x5d7d13(0x16e)+_0x1ed9d4[_0x5d7d13(0x15c)+'ed'](0x2)+(_0x5d7d13(0xf3)+'teCha'+_0x5d7d13(0x11d))+_0x2b7221[_0x5d7d13(0x15c)+'ed'](0x2)+')','urgency':'low'};}['reset'](){const _0x1ade11=_0x15d7dc;this[_0x1ade11(0x127)+_0x1ade11(0x11a)]=0x0,this[_0x1ade11(0xc9)+_0x1ade11(0xe3)+_0x1ade11(0xd1)]=null;}[_0x15d7dc(0xe1)+'lateS'+_0x15d7dc(0xee)+'hange'](_0x4a6180,_0x3d2ee5){const _0x2ce1bd=_0x15d7dc;if(!_0x4a6180||typeof _0x4a6180!==_0x2ce1bd(0x10f)+'t')throw new TypeError('curre'+_0x2ce1bd(0x120)+_0x2ce1bd(0x158)+_0x2ce1bd(0x11c)+'\x20an\x20o'+_0x2ce1bd(0x12e));if(!_0x3d2ee5)return 0x1;let _0x302acb=0x0,_0x6314d6=0x0;if(_0x4a6180['score']!==undefined&&_0x3d2ee5['score']!==undefined){const _0x19addb=typeof _0x4a6180['score']===_0x2ce1bd(0xc4)+'r'?_0x4a6180[_0x2ce1bd(0x102)]:0x0,_0x20cefc=typeof _0x3d2ee5['score']===_0x2ce1bd(0xc4)+'r'?_0x3d2ee5[_0x2ce1bd(0x102)]:0x0,_0x5545bb=Math[_0x2ce1bd(0xfd)](_0x19addb-_0x20cefc)/0xa;isFinite(_0x5545bb)&&(_0x302acb+=_0x5545bb,_0x6314d6++);}if(_0x4a6180['issue'+'s']&&_0x3d2ee5[_0x2ce1bd(0x14e)+'s']){if(Array['isArr'+'ay'](_0x4a6180['issue'+'s'])&&Array['isArr'+'ay'](_0x3d2ee5['issue'+'s'])){const _0x2299f2=new Set(_0x4a6180['issue'+'s']['map'](_0x514b66=>String(_0x514b66)['toLow'+'erCas'+'e']()['trim']())),_0xbd13aa=new Set(_0x3d2ee5[_0x2ce1bd(0x14e)+'s'][_0x2ce1bd(0x169)](_0x1f20b1=>String(_0x1f20b1)[_0x2ce1bd(0x149)+_0x2ce1bd(0xf5)+'e']()[_0x2ce1bd(0x144)]())),_0x121fad=[..._0x2299f2]['filte'+'r'](_0x3ab702=>!_0xbd13aa['has'](_0x3ab702))['lengt'+'h'],_0x46eceb=[..._0xbd13aa][_0x2ce1bd(0x113)+'r'](_0x30a7f6=>!_0x2299f2[_0x2ce1bd(0x138)](_0x30a7f6))['lengt'+'h'],_0x4026bb=_0x2299f2[_0x2ce1bd(0x11e)]+_0xbd13aa[_0x2ce1bd(0x11e)],_0x323cdd=_0x4026bb>0x0?(_0x121fad+_0x46eceb)/_0x4026bb:0x0;isFinite(_0x323cdd)&&(_0x302acb+=_0x323cdd,_0x6314d6++);}}if(_0x4a6180['gameS'+_0x2ce1bd(0x15d)]&&_0x3d2ee5[_0x2ce1bd(0x137)+'tate']){const _0x523d63=this['calcu'+'lateG'+'ameSt'+'ateCh'+_0x2ce1bd(0x14d)](_0x4a6180['gameS'+'tate'],_0x3d2ee5[_0x2ce1bd(0x137)+'tate']);isFinite(_0x523d63)&&(_0x302acb+=_0x523d63,_0x6314d6++);}const _0x4940c5=_0x6314d6>0x0?_0x302acb/_0x6314d6:0x0;return Math['max'](0x0,Math['min'](0x1,_0x4940c5));}[_0x15d7dc(0xe1)+_0x15d7dc(0x13a)+'ameSt'+_0x15d7dc(0x15f)+'ange'](_0x48f388,_0x462da8){const _0x3628bc=_0x15d7dc,_0x3d9225=Object['keys'](_0x48f388||{}),_0x275731=Object['keys'](_0x462da8||{}),_0x33d62b=_0x3d9225['filte'+'r'](_0x1ffdf4=>!_0x275731[_0x3628bc(0x148)+'des'](_0x1ffdf4))['lengt'+'h'],_0x45b1a=_0x275731['filte'+'r'](_0x18ac3f=>!_0x3d9225[_0x3628bc(0x148)+'des'](_0x18ac3f))[_0x3628bc(0xd3)+'h'],_0x1c775f=_0x3d9225['filte'+'r'](_0x56e4cd=>_0x275731['inclu'+_0x3628bc(0xdc)](_0x56e4cd)&&JSON[_0x3628bc(0x16b)+'gify'](_0x48f388[_0x56e4cd])!==JSON[_0x3628bc(0x16b)+_0x3628bc(0x104)](_0x462da8[_0x56e4cd]))['lengt'+'h'],_0x3fec59=new Set([..._0x3d9225,..._0x275731])[_0x3628bc(0x11e)];return _0x3fec59>0x0?(_0x33d62b+_0x45b1a+_0x1c775f)/_0x3fec59:0x0;}['hasRe'+'centU'+_0x15d7dc(0x156)+_0x15d7dc(0x12d)](_0x314bab,_0x8cbde1){const _0x3972cf=_0x15d7dc;if(_0x8cbde1['recen'+_0x3972cf(0x15e)+'on'])return!![];const _0x137767=_0x314bab['slice'](-0x3);return _0x137767['some'](_0x556ca0=>{const _0x4973b4=_0x3972cf,_0x333939=String(_0x556ca0['step']||''),_0x13223c=String(_0x556ca0[_0x4973b4(0xd4)+'vatio'+'n']||'');return _0x333939[_0x4973b4(0x148)+_0x4973b4(0xdc)]('inter'+'actio'+'n')||_0x333939['inclu'+'des']('click')||_0x333939[_0x4973b4(0x148)+_0x4973b4(0xdc)](_0x4973b4(0xea)+'n')||_0x13223c['inclu'+'des']('user')||_0x13223c['inclu'+_0x4973b4(0xdc)](_0x4973b4(0xed)+'ed');});}[_0x15d7dc(0x100)+_0x15d7dc(0x14f)+_0x15d7dc(0xd9)](_0xeb4e6c,_0x21db99){const _0x205caf=_0x15d7dc;if(_0x21db99['stage']==='decis'+_0x205caf(0xf9)||_0x21db99['stage']==='evalu'+'ation')return!![];if(_0x21db99['testT'+_0x205caf(0x13b)]==='criti'+'cal'||_0x21db99['criti'+_0x205caf(0x12a)])return!![];if(_0x21db99[_0x205caf(0x121)]&&_0x21db99[_0x205caf(0x116)+'omple'+_0x205caf(0x14a)])return!![];return![];}async[_0x15d7dc(0x14c)+_0x15d7dc(0xf4)+'rence'+_0x15d7dc(0x101)](_0x12e968,_0x244b86){const _0x525de9=_0x15d7dc;if(_0x12e968['lengt'+'h']<0x4)return![];const _0x35cb07=_0x12e968['slice'](0x0,-0x1),_0x39ebda=await aggregateTemporalNotes(_0x35cb07),_0x1963a8=_0x39ebda['coher'+_0x525de9(0x117)]||0x1,_0x391c65=_0x244b86['coher'+_0x525de9(0x117)]||0x1,_0x2fbe53=_0x1963a8-_0x391c65;return _0x2fbe53>this[_0x525de9(0xe4)+_0x525de9(0x167)+_0x525de9(0x103)+'d'];}['calcu'+'lateP'+_0x15d7dc(0xe3)+'Urgen'+'cy'](_0x2675cc,_0x58f265){const _0x2d8919=_0x15d7dc;if(_0x58f265[_0x2d8919(0xe4)+'cy']==='high')return 0x1;if(_0x58f265[_0x2d8919(0xe4)+'cy']===_0x2d8919(0x128)+'m')return 0.6;const _0x328760=_0x2675cc[_0x2d8919(0x107)+'ence']||0x0,_0xf24c86=_0x2675cc['timeS'+'inceL'+_0x2d8919(0xc5)+_0x2d8919(0x10b)]||0x0;if(_0x328760>0.7&&_0xf24c86>0x1388)return 0.4;return 0.2;}async['selec'+'tOpti'+'malTi'+'ming'](_0x58f790,_0x8ee1c6){const _0x330af9=_0x15d7dc,_0x45b783=await Promise['all'](_0x58f790[_0x330af9(0x169)](async _0x235959=>({'request':_0x235959,'decision':await this['shoul'+'dProm'+'pt'](_0x235959['curre'+_0x330af9(0x120)+'te'],_0x235959[_0x330af9(0x136)+'ousSt'+'ate'],_0x235959[_0x330af9(0x10a)+_0x330af9(0x13c)+'tes']||[],_0x235959['conte'+'xt']||{})}))),_0x1a026a=_0x45b783[_0x330af9(0x113)+'r'](_0xb6d7fa=>_0xb6d7fa[_0x330af9(0x123)+_0x330af9(0xf9)]['urgen'+'cy']==='high'),_0x2f4dee=_0x45b783['filte'+'r'](_0x41fd01=>_0x41fd01[_0x330af9(0x123)+'ion'][_0x330af9(0xe4)+'cy']==='mediu'+'m'),_0x5b3e50=_0x45b783[_0x330af9(0x113)+'r'](_0x1ad085=>_0x1ad085[_0x330af9(0x123)+_0x330af9(0xf9)][_0x330af9(0xe4)+'cy']==='low'),_0x15d80b=_0x8ee1c6[_0x330af9(0x107)+_0x330af9(0x117)]>0.7,_0xf4d08=_0x15d80b&&_0x2f4dee['lengt'+'h']+_0x5b3e50['lengt'+'h']>0x1;return{'promptNow':_0x1a026a[_0x330af9(0x169)](_0x281730=>_0x281730[_0x330af9(0x130)+'st']),'batch':_0xf4d08?[..._0x2f4dee,..._0x5b3e50][_0x330af9(0x169)](_0x3f2463=>_0x3f2463['reque'+'st']):_0x2f4dee[_0x330af9(0x169)](_0x272458=>_0x272458[_0x330af9(0x130)+'st']),'wait':_0xf4d08?[]:_0x5b3e50[_0x330af9(0x169)](_0x383578=>_0x383578[_0x330af9(0x130)+'st']),'decisions':_0x45b783};}}function _0x1330(){const _0x426d8a=['BNqGBM8','mZe5ntaZmLHeA2Tyza','lcbZDge','DenVAgu','zxjdyxm','AxruAw0','zsbPBNq','BwLU','Aw9U','mtiZDgXsswPn','q2HHBMC','y2HHBMC','ywjZ','ihjLCxu','AgfZvxm','Axnezwm','rhjVCa','C2nVCMu','zxnOB2W','z2LMEq','DgvZicG','zvrOCMu','y29Ozxi','mtK0ntK0nvnYBfvrAW','CMzVCM0','DgvTCg8','B21WDa','D2L0Aca','B2XK','ksSPkYK','B2jQzwm','C2LNBMK','C2HVDwW','zsbTDxm','zMLSDgu','x1rftva','DgvZrM8','z29HBem','zw5Jzq','xsWGz28','BwvZC2e','B3vUDa','DguGBNu','C3qGyMu','BMDLoIa','C2L6zq','Aw9Uiha','BNrtDge','z29HBa','BIb3Axq','zgvJAxm','BM93','DcbZDwy','BwLUtM8','C3rLCem','BwvKAxu','u3rHyMW','y2fS','lI9SB2C','DgHLBG','DgLVBG','yMPLy3q','zxHW','CMvXDwu','zw52','idWG','Aw4GwZa','CMvHy2G','zwnPC2K','ChjLDMK','z2fTzvm','AgfZ','v2fYBs0','Bgf0zuC','ExbL','CMfStM8','igDVDdO','BwfUy2u','B2XKig0','Bg9Nz2u','B2nLC3m','Dgv4Dca','B3jHBeq','DhjPBq','BxbSAw4','ywjSztO','C2HVBgq','Aw5JBhu','Dg9mB3C','DgvK','CMvHC28','zgv0zwm','yw5Nzq','AxnZDwu','AxnPB24','AgfUz2u','igzPBMK','ovHgBvHbqq','D2fYBvm','z2vYlM0','revcvuC','C2vYqwm','zfbYB20','DguGBxu','BMLMAwm','C3rHDgu','BhmVCgu','Dg9gAxG','Dgf0zq','DefJDgK','yxrLq2G','w1rLBxa','BwjLCIW','nJuXnJbTAerOsva','nJq0nJuYz21Irff5','q29Ozxi','t1jbta','lI91DgK','y3LuAhi','CLbYB20','BwfW','Dgf0zsa','C3rYAw4','B25Difa','DfbYB2i','BMnLoIa','zxiGDw4','AhjLC2G','BNvTyMu','yxn0uhi','yxzHAwW','zxjMB3i','mtqZmKX0te5hqW','BgfZDfa','Bgf0zvm','CxvHBgK','Bwf4','rgvJAxm','Bwf4v2e','Dg9tDhi','mJG3nZe0EurZEu1y','vgLTzq','DcbIzsa','BgvUz3q','B2jZzxi','DgvZig0','ywrHChq','y2f0y2G','q29UDgu','ug9PBNq','C3vLkq','ig11C3q','zgvZ','DgfYDfm','y29UC3q','zw5Jzvq','mtqYmtG3mMzdwLPKDq','y2fSy3u','DguGy2G','CM9TChq','DxjNzw4','yxjYyxK','DdOG','DgvWCW','Aw5N','AxzLu2e','ywn0Aw8','D2fYBG','AgfZuMu','y2XPy2S','Dgf0zum','igXVz2C','vxnLCIa'];_0x1330=function(){return _0x426d8a;};return _0x1330();}export function createTemporalDecisionManager(_0x37d8df={}){return new TemporalDecisionManager(_0x37d8df);}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal Decision Logic
|
|
3
|
+
*
|
|
4
|
+
* Extracted from VLLM Judge to improve testability and reduce complexity.
|
|
5
|
+
* Handles the decision of whether to prompt the LLM based on temporal notes and state.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { log } from './logger.mjs';
|
|
9
|
+
import { safeLogTemporalDecision } from './safe-logger.mjs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Evaluate temporal decision and handle logging/metrics
|
|
13
|
+
*
|
|
14
|
+
* @param {Object} context - Validation context
|
|
15
|
+
* @param {Object} config - Judge configuration
|
|
16
|
+
* @returns {Promise<Object|null>} Result if decision is to skip, null if we should proceed
|
|
17
|
+
*/
|
|
18
|
+
export async function evaluateTemporalDecision(context, config) {
|
|
19
|
+
// Only prompt when decision is needed, not on every state change
|
|
20
|
+
if (!context.useTemporalDecision || !context.temporalNotes || context.temporalNotes.length === 0) {
|
|
21
|
+
return null; // Proceed with validation
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Dynamic import to avoid circular dependencies if any
|
|
26
|
+
const { TemporalDecisionManager } = await import('./temporal-decision-manager.mjs');
|
|
27
|
+
const { aggregateTemporalNotes } = await import('./temporal.mjs');
|
|
28
|
+
|
|
29
|
+
const decisionManager = new TemporalDecisionManager(context.temporalDecisionOptions || {});
|
|
30
|
+
const currentState = { score: null, issues: [], ...context.currentState };
|
|
31
|
+
const previousState = context.previousState || null;
|
|
32
|
+
|
|
33
|
+
// Make decision
|
|
34
|
+
const decision = await decisionManager.shouldPrompt(
|
|
35
|
+
currentState,
|
|
36
|
+
previousState,
|
|
37
|
+
context.temporalNotes,
|
|
38
|
+
context
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Log decision reasoning
|
|
42
|
+
try {
|
|
43
|
+
const aggregated = await aggregateTemporalNotes(context.temporalNotes).catch(() => ({ coherence: null }));
|
|
44
|
+
safeLogTemporalDecision({
|
|
45
|
+
shouldPrompt: decision.shouldPrompt,
|
|
46
|
+
reason: decision.reason,
|
|
47
|
+
urgency: decision.urgency,
|
|
48
|
+
coherence: aggregated.coherence,
|
|
49
|
+
stateChange: decisionManager.calculateStateChange(currentState, previousState),
|
|
50
|
+
noteCount: context.temporalNotes.length,
|
|
51
|
+
isDecisionPoint: decisionManager.isDecisionPoint(currentState, context),
|
|
52
|
+
hasUserAction: decisionManager.hasRecentUserAction(context.temporalNotes, context)
|
|
53
|
+
});
|
|
54
|
+
} catch {
|
|
55
|
+
// Ignore logging errors
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Handle decision
|
|
59
|
+
if (!decision.shouldPrompt && decision.urgency !== 'high') {
|
|
60
|
+
// Don't prompt yet - return cached or previous result
|
|
61
|
+
if (context.previousResult) {
|
|
62
|
+
trackMetrics(false);
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...context.previousResult,
|
|
66
|
+
skipped: true,
|
|
67
|
+
skipReason: decision.reason,
|
|
68
|
+
urgency: decision.urgency
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// If no previous result, we proceed but marked as low urgency
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Proceeding with validation
|
|
75
|
+
trackMetrics(true);
|
|
76
|
+
return null; // Null means "proceed with validation"
|
|
77
|
+
|
|
78
|
+
} catch (error) {
|
|
79
|
+
// If TemporalDecisionManager fails, proceed with validation (graceful degradation)
|
|
80
|
+
if (config.debug?.verbose) {
|
|
81
|
+
log(`[VLLM] TemporalDecisionManager error: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Track metrics for temporal decisions
|
|
89
|
+
*/
|
|
90
|
+
async function trackMetrics(prompted) {
|
|
91
|
+
try {
|
|
92
|
+
const { researchMetrics } = await import('../evaluation/metrics/research-metrics-collector.mjs');
|
|
93
|
+
researchMetrics.recordTemporalDecision('with', {
|
|
94
|
+
llmCalls: prompted ? 1 : 0,
|
|
95
|
+
skipped: !prompted,
|
|
96
|
+
accuracy: null,
|
|
97
|
+
latency: prompted ? null : 0,
|
|
98
|
+
cost: prompted ? null : 0
|
|
99
|
+
});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// Silently fail metrics tracking
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|