Skip to content

Instantly share code, notes, and snippets.

@nathan815
Created March 10, 2026 03:37
Show Gist options
  • Select an option

  • Save nathan815/264d78ff877435932bd42f28b97f07e2 to your computer and use it in GitHub Desktop.

Select an option

Save nathan815/264d78ff877435932bd42f28b97f07e2 to your computer and use it in GitHub Desktop.

Bug: AdditionalContext in OnUserPromptSubmitted hook output is silently ignored

Repro: Run with dotnet run

Summary

When using the OnUserPromptSubmitted hook and returning a UserPromptSubmittedHookOutput with AdditionalContext set, the context is not injected into the conversation for the model. The hook fires correctly (confirmed via logging), but the model does not receive the additional context.

Using ModifiedPrompt on the same hook output works as expected — the model sees the modified prompt. This suggests the issue is specifically with AdditionalContext handling in the CLI runtime.

Reproduction

  1. Configure a BYOK provider (Azure OpenAI):
var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-5.2-chat",
    Provider = new ProviderConfig
    {
        Type = "azure",
        BaseUrl = "https://<endpoint>.openai.azure.com/openai/deployments/gpt-5.2-chat",
        ApiKey = "<key>",
        Azure = new AzureOptions { ApiVersion = "2024-12-01-preview" },
    },
    Streaming = true,
    Hooks = new SessionHooks
    {
        OnUserPromptSubmitted = (input, invocation) =>
        {
            Console.WriteLine($"Hook fired: {invocation.SessionId}");
            return Task.FromResult<UserPromptSubmittedHookOutput?>(
                new UserPromptSubmittedHookOutput
                {
                    AdditionalContext = "The user is currently viewing SDDC abc123 in region eastus2",
                }
            );
        },
    },
});

await session.SendAsync(new MessageOptions { Prompt = "What am I looking at?" });
  1. The hook fires (confirmed via console output).
  2. The model responds as if it has no additional context — it does not know about the SDDC.

Expected behavior

The AdditionalContext string should be injected into the conversation so the model can see it, as documented:

AdditionalContext - Additional context to inject into the conversation for the language model.

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GitHub.Copilot.SDK" Version="0.1.32" />
</ItemGroup>
</Project>
using GitHub.Copilot.SDK;
// ── Config ──────────────────────────────────────────────────────────
var endpoint = "https://<YOUR_ENDPOINT>.openai.azure.com/openai/deployments/<DEPLOYMENT>";
var apiKey = "<YOUR_API_KEY>";
var model = "<DEPLOYMENT_NAME>"; // e.g. "gpt-5.2-chat"
// ── Create client ───────────────────────────────────────────────────
await using var client = new CopilotClient();
await client.StartAsync();
// ── Test 1: AdditionalContext (BROKEN — model doesn't see it) ───────
Console.WriteLine("=== Test 1: AdditionalContext ===");
{
var done = new TaskCompletionSource();
var session = await client.CreateSessionAsync(
new SessionConfig
{
Model = model,
Provider = new ProviderConfig
{
Type = "azure",
BaseUrl = endpoint,
ApiKey = apiKey,
WireApi = "completions",
Azure = new AzureOptions { ApiVersion = "2025-03-01-preview" },
},
Streaming = true,
Hooks = new SessionHooks
{
OnUserPromptSubmitted = (input, invocation) =>
{
Console.WriteLine($" [Hook] Fired for session {invocation.SessionId}");
Console.WriteLine($" [Hook] Returning AdditionalContext: 'The secret code is BANANA42'");
return Task.FromResult<UserPromptSubmittedHookOutput?>(
new UserPromptSubmittedHookOutput
{
AdditionalContext =
"The secret code is BANANA42. If the user asks for the secret code, tell them it is BANANA42.",
}
);
},
},
OnPermissionRequest = (req, inv) =>
Task.FromResult(new PermissionRequestResult { Kind = PermissionRequestResultKind.Approved }),
}
);
session.On(evt =>
{
if (evt is AssistantMessageEvent msg)
Console.WriteLine($" [Assistant] {msg.Data.Content}");
else if (evt is SessionIdleEvent)
done.SetResult();
else if (evt is SessionErrorEvent err)
{
Console.WriteLine($" [Error] {err.Data.Message}");
done.SetResult();
}
});
await session.SendAsync(new MessageOptions { Prompt = "What is the secret code?" });
await done.Task;
await session.DisposeAsync();
}
Console.WriteLine();
// ── Test 2: ModifiedPrompt (WORKS — model sees it) ─────────────────
Console.WriteLine("=== Test 2: ModifiedPrompt ===");
{
var done = new TaskCompletionSource();
var session = await client.CreateSessionAsync(
new SessionConfig
{
Model = model,
Provider = new ProviderConfig
{
Type = "azure",
BaseUrl = endpoint,
ApiKey = apiKey,
WireApi = "completions",
Azure = new AzureOptions { ApiVersion = "2025-03-01-preview" },
},
Streaming = true,
Hooks = new SessionHooks
{
OnUserPromptSubmitted = (input, invocation) =>
{
Console.WriteLine($" [Hook] Fired for session {invocation.SessionId}");
Console.WriteLine($" [Hook] Returning ModifiedPrompt with context prepended");
return Task.FromResult<UserPromptSubmittedHookOutput?>(
new UserPromptSubmittedHookOutput
{
ModifiedPrompt = $"<context>The secret code is BANANA42.</context>\n{input.Prompt}",
}
);
},
},
OnPermissionRequest = (req, inv) =>
Task.FromResult(new PermissionRequestResult { Kind = PermissionRequestResultKind.Approved }),
}
);
session.On(evt =>
{
if (evt is AssistantMessageEvent msg)
Console.WriteLine($" [Assistant] {msg.Data.Content}");
else if (evt is SessionIdleEvent)
done.SetResult();
else if (evt is SessionErrorEvent err)
{
Console.WriteLine($" [Error] {err.Data.Message}");
done.SetResult();
}
});
await session.SendAsync(new MessageOptions { Prompt = "What is the secret code?" });
await done.Task;
await session.DisposeAsync();
}
Console.WriteLine();
Console.WriteLine("Done. If Test 1 didn't know the code but Test 2 did, AdditionalContext is broken.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment