floating-copilot-widget 1.4.3 → 1.5.1

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.esm.js CHANGED
@@ -257,4 +257,812 @@ const FloatingCopilot = ({ config = {} }) => {
257
257
  finalConfig.resizable && !isMaximized && (React.createElement("div", { className: "copilot-resize-handle", onMouseDown: handleMouseDownResize, title: "Drag to resize" }))));
258
258
  };
259
259
 
260
- export { FloatingCopilot, FloatingCopilot as default, defaultConfig };
260
+ /******************************************************************************
261
+ Copyright (c) Microsoft Corporation.
262
+
263
+ Permission to use, copy, modify, and/or distribute this software for any
264
+ purpose with or without fee is hereby granted.
265
+
266
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
267
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
268
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
269
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
270
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
271
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
272
+ PERFORMANCE OF THIS SOFTWARE.
273
+ ***************************************************************************** */
274
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
275
+
276
+
277
+ function __awaiter(thisArg, _arguments, P, generator) {
278
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
279
+ return new (P || (P = Promise))(function (resolve, reject) {
280
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
281
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
282
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
283
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
284
+ });
285
+ }
286
+
287
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
288
+ var e = new Error(message);
289
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
290
+ };
291
+
292
+ /**
293
+ * GitHub Copilot Integration Service
294
+ *
295
+ * Provides AI-powered intent analysis and API integration for the floating chat widget.
296
+ * Uses GitHub's Models API (backed by OpenAI GPT-4) for intelligent message understanding.
297
+ *
298
+ * To use this service, you need a GitHub Personal Access Token with appropriate scopes.
299
+ */
300
+ const GITHUB_COPILOT_MODELS = 'https://models.inference.ai.azure.com/chat/completions';
301
+ /**
302
+ * Get GitHub token from config or environment variables
303
+ */
304
+ function getGithubToken(configToken) {
305
+ var _a, _b, _c;
306
+ // 1. Use explicitly provided token from config
307
+ if (configToken) {
308
+ return configToken;
309
+ }
310
+ // 2. Check common environment variable names
311
+ const token = (typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.GITHUB_TOKEN)) ||
312
+ (typeof process !== 'undefined' && ((_b = process.env) === null || _b === void 0 ? void 0 : _b.VITE_GITHUB_TOKEN)) ||
313
+ (typeof process !== 'undefined' && ((_c = process.env) === null || _c === void 0 ? void 0 : _c.REACT_APP_GITHUB_TOKEN)) ||
314
+ (typeof window !== 'undefined' && window.__GITHUB_TOKEN__);
315
+ if (!token) {
316
+ throw new Error('GitHub token is required for Copilot integration. ' +
317
+ 'Provide it via:\n' +
318
+ '1. CopilotConfig.githubToken parameter\n' +
319
+ '2. Environment variable: GITHUB_TOKEN, VITE_GITHUB_TOKEN, or REACT_APP_GITHUB_TOKEN\n' +
320
+ '3. Global variable: window.__GITHUB_TOKEN__\n\n' +
321
+ 'Get token from: https://github.com/settings/tokens (scopes: copilot, read:user)');
322
+ }
323
+ return token;
324
+ }
325
+ /**
326
+ * Analyze user message to identify intent and extract parameters
327
+ */
328
+ function analyzeUserIntent(request, config, availableApis) {
329
+ var _a, _b, _c;
330
+ return __awaiter(this, void 0, void 0, function* () {
331
+ const { userMessage, context, customInstructions } = request;
332
+ const { model = 'gpt-4o', maxTokens = 2000 } = config;
333
+ const githubToken = getGithubToken(config.githubToken);
334
+ // Build system prompt
335
+ const systemPrompt = buildIntentSystemPrompt(availableApis, customInstructions);
336
+ // Build user prompt
337
+ const userPrompt = buildIntentUserPrompt(userMessage, context);
338
+ try {
339
+ const response = yield fetch(GITHUB_COPILOT_MODELS, {
340
+ method: 'POST',
341
+ headers: {
342
+ 'Authorization': `Bearer ${githubToken}`,
343
+ 'Content-Type': 'application/json',
344
+ 'X-GitHub-Api-Version': '2022-11-28'
345
+ },
346
+ body: JSON.stringify({
347
+ model: model,
348
+ messages: [
349
+ { role: 'system', content: systemPrompt },
350
+ { role: 'user', content: userPrompt }
351
+ ],
352
+ max_tokens: maxTokens,
353
+ temperature: 0.3
354
+ })
355
+ });
356
+ if (!response.ok) {
357
+ const errorText = yield response.text();
358
+ throw new Error(`Copilot API error (${response.status}): ${errorText}`);
359
+ }
360
+ const data = yield response.json();
361
+ const content = (_c = (_b = (_a = data.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content;
362
+ if (!content) {
363
+ throw new Error('No response received from Copilot');
364
+ }
365
+ // Parse the intent response
366
+ return parseIntentResponse(content, userMessage);
367
+ }
368
+ catch (error) {
369
+ throw new Error(`Failed to analyze intent: ${error.message}`);
370
+ }
371
+ });
372
+ }
373
+ /**
374
+ * Call an API integration based on intent and parameters
375
+ */
376
+ function callAPI(request, integration) {
377
+ return __awaiter(this, void 0, void 0, function* () {
378
+ try {
379
+ // Build the request
380
+ const apiRequest = integration.buildRequest(request.parameters, request.context);
381
+ // Prepare fetch options
382
+ const fetchOptions = {
383
+ method: integration.method,
384
+ headers: Object.assign({ 'Content-Type': 'application/json' }, integration.headers)
385
+ };
386
+ // Add body for non-GET requests
387
+ if (integration.method !== 'GET' && apiRequest) {
388
+ fetchOptions.body = typeof apiRequest === 'string' ? apiRequest : JSON.stringify(apiRequest);
389
+ }
390
+ // Make the API call
391
+ const response = yield fetch(integration.endpoint, fetchOptions);
392
+ if (!response.ok) {
393
+ const errorText = yield response.text();
394
+ return {
395
+ success: false,
396
+ error: `API error (${response.status}): ${errorText}`,
397
+ apiName: integration.name
398
+ };
399
+ }
400
+ const responseData = yield response.json();
401
+ // Format the response
402
+ const formattedData = integration.formatResponse(responseData);
403
+ return {
404
+ success: true,
405
+ data: formattedData,
406
+ rawData: responseData,
407
+ apiName: integration.name
408
+ };
409
+ }
410
+ catch (error) {
411
+ return {
412
+ success: false,
413
+ error: `Failed to call API: ${error.message}`,
414
+ apiName: integration.name
415
+ };
416
+ }
417
+ });
418
+ }
419
+ /**
420
+ * Process user message: analyze intent and call appropriate API
421
+ */
422
+ function processUserMessage(userMessage, config, availableApis, context) {
423
+ return __awaiter(this, void 0, void 0, function* () {
424
+ // Validate token is available early
425
+ getGithubToken(config.githubToken);
426
+ // Step 1: Analyze intent
427
+ const intentResponse = yield analyzeUserIntent({ userMessage, context }, config, availableApis);
428
+ // Step 2: Determine which API to call
429
+ let apiResponse;
430
+ if (intentResponse.suggestedApis.length > 0) {
431
+ const apiId = intentResponse.suggestedApis[0];
432
+ const api = availableApis.find(a => a.id === apiId);
433
+ if (api) {
434
+ // Check if API should be called for this intent
435
+ const shouldCall = api.shouldCall
436
+ ? api.shouldCall(intentResponse.intent, intentResponse.parameters)
437
+ : true;
438
+ if (shouldCall) {
439
+ apiResponse = yield callAPI({
440
+ apiId,
441
+ parameters: intentResponse.parameters,
442
+ context
443
+ }, api);
444
+ }
445
+ }
446
+ }
447
+ return {
448
+ intent: intentResponse,
449
+ apiResponse
450
+ };
451
+ });
452
+ }
453
+ /**
454
+ * Validate that GitHub token is available before processing
455
+ * Useful for early validation in applications
456
+ */
457
+ function validateGithubToken(config) {
458
+ try {
459
+ const token = getGithubToken(config.githubToken);
460
+ return { valid: true, token };
461
+ }
462
+ catch (error) {
463
+ return { valid: false, error: error.message };
464
+ }
465
+ }
466
+ /**
467
+ * Generate a user-friendly response from intent and API data
468
+ */
469
+ function generateCopilotResponse(userMessage, intentResponse, apiResponse, config) {
470
+ return __awaiter(this, void 0, void 0, function* () {
471
+ // If we have API response data, return it
472
+ if ((apiResponse === null || apiResponse === void 0 ? void 0 : apiResponse.success) && apiResponse.data) {
473
+ return apiResponse.data;
474
+ }
475
+ // If API call failed, explain the error
476
+ if (apiResponse === null || apiResponse === void 0 ? void 0 : apiResponse.error) {
477
+ return `I encountered an error while processing your request: ${apiResponse.error}`;
478
+ }
479
+ // If no API was called but we have intent analysis
480
+ if (intentResponse.intent && intentResponse.confidence > 0.5) {
481
+ return `I understand you want to: ${intentResponse.intent}
482
+
483
+ Parameters identified:
484
+ ${Object.entries(intentResponse.parameters)
485
+ .map(([key, value]) => `- ${key}: ${JSON.stringify(value)}`)
486
+ .join('\n')}
487
+
488
+ However, no API integration is available for this intent. Please check the available integrations.`;
489
+ }
490
+ // Fallback response
491
+ return `I'm not sure what you're asking. Could you provide more details?`;
492
+ });
493
+ }
494
+ /**
495
+ * Build system prompt for intent analysis
496
+ */
497
+ function buildIntentSystemPrompt(availableApis, customInstructions) {
498
+ let prompt = `You are an intelligent intent analyzer integrated into a chat application.
499
+ Your role is to understand user messages and identify the user's intent, extract relevant parameters, and suggest which API integrations to use.
500
+
501
+ RESPONSE FORMAT:
502
+ You MUST respond ONLY with a valid JSON object in this exact format:
503
+ {
504
+ "intent": "description of what the user wants",
505
+ "confidence": 0.95,
506
+ "parameters": {
507
+ "param1": "value1",
508
+ "param2": "value2"
509
+ },
510
+ "suggestedApis": ["api_id_1", "api_id_2"]
511
+ }
512
+
513
+ IMPORTANT:
514
+ - intent: A clear description of what the user wants to accomplish
515
+ - confidence: A number between 0 and 1 indicating how confident you are
516
+ - parameters: Key-value pairs of information extracted from the message
517
+ - suggestedApis: Array of API IDs that should be called (in order of preference)
518
+
519
+ Be conversational, helpful, and focus on understanding the user's actual need.`;
520
+ if (availableApis && availableApis.length > 0) {
521
+ prompt += `\n\nAVAILABLE API INTEGRATIONS:\n`;
522
+ availableApis.forEach(api => {
523
+ prompt += `\n- ID: ${api.id}\n Name: ${api.name}\n Description: ${api.name}`;
524
+ if (api.intents) {
525
+ prompt += `\n Intended for intents: ${api.intents.join(', ')}`;
526
+ }
527
+ });
528
+ }
529
+ if (customInstructions) {
530
+ prompt += `\n\nCUSTOM INSTRUCTIONS:\n${customInstructions}`;
531
+ }
532
+ return prompt;
533
+ }
534
+ /**
535
+ * Build user prompt for intent analysis
536
+ */
537
+ function buildIntentUserPrompt(userMessage, context, availableApis) {
538
+ let prompt = `Analyze this user message and respond with ONLY a valid JSON object (no markdown, no extra text):
539
+
540
+ User message: "${userMessage}"`;
541
+ if (context && Object.keys(context).length > 0) {
542
+ prompt += `\n\nContext information:\n`;
543
+ Object.entries(context).forEach(([key, value]) => {
544
+ prompt += `- ${key}: ${JSON.stringify(value)}\n`;
545
+ });
546
+ }
547
+ prompt += `\n\nRespond with ONLY the JSON object, no other text.`;
548
+ return prompt;
549
+ }
550
+ /**
551
+ * Parse intent response from Copilot
552
+ */
553
+ function parseIntentResponse(content, userMessage) {
554
+ try {
555
+ // Extract JSON from potential markdown code blocks
556
+ let jsonContent = content.trim();
557
+ const jsonMatch = content.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
558
+ if (jsonMatch) {
559
+ jsonContent = jsonMatch[1];
560
+ }
561
+ const parsed = JSON.parse(jsonContent);
562
+ return {
563
+ intent: parsed.intent || 'unknown',
564
+ confidence: typeof parsed.confidence === 'number' ? parsed.confidence : 0.5,
565
+ parameters: parsed.parameters || {},
566
+ suggestedApis: Array.isArray(parsed.suggestedApis) ? parsed.suggestedApis : [],
567
+ rawResponse: content
568
+ };
569
+ }
570
+ catch (error) {
571
+ // Fallback parsing if JSON parsing fails
572
+ return {
573
+ intent: 'user_query',
574
+ confidence: 0.3,
575
+ parameters: { query: userMessage },
576
+ suggestedApis: [],
577
+ rawResponse: content
578
+ };
579
+ }
580
+ }
581
+ /**
582
+ * Validate API integration configuration
583
+ */
584
+ function validateAPIIntegration(api) {
585
+ const errors = [];
586
+ if (!api.id)
587
+ errors.push('API must have an id');
588
+ if (!api.name)
589
+ errors.push('API must have a name');
590
+ if (!api.endpoint)
591
+ errors.push('API must have an endpoint');
592
+ if (!api.method)
593
+ errors.push('API must have a method');
594
+ if (!api.buildRequest || typeof api.buildRequest !== 'function') {
595
+ errors.push('API must have a buildRequest function');
596
+ }
597
+ if (!api.formatResponse || typeof api.formatResponse !== 'function') {
598
+ errors.push('API must have a formatResponse function');
599
+ }
600
+ return {
601
+ valid: errors.length === 0,
602
+ errors
603
+ };
604
+ }
605
+ /**
606
+ * Merge multiple API integrations from different sources
607
+ */
608
+ function mergeAPIIntegrations(...integrationSets) {
609
+ const merged = new Map();
610
+ integrationSets.forEach(set => {
611
+ set.forEach(api => {
612
+ const validation = validateAPIIntegration(api);
613
+ if (validation.valid) {
614
+ merged.set(api.id, api);
615
+ }
616
+ else {
617
+ console.warn(`Invalid API integration ${api.id}:`, validation.errors);
618
+ }
619
+ });
620
+ });
621
+ return Array.from(merged.values());
622
+ }
623
+ /**
624
+ * Get missing required parameters for an API
625
+ */
626
+ function getMissingParameters(api, providedParams) {
627
+ if (!api.requiredParameters || api.requiredParameters.length === 0) {
628
+ return [];
629
+ }
630
+ return api.requiredParameters
631
+ .filter(param => param.required !== false && !providedParams[param.name])
632
+ .map(param => param.name);
633
+ }
634
+ /**
635
+ * Get the next missing parameter to ask for
636
+ */
637
+ function getNextMissingParameter(api, providedParams) {
638
+ if (!api.requiredParameters || api.requiredParameters.length === 0) {
639
+ return null;
640
+ }
641
+ const missing = api.requiredParameters.find(param => param.required !== false && !providedParams[param.name]);
642
+ if (!missing) {
643
+ return null;
644
+ }
645
+ return {
646
+ parameter: missing.name,
647
+ description: missing.description,
648
+ example: missing.example,
649
+ type: missing.type
650
+ };
651
+ }
652
+ /**
653
+ * Validate a parameter value against its definition
654
+ */
655
+ function validateParameter(paramName, value, definition) {
656
+ if (!value) {
657
+ return { valid: false, error: `${paramName} cannot be empty` };
658
+ }
659
+ // Type validation
660
+ if (definition.type) {
661
+ switch (definition.type) {
662
+ case 'email':
663
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
664
+ return { valid: false, error: `${paramName} must be a valid email address` };
665
+ }
666
+ break;
667
+ case 'phone':
668
+ if (!/^[\d\s\-+()]+$/.test(value) || value.replace(/\D/g, '').length < 10) {
669
+ return { valid: false, error: `${paramName} must be a valid phone number` };
670
+ }
671
+ break;
672
+ case 'number':
673
+ if (isNaN(Number(value))) {
674
+ return { valid: false, error: `${paramName} must be a number` };
675
+ }
676
+ break;
677
+ case 'date':
678
+ if (isNaN(Date.parse(value))) {
679
+ return { valid: false, error: `${paramName} must be a valid date` };
680
+ }
681
+ break;
682
+ }
683
+ }
684
+ // Regex validation
685
+ if (definition.validation) {
686
+ const regex = new RegExp(definition.validation);
687
+ if (!regex.test(value)) {
688
+ return { valid: false, error: `${paramName} format is invalid` };
689
+ }
690
+ }
691
+ return { valid: true };
692
+ }
693
+ /**
694
+ * Check if all required parameters have been collected
695
+ */
696
+ function areAllParametersCollected(api, providedParams) {
697
+ if (!api.requiredParameters || api.requiredParameters.length === 0) {
698
+ return true;
699
+ }
700
+ return !api.requiredParameters.some(param => param.required !== false && !providedParams[param.name]);
701
+ }
702
+ /**
703
+ * Collect parameters interactively
704
+ * Returns a system prompt asking for the next missing parameter
705
+ * OR triggers API call if all parameters are collected
706
+ */
707
+ function generateParameterPromptOrCallAPI(api, providedParams, intent, context) {
708
+ return __awaiter(this, void 0, void 0, function* () {
709
+ // Check if all required parameters are collected
710
+ const allCollected = areAllParametersCollected(api, providedParams);
711
+ if (allCollected) {
712
+ // All parameters are collected - call the API
713
+ try {
714
+ const apiResponse = yield callAPI({
715
+ apiId: api.id,
716
+ parameters: providedParams,
717
+ context
718
+ }, api);
719
+ return {
720
+ apiResponse,
721
+ allParametersCollected: true
722
+ };
723
+ }
724
+ catch (error) {
725
+ return {
726
+ prompt: `Error executing request: ${error.message}`,
727
+ allParametersCollected: true
728
+ };
729
+ }
730
+ }
731
+ // Still missing parameters - ask for the next one
732
+ const nextParam = getNextMissingParameter(api, providedParams);
733
+ if (!nextParam) {
734
+ return {
735
+ allParametersCollected: true
736
+ };
737
+ }
738
+ const provided = Object.keys(providedParams)
739
+ .filter(key => providedParams[key])
740
+ .map(key => `- ${key}: ${providedParams[key]}`)
741
+ .join('\n');
742
+ let prompt = `To complete your request to ${intent}, I need the following information:\n\n`;
743
+ prompt += `**${nextParam.parameter}**: ${nextParam.description}`;
744
+ if (nextParam.type) {
745
+ prompt += ` (Type: ${nextParam.type})`;
746
+ }
747
+ if (nextParam.example) {
748
+ prompt += `\nExample: ${nextParam.example}`;
749
+ }
750
+ if (provided) {
751
+ prompt += `\n\nAlready provided:\n${provided}`;
752
+ }
753
+ return {
754
+ prompt,
755
+ allParametersCollected: false
756
+ };
757
+ });
758
+ }
759
+ /**
760
+ * Collect parameters interactively
761
+ * Returns a system prompt asking for the next missing parameter
762
+ */
763
+ function generateParameterPrompt(api, providedParams) {
764
+ const nextParam = getNextMissingParameter(api, providedParams);
765
+ if (!nextParam) {
766
+ return '';
767
+ }
768
+ const provided = Object.keys(providedParams)
769
+ .filter(key => providedParams[key])
770
+ .map(key => `- ${key}: ${providedParams[key]}`)
771
+ .join('\n');
772
+ let prompt = `To complete your request, I need the following information:\n\n`;
773
+ prompt += `**${nextParam.parameter}**: ${nextParam.description}`;
774
+ if (nextParam.type) {
775
+ prompt += ` (Type: ${nextParam.type})`;
776
+ }
777
+ if (nextParam.example) {
778
+ prompt += `\nExample: ${nextParam.example}`;
779
+ }
780
+ if (provided) {
781
+ prompt += `\n\nAlready provided:\n${provided}`;
782
+ }
783
+ return prompt;
784
+ }
785
+
786
+ /**
787
+ * API Integration Examples
788
+ *
789
+ * This file provides examples of how to create and configure API integrations
790
+ * for use with the Copilot chat widget.
791
+ */
792
+ /**
793
+ * Example: Customer Creation API with Required Parameters
794
+ *
795
+ * This example shows how to integrate an API that creates a customer
796
+ * with interactive parameter collection
797
+ */
798
+ const createCustomerAPIIntegration = (baseUrl) => {
799
+ const requiredParams = [
800
+ {
801
+ name: 'name',
802
+ description: 'Customer full name',
803
+ type: 'string',
804
+ required: true,
805
+ example: 'John Doe'
806
+ },
807
+ {
808
+ name: 'email',
809
+ description: 'Customer email address',
810
+ type: 'email',
811
+ required: true,
812
+ validation: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$',
813
+ example: 'john@example.com'
814
+ },
815
+ {
816
+ name: 'phone',
817
+ description: 'Customer phone number',
818
+ type: 'phone',
819
+ required: true,
820
+ example: '+1-555-123-4567'
821
+ },
822
+ {
823
+ name: 'company',
824
+ description: 'Company name (optional)',
825
+ type: 'string',
826
+ required: false,
827
+ example: 'Acme Corp'
828
+ }
829
+ ];
830
+ return {
831
+ id: 'create_customer',
832
+ name: 'Create Customer',
833
+ endpoint: `${baseUrl}/api/customers`,
834
+ method: 'POST',
835
+ intents: ['create_customer', 'add_customer', 'new_customer'],
836
+ requiredParameters: requiredParams,
837
+ buildRequest: (params) => ({
838
+ name: params.name,
839
+ email: params.email,
840
+ phone: params.phone,
841
+ company: params.company || null,
842
+ createdAt: new Date().toISOString()
843
+ }),
844
+ formatResponse: (data) => {
845
+ return `✅ **Customer Created Successfully**\n\n` +
846
+ `**ID**: ${data.id}\n` +
847
+ `**Name**: ${data.name}\n` +
848
+ `**Email**: ${data.email}\n` +
849
+ `**Phone**: ${data.phone}\n` +
850
+ (data.company ? `**Company**: ${data.company}\n` : '') +
851
+ `**Created**: ${new Date(data.createdAt).toLocaleDateString()}`;
852
+ },
853
+ shouldCall: (intent, params) => {
854
+ // Call when all required params are present
855
+ return !!(params.name && params.email && params.phone);
856
+ }
857
+ };
858
+ };
859
+ /**
860
+ * Example: REST API Integration
861
+ *
862
+ * This example shows how to integrate a generic REST API that returns user data
863
+ */
864
+ const createUserAPIIntegration = (baseUrl) => ({
865
+ id: 'user_api',
866
+ name: 'User Service API',
867
+ endpoint: `${baseUrl}/api/users`,
868
+ method: 'GET',
869
+ intents: ['get_user', 'find_user', 'lookup_user'],
870
+ buildRequest: (params) => {
871
+ // Transform intent parameters into API query string
872
+ const queryParams = new URLSearchParams();
873
+ if (params.userId)
874
+ queryParams.append('id', params.userId);
875
+ if (params.username)
876
+ queryParams.append('username', params.username);
877
+ if (params.email)
878
+ queryParams.append('email', params.email);
879
+ return queryParams.toString();
880
+ },
881
+ formatResponse: (data) => {
882
+ if (Array.isArray(data)) {
883
+ return data.map(user => `**${user.name}** (${user.email})\nID: ${user.id}\nRole: ${user.role}`).join('\n\n');
884
+ }
885
+ return `**${data.name}** (${data.email})\nID: ${data.id}\nRole: ${data.role}`;
886
+ },
887
+ shouldCall: (intent, params) => {
888
+ // Only call if we have identifying parameters
889
+ return !!(params.userId || params.username || params.email);
890
+ }
891
+ });
892
+ /**
893
+ * Example: Data Analysis API Integration
894
+ *
895
+ * This shows how to integrate an API that performs data analysis
896
+ */
897
+ const createAnalysisAPIIntegration = (baseUrl) => ({
898
+ id: 'analysis_api',
899
+ name: 'Data Analysis Service',
900
+ endpoint: `${baseUrl}/api/analysis`,
901
+ method: 'POST',
902
+ intents: ['analyze_data', 'generate_report', 'data_insights'],
903
+ buildRequest: (params) => ({
904
+ dataSource: params.dataSource,
905
+ analysisType: params.analysisType || 'summary',
906
+ timeRange: params.timeRange,
907
+ filters: params.filters || {}
908
+ }),
909
+ formatResponse: (data) => {
910
+ let response = `## Analysis Results\n\n`;
911
+ if (data.summary) {
912
+ response += `### Summary\n${data.summary}\n\n`;
913
+ }
914
+ if (data.metrics) {
915
+ response += `### Key Metrics\n`;
916
+ Object.entries(data.metrics).forEach(([key, value]) => {
917
+ response += `- **${key}**: ${value}\n`;
918
+ });
919
+ response += '\n';
920
+ }
921
+ if (data.recommendations) {
922
+ response += `### Recommendations\n`;
923
+ data.recommendations.forEach((rec) => {
924
+ response += `- ${rec}\n`;
925
+ });
926
+ }
927
+ return response;
928
+ },
929
+ shouldCall: (intent, params) => {
930
+ return !!(params.dataSource && params.analysisType);
931
+ }
932
+ });
933
+ /**
934
+ * Example: Search API Integration
935
+ *
936
+ * Shows how to integrate a search/query API
937
+ */
938
+ const createSearchAPIIntegration = (baseUrl) => ({
939
+ id: 'search_api',
940
+ name: 'Search Service',
941
+ endpoint: `${baseUrl}/api/search`,
942
+ method: 'POST',
943
+ intents: ['search', 'find', 'query'],
944
+ buildRequest: (params) => ({
945
+ query: params.query,
946
+ filters: {
947
+ type: params.type,
948
+ category: params.category,
949
+ dateRange: params.dateRange
950
+ },
951
+ limit: params.limit || 10,
952
+ offset: params.offset || 0
953
+ }),
954
+ formatResponse: (data) => {
955
+ if (!data.results || data.results.length === 0) {
956
+ return 'No results found matching your search criteria.';
957
+ }
958
+ let response = `Found **${data.results.length}** results:\n\n`;
959
+ response += data.results.map((result, index) => `${index + 1}. **${result.title}**\n ${result.description}\n URL: ${result.url}`).join('\n\n');
960
+ return response;
961
+ }
962
+ });
963
+ /**
964
+ * Example: Webhook/Action API Integration
965
+ *
966
+ * Shows how to integrate APIs that perform actions (create, update, delete)
967
+ */
968
+ const createActionAPIIntegration = (baseUrl) => ({
969
+ id: 'action_api',
970
+ name: 'Action Service',
971
+ endpoint: `${baseUrl}/api/actions`,
972
+ method: 'POST',
973
+ intents: ['create', 'update', 'delete', 'perform_action'],
974
+ buildRequest: (params) => ({
975
+ action: params.action,
976
+ targetId: params.targetId,
977
+ targetType: params.targetType,
978
+ payload: params.payload || {},
979
+ metadata: params.metadata || {}
980
+ }),
981
+ formatResponse: (data) => {
982
+ if (data.success) {
983
+ return `✅ **Action Completed Successfully**\n\n${data.message || 'The requested action has been performed.'}\n\nDetails: ${JSON.stringify(data.result, null, 2)}`;
984
+ }
985
+ return `❌ **Action Failed**\n\n${data.message || 'The requested action could not be completed.'}`;
986
+ }
987
+ });
988
+ /**
989
+ * Example: Database Query Integration
990
+ *
991
+ * Shows how to integrate a database query service
992
+ */
993
+ const createDatabaseAPIIntegration = (baseUrl) => ({
994
+ id: 'database_api',
995
+ name: 'Database Query Service',
996
+ endpoint: `${baseUrl}/api/query`,
997
+ method: 'POST',
998
+ intents: ['query_database', 'get_data', 'fetch_records'],
999
+ buildRequest: (params) => ({
1000
+ table: params.table,
1001
+ columns: params.columns || ['*'],
1002
+ where: params.where || {},
1003
+ orderBy: params.orderBy,
1004
+ limit: params.limit || 50
1005
+ }),
1006
+ formatResponse: (data) => {
1007
+ if (!data.rows || data.rows.length === 0) {
1008
+ return 'No records found matching your query.';
1009
+ }
1010
+ let response = `Retrieved **${data.rows.length}** records:\n\n`;
1011
+ // Format as table if we have column information
1012
+ if (data.columns && data.columns.length > 0) {
1013
+ response += `| ${data.columns.join(' | ')} |\n`;
1014
+ response += `|${data.columns.map(() => '-').join('|')}|\n`;
1015
+ data.rows.forEach((row) => {
1016
+ response += `| ${data.columns.map((col) => row[col] || '-').join(' | ')} |\n`;
1017
+ });
1018
+ }
1019
+ else {
1020
+ // Fallback: display as JSON
1021
+ response += '```json\n' + JSON.stringify(data.rows, null, 2) + '\n```';
1022
+ }
1023
+ return response;
1024
+ }
1025
+ });
1026
+ /**
1027
+ * Example: External Service Integration (Weather, News, etc.)
1028
+ */
1029
+ const createWeatherAPIIntegration = (apiKey) => ({
1030
+ id: 'weather_api',
1031
+ name: 'Weather Service',
1032
+ endpoint: 'https://api.openweathermap.org/data/2.5/weather',
1033
+ method: 'GET',
1034
+ headers: {
1035
+ 'User-Agent': 'FloatingCopilot/1.0'
1036
+ },
1037
+ intents: ['get_weather', 'weather', 'check_weather'],
1038
+ buildRequest: (params) => {
1039
+ // Note: For actual use, pass apiKey securely
1040
+ return {
1041
+ q: params.city,
1042
+ appid: apiKey,
1043
+ units: params.units || 'metric'
1044
+ };
1045
+ },
1046
+ formatResponse: (data) => {
1047
+ var _a, _b, _c;
1048
+ const weather = (_a = data.weather) === null || _a === void 0 ? void 0 : _a[0];
1049
+ const main = data.main;
1050
+ return `**Weather for ${data.name}, ${(_b = data.sys) === null || _b === void 0 ? void 0 : _b.country}**
1051
+
1052
+ Current: ${weather === null || weather === void 0 ? void 0 : weather.main} (${weather === null || weather === void 0 ? void 0 : weather.description})
1053
+ Temperature: ${main === null || main === void 0 ? void 0 : main.temp}°C
1054
+ Feels like: ${main === null || main === void 0 ? void 0 : main.feels_like}°C
1055
+ Humidity: ${main === null || main === void 0 ? void 0 : main.humidity}%
1056
+ Wind Speed: ${(_c = data.wind) === null || _c === void 0 ? void 0 : _c.speed} m/s
1057
+
1058
+ Updated: ${new Date(data.dt * 1000).toLocaleString()}`;
1059
+ }
1060
+ });
1061
+ /**
1062
+ * Helper function to create a custom API integration
1063
+ */
1064
+ function createCustomAPIIntegration(config) {
1065
+ return config;
1066
+ }
1067
+
1068
+ export { FloatingCopilot, analyzeUserIntent, areAllParametersCollected, callAPI, createActionAPIIntegration, createAnalysisAPIIntegration, createCustomAPIIntegration, createCustomerAPIIntegration, createDatabaseAPIIntegration, createSearchAPIIntegration, createUserAPIIntegration, createWeatherAPIIntegration, FloatingCopilot as default, defaultConfig, generateCopilotResponse, generateParameterPrompt, generateParameterPromptOrCallAPI, getMissingParameters, getNextMissingParameter, mergeAPIIntegrations, processUserMessage, validateAPIIntegration, validateGithubToken, validateParameter };