strapi-content-embeddings 0.2.0 → 0.2.2

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 (38) hide show
  1. package/dist/_chunks/en-B4KWt_jN.js +0 -1
  2. package/dist/_chunks/en-Byx4XI2L.mjs +0 -1
  3. package/dist/admin/index.js +754 -4
  4. package/dist/admin/index.mjs +751 -4
  5. package/dist/server/index.js +234 -231
  6. package/dist/server/index.mjs +234 -231
  7. package/dist/server/src/index.d.ts +5 -0
  8. package/dist/server/src/mcp/schemas/index.d.ts +3 -0
  9. package/dist/server/src/mcp/tools/create-embedding.d.ts +3 -4
  10. package/dist/server/src/mcp/tools/get-embedding.d.ts +3 -3
  11. package/dist/server/src/mcp/tools/index.d.ts +1 -0
  12. package/dist/server/src/mcp/tools/list-embeddings.d.ts +3 -3
  13. package/dist/server/src/mcp/tools/rag-query.d.ts +3 -3
  14. package/dist/server/src/mcp/tools/semantic-search.d.ts +3 -3
  15. package/dist/server/src/services/ai-tools.d.ts +13 -0
  16. package/dist/server/src/services/index.d.ts +5 -0
  17. package/dist/server/src/tools/create-embedding.d.ts +9 -0
  18. package/dist/server/src/tools/get-embedding.d.ts +8 -0
  19. package/dist/server/src/tools/index.d.ts +14 -0
  20. package/dist/server/src/tools/list-embeddings.d.ts +8 -0
  21. package/dist/server/src/tools/rag-query.d.ts +8 -0
  22. package/dist/server/src/tools/semantic-search.d.ts +8 -0
  23. package/dist/server/src/tools/types.d.ts +14 -0
  24. package/package.json +3 -3
  25. package/dist/_chunks/App-ByRBbkZn.js +0 -1600
  26. package/dist/_chunks/App-ByRBbkZn.js.map +0 -1
  27. package/dist/_chunks/App-MjsTrWRS.mjs +0 -1596
  28. package/dist/_chunks/App-MjsTrWRS.mjs.map +0 -1
  29. package/dist/_chunks/en-B4KWt_jN.js.map +0 -1
  30. package/dist/_chunks/en-Byx4XI2L.mjs.map +0 -1
  31. package/dist/_chunks/index-TWbcT-zJ.js +0 -785
  32. package/dist/_chunks/index-TWbcT-zJ.js.map +0 -1
  33. package/dist/_chunks/index-ifqYByO5.mjs +0 -783
  34. package/dist/_chunks/index-ifqYByO5.mjs.map +0 -1
  35. package/dist/admin/index.js.map +0 -1
  36. package/dist/admin/index.mjs.map +0 -1
  37. package/dist/server/index.js.map +0 -1
  38. package/dist/server/index.mjs.map +0 -1
