@nextclaw/ncp-react 0.3.3 → 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 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
- export { type NcpConversationSeed, type NcpConversationSeedLoader, type UseHydratedNcpAgentOptions, type UseHydratedNcpAgentResult, type UseNcpAgentResult, useHydratedNcpAgent, useNcpAgent };
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
@@ -224,7 +224,126 @@ function useNcpAgent(sessionId, client) {
224
224
  const manager = useScopedAgentManager(sessionId);
225
225
  return useNcpAgentRuntime({ sessionId, client, manager });
226
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
+ }
227
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,
228
347
  useHydratedNcpAgent,
229
348
  useNcpAgent
230
349
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/ncp-react",
3
- "version": "0.3.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",