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
2 changes: 2 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<PropertyGroup Condition="'$(IsPackable)' == 'true'">
<!-- Ensure all packable projects include the repository LICENSE -->
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<!-- Emit XML documentation for public APIs in packaged libraries -->
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<PropertyGroup>
Expand Down
47 changes: 0 additions & 47 deletions src/Coven.Agents.OpenAI/OpenAIChunkBatchTransmuter.cs

This file was deleted.

34 changes: 32 additions & 2 deletions src/Coven.Agents.OpenAI/OpenAIClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,48 @@ namespace Coven.Agents.OpenAI;
/// </summary>
public sealed record OpenAIClientConfig
{
/// <summary>
/// API key used to authenticate with the OpenAI Responses API.
/// </summary>
public required string ApiKey { get; init; }

/// <summary>
/// The model identifier to use for responses (e.g., <c>gpt-5-2025-08-07</c>).
/// </summary>
public required string Model { get; init; }

/// <summary>
/// Optional organization id for the client.
/// </summary>
public string? Organization { get; init; }

/// <summary>
/// Optional project id for the client.
/// </summary>
public string? Project { get; init; }

/// <summary>
/// Temperature sampling setting (model-dependent).
/// </summary>
public float? Temperature { get; init; }

/// <summary>
/// Top-p nucleus sampling (model-dependent).
/// </summary>
public float? TopP { get; init; }

/// <summary>
/// Maximum number of output tokens to generate.
/// </summary>
public int? MaxOutputTokens { get; init; }
// Max number of transcript items to include; default is unlimited

/// <summary>
/// Max number of transcript items to include; defaults to unlimited.
/// </summary>
public int HistoryClip { get; init; } = int.MaxValue;

// Configures reasoning options for models that support it.
/// <summary>
/// Configures reasoning options for models that support it.
/// </summary>
public ReasoningConfig Reasoning { get; init; } = new ReasoningConfig();
}
11 changes: 11 additions & 0 deletions src/Coven.Agents.OpenAI/OpenAIEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

namespace Coven.Agents.OpenAI;

/// <summary>
/// Base entry type for OpenAI agent journals (requests, responses, thoughts, chunks, acknowledgements).
/// </summary>
public abstract record OpenAIEntry(
string Sender
);

/// <summary>Outgoing request payload destined for OpenAI.</summary>
public sealed record OpenAIEfferent(
string Sender,
string Text
) : OpenAIEntry(Sender);

