@arizeai/phoenix-cli 1.5.3 → 1.6.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.
Files changed (45) hide show
  1. package/build/pxi/App.d.ts +22 -0
  2. package/build/pxi/App.d.ts.map +1 -0
  3. package/build/pxi/App.js +328 -0
  4. package/build/pxi/App.js.map +1 -0
  5. package/build/pxi/client.d.ts +77 -0
  6. package/build/pxi/client.d.ts.map +1 -0
  7. package/build/pxi/client.js +170 -0
  8. package/build/pxi/client.js.map +1 -0
  9. package/build/pxi/commands.d.ts +37 -0
  10. package/build/pxi/commands.d.ts.map +1 -0
  11. package/build/pxi/commands.js +61 -0
  12. package/build/pxi/commands.js.map +1 -0
  13. package/build/pxi/index.d.ts +14 -0
  14. package/build/pxi/index.d.ts.map +1 -0
  15. package/build/pxi/index.js +36 -0
  16. package/build/pxi/index.js.map +1 -0
  17. package/build/pxi/inkMarkdown.d.ts +17 -0
  18. package/build/pxi/inkMarkdown.d.ts.map +1 -0
  19. package/build/pxi/inkMarkdown.js +22 -0
  20. package/build/pxi/inkMarkdown.js.map +1 -0
  21. package/build/pxi/markdown.d.ts +24 -0
  22. package/build/pxi/markdown.d.ts.map +1 -0
  23. package/build/pxi/markdown.js +115 -0
  24. package/build/pxi/markdown.js.map +1 -0
  25. package/build/pxi/options.d.ts +64 -0
  26. package/build/pxi/options.d.ts.map +1 -0
  27. package/build/pxi/options.js +148 -0
  28. package/build/pxi/options.js.map +1 -0
  29. package/build/pxi/preflight.d.ts +88 -0
  30. package/build/pxi/preflight.d.ts.map +1 -0
  31. package/build/pxi/preflight.js +255 -0
  32. package/build/pxi/preflight.js.map +1 -0
  33. package/build/pxi/tokenUsage.d.ts +35 -0
  34. package/build/pxi/tokenUsage.d.ts.map +1 -0
  35. package/build/pxi/tokenUsage.js +62 -0
  36. package/build/pxi/tokenUsage.js.map +1 -0
  37. package/build/pxi/toolProgress.d.ts +37 -0
  38. package/build/pxi/toolProgress.d.ts.map +1 -0
  39. package/build/pxi/toolProgress.js +71 -0
  40. package/build/pxi/toolProgress.js.map +1 -0
  41. package/build/pxi/types.d.ts +123 -0
  42. package/build/pxi/types.d.ts.map +1 -0
  43. package/build/pxi/types.js +2 -0
  44. package/build/pxi/types.js.map +1 -0
  45. package/package.json +14 -5
