@magemetrics/core 0.12.2 → 0.14.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/README.md +220 -0
- package/dist/index.d.ts +1670 -137
- package/dist/index.js +1796 -430
- package/package.json +9 -9
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# @magemetrics/core
|
|
2
|
+
|
|
3
|
+
Headless Magemetrics client for custom integrations.
|
|
4
|
+
|
|
5
|
+
`@magemetrics/core` is designed for customers who want to build their own UI while reusing Magemetrics authentication, flow APIs, chat transport, file uploads, and typed domain models.
|
|
6
|
+
|
|
7
|
+
## What You Need
|
|
8
|
+
|
|
9
|
+
- `@magemetrics/core` for auth, flow APIs, chat transport, files, and types
|
|
10
|
+
- The AI SDK for chat state and streaming
|
|
11
|
+
- Your own UI layer in React, Svelte, Vue, or another framework
|
|
12
|
+
|
|
13
|
+
## Create A Client
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { MageMetricsClient } from "@magemetrics/core";
|
|
17
|
+
|
|
18
|
+
export const client = new MageMetricsClient({
|
|
19
|
+
apiUrl: "https://your-magemetrics-instance.com",
|
|
20
|
+
apiKey: "mm_live_...",
|
|
21
|
+
externalJwt: "customer-session-jwt",
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Start Or Resume A Flow
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const { flowId } = await client.api.createFlow({
|
|
29
|
+
query: "Show me revenue by country for the last 90 days",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const existingMessages = await client.api.getChatMessages(flowId);
|
|
33
|
+
const flow = await client.api.getFlow(flowId);
|
|
34
|
+
const reports = await client.api.getFlowDataReports(flowId);
|
|
35
|
+
const visualizations = await client.api.getFlowVisualizations(flowId);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Connect The AI SDK
|
|
39
|
+
|
|
40
|
+
The simplest integration is to reuse the Magemetrics transport with an AI SDK `Chat` instance and hydrate it with stored history.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { Chat, lastAssistantMessageIsCompleteWithToolCalls } from "@ai-sdk/react";
|
|
44
|
+
import { useChat } from "@ai-sdk/react";
|
|
45
|
+
import type { MMChatUIMessage } from "@magemetrics/core";
|
|
46
|
+
import { client } from "./client";
|
|
47
|
+
|
|
48
|
+
const chat = new Chat<MMChatUIMessage>({
|
|
49
|
+
id: `chat-${flowId}`,
|
|
50
|
+
transport: client.api.getChatTransport(flowId),
|
|
51
|
+
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
chat.setMessages(await client.api.getChatMessages(flowId));
|
|
55
|
+
|
|
56
|
+
const state = useChat({
|
|
57
|
+
chat,
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls` is important to support interactive tools such as `askUserQuestion`.
|
|
62
|
+
|
|
63
|
+
## Bootstrap The First Assistant Turn
|
|
64
|
+
|
|
65
|
+
`createFlow(...)` persists the first user message and returns `flowId`. The first assistant response starts when the chat stream is resumed.
|
|
66
|
+
|
|
67
|
+
After hydrating message history, if there is only one user message, trigger a one-time `regenerate()`:
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { useEffect, useRef } from "react";
|
|
71
|
+
import { hasOnlyInitialUserMessage } from "@magemetrics/core";
|
|
72
|
+
|
|
73
|
+
const hasStartedRef = useRef(false);
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (
|
|
77
|
+
status === "ready" &&
|
|
78
|
+
hasOnlyInitialUserMessage(messages) &&
|
|
79
|
+
!hasStartedRef.current
|
|
80
|
+
) {
|
|
81
|
+
hasStartedRef.current = true;
|
|
82
|
+
void regenerate();
|
|
83
|
+
}
|
|
84
|
+
}, [messages, status, regenerate]);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Handle Frontend Tools
|
|
88
|
+
|
|
89
|
+
Magemetrics can stream tool parts alongside assistant text. The main frontend-executed tool today is `askUserQuestion`.
|
|
90
|
+
|
|
91
|
+
**Important:** You must handle `tool-askUserQuestion` and always send a tool output.
|
|
92
|
+
If your UI never calls `chat.addToolOutput(...)`, the conversation can stay blocked waiting for tool completion.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import {
|
|
96
|
+
ASK_USER_QUESTION,
|
|
97
|
+
type AskUserQuestionInput,
|
|
98
|
+
type MMChatUIMessagePart,
|
|
99
|
+
} from "@magemetrics/core";
|
|
100
|
+
|
|
101
|
+
const renderPart = (part: MMChatUIMessagePart) => {
|
|
102
|
+
if (part.type !== `tool-${ASK_USER_QUESTION}`) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (part.state === "input-available") {
|
|
107
|
+
const input: AskUserQuestionInput = part.input;
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
questions: input.questions,
|
|
111
|
+
submit: async (answers: Record<string, string>) => {
|
|
112
|
+
await chat.addToolOutput({
|
|
113
|
+
tool: ASK_USER_QUESTION,
|
|
114
|
+
toolCallId: part.toolCallId,
|
|
115
|
+
output: {
|
|
116
|
+
tool: ASK_USER_QUESTION,
|
|
117
|
+
result: { status: "success", answers },
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
cancel: async () => {
|
|
122
|
+
await chat.addToolOutput({
|
|
123
|
+
tool: ASK_USER_QUESTION,
|
|
124
|
+
toolCallId: part.toolCallId,
|
|
125
|
+
output: {
|
|
126
|
+
tool: ASK_USER_QUESTION,
|
|
127
|
+
result: {
|
|
128
|
+
status: "error",
|
|
129
|
+
message: "User dismissed the question form.",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return null;
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The transport marks tool submissions correctly and the AI SDK can resume the stream automatically after `chat.addToolOutput(...)`.
|
|
142
|
+
|
|
143
|
+
Required behavior for frontend tools:
|
|
144
|
+
|
|
145
|
+
1. Detect `tool-askUserQuestion` parts.
|
|
146
|
+
2. Render the question UI for `state === "input-available"`.
|
|
147
|
+
3. Call `chat.addToolOutput(...)` for every tool call (submit and cancel paths).
|
|
148
|
+
4. Keep `sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls` enabled so the stream resumes automatically.
|
|
149
|
+
|
|
150
|
+
## Read Custom Data Parts
|
|
151
|
+
|
|
152
|
+
Messages can include custom streamed data parts in addition to text and tool calls.
|
|
153
|
+
|
|
154
|
+
- `quick-actions`: suggested follow-up prompts
|
|
155
|
+
- `report-status`: inline report generation status
|
|
156
|
+
- `node-added`: a new canvas node created during the run
|
|
157
|
+
|
|
158
|
+
The exported `MMChatUIMessage`, `MMChatUIMessagePart`, `QuickAction`, and `SignalWithReportId` types are designed for this.
|
|
159
|
+
|
|
160
|
+
## Send Files
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import {
|
|
164
|
+
CHAT_FILE_ACCEPT,
|
|
165
|
+
toUploadedFileRefUrl,
|
|
166
|
+
type UploadedFile,
|
|
167
|
+
} from "@magemetrics/core";
|
|
168
|
+
|
|
169
|
+
const uploaded = await client.api.uploadFile(file);
|
|
170
|
+
|
|
171
|
+
const filePart = {
|
|
172
|
+
type: "file" as const,
|
|
173
|
+
filename: uploaded.filename,
|
|
174
|
+
mediaType: uploaded.mediaType,
|
|
175
|
+
url: toUploadedFileRefUrl(uploaded.uploadedFileId),
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
For the first user request, attach uploaded files during flow creation:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const uploaded = await client.api.uploadFile(file);
|
|
183
|
+
|
|
184
|
+
const { flowId } = await client.api.createFlow({
|
|
185
|
+
query: "Summarize this PDF",
|
|
186
|
+
uploadedFileIds: [uploaded.uploadedFileId],
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
For later requests in an existing conversation, include the file part in the message you send through the AI SDK.
|
|
191
|
+
|
|
192
|
+
## Typed Domain Data
|
|
193
|
+
|
|
194
|
+
`@magemetrics/core` also exports the main response types you need to build custom views:
|
|
195
|
+
|
|
196
|
+
- `FrontendFlow`
|
|
197
|
+
- `FrontendRecentFlows`
|
|
198
|
+
- `FrontendReport`
|
|
199
|
+
- `FrontendReportColumns`
|
|
200
|
+
- `FrontendReportExplainability`
|
|
201
|
+
- `FrontendVisualization`
|
|
202
|
+
- `FrontendVisualizationWithData`
|
|
203
|
+
- `PromptStarter`
|
|
204
|
+
- `FrontendRecommendations`
|
|
205
|
+
|
|
206
|
+
Use `isFrontendV2VisualizationWithData(...)` if you need to branch on visualization shape at runtime (you will never need to deal with older V1 versions).
|
|
207
|
+
|
|
208
|
+
## Utilities
|
|
209
|
+
|
|
210
|
+
- `client.api.getPromptStarters(input?)`
|
|
211
|
+
- `client.api.getRecommendations(count)`
|
|
212
|
+
- `toSearchParams(...)` for report filtering and sorting
|
|
213
|
+
- `getMessageTextContent(...)` to extract plain text from an AI SDK message
|
|
214
|
+
- `hasOnlyInitialUserMessage(...)` to detect when a newly created flow still needs its first assistant turn
|
|
215
|
+
|
|
216
|
+
## Notes
|
|
217
|
+
|
|
218
|
+
- `client.api.getChatTransport(flowId)` assumes the AI SDK stream protocol used by Magemetrics chat.
|
|
219
|
+
- `client.api.getChatMessages(flowId)` returns the redacted frontend-safe message history.
|
|
220
|
+
- Tool outputs exposed through chat are already redacted for frontend use. Use the exported `Redacted*` response types when rendering them.
|