@@ -441,7 +441,8 @@ const GetEmbeddingSchema = zod.z.object({
441
441
  const CreateEmbeddingSchema = zod.z.object({
442
442
  title: zod.z.string().min(1, "Title is required"),
443
443
  content: zod.z.string().min(1, "Content is required"),
444
- metadata: zod.z.record(zod.z.any()).optional()
444
+ metadata: zod.z.record(zod.z.any()).optional(),
445
+ autoChunk: zod.z.boolean().optional().describe("Automatically split large content into chunks")
445
446
  });
446
447
  const ToolSchemas = {
447
448
  semantic_search: SemanticSearchSchema,
@@ -463,28 +464,12 @@ function validateToolInput(toolName, input) {
463
464
  return result.data;
464
465
  }
465
466
  const semanticSearchTool = {
466
- name: "semantic_search",
467
- description: 'TRIGGER: Use when user types "/rag" or asks to search embeddings/content. Search for semantically similar content using vector embeddings. Returns the most relevant documents matching your query based on meaning, not just keywords.',
468
- inputSchema: {
469
- type: "object",
470
- properties: {
471
- query: {
472
- type: "string",
473
- description: "The search query text to find similar content"
474
- },
475
- limit: {
476
- type: "number",
477
- description: "Maximum number of results to return (default: 5, max: 20)",
478
- default: 5
479
- }
480
- },
481
- required: ["query"]
482
- }
483
- };
484
- async function handleSemanticSearch(strapi, args) {
485
- const { query, limit = 5 } = args;
486
- const maxLimit = Math.min(limit, 20);
487
- try {
467
+ name: "semanticSearch",
468
+ description: "Search for semantically similar content using vector embeddings. Finds relevant documents by meaning, not just keywords.",
469
+ schema: SemanticSearchSchema,
470
+ execute: async (args, strapi) => {
471
+ const { query, limit = 5 } = args;
472
+ const maxLimit = Math.min(limit, 20);
488
473
  const pluginManager2 = strapi.contentEmbeddingsManager;
489
474
  if (!pluginManager2) {
490
475
  throw new Error("Content embeddings plugin not initialized");
@@ -497,49 +482,49 @@ async function handleSemanticSearch(strapi, args) {
497
482
  score: doc.score || null
498
483
  }));
499
484
  return {
500
- content: [
501
- {
502
- type: "text",
503
- text: JSON.stringify(
504
- {
505
- query,
506
- resultCount: formattedResults.length,
507
- results: formattedResults
508
- },
509
- null,
510
- 2
511
- )
512
- }
513
- ]
485
+ query,
486
+ resultCount: formattedResults.length,
487
+ results: formattedResults
514
488
  };
515
- } catch (error) {
516
- throw new Error(
517
- `Semantic search failed: ${error instanceof Error ? error.message : String(error)}`
518
- );
519
- }
520
- }
521
- const ragQueryTool = {
522
- name: "rag_query",
523
- description: 'TRIGGER: Use when user types "/rag" followed by a question. Ask a question and get an AI-generated answer based on your embedded content. Uses RAG (Retrieval-Augmented Generation) to find relevant documents and generate a contextual response. This is the PRIMARY tool for /rag queries.',
489
+ },
490
+ publicSafe: true
491
+ };
492
+ const semanticSearchMcpTool = {
493
+ name: "semantic_search",
494
+ description: semanticSearchTool.description,
524
495
  inputSchema: {
525
496
  type: "object",
526
497
  properties: {
527
498
  query: {
528
499
  type: "string",
529
- description: "The question or query to answer using embedded content"
500
+ description: "The search query text to find similar content"
530
501
  },
531
- includeSourceDocuments: {
532
- type: "boolean",
533
- description: "Include the source documents used to generate the answer (default: true)",
534
- default: true
502
+ limit: {
503
+ type: "number",
504
+ description: "Maximum number of results to return (default: 5, max: 20)",
505
+ default: 5
535
506
  }
536
507
  },
537
508
  required: ["query"]
538
509
  }
539
510
  };
540
- async function handleRagQuery(strapi, args) {
541
- const { query, includeSourceDocuments = true } = args;
542
- try {
511
+ async function handleSemanticSearch(strapi, args) {
512
+ const result = await semanticSearchTool.execute(args, strapi);
513
+ return {
514
+ content: [
515
+ {
516
+ type: "text",
517
+ text: JSON.stringify(result, null, 2)
518
+ }
519
+ ]
520
+ };
521
+ }
522
+ const ragQueryTool = {
523
+ name: "ragQuery",
524
+ description: "Ask a question and get an AI-generated answer grounded in embedded content. Uses retrieval-augmented generation (RAG) with vector search.",
525
+ schema: RagQuerySchema,
526
+ execute: async (args, strapi) => {
527
+ const { query, includeSourceDocuments = true } = args;
543
528
  const embeddingsService = strapi.plugin("strapi-content-embeddings").service("embeddings");
544
529
  const result = await embeddingsService.queryEmbeddings(query);
545
530
  const response = {
@@ -554,48 +539,47 @@ async function handleRagQuery(strapi, args) {
554
539
  }));
555
540
  response.sourceCount = result.sourceDocuments.length;
556
541
  }
557
- return {
558
- content: [
559
- {
560
- type: "text",
561
- text: JSON.stringify(response, null, 2)
562
- }
563
- ]
564
- };
565
- } catch (error) {
566
- throw new Error(
567
- `RAG query failed: ${error instanceof Error ? error.message : String(error)}`
568
- );
569
- }
570
- }
571
- const listEmbeddingsTool = {
572
- name: "list_embeddings",
573
- description: "List all embeddings stored in the database. Returns metadata without the full content to avoid context overflow.",
542
+ return response;
543
+ },
544
+ publicSafe: true
545
+ };
546
+ const ragQueryMcpTool = {
547
+ name: "rag_query",
548
+ description: ragQueryTool.description,
574
549
  inputSchema: {
575
550
  type: "object",
576
551
  properties: {
577
- page: {
578
- type: "number",
579
- description: "Page number (starts at 1)",
580
- default: 1
581
- },
582
- pageSize: {
583
- type: "number",
584
- description: "Number of items per page (max: 50)",
585
- default: 25
586
- },
587
- search: {
552
+ query: {
588
553
  type: "string",
589
- description: "Search filter for title"
554
+ description: "The question or query to answer using embedded content"
555
+ },
556
+ includeSourceDocuments: {
557
+ type: "boolean",
558
+ description: "Include the source documents used to generate the answer (default: true)",
559
+ default: true
590
560
  }
591
561
  },
592
- required: []
562
+ required: ["query"]
593
563
  }
594
564
  };
595
- async function handleListEmbeddings(strapi, args) {
596
- const { page = 1, pageSize = 25, search } = args;
597
- const limit = Math.min(pageSize, 50);
598
- try {
565
+ async function handleRagQuery(strapi, args) {
566
+ const result = await ragQueryTool.execute(args, strapi);
567
+ return {
568
+ content: [
569
+ {
570
+ type: "text",
571
+ text: JSON.stringify(result, null, 2)
572
+ }
573
+ ]
574
+ };
575
+ }
576
+ const listEmbeddingsTool = {
577
+ name: "listEmbeddings",
578
+ description: "List all embedded documents with pagination. Returns metadata and content preview without full text.",
579
+ schema: ListEmbeddingsSchema,
580
+ execute: async (args, strapi) => {
581
+ const { page = 1, pageSize = 25, search } = args;
582
+ const limit = Math.min(pageSize, 50);
599
583
  const embeddingsService = strapi.plugin("strapi-content-embeddings").service("embeddings");
600
584
  const filters = {};
601
585
  if (search) {
@@ -618,65 +602,63 @@ async function handleListEmbeddings(strapi, args) {
618
602
  updatedAt: emb.updatedAt
619
603
  }));
620
604
  return {
621
- content: [
622
- {
623
- type: "text",
624
- text: JSON.stringify(
625
- {
626
- embeddings: embeddings2,
627
- pagination: result.pagination || {
628
- page,
629
- pageSize: limit,
630
- total: embeddings2.length
631
- }
632
- },
633
- null,
634
- 2
635
- )
636
- }
637
- ]
605
+ embeddings: embeddings2,
606
+ pagination: result.pagination || {
607
+ page,
608
+ pageSize: limit,
609
+ total: embeddings2.length
610
+ }
638
611
  };
639
- } catch (error) {
640
- throw new Error(
641
- `Failed to list embeddings: ${error instanceof Error ? error.message : String(error)}`
642
- );
643
- }
644
- }
645
- const getEmbeddingTool = {
646
- name: "get_embedding",
647
- description: "Get a specific embedding by its document ID. Returns the full content and metadata.",
612
+ },
613
+ publicSafe: true
614
+ };
615
+ const listEmbeddingsMcpTool = {
616
+ name: "list_embeddings",
617
+ description: listEmbeddingsTool.description,
648
618
  inputSchema: {
649
619
  type: "object",
650
620
  properties: {
651
- documentId: {
652
- type: "string",
653
- description: "The document ID of the embedding to retrieve"
621
+ page: {
622
+ type: "number",
623
+ description: "Page number (starts at 1)",
624
+ default: 1
654
625
  },
655
- includeContent: {
656
- type: "boolean",
657
- description: "Include the full content text (default: true)",
658
- default: true
626
+ pageSize: {
627
+ type: "number",
628
+ description: "Number of items per page (max: 50)",
629
+ default: 25
630
+ },
631
+ search: {
632
+ type: "string",
633
+ description: "Search filter for title"
659
634
  }
660
635
  },
661
- required: ["documentId"]
636
+ required: []
662
637
  }
663
638
  };
664
- async function handleGetEmbedding(strapi, args) {
665
- const { documentId, includeContent = true } = args;
666
- try {
639
+ async function handleListEmbeddings(strapi, args) {
640
+ const result = await listEmbeddingsTool.execute(args, strapi);
641
+ return {
642
+ content: [
643
+ {
644
+ type: "text",
645
+ text: JSON.stringify(result, null, 2)
646
+ }
647
+ ]
648
+ };
649
+ }
650
+ const getEmbeddingTool = {
651
+ name: "getEmbedding",
652
+ description: "Get a specific embedded document by its document ID. Returns full content and metadata.",
653
+ schema: GetEmbeddingSchema,
654
+ execute: async (args, strapi) => {
655
+ const { documentId, includeContent = true } = args;
667
656
  const embeddingsService = strapi.plugin("strapi-content-embeddings").service("embeddings");
668
657
  const embedding2 = await embeddingsService.getEmbedding(documentId);
669
658
  if (!embedding2) {
670
659
  return {
671
- content: [
672
- {
673
- type: "text",
674
- text: JSON.stringify({
675
- error: true,
676
- message: `Embedding not found with documentId: ${documentId}`
677
- })
678
- }
679
- ]
660
+ error: true,
661
+ message: `Embedding not found with documentId: ${documentId}`
680
662
  };
681
663
  }
682
664
  const result = {
@@ -693,49 +675,46 @@ async function handleGetEmbedding(strapi, args) {
693
675
  if (includeContent) {
694
676
  result.content = embedding2.content;
695
677
  }
696
- return {
697
- content: [
698
- {
699
- type: "text",
700
- text: JSON.stringify(result, null, 2)
701
- }
702
- ]
703
- };
704
- } catch (error) {
705
- throw new Error(
706
- `Failed to get embedding: ${error instanceof Error ? error.message : String(error)}`
707
- );
708
- }
709
- }
710
- const createEmbeddingTool = {
711
- name: "create_embedding",
712
- description: "Create a new embedding from text content. The content will be vectorized and stored for semantic search. For large content (over 4000 characters), enable autoChunk to automatically split into multiple embeddings.",
678
+ return result;
679
+ },
680
+ publicSafe: true
681
+ };
682
+ const getEmbeddingMcpTool = {
683
+ name: "get_embedding",
684
+ description: getEmbeddingTool.description,
713
685
  inputSchema: {
714
686
  type: "object",
715
687
  properties: {
716
- title: {
717
- type: "string",
718
- description: "A descriptive title for the embedding"
719
- },
720
- content: {
688
+ documentId: {
721
689
  type: "string",
722
- description: "The text content to embed (will be vectorized)"
723
- },
724
- metadata: {
725
- type: "object",
726
- description: "Optional metadata to associate with the embedding (tags, source, etc.)"
690
+ description: "The document ID of the embedding to retrieve"
727
691
  },
728
- autoChunk: {
692
+ includeContent: {
729
693
  type: "boolean",
730
- description: "Automatically split large content into chunks (default: false). When enabled, content over 4000 characters will be split into multiple embeddings with overlap for context preservation."
694
+ description: "Include the full content text (default: true)",
695
+ default: true
731
696
  }
732
697
  },
733
- required: ["title", "content"]
698
+ required: ["documentId"]
734
699
  }
735
700
  };
736
- async function handleCreateEmbedding(strapi, args) {
737
- const { title, content, metadata, autoChunk } = args;
738
- try {
701
+ async function handleGetEmbedding(strapi, args) {
702
+ const result = await getEmbeddingTool.execute(args, strapi);
703
+ return {
704
+ content: [
705
+ {
706
+ type: "text",
707
+ text: JSON.stringify(result, null, 2)
708
+ }
709
+ ]
710
+ };
711
+ }
712
+ const createEmbeddingTool = {
713
+ name: "createEmbedding",
714
+ description: "Create a new embedding from text content for future semantic search. Large content can be auto-chunked into multiple embeddings.",
715
+ schema: CreateEmbeddingSchema,
716
+ execute: async (args, strapi) => {
717
+ const { title, content, metadata, autoChunk } = args;
739
718
  const embeddingsService = strapi.plugin("strapi-content-embeddings").service("embeddings");
740
719
  if (autoChunk) {
741
720
  const result = await embeddingsService.createChunkedEmbedding({
@@ -748,34 +727,23 @@ async function handleCreateEmbedding(strapi, args) {
748
727
  }
749
728
  });
750
729
  return {
751
- content: [
752
- {
753
- type: "text",
754
- text: JSON.stringify(
755
- {
756
- success: true,
757
- message: result.wasChunked ? `Content chunked into ${result.totalChunks} embeddings` : "Embedding created successfully (no chunking needed)",
758
- wasChunked: result.wasChunked,
759
- totalChunks: result.totalChunks,
760
- primaryEmbedding: {
761
- id: result.entity.id,
762
- documentId: result.entity.documentId,
763
- title: result.entity.title,
764
- embeddingId: result.entity.embeddingId
765
- },
766
- chunks: result.chunks.map((chunk) => ({
767
- documentId: chunk.documentId,
768
- title: chunk.title,
769
- contentLength: chunk.content?.length || 0
770
- })),
771
- contentLength: content.length,
772
- estimatedTokens: Math.ceil(content.length / 4)
773
- },
774
- null,
775
- 2
776
- )
777
- }
778
- ]
730
+ success: true,
731
+ message: result.wasChunked ? `Content chunked into ${result.totalChunks} embeddings` : "Embedding created successfully (no chunking needed)",
732
+ wasChunked: result.wasChunked,
733
+ totalChunks: result.totalChunks,
734
+ primaryEmbedding: {
735
+ id: result.entity.id,
736
+ documentId: result.entity.documentId,
737
+ title: result.entity.title,
738
+ embeddingId: result.entity.embeddingId
739
+ },
740
+ chunks: result.chunks.map((chunk) => ({
741
+ documentId: chunk.documentId,
742
+ title: chunk.title,
743
+ contentLength: chunk.content?.length || 0
744
+ })),
745
+ contentLength: content.length,
746
+ estimatedTokens: Math.ceil(content.length / 4)
779
747
  };
780
748
  }
781
749
  const embedding2 = await embeddingsService.createEmbedding({
@@ -788,42 +756,65 @@ async function handleCreateEmbedding(strapi, args) {
788
756
  }
789
757
  });
790
758
  return {
791
- content: [
792
- {
793
- type: "text",
794
- text: JSON.stringify(
795
- {
796
- success: true,
797
- message: "Embedding created successfully",
798
- embedding: {
799
- id: embedding2.id,
800
- documentId: embedding2.documentId,
801
- title: embedding2.title,
802
- embeddingId: embedding2.embeddingId,
803
- contentLength: content.length,
804
- metadata: embedding2.metadata,
805
- createdAt: embedding2.createdAt
806
- },
807
- hint: content.length > 4e3 ? "Content is large. Consider using autoChunk: true for better search results." : void 0
808
- },
809
- null,
810
- 2
811
- )
812
- }
813
- ]
759
+ success: true,
760
+ message: "Embedding created successfully",
761
+ embedding: {
762
+ id: embedding2.id,
763
+ documentId: embedding2.documentId,
764
+ title: embedding2.title,
765
+ embeddingId: embedding2.embeddingId,
766
+ contentLength: content.length,
767
+ metadata: embedding2.metadata,
768
+ createdAt: embedding2.createdAt
769
+ },
770
+ hint: content.length > 4e3 ? "Content is large. Consider using autoChunk: true for better search results." : void 0
814
771
  };
815
- } catch (error) {
816
- throw new Error(
817
- `Failed to create embedding: ${error instanceof Error ? error.message : String(error)}`
818
- );
772
+ },
773
+ publicSafe: false
774
+ };
775
+ const createEmbeddingMcpTool = {
776
+ name: "create_embedding",
777
+ description: createEmbeddingTool.description,
778
+ inputSchema: {
779
+ type: "object",
780
+ properties: {
781
+ title: {
782
+ type: "string",
783
+ description: "A descriptive title for the embedding"
784
+ },
785
+ content: {
786
+ type: "string",
787
+ description: "The text content to embed (will be vectorized)"
788
+ },
789
+ metadata: {
790
+ type: "object",
791
+ description: "Optional metadata to associate with the embedding (tags, source, etc.)"
792
+ },
793
+ autoChunk: {
794
+ type: "boolean",
795
+ description: "Automatically split large content into chunks (default: false). When enabled, content over 4000 characters will be split into multiple embeddings with overlap for context preservation."
796
+ }
797
+ },
798
+ required: ["title", "content"]
819
799
  }
800
+ };
801
+ async function handleCreateEmbedding(strapi, args) {
802
+ const result = await createEmbeddingTool.execute(args, strapi);
803
+ return {
804
+ content: [
805
+ {
806
+ type: "text",
807
+ text: JSON.stringify(result, null, 2)
808
+ }
809
+ ]
810
+ };
820
811
  }
821
- const tools = [
822
- semanticSearchTool,
823
- ragQueryTool,
824
- listEmbeddingsTool,
825
- getEmbeddingTool,
826
- createEmbeddingTool
812
+ const tools$1 = [
813
+ semanticSearchMcpTool,
814
+ ragQueryMcpTool,
815
+ listEmbeddingsMcpTool,
816
+ getEmbeddingMcpTool,
817
+ createEmbeddingMcpTool
827
818
  ];
828
819
  const toolHandlers = {
829
820
  semantic_search: handleSemanticSearch,
@@ -883,7 +874,7 @@ function createMcpServer(strapi) {
883
874
  }
884
875
  );
885
876
  server.setRequestHandler(types_js.ListToolsRequestSchema, async () => {
886
- return { tools };
877
+ return { tools: tools$1 };
887
878
  });
888
879
  server.setRequestHandler(types_js.CallToolRequestSchema, async (request) => {
889
880
  return handleToolCall(strapi, request);
@@ -2531,9 +2522,22 @@ const sync = ({ strapi }) => ({
2531
2522
  }
2532
2523
  }
2533
2524
  });
2525
+ const tools = [
2526
+ semanticSearchTool,
2527
+ ragQueryTool,
2528
+ listEmbeddingsTool,
2529
+ getEmbeddingTool,
2530
+ createEmbeddingTool
2531
+ ];
2532
+ const aiTools = ({ strapi }) => ({
2533
+ getTools() {
2534
+ return tools;
2535
+ }
2536
+ });
2534
2537
  const services = {
2535
2538
  embeddings,
2536
- sync
2539
+ sync,
2540
+ "ai-tools": aiTools
2537
2541
  };
2538
2542
  const index = {
2539
2543
  register,
@@ -2548,4 +2552,3 @@ const index = {
2548
2552
  middlewares
2549
2553
  };
2550
2554
  module.exports = index;
2551
- //# sourceMappingURL=index.js.map