/// <summary>Incoming response from OpenAI after completion.</summary>
public sealed record OpenAIAfferent(
string Sender,
string Text,
Expand All @@ -19,6 +24,7 @@ public sealed record OpenAIAfferent(
string Model
) : OpenAIEntry(Sender);

/// <summary>Incoming response chunk (streaming) from OpenAI.</summary>
public sealed record OpenAIAfferentChunk(
string Sender,
string Text,
Expand All @@ -28,6 +34,7 @@ string Model
) : OpenAIEntry(Sender);

// Streaming thought chunks (afferent): model streams thoughts back
/// <summary>Incoming thought chunk from OpenAI.</summary>
public sealed record OpenAIAfferentThoughtChunk(
string Sender,
string Text,
Expand All @@ -36,6 +43,7 @@ public sealed record OpenAIAfferentThoughtChunk(
string Model
) : OpenAIEntry(Sender);

/// <summary>Full thought message from OpenAI (non-chunked).</summary>
public sealed record OpenAIThought(
string Sender,
string Text,
Expand All @@ -44,17 +52,20 @@ public sealed record OpenAIThought(
string Model
) : OpenAIEntry(Sender);

/// <summary>OpenAI acknowledgement used for synchronization.</summary>
public sealed record OpenAIAck(
string Sender,
string Text
) : OpenAIEntry(Sender);

// Streaming thought chunks (efferent): agent streams thoughts out
/// <summary>Outgoing thought chunk destined for OpenAI (not forwarded by gateway today).</summary>
public sealed record OpenAIEfferentThoughtChunk(
string Sender,
string Text
) : OpenAIEntry(Sender);

/// <summary>Marks completion of a streaming response from OpenAI.</summary>
public sealed record OpenAIStreamCompleted(
string Sender,
string ResponseId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Coven.Agents.OpenAI;
/// Maps OpenAI journal entries to OpenAI SDK <see cref="ResponseItem"/> inputs.
/// Only user/assistant textual entries are emitted; others return null.
/// </summary>
public sealed class OpenAIEntryToResponseItemTransmuter : ITransmuter<OpenAIEntry, ResponseItem?>
internal sealed class OpenAIEntryToResponseItemTransmuter : ITransmuter<OpenAIEntry, ResponseItem?>
{
public Task<ResponseItem?> Transmute(OpenAIEntry Input, CancellationToken cancellationToken = default)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Coven.Agents.OpenAI/OpenAIMaxLengthWindowPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Coven.Agents.OpenAI;
/// Emits when the recent OpenAI chunk(s) length reaches a max.
/// Minimal lookback of 1; intended as a safety cap in combination with semantic policies.
/// </summary>
public sealed class OpenAIMaxLengthWindowPolicy : IWindowPolicy<OpenAIAfferentChunk>
internal sealed class OpenAIMaxLengthWindowPolicy : IWindowPolicy<OpenAIAfferentChunk>
{
private readonly int _max;

Expand Down
2 changes: 1 addition & 1 deletion src/Coven.Agents.OpenAI/OpenAIParagraphShatterPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Coven.Agents.OpenAI;
/// - Second: remainder of the original text
/// If no boundary exists, produces no outputs (forward unchanged).
/// </summary>
public sealed class OpenAIThoughtParagraphShatterPolicy : IShatterPolicy<OpenAIEntry>
internal sealed class OpenAIThoughtParagraphShatterPolicy : IShatterPolicy<OpenAIEntry>
{
public IEnumerable<OpenAIEntry> Shatter(OpenAIEntry entry)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Coven.Agents.OpenAI/OpenAIParagraphWindowPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Coven.Agents.OpenAI;
/// A paragraph boundary is a double newline sequence ("\r\n\r\n" or "\n\n").
/// Uses a minimal lookback of 2 to account for boundaries that straddle chunk edges.
/// </summary>
public sealed class OpenAIParagraphWindowPolicy : IWindowPolicy<OpenAIAfferentChunk>
internal sealed class OpenAIParagraphWindowPolicy : IWindowPolicy<OpenAIAfferentChunk>
{
public int MinChunkLookback => 2;

Expand Down
8 changes: 7 additions & 1 deletion src/Coven.Agents.OpenAI/OpenAIRegistration.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// SPDX-License-Identifier: BUSL-1.1
using Coven.Agents;

namespace Coven.Agents.OpenAI;

/// <summary>
/// Registration customization for the OpenAI integration.
/// </summary>
public sealed class OpenAIRegistration
{
internal bool StreamingEnabled { get; private set; }

/// <summary>
/// Enables streaming mode (streaming gateway + windowing daemons).
/// </summary>
/// <returns>The same registration for fluent chaining.</returns>
public OpenAIRegistration EnableStreaming()
{
StreamingEnabled = true;
Expand Down
2 changes: 1 addition & 1 deletion src/Coven.Agents.OpenAI/OpenAITransmuter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Coven.Agents.OpenAI;

public sealed class OpenAITransmuter : IBiDirectionalTransmuter<OpenAIEntry, AgentEntry>
internal sealed class OpenAITransmuter : IBiDirectionalTransmuter<OpenAIEntry, AgentEntry>
{
public Task<AgentEntry> TransmuteAfferent(OpenAIEntry Input, CancellationToken cancellationToken)
{
Expand Down
11 changes: 10 additions & 1 deletion src/Coven.Agents.OpenAI/ReasoningConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@

namespace Coven.Agents.OpenAI;

/// <summary>
/// Reasoning configuration for models that support structured reasoning controls.
/// </summary>
public sealed class ReasoningConfig
{
// When reasoning is provided, assume enabled and default required settings.
/// <summary>
/// Reasoning effort setting; defaults to <see cref="ReasoningEffort.Medium"/>.
/// </summary>
public ReasoningEffort Effort { get; init; } = ReasoningEffort.Medium;

/// <summary>
/// Controls verbosity of returned reasoning summaries.
/// </summary>
public ReasoningSummaryVerbosity SummaryVerbosity { get; init; } = ReasoningSummaryVerbosity.Auto;
}
7 changes: 6 additions & 1 deletion src/Coven.Agents.OpenAI/ReasoningSummaryVerbosity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

namespace Coven.Agents.OpenAI;

/// <summary>
/// Controls verbosity of model-provided reasoning summaries when available.
/// </summary>
public enum ReasoningSummaryVerbosity
{
/// <summary>Let the model decide verbosity.</summary>
Auto,
/// <summary>Prefer brief summaries.</summary>
Concise,
/// <summary>Prefer detailed summaries.</summary>
Detailed
}

17 changes: 17 additions & 0 deletions src/Coven.Agents.OpenAI/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,28 @@

namespace Coven.Agents.OpenAI;

/// <summary>
/// Dependency Injection helpers for wiring the OpenAI agent integration.
/// Registers journals, gateway connection, transmuters, windowing daemons, and the official OpenAI client.
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Registers OpenAI agents with required defaults.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="config">OpenAI client configuration (API key and model are required).</param>
/// <returns>The same service collection to enable fluent chaining.</returns>
public static IServiceCollection AddOpenAIAgents(this IServiceCollection services, OpenAIClientConfig config)
=> AddOpenAIAgents(services, config, null);

/// <summary>
/// Registers OpenAI agents with optional configuration of streaming/windowing behavior.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="config">OpenAI client configuration (API key and model are required).</param>
/// <param name="configure">Optional registration customization (e.g., enable streaming).</param>
/// <returns>The same service collection to enable fluent chaining.</returns>
public static IServiceCollection AddOpenAIAgents(this IServiceCollection services, OpenAIClientConfig config, Action<OpenAIRegistration>? configure)
{
ArgumentNullException.ThrowIfNull(services);
Expand Down
4 changes: 4 additions & 0 deletions src/Coven.Agents/AgentAfferentBatchTransmuter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

namespace Coven.Agents;

/// <summary>
/// Batches afferent agent chunks into a single <see cref="AgentResponse"/>.
/// </summary>
public sealed class AgentAfferentBatchTransmuter : IBatchTransmuter<AgentAfferentChunk, AgentResponse>
{
/// <inheritdoc />
public Task<BatchTransmuteResult<AgentAfferentChunk, AgentResponse>> Transmute(IEnumerable<AgentAfferentChunk> Input, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(Input);
Expand Down
4 changes: 4 additions & 0 deletions src/Coven.Agents/AgentAfferentThoughtBatchTransmuter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

namespace Coven.Agents;

/// <summary>
/// Batches afferent agent thought chunks into a single <see cref="AgentThought"/>.
/// </summary>
public sealed class AgentAfferentThoughtBatchTransmuter : IBatchTransmuter<AgentAfferentThoughtChunk, AgentThought>
{
/// <inheritdoc />
public Task<BatchTransmuteResult<AgentAfferentThoughtChunk, AgentThought>> Transmute(IEnumerable<AgentAfferentThoughtChunk> Input, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(Input);
Expand Down
4 changes: 4 additions & 0 deletions src/Coven.Agents/AgentEfferentBatchTransmuter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

namespace Coven.Agents;

/// <summary>
/// Batches efferent agent chunks into a single <see cref="AgentPrompt"/>.
/// </summary>
public sealed class AgentEfferentBatchTransmuter : IBatchTransmuter<AgentEfferentChunk, AgentPrompt>
{
/// <inheritdoc />
public Task<BatchTransmuteResult<AgentEfferentChunk, AgentPrompt>> Transmute(IEnumerable<AgentEfferentChunk> Input, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(Input);
Expand Down
17 changes: 15 additions & 2 deletions src/Coven.Agents/AgentEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,39 @@

namespace Coven.Agents;

// Minimal agent entry union used with IScrivener<T>
/// <summary>
/// Base entry type for agent journals (prompts, responses, thoughts, acks, and streaming chunks).
/// </summary>
public abstract record AgentEntry(string Sender);

// Unfixed/draft entries that should never be forwarded by adapters directly
/// <summary>
/// Marker base for draft entries that should not be forwarded out of the agent journal directly.
/// </summary>
public abstract record AgentEntryDraft(string Sender) : AgentEntry(Sender);

/// <summary>Represents a user or upstream prompt destined for an agent.</summary>
public sealed record AgentPrompt(string Sender, string Text) : AgentEntry(Sender);

/// <summary>Represents an agent's finalized response.</summary>
public sealed record AgentResponse(string Sender, string Text) : AgentEntry(Sender);

/// <summary>Represents an agent's introspective thought (not typically user-visible).</summary>
public sealed record AgentThought(string Sender, string Text) : AgentEntry(Sender);

/// <summary>Represents an acknowledgement for internal synchronization.</summary>
public sealed record AgentAck(string Sender) : AgentEntry(Sender);

// Streaming additions
/// <summary>Outgoing (efferent) response chunk prior to finalization.</summary>
public sealed record AgentEfferentChunk(string Sender, string Text) : AgentEntryDraft(Sender);

/// <summary>Incoming (afferent) response chunk prior to finalization.</summary>
public sealed record AgentAfferentChunk(string Sender, string Text) : AgentEntryDraft(Sender);
/// <summary>Outgoing (efferent) thought chunk prior to finalization.</summary>
public sealed record AgentEfferentThoughtChunk(string Sender, string Text) : AgentEntryDraft(Sender);

/// <summary>Incoming (afferent) thought chunk prior to finalization.</summary>
public sealed record AgentAfferentThoughtChunk(string Sender, string Text) : AgentEntryDraft(Sender);

/// <summary>Marks completion of a streaming sequence.</summary>
public sealed record AgentStreamCompleted(string Sender) : AgentEntryDraft(Sender);
Loading