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
16 changes: 15 additions & 1 deletion eng/config/collector-semantic-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@
},
"developmentAttributeAllowList": {
"span": [
"qyl.agent.diagnostic.check.count",
"qyl.agent.diagnostic.check.failed_count",
"qyl.agent.diagnostic.extension.id",
"qyl.agent.diagnostic.format.version",
"qyl.agent.diagnostic.outcome",
"qyl.agent.diagnostic.phase",
"qyl.agent.diagnostic.probe.id",
"qyl.agent.diagnostic.snapshot.id",
"qyl.agent.diagnostic.variable.count",
"qyl.exception.source",
"qyl.instrumentation.domain",
"qyl.mcp.evaluation_run.id",
Expand All @@ -54,7 +63,12 @@
"qyl.mcp.sdk.tier",
"qyl.mcp.server.id",
"qyl.mcp.test_case.id",
"qyl.mcp.tool.name"
"qyl.mcp.tool.name",
"qyl.workflow.agent.id",
"qyl.workflow.attempt.id",
"qyl.workflow.event.id",
"qyl.workflow.run.id",
"qyl.workflow.tool_call.id"
],
"log": [
"browser.device_memory",
Expand Down
3 changes: 3 additions & 0 deletions packages/Qyl.Cli/Codex/ActiveWorkflowRunStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ internal sealed class ActiveWorkflowRunStore
public ActiveWorkflowRunStore(string root)
{
Directory.CreateDirectory(root);
Root = root;
_activePath = Path.Combine(root, ActiveFileName);
_lockPath = Path.Combine(root, LockFileName);
}

public string Root { get; }

public FileStream Acquire()
{
try
Expand Down
62 changes: 62 additions & 0 deletions packages/Qyl.Cli/Codex/CodexEventNormalizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ internal sealed class CodexEventNormalizer
private readonly HashSet<string> _eventIds = new(StringComparer.Ordinal);
private readonly Dictionary<string, ThreadContext> _threads = new(StringComparer.Ordinal);
private readonly Dictionary<string, ApprovalContext> _approvals = new(StringComparer.Ordinal);
private readonly Dictionary<string, DiagnosticSnapshotContext> _diagnosticSnapshots =
new(StringComparer.Ordinal);
private ulong _sourceSequence;
private string? _rootThreadId;
private string? _activeRootTurnId;
Expand Down Expand Up @@ -119,6 +121,58 @@ public CodexNormalizedBatch CompleteRun(DateTimeOffset timestamp, bool succeeded
: new CodexNormalizedBatch([workflowEvent], []);
}

public CodexNormalizedBatch NormalizeDiagnosticSnapshot(
DiagnosticSnapshotInboxRequest request,
DateTimeOffset receivedAt)
{
if (_diagnosticSnapshots.TryGetValue(request.SnapshotId, out var previous))
{
if (!string.Equals(previous.PayloadDigest, request.PayloadDigest, StringComparison.Ordinal))
throw new DiagnosticSnapshotConflictException();
return previous.Batch ?? default;
}
if (_rootThreadId is null || !_threads.TryGetValue(_rootThreadId, out var root))
throw new DiagnosticSnapshotContextUnavailableException();

var eventId = StableEventId("diagnostic", request.SnapshotId);
var workflowEvent = CreateEvent(
eventId,
WorkflowJournalEventKind.ContentCaptured,
receivedAt,
_rootThreadId,
root.ActiveTurnId,
root.AttemptId,
null,
null,
null,
null,
[request.Content.ContentRef],
new Dictionary<string, object>(StringComparer.Ordinal)
{
["extension_id"] = DiagnosticSnapshotCapture.ExtensionId,
["format_version"] = DiagnosticSnapshotCapture.FormatVersion,
["snapshot_id"] = request.SnapshotId,
["probe_id"] = request.ProbeId,
["phase"] = request.Phase,
["outcome"] = request.Outcome,
["variable_count"] = request.VariableCount,
["check_count"] = request.CheckCount,
["failed_check_count"] = request.FailedCheckCount,
["content_ref"] = request.Content.ContentRef.Value
}) ?? throw new DiagnosticSnapshotConflictException();
var batch = new CodexNormalizedBatch([workflowEvent], [request.Content]);
_diagnosticSnapshots.Add(
request.SnapshotId,
new DiagnosticSnapshotContext(request.PayloadDigest, batch));
return batch;
}

public void MarkDiagnosticSnapshotRecorded(string snapshotId)
{
if (_diagnosticSnapshots.TryGetValue(snapshotId, out var context))
_diagnosticSnapshots[snapshotId] = context with { Batch = null };
}

private void NormalizeThreadStarted(
JsonElement parameters,
DateTimeOffset receivedAt,
Expand Down Expand Up @@ -1008,4 +1062,12 @@ private sealed record ApprovalContext(
string TurnId,
string? ItemId,
string? AttemptId);

private sealed record DiagnosticSnapshotContext(
string PayloadDigest,
CodexNormalizedBatch? Batch);
}

internal sealed class DiagnosticSnapshotConflictException : Exception;

internal sealed class DiagnosticSnapshotContextUnavailableException : Exception;
2 changes: 2 additions & 0 deletions packages/Qyl.Cli/Codex/CodexObserverJsonContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ internal partial class CodexWorkflowContractJsonContext : JsonSerializerContext;
[JsonSerializable(typeof(WorkflowSpoolEntry[]))]
[JsonSerializable(typeof(WorkflowSpoolEnvelope))]
[JsonSerializable(typeof(ActiveWorkflowRun))]
[JsonSerializable(typeof(DiagnosticSnapshotInboxRequest))]
[JsonSerializable(typeof(DiagnosticSnapshotInboxAcknowledgement))]
[JsonSerializable(typeof(string))]
internal partial class CodexObserverStateJsonContext : JsonSerializerContext;
27 changes: 27 additions & 0 deletions packages/Qyl.Cli/Codex/CodexObserverModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ internal sealed record ActiveWorkflowRun(
DateTimeOffset StartedAt,
int ProcessId);

internal sealed record DiagnosticSnapshotInboxRequest(
string RunId,
string SnapshotId,
string ProbeId,
string Phase,
string Outcome,
int VariableCount,
int CheckCount,
int FailedCheckCount,
string PayloadDigest,
DateTimeOffset SubmittedAt,
Qyl.Api.Contracts.Workflow.WorkflowContentChunk Content);

internal sealed record DiagnosticSnapshotInboxAcknowledgement(
string RunId,
string SnapshotId,
string PayloadDigest,
string Status,
string Code,
string? EventId);

internal readonly record struct DiagnosticSnapshotSubmissionResult(
bool Recorded,
string Code,
string SnapshotId,
string? EventId);

internal sealed record CodexSchemaIdentity(
string CodexVersion,
string SchemaDirectory,
Expand Down
Loading
Loading