@nextclaw/ncp-react 0.3.4 → 0.3.6
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 +12 -3
- package/dist/index.js +90 -30
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NcpAgentConversationSnapshot, NcpMessage, NcpRequestEnvelope, NcpAgentClientEndpoint } from '@nextclaw/ncp';
|
|
1
|
+
import { NcpAgentConversationSnapshot, NcpMessage, NcpRequestEnvelope, NcpAgentClientEndpoint, NcpMessagePart } from '@nextclaw/ncp';
|
|
2
2
|
|
|
3
3
|
type NcpAgentSendInput = string | NcpRequestEnvelope;
|
|
4
4
|
type UseNcpAgentResult = {
|
|
@@ -34,13 +34,17 @@ declare function useNcpAgent(sessionId: string, client: NcpAgentClientEndpoint):
|
|
|
34
34
|
|
|
35
35
|
declare const DEFAULT_NCP_IMAGE_ATTACHMENT_ACCEPT = "image/png,image/jpeg,image/webp,image/gif";
|
|
36
36
|
declare const DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES: readonly ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
37
|
+
declare const DEFAULT_NCP_ATTACHMENT_MAX_BYTES: number;
|
|
37
38
|
declare const DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES: number;
|
|
39
|
+
declare const DEFAULT_NCP_FALLBACK_ATTACHMENT_MIME_TYPE = "application/octet-stream";
|
|
38
40
|
type NcpDraftAttachment = {
|
|
39
41
|
id: string;
|
|
40
42
|
name: string;
|
|
41
43
|
mimeType: string;
|
|
42
|
-
contentBase64: string;
|
|
43
44
|
sizeBytes: number;
|
|
45
|
+
attachmentUri?: string;
|
|
46
|
+
url?: string;
|
|
47
|
+
contentBase64?: string;
|
|
44
48
|
};
|
|
45
49
|
type NcpRejectedAttachment = {
|
|
46
50
|
fileName: string;
|
|
@@ -52,6 +56,9 @@ type ReadNcpDraftAttachmentsOptions = {
|
|
|
52
56
|
acceptedMimeTypes?: readonly string[];
|
|
53
57
|
maxBytes?: number;
|
|
54
58
|
};
|
|
59
|
+
type UploadNcpDraftAttachmentsOptions = ReadNcpDraftAttachmentsOptions & {
|
|
60
|
+
uploadBatch: (files: File[]) => Promise<NcpDraftAttachment[]>;
|
|
61
|
+
};
|
|
55
62
|
type ReadNcpDraftAttachmentsResult = {
|
|
56
63
|
attachments: NcpDraftAttachment[];
|
|
57
64
|
rejected: NcpRejectedAttachment[];
|
|
@@ -61,10 +68,12 @@ declare function buildNcpRequestEnvelope(params: {
|
|
|
61
68
|
sessionId: string;
|
|
62
69
|
text?: string;
|
|
63
70
|
attachments?: readonly NcpDraftAttachment[];
|
|
71
|
+
parts?: readonly NcpMessagePart[];
|
|
64
72
|
metadata?: Record<string, unknown>;
|
|
65
73
|
messageId?: string;
|
|
66
74
|
timestamp?: string;
|
|
67
75
|
}): NcpRequestEnvelope | null;
|
|
68
76
|
declare function readFilesAsNcpDraftAttachments(files: Iterable<File>, options?: ReadNcpDraftAttachmentsOptions): Promise<ReadNcpDraftAttachmentsResult>;
|
|
77
|
+
declare function uploadFilesAsNcpDraftAttachments(files: Iterable<File>, options: UploadNcpDraftAttachmentsOptions): Promise<ReadNcpDraftAttachmentsResult>;
|
|
69
78
|
|
|
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 };
|
|
79
|
+
export { DEFAULT_NCP_ATTACHMENT_MAX_BYTES, DEFAULT_NCP_FALLBACK_ATTACHMENT_MIME_TYPE, 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 UploadNcpDraftAttachmentsOptions, type UseHydratedNcpAgentOptions, type UseHydratedNcpAgentResult, type UseNcpAgentResult, buildNcpImageAttachmentDataUrl, buildNcpRequestEnvelope, readFilesAsNcpDraftAttachments, uploadFilesAsNcpDraftAttachments, useHydratedNcpAgent, useNcpAgent };
|
package/dist/index.js
CHANGED
|
@@ -233,7 +233,9 @@ var DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES = [
|
|
|
233
233
|
"image/webp",
|
|
234
234
|
"image/gif"
|
|
235
235
|
];
|
|
236
|
-
var
|
|
236
|
+
var DEFAULT_NCP_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
|
|
237
|
+
var DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES = DEFAULT_NCP_ATTACHMENT_MAX_BYTES;
|
|
238
|
+
var DEFAULT_NCP_FALLBACK_ATTACHMENT_MIME_TYPE = "application/octet-stream";
|
|
237
239
|
function createAttachmentId() {
|
|
238
240
|
return `ncp-file-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
239
241
|
}
|
|
@@ -255,19 +257,57 @@ function toBase64Content(dataUrl) {
|
|
|
255
257
|
const commaIndex = dataUrl.indexOf(",");
|
|
256
258
|
return commaIndex >= 0 ? dataUrl.slice(commaIndex + 1) : dataUrl;
|
|
257
259
|
}
|
|
260
|
+
function normalizeAttachmentMimeType(file) {
|
|
261
|
+
const mimeType = file.type.trim().toLowerCase();
|
|
262
|
+
return mimeType.length > 0 ? mimeType : DEFAULT_NCP_FALLBACK_ATTACHMENT_MIME_TYPE;
|
|
263
|
+
}
|
|
264
|
+
function validateAttachmentFile(file, options) {
|
|
265
|
+
const acceptedMimeTypes = options.acceptedMimeTypes && options.acceptedMimeTypes.length > 0 ? new Set(options.acceptedMimeTypes.map((mimeType2) => mimeType2.trim().toLowerCase())) : null;
|
|
266
|
+
const maxBytes = options.maxBytes ?? DEFAULT_NCP_ATTACHMENT_MAX_BYTES;
|
|
267
|
+
const mimeType = normalizeAttachmentMimeType(file);
|
|
268
|
+
if (acceptedMimeTypes && !acceptedMimeTypes.has(mimeType)) {
|
|
269
|
+
return {
|
|
270
|
+
ok: false,
|
|
271
|
+
rejected: {
|
|
272
|
+
fileName: file.name,
|
|
273
|
+
mimeType,
|
|
274
|
+
sizeBytes: file.size,
|
|
275
|
+
reason: "unsupported-type"
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
if (file.size > maxBytes) {
|
|
280
|
+
return {
|
|
281
|
+
ok: false,
|
|
282
|
+
rejected: {
|
|
283
|
+
fileName: file.name,
|
|
284
|
+
mimeType,
|
|
285
|
+
sizeBytes: file.size,
|
|
286
|
+
reason: "too-large"
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
return { ok: true, mimeType };
|
|
291
|
+
}
|
|
258
292
|
function buildNcpImageAttachmentDataUrl(attachment) {
|
|
293
|
+
if (attachment.url?.trim()) {
|
|
294
|
+
return attachment.url.trim();
|
|
295
|
+
}
|
|
296
|
+
if (!attachment.contentBase64?.trim()) {
|
|
297
|
+
throw new Error(`Attachment ${attachment.name} does not have image content.`);
|
|
298
|
+
}
|
|
259
299
|
return `data:${attachment.mimeType};base64,${attachment.contentBase64}`;
|
|
260
300
|
}
|
|
261
301
|
function buildNcpRequestEnvelope(params) {
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
...trimmedText ? [{ type: "text", text: trimmedText }] : [],
|
|
266
|
-
...attachments.map((attachment) => ({
|
|
302
|
+
const parts = params.parts && params.parts.length > 0 ? params.parts.map((part) => structuredClone(part)) : [
|
|
303
|
+
...params.text?.trim() ?? "" ? [{ type: "text", text: params.text.trim() }] : [],
|
|
304
|
+
...(params.attachments ?? []).map((attachment) => ({
|
|
267
305
|
type: "file",
|
|
268
306
|
name: attachment.name,
|
|
269
307
|
mimeType: attachment.mimeType,
|
|
270
|
-
|
|
308
|
+
...attachment.attachmentUri?.trim() ? { attachmentUri: attachment.attachmentUri.trim() } : {},
|
|
309
|
+
...attachment.url?.trim() ? { url: attachment.url.trim() } : {},
|
|
310
|
+
...attachment.contentBase64?.trim() ? { contentBase64: attachment.contentBase64.trim() } : {},
|
|
271
311
|
sizeBytes: attachment.sizeBytes
|
|
272
312
|
}))
|
|
273
313
|
];
|
|
@@ -291,30 +331,12 @@ function buildNcpRequestEnvelope(params) {
|
|
|
291
331
|
};
|
|
292
332
|
}
|
|
293
333
|
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
334
|
const attachments = [];
|
|
299
335
|
const rejected = [];
|
|
300
336
|
for (const file of files) {
|
|
301
|
-
const
|
|
302
|
-
if (!
|
|
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
|
-
});
|
|
337
|
+
const validation = validateAttachmentFile(file, options);
|
|
338
|
+
if (!validation.ok) {
|
|
339
|
+
rejected.push(validation.rejected);
|
|
318
340
|
continue;
|
|
319
341
|
}
|
|
320
342
|
try {
|
|
@@ -322,14 +344,14 @@ async function readFilesAsNcpDraftAttachments(files, options = {}) {
|
|
|
322
344
|
attachments.push({
|
|
323
345
|
id: createAttachmentId(),
|
|
324
346
|
name: file.name,
|
|
325
|
-
mimeType,
|
|
347
|
+
mimeType: validation.mimeType,
|
|
326
348
|
contentBase64: toBase64Content(dataUrl),
|
|
327
349
|
sizeBytes: file.size
|
|
328
350
|
});
|
|
329
351
|
} catch {
|
|
330
352
|
rejected.push({
|
|
331
353
|
fileName: file.name,
|
|
332
|
-
mimeType,
|
|
354
|
+
mimeType: validation.mimeType,
|
|
333
355
|
sizeBytes: file.size,
|
|
334
356
|
reason: "read-failed"
|
|
335
357
|
});
|
|
@@ -337,13 +359,51 @@ async function readFilesAsNcpDraftAttachments(files, options = {}) {
|
|
|
337
359
|
}
|
|
338
360
|
return { attachments, rejected };
|
|
339
361
|
}
|
|
362
|
+
async function uploadFilesAsNcpDraftAttachments(files, options) {
|
|
363
|
+
const validFiles = [];
|
|
364
|
+
const rejected = [];
|
|
365
|
+
for (const file of files) {
|
|
366
|
+
const validation = validateAttachmentFile(file, options);
|
|
367
|
+
if (!validation.ok) {
|
|
368
|
+
rejected.push(validation.rejected);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
validFiles.push(file);
|
|
372
|
+
}
|
|
373
|
+
if (validFiles.length === 0) {
|
|
374
|
+
return { attachments: [], rejected };
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const attachments = await options.uploadBatch(validFiles);
|
|
378
|
+
return {
|
|
379
|
+
attachments,
|
|
380
|
+
rejected
|
|
381
|
+
};
|
|
382
|
+
} catch {
|
|
383
|
+
rejected.push(
|
|
384
|
+
...validFiles.map((file) => ({
|
|
385
|
+
fileName: file.name,
|
|
386
|
+
mimeType: normalizeAttachmentMimeType(file),
|
|
387
|
+
sizeBytes: file.size,
|
|
388
|
+
reason: "read-failed"
|
|
389
|
+
}))
|
|
390
|
+
);
|
|
391
|
+
return {
|
|
392
|
+
attachments: [],
|
|
393
|
+
rejected
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
}
|
|
340
397
|
export {
|
|
398
|
+
DEFAULT_NCP_ATTACHMENT_MAX_BYTES,
|
|
399
|
+
DEFAULT_NCP_FALLBACK_ATTACHMENT_MIME_TYPE,
|
|
341
400
|
DEFAULT_NCP_IMAGE_ATTACHMENT_ACCEPT,
|
|
342
401
|
DEFAULT_NCP_IMAGE_ATTACHMENT_MAX_BYTES,
|
|
343
402
|
DEFAULT_NCP_IMAGE_ATTACHMENT_MIME_TYPES,
|
|
344
403
|
buildNcpImageAttachmentDataUrl,
|
|
345
404
|
buildNcpRequestEnvelope,
|
|
346
405
|
readFilesAsNcpDraftAttachments,
|
|
406
|
+
uploadFilesAsNcpDraftAttachments,
|
|
347
407
|
useHydratedNcpAgent,
|
|
348
408
|
useNcpAgent
|
|
349
409
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ncp-react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
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
|
|
18
|
+
"@nextclaw/ncp-toolkit": "0.4.3",
|
|
19
|
+
"@nextclaw/ncp": "0.3.3"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": "^18.0.0 || ^19.0.0"
|