// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI.Foundry.Hosting;
///
/// Extension methods for reading and writing the associated
/// with an in a Foundry hosted agent.
///
///
/// The hosted session context is written exactly once by the hosting layer when a session is created,
/// and is validated against the live request on every subsequent invocation. The
/// method is intentionally so that only the hosting layer can establish the
/// identity values; consumers (such as implementations) read the values
/// through the public accessor.
///
[Experimental(DiagnosticIds.Experiments.AIOpenAIResponses)]
public static class HostedSessionContextExtensions
{
///
/// The well-known key used to store the
/// on a session.
///
///
/// Exposed as a constant so consumers can correlate persisted state across processes.
/// External code must not write to this key directly; use from the
/// hosting assembly instead.
///
public const string StateKey = "Microsoft.Agents.AI.Foundry.Hosting.HostedSessionContext";
///
/// Gets the previously written by the hosting layer
/// for this session, if any.
///
/// The session to read from.
///
/// The for the session, or when the
/// session was not produced by a hosted agent (or the value has not yet been written).
///
/// Thrown when is .
public static HostedSessionContext? GetHostedContext(this AgentSession session)
{
Throw.IfNull(session);
return session.StateBag.TryGetValue(StateKey, out var context, HostedSessionJsonUtilities.DefaultOptions)
? context
: null;
}
///
/// Writes the for this session.
///
/// The session to write to.
/// The hosted session context to associate with .
///
/// Internal to the hosting assembly. Consumers must not invoke this method directly; the hosting
/// layer is the single writer and uses validation against the live request to detect any tampering
/// that does occur via lower-level APIs. Throws when a context has already been written for this
/// session to enforce the write-once contract.
///
/// Thrown when or is .
/// Thrown when this session already carries a .
internal static void SetHostedContext(this AgentSession session, HostedSessionContext context)
{
Throw.IfNull(session);
Throw.IfNull(context);
if (session.StateBag.TryGetValue(StateKey, out _, HostedSessionJsonUtilities.DefaultOptions))
{
throw new InvalidOperationException(
$"A {nameof(HostedSessionContext)} has already been written to this session. " +
"The hosted session identity is write-once; resumed sessions must validate against the existing context, not overwrite it.");
}
session.StateBag.SetValue(StateKey, context, HostedSessionJsonUtilities.DefaultOptions);
}
}