Skip to content

Conversation

@yemohyleyemohyle
Copy link
Contributor

Refactor microsoft internal telemetry for agent mode to be sent in smaller events to avoid high drop rate. This is specifically targeted to substitute engine.messages events that attempt to send entire input to each model call, which includes all the messages from the conversation history up to the moment and contains lots of duplicates

Copy link
Member

@roblourens roblourens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really sad that we have to do this at this layer but thanks for doing it! I worry that telemetry could still be too lossy to reconstruct the trajectories but I hope it works. I think I mostly follow it but just a few questions.

telemetryService.sendInternalMSFTTelemetryEvent('engine.messages', multiplexProperties(telemetryDataWithPrompt.properties), telemetryDataWithPrompt.measurements);

// Send all model telemetry events (model.request.added, model.message.added, model.modelCall.input/output, model.request.options.added)
// Comment out the line below to disable the new deduplicated model telemetry events
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the comment about disabling it, is that something somebody needs to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully not. At the moment the existing engine.messages event and model.... events I am adding are substitutes of each other. So after conformation that the new schema works better we would disable engine.messages events. In case the new schema (shorter events but more of them) still does not help with drop rate, it may be disabled.

* If it's the same conversationId, increments the turn.
* Returns the current conversationTurn for the conversationId.
*/
function updateConversationTracker(conversationId: string): number {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this wrong when you have more than one conversation going at a time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are parallel conversations allowed by UI? It would be then. I changed the conversationTracker to allow for parallel conversations.

return;
}

// Check if this is a conversation mode (has conversationId) or supplementary mode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When do we not have a conversationId?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see conversationId available when semantic_search has its own model call, or edit healing ... I called it supplementary mode.

}).toString();

// Get existing UUID for this message content + headerRequestId combination, or generate a new one
let messageUuid = messageHashToUuid.get(messageHash);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we send the hashes instead of having to map it to uuids? So that we can even track conversatations that continue after reloading the window, etc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I have no idea if that would be allowed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I follow here. If the question is why don't we use hash itself instead of creating messageUuids? I was not sure how large those hashes could be, so used a standard uuid.

}

function sendModelCallTelemetry(telemetryService: ITelemetryService, messageData: Array<{ uuid: string; headerRequestId: string }>, telemetryData: TelemetryData, messageDirection: 'input' | 'output', logService?: ILogService) {
// Get the unique model call ID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I understand what this function is doing, what's a "model call"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For every model call, there’s an input array of messages and an output array containing a single message.
This function doesn’t send the full messages directly. Instead, it sends events with an array of messageUuids (unique message identifiers).
For example, if the agent takes n turns, there are n model calls. A system message will appear at the start of each input array across all n turns. Rather than sending the entire system message n times, we send it once in a model.message.added event. Then, in each of the model.modelCall events, we only include the corresponding messageUuid and its position in the array.

roblourens
roblourens previously approved these changes Sep 9, 2025
@vs-code-engineering vs-code-engineering bot added this to the September 2025 milestone Sep 9, 2025
…d version of new model... events

Comment out the internal MSFT telemetry event sending.
Copilot AI review requested due to automatic review settings September 9, 2025 17:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors internal Microsoft telemetry for agent mode to reduce event size and eliminate duplicates by sending telemetry in smaller, deduplicated events instead of the large engine.messages events that contain entire conversation histories.

Key Changes

  • Introduces new granular telemetry events (model.request.added, model.message.added, model.modelCall.input/output, model.request.options.added) that use deduplication via LRU caches and UUID mapping
  • Comments out the internal MSFT engine.messages event to reduce telemetry volume while keeping the enhanced GitHub telemetry
  • Updates the existing engine.messages.length telemetry to use a new TelemetryData.createAndMarkAsIssued pattern instead of extendedBy

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/platform/networking/node/chatStream.ts Adds comprehensive deduplication logic for model telemetry events with LRU caches and UUID tracking, plus modifications to existing length telemetry
src/extension/conversation/vscode-node/test/interactiveSessionProvider.telemetry.test.ts Updates integration test to verify the new model telemetry events are sent correctly
Comments suppressed due to low confidence (1)

src/platform/networking/node/chatStream.ts:1

  • This TODO comment indicates that telemetry functions are misplaced in a chat stream file. Consider moving these telemetry functions to a dedicated telemetry module to improve code organization and separation of concerns.
/*---------------------------------------------------------------------------------------------

Comment on lines +449 to +450
//telemetryService.sendInternalMSFTTelemetryEvent('engine.messages', multiplexProperties(telemetryDataWithPrompt.properties), telemetryDataWithPrompt.measurements);

Copy link

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace the commented-out code with a clear explanation of why this telemetry event was disabled, or remove it entirely if it's permanently disabled. Commented-out code can cause confusion and should be avoided in production.

Suggested change
//telemetryService.sendInternalMSFTTelemetryEvent('engine.messages', multiplexProperties(telemetryDataWithPrompt.properties), telemetryDataWithPrompt.measurements);

Copilot uses AI. Check for mistakes.
//telemetryService.sendInternalMSFTTelemetryEvent('engine.messages', multiplexProperties(telemetryDataWithPrompt.properties), telemetryDataWithPrompt.measurements);

// Send all model telemetry events (model.request.added, model.message.added, model.modelCall.input/output, model.request.options.added)
// Comment out the line below to disable the new deduplicated model telemetry events
Copy link

Copilot AI Sep 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment appears to be development instructions rather than production documentation. Consider either removing this comment or replacing it with proper documentation explaining the purpose of the telemetry events.

Suggested change
// Comment out the line below to disable the new deduplicated model telemetry events
// The following line sends deduplicated model telemetry events to track user requests, message additions, model calls, and request options.

Copilot uses AI. Check for mistakes.
Comment out the old telemetry event sending method for testing.
@roblourens roblourens added this pull request to the merge queue Sep 9, 2025
Merged via the queue into microsoft:main with commit 37b4318 Sep 9, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants