pi-advisor-flow 0.3.6 → 0.5.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/CHANGELOG.md +38 -0
- package/README.md +11 -5
- package/extensions/index.ts +0 -10
- package/package.json +11 -13
- package/src/commands.ts +355 -118
- package/src/config.ts +29 -3
- package/src/model-stream.ts +123 -0
- package/src/scout-context.ts +34 -8
- package/src/scout.ts +7 -34
- package/src/session-state.ts +48 -2
- package/src/tools.ts +208 -121
- package/src/ui.ts +1060 -600
- package/src/usage.ts +199 -0
- package/src/telemetry.ts +0 -270
package/src/usage.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { Usage } from "@earendil-works/pi-ai/compat";
|
|
2
|
+
|
|
3
|
+
/** Normalized usage returned by an Advisor or Scout provider response. */
|
|
4
|
+
export interface AdvisorUsageSnapshot {
|
|
5
|
+
cacheRead?: number;
|
|
6
|
+
cacheWrite?: number;
|
|
7
|
+
cost?: number;
|
|
8
|
+
input?: number;
|
|
9
|
+
output?: number;
|
|
10
|
+
totalTokens?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Session-local totals for direct Advisor model requests. */
|
|
14
|
+
export interface AdvisorUsageTotals {
|
|
15
|
+
cacheRead?: number;
|
|
16
|
+
cacheWrite?: number;
|
|
17
|
+
calls: number;
|
|
18
|
+
cost?: number;
|
|
19
|
+
costCalls: number;
|
|
20
|
+
input?: number;
|
|
21
|
+
knownCalls: number;
|
|
22
|
+
output?: number;
|
|
23
|
+
totalTokens?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const finite = (value: unknown) =>
|
|
27
|
+
typeof value === "number" && Number.isFinite(value) && value >= 0
|
|
28
|
+
? value
|
|
29
|
+
: undefined;
|
|
30
|
+
|
|
31
|
+
const add = (left: number | undefined, right: number | undefined) =>
|
|
32
|
+
left === undefined || right === undefined ? (left ?? right) : left + right;
|
|
33
|
+
|
|
34
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
35
|
+
Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
36
|
+
|
|
37
|
+
const costFields = ["input", "output", "cacheRead", "cacheWrite", "total"];
|
|
38
|
+
|
|
39
|
+
/** Extracts provider-agnostic usage fields without trusting provider metadata. */
|
|
40
|
+
export const snapshotAdvisorUsage = (
|
|
41
|
+
usage: unknown
|
|
42
|
+
): AdvisorUsageSnapshot | undefined => {
|
|
43
|
+
if (!isRecord(usage)) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const cost = isRecord(usage.cost) ? usage.cost : undefined;
|
|
47
|
+
const snapshot = {
|
|
48
|
+
cacheRead: finite(usage.cacheRead),
|
|
49
|
+
cacheWrite: finite(usage.cacheWrite),
|
|
50
|
+
cost: finite(cost?.total) ?? finite(usage.totalCost) ?? finite(usage.cost),
|
|
51
|
+
input: finite(usage.input),
|
|
52
|
+
output: finite(usage.output),
|
|
53
|
+
totalTokens: finite(usage.totalTokens),
|
|
54
|
+
} satisfies AdvisorUsageSnapshot;
|
|
55
|
+
const hasCostField = costFields.some(
|
|
56
|
+
(field) => finite(cost?.[field]) !== undefined
|
|
57
|
+
);
|
|
58
|
+
return Object.values(snapshot).some((value) => value !== undefined) ||
|
|
59
|
+
hasCostField
|
|
60
|
+
? snapshot
|
|
61
|
+
: undefined;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Returns the reported provider cost, when the response includes one. */
|
|
65
|
+
export const advisorUsageCost = (usage: unknown): number | undefined =>
|
|
66
|
+
snapshotAdvisorUsage(usage)?.cost;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Converts supported provider usage to Pi's complete nested-tool usage shape.
|
|
70
|
+
* Missing fields become zero only at this Pi API boundary; absent usage remains
|
|
71
|
+
* undefined so an unavailable request is never presented as a zero-cost call.
|
|
72
|
+
*/
|
|
73
|
+
export const advisorUsageForPi = (usage: unknown): Usage | undefined => {
|
|
74
|
+
const snapshot = snapshotAdvisorUsage(usage);
|
|
75
|
+
if (!(snapshot && isRecord(usage))) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const cost = isRecord(usage.cost) ? usage.cost : undefined;
|
|
79
|
+
const input = snapshot.input ?? 0;
|
|
80
|
+
const output = snapshot.output ?? 0;
|
|
81
|
+
const cacheRead = snapshot.cacheRead ?? 0;
|
|
82
|
+
const cacheWrite = snapshot.cacheWrite ?? 0;
|
|
83
|
+
const cacheWrite1h = finite(usage.cacheWrite1h);
|
|
84
|
+
const reasoning = finite(usage.reasoning);
|
|
85
|
+
return {
|
|
86
|
+
cacheRead,
|
|
87
|
+
cacheWrite,
|
|
88
|
+
...(cacheWrite1h === undefined ? {} : { cacheWrite1h }),
|
|
89
|
+
...(reasoning === undefined ? {} : { reasoning }),
|
|
90
|
+
cost: {
|
|
91
|
+
cacheRead: finite(cost?.cacheRead) ?? 0,
|
|
92
|
+
cacheWrite: finite(cost?.cacheWrite) ?? 0,
|
|
93
|
+
input: finite(cost?.input) ?? 0,
|
|
94
|
+
output: finite(cost?.output) ?? 0,
|
|
95
|
+
total: snapshot.cost ?? 0,
|
|
96
|
+
},
|
|
97
|
+
input,
|
|
98
|
+
output,
|
|
99
|
+
totalTokens:
|
|
100
|
+
snapshot.totalTokens ?? input + output + cacheRead + cacheWrite,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** Creates empty totals without treating absent usage as zero usage. */
|
|
105
|
+
export const emptyAdvisorUsageTotals = (): AdvisorUsageTotals => ({
|
|
106
|
+
calls: 0,
|
|
107
|
+
costCalls: 0,
|
|
108
|
+
knownCalls: 0,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/** Adds one direct Advisor response to session-local usage totals. */
|
|
112
|
+
export const addAdvisorUsage = (totals: AdvisorUsageTotals, usage: unknown) => {
|
|
113
|
+
totals.calls += 1;
|
|
114
|
+
const snapshot = snapshotAdvisorUsage(usage);
|
|
115
|
+
if (!snapshot) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
totals.knownCalls += 1;
|
|
119
|
+
totals.cacheRead = add(totals.cacheRead, snapshot.cacheRead);
|
|
120
|
+
totals.cacheWrite = add(totals.cacheWrite, snapshot.cacheWrite);
|
|
121
|
+
totals.input = add(totals.input, snapshot.input);
|
|
122
|
+
totals.output = add(totals.output, snapshot.output);
|
|
123
|
+
totals.totalTokens = add(totals.totalTokens, snapshot.totalTokens);
|
|
124
|
+
if (snapshot.cost !== undefined) {
|
|
125
|
+
totals.cost = add(totals.cost, snapshot.cost);
|
|
126
|
+
totals.costCalls += 1;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const formatTokens = (value: number) => {
|
|
131
|
+
if (value < 1000) {
|
|
132
|
+
return String(value);
|
|
133
|
+
}
|
|
134
|
+
if (value < 10_000) {
|
|
135
|
+
return `${(value / 1000).toFixed(1)}k`;
|
|
136
|
+
}
|
|
137
|
+
if (value < 1_000_000) {
|
|
138
|
+
return `${Math.round(value / 1000)}k`;
|
|
139
|
+
}
|
|
140
|
+
if (value < 10_000_000) {
|
|
141
|
+
return `${(value / 1_000_000).toFixed(1)}M`;
|
|
142
|
+
}
|
|
143
|
+
return `${Math.round(value / 1_000_000)}M`;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const formatCost = (value: number) => `$${value.toFixed(4)}`;
|
|
147
|
+
|
|
148
|
+
const formatUsageFields = (usage: AdvisorUsageSnapshot): string | undefined => {
|
|
149
|
+
const tokens = [
|
|
150
|
+
usage.input === undefined ? undefined : `↑${formatTokens(usage.input)}`,
|
|
151
|
+
usage.output === undefined ? undefined : `↓${formatTokens(usage.output)}`,
|
|
152
|
+
usage.cacheRead === undefined
|
|
153
|
+
? undefined
|
|
154
|
+
: `cr:${formatTokens(usage.cacheRead)}`,
|
|
155
|
+
usage.cacheWrite === undefined
|
|
156
|
+
? undefined
|
|
157
|
+
: `cw:${formatTokens(usage.cacheWrite)}`,
|
|
158
|
+
].filter((value): value is string => value !== undefined);
|
|
159
|
+
if (tokens.length === 0 && usage.totalTokens !== undefined) {
|
|
160
|
+
tokens.push(`tokens:${formatTokens(usage.totalTokens)}`);
|
|
161
|
+
}
|
|
162
|
+
if (usage.cost !== undefined) {
|
|
163
|
+
tokens.push(formatCost(usage.cost));
|
|
164
|
+
}
|
|
165
|
+
return tokens.join(" · ") || undefined;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/** Formats one response for an Advisor or Scout result renderer. */
|
|
169
|
+
export const formatAdvisorUsage = (usage: unknown): string | undefined => {
|
|
170
|
+
const snapshot = snapshotAdvisorUsage(usage);
|
|
171
|
+
return snapshot ? formatUsageFields(snapshot) : undefined;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/** Formats cumulative direct Advisor usage for a footer or session summary. */
|
|
175
|
+
export const formatAdvisorUsageTotals = (
|
|
176
|
+
totals: AdvisorUsageTotals
|
|
177
|
+
): string => {
|
|
178
|
+
const usage = formatUsageFields(totals);
|
|
179
|
+
const missing = totals.calls - totals.knownCalls;
|
|
180
|
+
const parts = [
|
|
181
|
+
usage,
|
|
182
|
+
missing > 0 ? `${missing} without usage data` : undefined,
|
|
183
|
+
];
|
|
184
|
+
return (
|
|
185
|
+
parts.filter((value): value is string => value !== undefined).join(" · ") ||
|
|
186
|
+
"unavailable"
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/** Formats the current direct Advisor usage status for the Pi footer. */
|
|
191
|
+
export const formatAdvisorUsageStatus = (
|
|
192
|
+
totals: AdvisorUsageTotals
|
|
193
|
+
): string | undefined => {
|
|
194
|
+
if (totals.calls === 0) {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
const label = `Advisor: ${totals.calls} call${totals.calls === 1 ? "" : "s"}`;
|
|
198
|
+
return `${label} · ${formatAdvisorUsageTotals(totals)}`;
|
|
199
|
+
};
|
package/src/telemetry.ts
DELETED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import type { EventBus } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { redactAndCapText } from "./conversation.js";
|
|
3
|
-
|
|
4
|
-
export const BENCHMARK_TELEMETRY_CHANNEL = "pi-advisor:benchmark";
|
|
5
|
-
const BENCHMARK_CONTEXT = "PI_ADVISOR_BENCHMARK_CONTEXT";
|
|
6
|
-
const BENCHMARK_RUN_ID = "PI_ADVISOR_BENCHMARK_RUN_ID";
|
|
7
|
-
const BENCHMARK_TOKEN = "PI_ADVISOR_BENCHMARK_TOKEN";
|
|
8
|
-
const MAX_TEXT_BYTES = 2000;
|
|
9
|
-
const MAX_LABELS = 32;
|
|
10
|
-
const MAX_LABEL_BYTES = 160;
|
|
11
|
-
|
|
12
|
-
export interface BenchmarkAdvisorStart {
|
|
13
|
-
model: string;
|
|
14
|
-
question?: string;
|
|
15
|
-
trigger?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface BenchmarkAdvisorEnd extends BenchmarkAdvisorStart {
|
|
19
|
-
outcome?: string;
|
|
20
|
-
response?: string;
|
|
21
|
-
usage?: unknown;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface BenchmarkAdvisorError extends BenchmarkAdvisorStart {
|
|
25
|
-
category: "provider-error" | "empty-response" | "cancelled" | "unknown";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type BenchmarkScoutEvent =
|
|
29
|
-
| { model: string; type: "call" }
|
|
30
|
-
| {
|
|
31
|
-
availableCount?: number;
|
|
32
|
-
latencyMs?: number;
|
|
33
|
-
model: string;
|
|
34
|
-
omittedBeforeScout?: number;
|
|
35
|
-
selectedCount?: number;
|
|
36
|
-
selectedLabels?: string[];
|
|
37
|
-
synthesis?: string;
|
|
38
|
-
type: "success";
|
|
39
|
-
usage?: unknown;
|
|
40
|
-
}
|
|
41
|
-
| {
|
|
42
|
-
availableCount?: number;
|
|
43
|
-
fallback?: string;
|
|
44
|
-
latencyMs?: number;
|
|
45
|
-
model: string;
|
|
46
|
-
omittedBeforeScout?: number;
|
|
47
|
-
selectedCount?: number;
|
|
48
|
-
type: "fallback";
|
|
49
|
-
usage?: unknown;
|
|
50
|
-
}
|
|
51
|
-
| { type: "cancelled" };
|
|
52
|
-
|
|
53
|
-
export type BenchmarkTelemetryEvent =
|
|
54
|
-
| {
|
|
55
|
-
type: "advisor:start";
|
|
56
|
-
runId: string;
|
|
57
|
-
model: string;
|
|
58
|
-
question?: string;
|
|
59
|
-
trigger?: string;
|
|
60
|
-
timestamp: string;
|
|
61
|
-
}
|
|
62
|
-
| {
|
|
63
|
-
type: "advisor:end";
|
|
64
|
-
runId: string;
|
|
65
|
-
model: string;
|
|
66
|
-
outcome?: string;
|
|
67
|
-
response?: string;
|
|
68
|
-
timestamp: string;
|
|
69
|
-
usage?: Record<string, unknown>;
|
|
70
|
-
}
|
|
71
|
-
| {
|
|
72
|
-
type: "advisor:error";
|
|
73
|
-
category: BenchmarkAdvisorError["category"];
|
|
74
|
-
runId: string;
|
|
75
|
-
model: string;
|
|
76
|
-
timestamp: string;
|
|
77
|
-
}
|
|
78
|
-
| {
|
|
79
|
-
event: BenchmarkScoutEvent;
|
|
80
|
-
runId: string;
|
|
81
|
-
timestamp: string;
|
|
82
|
-
type: "scout";
|
|
83
|
-
}
|
|
84
|
-
| {
|
|
85
|
-
fields: Record<string, unknown>;
|
|
86
|
-
runId: string;
|
|
87
|
-
timestamp: string;
|
|
88
|
-
type: "provider-request";
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
type BenchmarkTelemetryPayload = {
|
|
92
|
-
[K in BenchmarkTelemetryEvent["type"]]: Omit<
|
|
93
|
-
Extract<BenchmarkTelemetryEvent, { type: K }>,
|
|
94
|
-
"runId" | "timestamp"
|
|
95
|
-
>;
|
|
96
|
-
}[BenchmarkTelemetryEvent["type"]];
|
|
97
|
-
|
|
98
|
-
export interface BenchmarkTelemetry {
|
|
99
|
-
advisorEnd: (event: BenchmarkAdvisorEnd) => void;
|
|
100
|
-
advisorError: (event: BenchmarkAdvisorError) => void;
|
|
101
|
-
advisorStart: (event: BenchmarkAdvisorStart) => void;
|
|
102
|
-
providerRequest: (payload: unknown) => void;
|
|
103
|
-
scout: (event: BenchmarkScoutEvent) => void;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const finite = (value: unknown) =>
|
|
107
|
-
typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
108
|
-
|
|
109
|
-
const usageSnapshot = (usage: unknown): Record<string, unknown> | undefined => {
|
|
110
|
-
if (!usage || typeof usage !== "object") {
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
|
-
const source = usage as Record<string, unknown>;
|
|
114
|
-
const { cost } = source;
|
|
115
|
-
const costSource =
|
|
116
|
-
cost && typeof cost === "object"
|
|
117
|
-
? (cost as Record<string, unknown>)
|
|
118
|
-
: undefined;
|
|
119
|
-
const result = Object.fromEntries(
|
|
120
|
-
["input", "output", "cacheRead", "cacheWrite", "totalTokens"]
|
|
121
|
-
.map((key) => [key, finite(source[key])] as const)
|
|
122
|
-
.filter(([, value]) => value !== undefined)
|
|
123
|
-
) as Record<string, unknown>;
|
|
124
|
-
const providerCost = finite(costSource?.total);
|
|
125
|
-
if (providerCost !== undefined) {
|
|
126
|
-
result.cost = { total: providerCost };
|
|
127
|
-
}
|
|
128
|
-
return Object.keys(result).length > 0 ? result : undefined;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const text = (value: string | undefined, maxBytes = MAX_TEXT_BYTES) =>
|
|
132
|
-
value ? redactAndCapText(value, maxBytes, true) : undefined;
|
|
133
|
-
|
|
134
|
-
const labels = (values: string[] | undefined) =>
|
|
135
|
-
values
|
|
136
|
-
?.slice(0, MAX_LABELS)
|
|
137
|
-
.map((value) => text(value, MAX_LABEL_BYTES))
|
|
138
|
-
.filter((value): value is string => Boolean(value));
|
|
139
|
-
|
|
140
|
-
const PROVIDER_SENSITIVE_KEY = /message|prompt|content|input|system/i;
|
|
141
|
-
const SAFE_PROVIDER_FIELDS = new Set([
|
|
142
|
-
"max_completion_tokens",
|
|
143
|
-
"max_tokens",
|
|
144
|
-
"parallel_tool_calls",
|
|
145
|
-
"reasoning_effort",
|
|
146
|
-
"temperature",
|
|
147
|
-
"top_p",
|
|
148
|
-
"tool_choice",
|
|
149
|
-
]);
|
|
150
|
-
const sanitizeProviderValue = (value: unknown, depth = 0): unknown => {
|
|
151
|
-
if (depth > 3 || value === null) {
|
|
152
|
-
return value;
|
|
153
|
-
}
|
|
154
|
-
if (
|
|
155
|
-
typeof value === "string" ||
|
|
156
|
-
typeof value === "number" ||
|
|
157
|
-
typeof value === "boolean"
|
|
158
|
-
) {
|
|
159
|
-
return typeof value === "string" ? text(value, 320) : value;
|
|
160
|
-
}
|
|
161
|
-
if (Array.isArray(value)) {
|
|
162
|
-
return value
|
|
163
|
-
.slice(0, 16)
|
|
164
|
-
.map((item) => sanitizeProviderValue(item, depth + 1));
|
|
165
|
-
}
|
|
166
|
-
if (typeof value === "object") {
|
|
167
|
-
return Object.fromEntries(
|
|
168
|
-
Object.entries(value as Record<string, unknown>)
|
|
169
|
-
.filter(([key]) => !PROVIDER_SENSITIVE_KEY.test(key))
|
|
170
|
-
.slice(0, 32)
|
|
171
|
-
.map(([key, item]) => [key, sanitizeProviderValue(item, depth + 1)])
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
return undefined;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const providerFields = (payload: unknown): Record<string, unknown> => {
|
|
178
|
-
const value =
|
|
179
|
-
payload && typeof payload === "object"
|
|
180
|
-
? (payload as Record<string, unknown>)
|
|
181
|
-
: {};
|
|
182
|
-
return Object.fromEntries(
|
|
183
|
-
[...SAFE_PROVIDER_FIELDS]
|
|
184
|
-
.filter((key) => key in value)
|
|
185
|
-
.map((key) => [key, sanitizeProviderValue(value[key])])
|
|
186
|
-
);
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
const enabledCapability = () => {
|
|
190
|
-
const context = process.env[BENCHMARK_CONTEXT] === "1";
|
|
191
|
-
const runId = process.env[BENCHMARK_RUN_ID];
|
|
192
|
-
const token = process.env[BENCHMARK_TOKEN];
|
|
193
|
-
if (!(context && runId && token && token.length >= 32)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
return { runId, token };
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
export const createBenchmarkTelemetry = (
|
|
200
|
-
events: EventBus
|
|
201
|
-
): BenchmarkTelemetry | undefined => {
|
|
202
|
-
const capability = enabledCapability();
|
|
203
|
-
if (!capability) {
|
|
204
|
-
return undefined;
|
|
205
|
-
}
|
|
206
|
-
const emit = (event: BenchmarkTelemetryPayload) => {
|
|
207
|
-
try {
|
|
208
|
-
events.emit(BENCHMARK_TELEMETRY_CHANNEL, {
|
|
209
|
-
...event,
|
|
210
|
-
runId: capability.runId,
|
|
211
|
-
timestamp: new Date().toISOString(),
|
|
212
|
-
} satisfies BenchmarkTelemetryEvent);
|
|
213
|
-
} catch {
|
|
214
|
-
// Benchmark diagnostics must never change Advisor/Scout behavior.
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
return {
|
|
218
|
-
advisorEnd: (event) =>
|
|
219
|
-
emit({
|
|
220
|
-
model: event.model,
|
|
221
|
-
outcome: text(event.outcome, 160),
|
|
222
|
-
response: text(event.response),
|
|
223
|
-
type: "advisor:end",
|
|
224
|
-
usage: usageSnapshot(event.usage),
|
|
225
|
-
}),
|
|
226
|
-
advisorError: (event) =>
|
|
227
|
-
emit({
|
|
228
|
-
category: event.category,
|
|
229
|
-
model: event.model,
|
|
230
|
-
type: "advisor:error",
|
|
231
|
-
}),
|
|
232
|
-
advisorStart: (event) =>
|
|
233
|
-
emit({
|
|
234
|
-
model: event.model,
|
|
235
|
-
question: text(event.question),
|
|
236
|
-
trigger: text(event.trigger, 160),
|
|
237
|
-
type: "advisor:start",
|
|
238
|
-
}),
|
|
239
|
-
providerRequest: (payload) => {
|
|
240
|
-
emit({
|
|
241
|
-
fields: providerFields(payload),
|
|
242
|
-
type: "provider-request",
|
|
243
|
-
});
|
|
244
|
-
},
|
|
245
|
-
scout: (event) => {
|
|
246
|
-
if (event.type === "call" || event.type === "cancelled") {
|
|
247
|
-
emit({ event, type: "scout" });
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
emit({
|
|
251
|
-
event: {
|
|
252
|
-
...(event.type === "success"
|
|
253
|
-
? {
|
|
254
|
-
selectedLabels: labels(event.selectedLabels),
|
|
255
|
-
synthesis: text(event.synthesis),
|
|
256
|
-
}
|
|
257
|
-
: { fallback: text(event.fallback, 320) }),
|
|
258
|
-
availableCount: finite(event.availableCount),
|
|
259
|
-
latencyMs: finite(event.latencyMs),
|
|
260
|
-
model: event.model,
|
|
261
|
-
omittedBeforeScout: finite(event.omittedBeforeScout),
|
|
262
|
-
selectedCount: finite(event.selectedCount),
|
|
263
|
-
type: event.type,
|
|
264
|
-
usage: usageSnapshot(event.usage),
|
|
265
|
-
},
|
|
266
|
-
type: "scout",
|
|
267
|
-
});
|
|
268
|
-
},
|
|
269
|
-
};
|
|
270
|
-
};
|