Skip to content
Draft
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
41 changes: 41 additions & 0 deletions .github/workflows/auto_resonance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "Auto Resonance"

on: [push, pull_request]

permissions:
contents: read
id-token: write
attestations: write

jobs:
auto-resonance:
name: "Auto Resonance"
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Checkout repo
uses: actions/checkout@v6

- name: Run Proof-of-Resonance Core
run: |
echo "Run Proof-of-Resonance Core"

- name: Run Resonant Stability Field
run: |
echo "Run Resonant Stability Field"

- name: Generate Build Provenance
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/attest-build-provenance@v1
with:
subject-path: .

- name: Upload Resonance Artifacts
uses: actions/upload-artifact@v4
with:
name: resonance-artifacts
path: |
artifacts/**
if-no-files-found: warn
20 changes: 20 additions & 0 deletions dotnet/test/Harness/SessionOutcome.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/

namespace GitHub.Copilot.SDK.Test.Harness;

public enum SessionOutcomeKind
{
Message,
Abstention,
}

public sealed record SessionOutcome(SessionOutcomeKind Kind, AssistantMessageEvent? AssistantMessage)
{
public static SessionOutcome Message(AssistantMessageEvent message) =>
new(SessionOutcomeKind.Message, message);

public static SessionOutcome Abstention() =>
new(SessionOutcomeKind.Abstention, null);
}
28 changes: 19 additions & 9 deletions dotnet/test/Harness/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ namespace GitHub.Copilot.SDK.Test.Harness;

public static class TestHelper
{
public static async Task<AssistantMessageEvent?> GetFinalAssistantMessageAsync(
public static async Task<SessionOutcome> GetFinalSessionOutcomeAsync(
CopilotSession session,
TimeSpan? timeout = null)
{
var tcs = new TaskCompletionSource<AssistantMessageEvent>();
var tcs = new TaskCompletionSource<SessionOutcome>();
using var cts = new CancellationTokenSource(timeout ?? TimeSpan.FromSeconds(60));

AssistantMessageEvent? finalAssistantMessage = null;
Expand All @@ -22,8 +22,10 @@ public static class TestHelper
case AssistantMessageEvent msg:
finalAssistantMessage = msg;
break;
case SessionIdleEvent when finalAssistantMessage != null:
tcs.TrySetResult(finalAssistantMessage);
case SessionIdleEvent:
tcs.TrySetResult(finalAssistantMessage != null
? SessionOutcome.Message(finalAssistantMessage)
: SessionOutcome.Abstention());
break;
case SessionErrorEvent error:
tcs.TrySetException(new Exception(error.Data.Message ?? "session error"));
Expand All @@ -34,15 +36,15 @@ public static class TestHelper
// Check existing messages
CheckExistingMessages();

cts.Token.Register(() => tcs.TrySetException(new TimeoutException("Timeout waiting for assistant message")));
cts.Token.Register(() => tcs.TrySetException(new TimeoutException("Timeout waiting for session outcome")));

return await tcs.Task;

async void CheckExistingMessages()
{
try
{
var existing = await GetExistingFinalResponseAsync(session);
var existing = await GetExistingFinalOutcomeAsync(session);
if (existing != null) tcs.TrySetResult(existing);
}
catch (Exception ex)
Expand All @@ -52,7 +54,15 @@ async void CheckExistingMessages()
}
}

private static async Task<AssistantMessageEvent?> GetExistingFinalResponseAsync(CopilotSession session)
public static async Task<AssistantMessageEvent?> GetFinalAssistantMessageAsync(
CopilotSession session,
TimeSpan? timeout = null)
{
var outcome = await GetFinalSessionOutcomeAsync(session, timeout);
return outcome.AssistantMessage;
}

private static async Task<SessionOutcome?> GetExistingFinalOutcomeAsync(CopilotSession session)
{
var messages = (await session.GetMessagesAsync()).ToList();

Expand All @@ -68,10 +78,10 @@ async void CheckExistingMessages()
for (var i = idleIdx - 1; i >= 0; i--)
{
if (currentTurn[i] is AssistantMessageEvent msg)
return msg;
return SessionOutcome.Message(msg);
}

return null;
return SessionOutcome.Abstention();
}

public static async Task<T> GetNextEventOfTypeAsync<T>(
Expand Down
8 changes: 8 additions & 0 deletions nodejs/src/por/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# copilot-por-sdk

Fork of github/copilot-sdk with an interception layer for control primitives.

PoR primitive: when coherence cannot be guaranteed, the agent may intentionally abstain
instead of retrying indefinitely.

Status: WIP (por-interception-layer).
17 changes: 17 additions & 0 deletions nodejs/src/por/intercept.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export type PorDecision = "PROCEED" | "ABSTAIN";

export function porCheck(args: {
coherence: number;
drift: number;
thresholds?: { coherence: number; drift: number };
}): { decision: PorDecision; reason?: string } {
const thresholds = args.thresholds ?? { coherence: 0.72, drift: 0.18 };

if (args.drift > thresholds.drift) {
return { decision: "ABSTAIN", reason: "drift_gt_tolerance" };
}
if (args.coherence < thresholds.coherence) {
return { decision: "ABSTAIN", reason: "coherence_lt_threshold" };
}
return { decision: "PROCEED" };
}
42 changes: 42 additions & 0 deletions scripts/CERTIFICATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: PoR AutoResonance Certification

on:
push:
branches: [main]
pull_request:

jobs:
por-certify:
runs-on: ubuntu-latest

steps:
- name: Checkout repo
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20

- name: Install dependencies
run: npm ci

- name: Run PoR invariant certification
run: |
node scripts/por_certify.js

- name: Generate certificate
if: success()
run: |
echo "# PoR AutoResonance Certificate" > CERTIFICATE.md
echo "" >> CERTIFICATE.md
echo "Commit: $GITHUB_SHA" >> CERTIFICATE.md
echo "Date: $(date -u)" >> CERTIFICATE.md
echo "Status: CERTIFIED" >> CERTIFICATE.md

- name: Upload certificate artifact
if: success()
uses: actions/upload-artifact@v4
with:
name: por-autoresonance-certificate
path: CERTIFICATE.md