@nextclaw/ncp-react 0.3.2 → 0.3.4
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/dist/index.d.ts +36 -1
- package/dist/index.js +119 -11
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -32,4 +32,39 @@ declare function useHydratedNcpAgent({ sessionId, client, loadSeed, autoResumeRu
|
|
|
32
32
|
|
|
33
33
|
declare function useNcpAgent(sessionId: string, client: NcpAgentClientEndpoint): UseNcpAgentResult;
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
declare const DEFAULT_NCP_IMAGE_ATTACHMENT_ACCEPT = "image/png,image/jpeg,image/webp,image/gif";
|
|
36
|
+
declare const DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES: readonly ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
37
|
+
declare const DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES: number;
|
|
38
|
+
type NcpDraftAttachment = {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
mimeType: string;
|
|
42
|
+
contentBase64: string;
|
|
43
|
+
sizeBytes: number;
|
|
44
|
+
};
|
|
45
|
+
type NcpRejectedAttachment = {
|
|
46
|
+
fileName: string;
|
|
47
|
+
mimeType: string;
|
|
48
|
+
sizeBytes: number;
|
|
49
|
+
reason: "unsupported-type" | "too-large" | "read-failed";
|
|
50
|
+
};
|
|
51
|
+
type ReadNcpDraftAttachmentsOptions = {
|
|
52
|
+
acceptedMimeTypes?: readonly string[];
|
|
53
|
+
maxBytes?: number;
|
|
54
|
+
};
|
|
55
|
+
type ReadNcpDraftAttachmentsResult = {
|
|
56
|
+
attachments: NcpDraftAttachment[];
|
|
57
|
+
rejected: NcpRejectedAttachment[];
|
|
58
|
+
};
|
|
59
|
+
declare function buildNcpImageAttachmentDataUrl(attachment: NcpDraftAttachment): string;
|
|
60
|
+
declare function buildNcpRequestEnvelope(params: {
|
|
61
|
+
sessionId: string;
|
|
62
|
+
text?: string;
|
|
63
|
+
attachments?: readonly NcpDraftAttachment[];
|
|
64
|
+
metadata?: Record<string, unknown>;
|
|
65
|
+
messageId?: string;
|
|
66
|
+
timestamp?: string;
|
|
67
|
+
}): NcpRequestEnvelope | null;
|
|
68
|
+
declare function readFilesAsNcpDraftAttachments(files: Iterable<File>, options?: ReadNcpDraftAttachmentsOptions): Promise<ReadNcpDraftAttachmentsResult>;
|
|
69
|
+
|
|
70
|
+
export { DEFAULT_NCP_IMAGE_ATTACHMENT_ACCEPT, DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES, DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES, type NcpConversationSeed, type NcpConversationSeedLoader, type NcpDraftAttachment, type NcpRejectedAttachment, type ReadNcpDraftAttachmentsOptions, type ReadNcpDraftAttachmentsResult, type UseHydratedNcpAgentOptions, type UseHydratedNcpAgentResult, type UseNcpAgentResult, buildNcpImageAttachmentDataUrl, buildNcpRequestEnvelope, readFilesAsNcpDraftAttachments, useHydratedNcpAgent, useNcpAgent };
|
package/dist/index.js
CHANGED
|
@@ -55,13 +55,6 @@ function normalizeSendEnvelope(input, sessionId) {
|
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
-
function toHydrationPayload(sessionId, snapshot) {
|
|
59
|
-
return {
|
|
60
|
-
sessionId,
|
|
61
|
-
messages: snapshot.messages,
|
|
62
|
-
activeRun: snapshot.activeRun
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
58
|
function useScopedAgentManager(sessionId) {
|
|
66
59
|
const managerRef = useRef();
|
|
67
60
|
if (!managerRef.current || managerRef.current.sessionId !== sessionId) {
|
|
@@ -110,7 +103,6 @@ function useNcpAgentRuntime({
|
|
|
110
103
|
return;
|
|
111
104
|
}
|
|
112
105
|
setIsSending(true);
|
|
113
|
-
const previousSnapshot = manager.getSnapshot();
|
|
114
106
|
await manager.dispatch({
|
|
115
107
|
type: NcpEventType.MessageSent,
|
|
116
108
|
payload: {
|
|
@@ -121,9 +113,6 @@ function useNcpAgentRuntime({
|
|
|
121
113
|
});
|
|
122
114
|
try {
|
|
123
115
|
await client.send(envelope);
|
|
124
|
-
} catch (error) {
|
|
125
|
-
manager.hydrate(toHydrationPayload(sessionId, previousSnapshot));
|
|
126
|
-
throw error;
|
|
127
116
|
} finally {
|
|
128
117
|
setIsSending(false);
|
|
129
118
|
}
|
|
@@ -235,7 +224,126 @@ function useNcpAgent(sessionId, client) {
|
|
|
235
224
|
const manager = useScopedAgentManager(sessionId);
|
|
236
225
|
return useNcpAgentRuntime({ sessionId, client, manager });
|
|
237
226
|
}
|
|
227
|
+
|
|
228
|
+
// src/attachments/ncp-attachments.ts
|
|
229
|
+
var DEFAULT_NCP_IMAGE_ATTACHMENT_ACCEPT = "image/png,image/jpeg,image/webp,image/gif";
|
|
230
|
+
var DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES = [
|
|
231
|
+
"image/png",
|
|
232
|
+
"image/jpeg",
|
|
233
|
+
"image/webp",
|
|
234
|
+
"image/gif"
|
|
235
|
+
];
|
|
236
|
+
var DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
|
|
237
|
+
function createAttachmentId() {
|
|
238
|
+
return `ncp-file-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
239
|
+
}
|
|
240
|
+
function readFileAsDataUrl(file) {
|
|
241
|
+
return new Promise((resolve, reject) => {
|
|
242
|
+
const reader = new FileReader();
|
|
243
|
+
reader.onerror = () => reject(reader.error ?? new Error(`Failed to read ${file.name}`));
|
|
244
|
+
reader.onload = () => {
|
|
245
|
+
if (typeof reader.result !== "string") {
|
|
246
|
+
reject(new Error(`Unexpected FileReader result for ${file.name}`));
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
resolve(reader.result);
|
|
250
|
+
};
|
|
251
|
+
reader.readAsDataURL(file);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
function toBase64Content(dataUrl) {
|
|
255
|
+
const commaIndex = dataUrl.indexOf(",");
|
|
256
|
+
return commaIndex >= 0 ? dataUrl.slice(commaIndex + 1) : dataUrl;
|
|
257
|
+
}
|
|
258
|
+
function buildNcpImageAttachmentDataUrl(attachment) {
|
|
259
|
+
return `data:${attachment.mimeType};base64,${attachment.contentBase64}`;
|
|
260
|
+
}
|
|
261
|
+
function buildNcpRequestEnvelope(params) {
|
|
262
|
+
const trimmedText = params.text?.trim() ?? "";
|
|
263
|
+
const attachments = params.attachments ?? [];
|
|
264
|
+
const parts = [
|
|
265
|
+
...trimmedText ? [{ type: "text", text: trimmedText }] : [],
|
|
266
|
+
...attachments.map((attachment) => ({
|
|
267
|
+
type: "file",
|
|
268
|
+
name: attachment.name,
|
|
269
|
+
mimeType: attachment.mimeType,
|
|
270
|
+
contentBase64: attachment.contentBase64,
|
|
271
|
+
sizeBytes: attachment.sizeBytes
|
|
272
|
+
}))
|
|
273
|
+
];
|
|
274
|
+
if (parts.length === 0) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
const timestamp = params.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
278
|
+
const messageId = params.messageId ?? `user-${Date.now().toString(36)}`;
|
|
279
|
+
return {
|
|
280
|
+
sessionId: params.sessionId,
|
|
281
|
+
message: {
|
|
282
|
+
id: messageId,
|
|
283
|
+
sessionId: params.sessionId,
|
|
284
|
+
role: "user",
|
|
285
|
+
status: "final",
|
|
286
|
+
parts,
|
|
287
|
+
timestamp,
|
|
288
|
+
...params.metadata ? { metadata: params.metadata } : {}
|
|
289
|
+
},
|
|
290
|
+
...params.metadata ? { metadata: params.metadata } : {}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
async function readFilesAsNcpDraftAttachments(files, options = {}) {
|
|
294
|
+
const acceptedMimeTypes = new Set(
|
|
295
|
+
options.acceptedMimeTypes ?? DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES
|
|
296
|
+
);
|
|
297
|
+
const maxBytes = options.maxBytes ?? DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES;
|
|
298
|
+
const attachments = [];
|
|
299
|
+
const rejected = [];
|
|
300
|
+
for (const file of files) {
|
|
301
|
+
const mimeType = file.type.trim().toLowerCase();
|
|
302
|
+
if (!acceptedMimeTypes.has(mimeType)) {
|
|
303
|
+
rejected.push({
|
|
304
|
+
fileName: file.name,
|
|
305
|
+
mimeType,
|
|
306
|
+
sizeBytes: file.size,
|
|
307
|
+
reason: "unsupported-type"
|
|
308
|
+
});
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (file.size > maxBytes) {
|
|
312
|
+
rejected.push({
|
|
313
|
+
fileName: file.name,
|
|
314
|
+
mimeType,
|
|
315
|
+
sizeBytes: file.size,
|
|
316
|
+
reason: "too-large"
|
|
317
|
+
});
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
const dataUrl = await readFileAsDataUrl(file);
|
|
322
|
+
attachments.push({
|
|
323
|
+
id: createAttachmentId(),
|
|
324
|
+
name: file.name,
|
|
325
|
+
mimeType,
|
|
326
|
+
contentBase64: toBase64Content(dataUrl),
|
|
327
|
+
sizeBytes: file.size
|
|
328
|
+
});
|
|
329
|
+
} catch {
|
|
330
|
+
rejected.push({
|
|
331
|
+
fileName: file.name,
|
|
332
|
+
mimeType,
|
|
333
|
+
sizeBytes: file.size,
|
|
334
|
+
reason: "read-failed"
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return { attachments, rejected };
|
|
339
|
+
}
|
|
238
340
|
export {
|
|
341
|
+
DEFAULT_NCP_IMAGE_ATTACHMENT_ACCEPT,
|
|
342
|
+
DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES,
|
|
343
|
+
DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES,
|
|
344
|
+
buildNcpImageAttachmentDataUrl,
|
|
345
|
+
buildNcpRequestEnvelope,
|
|
346
|
+
readFilesAsNcpDraftAttachments,
|
|
239
347
|
useHydratedNcpAgent,
|
|
240
348
|
useNcpAgent
|
|
241
349
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ncp-react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "React bindings for building NCP-based agent applications.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@nextclaw/ncp": "0.3.
|
|
19
|
-
"@nextclaw/ncp-toolkit": "0.4.
|
|
18
|
+
"@nextclaw/ncp": "0.3.2",
|
|
19
|
+
"@nextclaw/ncp-toolkit": "0.4.2"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": "^18.0.0 || ^19.0.0"
|