@@ -0,0 +1,88 @@
1
+ import type { PhoenixConfig } from "../config.js";
2
+ import type { ModelSelection, PxiRuntimeOptions } from "./types.js";
3
+ /**
4
+ * Pre-launch validation of the selected model.
5
+ *
6
+ * Before the chat UI opens, PXI asks the Phoenix server which providers and
7
+ * models are actually installed and credentialed, then checks the user's
8
+ * `--provider`/`--model` selection against that catalog. Catching a bad or
9
+ * unconfigured model here turns what would be a cryptic mid-stream failure into
10
+ * a clear, actionable startup error. The whole check can be skipped with
11
+ * `--skip-model-preflight`.
12
+ */
13
+ /** GraphQL query fetching the server's provider catalog, credential state, and known models. */
14
+ export declare const PXI_MODEL_PREFLIGHT_QUERY = "\n query PxiModelPreflightQuery {\n modelProviders {\n key\n name\n dependenciesInstalled\n credentialsSet\n credentialRequirements {\n envVarName\n isRequired\n }\n }\n playgroundModels {\n providerKey\n name\n }\n generativeModelCustomProviders(first: 50) {\n edges {\n node {\n id\n name\n sdk\n modelNames\n }\n }\n }\n }\n";
15
+ type PxiModelProvider = {
16
+ key: string;
17
+ name: string;
18
+ dependenciesInstalled: boolean;
19
+ credentialsSet: boolean;
20
+ credentialRequirements: Array<{
21
+ envVarName: string;
22
+ isRequired: boolean;
23
+ }>;
24
+ };
25
+ type PxiPlaygroundModel = {
26
+ providerKey: string;
27
+ name: string;
28
+ };
29
+ type PxiCustomProvider = {
30
+ id: string;
31
+ name: string;
32
+ sdk: string;
33
+ modelNames: string[];
34
+ };
35
+ type PxiModelPreflightData = {
36
+ modelProviders: PxiModelProvider[];
37
+ playgroundModels: PxiPlaygroundModel[];
38
+ generativeModelCustomProviders: {
39
+ edges: Array<{
40
+ node: PxiCustomProvider;
41
+ }>;
42
+ };
43
+ };
44
+ /**
45
+ * Fetch the provider/model catalog from Phoenix via GraphQL. Requires a
46
+ * configured endpoint and turns non-2xx responses into errors that include the
47
+ * HTTP status and any response body. `fetchImpl` is injectable for testing.
48
+ */
49
+ export declare function fetchPxiModelPreflight({ config, fetchImpl, }: {
50
+ config: PhoenixConfig;
51
+ fetchImpl?: typeof globalThis.fetch;
52
+ }): Promise<PxiModelPreflightData>;
53
+ /**
54
+ * Check a model selection against the fetched catalog, throwing
55
+ * {@link InvalidArgumentError} with a helpful message on the first problem.
56
+ *
57
+ * For custom providers: the provider id must exist, and the model must be one of
58
+ * its configured names (when it advertises any). For built-in providers: the
59
+ * provider must be available, have its dependencies installed and credentials
60
+ * set, and — if the server publishes a model catalog for it — the model must be
61
+ * in that catalog. A provider with no published catalog accepts any model name.
62
+ */
63
+ export declare function validatePxiModelSelection({ data, modelSelection, }: {
64
+ data: PxiModelPreflightData;
65
+ modelSelection: ModelSelection;
66
+ }): void;
67
+ /**
68
+ * Run the full preflight for a session: fetch the catalog and validate the
69
+ * selected model, unless `--skip-model-preflight` was passed. This is the single
70
+ * call the entry point makes before rendering the UI.
71
+ */
72
+ export declare function runPxiModelPreflight({ options, fetchImpl, }: {
73
+ options: PxiRuntimeOptions;
74
+ fetchImpl?: typeof globalThis.fetch;
75
+ }): Promise<void>;
76
+ /**
77
+ * Wrap an error thrown while talking to PXI into a single message that names the
78
+ * model and appends a tailored next step — pointing custom providers at their
79
+ * Phoenix settings and built-in providers at credential configuration or
80
+ * choosing a different model. Used for failures that surface after the preflight
81
+ * has already passed.
82
+ */
83
+ export declare function formatPxiRuntimeError({ error, modelSelection, }: {
84
+ error: unknown;
85
+ modelSelection: ModelSelection;
86
+ }): Error;
87
+ export {};
88
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../src/pxi/preflight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjE;;;;;;;;;GASG;AAEH,gGAAgG;AAChG,eAAO,MAAM,yBAAyB,kdA2BrC,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB,EAAE,OAAO,CAAC;IAC/B,cAAc,EAAE,OAAO,CAAC;IACxB,sBAAsB,EAAE,KAAK,CAAC;QAC5B,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC,CAAC;CACJ,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,8BAA8B,EAAE;QAC9B,KAAK,EAAE,KAAK,CAAC;YACX,IAAI,EAAE,iBAAiB,CAAC;SACzB,CAAC,CAAC;KACJ,CAAC;CACH,CAAC;AAoKF;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,MAAM,EACN,SAA4B,GAC7B,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAqCjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,IAAI,EACJ,cAAc,GACf,EAAE;IACD,IAAI,EAAE,qBAAqB,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC;CAChC,GAAG,IAAI,CA4DP;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,OAAO,EACP,SAA4B,GAC7B,EAAE;IACD,OAAO,EAAE,iBAAiB,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACrC,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,cAAc,GACf,EAAE;IACD,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,cAAc,CAAC;CAChC,GAAG,KAAK,CASR"}
@@ -0,0 +1,255 @@
1
+ import { buildGraphqlRequest } from "../commands/api.js";
2
+ import { InvalidArgumentError } from "../exitCodes.js";
3
+ /**
4
+ * Pre-launch validation of the selected model.
5
+ *
6
+ * Before the chat UI opens, PXI asks the Phoenix server which providers and
7
+ * models are actually installed and credentialed, then checks the user's
8
+ * `--provider`/`--model` selection against that catalog. Catching a bad or
9
+ * unconfigured model here turns what would be a cryptic mid-stream failure into
10
+ * a clear, actionable startup error. The whole check can be skipped with
11
+ * `--skip-model-preflight`.
12
+ */
13
+ /** GraphQL query fetching the server's provider catalog, credential state, and known models. */
14
+ export const PXI_MODEL_PREFLIGHT_QUERY = /* GraphQL */ `
15
+ query PxiModelPreflightQuery {
16
+ modelProviders {
17
+ key
18
+ name
19
+ dependenciesInstalled
20
+ credentialsSet
21
+ credentialRequirements {
22
+ envVarName
23
+ isRequired
24
+ }
25
+ }
26
+ playgroundModels {
27
+ providerKey
28
+ name
29
+ }
30
+ generativeModelCustomProviders(first: 50) {
31
+ edges {
32
+ node {
33
+ id
34
+ name
35
+ sdk
36
+ modelNames
37
+ }
38
+ }
39
+ }
40
+ }
41
+ `;
42
+ /**
43
+ * Render a list of values for an error message, capping it at `limit` and
44
+ * summarizing the overflow as "…, and N more" so messages stay readable when a
45
+ * provider exposes many models.
46
+ */
47
+ function formatList({ values, limit = 8, }) {
48
+ if (values.length === 0) {
49
+ return "none";
50
+ }
51
+ const visibleValues = values.slice(0, limit);
52
+ const remainingCount = values.length - visibleValues.length;
53
+ if (remainingCount <= 0) {
54
+ return visibleValues.join(", ");
55
+ }
56
+ return `${visibleValues.join(", ")}, and ${remainingCount} more`;
57
+ }
58
+ function getModelLabel({ modelSelection, }) {
59
+ if (modelSelection.providerType === "custom") {
60
+ return `custom:${modelSelection.providerId}/${modelSelection.modelName}`;
61
+ }
62
+ return `${modelSelection.provider}/${modelSelection.modelName}`;
63
+ }
64
+ function getErrorMessage({ error }) {
65
+ return error instanceof Error ? error.message : String(error);
66
+ }
67
+ function getErrorCauseMessage({ error }) {
68
+ if (!(error instanceof Error) || !("cause" in error)) {
69
+ return null;
70
+ }
71
+ const cause = error.cause;
72
+ if (!cause) {
73
+ return null;
74
+ }
75
+ return getErrorMessage({ error: cause });
76
+ }
77
+ function formatEndpointPreflightFailure({ error, endpoint, requestUrl, }) {
78
+ const causeMessage = getErrorCauseMessage({ error });
79
+ const causeLine = causeMessage ? `\nCause: ${causeMessage}` : "";
80
+ return [
81
+ "Could not reach Phoenix during PXI startup preflight.",
82
+ "",
83
+ `Endpoint: ${endpoint}`,
84
+ `Request: ${requestUrl}`,
85
+ `Network error: ${getErrorMessage({ error })}${causeLine}`,
86
+ "",
87
+ "How to fix:",
88
+ " 1. Start Phoenix and confirm the server is listening.",
89
+ " 2. If Phoenix is running at a different URL, pass --endpoint <url> or set PHOENIX_HOST.",
90
+ " 3. For remote endpoints, check VPN, proxy, firewall, and DNS settings.",
91
+ " 4. To skip only model validation, pass --skip-model-preflight.",
92
+ ].join("\n");
93
+ }
94
+ /**
95
+ * Compose the "missing credentials" error for a provider, listing the required
96
+ * environment variables (falling back to all known ones if none are flagged
97
+ * required) and clarifying that these are server-side provider credentials, not
98
+ * the PXI CLI `--api-key`.
99
+ */
100
+ function buildServerCredentialMessage({ provider, }) {
101
+ const requiredEnvVars = provider.credentialRequirements
102
+ .filter((requirement) => requirement.isRequired)
103
+ .map((requirement) => requirement.envVarName);
104
+ const envVars = requiredEnvVars.length > 0
105
+ ? requiredEnvVars
106
+ : provider.credentialRequirements.map((requirement) => requirement.envVarName);
107
+ return [
108
+ `Missing credentials for ${provider.name} (${provider.key}).`,
109
+ `Required server credential variables/secrets: ${formatList({
110
+ values: envVars,
111
+ })}.`,
112
+ "Configure credentials in Phoenix Settings > AI Providers, or set the required environment variables on the Phoenix server.",
113
+ "These are Phoenix server-side provider credentials, not the PXI CLI --api-key.",
114
+ ].join(" ");
115
+ }
116
+ function getCustomProviders({ data, }) {
117
+ return data.generativeModelCustomProviders.edges.map((edge) => edge.node);
118
+ }
119
+ async function readResponseText({ response, }) {
120
+ try {
121
+ return await response.text();
122
+ }
123
+ catch {
124
+ return "";
125
+ }
126
+ }
127
+ /**
128
+ * Unwrap a GraphQL response into its `data`, throwing a descriptive error if the
129
+ * server returned GraphQL errors or no data at all. Error messages point at
130
+ * `--skip-model-preflight` as the escape hatch.
131
+ */
132
+ function assertPreflightData({ payload, }) {
133
+ const errors = payload.errors
134
+ ?.map((error) => error.message)
135
+ .filter((message) => Boolean(message));
136
+ if (errors && errors.length > 0) {
137
+ throw new Error(`Could not validate PXI model selection because Phoenix returned GraphQL errors: ${errors.join("; ")}. Use --skip-model-preflight to bypass this startup check.`);
138
+ }
139
+ if (!payload.data) {
140
+ throw new Error("Could not validate PXI model selection because Phoenix returned no GraphQL data. Use --skip-model-preflight to bypass this startup check.");
141
+ }
142
+ return payload.data;
143
+ }
144
+ /**
145
+ * Fetch the provider/model catalog from Phoenix via GraphQL. Requires a
146
+ * configured endpoint and turns non-2xx responses into errors that include the
147
+ * HTTP status and any response body. `fetchImpl` is injectable for testing.
148
+ */
149
+ export async function fetchPxiModelPreflight({ config, fetchImpl = globalThis.fetch, }) {
150
+ if (!config.endpoint) {
151
+ throw new InvalidArgumentError("Phoenix endpoint not configured. Set PHOENIX_HOST or pass --endpoint.");
152
+ }
153
+ const request = buildGraphqlRequest({
154
+ query: PXI_MODEL_PREFLIGHT_QUERY,
155
+ config,
156
+ });
157
+ let response;
158
+ try {
159
+ response = await fetchImpl(request.url, {
160
+ method: request.method,
161
+ headers: request.headers,
162
+ body: request.body,
163
+ });
164
+ }
165
+ catch (error) {
166
+ throw new TypeError(formatEndpointPreflightFailure({
167
+ error,
168
+ endpoint: config.endpoint,
169
+ requestUrl: request.url,
170
+ }), { cause: error });
171
+ }
172
+ if (!response.ok) {
173
+ const detail = await readResponseText({ response });
174
+ const detailText = detail ? `: ${detail}` : "";
175
+ throw new Error(`Could not validate PXI model selection: HTTP ${response.status} ${response.statusText} from ${request.url}${detailText}. Use --skip-model-preflight to bypass this startup check.`);
176
+ }
177
+ const payload = (await response.json());
178
+ return assertPreflightData({ payload });
179
+ }
180
+ /**
181
+ * Check a model selection against the fetched catalog, throwing
182
+ * {@link InvalidArgumentError} with a helpful message on the first problem.
183
+ *
184
+ * For custom providers: the provider id must exist, and the model must be one of
185
+ * its configured names (when it advertises any). For built-in providers: the
186
+ * provider must be available, have its dependencies installed and credentials
187
+ * set, and — if the server publishes a model catalog for it — the model must be
188
+ * in that catalog. A provider with no published catalog accepts any model name.
189
+ */
190
+ export function validatePxiModelSelection({ data, modelSelection, }) {
191
+ if (modelSelection.providerType === "custom") {
192
+ const customProviders = getCustomProviders({ data });
193
+ const provider = customProviders.find((candidate) => candidate.id === modelSelection.providerId);
194
+ if (!provider) {
195
+ throw new InvalidArgumentError(`Custom provider ${modelSelection.providerId} was not found on this Phoenix server. Configure it in Phoenix Settings > AI Providers or pass --skip-model-preflight. Available custom provider IDs: ${formatList({ values: customProviders.map((candidate) => candidate.id) })}.`);
196
+ }
197
+ if (provider.modelNames.length > 0 &&
198
+ !provider.modelNames.includes(modelSelection.modelName)) {
199
+ throw new InvalidArgumentError(`Invalid model for custom provider ${provider.name} (${provider.id}): ${modelSelection.modelName}. Configured model names: ${formatList({ values: provider.modelNames })}.`);
200
+ }
201
+ return;
202
+ }
203
+ const provider = data.modelProviders.find((candidate) => candidate.key === modelSelection.provider);
204
+ const availableProviderKeys = data.modelProviders.map((candidate) => candidate.key);
205
+ if (!provider) {
206
+ throw new InvalidArgumentError(`Provider ${modelSelection.provider} is not available on this Phoenix server. Available providers: ${formatList({ values: availableProviderKeys })}.`);
207
+ }
208
+ if (!provider.dependenciesInstalled) {
209
+ throw new InvalidArgumentError(`${provider.name} (${provider.key}) is unavailable because the Phoenix server does not have that provider installed. Install the provider dependencies on the Phoenix server or choose another provider.`);
210
+ }
211
+ if (provider.credentialRequirements.length > 0 && !provider.credentialsSet) {
212
+ throw new InvalidArgumentError(buildServerCredentialMessage({ provider }));
213
+ }
214
+ const providerModels = data.playgroundModels
215
+ .filter((model) => model.providerKey === modelSelection.provider)
216
+ .map((model) => model.name);
217
+ const hasProviderCatalog = providerModels.length > 0;
218
+ const isKnownModel = providerModels.includes(modelSelection.modelName);
219
+ if (hasProviderCatalog && !isKnownModel) {
220
+ throw new InvalidArgumentError(`Invalid model for ${provider.name} (${provider.key}): ${modelSelection.modelName}. Available models for this provider include: ${formatList({ values: providerModels })}.`);
221
+ }
222
+ }
223
+ /**
224
+ * Run the full preflight for a session: fetch the catalog and validate the
225
+ * selected model, unless `--skip-model-preflight` was passed. This is the single
226
+ * call the entry point makes before rendering the UI.
227
+ */
228
+ export async function runPxiModelPreflight({ options, fetchImpl = globalThis.fetch, }) {
229
+ if (options.skipModelPreflight) {
230
+ return;
231
+ }
232
+ const data = await fetchPxiModelPreflight({
233
+ config: options.config,
234
+ fetchImpl,
235
+ });
236
+ validatePxiModelSelection({
237
+ data,
238
+ modelSelection: options.modelSelection,
239
+ });
240
+ }
241
+ /**
242
+ * Wrap an error thrown while talking to PXI into a single message that names the
243
+ * model and appends a tailored next step — pointing custom providers at their
244
+ * Phoenix settings and built-in providers at credential configuration or
245
+ * choosing a different model. Used for failures that surface after the preflight
246
+ * has already passed.
247
+ */
248
+ export function formatPxiRuntimeError({ error, modelSelection, }) {
249
+ const message = error instanceof Error ? error.message : String(error);
250
+ const nextAction = modelSelection.providerType === "custom"
251
+ ? "Check the custom provider configuration in Phoenix Settings > AI Providers."
252
+ : `Configure ${modelSelection.provider} credentials in Phoenix Settings > AI Providers, set the required environment variables on the Phoenix server, or choose a different model.`;
253
+ return new Error(`PXI request failed for ${getModelLabel({ modelSelection })}: ${message} ${nextAction}`);
254
+ }
255
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/pxi/preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { AssistantMessageMetadata, PxiMessage } from "./types.js";
2
+ /**
3
+ * Token-usage helpers for the PXI status line.
4
+ *
5
+ * The Phoenix server attaches {@link AssistantMessageMetadata} usage to each
6
+ * assistant turn. These helpers pull the most recent usage off the transcript
7
+ * and format it for the bottom-right status line, mirroring how the web UI's
8
+ * `ChatSessionUsage` surfaces the latest token count plus any cache activity so
9
+ * the user can gauge how much of the context window is in play.
10
+ */
11
+ /** The usage metadata reported for a single assistant turn. */
12
+ export type PxiUsage = NonNullable<AssistantMessageMetadata["usage"]>;
13
+ /**
14
+ * Return the usage reported by the most recent assistant message that carries
15
+ * any, scanning newest-first. Returns `null` when no assistant turn reported
16
+ * usage (tracing/usage reporting can be disabled server-side).
17
+ */
18
+ export declare function getLatestAssistantUsage(messages: PxiMessage[]): PxiUsage | null;
19
+ /** Format a token count with thousands separators (e.g. `12,345`). */
20
+ export declare function formatTokenCount(value: number): string;
21
+ /**
22
+ * Build the cache-activity portion of the status line from a turn's prompt
23
+ * details, matching the web UI: always show cache reads, and only show cache
24
+ * writes when non-zero (OpenAI never reports them). Returns `null` when there
25
+ * is no cache activity to surface.
26
+ */
27
+ export declare function formatCacheSummary(promptDetails: PxiUsage["promptDetails"]): string | null;
28
+ /**
29
+ * Compose the full bottom-right status line for a turn's usage — the headline
30
+ * total token count, optionally preceded by a cache-activity summary. Returns
31
+ * `null` when there is no usage to show, so the caller can omit the line
32
+ * entirely.
33
+ */
34
+ export declare function formatTokenUsageLine(usage: PxiUsage | null): string | null;
35
+ //# sourceMappingURL=tokenUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenUsage.d.ts","sourceRoot":"","sources":["../../src/pxi/tokenUsage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEpE;;;;;;;;GAQG;AAEH,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC;AAEtE;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,UAAU,EAAE,GACrB,QAAQ,GAAG,IAAI,CAYjB;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,QAAQ,CAAC,eAAe,CAAC,GACvC,MAAM,GAAG,IAAI,CAcf;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAW1E"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Return the usage reported by the most recent assistant message that carries
3
+ * any, scanning newest-first. Returns `null` when no assistant turn reported
4
+ * usage (tracing/usage reporting can be disabled server-side).
5
+ */
6
+ export function getLatestAssistantUsage(messages) {
7
+ for (let index = messages.length - 1; index >= 0; index--) {
8
+ const message = messages[index];
9
+ if (message?.role !== "assistant") {
10
+ continue;
11
+ }
12
+ const usage = message.metadata?.usage;
13
+ if (usage != null) {
14
+ return usage;
15
+ }
16
+ }
17
+ return null;
18
+ }
19
+ /** Format a token count with thousands separators (e.g. `12,345`). */
20
+ export function formatTokenCount(value) {
21
+ return value.toLocaleString("en-US");
22
+ }
23
+ /**
24
+ * Build the cache-activity portion of the status line from a turn's prompt
25
+ * details, matching the web UI: always show cache reads, and only show cache
26
+ * writes when non-zero (OpenAI never reports them). Returns `null` when there
27
+ * is no cache activity to surface.
28
+ */
29
+ export function formatCacheSummary(promptDetails) {
30
+ if (!promptDetails) {
31
+ return null;
32
+ }
33
+ const cacheRead = promptDetails.cacheRead ?? 0;
34
+ const cacheWrite = promptDetails.cacheWrite ?? 0;
35
+ if (cacheRead <= 0 && cacheWrite <= 0) {
36
+ return null;
37
+ }
38
+ const parts = [`cache read ${formatTokenCount(cacheRead)}`];
39
+ if (cacheWrite > 0) {
40
+ parts.push(`cache write ${formatTokenCount(cacheWrite)}`);
41
+ }
42
+ return parts.join(" / ");
43
+ }
44
+ /**
45
+ * Compose the full bottom-right status line for a turn's usage — the headline
46
+ * total token count, optionally preceded by a cache-activity summary. Returns
47
+ * `null` when there is no usage to show, so the caller can omit the line
48
+ * entirely.
49
+ */
50
+ export function formatTokenUsageLine(usage) {
51
+ if (!usage) {
52
+ return null;
53
+ }
54
+ const segments = [];
55
+ const cacheSummary = formatCacheSummary(usage.promptDetails);
56
+ if (cacheSummary) {
57
+ segments.push(cacheSummary);
58
+ }
59
+ segments.push(`${formatTokenCount(usage.tokens.total)} tokens`);
60
+ return segments.join(" · ");
61
+ }
62
+ //# sourceMappingURL=tokenUsage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenUsage.js","sourceRoot":"","sources":["../../src/pxi/tokenUsage.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAAsB;IAEtB,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,OAAO,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;YAClC,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC;QACtC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAwC;IAExC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,IAAI,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,IAAI,CAAC,CAAC;IACjD,IAAI,SAAS,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,cAAc,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC5D,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,eAAe,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAsB;IACzD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC7D,IAAI,YAAY,EAAE,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9B,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { UIDataTypes, UIMessagePart, UITools } from "ai";
2
+ import type { PxiMessage } from "./types.js";
3
+ /**
4
+ * Distills the AI SDK's tool-call message parts into a small, display-ready
5
+ * {@link ToolProgress} shape the UI can render directly. The SDK models a tool
6
+ * call as a sequence of parts moving through lifecycle states; this module reads
7
+ * the current state and produces a human-readable status line plus an optional
8
+ * one-line summary of the tool's input or output.
9
+ */
10
+ /** Lifecycle state of a single tool call, mirroring the AI SDK's part states. */
11
+ export type ToolProgressState = "input-streaming" | "input-available" | "approval-requested" | "approval-responded" | "output-available" | "output-error" | "output-denied";
12
+ /** A display-ready summary of one tool call's current progress. */
13
+ export type ToolProgress = {
14
+ toolCallId: string;
15
+ toolName: string;
16
+ state: ToolProgressState;
17
+ statusText: string;
18
+ errorText?: string;
19
+ };
20
+ /**
21
+ * Collect the progress of every tool call across a list of messages, in order,
22
+ * skipping non-tool parts.
23
+ */
24
+ export declare function getToolProgressFromMessages(messages: readonly PxiMessage[]): ToolProgress[];
25
+ /**
26
+ * Convert a single message part into a {@link ToolProgress}, or `null` if the
27
+ * part isn't a tool call. This is the core mapping that derives the tool name,
28
+ * status label, detail summary, and any error text from the raw SDK part.
29
+ */
30
+ export declare function getToolProgressFromPart({ part, }: {
31
+ part: UIMessagePart<UIDataTypes, UITools>;
32
+ }): ToolProgress | null;
33
+ /** Concatenate the text of all text parts in a message, ignoring tool parts. */
34
+ export declare function getMessageText({ message }: {
35
+ message: PxiMessage;
36
+ }): string;
37
+ //# sourceMappingURL=toolProgress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolProgress.d.ts","sourceRoot":"","sources":["../../src/pxi/toolProgress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;;GAMG;AAEH,iFAAiF;AACjF,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,iBAAiB,GACjB,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,cAAc,GACd,eAAe,CAAC;AAEpB,mEAAmE;AACnE,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAoDF;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAC9B,YAAY,EAAE,CAOhB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,IAAI,GACL,EAAE;IACD,IAAI,EAAE,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,GAAG,YAAY,GAAG,IAAI,CAatB;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,UAAU,CAAA;CAAE,GAAG,MAAM,CAK3E"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Type guard recognizing the message parts that represent a tool call — both
3
+ * statically-typed (`tool-*`) and dynamic tools — so non-tool parts (like text)
4
+ * are skipped.
5
+ */
6
+ function isPxiToolPart(part) {
7
+ return ("toolCallId" in part &&
8
+ "state" in part &&
9
+ (part.type === "dynamic-tool" || part.type.startsWith("tool-")));
10
+ }
11
+ function getToolName(part) {
12
+ return part.type === "dynamic-tool"
13
+ ? (part.toolName ?? "dynamic-tool")
14
+ : part.type.replace(/^tool-/, "");
15
+ }
16
+ /** Map a lifecycle state to the short human-readable label shown to the user. */
17
+ function getStatusText(state) {
18
+ switch (state) {
19
+ case "input-streaming":
20
+ return "Preparing";
21
+ case "input-available":
22
+ return "Running";
23
+ case "approval-requested":
24
+ return "Awaiting approval";
25
+ case "approval-responded":
26
+ return "Approval recorded";
27
+ case "output-available":
28
+ return "Complete";
29
+ case "output-error":
30
+ return "Failed";
31
+ case "output-denied":
32
+ return "Denied";
33
+ }
34
+ }
35
+ /**
36
+ * Collect the progress of every tool call across a list of messages, in order,
37
+ * skipping non-tool parts.
38
+ */
39
+ export function getToolProgressFromMessages(messages) {
40
+ return messages.flatMap((message) => message.parts.flatMap((part) => {
41
+ const toolProgress = getToolProgressFromPart({ part });
42
+ return toolProgress ? [toolProgress] : [];
43
+ }));
44
+ }
45
+ /**
46
+ * Convert a single message part into a {@link ToolProgress}, or `null` if the
47
+ * part isn't a tool call. This is the core mapping that derives the tool name,
48
+ * status label, detail summary, and any error text from the raw SDK part.
49
+ */
50
+ export function getToolProgressFromPart({ part, }) {
51
+ if (!isPxiToolPart(part)) {
52
+ return null;
53
+ }
54
+ const toolName = getToolName(part);
55
+ const state = part.state;
56
+ return {
57
+ toolCallId: part.toolCallId,
58
+ toolName,
59
+ state,
60
+ statusText: getStatusText(state),
61
+ errorText: "errorText" in part ? part.errorText : undefined,
62
+ };
63
+ }
64
+ /** Concatenate the text of all text parts in a message, ignoring tool parts. */
65
+ export function getMessageText({ message }) {
66
+ return message.parts
67
+ .filter((part) => part.type === "text")
68
+ .map((part) => part.text)
69
+ .join("");
70
+ }
71
+ //# sourceMappingURL=toolProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolProgress.js","sourceRoot":"","sources":["../../src/pxi/toolProgress.ts"],"names":[],"mappings":"AAwCA;;;;GAIG;AACH,SAAS,aAAa,CACpB,IAAyC;IAEzC,OAAO,CACL,YAAY,IAAI,IAAI;QACpB,OAAO,IAAI,IAAI;QACf,CAAC,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAChE,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAiB;IACpC,OAAO,IAAI,CAAC,IAAI,KAAK,cAAc;QACjC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,cAAc,CAAC;QACnC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,iFAAiF;AACjF,SAAS,aAAa,CAAC,KAAwB;IAC7C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,iBAAiB;YACpB,OAAO,WAAW,CAAC;QACrB,KAAK,iBAAiB;YACpB,OAAO,SAAS,CAAC;QACnB,KAAK,oBAAoB;YACvB,OAAO,mBAAmB,CAAC;QAC7B,KAAK,oBAAoB;YACvB,OAAO,mBAAmB,CAAC;QAC7B,KAAK,kBAAkB;YACrB,OAAO,UAAU,CAAC;QACpB,KAAK,cAAc;YACjB,OAAO,QAAQ,CAAC;QAClB,KAAK,eAAe;YAClB,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAA+B;IAE/B,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAClC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7B,MAAM,YAAY,GAAG,uBAAuB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACtC,IAAI,GAGL;IACC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ;QACR,KAAK;QACL,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC;QAChC,SAAS,EAAE,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;KAC5D,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAAC,EAAE,OAAO,EAA2B;IACjE,OAAO,OAAO,CAAC,KAAK;SACjB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;SACtC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACxB,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}