mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-05 01:47:21 +00:00
Generated the JSON contracts of providers, the runtime, and services at compile time (#1150)
This commit is contained in:
1 parent
e954881fda
commit
24e3c22db3
140 files changed
+1415
-292
No files matched your search
@@ -0,0 +1,154 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Provider.Anthropic;
|
||||
using AIStudio.Provider.Google;
|
||||
using AIStudio.Provider.OpenAI;
|
||||
using AIStudio.Tools.ToolCallingSystem;
|
||||
|
||||
using AnthropicImageUrl = AIStudio.Provider.Anthropic.SubContentImageUrl;
|
||||
using OpenAIImageUrl = AIStudio.Provider.OpenAI.SubContentImageUrl;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Requests to LLM providers as AI Studio builds them, with every kind of content they carry.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The values are made up. What counts is that every part of a request holds one, so that its golden file shows
|
||||
/// how each part gets written.
|
||||
/// </remarks>
|
||||
public static class JsonSampleRequests
|
||||
{
|
||||
/// <summary>
|
||||
/// A tool with one required and one optional argument, the shape the web search has.
|
||||
/// </summary>
|
||||
public static ToolDefinition Tool() => new()
|
||||
{
|
||||
Id = "web_search",
|
||||
Function = new()
|
||||
{
|
||||
Name = "web_search",
|
||||
DescriptionForLLM = "Search the web.",
|
||||
Strict = true,
|
||||
Parameters = ToolParameterSchemaBuilder.Create()
|
||||
.RequiredString("query", "The search query.")
|
||||
.OptionalInteger("page", "The page, starting at 1.")
|
||||
.Build(),
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A request to a Chat Completions API, with a tool, a call of it, and its result.
|
||||
/// </summary>
|
||||
public static ChatCompletionAPIRequest ChatCompletion() => new("chat-model", Messages(), true)
|
||||
{
|
||||
Tools = [ProviderToolAdapters.ToChatCompletionTool(Tool(), hostEnforcesStrict: true)],
|
||||
ParallelToolCalls = false,
|
||||
AdditionalApiParameters = ApiParameters(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A request to the Responses API of OpenAI, with an item of an earlier answer and the result of a tool.
|
||||
/// </summary>
|
||||
public static ResponsesAPIRequest Responses() => new("responses-model",
|
||||
[
|
||||
new TextMessage("You answer briefly.", "developer"),
|
||||
new MultimodalMessage(
|
||||
[
|
||||
new SubContentInputText(SubContentType.INPUT_TEXT, "What does the picture show?"),
|
||||
new SubContentInputImage(SubContentType.INPUT_IMAGE, "data:image/png;base64,iVBORw0KGgo="),
|
||||
], "user"),
|
||||
Parse("""{"type":"function_call","id":"fc_1","call_id":"call_1","name":"web_search","arguments":"{\"query\":\"weather\"}"}"""),
|
||||
new ResponsesFunctionCallOutputItem { CallId = "call_1", Output = "It is sunny." },
|
||||
],
|
||||
true, false, [ProviderToolAdapters.ToResponsesTool(Tool())])
|
||||
{
|
||||
AdditionalApiParameters = ApiParameters(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A request to the Messages API of Anthropic, with images from a URL and as data, and a tool round.
|
||||
/// </summary>
|
||||
public static ChatRequest Anthropic() => new("messages-model",
|
||||
[
|
||||
new TextMessage("What is the weather?", "user"),
|
||||
new MultimodalMessage(
|
||||
[
|
||||
new SubContentText(SubContentType.TEXT, "Compare these pictures."),
|
||||
new SubContentImage(SubContentType.IMAGE, new SubContentBase64Image { MediaType = "image/png", Data = "iVBORw0KGgo=" }),
|
||||
new SubContentImage(SubContentType.IMAGE, new AnthropicImageUrl { Url = "https://example.org/picture.png" }),
|
||||
], "user"),
|
||||
new AnthropicMessage(
|
||||
[
|
||||
Parse("""{"type":"text","text":"Let me search."}"""),
|
||||
Parse("""{"type":"tool_use","id":"toolu_1","name":"web_search","input":{"query":"weather"}}"""),
|
||||
]),
|
||||
new AnthropicToolResultMessage([new AnthropicToolResultContent { ToolUseId = "toolu_1", Content = "It is sunny.", IsError = true }]),
|
||||
],
|
||||
1024, true, "You answer briefly.")
|
||||
{
|
||||
Tools = [ProviderToolAdapters.ToAnthropicTool(Tool())],
|
||||
AdditionalApiParameters = ApiParameters(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A request for embeddings in the shape of the OpenAI API.
|
||||
/// </summary>
|
||||
public static EmbeddingRequest Embedding() => new("embedding-model", ["The first text.", "The second text."]);
|
||||
|
||||
/// <summary>
|
||||
/// A request for an embedding to the Gemini API.
|
||||
/// </summary>
|
||||
public static GoogleEmbeddingRequest GoogleEmbedding() => GoogleEmbeddingRequest.Of(["The first text.", "The second text."]);
|
||||
|
||||
private static List<IMessageBase> Messages() =>
|
||||
[
|
||||
new TextMessage("You answer briefly.", "system"),
|
||||
new MultimodalMessage(
|
||||
[
|
||||
new SubContentText(SubContentType.TEXT, "What do the pictures show?"),
|
||||
new SubContentImageUrlNested(SubContentType.IMAGE_URL, new SubContentImageUrlData { Url = "data:image/png;base64,iVBORw0KGgo=" }),
|
||||
new OpenAIImageUrl(SubContentType.IMAGE_URL, "https://example.org/picture.png"),
|
||||
], "user"),
|
||||
new AssistantToolCallMessage
|
||||
{
|
||||
Content = Parse("null"),
|
||||
ReasoningContent = "The weather needs a search.",
|
||||
ToolCalls =
|
||||
[
|
||||
new ChatCompletionToolCall
|
||||
{
|
||||
Id = "call_1",
|
||||
Function = new() { Name = "web_search", Arguments = """{"query":"weather"}""" },
|
||||
AdditionalMetadata = { ["index"] = Parse("0") },
|
||||
},
|
||||
],
|
||||
},
|
||||
new ToolResultMessage { Content = "It is sunny.", ToolCallId = "call_1" },
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Additional API parameters of every kind, read the way the provider settings read them.
|
||||
/// </summary>
|
||||
private static IDictionary<string, object> ApiParameters()
|
||||
{
|
||||
if (!AdditionalApiParametersParser.TryParse("""
|
||||
"temperature": 0.5,
|
||||
"top_k": 40,
|
||||
"seed": 12345678901,
|
||||
"stop": ["END", 7],
|
||||
"reasoning": { "effort": "low", "summary": null },
|
||||
"logprobs": false
|
||||
""", out var parameters, out var errorMessage))
|
||||
throw new InvalidOperationException(errorMessage);
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static JsonElement Parse(string json)
|
||||
{
|
||||
using var document = JsonDocument.Parse(json);
|
||||
return document.RootElement.Clone();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user