From 5325f53915dac7290e656966eb4f1f69a60c79b9 Mon Sep 17 00:00:00 2001 From: MehakBindra Date: Fri, 28 Aug 2026 17:34:35 -0700 Subject: [PATCH 1/2] fix(api): type Activity timestamps as strings Keep the fluent timestamp setters for compatibility, normalize Date inputs to ISO strings, and mark them deprecated because outgoing timestamps are ignored. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1f4358e5-fe2f-401c-a10b-d2bab35524fe --- packages/api/src/activities/activity.spec.ts | 22 +++++++++++++--- packages/api/src/activities/activity.ts | 26 +++++++++++++------ .../activities/event/agent-lifecycle.spec.ts | 2 +- packages/devtools/src/stores/ChatStore.ts | 8 ++++-- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/packages/api/src/activities/activity.spec.ts b/packages/api/src/activities/activity.spec.ts index caed9a532..0e9cb90ad 100644 --- a/packages/api/src/activities/activity.spec.ts +++ b/packages/api/src/activities/activity.spec.ts @@ -35,8 +35,8 @@ describe('Activity', () => { }) .withRecipient(bot) .withServiceUrl('http://localhost') - .withTimestamp(new Date()) - .withLocalTimestamp(new Date()); + .withTimestamp(new Date('2026-06-04T21:00:00.000Z')) + .withLocalTimestamp('2026-06-04T14:00:00.000-07:00'); expect(activity.id).toEqual('1'); expect(activity.type).toEqual('test'); @@ -52,8 +52,22 @@ describe('Activity', () => { expect(activity.recipient).toEqual(bot); expect(activity.serviceUrl).toEqual('http://localhost'); - expect(activity.timestamp).toBeDefined(); - expect(activity.localTimestamp).toBeDefined(); + expect(activity.timestamp).toEqual('2026-06-04T21:00:00.000Z'); + expect(activity.localTimestamp).toEqual('2026-06-04T14:00:00.000-07:00'); + }); + + it('should preserve timestamp strings from constructor data', () => { + const timestamp = '2026-06-04T21:00:00.000Z'; + const localTimestamp = '2026-06-04T14:00:00.000-07:00'; + + const activity = new Activity({ + type: 'test', + timestamp, + localTimestamp, + }); + + expect(activity.timestamp).toEqual(timestamp); + expect(activity.localTimestamp).toEqual(localTimestamp); }); it('should build from interface', () => { diff --git a/packages/api/src/activities/activity.ts b/packages/api/src/activities/activity.ts index 974d281e2..cc065b1eb 100644 --- a/packages/api/src/activities/activity.ts +++ b/packages/api/src/activities/activity.ts @@ -34,7 +34,7 @@ export interface IActivity { /** * Contains the date and time that the message was sent, in UTC, expressed in ISO-8601 format. */ - timestamp?: Date; + timestamp?: string; /** * A locale name for the contents of the text field. @@ -50,7 +50,7 @@ export interface IActivity { * * For example, 2016-09-23T13:07:49.4714686-07:00. */ - localTimestamp?: Date; + localTimestamp?: string; /** * Contains an ID that uniquely identifies the channel. Set by the channel. @@ -460,7 +460,7 @@ export class Activity implements IActivity { /** * Contains the date and time that the message was sent, in UTC, expressed in ISO-8601 format. */ - timestamp?: Date; + timestamp?: string; /** * A locale name for the contents of the text field. @@ -476,7 +476,7 @@ export class Activity implements IActivity { * * For example, 2016-09-23T13:07:49.4714686-07:00. */ - localTimestamp?: Date; + localTimestamp?: string; /** * Contains an ID that uniquely identifies the channel. Set by the channel. @@ -626,8 +626,13 @@ export class Activity implements IActivity { return this; } - withTimestamp(value: Date) { - this.timestamp = value; + /** + * Sets the activity timestamp as an ISO-8601 string. + * + * @deprecated Timestamps set on outgoing activities are ignored. + */ + withTimestamp(value: Date | string) { + this.timestamp = value instanceof Date ? value.toISOString() : value; return this; } @@ -636,8 +641,13 @@ export class Activity implements IActivity { return this; } - withLocalTimestamp(value: Date) { - this.localTimestamp = value; + /** + * Sets the activity's local timestamp as an ISO-8601 string. + * + * @deprecated Local timestamps set on outgoing activities are ignored. + */ + withLocalTimestamp(value: Date | string) { + this.localTimestamp = value instanceof Date ? value.toISOString() : value; return this; } diff --git a/packages/api/src/activities/event/agent-lifecycle.spec.ts b/packages/api/src/activities/event/agent-lifecycle.spec.ts index bad16a679..5c325603b 100644 --- a/packages/api/src/activities/event/agent-lifecycle.spec.ts +++ b/packages/api/src/activities/event/agent-lifecycle.spec.ts @@ -15,7 +15,7 @@ const BLUEPRINT_ID = '00000000-0000-0000-0000-000000000005'; const baseActivity = { type: 'event', id: 'activity-id', - timestamp: new Date('2026-06-29T00:00:00Z'), + timestamp: '2026-06-29T00:00:00Z', serviceUrl: 'https://smba.trafficmanager.net/amer/tenant/', channelId: 'agents', from: { id: 'system', name: 'System', role: 'bot', tenantId: TENANT_ID }, diff --git a/packages/devtools/src/stores/ChatStore.ts b/packages/devtools/src/stores/ChatStore.ts index 1809bc46b..d36dcfbe7 100644 --- a/packages/devtools/src/stores/ChatStore.ts +++ b/packages/devtools/src/stores/ChatStore.ts @@ -40,6 +40,10 @@ interface MessageBase { createdDateTime: string; } +const toUTCString = (value?: string | Date) => { + return (value instanceof Date ? value : new Date(value || Date.now())).toUTCString(); +}; + const createMessageBase = ( event: ActivityEvent ): MessageBase => { @@ -66,7 +70,7 @@ const createMessageBase = ( } : undefined, }, - createdDateTime: (event.body.timestamp || new Date()).toUTCString(), + createdDateTime: toUTCString(event.body.timestamp), }; }; @@ -303,7 +307,7 @@ export const useChatStore = create()( message.body.textContent = event.body.text; } - message.lastModifiedDateTime = (event.body.timestamp || new Date()).toUTCString(); + message.lastModifiedDateTime = toUTCString(event.body.timestamp); state.put(state.chat.id, message); return state; }, From f389ecda645f72f49da39c43bfc5dd4a60f4e3b7 Mon Sep 17 00:00:00 2001 From: Mehak Bindra Date: Fri, 28 Aug 2026 17:54:42 -0700 Subject: [PATCH 2/2] Clarify deprecation messages for timestamp methods Updated deprecation messages for timestamp methods to provide clearer guidance on using ActivityInput. --- packages/api/src/activities/activity.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api/src/activities/activity.ts b/packages/api/src/activities/activity.ts index cc065b1eb..eafb782c6 100644 --- a/packages/api/src/activities/activity.ts +++ b/packages/api/src/activities/activity.ts @@ -629,7 +629,7 @@ export class Activity implements IActivity { /** * Sets the activity timestamp as an ISO-8601 string. * - * @deprecated Timestamps set on outgoing activities are ignored. + * @deprecated Use ActivityInput/MessageActivityInput/TypingActivityInput when constructing outbound activities. */ withTimestamp(value: Date | string) { this.timestamp = value instanceof Date ? value.toISOString() : value; @@ -644,7 +644,7 @@ export class Activity implements IActivity { /** * Sets the activity's local timestamp as an ISO-8601 string. * - * @deprecated Local timestamps set on outgoing activities are ignored. + * @deprecated Use ActivityInput/MessageActivityInput/TypingActivityInput when constructing outbound activities. */ withLocalTimestamp(value: Date | string) { this.localTimestamp = value instanceof Date ? value.toISOString() : value;