@csntgao/ai-employee-client 0.15.5 → 0.15.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -171,6 +171,7 @@ declare class AiEmployeeClient {
171
171
  private socketAuthenticationFailure;
172
172
  private availabilityReconnectAttempt;
173
173
  private pendingFirstMessage;
174
+ private sessionListResolved;
174
175
  constructor(options: AiEmployeeClientOptions);
175
176
  get connectionState(): AiEmployeeConnectionState;
176
177
  get sessionId(): string | null;
@@ -419,6 +420,7 @@ declare class CustomerSupportClient {
419
420
  private readonly readCursorStates;
420
421
  private readLifecycleGeneration;
421
422
  private requestedSessionId;
423
+ private sessionListResolved;
422
424
  constructor(options: CustomerSupportClientOptions);
423
425
  get session(): CustomerSupportSession | null;
424
426
  get messages(): readonly CustomerSupportMessage[];
package/dist/index.js CHANGED
@@ -502,6 +502,7 @@ var AiEmployeeClient = class {
502
502
  socketAuthenticationFailure = null;
503
503
  availabilityReconnectAttempt = 0;
504
504
  pendingFirstMessage = null;
505
+ sessionListResolved;
505
506
  constructor(options) {
506
507
  this.realtimeUrl = validateRealtimeUrl(options.realtimeUrl);
507
508
  this.aeCode = requiredText(options.aeCode, "aeCode");
@@ -517,6 +518,7 @@ var AiEmployeeClient = class {
517
518
  }
518
519
  this.transport = options.transport;
519
520
  this.currentSessionId = normalizeSessionId(options.sessionId);
521
+ this.sessionListResolved = Boolean(this.currentSessionId) || typeof options.transport.listSessions !== "function";
520
522
  this.reconnectOptions = normalizeReconnectOptions(options.reconnect);
521
523
  this.minimumHeartbeatMs = Math.max(1, options.minimumHeartbeatMs ?? 5e3);
522
524
  this.requestIdFactory = options.requestIdFactory ?? createRequestId;
@@ -573,6 +575,7 @@ var AiEmployeeClient = class {
573
575
  const lifecycle = ++this.lifecycleGeneration;
574
576
  this.stopConnection(false);
575
577
  this.currentSessionId = target;
578
+ this.sessionListResolved = true;
576
579
  this.currentMessages = [];
577
580
  this.seenMessageIds.clear();
578
581
  this.pendingLocalMessages.clear();
@@ -596,6 +599,7 @@ var AiEmployeeClient = class {
596
599
  this.lifecycleGeneration += 1;
597
600
  this.stopConnection(false);
598
601
  this.currentSessionId = null;
602
+ this.sessionListResolved = true;
599
603
  this.currentMessages = [];
600
604
  this.seenMessageIds.clear();
601
605
  this.pendingLocalMessages.clear();
@@ -622,12 +626,18 @@ var AiEmployeeClient = class {
622
626
  if (!normalizedContent) {
623
627
  throw new AiEmployeeClientError("EMPTY_MESSAGE", "\u6D88\u606F\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\u3002");
624
628
  }
625
- if (this.sending) {
629
+ if (this.sending || this.processing) {
626
630
  throw new AiEmployeeClientError("SEND_IN_PROGRESS", "\u4E0A\u4E00\u6761\u6D88\u606F\u4ECD\u5728\u53D1\u9001\u4E2D\u3002");
627
631
  }
628
632
  this.sending = true;
629
633
  try {
630
634
  const sessionId = this.currentSessionId;
635
+ if (!sessionId && !this.sessionListResolved) {
636
+ throw new AiEmployeeClientError(
637
+ "SESSION_UNAVAILABLE",
638
+ "\u6700\u8FD1\u4E00\u6761\u6570\u5B57\u5458\u5DE5\u4F1A\u8BDD\u5C1A\u672A\u6062\u590D\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
639
+ );
640
+ }
631
641
  return sessionId ? await this.sendFollowUp(sessionId, normalizedContent) : await this.sendFirstMessage(normalizedContent, options);
632
642
  } catch (error) {
633
643
  if (error instanceof AiEmployeeClientError) throw error;
@@ -671,8 +681,14 @@ var AiEmployeeClient = class {
671
681
  }
672
682
  async sendFollowUp(sessionId, content) {
673
683
  this.assistantReceivedInCurrentTurn = false;
674
- await this.transport.sendMessage(sessionId, content);
675
- this.assertUsable();
684
+ this.rememberPendingLocalMessage(content);
685
+ try {
686
+ await this.transport.sendMessage(sessionId, content);
687
+ this.assertUsable();
688
+ } catch (error) {
689
+ this.pendingLocalMessages.delete(content);
690
+ throw error;
691
+ }
676
692
  const now = /* @__PURE__ */ new Date();
677
693
  const message = {
678
694
  id: `local:${now.getTime()}:${++this.localMessageSequence}`,
@@ -681,7 +697,6 @@ var AiEmployeeClient = class {
681
697
  content,
682
698
  createdAt: now.toISOString()
683
699
  };
684
- this.rememberPendingLocalMessage(content);
685
700
  this.appendMessage(message, "local");
686
701
  this.setProcessing(true);
687
702
  return message;
@@ -737,6 +752,17 @@ var AiEmployeeClient = class {
737
752
  return message;
738
753
  }
739
754
  async initialize(lifecycle) {
755
+ const listSessions = this.transport.listSessions;
756
+ if (!this.currentSessionId && listSessions && !this.sessionListResolved) {
757
+ const sessions = await listSessions.call(this.transport);
758
+ this.assertUsable();
759
+ if (!this.isCurrentLifecycle(lifecycle)) {
760
+ throw new AiEmployeeClientError("SESSION_UNAVAILABLE", "\u4F1A\u8BDD\u6062\u590D\u5DF2\u88AB\u65B0\u7684\u64CD\u4F5C\u66FF\u4EE3\u3002");
761
+ }
762
+ this.currentSessionId = latestAiEmployeeSession(sessions)?.sessionId ?? null;
763
+ this.sessionListResolved = true;
764
+ if (this.currentSessionId) await this.clearStoredFirstMessageRequest();
765
+ }
740
766
  if (!this.currentSessionId) {
741
767
  this.shouldReconnect = true;
742
768
  this.openSocket(false);
@@ -1182,6 +1208,21 @@ var AiEmployeeClient = class {
1182
1208
  }
1183
1209
  }
1184
1210
  };
1211
+ function latestAiEmployeeSession(sessions) {
1212
+ return latestUpdatedSession(sessions, (session) => session.updatedAt);
1213
+ }
1214
+ function latestUpdatedSession(sessions, updatedAt) {
1215
+ let latest = null;
1216
+ let latestTimestamp = Number.NEGATIVE_INFINITY;
1217
+ for (const session of sessions) {
1218
+ const timestamp = Date.parse(updatedAt(session));
1219
+ if (latest === null || Number.isFinite(timestamp) && timestamp > latestTimestamp) {
1220
+ latest = session;
1221
+ latestTimestamp = Number.isFinite(timestamp) ? timestamp : latestTimestamp;
1222
+ }
1223
+ }
1224
+ return latest;
1225
+ }
1185
1226
  function safeAssistantStreamContent(content) {
1186
1227
  const parsed = parseAiEmployeeAssistantContent(content);
1187
1228
  if (parsed.actions.length > 0 || parsed.rejectedActionTypes?.length) return parsed.content;
@@ -1521,6 +1562,7 @@ var CustomerSupportClient = class {
1521
1562
  readCursorStates = /* @__PURE__ */ new Map();
1522
1563
  readLifecycleGeneration = 0;
1523
1564
  requestedSessionId;
1565
+ sessionListResolved = false;
1524
1566
  constructor(options) {
1525
1567
  this.realtimeUrl = validateRealtimeUrl2(options.realtimeUrl);
1526
1568
  if (!options.transport) {
@@ -1564,10 +1606,9 @@ var CustomerSupportClient = class {
1564
1606
  const sessions = await this.transport.listSessions();
1565
1607
  this.assertUsable();
1566
1608
  this.replaceSessions(sessions);
1609
+ this.sessionListResolved = true;
1567
1610
  const requested = this.requestedSessionId;
1568
- this.currentSession = requested ? sessions.find((session) => session.id === requested) ?? null : sessions.find(
1569
- (session) => session.status !== "closed" && hasCustomerSupportMessages(session)
1570
- ) ?? sessions.find(hasCustomerSupportMessages) ?? null;
1611
+ this.currentSession = requested ? sessions.find((session) => session.id === requested) ?? null : latestCustomerSupportSession(sessions);
1571
1612
  if (this.currentSession) {
1572
1613
  this.emit("session", { session: this.currentSession });
1573
1614
  await this.refreshHistory();
@@ -1585,12 +1626,14 @@ var CustomerSupportClient = class {
1585
1626
  this.currentSession = null;
1586
1627
  this.requestedSessionId = null;
1587
1628
  this.currentMessages = [];
1629
+ this.sessionListResolved = true;
1588
1630
  }
1589
1631
  async bindSession(sessionId) {
1590
1632
  this.assertUsable();
1591
1633
  const normalized = requiredText2(sessionId, "sessionId");
1592
1634
  const sessions = await this.transport.listSessions();
1593
1635
  this.replaceSessions(sessions);
1636
+ this.sessionListResolved = true;
1594
1637
  const session = sessions.find((candidate) => candidate.id === normalized);
1595
1638
  if (!session) {
1596
1639
  throw new CustomerSupportClientError("SESSION_UNAVAILABLE", "\u5BA2\u670D\u4F1A\u8BDD\u4E0D\u5B58\u5728\u3002");
@@ -1610,6 +1653,12 @@ var CustomerSupportClient = class {
1610
1653
  this.sending = true;
1611
1654
  try {
1612
1655
  if (!this.currentSession) {
1656
+ if (!this.sessionListResolved) {
1657
+ throw new CustomerSupportClientError(
1658
+ "SESSION_UNAVAILABLE",
1659
+ "\u6700\u8FD1\u4E00\u6761\u4EBA\u5DE5\u5BA2\u670D\u4F1A\u8BDD\u5C1A\u672A\u6062\u590D\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"
1660
+ );
1661
+ }
1613
1662
  const result = await this.transport.createSession({
1614
1663
  clientRequestId: requiredRequestId2(this.requestIdFactory()),
1615
1664
  title: normalized.slice(0, 30),
@@ -2187,8 +2236,17 @@ function compareReadCursors(left, right) {
2187
2236
  function maxReadCursor(left, right) {
2188
2237
  return left && compareReadCursors(left, right) >= 0 ? left : right;
2189
2238
  }
2190
- function hasCustomerSupportMessages(session) {
2191
- return session.lastMessage.trim().length > 0;
2239
+ function latestCustomerSupportSession(sessions) {
2240
+ let latest = null;
2241
+ let latestTimestamp = Number.NEGATIVE_INFINITY;
2242
+ for (const session of sessions) {
2243
+ const timestamp = Date.parse(session.updatedAt);
2244
+ if (latest === null || Number.isFinite(timestamp) && timestamp > latestTimestamp) {
2245
+ latest = session;
2246
+ latestTimestamp = Number.isFinite(timestamp) ? timestamp : latestTimestamp;
2247
+ }
2248
+ }
2249
+ return latest;
2192
2250
  }
2193
2251
  function requiredText2(value, field) {
2194
2252
  const normalized = normalizedText(value);