-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathexplain-traces.fixture.ts
More file actions
139 lines (132 loc) · 4.52 KB
/
Copy pathexplain-traces.fixture.ts
File metadata and controls
139 lines (132 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { test as baseTest } from './annotation-queue.fixture';
export interface ExplainTraceRef {
id: string;
name: string;
errorType: string;
/** Seeded trace duration in seconds; null means left unset (renders as Duration "NA"). */
durationSeconds: number | null;
/** Seeded LLM-span cost; null means no cost-bearing span (renders as Cost "-"). */
cost: number | null;
/**
* Source of a case-insensitive RegExp expected to appear in Ollie's error
* explanation for this trace. Ollie's phrasing is non-deterministic (see
* ollie-explain.spec.ts), so this is anchored to concrete details of the
* seeded error (exception type / message) rather than generic
* error-adjacent vocabulary ("error", "fail", ...) — those turned out to be
* skippable depending on phrasing (e.g. a rate-limit explanation that never
* says "fail" or "exceed"), while the concrete subject (rate limit,
* document store, timeout, permissions, faiss) reliably recurs because
* Ollie is grounded in that seeded content.
*/
errorKeywordSource: string;
}
export interface ExplainTracesFixtures {
explainTraces: ExplainTraceRef[];
}
/**
* Five traces shaped for the Ollie "Explain" cell feature: each has a distinct
* trace-level error, and distinct duration/cost, with one trace leaving both
* duration and cost unset so the explain button's N/A path (Duration "NA",
* Cost "-") gets covered too — per `explainTargets.ts`, those cells stay
* explainable even at N/A, unlike the error cell which vetoes on no error.
*/
const SEEDS: Array<{
suffix: string;
errorType: string;
errorMessage: string;
/** RegExp source (case-insensitive) expected in Ollie's explanation of this error. */
errorKeyword: string;
durationSeconds: number | null;
cost: number | null;
}> = [
{
suffix: 'rate-limit',
errorType: 'RuntimeError',
errorMessage: 'Model returned status 429: rate limit exceeded',
errorKeyword: 'rate.?limit',
durationSeconds: 2,
cost: 0.0005,
},
{
suffix: 'missing-context',
errorType: 'ValueError',
errorMessage: 'Missing required context: document store unavailable',
errorKeyword: 'context|document store',
durationSeconds: 15,
cost: 0.02,
},
{
suffix: 'tool-timeout',
errorType: 'TimeoutError',
errorMessage: 'Tool call timed out after 30 s',
errorKeyword: 'timeout',
durationSeconds: 60,
cost: 0.5,
},
{
suffix: 'auth-failure',
errorType: 'PermissionError',
errorMessage: 'API key does not have access to model claude-3-opus',
errorKeyword: 'permission|access|api key',
durationSeconds: 180,
cost: 2.0,
},
{
suffix: 'quota-exceeded',
errorType: 'ImportError',
errorMessage: "Required dependency 'faiss' is not installed",
errorKeyword: 'faiss|install|depend',
durationSeconds: null,
cost: null,
},
];
export const test = baseTest.extend<ExplainTracesFixtures>({
explainTraces: async ({ sdkClient, project, testNamespace }, use, testInfo) => {
const refs: ExplainTraceRef[] = [];
for (const seed of SEEDS) {
const name = `${testNamespace}-explain-${seed.suffix}`;
const spans =
seed.cost === null
? []
: [
{
name: 'llm-call',
type: 'llm' as const,
model: 'gpt-4o',
provider: 'openai',
input: { prompt: 'seed prompt' },
output: { completion: 'seed completion' },
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
total_cost: seed.cost,
},
];
const created = await sdkClient.python.createNestedTrace({
project_name: project.name,
name,
input: { user: `trigger for ${seed.suffix}` },
tags: ['explain', seed.suffix],
error_info: {
exception_type: seed.errorType,
message: seed.errorMessage,
},
duration_seconds: seed.durationSeconds ?? undefined,
spans,
});
refs.push({
id: created.id,
name: created.name,
errorType: seed.errorType,
durationSeconds: seed.durationSeconds,
cost: seed.cost,
errorKeywordSource: seed.errorKeyword,
});
}
await testInfo.attach('opik.explainTraces', {
body: JSON.stringify(refs, null, 2),
contentType: 'application/json',
});
await use(refs);
// No explicit teardown — the project fixture's deleteProject cascades.
},
});
export { expect } from './annotation-queue.fixture';