Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"IsSuccessStatusCode":true,"StatusCode":200,"Headers":{"SPRequestGuid":"13b005a2-204f-9000-8664-ea73a2d64880","SPClientServiceRequestDuration":"16","X-SharePointHealthScore":"2","X-SP-SERVERSTATE":"ReadOnly=0"},"Response":"{\u0022RegionalSettings\u0022:{\u0022TimeZone\u0022:{\u0022Description\u0022:\u0022(UTC-08:00) Pacific Time (US and Canada)\u0022,\u0022Id\u0022:13,\u0022Information\u0022:{\u0022Bias\u0022:480,\u0022DaylightBias\u0022:-60,\u0022StandardBias\u0022:0}},\u0022AdjustHijriDays\u0022:0,\u0022AlternateCalendarType\u0022:0,\u0022AM\u0022:\u0022AM\u0022,\u0022CalendarType\u0022:1,\u0022Collation\u0022:25,\u0022CollationLCID\u0022:2070,\u0022DateFormat\u0022:0,\u0022DateSeparator\u0022:\u0022/\u0022,\u0022DecimalSeparator\u0022:\u0022.\u0022,\u0022DigitGrouping\u0022:\u00223;0\u0022,\u0022FirstDayOfWeek\u0022:0,\u0022FirstWeekOfYear\u0022:0,\u0022IsEastAsia\u0022:false,\u0022IsRightToLeft\u0022:false,\u0022IsUIRightToLeft\u0022:false,\u0022ListSeparator\u0022:\u0022,\u0022,\u0022LocaleId\u0022:1033,\u0022NegativeSign\u0022:\u0022-\u0022,\u0022NegNumberMode\u0022:1,\u0022PM\u0022:\u0022PM\u0022,\u0022PositiveSign\u0022:\u0022\u0022,\u0022ShowWeeks\u0022:false,\u0022ThousandSeparator\u0022:\u0022,\u0022,\u0022Time24\u0022:false,\u0022TimeMarkerPosition\u0022:0,\u0022TimeSeparator\u0022:\u0022:\u0022,\u0022WorkDayEndHour\u0022:1020,\u0022WorkDays\u0022:62,\u0022WorkDayStartHour\u0022:480},\u0022Id\u0022:\u002221e96bcf-bdc1-4027-9225-ef8934b4dc4e\u0022,\u0022Url\u0022:\u0022https://test.sharepoint.com/sites/HarmonyWorksIndustrials\u0022}"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"IsSuccessStatusCode":true,"StatusCode":200,"Headers":{"SPRequestGuid":"13b005a2-1057-9000-8664-eb9612670866","SPClientServiceRequestDuration":"18","X-SharePointHealthScore":"0","X-SP-SERVERSTATE":"ReadOnly=0"},"Response":"{\u0022GroupId\u0022:\u002200000000-0000-0000-0000-000000000000\u0022,\u0022Id\u0022:\u0022092c099d-52a7-44da-9ce0-02400f849abe\u0022}"}

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions src/sdk/PnP.Core.Test/Copilot/RetrievalTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PnP.Core.Model.Copilot.Public.DTO;
using PnP.Core.Test.Utilities;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace PnP.Core.Test.Copilot
{
[TestClass]
public class RetrievalTests
{
[ClassInitialize]
public static void TestFixtureSetup(TestContext context)
{
// Configure mocking default for all tests in this class, unless override by a specific test
//TestCommon.Instance.Mocking = false;
}
[TestMethod]
public async Task RetriveTest()
{
//TestCommon.Instance.Mocking = false;
TestCommon.Instance.UseApplicationPermissions = false;

using (var context = await TestCommon.Instance.GetContextAsync(TestCommon.TestSite))
{
var response = await context.Copilot.Retrive(new RetrievalRequest
{
DataSource = "sharePoint",
QueryString = "Find me documents about test project",
});
Assert.AreEqual(response.RetrievalHits.Count, 4);
}
}
}
}
1 change: 1 addition & 0 deletions src/sdk/PnP.Core.Test/PnP.Core.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

