@tagit/ai-client-core 0.4.1 → 0.6.0-beta.0

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/README.md CHANGED
@@ -52,6 +52,18 @@ import { AIClient, createDefaultConfig } from '@tagit/ai-client-core';
52
52
 
53
53
  const client = new AIClient(
54
54
  createDefaultConfig('uc-default-1lji40', 'https://ai.tagit.live', {
55
+ user: {
56
+ entityId: 'anonymous-or-authenticated-user-id',
57
+ userId: 'optional-friendly-user-id',
58
+ entityidType: 'internal_user_id',
59
+ entityidAlgo: 'native',
60
+ entityidOwner: 'your-service',
61
+ },
62
+ conversation: {
63
+ conversationId: 'optional-durable-conversation-id',
64
+ title: 'Optional conversation title',
65
+ memoryMaxTurns: 6,
66
+ },
55
67
  orchestrator: {
56
68
  apiKey: import.meta.env.VITE_TAGIT_AI_ORCHESTRATOR_API_KEY,
57
69
  },
@@ -68,7 +80,7 @@ const client = new AIClient(
68
80
 
69
81
  `AIClient` is the stateful engine:
70
82
 
71
- - builds the `/v1/chat` request
83
+ - builds the `/v2/chat` request
72
84
  - manages the conversation transcript
73
85
  - streams assistant output
74
86
  - retries transient failures
@@ -81,7 +93,7 @@ const client = new AIClient(
81
93
 
82
94
  ### `OrchestratorRequest`
83
95
 
84
- `OrchestratorRequest` is the payload posted to the orchestrator `/v1/chat` endpoint.
96
+ `OrchestratorRequest` is the payload posted to the orchestrator `/v2/chat` endpoint.
85
97
 
86
98
  ### `OrchestratorChunk`
87
99
 
@@ -106,14 +118,38 @@ const config = createDefaultConfig('uc-default-1lji40', 'https://ai.tagit.live',
106
118
  | Field | Type / values | Default | What it does | Example |
107
119
  |---|---|---:|---|---|
108
120
  | `useCaseId` | `string` | required | Runtime use case identifier used by the orchestrator. | `'uc-default-1lji40'` |
109
- | `orchestratorUrl` | URL string | required | Base URL for the orchestrator. Do not include `/v1/chat`. | `'https://ai.tagit.live'` |
121
+ | `orchestratorUrl` | URL string | required | Base URL for the orchestrator. Do not include `/v2/chat`. | `'https://ai.tagit.live'` |
110
122
  | `options.orchestrator` | partial orchestrator config | `undefined` | Overrides specific orchestrator fields. | `{ apiKey: '...' }` |
123
+ | `options.user` | user identity config | `undefined` | Shared identity used by orchestrator memory and collector events. | `{ entityId: 'user_123' }` |
124
+ | `options.conversation` | conversation config | `undefined` | Durable conversation id, title, and memory window. | `{ memoryMaxTurns: 6 }` |
111
125
  | `options.collector` | partial collector config | `undefined` | Enables or customizes collector emission. | `{ enabled: false }` |
112
126
  | `options.ui` | partial UI config | `undefined` | Overrides client UI/runtime behavior. | `{ streaming: true }` |
113
127
 
128
+ ### Shared User Config
129
+
130
+ The `user` block is the single identity source for V2. At minimum, production integrations should provide `user.entityId`. When `user.userId` is omitted, the SDK uses `user.entityId` as the orchestrator `user_id` and collector `content.contentData.userId`.
131
+
132
+ | Field | Type / values | Required | What it does | Example |
133
+ |---|---|---:|---|---|
134
+ | `user.entityId` | string | yes for production | Primary user or anonymous entity identifier supplied by the host app. | `visitor_abc123` |
135
+ | `user.userId` | string | no | Optional friendly/application user id. Defaults to `entityId`. | `sandro` |
136
+ | `user.entityidType` | string | no | Entity type metadata for collector normalization. | `internal_user_id` |
137
+ | `user.entityidAlgo` | string | no | Entity ID algorithm metadata. | `native` |
138
+ | `user.entityidOwner` | string | no | Entity owner metadata. | `tagit.live` |
139
+
140
+ ### Shared Conversation Config
141
+
142
+ The `conversation` block controls durable memory. The SDK sends only the current user message to the orchestrator; the orchestrator rehydrates recent history server-side using `conversationId` and `userId`.
143
+
144
+ | Field | Type / values | Required | What it does | Example |
145
+ |---|---|---:|---|---|
146
+ | `conversation.conversationId` | string | no | Durable conversation identifier. Generated locally when omitted. | `conv-homepage-001` |
147
+ | `conversation.title` | string | no | Optional user-facing title sent to the orchestrator. | `Homepage assistant` |
148
+ | `conversation.memoryMaxTurns` | nonnegative integer | no | Server-side recent-history window. Use `0` to disable rehydration. | `6` |
149
+
114
150
  ### Orchestrator Config
115
151
 
116
- `orchestrator.baseUrl` should point to the orchestrator root URL, not `/v1/chat`. The client appends `/v1/chat` internally.
152
+ `orchestrator.baseUrl` should point to the orchestrator root URL, not `/v2/chat`. The client appends `/v2/chat` internally.
117
153
 
118
154
  | Field | Type / values | Required | What it does | Example |
119
155
  |---|---|---:|---|---|
@@ -134,17 +170,14 @@ Collector is optional and can be disabled. When enabled, the client emits a TagI
134
170
  | `collector.baseUrl` | URL string | yes | Collector endpoint base URL. | `https://collector.tagit.live` |
135
171
  | `collector.tagId` | string | yes | Tag identifier used to route and classify collector events. | `tagit-site-demo` |
136
172
  | `collector.acceptCookies` | `boolean` | no | Whether the widget should request/set cookies when emitting collector events. | `true` |
137
- | `collector.userId` | string | no | Optional user identity for collector payloads. | `user_123` |
138
- | `collector.agentId` | string | no | Optional agent identity for collector payloads. | `uc-default-1lji40` |
139
- | `collector.entityId` | string | no | Optional entity identifier for the tracked subject. | `acct_456` |
140
- | `collector.entityidType` | string | no | Entity type metadata. | `account` |
141
- | `collector.entityidAlgo` | string | no | Entity ID algorithm metadata. | `sha256` |
142
- | `collector.entityidOwner` | string | no | Entity owner metadata. | `tagit` |
143
- | `collector.spaceId` | string | no | Optional space/context identifier. | `website-homepage` |
144
- | `collector.sessionId` | string | no | Optional session identifier. | `session_abc123` |
173
+ | `collector.agentId` | string | no | Optional collector agent identity. Defaults to the request use case id. | `uc-default-1lji40` |
174
+ | `collector.eventSubContext` | string | no | Optional sub-context identifier for the event surface. | `website-homepage` |
175
+ | `collector.sessionId` | string | no | Optional collector session identifier. It is not the primary durable conversation id when `conversation.conversationId` exists. | `session_abc123` |
145
176
  | `collector.privacy.jurisdiction` | string | no | Privacy jurisdiction metadata. | `US-CA` |
146
177
  | `collector.privacy.purposesConsent.analytics` | `boolean` | no | Consent flag for analytics collection. | `true` |
147
178
 
179
+ Legacy collector identity fields are still accepted for migration compatibility, but new integrations should put identity in the shared `user` block.
180
+
148
181
  ### UI Config
149
182
 
150
183
  | Field | Type / values | Default | What it does | Example |
@@ -177,7 +210,7 @@ const client = new AIClient(config, options);
177
210
  | `on(listener)` | `(): () => void` | Subscribes to client events and returns an unsubscribe function. | `client.on(handleEvent)` |
178
211
  | `sendMessage()` | `(message, options?) => Promise<void>` | Sends a user message and streams the orchestrator response. | `await client.sendMessage('Hello')` |
179
212
  | `cancel()` | `(): void` | Cancels the current in-flight request. | `client.cancel()` |
180
- | `clearHistory()` | `(): void` | Clears the transcript and resets the conversation ID. | `client.clearHistory()` |
213
+ | `clearHistory()` | `(): void` | Clears the local transcript. If `conversation.conversationId` is configured, the durable id is preserved. | `client.clearHistory()` |
181
214
  | `trimHistoryBefore()` | `(messageId) => string \| null` | Removes a message and everything after it. | `client.trimHistoryBefore(id)` |
182
215
 
183
216
  ## Message Options
@@ -188,11 +221,18 @@ const client = new AIClient(config, options);
188
221
  |---|---|---|---|
189
222
  | `tools` | `'none' \| 'all' \| string[]` | Limits which MCP tools are available for the request. | `tools: 'none'` |
190
223
  | `useCaseMessage` | `string` | Injects an additional use-case instruction as a system message. | `useCaseMessage: 'Keep it short and direct.'` |
224
+ | `userId` | `string` | Overrides the resolved user id for this request. | `userId: 'request-user'` |
225
+ | `useCaseId` | `string` | Overrides the configured use case for this request. | `useCaseId: 'uc-other'` |
226
+ | `snapshotId` | `string` | Overrides the configured snapshot for this request. | `snapshotId: 'snap-123'` |
227
+ | `conversationId` | `string` | Overrides the durable conversation id for this request. | `conversationId: 'conv-other'` |
228
+ | `conversationTitle` | `string` | Overrides the conversation title for this request. | `conversationTitle: 'Support chat'` |
229
+ | `conversationMemoryMaxTurns` | `number` | Overrides the server-side memory window for this request. | `conversationMemoryMaxTurns: 0` |
191
230
 
192
231
  ```ts
193
232
  await client.sendMessage('Hello', {
194
233
  tools: 'none',
195
234
  useCaseMessage: 'You are helping a new customer onboard.',
235
+ conversationMemoryMaxTurns: 6,
196
236
  });
197
237
  ```
198
238
 
@@ -209,6 +249,11 @@ await client.sendMessage('Hello', {
209
249
  | `error` | `string \| undefined` | Safe user-facing error text. | `Request timed out before completion.` |
210
250
  | `lastError` | `ClientErrorInfo \| undefined` | Structured internal error details. | `{ code: 'TIMEOUT', ... }` |
211
251
  | `useCaseId` | `string` | Use case currently bound to the conversation. | `uc-default-1lji40` |
252
+ | `workflowId` | `string \| undefined` | Latest workflow run id returned by a V2 workflow use case. | `wf_123` |
253
+ | `workflowStatus` | `string \| undefined` | Latest workflow status returned by the orchestrator. | `completed` |
254
+ | `checkpointPrompt` | `string \| undefined` | Latest checkpoint prompt returned by a workflow use case. | `Review before continuing?` |
255
+
256
+ Checkpoint action UI is not included in the beta React widget. Consumers can inspect workflow metadata from state/events and add explicit continue/revise/cancel controls in a later integration.
212
257
 
213
258
  ## Client Events
214
259
 
@@ -239,24 +284,34 @@ await client.sendMessage('Hello', {
239
284
 
240
285
  ## Orchestrator Request Shape
241
286
 
242
- The core client posts a canonical request to `/v1/chat`.
287
+ The core client posts a canonical request to `/v2/chat`.
243
288
 
244
289
  | Field | Type / values | Required | What it does | Example |
245
290
  |---|---|---:|---|---|
246
291
  | `use_case_id` | string | yes | Runtime use case identifier. | `uc-default-1lji40` |
247
292
  | `stream` | `boolean` | no | Requests SSE when `true`. | `true` |
248
- | `messages` | array | yes | Message history sent to the orchestrator. | `[{ role: 'user', content: 'Hello' }]` |
293
+ | `messages` | array | yes | Current user message, plus optional `useCaseMessage` system instruction. Server-side memory comes from `conversation_id`. | `[{ role: 'user', content: 'Hello' }]` |
249
294
  | `tools` | `'none' \| 'all' \| string[]` | no | Limits which tools the orchestrator may use. | `['search_docs']` |
250
295
  | `snapshot_id` | string | no | Pins the request to a published orchestration snapshot. | `snapshot_2026_04_14` |
296
+ | `runtime_version` | `'v2'` | yes | Runtime contract marker sent by the client. | `v2` |
297
+ | `user_id` | string | yes | User id for ownership and conversation memory. | `visitor_abc123` |
298
+ | `conversation_id` | string | yes | Durable conversation id. | `conv-homepage-001` |
299
+ | `session_id` | string | no | Backward-compatible mirror of `conversation_id` during migration. | `conv-homepage-001` |
300
+ | `conversation_title` | string | no | Optional conversation title. | `Homepage assistant` |
301
+ | `conversation_memory_max_turns` | number | no | Server-side memory window. | `6` |
251
302
 
252
303
  Example:
253
304
 
254
305
  ```ts
255
306
  {
256
307
  use_case_id: 'uc-default-1lji40',
308
+ runtime_version: 'v2',
309
+ user_id: 'visitor_abc123',
310
+ conversation_id: 'conv-homepage-001',
311
+ session_id: 'conv-homepage-001',
312
+ conversation_memory_max_turns: 6,
257
313
  stream: true,
258
314
  messages: [
259
- { role: 'system', content: 'Keep it short and direct.' },
260
315
  { role: 'user', content: 'How do I get started?' },
261
316
  ],
262
317
  tools: 'none',
@@ -275,7 +330,7 @@ When collector emission is enabled, the client emits a conversation envelope aft
275
330
  | `remember` | boolean | Signals that the event should be retained for memory processing. | `true` |
276
331
  | `eventType` | string | High-level event class. | `conversation` |
277
332
  | `eventSubType` | string | Specific collector subtype. | `chat_turn` |
278
- | `eventSubContext` | string | Context label for the event. | `uc-default-1lji40` |
333
+ | `eventSubContext` | string | Context or sub-context label for the event. | `website-homepage` |
279
334
  | `eventGuid` | string | Unique event identifier. | `1713100000000-x8q1abcde` |
280
335
  | `sessionId` | string | Optional session identifier. | `session_abc123` |
281
336
  | `entityId` | string | Entity identity for the event subject. | `user_123` |
@@ -291,7 +346,6 @@ When collector emission is enabled, the client emits a conversation envelope aft
291
346
  | `content.contentData.agentMessageId` | string \| null | Assistant message ID when present. | `1713100000002-z1a3cdefg` |
292
347
  | `content.contentData.userMessage` | string | Captured user message content. | `How do I get started?` |
293
348
  | `content.contentData.agentMessage` | string \| null | Captured assistant message content. | `Open the onboarding checklist...` |
294
- | `content.contentData.spaceId` | string | Optional space identifier. | `website-homepage` |
295
349
 
296
350
  ## Transport
297
351
 
@@ -302,7 +356,7 @@ import type { OrchestratorTransport } from '@tagit/ai-client-core';
302
356
 
303
357
  const transport: OrchestratorTransport = {
304
358
  async send(request, context) {
305
- return fetch(`${context.baseUrl}/v1/chat`, {
359
+ return fetch(`${context.baseUrl}${context.endpointPath}`, {
306
360
  method: 'POST',
307
361
  headers: context.headers,
308
362
  body: JSON.stringify(request),
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ClientConfig, ClientEventListener, ConversationState } from './types.js';
1
+ import type { ClientConfig, ClientEventListener, ConversationState, SendMessageOptions } from './types.js';
2
2
  import { type OrchestratorTransport } from './transport.js';
3
3
  /**
4
4
  * Headless AI client core
@@ -34,6 +34,19 @@ export declare class AIClient {
34
34
  * Check if history exceeds max messages and emit warning event
35
35
  */
36
36
  private checkAndTrimHistory;
37
+ private getEndpointPath;
38
+ private buildRequestMessages;
39
+ resolveUserId(options?: Pick<SendMessageOptions, 'userId'>): string;
40
+ resolveConversationId(options?: Pick<SendMessageOptions, 'conversationId'>): string;
41
+ hasConfiguredConversationId(): boolean;
42
+ getResolvedIdentity(options?: Pick<SendMessageOptions, 'userId' | 'conversationId'>): {
43
+ userId: string;
44
+ conversationId: string;
45
+ entityId: string;
46
+ entityidType: string;
47
+ entityidAlgo: string;
48
+ entityidOwner: string;
49
+ };
37
50
  /**
38
51
  * Truncate error details to prevent massive error payloads
39
52
  */
@@ -41,10 +54,7 @@ export declare class AIClient {
41
54
  /**
42
55
  * Send a message and stream the response
43
56
  */
44
- sendMessage(userMessage: string, options?: {
45
- tools?: 'none' | 'all' | string[];
46
- useCaseMessage?: string;
47
- }): Promise<void>;
57
+ sendMessage(userMessage: string, options?: SendMessageOptions): Promise<void>;
48
58
  private streamResponseWithRetry;
49
59
  /**
50
60
  * Stream response from orchestrator
@@ -65,6 +75,7 @@ export declare class AIClient {
65
75
  private appendAssistantDelta;
66
76
  private applyTerminalContent;
67
77
  private handleNonStreamingResponse;
78
+ private applyWorkflowDetails;
68
79
  private extractAssistantText;
69
80
  private shouldAcceptDegradedCompletion;
70
81
  private hasAssistantContent;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEZ,mBAAmB,EACnB,iBAAiB,EAMlB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AASxB;;;GAGG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,SAAS,CAAwB;gBAGvC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,qBAAqB,CAAC;KACnC;IAaH;;OAEG;IACH,QAAQ,IAAI,iBAAiB;IAI7B;;OAEG;IACH,EAAE,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,IAAI;IAO7C;;OAEG;IACH,OAAO,CAAC,IAAI;IAUZ;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GACvE,OAAO,CAAC,IAAI,CAAC;YAuDF,uBAAuB;IA0CrC;;OAEG;YACW,cAAc;IA4M5B;;OAEG;YACW,WAAW;IAoHzB;;;OAGG;YACW,mBAAmB;IA0BjC,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,oBAAoB;IAwB5B,OAAO,CAAC,oBAAoB;YAyBd,0BAA0B;IA0CxC,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,8BAA8B;IAgBtC,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;YACW,kBAAkB;IA8DhC;;OAEG;IACH,MAAM,IAAI,IAAI;IAUd;;;OAGG;IACH,YAAY,IAAI,IAAI;IAiBpB;;;;;OAKG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAWpD;AAED,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEZ,mBAAmB,EACnB,iBAAiB,EAMjB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AASxB;;;GAGG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,SAAS,CAAwB;gBAGvC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,qBAAqB,CAAC;KACnC;IAiBH;;OAEG;IACH,QAAQ,IAAI,iBAAiB;IAI7B;;OAEG;IACH,EAAE,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,IAAI;IAO7C;;OAEG;IACH,OAAO,CAAC,IAAI;IAUZ;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,oBAAoB;IAwB5B,aAAa,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GAAG,MAAM;IAYnE,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,GAAG,MAAM;IASnF,2BAA2B,IAAI,OAAO;IAItC,mBAAmB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,gBAAgB,CAAC,GAAG;QACpF,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;KACvB;IAYD;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,IAAI,CAAC;YAuDF,uBAAuB;IAyCrC;;OAEG;YACW,cAAc;IA0M5B;;OAEG;YACW,WAAW;IAqHzB;;;OAGG;YACW,mBAAmB;IA0BjC,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,oBAAoB;IAwB5B,OAAO,CAAC,oBAAoB;YA0Bd,0BAA0B;IA2CxC,OAAO,CAAC,oBAAoB;IA+C5B,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,8BAA8B;IAgBtC,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,mBAAmB;IA+C3B;;OAEG;YACW,kBAAkB;IAkEhC;;OAEG;IACH,MAAM,IAAI,IAAI;IAUd;;;OAGG;IACH,YAAY,IAAI,IAAI;IAmBpB;;;;;OAKG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAWpD;AAED,eAAe,QAAQ,CAAC"}
package/dist/client.js CHANGED
@@ -50,8 +50,11 @@ export class AIClient {
50
50
  });
51
51
  this.config = validateConfig(config);
52
52
  this.transport = options?.transport ?? new FetchOrchestratorTransport();
53
+ const initialConversationId = this.config.conversation?.conversationId?.trim() ||
54
+ this.config.collector?.sessionId?.trim() ||
55
+ generateId();
53
56
  this.conversationState = {
54
- id: generateId(),
57
+ id: initialConversationId,
55
58
  messages: [],
56
59
  isLoading: false,
57
60
  isStreaming: false,
@@ -111,6 +114,56 @@ export class AIClient {
111
114
  });
112
115
  }
113
116
  }
117
+ getEndpointPath() {
118
+ return '/v2/chat';
119
+ }
120
+ buildRequestMessages(useCaseMessage) {
121
+ const allMessages = this.conversationState.messages.map((msg) => ({
122
+ role: msg.role,
123
+ content: msg.content,
124
+ }));
125
+ let requestMessages = allMessages.slice(-1);
126
+ const trimmedUseCaseMessage = useCaseMessage?.trim();
127
+ if (trimmedUseCaseMessage) {
128
+ requestMessages = [
129
+ {
130
+ role: 'system',
131
+ content: trimmedUseCaseMessage,
132
+ },
133
+ ...requestMessages,
134
+ ];
135
+ }
136
+ return requestMessages;
137
+ }
138
+ resolveUserId(options) {
139
+ const user = this.config.user;
140
+ return (options?.userId?.trim() ||
141
+ user?.userId?.trim() ||
142
+ user?.entityId?.trim() ||
143
+ this.config.collector?.userId?.trim() ||
144
+ this.config.collector?.entityId?.trim() ||
145
+ this.conversationState.id);
146
+ }
147
+ resolveConversationId(options) {
148
+ return (options?.conversationId?.trim() ||
149
+ this.config.conversation?.conversationId?.trim() ||
150
+ this.config.collector?.sessionId?.trim() ||
151
+ this.conversationState.id);
152
+ }
153
+ hasConfiguredConversationId() {
154
+ return Boolean(this.config.conversation?.conversationId?.trim());
155
+ }
156
+ getResolvedIdentity(options) {
157
+ const userId = this.resolveUserId(options);
158
+ return {
159
+ userId,
160
+ conversationId: this.resolveConversationId(options),
161
+ entityId: this.config.user?.entityId?.trim() || this.config.collector?.entityId?.trim() || userId,
162
+ entityidType: this.config.user?.entityidType?.trim() || this.config.collector?.entityidType?.trim() || 'internal_user_id',
163
+ entityidAlgo: this.config.user?.entityidAlgo?.trim() || this.config.collector?.entityidAlgo?.trim() || 'native',
164
+ entityidOwner: this.config.user?.entityidOwner?.trim() || this.config.collector?.entityidOwner?.trim() || 'tagit-ai-client',
165
+ };
166
+ }
114
167
  /**
115
168
  * Truncate error details to prevent massive error payloads
116
169
  */
@@ -156,11 +209,11 @@ export class AIClient {
156
209
  this.conversationState.isLoading = true;
157
210
  this.emit({ type: 'message_added', message: userMsg });
158
211
  try {
159
- await this.streamResponseWithRetry(options?.tools, options?.useCaseMessage);
212
+ await this.streamResponseWithRetry(options);
160
213
  // Emit collector event if configured
161
214
  if (this.config.collector?.enabled) {
162
215
  const assistantMsg = this.findLatestAssistantMessage();
163
- await this.emitCollectorEvent(userMsg, assistantMsg ?? null);
216
+ await this.emitCollectorEvent(userMsg, assistantMsg ?? null, options);
164
217
  }
165
218
  }
166
219
  catch (error) {
@@ -183,13 +236,13 @@ export class AIClient {
183
236
  this.emit({ type: 'state_synced' });
184
237
  }
185
238
  }
186
- async streamResponseWithRetry(tools, useCaseMessage) {
239
+ async streamResponseWithRetry(options) {
187
240
  const retries = this.config.orchestrator.maxRetries ?? 0;
188
241
  const maxAttempts = Math.max(1, retries + 1);
189
242
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
190
243
  const baselineLength = this.conversationState.messages.length;
191
244
  try {
192
- await this.streamResponse(tools, useCaseMessage);
245
+ await this.streamResponse(options);
193
246
  return;
194
247
  }
195
248
  catch (error) {
@@ -219,32 +272,30 @@ export class AIClient {
219
272
  /**
220
273
  * Stream response from orchestrator
221
274
  */
222
- async streamResponse(tools, useCaseMessage) {
223
- const requestMessages = this.conversationState.messages.map((msg) => ({
224
- role: msg.role,
225
- content: msg.content,
226
- }));
227
- const trimmedUseCaseMessage = useCaseMessage?.trim();
228
- if (trimmedUseCaseMessage) {
229
- requestMessages.unshift({
230
- role: 'system',
231
- content: trimmedUseCaseMessage,
232
- });
233
- }
275
+ async streamResponse(options) {
276
+ const requestMessages = this.buildRequestMessages(options?.useCaseMessage);
277
+ const endpointPath = this.getEndpointPath();
234
278
  const request = {
235
- use_case_id: this.config.orchestrator.useCaseId,
279
+ use_case_id: options?.useCaseId?.trim() || this.config.orchestrator.useCaseId,
236
280
  stream: this.config.ui?.streaming ?? true,
237
281
  messages: requestMessages,
238
282
  };
239
- if (tools) {
240
- request.tools = tools;
241
- }
242
- if (this.config.orchestrator.snapshotId) {
243
- request.snapshot_id = this.config.orchestrator.snapshotId;
283
+ request.runtime_version = 'v2';
284
+ request.conversation_id = this.resolveConversationId(options);
285
+ request.session_id = request.conversation_id;
286
+ request.user_id = this.resolveUserId(options);
287
+ request.conversation_title = options?.conversationTitle ?? this.config.conversation?.title;
288
+ request.conversation_memory_max_turns = options?.conversationMemoryMaxTurns ?? this.config.conversation?.memoryMaxTurns;
289
+ if (options?.tools) {
290
+ request.tools = options.tools;
291
+ }
292
+ const snapshotId = options?.snapshotId?.trim() || this.config.orchestrator.snapshotId;
293
+ if (snapshotId) {
294
+ request.snapshot_id = snapshotId;
244
295
  }
245
296
  this.emit({
246
297
  type: 'orchestrator_request',
247
- endpoint: `${this.config.orchestrator.baseUrl}/v1/chat`,
298
+ endpoint: `${this.config.orchestrator.baseUrl.replace(/\/+$/, '')}${endpointPath}`,
248
299
  request,
249
300
  });
250
301
  this.abortReason = null;
@@ -265,6 +316,7 @@ export class AIClient {
265
316
  try {
266
317
  const response = await this.transport.send(request, {
267
318
  baseUrl: this.config.orchestrator.baseUrl,
319
+ endpointPath,
268
320
  headers,
269
321
  signal: this.abortController.signal,
270
322
  });
@@ -475,6 +527,7 @@ export class AIClient {
475
527
  const text = this.extractAssistantText(chunk.data) ?? '';
476
528
  const lastMsg = this.conversationState.messages[this.conversationState.messages.length - 1];
477
529
  if (text.trim() && lastMsg?.role === 'assistant' && !lastMsg.content.trim()) {
530
+ this.applyWorkflowDetails(chunk.data);
478
531
  // Server batched the full response with no deltas — animate it in.
479
532
  this.emit({ type: 'first_token', messageId: lastMsg.id });
480
533
  await this.simulateDeltaStream(text, lastMsg.id);
@@ -576,6 +629,7 @@ export class AIClient {
576
629
  return target.id;
577
630
  }
578
631
  applyTerminalContent(data) {
632
+ this.applyWorkflowDetails(data);
579
633
  const text = this.extractAssistantText(data) ?? '';
580
634
  if (!text.trim()) {
581
635
  return;
@@ -614,6 +668,7 @@ export class AIClient {
614
668
  if (contentType.includes('application/json') || raw.trim().startsWith('{')) {
615
669
  try {
616
670
  const parsed = JSON.parse(raw);
671
+ this.applyWorkflowDetails(parsed);
617
672
  const extracted = this.extractAssistantText(parsed);
618
673
  assistantText = extracted ?? raw;
619
674
  }
@@ -633,6 +688,48 @@ export class AIClient {
633
688
  this.emit({ type: 'first_token', messageId: assistantMsg.id });
634
689
  }
635
690
  }
691
+ applyWorkflowDetails(payload) {
692
+ const details = payload.details;
693
+ if (!details || typeof details !== 'object') {
694
+ return;
695
+ }
696
+ const workflow = details.workflow;
697
+ if (!workflow || typeof workflow !== 'object') {
698
+ return;
699
+ }
700
+ const workflowDetails = workflow;
701
+ const conversationId = typeof workflowDetails.conversationId === 'string'
702
+ ? workflowDetails.conversationId.trim()
703
+ : undefined;
704
+ const workflowId = typeof workflowDetails.workflowId === 'string'
705
+ ? workflowDetails.workflowId.trim()
706
+ : undefined;
707
+ const status = typeof workflowDetails.status === 'string'
708
+ ? workflowDetails.status.trim()
709
+ : undefined;
710
+ const checkpointPrompt = typeof workflowDetails.checkpointPrompt === 'string'
711
+ ? workflowDetails.checkpointPrompt
712
+ : undefined;
713
+ if (conversationId && conversationId !== this.conversationState.id) {
714
+ this.conversationState.id = conversationId;
715
+ }
716
+ if (workflowId) {
717
+ this.conversationState.workflowId = workflowId;
718
+ }
719
+ if (status) {
720
+ this.conversationState.workflowStatus = status;
721
+ }
722
+ if (checkpointPrompt !== undefined) {
723
+ this.conversationState.checkpointPrompt = checkpointPrompt;
724
+ }
725
+ this.emit({
726
+ type: 'workflow_metadata_updated',
727
+ conversationId: conversationId || this.conversationState.id,
728
+ workflowId,
729
+ status,
730
+ checkpointPrompt,
731
+ });
732
+ }
636
733
  extractAssistantText(payload) {
637
734
  const messages = payload.messages;
638
735
  if (Array.isArray(messages)) {
@@ -722,16 +819,18 @@ export class AIClient {
722
819
  }
723
820
  return undefined;
724
821
  }
725
- buildCollectorEvent(userMessage, assistantMessage) {
822
+ buildCollectorEvent(userMessage, assistantMessage, options) {
726
823
  const collector = this.config.collector;
727
- const userId = collector.userId ?? this.conversationState.id;
728
- const agentId = collector.agentId ?? this.config.orchestrator.useCaseId;
729
- const entityId = collector.entityId ?? userId;
730
- const entityidType = collector.entityidType ?? 'internal_user_id';
731
- const entityidAlgo = collector.entityidAlgo ?? 'native';
732
- const entityidOwner = collector.entityidOwner ?? 'tagit-ai-client';
824
+ const resolved = this.getResolvedIdentity(options);
825
+ const userId = resolved.userId;
826
+ const requestUseCaseId = options?.useCaseId?.trim() || this.config.orchestrator.useCaseId;
827
+ const agentId = collector.agentId ?? requestUseCaseId;
828
+ const entityId = resolved.entityId;
829
+ const entityidType = resolved.entityidType;
830
+ const entityidAlgo = resolved.entityidAlgo;
831
+ const entityidOwner = resolved.entityidOwner;
733
832
  const acceptCookies = collector.acceptCookies ?? false;
734
- const spaceId = collector.spaceId ?? 'default';
833
+ const eventSubContext = collector.eventSubContext ?? requestUseCaseId;
735
834
  return {
736
835
  tagId: collector.tagId,
737
836
  tagType: 'web-sdk-nativeId',
@@ -739,7 +838,7 @@ export class AIClient {
739
838
  remember: true,
740
839
  eventType: 'conversation',
741
840
  eventSubType: 'chat_turn',
742
- eventSubContext: this.config.orchestrator.useCaseId,
841
+ eventSubContext,
743
842
  eventGuid: generateId(),
744
843
  ...(collector.sessionId ? { sessionId: collector.sessionId } : {}),
745
844
  entityId,
@@ -752,12 +851,11 @@ export class AIClient {
752
851
  contentData: {
753
852
  userId,
754
853
  agentId,
755
- conversationId: this.conversationState.id,
854
+ conversationId: resolved.conversationId,
756
855
  userMessageId: userMessage.id,
757
856
  agentMessageId: assistantMessage?.id ?? null,
758
857
  userMessage: userMessage.content,
759
858
  agentMessage: assistantMessage?.content ?? null,
760
- spaceId,
761
859
  },
762
860
  },
763
861
  };
@@ -765,12 +863,12 @@ export class AIClient {
765
863
  /**
766
864
  * Emit a conversation event to the TagIt collector
767
865
  */
768
- async emitCollectorEvent(userMessage, assistantMessage) {
866
+ async emitCollectorEvent(userMessage, assistantMessage, options) {
769
867
  if (!this.config.collector?.baseUrl || !this.config.collector?.tagId) {
770
868
  return;
771
869
  }
772
870
  const endpoint = this.config.collector.baseUrl;
773
- const event = this.buildCollectorEvent(userMessage, assistantMessage);
871
+ const event = this.buildCollectorEvent(userMessage, assistantMessage, options);
774
872
  try {
775
873
  const MAX_PAYLOAD_SIZE = 16 * 1024;
776
874
  const body = JSON.stringify(event);
@@ -846,7 +944,9 @@ export class AIClient {
846
944
  });
847
945
  }
848
946
  this.conversationState.messages = [];
849
- this.conversationState.id = generateId();
947
+ if (!this.hasConfiguredConversationId()) {
948
+ this.conversationState.id = generateId();
949
+ }
850
950
  this.conversationState.error = undefined;
851
951
  this.conversationState.lastError = undefined;
852
952
  this.conversationState.isStreaming = false;