Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
204e95a
fix: resolve UV path override not being detected in System Requirements
whatevertogo Jan 11, 2026
25e5d05
fix: improve uv/uvx detection robustness on macOS and Linux
whatevertogo Jan 11, 2026
cc22320
Merge branch 'CoplayDev:main' into main
whatevertogo Jan 11, 2026
8d5fa2f
refactor: unify process execution with ExecPath.TryRun and add Window…
whatevertogo Jan 11, 2026
84cee8c
fix: improve version parsing to handle both spaces and parentheses
whatevertogo Jan 11, 2026
510e631
refactor: improve platform detectors with absolute path resolution
whatevertogo Jan 11, 2026
bf41479
fix: improve error handling in PathResolverService by logging exceptions
whatevertogo Jan 11, 2026
f39857c
Remove .meta files added after fork and update .gitignore
whatevertogo Jan 11, 2026
c4be11c
Merge branch 'CoplayDev:main' into main
whatevertogo Jan 12, 2026
1832715
Update .gitignore
whatevertogo Jan 12, 2026
554ddd0
save .meta
whatevertogo Jan 12, 2026
fb5909d
refactor: unify uv/uvx naming and path detection across platforms
whatevertogo Jan 12, 2026
254125a
fix: improve validation light(uvxPathStatus) logic for UVX path overr…
whatevertogo Jan 12, 2026
f9ae5d5
refactor: streamline UV version validation and unify path detection m…
whatevertogo Jan 12, 2026
84cb9c6
fix: add type handling for Claude Code client in config JSON builder
whatevertogo Jan 12, 2026
ee33077
fix: correct command from 'uvx' to 'uv' for Python version listing in…
whatevertogo Jan 12, 2026
2c3ebcd
Merge branch 'CoplayDev:main' into main
whatevertogo Jan 14, 2026
66fe194
Merge branch 'CoplayDev:main' into main
whatevertogo Jan 15, 2026
79bce47
Merge branch 'CoplayDev:main' into main
whatevertogo Jan 16, 2026
b0eb274
feat: Add ActionTrace system for editor event tracking and replay
whatevertogo Jan 16, 2026
ec59a59
refactor: split EventStore into partial classes for better maintainab…
whatevertogo Jan 16, 2026
4e54591
fix: update stylesheet references and comment unsupported styles in A…
whatevertogo Jan 16, 2026
e599807
refactor: update comments and documentation in action trace files for…
whatevertogo Jan 16, 2026
f475bee
feat: enhance ActionTrace with layered settings, preset system, and q…
whatevertogo Jan 17, 2026
af77674
feat: optimize performance in ActionTrace by replacing LINQ with manu…
whatevertogo Jan 17, 2026
f547208
feat: enhance ActionTrace settings with Range attributes and dynamic …
whatevertogo Jan 17, 2026
44b7045
feat: add GlobalIdHelper for cross-session stable object identificati…
whatevertogo Jan 17, 2026
a86506c
fix: replace delayCall with EditorApplication.update to avoid memory …
whatevertogo Jan 18, 2026
f340636
Merge branch 'main' into feature/ActionTrace
whatevertogo Jan 18, 2026
061a821
Merge branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo Jan 19, 2026
25e1253
feat: add built-in HookRegistry system with Event Args pattern
whatevertogo Jan 19, 2026
13c0bc5
fix: resolve P1 issues in ActionTrace system
whatevertogo Jan 20, 2026
05e7674
Merge branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo Jan 20, 2026
1e727eb
Enhance ActionTrace Editor Window UI
whatevertogo Jan 20, 2026
2e161b7
Merge remote-tracking branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo Jan 20, 2026
9b24a2e
fix: enhance event handling and error logging in ActionTrace system
whatevertogo Jan 20, 2026
4609817
refactor: improve ActionTrace system architecture and UI
whatevertogo Jan 20, 2026
87280a8
refactor: update filter summary bar functionality and UI elements in …
whatevertogo Jan 20, 2026
eb14322
refactor: update comments and translations for clarity in ActionTrace…
whatevertogo Jan 20, 2026
4e4feae
fix: enhance sample eviction handling to prevent data loss in Samplin…
whatevertogo Jan 20, 2026
8920715
refactor: decouple Hooks system from ActionTrace via dependency injec…
whatevertogo Jan 21, 2026
6385944
Merge branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo Jan 21, 2026
0d4e6a4
Remove obsolete event capture and context management components
whatevertogo Jan 21, 2026
285fb20
feat: 添加 HookTest 脚本以验证 HookRegistry 事件的正确性
whatevertogo Jan 21, 2026
7831025
feat: add ActionTrace summary tool and enhance GlobalID resolution
whatevertogo Jan 21, 2026
6feadbf
feat: Update sampling config. Remove SamplingSettings and use hardcod…
whatevertogo Jan 21, 2026
456fc1c
Merge branch 'CoplayDev:main' into feature/ActionTrace
whatevertogo Jan 22, 2026
1044319
Refactor ActionTrace capture classes to streamline Undo functionality…
whatevertogo Jan 22, 2026
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
374 changes: 374 additions & 0 deletions MCPForUnity/Editor/ActionTrace/Analysis/Query/ActionTraceQuery.cs

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MCPForUnity.Editor.ActionTrace.Core.Models;
using MCPForUnity.Editor.ActionTrace.Core.Settings;
using MCPForUnity.Editor.ActionTrace.Helpers;