<ItemGroup>
<Folder Include="Base\MockData\GraphRestTransitionTests\" />
<Folder Include="Copilot\MockData\RetrievalTests\" />
<Folder Include="QueryModel\MockData\" />
<Folder Include="Security\MockData\ListItemSecurityTests\" />
<Folder Include="Security\MockData\UserTests\" />
Expand Down
43 changes: 43 additions & 0 deletions src/sdk/PnP.Core/Model/Copilot/Internal/Copilot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using PnP.Core.Model.Copilot.Public;
using PnP.Core.Model.Copilot.Public.DTO;
using PnP.Core.Model.Me;
using PnP.Core.Model.Security;
using PnP.Core.Services;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace PnP.Core.Model.Copilot.Internal
{
/// <summary>
/// Provides methods for interacting with Microsoft Graph services to perform retrieval operations using a specified
/// Microsoft Graph client.
/// </summary>
internal sealed class Copilot : BaseDataModel<ICopilot>, ICopilot
{
/// <summary>
/// Sends a retrieval request to MS Graph API and returns the deserialized response.
/// </summary>
/// <param name="request">The retrieval request containing the parameters to be sent to the service. Cannot be null.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the deserialized retrieval
/// response from the MS Graph API.</returns>
/// <exception cref="HttpRequestException">Thrown if the HTTP request fails or the response indicates an unsuccessful status code.</exception>
public async Task<RetrievalResponse> Retrive(RetrievalRequest request)
{
var apiCall = new ApiCall($"copilot/retrieval", ApiType.Graph, JsonSerializer.Serialize(request, PnPConstants.JsonSerializer_IgnoreNullValues));
apiCall.ExecuteRequestApiCall = true;

var response = await RawRequestAsync(apiCall, HttpMethod.Post).ConfigureAwait(false);

if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return JsonSerializer.Deserialize<RetrievalResponse>(response.Json);
}
else
{
throw new HttpRequestException($"Request failed with status code {response.StatusCode}");
}
}
}
}
81 changes: 81 additions & 0 deletions src/sdk/PnP.Core/Model/Copilot/Public/DTO/RetrievalRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;

namespace PnP.Core.Model.Copilot.Public.DTO
{
/// <summary>
/// Represents a request to retrieve relevant text extracts from specified data sources using a natural language
/// query and optional filtering or configuration parameters.
/// </summary>
/// <remarks>Use this class to specify the parameters for retrieving content from supported sources such
/// as SharePoint, OneDrive for Business, or Copilot connectors. Configure the query, data source, and optional
/// metadata or filtering to tailor the retrieval to your application's needs. Ensure that required properties are
/// set before submitting the request. The class supports limiting the number of results and customizing the
/// metadata returned for each item.</remarks>
public class RetrievalRequest
{
/// <summary>
/// Natural language query string used to retrieve relevant text extracts. This parameter has a limit of 1,500 characters. Your queryString should be a single sentence, and you should avoid spelling errors in context-rich keywords. Required
/// </summary>
[JsonPropertyName("queryString")]
public string QueryString { get; set; } = "*";
/// <summary>
/// Indicates whether extracts should be retrieved from SharePoint, OneDrive, or Copilot connectors. Acceptable values are sharePoint, oneDriveBusiness, and externalItem. Required.
/// </summary>
[JsonPropertyName("dataSource")]
public string DataSource { get; set; } = "sharepoint";
/// <summary>
/// Contains additional configuration information for applicable data sources. dataSourceConfiguration includes an object called externalItem, where you can configure Copilot connectors retrieval. Optional.
/// </summary>
[JsonPropertyName("dataSourceConfiguration")]
public DataSourceConfiguration? DataSourceConfiguration { get; set; }
/// <summary>
/// A list of metadata fields to be returned for each item in the response. Only retrievable metadata properties can be included in this list. By default, no metadata is returned. Optional.
/// </summary>
[JsonPropertyName("resourceMetadata")]
public List<string>? ResourceMetadata { get; set; }
/// <summary>
/// The number of results that are returned in the response. Must be between 1 and 25. By default, returns up to 25 results. Optional.
/// </summary>
[JsonPropertyName("maximumNumberOfResults")]
public int MaximumNumberOfResults { get; set; } = 25;
/// <summary>
/// Keyword Query Language (KQL) expression with queryable SharePoint, OneDrive, or Copilot connectors properties and attributes to scope the retrieval before the query runs.
/// </summary>
[JsonPropertyName("filterExpression")]
public string? FilterExpression { get; set; }
}
/// <summary>
/// Represents the data source configuration
/// </summary>
public class DataSourceConfiguration
{
[JsonPropertyName("externalItem")]
public ExternalItemConfiguration? ExternalItem { get; set; }
}
/// <summary>
/// Represents configuration options for retrieving data from Copilot connectors
/// </summary>
public class ExternalItemConfiguration
{
/// <summary>
/// An array of connection objects specifying the Copilot connector connection identifiers to include in retrieval. Required.
/// </summary>
[JsonPropertyName("connections")]
public List<ExternalItemConnection> Connections { get; set; } = new List<ExternalItemConnection>();
}
/// <summary>
/// Represents a Copilot connector to include in retrieval operations
/// </summary>
public class ExternalItemConnection
{
/// <summary>
/// The ID of a Copilot connector connection to include. Required.
/// </summary>
[JsonPropertyName("connectionId")]
public string ConnectionId { get; set; } = string.Empty;
}

}
98 changes: 98 additions & 0 deletions src/sdk/PnP.Core/Model/Copilot/Public/DTO/RetrievalResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using PnP.Core.Model.SharePoint;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;

