Skip to content
Merged
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
4 changes: 2 additions & 2 deletions docs/design/agent-mode.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Linq2GraphQL Agent Mode Design

**Status:** in progress. Plan steps 1-3 (the groundwork, SDL input and SDL output) are implemented. The AI package is being built in slices: (1) package skeleton and scoped schema, (2) renderer, (3) validator, (4) the four tools, (5) the `AsAgentTools` adapter, (6) sample and regression harness. Slices 1 to 5 are merged; slice 6 (the sample and regression harness) is in review. See [Plan](#plan-and-risks).
**Status:** in progress. Plan steps 1-3 (the groundwork, SDL input and SDL output) are implemented. The AI package is being built in slices: (1) package skeleton and scoped schema, (2) renderer, (3) validator, (4) the four tools, (5) the `AsAgentTools` adapter, (6) sample and regression harness. All six slices are merged, and the package ships as a preview (`-preview`, same version number as the core packages). Next: evaluation with the sample against a real model, then pilots. See [Plan](#plan-and-risks).

## Summary

Expand Down Expand Up @@ -420,7 +420,7 @@ Subscriptions stay out entirely; they don't fit the request/response shape of to
1. **Core prerequisites** (done): the per-request hook and the schema cache-key fix.
2. **SDL input in the generator** (done): it introduced GraphQL-Parser.
3. **SDL output** (done): the `--agent` flag, `IGraphSchemaSource`, and derived clients for per-user tokens. `[Description]` attributes and the two extra introspection fields shipped with step 2.
4. **Preview and pilots:** the first version as a prerelease package (`-preview`), complete enough to run end to end, with a runnable sample against the test server. Usefulness depends on the use case, so it is evaluated in one or two pilot apps with a real schema and real users, ideally different ones (interactive and background, small and large schema). The evaluation is part of the product: `OnQuery` logs (questions, queries, validation errors, tool calls per answer), simple user feedback per answer in the pilot app, and which questions the team moves to dedicated tools. The pilots can start before step 3 by using an exported `schema.graphql`. The sample (`test/Linq2GraphQL.Agent.Sample`) runs a chat loop against the in-process test server, with Azure AI Foundry (Entra ID, no keys) or any OpenAI-compatible endpoint such as Ollama, and an `eval` mode that runs a question set and reports pass rate, tool calls, rejected queries and tokens; it is the regression harness for prompt and tool changes. CI runs the loop without a model: a scripted chat client replays tool calls through Microsoft.Extensions.AI's function invocation (`AgentLoopTests`).
4. **Preview and pilots:** the first version as a prerelease package (`-preview`; the AI project's csproj adds the suffix to the shared version, so a release publishes the core packages as stable and this one as a preview), complete enough to run end to end, with a runnable sample against the test server. Usefulness depends on the use case, so it is evaluated in one or two pilot apps with a real schema and real users, ideally different ones (interactive and background, small and large schema). The evaluation is part of the product: `OnQuery` logs (questions, queries, validation errors, tool calls per answer), simple user feedback per answer in the pilot app, and which questions the team moves to dedicated tools. The pilots can start before step 3 by using an exported `schema.graphql`. The sample (`test/Linq2GraphQL.Agent.Sample`) runs a chat loop against the in-process test server, with Azure AI Foundry (Entra ID, no keys) or any OpenAI-compatible endpoint such as Ollama, and an `eval` mode that runs a question set and reports pass rate, tool calls, rejected queries and tokens; it is the regression harness for prompt and tool changes. CI runs the loop without a model: a scripted chat client replays tool calls through Microsoft.Extensions.AI's function invocation (`AgentLoopTests`).
5. **Decide from the pilots:** did the teams get a working agent quickly, were users satisfied with the answers, where did it fail (filters, paging, large schemas), and what did they specialise? If it holds up, release `Linq2GraphQL.Client.AI`. If not, the core and generator improvements still stand.

**Risks**
Expand Down
12 changes: 12 additions & 0 deletions src/Linq2GraphQL.Client.AI/Linq2GraphQL.Client.AI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@
<PackageTags>Linq GraphQL Client AI Agent</PackageTags>
</PropertyGroup>

<!--
Agent mode ships as a preview until the pilots are evaluated: it keeps the core packages' version but always
packs as a prerelease, so a stable release (1.0.45) publishes this package as 1.0.45-preview. Remove this
target to release it as stable.
-->
<Target Name="AddPreviewSuffix" AfterTargets="GetBuildVersion">
<PropertyGroup Condition="!$(PackageVersion.Contains('-'))">
<PackageVersion>$(PackageVersion)-preview</PackageVersion>
<NuGetPackageVersion>$(PackageVersion)</NuGetPackageVersion>
</PropertyGroup>
</Target>

<ItemGroup>
<InternalsVisibleTo Include="Linq2GraphQL.Tests"/>
</ItemGroup>
Expand Down
6 changes: 5 additions & 1 deletion test/Linq2GraphQL.Agent.Sample/AgentSampleApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Linq2GraphQL.Client;
using Linq2GraphQL.Client.AI;
using Linq2GraphQL.TestClient;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -174,7 +175,10 @@ private static IDisposable StartServer(string? serverUrl, out HttpClient httpCli
return httpClient;
}

var application = new WebApplicationFactory<Program>();
// The factory looks for the server's content root next to the solution file, which only works from a
// test project; the test server reads nothing from it, so the sample's own output folder will do.
var application = new WebApplicationFactory<Program>()
.WithWebHostBuilder(b => b.UseContentRoot(AppContext.BaseDirectory));
httpClient = application.CreateClient(new() { BaseAddress = new Uri("https://localhost/graphql/") });
return application;
}
Expand Down
7 changes: 7 additions & 0 deletions test/Linq2GraphQL.Agent.Sample/ChatClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ internal sealed record AgentSettings(AgentProvider Provider, string Endpoint, st
return null;
}

endpoint = endpoint.Trim().Trim('"', '\'');
if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var uri) || uri.Scheme is not ("https" or "http"))
{
problem = $"Agent:Endpoint '{endpoint}' is not a valid URL; expected something like https://my-resource.cognitiveservices.azure.com/.";
return null;
}

problem = "";
return new AgentSettings(provider, endpoint, deployment, section["ApiKey"]);
}
Expand Down
Loading