Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,35 @@ export function getTenantIdPair(turnContext: TurnContext): Array<[string, string
export function getChannelBaggagePairs(turnContext: TurnContext): Array<[string, string]> {
if (!turnContext) {
return [];
}
}

let subChannel = turnContext.activity?.channelIdSubChannel as string | undefined;

// Try to get subChannel from productContext in channelData if subChannel is not set or empty
if ((!subChannel || subChannel.trim() === '') && turnContext.activity?.channelData) {
try {
const channelData = turnContext.activity.channelData;
let channelDataObj: Record<string, unknown> | undefined;

// Convert channelData to object if it's a string
if (typeof channelData === 'string') {
channelDataObj = JSON.parse(channelData);
} else if (typeof channelData === 'object') {
channelDataObj = channelData as Record<string, unknown>;
}

// Extract productContext if available
if (channelDataObj && typeof channelDataObj.productContext === 'string') {
subChannel = channelDataObj.productContext;
}
} catch {
// Silently ignore any parsing errors
}
}

const pairs: Array<[string, string | undefined]> = [
[OpenTelemetryConstants.CHANNEL_NAME_KEY, turnContext.activity?.channelId],
[OpenTelemetryConstants.CHANNEL_LINK_KEY, turnContext.activity?.channelIdSubChannel as string | undefined]
[OpenTelemetryConstants.CHANNEL_LINK_KEY, subChannel]
];
return normalizePairs(pairs);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,90 @@ describe('BaggageMiddleware', () => {

expect(nextCalled).toBe(true);
});

it('should extract productContext from channelData when channelIdSubChannel is not set', async () => {
const middleware = new BaggageMiddleware();
const ctx: any = makeMockTurnContext({ channelId: 'msteams' });

// Add channelData with productContext, no channelIdSubChannel
Comment thread
gwharris7 marked this conversation as resolved.
ctx.activity.channelData = { productContext: 'COPILOT' };
ctx.activity.channelIdSubChannel = undefined;

let capturedChannelLink: string | undefined;

await middleware.onTurn(ctx, async () => {
const bag = propagation.getBaggage(otelContext.active());
if (bag) {
const entry = bag.getEntry(OpenTelemetryConstants.CHANNEL_LINK_KEY);
capturedChannelLink = entry?.value;
}
});

expect(capturedChannelLink).toBe('COPILOT');
});

it('should use channelIdSubChannel when both channelIdSubChannel and productContext are present', async () => {
const middleware = new BaggageMiddleware();
const ctx: any = makeMockTurnContext({ channelId: 'msteams' });

// Set BOTH channelIdSubChannel and productContext in channelData
ctx.activity.channelIdSubChannel = 'teams-subchannel';
ctx.activity.channelData = { productContext: 'COPILOT' };

let capturedChannelLink: string | undefined;

await middleware.onTurn(ctx, async () => {
const bag = propagation.getBaggage(otelContext.active());
if (bag) {
const entry = bag.getEntry(OpenTelemetryConstants.CHANNEL_LINK_KEY);
capturedChannelLink = entry?.value;
}
});

// channelIdSubChannel should take precedence, productContext should be ignored
expect(capturedChannelLink).toBe('teams-subchannel');
});

it('should extract productContext from channelData when it is a JSON string', async () => {
const middleware = new BaggageMiddleware();
const ctx: any = makeMockTurnContext({ channelId: 'msteams' });

// Set channelData as a JSON string (simulating wire format)
ctx.activity.channelIdSubChannel = undefined;
ctx.activity.channelData = JSON.stringify({ productContext: 'COPILOT' });

let capturedChannelLink: string | undefined;

await middleware.onTurn(ctx, async () => {
const bag = propagation.getBaggage(otelContext.active());
if (bag) {
const entry = bag.getEntry(OpenTelemetryConstants.CHANNEL_LINK_KEY);
capturedChannelLink = entry?.value;
}
});

expect(capturedChannelLink).toBe('COPILOT');
});

it('should not set channel link when channelData is invalid JSON', async () => {
const middleware = new BaggageMiddleware();
const ctx: any = makeMockTurnContext({ channelId: 'msteams' });

// Set channelData as an invalid JSON string
ctx.activity.channelIdSubChannel = undefined;
ctx.activity.channelData = 'not valid json';

let capturedChannelLink: string | undefined;

await middleware.onTurn(ctx, async () => {
const bag = propagation.getBaggage(otelContext.active());
if (bag) {
const entry = bag.getEntry(OpenTelemetryConstants.CHANNEL_LINK_KEY);
capturedChannelLink = entry?.value;
}
});

// Channel link should not be set when JSON parsing fails
expect(capturedChannelLink).toBeUndefined();
});
});
Loading