namespace PnP.Core.Model.Copilot.Public.DTO
{
/// <summary>
/// Represents results from a retrieval query.
/// </summary>
public class RetrievalResponse
{
/// <summary>
/// A collection of the retrieval results. If empty, no relevant results were found.
/// </summary>
[JsonPropertyName("retrievalHits")]
public List<RetrievalHit> RetrievalHits { get; set; } = new List<RetrievalHit>();
}
/// <summary>
/// Represents a single result within the list of retrieval results.
/// </summary>
public class RetrievalHit
{
/// <summary>
/// The resource type of the item. Possible values: site, list, listItem, externalItem, drive, driveItem ,unknownFutureValue
/// </summary>
[JsonPropertyName("resourceType")]
public string ResourceType { get; set; } = string.Empty;
/// <summary>
/// The URL of the item in which the extract was retrieved.
/// </summary>
[JsonPropertyName("webUrl")]
public string WebUrl { get; set; } = string.Empty;
/// <summary>
/// An array of text extracts extracted from the document for Retrieval-Augmented Generation. Currently, only one text snippet is extracted.
/// </summary>
[JsonPropertyName("extracts")]
public List<RetrievalExtract> Extracts { get; set; } = new List<RetrievalExtract>();
/// <summary>
/// A JSON object with information about the document's sensitivity label.
/// </summary>
[JsonPropertyName("sensitivityLabelInfo")]
public SensitivityLabelInfo? SensitivityLabelInfo { get; set; }
/// <summary>
/// The requested SharePoint and Microsoft 365 Copilot connectors metadata from the request payload (empty if not applicable).
/// </summary>
[JsonPropertyName("resourceMetadata")]
public Dictionary<string, object>? ResourceMetadata { get; set; }
}
/// <summary>
/// Represents a single extract within the list of retrieval extracts.
/// </summary>
public class RetrievalExtract
{
/// <summary>
/// The text extract received.
/// </summary>
[JsonPropertyName("text")]
public string Text { get; set; } = string.Empty;
/// <summary>
/// The cosine similarity between the text extract and the queryString, normalized to the 0-1 range. It's possible for a retrievalExtract to be returned without a relevance score.
/// </summary>
[JsonPropertyName("relevanceScore")]
public float RelevanceScore { get; set; }
}
/// <summary>
/// Describes the information protection label that details how to properly apply a sensitivity label to information.
/// </summary>
public class SensitivityLabelInfo
{
/// <summary>
/// The ID of the sensitivity label.
/// </summary>
[JsonPropertyName("sensitivityLabelId")]
public string SensitivityLabelId { get; set; } = string.Empty;
/// <summary>
/// The display name for the sensitivity label
/// </summary>
[JsonPropertyName("displayName")]
public string DisplayName { get; set; } = string.Empty;
/// <summary>
/// The color that the UI should display for the label, if configured.
/// </summary>
[JsonPropertyName("color")]
public string Color { get; set; } = string.Empty;
/// <summary>
/// The priority in which the sensitivity label is applied.
/// </summary>
[JsonPropertyName("priority")]
public int Priority { get; set; }
/// <summary>
/// The tooltip that should be displayed for the label in a UI.
/// </summary>
[JsonPropertyName("tooltip")]
public string Tooltip { get; set; } = string.Empty;
}
}
20 changes: 20 additions & 0 deletions src/sdk/PnP.Core/Model/Copilot/Public/ICopilot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