namespace MCPForUnity.Editor.ActionTrace.Analysis.Summarization
{
/// <summary>
/// Logical transaction aggregator for ActionTrace events.
///
/// Groups continuous events into "atomic operations" (logical transactions)
/// to reduce token consumption and improve AI efficiency.
///
/// Aggregation priority (from document ActionTrace-enhancements.md P1.1):
/// 1. ToolCallId boundary (strongest) - Different tool calls split
/// 2. TriggeredByTool boundary - Different tools split
/// 3. Time window boundary (from ActionTraceSettings.TransactionWindowMs) - User operations backup
///
/// Design principles:
/// - Query-time computation (does not modify stored events)
/// - Preserves EventStore immutability
/// - Compatible with semantic projection layer
///
/// Usage:
/// var operations = TransactionAggregator.Aggregate(events);
/// // Returns: 50 events → 3 AtomicOperation objects
/// </summary>
public static class TransactionAggregator
{
/// <summary>
/// Default time window for user operation aggregation (fallback if settings unavailable).
/// Events within 2 seconds are grouped if no ToolId information exists.
/// </summary>
private const long DefaultTransactionWindowMs = 2000;

/// <summary>
/// Aggregates a flat list of events into logical transactions.
///
/// Algorithm (from document decision tree):
/// 1. Check ToolCallId boundary (if exists)
/// 2. Check TriggeredByTool boundary (if exists)
/// 3. Fallback to 2-second time window
///
/// Returns a list of AtomicOperation objects, each representing
/// a logical group of events (e.g., one tool call).
/// </summary>
public static List<AtomicOperation> Aggregate(IReadOnlyList<EditorEvent> events)
{
if (events == null || events.Count == 0)
return new List<AtomicOperation>();

var result = new List<AtomicOperation>();
var currentBatch = new List<EditorEvent>(events.Count / 2); // Preallocate half capacity

for (int i = 0; i < events.Count; i++)
{
var evt = events[i];

if (currentBatch.Count == 0)
{
// First event starts a new batch
currentBatch.Add(evt);
continue;
}

var first = currentBatch[0];
if (ShouldSplit(first, evt))
{
// Boundary reached - finalize current batch
if (currentBatch.Count > 0)
result.Add(CreateAtomicOperation(currentBatch));

// Start new batch with current event - clear and reuse list
currentBatch.Clear();
currentBatch.Add(evt);
}
else
{
// Same transaction - add to current batch
currentBatch.Add(evt);
}
}

// Don't forget the last batch
if (currentBatch.Count > 0)
result.Add(CreateAtomicOperation(currentBatch));

return result;
}

/// <summary>
/// Determines if two events should be in different transactions.
///
/// Decision tree (from ActionTrace-enhancements.md line 274-290):
/// - Priority 1: ToolCallId boundary (mandatory split if different)
/// - Priority 2: TriggeredByTool boundary (mandatory split if different)
/// - Priority 3: Time window (from ActionTraceSettings.TransactionWindowMs, default 2000ms)
/// </summary>
private static bool ShouldSplit(EditorEvent first, EditorEvent current)
{
// Get transaction window from settings, with fallback to default
var settings = ActionTraceSettings.Instance;
long transactionWindowMs = settings?.Merging.TransactionWindowMs ?? DefaultTransactionWindowMs;

// Extract ToolCallId from Payload (if exists)
string firstToolCallId = GetToolCallId(first);
string currentToolCallId = GetToolCallId(current);

// ========== Priority 1: ToolCallId boundary ==========
// Split if tool call IDs differ (including null vs non-null for symmetry)
if (currentToolCallId != firstToolCallId)
return true; // Different tool call → split

// ========== Priority 2: TriggeredByTool boundary ==========
string firstTool = GetTriggeredByTool(first);
string currentTool = GetTriggeredByTool(current);

// Split if tools differ (including null vs non-null for symmetry)
if (currentTool != firstTool)
return true; // Different tool → split

// ========== Priority 3: Time window (user operations) ==========
// If no ToolId information, use configured time window
long timeDelta = current.TimestampUnixMs - first.TimestampUnixMs;
return timeDelta > transactionWindowMs;
}

/// <summary>
/// Creates an AtomicOperation from a batch of events.
///
/// Summary generation strategy:
/// - If tool_call_id exists: "ToolName: N events in X.Xs"
/// - If time-based: Use first event's summary + " + N-1 related events"
/// </summary>
private static AtomicOperation CreateAtomicOperation(List<EditorEvent> batch)
{
if (batch == null || batch.Count == 0)
throw new ArgumentException("Batch cannot be empty", nameof(batch));

var first = batch[0];
var last = batch[batch.Count - 1];

string toolCallId = GetToolCallId(first);
string toolName = GetTriggeredByTool(first);

// Generate summary
string summary = GenerateSummary(batch, toolCallId, toolName);

// Calculate duration
long durationMs = last.TimestampUnixMs - first.TimestampUnixMs;

return new AtomicOperation
{
StartSequence = first.Sequence,
EndSequence = last.Sequence,
Summary = summary,
EventCount = batch.Count,
DurationMs = durationMs,
ToolCallId = toolCallId,
TriggeredByTool = toolName
};
}

/// <summary>
/// Generates a human-readable summary for an atomic operation.
/// </summary>
private static string GenerateSummary(
List<EditorEvent> batch,
string toolCallId,
string toolName)
{
if (batch.Count == 1)
{
// Single event - use its summary
return EventSummarizer.Summarize(batch[0]);
}

// Multiple events
if (!string.IsNullOrEmpty(toolCallId))
{
// Tool call - use tool name + count
string displayName = string.IsNullOrEmpty(toolName)
? "AI operation"
: ActionTraceHelper.FormatToolName(toolName);

return $"{displayName}: {batch.Count} events in {ActionTraceHelper.FormatDurationFromRange(batch[0].TimestampUnixMs, batch[batch.Count - 1].TimestampUnixMs)}";
}

// Time-based aggregation - use first event + count
string firstSummary = EventSummarizer.Summarize(batch[0]);
return $"{firstSummary} + {batch.Count - 1} related events";
}

/// <summary>
/// Extracts tool_call_id from event Payload.
/// Returns null if not present.
/// </summary>
private static string GetToolCallId(EditorEvent evt) => evt.GetPayloadString("tool_call_id");

/// <summary>
/// Extracts triggered_by_tool from event Payload.
/// Returns null if not present.
/// </summary>
private static string GetTriggeredByTool(EditorEvent evt) => evt.GetPayloadString("triggered_by_tool");
}

/// <summary>
/// Represents a logical transaction (atomic operation) composed of multiple events.
///
/// Use cases:
/// - AI tool call grouping (e.g., "create_complex_object" → 50 events)
/// - User rapid operations (e.g., 5 component additions in 1.5s)
/// - Undo group alignment (one Ctrl+Z = one AtomicOperation)
///
/// From ActionTrace-enhancements.md P1.1, line 189-198.
/// </summary>
public sealed class AtomicOperation
{
/// <summary>
/// First event sequence number in this transaction.
/// </summary>
public long StartSequence { get; set; }

/// <summary>
/// Last event sequence number in this transaction.
/// </summary>
public long EndSequence { get; set; }

/// <summary>
/// Human-readable summary of the entire transaction.
/// Examples:
/// - "Manage GameObject: 50 events in 2.3s"
/// - "Added Rigidbody to Player + 4 related events"
/// </summary>
public string Summary { get; set; }

/// <summary>
/// Number of events in this transaction.
/// </summary>
public int EventCount { get; set; }

/// <summary>
/// Duration of the transaction in milliseconds.
/// Time from first event to last event.
/// </summary>
public long DurationMs { get; set; }

/// <summary>
/// Tool call identifier if this transaction represents a single tool call.
/// Null for time-based user operations.
/// </summary>
public string ToolCallId { get; set; }

/// <summary>
/// Tool name that triggered this transaction.
/// Examples: "manage_gameobject", "add_ActionTrace_note"
/// Null for user manual operations.
/// </summary>
public string TriggeredByTool { get; set; }
}
}
Loading