-
Notifications
You must be signed in to change notification settings - Fork 436
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a52e352
commit 6ea7da1
Showing
10 changed files
with
225 additions
and
163 deletions.
There are no files selected for viewing
132 changes: 132 additions & 0 deletions
132
packages/core/src/amazonq/messages/chatMessageDuration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/*! | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { globals } from '../../shared' | ||
import { telemetry } from '../../shared/telemetry' | ||
import { MetadataEntry, MetricDatum } from '../../shared/telemetry/clienttelemetry' | ||
import { TelemetrySpan } from '../../shared/telemetry/spans' | ||
import { uiEventRecorder } from '../util/eventRecorder' | ||
import { ChatSessionStorageFacade } from '../util/storageFacade' | ||
import { TabType } from '../webview/ui/storages/tabsStorage' | ||
|
||
export class AmazonQChatMessageDuration { | ||
/** | ||
* Listen to all incoming telemetry events. If one of them has cwsprChatConversationId or amazonQConversationId | ||
* then it is considered an Amazon Q event that we want to track. | ||
* | ||
* We build up all the Amazon Q events we want to track by conversation ID | ||
* | ||
* This allows us to eventually connect metadata coming from a conversation ID with metadata coming from a tabID. Tabs know nothing | ||
* of conversation IDs and conversation IDs have no knowledge of tabIDs except for in chat session storages. | ||
* | ||
* In the flow Webview -> Message Dispatcher -> Amazon Q Feature -> Amazon Q Feature Implementation -> Message Dispatcher -> Webview | ||
* only "Amazon Q Feature Implementation" has knowledge about conversation IDs | ||
* everything else has knowledge of tabIDs | ||
*/ | ||
static initializeListener() { | ||
telemetry.chat_roundTrip.listen( | ||
(metric: MetricDatum) => { | ||
if (!metric.Metadata) { | ||
return false | ||
} | ||
|
||
return metric.Metadata.some((k: MetadataEntry) => k.Key === 'cwsprChatConversationId') | ||
}, | ||
(_: TelemetrySpan, metric: MetricDatum) => { | ||
if (!metric.Metadata) { | ||
return | ||
} | ||
const conversationId = metric.Metadata.find((x: any) => x.Key === 'cwsprChatConversationId')?.Value | ||
if (!conversationId) { | ||
return | ||
} | ||
uiEventRecorder.set(conversationId, { | ||
events: { | ||
[metric.MetricName]: metric.EpochTimestamp, | ||
}, | ||
}) | ||
} | ||
) | ||
} | ||
|
||
/** | ||
* Record the initial requests in the chat message flow | ||
*/ | ||
static startListening(tabID: string, startTime: number, trigger?: string) { | ||
// listen to all events for this tab | ||
uiEventRecorder.set(tabID, { | ||
events: { | ||
initialRequestTime: startTime, | ||
}, | ||
}) | ||
uiEventRecorder.set(tabID, { | ||
events: { | ||
webviewToDispatcher: globals.clock.Date.now(), | ||
}, | ||
}) | ||
if (trigger) { | ||
uiEventRecorder.set(tabID, { | ||
trigger, | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* Stop listening to all incoming events and emit what we've found | ||
*/ | ||
static stopListening(msg: { tabID: string; tabType: TabType }, chatSessionFacade: ChatSessionStorageFacade) { | ||
const { tabID, tabType } = msg | ||
|
||
uiEventRecorder.set(tabID, { | ||
events: { | ||
finalRequestTime: globals.clock.Date.now(), | ||
}, | ||
}) | ||
|
||
const conversationId = chatSessionFacade.getConversationId(tabType, tabID) | ||
if (!conversationId) { | ||
return | ||
} | ||
|
||
/** | ||
* Consolidate all the events we know about tabID with all the telemetry events that happened inside of that | ||
* conversation in the tab | ||
*/ | ||
const tabUIMetrics = uiEventRecorder.get(tabID) | ||
const conversationMetrics = uiEventRecorder.get(conversationId) | ||
|
||
// get metrics sorted by the time they were created | ||
const allMetrics = Object.entries({ ...tabUIMetrics.events, ...conversationMetrics.events }).sort((a, b) => { | ||
return a[1] - b[1] | ||
}) | ||
|
||
// Get the total duration by subtracting the last (finalRequestTime) and the first duration (initialRequestTime) | ||
const totalDuration = allMetrics[allMetrics.length - 1][1] - allMetrics[0][1] | ||
|
||
// Find the time difference between current metric and current metric - 1 | ||
const differences = new Map<string, number>() | ||
for (let i = 1; i < allMetrics.length; i++) { | ||
const currentEvent = allMetrics[i] | ||
const previousEvent = allMetrics[i - 1] | ||
|
||
const timeDifference = currentEvent[1] - previousEvent[1] | ||
|
||
differences.set(currentEvent[0], timeDifference) | ||
} | ||
|
||
const flowName = tabUIMetrics.trigger ?? conversationMetrics.trigger ?? 'unknown' | ||
|
||
telemetry.chat_roundTrip.emit({ | ||
duration: totalDuration, | ||
name: flowName, | ||
child_metrics: allMetrics.map((x) => x[0]), | ||
child_metric_durations: JSON.stringify(Object.fromEntries(differences)), | ||
result: 'Succeeded', | ||
} as any) | ||
|
||
uiEventRecorder.delete(tabID) | ||
uiEventRecorder.delete(conversationId) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/*! | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { MetricName } from '../../shared/telemetry/clienttelemetry' | ||
import { RecordMap } from '../../shared/utilities/map' | ||
|
||
type Event = | ||
| 'initialRequestTime' // initial on chat prompt event in the ui | ||
| 'webviewToDispatcher' // message gets from the chat prompt to VSCode | ||
| 'dispatcherToFeature' // message gets redirected from VSCode -> Partner team features implementation | ||
| MetricName // any telemetry event emitted between when the partner teams code gets the original message to when its sent to the UI | ||
| 'finalRequestTime' // message gets received in the UI | ||
|
||
/** | ||
* For a given conversation ID or tabID, map an event to a time | ||
*/ | ||
export const uiEventRecorder = new RecordMap<{ | ||
trigger: string | ||
events: Record<Event, number> | ||
}>() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.