using PnP.Core.Model.Copilot.Public.DTO;
using System.Threading.Tasks;

namespace PnP.Core.Model.Copilot.Public
{
/// <summary>
/// Represents MS Graph API endpoint under Copilot path.
/// </summary>
[ConcreteType(typeof(Internal.Copilot))]
public interface ICopilot
{
/// <summary>
/// The Microsoft 365 Copilot Retrieval API allows for the retrieval of relevant text extracts from SharePoint, OneDrive, and Copilot connectors content that the calling user has access to, while respecting the defined access controls within the tenant. Use the Retrieval API to ground your generative AI solutions with Microsoft 365 data while optimizing for context recall.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Task<RetrievalResponse> Retrive(RetrievalRequest request);
}
}
6 changes: 6 additions & 0 deletions src/sdk/PnP.Core/Services/Core/IPnPContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using PnP.Core.Model.Copilot.Public;
using PnP.Core.Model.Me;
using PnP.Core.Model.Security;
using PnP.Core.Model.SharePoint;
Expand Down Expand Up @@ -49,6 +50,11 @@ public interface IPnPContext : IDisposable
/// </summary>
IMe Me { get; }

/// <summary>
/// Entry point for Copilot functionality
/// </summary>
ICopilot Copilot { get; }

/// <summary>
/// Entry point for the ContentTypeHub Object
/// </summary>
Expand Down
26 changes: 22 additions & 4 deletions src/sdk/PnP.Core/Services/Core/PnPContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PnP.Core.Model.Copilot.Internal;
using PnP.Core.Model.Copilot.Public;
using PnP.Core.Model.Me;
using PnP.Core.Model.Security;
using PnP.Core.Model.SharePoint;
Expand Down Expand Up @@ -60,7 +62,7 @@ public class PnPContext : IPnPContext
return new Social();
}, true);

private readonly Lazy<IMe> me= new Lazy<IMe>(() =>
private readonly Lazy<IMe> me = new Lazy<IMe>(() =>
{
return new Me();
}, true);
Expand All @@ -70,6 +72,11 @@ public class PnPContext : IPnPContext
return new ContentTypeHub();
}, true);

private readonly Lazy<ICopilot> copilot = new Lazy<ICopilot>(() =>
{
return new Copilot();
}, true);

#endregion

#region Internal properties
Expand Down Expand Up @@ -140,7 +147,7 @@ internal PnPContext(ILogger logger,
{
MicrosoftGraphAuthority = globalOptions.MicrosoftGraphAuthority;
AzureADLoginAuthority = globalOptions.AzureADLoginAuthority;

// Ensure the Microsoft Graph URL is set depending on the used cloud environment
GraphClient.UpdateBaseAddress(MicrosoftGraphAuthority);
}
Expand Down Expand Up @@ -427,6 +434,17 @@ public IMe Me
}
}

/// <summary>
/// Entry point for Copilot functionality
/// </summary>
public ICopilot Copilot
{
get
{
(copilot.Value as Copilot).PnPContext = this;
return copilot.Value;
}
}
/// <summary>
/// Entry point for the ContentTypeHub object
/// </summary>
Expand All @@ -451,7 +469,7 @@ public Batch NewBatch()
{
return BatchClient.EnsureBatch();
}

/// <summary>
/// Gets an ongoing Graph long-running operation.
/// </summary>
Expand Down Expand Up @@ -601,7 +619,7 @@ public async Task<PnPContext> CloneAsync(Uri uri)
/// <param name="groupId">Id of the other Microsoft 365 group to create a <see cref="PnPContext"/> for</param>
/// <returns>New <see cref="PnPContext"/></returns>
public PnPContext Clone(Guid groupId)
{
{
return CloneAsync(groupId).GetAwaiter().GetResult();
}

Expand Down
Loading