@webpresso/agent-kit 0.21.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/_run.js +2 -1
- package/catalog/agent/rules/changeset-release.md +5 -3
- package/dist/esm/audit/repo-guardrails.js +2 -1
- package/dist/esm/blueprint/core/schema.d.ts +1 -1
- package/dist/esm/blueprint/db/enums.d.ts +1 -1
- package/dist/esm/blueprint/execution/progress-bridge.js +2 -2
- package/dist/esm/blueprint/graph/schema.d.ts +3 -3
- package/dist/esm/build/package-manifest.d.ts +13 -0
- package/dist/esm/build/package-manifest.js +165 -0
- package/dist/esm/cli/commands/bench/session-memory.js +1 -1
- package/dist/esm/config/docs-lint/schemas/agents.d.ts +2 -2
- package/dist/esm/config/docs-lint/schemas/audit.d.ts +3 -3
- package/dist/esm/config/docs-lint/schemas/common.d.ts +1 -1
- package/dist/esm/config/docs-lint/schemas/cookbook.d.ts +1 -1
- package/dist/esm/config/docs-lint/schemas/core.d.ts +7 -7
- package/dist/esm/config/docs-lint/schemas/draft.d.ts +2 -2
- package/dist/esm/config/docs-lint/schemas/evaluation.d.ts +1 -1
- package/dist/esm/config/docs-lint/schemas/ongoing-initiative.d.ts +2 -2
- package/dist/esm/config/docs-lint/schemas/rule.d.ts +1 -1
- package/dist/esm/mcp/blueprint-server.js +1 -1
- package/dist/esm/mcp/runners/test.js +1 -1
- package/package.json +1 -1
- package/dist/esm/ai-prompts/business-canvas.d.ts +0 -52
- package/dist/esm/ai-prompts/business-canvas.js +0 -292
- package/dist/esm/ai-prompts/circuit-breaker.d.ts +0 -35
- package/dist/esm/ai-prompts/circuit-breaker.js +0 -171
- package/dist/esm/ai-prompts/experiment-draft.d.ts +0 -86
- package/dist/esm/ai-prompts/experiment-draft.js +0 -188
- package/dist/esm/ai-prompts/index.d.ts +0 -12
- package/dist/esm/ai-prompts/index.js +0 -11
- package/dist/esm/ai-prompts/persona-context.d.ts +0 -70
- package/dist/esm/ai-prompts/persona-context.js +0 -158
- package/dist/esm/ai-prompts/persona-debate.d.ts +0 -67
- package/dist/esm/ai-prompts/persona-debate.js +0 -172
- package/dist/esm/ai-prompts/persona-tools.d.ts +0 -26
- package/dist/esm/ai-prompts/persona-tools.js +0 -172
- package/dist/esm/ai-prompts/personas.d.ts +0 -16
- package/dist/esm/ai-prompts/personas.js +0 -492
- package/dist/esm/ai-prompts/rachel-planning.d.ts +0 -28
- package/dist/esm/ai-prompts/rachel-planning.js +0 -217
- package/dist/esm/ai-prompts/task-analysis.d.ts +0 -49
- package/dist/esm/ai-prompts/task-analysis.js +0 -434
- package/dist/esm/ai-prompts/types.d.ts +0 -3
- package/dist/esm/ai-prompts/types.js +0 -2
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
export const BUSINESS_CANVAS_SYSTEM_PROMPT = `You are conducting a business viability analysis conversation.
|
|
2
|
-
|
|
3
|
-
## Conversation Flow
|
|
4
|
-
|
|
5
|
-
Guide the user through these phases naturally (don't announce phases):
|
|
6
|
-
|
|
7
|
-
1. **Problem Discovery** (2-3 questions)
|
|
8
|
-
- What problem are you solving?
|
|
9
|
-
- Who experiences this problem most acutely?
|
|
10
|
-
- How do they currently solve it?
|
|
11
|
-
|
|
12
|
-
2. **Target Audience Deep Dive** (1-2 questions)
|
|
13
|
-
- Who is the ideal customer persona?
|
|
14
|
-
- What are their specific pain points and demographics?
|
|
15
|
-
|
|
16
|
-
3. **Market Validation** (2-3 questions)
|
|
17
|
-
- Who are your competitors?
|
|
18
|
-
- What's your target price point?
|
|
19
|
-
- How big is your addressable market?
|
|
20
|
-
|
|
21
|
-
4. **Differentiation & Success Criteria** (1-2 questions)
|
|
22
|
-
- What makes your solution unique?
|
|
23
|
-
- What metrics will define success for MVP?
|
|
24
|
-
|
|
25
|
-
5. **Canvas Generation**
|
|
26
|
-
When you have enough information (typically 5-8 exchanges), generate the canvas.
|
|
27
|
-
|
|
28
|
-
## Output Format
|
|
29
|
-
|
|
30
|
-
When ready to generate the canvas, include these XML tags in your response:
|
|
31
|
-
|
|
32
|
-
<business_canvas>
|
|
33
|
-
{
|
|
34
|
-
"problem": "Clear problem statement describing the pain point",
|
|
35
|
-
"solution": "Your proposed solution summary",
|
|
36
|
-
"targetAudience": [
|
|
37
|
-
{
|
|
38
|
-
"persona": "Primary user type (e.g., 'Freelance designers')",
|
|
39
|
-
"painPoints": ["Specific pain point 1", "Specific pain point 2"],
|
|
40
|
-
"demographics": "Age, role, industry, etc.",
|
|
41
|
-
"marketSize": "Estimated TAM for this segment"
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
"successMetrics": [
|
|
45
|
-
{
|
|
46
|
-
"name": "MRR",
|
|
47
|
-
"target": "$10K",
|
|
48
|
-
"timeframe": "6 months post-launch"
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"name": "Active Users",
|
|
52
|
-
"target": "500",
|
|
53
|
-
"timeframe": "3 months post-launch"
|
|
54
|
-
}
|
|
55
|
-
],
|
|
56
|
-
"keyMetrics": ["MRR", "Churn Rate", "DAU"],
|
|
57
|
-
"uniqueValue": "What makes this unique/differentiated",
|
|
58
|
-
"channels": ["ProductHunt", "Twitter", "Content Marketing"],
|
|
59
|
-
"revenueModel": "How you'll make money (e.g., $15/mo subscription)",
|
|
60
|
-
"costStructure": "Estimated monthly costs breakdown",
|
|
61
|
-
"features": [
|
|
62
|
-
{
|
|
63
|
-
"name": "Feature Name",
|
|
64
|
-
"description": "What it does and why it matters",
|
|
65
|
-
"priority": "must-have",
|
|
66
|
-
"complexity": "medium"
|
|
67
|
-
}
|
|
68
|
-
],
|
|
69
|
-
"marketResearch": {
|
|
70
|
-
"competitors": [
|
|
71
|
-
{
|
|
72
|
-
"name": "Competitor Name",
|
|
73
|
-
"pricing": "$X/mo",
|
|
74
|
-
"strengths": ["Strength 1"],
|
|
75
|
-
"weaknesses": ["Weakness 1"]
|
|
76
|
-
}
|
|
77
|
-
],
|
|
78
|
-
"trends": ["Market trend 1", "Market trend 2"],
|
|
79
|
-
"gaps": ["Gap in market 1", "Gap in market 2"]
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
</business_canvas>
|
|
83
|
-
|
|
84
|
-
<viability_decision>GO|NO_GO|NEEDS_MORE_INFO</viability_decision>
|
|
85
|
-
<viability_rationale>Why this decision...</viability_rationale>
|
|
86
|
-
|
|
87
|
-
## Feature Prioritization Rules
|
|
88
|
-
|
|
89
|
-
When generating features, follow strict MVP prioritization:
|
|
90
|
-
|
|
91
|
-
- **must-have** (Week 1-2): Core features that validate the hypothesis. Max 3-4 features.
|
|
92
|
-
- **should-have** (Week 2-4): Important but not blocking validation. Max 2-3 features.
|
|
93
|
-
- **nice-to-have** (Post-MVP): Polish and expansion features.
|
|
94
|
-
|
|
95
|
-
Complexity estimates:
|
|
96
|
-
- **low**: Can be built in < 1 day
|
|
97
|
-
- **medium**: 1-3 days of development
|
|
98
|
-
- **high**: 3+ days or requires external integrations
|
|
99
|
-
|
|
100
|
-
## Viability Criteria
|
|
101
|
-
|
|
102
|
-
- **GO**: Clear problem, addressable market (>$1B TAM), differentiated solution, viable unit economics (LTV:CAC > 3:1)
|
|
103
|
-
- **NO_GO**: No clear problem, saturated market with dominant players, no differentiation, unsustainable costs
|
|
104
|
-
- **NEEDS_MORE_INFO**: Missing critical information to make a decision (e.g., unknown pricing, unclear target audience)
|
|
105
|
-
|
|
106
|
-
## Guidelines
|
|
107
|
-
|
|
108
|
-
- Ask one question at a time (occasionally two if related)
|
|
109
|
-
- Challenge assumptions politely but directly
|
|
110
|
-
- Use investor terminology naturally (CAC, LTV, Churn, ROI, TAM, SAM)
|
|
111
|
-
- Provide insights from market patterns you've seen
|
|
112
|
-
- When generating canvas, prioritize features ruthlessly for MVP
|
|
113
|
-
- Always include your conversational response before the canvas tags
|
|
114
|
-
- Include at least 2 success metrics with realistic targets
|
|
115
|
-
- Identify at least 2 competitors in market research
|
|
116
|
-
`;
|
|
117
|
-
export const BUSINESS_CANVAS_USER_PROMPT = `Continue the conversation to understand this business idea.
|
|
118
|
-
If you have enough information (5-8 exchanges), generate the Business Canvas.
|
|
119
|
-
|
|
120
|
-
Previous conversation:
|
|
121
|
-
{conversation_history}
|
|
122
|
-
|
|
123
|
-
User's latest message:
|
|
124
|
-
{user_message}
|
|
125
|
-
`;
|
|
126
|
-
export function parseBusinessCanvas(response) {
|
|
127
|
-
const canvasMatch = response.match(/<business_canvas>([\s\S]*?)<\/business_canvas>/);
|
|
128
|
-
const viabilityMatch = response.match(/<viability_decision>(\w+)<\/viability_decision>/);
|
|
129
|
-
const rationaleMatch = response.match(/<viability_rationale>([\s\S]*?)<\/viability_rationale>/);
|
|
130
|
-
const message = response
|
|
131
|
-
.replace(/<business_canvas>[\s\S]*?<\/business_canvas>/g, '')
|
|
132
|
-
.replace(/<viability_decision>[\s\S]*?<\/viability_decision>/g, '')
|
|
133
|
-
.replace(/<viability_rationale>[\s\S]*?<\/viability_rationale>/g, '')
|
|
134
|
-
.trim();
|
|
135
|
-
let canvas;
|
|
136
|
-
if (canvasMatch?.[1]) {
|
|
137
|
-
try {
|
|
138
|
-
canvas = JSON.parse(canvasMatch[1].trim());
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
console.warn('Failed to parse business canvas JSON');
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
let viability;
|
|
145
|
-
if (viabilityMatch?.[1]) {
|
|
146
|
-
const decision = viabilityMatch[1].toUpperCase();
|
|
147
|
-
if (decision === 'GO' || decision === 'NO_GO' || decision === 'NEEDS_MORE_INFO') {
|
|
148
|
-
viability = decision;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
const rationale = rationaleMatch?.[1]?.trim();
|
|
152
|
-
return {
|
|
153
|
-
message,
|
|
154
|
-
canvas,
|
|
155
|
-
viability,
|
|
156
|
-
rationale,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function isValidTargetAudience(audience) {
|
|
160
|
-
if (!audience || typeof audience !== 'object') {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
const a = audience;
|
|
164
|
-
if (typeof a.persona !== 'string' || !a.persona) {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
if (!Array.isArray(a.painPoints) || !a.painPoints.length) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
function isValidSuccessMetric(metric) {
|
|
173
|
-
if (!metric || typeof metric !== 'object') {
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
const m = metric;
|
|
177
|
-
if (typeof m.name !== 'string' || !m.name) {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
if (typeof m.target !== 'string' || !m.target) {
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
if (typeof m.timeframe !== 'string' || !m.timeframe) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
function hasValidCanvasStrings(c) {
|
|
189
|
-
const requiredStrings = [
|
|
190
|
-
'problem',
|
|
191
|
-
'solution',
|
|
192
|
-
'uniqueValue',
|
|
193
|
-
'revenueModel',
|
|
194
|
-
'costStructure',
|
|
195
|
-
];
|
|
196
|
-
for (const field of requiredStrings) {
|
|
197
|
-
if (typeof c[field] !== 'string' || !c[field]) {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return true;
|
|
202
|
-
}
|
|
203
|
-
function hasValidCanvasArrays(c) {
|
|
204
|
-
const requiredArrays = [
|
|
205
|
-
'keyMetrics',
|
|
206
|
-
'channels',
|
|
207
|
-
'features',
|
|
208
|
-
'targetAudience',
|
|
209
|
-
'successMetrics',
|
|
210
|
-
];
|
|
211
|
-
for (const field of requiredArrays) {
|
|
212
|
-
if (!Array.isArray(c[field])) {
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
function hasValidCanvasAudience(c) {
|
|
219
|
-
const targetAudience = c.targetAudience;
|
|
220
|
-
if (!targetAudience.length) {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
for (const audience of targetAudience) {
|
|
224
|
-
if (!isValidTargetAudience(audience)) {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
function hasValidCanvasMetrics(c) {
|
|
231
|
-
const successMetrics = c.successMetrics;
|
|
232
|
-
if (!successMetrics.length) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
for (const metric of successMetrics) {
|
|
236
|
-
if (!isValidSuccessMetric(metric)) {
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
function hasValidCanvasFeatures(c) {
|
|
243
|
-
const features = c.features;
|
|
244
|
-
for (const feature of features) {
|
|
245
|
-
if (!isValidFeatureProposal(feature)) {
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return true;
|
|
250
|
-
}
|
|
251
|
-
export function isValidBusinessCanvas(canvas) {
|
|
252
|
-
if (!canvas || typeof canvas !== 'object') {
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
const c = canvas;
|
|
256
|
-
if (!hasValidCanvasStrings(c)) {
|
|
257
|
-
return false;
|
|
258
|
-
}
|
|
259
|
-
if (!hasValidCanvasArrays(c)) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
if (!hasValidCanvasAudience(c)) {
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
if (!hasValidCanvasMetrics(c)) {
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
if (!hasValidCanvasFeatures(c)) {
|
|
269
|
-
return false;
|
|
270
|
-
}
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
function isValidFeatureProposal(feature) {
|
|
274
|
-
if (!feature || typeof feature !== 'object') {
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
const f = feature;
|
|
278
|
-
if (typeof f.name !== 'string' || !f.name) {
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
if (typeof f.description !== 'string' || !f.description) {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
if (!['must-have', 'should-have', 'nice-to-have'].includes(f.priority)) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
if (!['low', 'medium', 'high'].includes(f.complexity)) {
|
|
288
|
-
return false;
|
|
289
|
-
}
|
|
290
|
-
return true;
|
|
291
|
-
}
|
|
292
|
-
//# sourceMappingURL=business-canvas.js.map
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { DebateOutcome, DebateState } from './persona-debate.js';
|
|
2
|
-
export interface CircuitBreakerConfig {
|
|
3
|
-
maxTokensPerDebate: number;
|
|
4
|
-
requireHumanReviewFor: Array<DebateOutcome['decision']>;
|
|
5
|
-
similarityThreshold: number;
|
|
6
|
-
minRoundsForSimilarityCheck: number;
|
|
7
|
-
}
|
|
8
|
-
export declare const DEFAULT_CIRCUIT_BREAKER_CONFIG: CircuitBreakerConfig;
|
|
9
|
-
export interface CircuitBreakerState {
|
|
10
|
-
totalTokensUsed: number;
|
|
11
|
-
roundSimilarities: number[];
|
|
12
|
-
humanReviewRequired: boolean;
|
|
13
|
-
breakerTripped: boolean;
|
|
14
|
-
tripReason?: CircuitBreakerTripReason;
|
|
15
|
-
trippedAt?: Date;
|
|
16
|
-
}
|
|
17
|
-
export type CircuitBreakerTripReason = 'max_tokens_exceeded' | 'hallucination_loop_detected' | 'human_review_required';
|
|
18
|
-
export declare function createCircuitBreakerState(): CircuitBreakerState;
|
|
19
|
-
export declare function updateTokens(state: CircuitBreakerState, inputTokens: number, outputTokens: number, config?: CircuitBreakerConfig): CircuitBreakerState;
|
|
20
|
-
export declare function calculateSimilarity(text1: string, text2: string): number;
|
|
21
|
-
export declare function checkForHallucinationLoop(state: DebateState, config?: CircuitBreakerConfig): {
|
|
22
|
-
detected: boolean;
|
|
23
|
-
similarity: number;
|
|
24
|
-
};
|
|
25
|
-
export declare function updateSimilarity(state: CircuitBreakerState, similarity: number, isLoop: boolean): CircuitBreakerState;
|
|
26
|
-
export declare function requiresHumanReview(outcome: DebateOutcome, config?: CircuitBreakerConfig): boolean;
|
|
27
|
-
export declare function flagForHumanReview(state: CircuitBreakerState): CircuitBreakerState;
|
|
28
|
-
export interface CircuitBreakerCheckResult {
|
|
29
|
-
shouldContinue: boolean;
|
|
30
|
-
state: CircuitBreakerState;
|
|
31
|
-
message?: string;
|
|
32
|
-
}
|
|
33
|
-
export declare function checkCircuitBreaker(debateState: DebateState, breakerState: CircuitBreakerState, config?: CircuitBreakerConfig): CircuitBreakerCheckResult;
|
|
34
|
-
export declare function createCircuitBreakerLog(debateId: string, state: CircuitBreakerState, event: 'check' | 'trip' | 'human_review_flagged'): Record<string, unknown>;
|
|
35
|
-
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
2
|
-
maxTokensPerDebate: 50000,
|
|
3
|
-
requireHumanReviewFor: ['approved', 'rejected'],
|
|
4
|
-
similarityThreshold: 0.85,
|
|
5
|
-
minRoundsForSimilarityCheck: 2,
|
|
6
|
-
};
|
|
7
|
-
export function createCircuitBreakerState() {
|
|
8
|
-
return {
|
|
9
|
-
totalTokensUsed: 0,
|
|
10
|
-
roundSimilarities: [],
|
|
11
|
-
humanReviewRequired: false,
|
|
12
|
-
breakerTripped: false,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
export function updateTokens(state, inputTokens, outputTokens, config = DEFAULT_CIRCUIT_BREAKER_CONFIG) {
|
|
16
|
-
const newTotal = state.totalTokensUsed + inputTokens + outputTokens;
|
|
17
|
-
if (newTotal >= config.maxTokensPerDebate && !state.breakerTripped) {
|
|
18
|
-
return {
|
|
19
|
-
...state,
|
|
20
|
-
totalTokensUsed: newTotal,
|
|
21
|
-
breakerTripped: true,
|
|
22
|
-
tripReason: 'max_tokens_exceeded',
|
|
23
|
-
trippedAt: new Date(),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
return {
|
|
27
|
-
...state,
|
|
28
|
-
totalTokensUsed: newTotal,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
function extractWords(text) {
|
|
32
|
-
return new Set(text
|
|
33
|
-
.toLowerCase()
|
|
34
|
-
.split(/\s+/)
|
|
35
|
-
.filter((w) => w.length >= 4)
|
|
36
|
-
.map((w) => w.replace(/[^a-z0-9]/g, ''))
|
|
37
|
-
.filter((w) => w.length >= 4));
|
|
38
|
-
}
|
|
39
|
-
export function calculateSimilarity(text1, text2) {
|
|
40
|
-
const words1 = extractWords(text1);
|
|
41
|
-
const words2 = extractWords(text2);
|
|
42
|
-
if (words1.size === 0 && words2.size === 0)
|
|
43
|
-
return 1;
|
|
44
|
-
if (words1.size === 0 || words2.size === 0)
|
|
45
|
-
return 0;
|
|
46
|
-
const intersection = new Set([...words1].filter((x) => words2.has(x)));
|
|
47
|
-
const union = new Set([...words1, ...words2]);
|
|
48
|
-
return intersection.size / union.size;
|
|
49
|
-
}
|
|
50
|
-
function getRoundText(contributions) {
|
|
51
|
-
return contributions.map((c) => c.content).join('\n');
|
|
52
|
-
}
|
|
53
|
-
export function checkForHallucinationLoop(state, config = DEFAULT_CIRCUIT_BREAKER_CONFIG) {
|
|
54
|
-
const { rounds } = state;
|
|
55
|
-
if (rounds.length < config.minRoundsForSimilarityCheck) {
|
|
56
|
-
return { detected: false, similarity: 0 };
|
|
57
|
-
}
|
|
58
|
-
const currentRound = rounds[rounds.length - 1];
|
|
59
|
-
const previousRound = rounds[rounds.length - 2];
|
|
60
|
-
if (!currentRound || !previousRound) {
|
|
61
|
-
return { detected: false, similarity: 0 };
|
|
62
|
-
}
|
|
63
|
-
const currentText = getRoundText(currentRound.contributions);
|
|
64
|
-
const previousText = getRoundText(previousRound.contributions);
|
|
65
|
-
const similarity = calculateSimilarity(currentText, previousText);
|
|
66
|
-
return {
|
|
67
|
-
detected: similarity >= config.similarityThreshold,
|
|
68
|
-
similarity,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
export function updateSimilarity(state, similarity, isLoop) {
|
|
72
|
-
const newSimilarities = [...state.roundSimilarities, similarity];
|
|
73
|
-
if (isLoop && !state.breakerTripped) {
|
|
74
|
-
return {
|
|
75
|
-
...state,
|
|
76
|
-
roundSimilarities: newSimilarities,
|
|
77
|
-
breakerTripped: true,
|
|
78
|
-
tripReason: 'hallucination_loop_detected',
|
|
79
|
-
trippedAt: new Date(),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
...state,
|
|
84
|
-
roundSimilarities: newSimilarities,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
export function requiresHumanReview(outcome, config = DEFAULT_CIRCUIT_BREAKER_CONFIG) {
|
|
88
|
-
return config.requireHumanReviewFor.includes(outcome.decision);
|
|
89
|
-
}
|
|
90
|
-
export function flagForHumanReview(state) {
|
|
91
|
-
return {
|
|
92
|
-
...state,
|
|
93
|
-
humanReviewRequired: true,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
function checkAlreadyTripped(breakerState) {
|
|
97
|
-
if (breakerState.breakerTripped) {
|
|
98
|
-
return {
|
|
99
|
-
shouldContinue: false,
|
|
100
|
-
state: breakerState,
|
|
101
|
-
message: `Circuit breaker tripped: ${breakerState.tripReason}`,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
function checkTokenLimit(breakerState, config) {
|
|
107
|
-
if (breakerState.totalTokensUsed >= config.maxTokensPerDebate) {
|
|
108
|
-
const newState = {
|
|
109
|
-
...breakerState,
|
|
110
|
-
breakerTripped: true,
|
|
111
|
-
tripReason: 'max_tokens_exceeded',
|
|
112
|
-
trippedAt: new Date(),
|
|
113
|
-
};
|
|
114
|
-
return {
|
|
115
|
-
shouldContinue: false,
|
|
116
|
-
state: newState,
|
|
117
|
-
message: `Token limit exceeded: ${breakerState.totalTokensUsed}/${config.maxTokensPerDebate}`,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
function checkHallucinationLoopDetection(debateState, breakerState, config) {
|
|
123
|
-
const loopCheck = checkForHallucinationLoop(debateState, config);
|
|
124
|
-
if (loopCheck.detected) {
|
|
125
|
-
const newState = {
|
|
126
|
-
...breakerState,
|
|
127
|
-
roundSimilarities: [...breakerState.roundSimilarities, loopCheck.similarity],
|
|
128
|
-
breakerTripped: true,
|
|
129
|
-
tripReason: 'hallucination_loop_detected',
|
|
130
|
-
trippedAt: new Date(),
|
|
131
|
-
};
|
|
132
|
-
return {
|
|
133
|
-
shouldContinue: false,
|
|
134
|
-
state: newState,
|
|
135
|
-
message: `Potential hallucination loop detected: ${Math.round(loopCheck.similarity * 100)}% similarity between rounds`,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
return {
|
|
139
|
-
shouldContinue: true,
|
|
140
|
-
state: {
|
|
141
|
-
...breakerState,
|
|
142
|
-
roundSimilarities: [...breakerState.roundSimilarities, loopCheck.similarity],
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
export function checkCircuitBreaker(debateState, breakerState, config = DEFAULT_CIRCUIT_BREAKER_CONFIG) {
|
|
147
|
-
const trippedCheck = checkAlreadyTripped(breakerState);
|
|
148
|
-
if (trippedCheck) {
|
|
149
|
-
return trippedCheck;
|
|
150
|
-
}
|
|
151
|
-
const tokenCheck = checkTokenLimit(breakerState, config);
|
|
152
|
-
if (tokenCheck) {
|
|
153
|
-
return tokenCheck;
|
|
154
|
-
}
|
|
155
|
-
return checkHallucinationLoopDetection(debateState, breakerState, config);
|
|
156
|
-
}
|
|
157
|
-
export function createCircuitBreakerLog(debateId, state, event) {
|
|
158
|
-
return {
|
|
159
|
-
timestamp: new Date().toISOString(),
|
|
160
|
-
level: event === 'trip' ? 'warn' : 'info',
|
|
161
|
-
component: 'circuit-breaker',
|
|
162
|
-
debateId,
|
|
163
|
-
event,
|
|
164
|
-
totalTokensUsed: state.totalTokensUsed,
|
|
165
|
-
roundSimilarities: state.roundSimilarities,
|
|
166
|
-
breakerTripped: state.breakerTripped,
|
|
167
|
-
tripReason: state.tripReason,
|
|
168
|
-
humanReviewRequired: state.humanReviewRequired,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Experiment draft generation from analytics signals
|
|
3
|
-
*
|
|
4
|
-
* Converts analytics data into structured experiment drafts with
|
|
5
|
-
* hypothesis, primary metric, guardrails, and rollout plan.
|
|
6
|
-
*/
|
|
7
|
-
export interface AnalyticsSignal {
|
|
8
|
-
metricName: string;
|
|
9
|
-
currentValue: number;
|
|
10
|
-
previousValue: number;
|
|
11
|
-
trend: 'improving' | 'declining' | 'stable';
|
|
12
|
-
sampleSize: number;
|
|
13
|
-
periodDays: number;
|
|
14
|
-
metadata?: Record<string, unknown>;
|
|
15
|
-
}
|
|
16
|
-
export interface ExperimentDraftInput {
|
|
17
|
-
projectId: string;
|
|
18
|
-
projectName: string;
|
|
19
|
-
signals: AnalyticsSignal[];
|
|
20
|
-
existingFlagKeys?: string[];
|
|
21
|
-
}
|
|
22
|
-
export interface VariantDraft {
|
|
23
|
-
name: string;
|
|
24
|
-
description: string;
|
|
25
|
-
isControl: boolean;
|
|
26
|
-
}
|
|
27
|
-
export interface GuardrailDraft {
|
|
28
|
-
metricName: string;
|
|
29
|
-
operator: string;
|
|
30
|
-
threshold: number;
|
|
31
|
-
}
|
|
32
|
-
export interface RolloutMilestone {
|
|
33
|
-
percentage: number;
|
|
34
|
-
criteria: string;
|
|
35
|
-
}
|
|
36
|
-
export interface RolloutPlan {
|
|
37
|
-
initialPercentage: number;
|
|
38
|
-
milestones: RolloutMilestone[];
|
|
39
|
-
}
|
|
40
|
-
export interface ExperimentDraft {
|
|
41
|
-
name: string;
|
|
42
|
-
hypothesis: string;
|
|
43
|
-
primaryMetric: string;
|
|
44
|
-
guardrails: GuardrailDraft[];
|
|
45
|
-
variants: VariantDraft[];
|
|
46
|
-
rolloutPlan: RolloutPlan;
|
|
47
|
-
rationale: string;
|
|
48
|
-
confidence: number;
|
|
49
|
-
estimatedImpact: string;
|
|
50
|
-
}
|
|
51
|
-
export type DraftDisposition = 'auto_queue' | 'require_approval' | 'suggest_only';
|
|
52
|
-
export interface ExperimentDecisionEvent {
|
|
53
|
-
type: 'experiment_draft_generated';
|
|
54
|
-
projectId: string;
|
|
55
|
-
draftName: string;
|
|
56
|
-
disposition: DraftDisposition;
|
|
57
|
-
autonomyLevel: string;
|
|
58
|
-
primaryMetric: string;
|
|
59
|
-
confidence: number;
|
|
60
|
-
timestamp: string;
|
|
61
|
-
signals: Array<{
|
|
62
|
-
metricName: string;
|
|
63
|
-
trend: string;
|
|
64
|
-
deltaPercent: number;
|
|
65
|
-
}>;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Compute urgency score for a signal.
|
|
69
|
-
* Higher = more urgent to experiment on.
|
|
70
|
-
*/
|
|
71
|
-
export declare function computeSignalUrgency(signal: AnalyticsSignal): number;
|
|
72
|
-
/**
|
|
73
|
-
* Select the primary signal to experiment on.
|
|
74
|
-
* Prefers declining signals with largest delta.
|
|
75
|
-
*/
|
|
76
|
-
export declare function selectPrimarySignal(signals: AnalyticsSignal[]): AnalyticsSignal;
|
|
77
|
-
/**
|
|
78
|
-
* Build the LLM prompt for experiment draft generation.
|
|
79
|
-
*/
|
|
80
|
-
export declare function buildExperimentDraftPrompt(input: ExperimentDraftInput): string;
|
|
81
|
-
/**
|
|
82
|
-
* Parse and validate an LLM response into an ExperimentDraft.
|
|
83
|
-
* Returns null if the response is invalid or incomplete.
|
|
84
|
-
*/
|
|
85
|
-
export declare function parseExperimentDraftResponse(response: string): ExperimentDraft | null;
|
|
86
|
-
//# sourceMappingURL=experiment-draft.d.ts.map
|