@paymanai/payman-typescript-ask-sdk 1.0.2 → 1.1.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/dist/index.d.mts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +303 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +302 -25
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +303 -23
- package/dist/index.native.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -3,6 +3,17 @@ import React from 'react';
|
|
|
3
3
|
type MessageRole = "user" | "assistant" | "system";
|
|
4
4
|
type StreamProgress = "started" | "processing" | "completed" | "error";
|
|
5
5
|
type WorkflowStage = "DEV" | "SANDBOX" | "PROD" | "ARCHIVED";
|
|
6
|
+
type UserActionRequest = {
|
|
7
|
+
userActionId: string;
|
|
8
|
+
message: string;
|
|
9
|
+
requestedSchema: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
type UserActionResult = "approved" | "rejected";
|
|
12
|
+
type UserActionState = {
|
|
13
|
+
request: UserActionRequest | null;
|
|
14
|
+
result: UserActionResult | null;
|
|
15
|
+
clearOtpTrigger: number;
|
|
16
|
+
};
|
|
6
17
|
type StreamingStep = {
|
|
7
18
|
id: string;
|
|
8
19
|
eventType: string;
|
|
@@ -36,6 +47,8 @@ type MessageDisplay = {
|
|
|
36
47
|
steps?: StreamingStep[];
|
|
37
48
|
isCancelled?: boolean;
|
|
38
49
|
currentExecutingStepId?: string;
|
|
50
|
+
/** Result of user action (OTP approval/rejection) */
|
|
51
|
+
userActionResult?: UserActionResult;
|
|
39
52
|
};
|
|
40
53
|
type SessionParams = {
|
|
41
54
|
id?: string;
|
|
@@ -125,9 +138,13 @@ type ChatCallbacks = {
|
|
|
125
138
|
}) => void;
|
|
126
139
|
/** Called when session ID changes */
|
|
127
140
|
onSessionIdChange?: (sessionId: string) => void;
|
|
141
|
+
/** Called when a user action (e.g. OTP) is required */
|
|
142
|
+
onUserActionRequired?: (request: UserActionRequest) => void;
|
|
143
|
+
/** Called on user action events (SUCCESS, INVALID, EXPIRED, REJECTED, RESENT, FAILED) */
|
|
144
|
+
onUserActionEvent?: (eventType: string, message: string) => void;
|
|
128
145
|
};
|
|
129
146
|
|
|
130
|
-
|
|
147
|
+
type UseChatReturn = {
|
|
131
148
|
messages: MessageDisplay[];
|
|
132
149
|
sendMessage: (userMessage: string) => Promise<void>;
|
|
133
150
|
clearMessages: () => void;
|
|
@@ -137,7 +154,16 @@ declare function useChat(config: ChatConfig, callbacks?: ChatCallbacks): {
|
|
|
137
154
|
getMessages: () => MessageDisplay[];
|
|
138
155
|
isWaitingForResponse: boolean;
|
|
139
156
|
sessionId: string | undefined;
|
|
157
|
+
/** User action (OTP) state — always present, inert when workflow has no user actions */
|
|
158
|
+
userActionState: UserActionState;
|
|
159
|
+
/** Submit OTP for approval */
|
|
160
|
+
approveUserAction: (otp: string) => Promise<void>;
|
|
161
|
+
/** Reject / cancel a user action */
|
|
162
|
+
rejectUserAction: () => Promise<void>;
|
|
163
|
+
/** Resend OTP code */
|
|
164
|
+
resendOtp: () => Promise<void>;
|
|
140
165
|
};
|
|
166
|
+
declare function useChat(config: ChatConfig, callbacks?: ChatCallbacks): UseChatReturn;
|
|
141
167
|
|
|
142
168
|
/**
|
|
143
169
|
* Cross-platform UUID v4 generator
|
|
@@ -159,6 +185,11 @@ type StreamEvent = {
|
|
|
159
185
|
inputTokens?: number;
|
|
160
186
|
outputTokens?: number;
|
|
161
187
|
elapsedMs?: number;
|
|
188
|
+
userActionRequest?: {
|
|
189
|
+
userActionId: string;
|
|
190
|
+
message: string;
|
|
191
|
+
requestedSchema: Record<string, unknown>;
|
|
192
|
+
};
|
|
162
193
|
[key: string]: unknown;
|
|
163
194
|
};
|
|
164
195
|
type StreamOptions = {
|
|
@@ -172,4 +203,21 @@ type StreamOptions = {
|
|
|
172
203
|
*/
|
|
173
204
|
declare function streamWorkflowEvents(url: string, body: Record<string, unknown>, headers: Record<string, string>, options?: StreamOptions): Promise<void>;
|
|
174
205
|
|
|
175
|
-
|
|
206
|
+
type UserActionResponse = {
|
|
207
|
+
success: boolean;
|
|
208
|
+
message: string;
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Submit a user action (e.g. OTP verification)
|
|
212
|
+
*/
|
|
213
|
+
declare function submitUserAction(config: ChatConfig, userActionId: string, data?: Record<string, unknown>): Promise<UserActionResponse>;
|
|
214
|
+
/**
|
|
215
|
+
* Cancel / reject a user action
|
|
216
|
+
*/
|
|
217
|
+
declare function cancelUserAction(config: ChatConfig, userActionId: string): Promise<UserActionResponse>;
|
|
218
|
+
/**
|
|
219
|
+
* Resend a user action (e.g. request a new OTP)
|
|
220
|
+
*/
|
|
221
|
+
declare function resendUserAction(config: ChatConfig, userActionId: string): Promise<UserActionResponse>;
|
|
222
|
+
|
|
223
|
+
export { type APIConfig, type ChatCallbacks, type ChatConfig, type ChunkDisplay, type MessageDisplay, type MessageRole, type SessionParams, type StreamEvent, type StreamOptions, type StreamProgress, type StreamingStep, type UseChatReturn, type UserActionRequest, type UserActionResult, type UserActionState, type WorkflowStage, cancelUserAction, generateId, resendUserAction, streamWorkflowEvents, submitUserAction, useChat };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,17 @@ import React from 'react';
|
|
|
3
3
|
type MessageRole = "user" | "assistant" | "system";
|
|
4
4
|
type StreamProgress = "started" | "processing" | "completed" | "error";
|
|
5
5
|
type WorkflowStage = "DEV" | "SANDBOX" | "PROD" | "ARCHIVED";
|
|
6
|
+
type UserActionRequest = {
|
|
7
|
+
userActionId: string;
|
|
8
|
+
message: string;
|
|
9
|
+
requestedSchema: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
type UserActionResult = "approved" | "rejected";
|
|
12
|
+
type UserActionState = {
|
|
13
|
+
request: UserActionRequest | null;
|
|
14
|
+
result: UserActionResult | null;
|
|
15
|
+
clearOtpTrigger: number;
|
|
16
|
+
};
|
|
6
17
|
type StreamingStep = {
|
|
7
18
|
id: string;
|
|
8
19
|
eventType: string;
|
|
@@ -36,6 +47,8 @@ type MessageDisplay = {
|
|
|
36
47
|
steps?: StreamingStep[];
|
|
37
48
|
isCancelled?: boolean;
|
|
38
49
|
currentExecutingStepId?: string;
|
|
50
|
+
/** Result of user action (OTP approval/rejection) */
|
|
51
|
+
userActionResult?: UserActionResult;
|
|
39
52
|
};
|
|
40
53
|
type SessionParams = {
|
|
41
54
|
id?: string;
|
|
@@ -125,9 +138,13 @@ type ChatCallbacks = {
|
|
|
125
138
|
}) => void;
|
|
126
139
|
/** Called when session ID changes */
|
|
127
140
|
onSessionIdChange?: (sessionId: string) => void;
|
|
141
|
+
/** Called when a user action (e.g. OTP) is required */
|
|
142
|
+
onUserActionRequired?: (request: UserActionRequest) => void;
|
|
143
|
+
/** Called on user action events (SUCCESS, INVALID, EXPIRED, REJECTED, RESENT, FAILED) */
|
|
144
|
+
onUserActionEvent?: (eventType: string, message: string) => void;
|
|
128
145
|
};
|
|
129
146
|
|
|
130
|
-
|
|
147
|
+
type UseChatReturn = {
|
|
131
148
|
messages: MessageDisplay[];
|
|
132
149
|
sendMessage: (userMessage: string) => Promise<void>;
|
|
133
150
|
clearMessages: () => void;
|
|
@@ -137,7 +154,16 @@ declare function useChat(config: ChatConfig, callbacks?: ChatCallbacks): {
|
|
|
137
154
|
getMessages: () => MessageDisplay[];
|
|
138
155
|
isWaitingForResponse: boolean;
|
|
139
156
|
sessionId: string | undefined;
|
|
157
|
+
/** User action (OTP) state — always present, inert when workflow has no user actions */
|
|
158
|
+
userActionState: UserActionState;
|
|
159
|
+
/** Submit OTP for approval */
|
|
160
|
+
approveUserAction: (otp: string) => Promise<void>;
|
|
161
|
+
/** Reject / cancel a user action */
|
|
162
|
+
rejectUserAction: () => Promise<void>;
|
|
163
|
+
/** Resend OTP code */
|
|
164
|
+
resendOtp: () => Promise<void>;
|
|
140
165
|
};
|
|
166
|
+
declare function useChat(config: ChatConfig, callbacks?: ChatCallbacks): UseChatReturn;
|
|
141
167
|
|
|
142
168
|
/**
|
|
143
169
|
* Cross-platform UUID v4 generator
|
|
@@ -159,6 +185,11 @@ type StreamEvent = {
|
|
|
159
185
|
inputTokens?: number;
|
|
160
186
|
outputTokens?: number;
|
|
161
187
|
elapsedMs?: number;
|
|
188
|
+
userActionRequest?: {
|
|
189
|
+
userActionId: string;
|
|
190
|
+
message: string;
|
|
191
|
+
requestedSchema: Record<string, unknown>;
|
|
192
|
+
};
|
|
162
193
|
[key: string]: unknown;
|
|
163
194
|
};
|
|
164
195
|
type StreamOptions = {
|
|
@@ -172,4 +203,21 @@ type StreamOptions = {
|
|
|
172
203
|
*/
|
|
173
204
|
declare function streamWorkflowEvents(url: string, body: Record<string, unknown>, headers: Record<string, string>, options?: StreamOptions): Promise<void>;
|
|
174
205
|
|
|
175
|
-
|
|
206
|
+
type UserActionResponse = {
|
|
207
|
+
success: boolean;
|
|
208
|
+
message: string;
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Submit a user action (e.g. OTP verification)
|
|
212
|
+
*/
|
|
213
|
+
declare function submitUserAction(config: ChatConfig, userActionId: string, data?: Record<string, unknown>): Promise<UserActionResponse>;
|
|
214
|
+
/**
|
|
215
|
+
* Cancel / reject a user action
|
|
216
|
+
*/
|
|
217
|
+
declare function cancelUserAction(config: ChatConfig, userActionId: string): Promise<UserActionResponse>;
|
|
218
|
+
/**
|
|
219
|
+
* Resend a user action (e.g. request a new OTP)
|
|
220
|
+
*/
|
|
221
|
+
declare function resendUserAction(config: ChatConfig, userActionId: string): Promise<UserActionResponse>;
|
|
222
|
+
|
|
223
|
+
export { type APIConfig, type ChatCallbacks, type ChatConfig, type ChunkDisplay, type MessageDisplay, type MessageRole, type SessionParams, type StreamEvent, type StreamOptions, type StreamProgress, type StreamingStep, type UseChatReturn, type UserActionRequest, type UserActionResult, type UserActionState, type WorkflowStage, cancelUserAction, generateId, resendUserAction, streamWorkflowEvents, submitUserAction, useChat };
|
package/dist/index.js
CHANGED
|
@@ -113,10 +113,10 @@ async function streamWorkflowEvents(url, body, headers, options = {}) {
|
|
|
113
113
|
// src/utils/eventProcessor.ts
|
|
114
114
|
function getEventMessage(event) {
|
|
115
115
|
if (event.message?.trim()) {
|
|
116
|
-
return event.message;
|
|
116
|
+
return event.message.trim();
|
|
117
117
|
}
|
|
118
118
|
if (event.errorMessage?.trim()) {
|
|
119
|
-
return event.errorMessage;
|
|
119
|
+
return event.errorMessage.trim();
|
|
120
120
|
}
|
|
121
121
|
const eventType = event.eventType;
|
|
122
122
|
switch (eventType) {
|
|
@@ -144,6 +144,20 @@ function getEventMessage(event) {
|
|
|
144
144
|
case "WORKFLOW_ERROR":
|
|
145
145
|
case "INTENT_ERROR":
|
|
146
146
|
return event.errorMessage || "An error occurred";
|
|
147
|
+
case "USER_ACTION_REQUIRED":
|
|
148
|
+
return "Waiting for verification...";
|
|
149
|
+
case "USER_ACTION_SUCCESS":
|
|
150
|
+
return "Verification successful";
|
|
151
|
+
case "USER_ACTION_EXPIRED":
|
|
152
|
+
return "Verification expired";
|
|
153
|
+
case "USER_ACTION_INVALID":
|
|
154
|
+
return "Invalid input, please try again";
|
|
155
|
+
case "USER_ACTION_REJECTED":
|
|
156
|
+
return "Verification rejected";
|
|
157
|
+
case "USER_ACTION_RESENT":
|
|
158
|
+
return "Verification code resent";
|
|
159
|
+
case "USER_ACTION_FAILED":
|
|
160
|
+
return "Verification failed";
|
|
147
161
|
default:
|
|
148
162
|
return eventType;
|
|
149
163
|
}
|
|
@@ -170,6 +184,14 @@ function extractResponseContent(response) {
|
|
|
170
184
|
}
|
|
171
185
|
return "";
|
|
172
186
|
}
|
|
187
|
+
function completeLastInProgressStep(steps) {
|
|
188
|
+
for (let i = steps.length - 1; i >= 0; i--) {
|
|
189
|
+
if (steps[i].status === "in_progress") {
|
|
190
|
+
steps[i].status = "completed";
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
173
195
|
function processStreamEvent(event, state) {
|
|
174
196
|
const eventType = event.eventType;
|
|
175
197
|
const message = getEventMessage(event);
|
|
@@ -269,6 +291,110 @@ function processStreamEvent(event, state) {
|
|
|
269
291
|
});
|
|
270
292
|
state.currentExecutingStepId = stepId;
|
|
271
293
|
}
|
|
294
|
+
} else if (eventType === "USER_ACTION_REQUIRED") {
|
|
295
|
+
completeLastInProgressStep(state.steps);
|
|
296
|
+
if (event.userActionRequest) {
|
|
297
|
+
state.userActionRequest = {
|
|
298
|
+
userActionId: event.userActionRequest.userActionId,
|
|
299
|
+
message: event.userActionRequest.message,
|
|
300
|
+
requestedSchema: event.userActionRequest.requestedSchema
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
state.userActionPending = true;
|
|
304
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
305
|
+
state.steps.push({
|
|
306
|
+
id: stepId,
|
|
307
|
+
eventType,
|
|
308
|
+
message,
|
|
309
|
+
status: "in_progress",
|
|
310
|
+
timestamp: Date.now(),
|
|
311
|
+
elapsedMs: event.elapsedMs
|
|
312
|
+
});
|
|
313
|
+
state.currentExecutingStepId = stepId;
|
|
314
|
+
} else if (eventType === "USER_ACTION_SUCCESS") {
|
|
315
|
+
completeLastInProgressStep(state.steps);
|
|
316
|
+
state.userActionRequest = void 0;
|
|
317
|
+
state.userActionPending = false;
|
|
318
|
+
state.userActionResult = "approved";
|
|
319
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
320
|
+
state.steps.push({
|
|
321
|
+
id: stepId,
|
|
322
|
+
eventType,
|
|
323
|
+
message,
|
|
324
|
+
status: "completed",
|
|
325
|
+
timestamp: Date.now(),
|
|
326
|
+
elapsedMs: event.elapsedMs
|
|
327
|
+
});
|
|
328
|
+
} else if (eventType === "USER_ACTION_INVALID") {
|
|
329
|
+
completeLastInProgressStep(state.steps);
|
|
330
|
+
const errorStepId = `step-${state.stepCounter++}`;
|
|
331
|
+
state.steps.push({
|
|
332
|
+
id: errorStepId,
|
|
333
|
+
eventType,
|
|
334
|
+
message,
|
|
335
|
+
status: "error",
|
|
336
|
+
timestamp: Date.now(),
|
|
337
|
+
elapsedMs: event.elapsedMs
|
|
338
|
+
});
|
|
339
|
+
const retryStepId = `step-${state.stepCounter++}`;
|
|
340
|
+
state.steps.push({
|
|
341
|
+
id: retryStepId,
|
|
342
|
+
eventType: "USER_ACTION_REQUIRED",
|
|
343
|
+
message: "Waiting for verification...",
|
|
344
|
+
status: "in_progress",
|
|
345
|
+
timestamp: Date.now()
|
|
346
|
+
});
|
|
347
|
+
state.currentExecutingStepId = retryStepId;
|
|
348
|
+
} else if (eventType === "USER_ACTION_EXPIRED") {
|
|
349
|
+
completeLastInProgressStep(state.steps);
|
|
350
|
+
state.userActionRequest = void 0;
|
|
351
|
+
state.userActionPending = false;
|
|
352
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
353
|
+
state.steps.push({
|
|
354
|
+
id: stepId,
|
|
355
|
+
eventType,
|
|
356
|
+
message,
|
|
357
|
+
status: "error",
|
|
358
|
+
timestamp: Date.now(),
|
|
359
|
+
elapsedMs: event.elapsedMs
|
|
360
|
+
});
|
|
361
|
+
} else if (eventType === "USER_ACTION_REJECTED") {
|
|
362
|
+
completeLastInProgressStep(state.steps);
|
|
363
|
+
state.userActionRequest = void 0;
|
|
364
|
+
state.userActionPending = false;
|
|
365
|
+
state.userActionResult = "rejected";
|
|
366
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
367
|
+
state.steps.push({
|
|
368
|
+
id: stepId,
|
|
369
|
+
eventType,
|
|
370
|
+
message,
|
|
371
|
+
status: "completed",
|
|
372
|
+
timestamp: Date.now(),
|
|
373
|
+
elapsedMs: event.elapsedMs
|
|
374
|
+
});
|
|
375
|
+
} else if (eventType === "USER_ACTION_RESENT") {
|
|
376
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
377
|
+
state.steps.push({
|
|
378
|
+
id: stepId,
|
|
379
|
+
eventType,
|
|
380
|
+
message,
|
|
381
|
+
status: "completed",
|
|
382
|
+
timestamp: Date.now(),
|
|
383
|
+
elapsedMs: event.elapsedMs
|
|
384
|
+
});
|
|
385
|
+
} else if (eventType === "USER_ACTION_FAILED") {
|
|
386
|
+
completeLastInProgressStep(state.steps);
|
|
387
|
+
state.userActionRequest = void 0;
|
|
388
|
+
state.userActionPending = false;
|
|
389
|
+
const stepId = `step-${state.stepCounter++}`;
|
|
390
|
+
state.steps.push({
|
|
391
|
+
id: stepId,
|
|
392
|
+
eventType,
|
|
393
|
+
message,
|
|
394
|
+
status: "error",
|
|
395
|
+
timestamp: Date.now(),
|
|
396
|
+
elapsedMs: event.elapsedMs
|
|
397
|
+
});
|
|
272
398
|
}
|
|
273
399
|
return state;
|
|
274
400
|
}
|
|
@@ -290,9 +416,9 @@ ${state.errorMessage}` : "",
|
|
|
290
416
|
executionId: state.executionId,
|
|
291
417
|
sessionId: state.sessionId,
|
|
292
418
|
steps: state.hasError ? [] : [...state.steps],
|
|
293
|
-
// Don't show steps on error
|
|
294
419
|
currentExecutingStepId: state.hasError ? void 0 : state.currentExecutingStepId,
|
|
295
|
-
isCancelled: false
|
|
420
|
+
isCancelled: false,
|
|
421
|
+
userActionResult: state.userActionResult
|
|
296
422
|
};
|
|
297
423
|
}
|
|
298
424
|
function createErrorMessageUpdate(error, state) {
|
|
@@ -333,9 +459,9 @@ ${state.errorMessage}` : state.accumulatedContent || "",
|
|
|
333
459
|
executionId: state.executionId,
|
|
334
460
|
tracingData: state.finalData,
|
|
335
461
|
steps: state.hasError ? [] : [...state.steps],
|
|
336
|
-
// Don't show steps on error
|
|
337
462
|
isCancelled: false,
|
|
338
|
-
currentExecutingStepId: void 0
|
|
463
|
+
currentExecutingStepId: void 0,
|
|
464
|
+
userActionResult: state.userActionResult
|
|
339
465
|
};
|
|
340
466
|
}
|
|
341
467
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
@@ -381,6 +507,14 @@ function buildStreamingUrl(config) {
|
|
|
381
507
|
}
|
|
382
508
|
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
383
509
|
}
|
|
510
|
+
function buildUserActionUrl(config, userActionId, action) {
|
|
511
|
+
const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
512
|
+
const [endpointPath] = endpoint.split("?");
|
|
513
|
+
const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
|
|
514
|
+
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
515
|
+
const encodedUserActionId = encodeURIComponent(userActionId);
|
|
516
|
+
return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
|
|
517
|
+
}
|
|
384
518
|
function buildRequestHeaders(config) {
|
|
385
519
|
const headers = {
|
|
386
520
|
...config.api.headers
|
|
@@ -390,8 +524,39 @@ function buildRequestHeaders(config) {
|
|
|
390
524
|
}
|
|
391
525
|
return headers;
|
|
392
526
|
}
|
|
527
|
+
|
|
528
|
+
// src/utils/userActionClient.ts
|
|
529
|
+
async function sendUserActionRequest(config, userActionId, action, data) {
|
|
530
|
+
const url = buildUserActionUrl(config, userActionId, action);
|
|
531
|
+
const baseHeaders = buildRequestHeaders(config);
|
|
532
|
+
const hasBody = data !== void 0;
|
|
533
|
+
const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
|
|
534
|
+
const response = await fetch(url, {
|
|
535
|
+
method: "POST",
|
|
536
|
+
headers,
|
|
537
|
+
body: hasBody ? JSON.stringify(data) : void 0
|
|
538
|
+
});
|
|
539
|
+
if (!response.ok) {
|
|
540
|
+
const errorText = await response.text();
|
|
541
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
542
|
+
}
|
|
543
|
+
return await response.json();
|
|
544
|
+
}
|
|
545
|
+
async function submitUserAction(config, userActionId, data) {
|
|
546
|
+
return sendUserActionRequest(config, userActionId, "submit", data);
|
|
547
|
+
}
|
|
548
|
+
async function cancelUserAction(config, userActionId) {
|
|
549
|
+
return sendUserActionRequest(config, userActionId, "cancel");
|
|
550
|
+
}
|
|
551
|
+
async function resendUserAction(config, userActionId) {
|
|
552
|
+
return sendUserActionRequest(config, userActionId, "resend");
|
|
553
|
+
}
|
|
393
554
|
function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
394
555
|
const abortControllerRef = react.useRef(null);
|
|
556
|
+
const configRef = react.useRef(config);
|
|
557
|
+
configRef.current = config;
|
|
558
|
+
const callbacksRef = react.useRef(callbacks);
|
|
559
|
+
callbacksRef.current = callbacks;
|
|
395
560
|
const startStream = react.useCallback(
|
|
396
561
|
async (userMessage, streamingId, sessionId) => {
|
|
397
562
|
abortControllerRef.current?.abort();
|
|
@@ -406,11 +571,15 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
406
571
|
stepCounter: 0,
|
|
407
572
|
currentExecutingStepId: void 0,
|
|
408
573
|
hasError: false,
|
|
409
|
-
errorMessage: ""
|
|
574
|
+
errorMessage: "",
|
|
575
|
+
userActionRequest: void 0,
|
|
576
|
+
userActionPending: false,
|
|
577
|
+
userActionResult: void 0
|
|
410
578
|
};
|
|
411
|
-
const
|
|
412
|
-
const
|
|
413
|
-
const
|
|
579
|
+
const currentConfig = configRef.current;
|
|
580
|
+
const requestBody = buildRequestBody(currentConfig, userMessage, sessionId);
|
|
581
|
+
const url = buildStreamingUrl(currentConfig);
|
|
582
|
+
const headers = buildRequestHeaders(currentConfig);
|
|
414
583
|
try {
|
|
415
584
|
await streamWorkflowEvents(url, requestBody, headers, {
|
|
416
585
|
signal: abortController.signal,
|
|
@@ -421,7 +590,15 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
421
590
|
if (event.executionId) state.executionId = event.executionId;
|
|
422
591
|
if (event.sessionId) state.currentSessionId = event.sessionId;
|
|
423
592
|
processStreamEvent(event, state);
|
|
424
|
-
const
|
|
593
|
+
const eventType = event.eventType;
|
|
594
|
+
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
595
|
+
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
596
|
+
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
597
|
+
const msg = event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event);
|
|
598
|
+
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
599
|
+
}
|
|
600
|
+
const rawMessage = event.message?.trim() || event.errorMessage?.trim();
|
|
601
|
+
const currentMessage = rawMessage || (event.eventType?.startsWith("USER_ACTION_") ? getEventMessage(event) : void 0);
|
|
425
602
|
setMessages(
|
|
426
603
|
(prev) => prev.map(
|
|
427
604
|
(msg) => msg.id === streamingId ? {
|
|
@@ -437,7 +614,7 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
437
614
|
onError: (error) => {
|
|
438
615
|
setIsWaitingForResponse(false);
|
|
439
616
|
if (error.name !== "AbortError") {
|
|
440
|
-
|
|
617
|
+
callbacksRef.current.onError?.(error);
|
|
441
618
|
}
|
|
442
619
|
setMessages(
|
|
443
620
|
(prev) => prev.map(
|
|
@@ -451,7 +628,7 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
451
628
|
onComplete: () => {
|
|
452
629
|
setIsWaitingForResponse(false);
|
|
453
630
|
if (state.currentSessionId && state.currentSessionId !== sessionId) {
|
|
454
|
-
|
|
631
|
+
callbacksRef.current.onSessionIdChange?.(state.currentSessionId);
|
|
455
632
|
}
|
|
456
633
|
const finalMessage = createFinalMessage(streamingId, {
|
|
457
634
|
...state,
|
|
@@ -462,14 +639,14 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
462
639
|
(msg) => msg.id === streamingId ? finalMessage : msg
|
|
463
640
|
)
|
|
464
641
|
);
|
|
465
|
-
|
|
642
|
+
callbacksRef.current.onStreamComplete?.(finalMessage);
|
|
466
643
|
}
|
|
467
644
|
});
|
|
468
645
|
return state.currentSessionId;
|
|
469
646
|
} catch (error) {
|
|
470
647
|
setIsWaitingForResponse(false);
|
|
471
648
|
if (error.name !== "AbortError") {
|
|
472
|
-
|
|
649
|
+
callbacksRef.current.onError?.(error);
|
|
473
650
|
}
|
|
474
651
|
setMessages(
|
|
475
652
|
(prev) => prev.map(
|
|
@@ -482,7 +659,7 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
|
|
|
482
659
|
return state.currentSessionId;
|
|
483
660
|
}
|
|
484
661
|
},
|
|
485
|
-
[
|
|
662
|
+
[setMessages, setIsWaitingForResponse]
|
|
486
663
|
);
|
|
487
664
|
const cancelStream = react.useCallback(() => {
|
|
488
665
|
abortControllerRef.current?.abort();
|
|
@@ -499,18 +676,61 @@ function useChat(config, callbacks = {}) {
|
|
|
499
676
|
const [messages, setMessages] = react.useState([]);
|
|
500
677
|
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(false);
|
|
501
678
|
const sessionIdRef = react.useRef(void 0);
|
|
679
|
+
const callbacksRef = react.useRef(callbacks);
|
|
680
|
+
callbacksRef.current = callbacks;
|
|
681
|
+
const configRef = react.useRef(config);
|
|
682
|
+
configRef.current = config;
|
|
683
|
+
const [userActionState, setUserActionState] = react.useState({
|
|
684
|
+
request: null,
|
|
685
|
+
result: null,
|
|
686
|
+
clearOtpTrigger: 0
|
|
687
|
+
});
|
|
688
|
+
const userActionStateRef = react.useRef(userActionState);
|
|
689
|
+
userActionStateRef.current = userActionState;
|
|
690
|
+
const wrappedCallbacks = react.useMemo(() => ({
|
|
691
|
+
...callbacksRef.current,
|
|
692
|
+
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
693
|
+
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
694
|
+
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
695
|
+
onError: (error) => callbacksRef.current.onError?.(error),
|
|
696
|
+
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
697
|
+
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
698
|
+
onUserActionRequired: (request) => {
|
|
699
|
+
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
700
|
+
callbacksRef.current.onUserActionRequired?.(request);
|
|
701
|
+
},
|
|
702
|
+
onUserActionEvent: (eventType, message) => {
|
|
703
|
+
switch (eventType) {
|
|
704
|
+
case "USER_ACTION_SUCCESS":
|
|
705
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
706
|
+
break;
|
|
707
|
+
case "USER_ACTION_REJECTED":
|
|
708
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
709
|
+
break;
|
|
710
|
+
case "USER_ACTION_EXPIRED":
|
|
711
|
+
case "USER_ACTION_FAILED":
|
|
712
|
+
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
713
|
+
break;
|
|
714
|
+
case "USER_ACTION_INVALID":
|
|
715
|
+
setUserActionState((prev) => ({ ...prev, clearOtpTrigger: prev.clearOtpTrigger + 1 }));
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
719
|
+
}
|
|
720
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
721
|
+
}), []);
|
|
502
722
|
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManager(
|
|
503
723
|
config,
|
|
504
|
-
|
|
724
|
+
wrappedCallbacks,
|
|
505
725
|
setMessages,
|
|
506
726
|
setIsWaitingForResponse
|
|
507
727
|
);
|
|
508
728
|
const sendMessage = react.useCallback(
|
|
509
729
|
async (userMessage) => {
|
|
510
730
|
if (!userMessage.trim()) return;
|
|
511
|
-
if (!sessionIdRef.current &&
|
|
731
|
+
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
512
732
|
sessionIdRef.current = generateId();
|
|
513
|
-
|
|
733
|
+
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
514
734
|
}
|
|
515
735
|
const userMessageId = `user-${Date.now()}`;
|
|
516
736
|
const userMsg = {
|
|
@@ -521,9 +741,9 @@ function useChat(config, callbacks = {}) {
|
|
|
521
741
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
522
742
|
};
|
|
523
743
|
setMessages((prev) => [...prev, userMsg]);
|
|
524
|
-
|
|
744
|
+
callbacksRef.current.onMessageSent?.(userMessage);
|
|
525
745
|
setIsWaitingForResponse(true);
|
|
526
|
-
|
|
746
|
+
callbacksRef.current.onStreamStart?.();
|
|
527
747
|
const streamingId = `assistant-${Date.now()}`;
|
|
528
748
|
const streamingMsg = {
|
|
529
749
|
id: streamingId,
|
|
@@ -549,7 +769,7 @@ function useChat(config, callbacks = {}) {
|
|
|
549
769
|
sessionIdRef.current = newSessionId;
|
|
550
770
|
}
|
|
551
771
|
},
|
|
552
|
-
[
|
|
772
|
+
[startStream]
|
|
553
773
|
);
|
|
554
774
|
const clearMessages = react.useCallback(() => {
|
|
555
775
|
setMessages([]);
|
|
@@ -557,6 +777,7 @@ function useChat(config, callbacks = {}) {
|
|
|
557
777
|
const cancelStream = react.useCallback(() => {
|
|
558
778
|
cancelStreamManager();
|
|
559
779
|
setIsWaitingForResponse(false);
|
|
780
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: null }));
|
|
560
781
|
setMessages(
|
|
561
782
|
(prev) => prev.map((msg) => {
|
|
562
783
|
if (msg.isStreaming) {
|
|
@@ -577,6 +798,7 @@ function useChat(config, callbacks = {}) {
|
|
|
577
798
|
sessionIdRef.current = void 0;
|
|
578
799
|
abortControllerRef.current?.abort();
|
|
579
800
|
setIsWaitingForResponse(false);
|
|
801
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
580
802
|
}, []);
|
|
581
803
|
const getSessionId = react.useCallback(() => {
|
|
582
804
|
return sessionIdRef.current;
|
|
@@ -584,6 +806,56 @@ function useChat(config, callbacks = {}) {
|
|
|
584
806
|
const getMessages = react.useCallback(() => {
|
|
585
807
|
return messages;
|
|
586
808
|
}, [messages]);
|
|
809
|
+
const approveUserAction = react.useCallback(
|
|
810
|
+
async (otp) => {
|
|
811
|
+
const request = userActionStateRef.current.request;
|
|
812
|
+
if (!request) return;
|
|
813
|
+
try {
|
|
814
|
+
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
815
|
+
} catch (error) {
|
|
816
|
+
setUserActionState((prev) => ({
|
|
817
|
+
...prev,
|
|
818
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
819
|
+
}));
|
|
820
|
+
callbacksRef.current.onError?.(error);
|
|
821
|
+
throw error;
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
[]
|
|
825
|
+
);
|
|
826
|
+
const rejectUserAction = react.useCallback(async () => {
|
|
827
|
+
const request = userActionStateRef.current.request;
|
|
828
|
+
if (!request) return;
|
|
829
|
+
try {
|
|
830
|
+
setMessages((prev) => {
|
|
831
|
+
let lastStreamingIdx = -1;
|
|
832
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
833
|
+
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
834
|
+
lastStreamingIdx = i;
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (lastStreamingIdx === -1) return prev;
|
|
839
|
+
return prev.map(
|
|
840
|
+
(msg, i) => i === lastStreamingIdx ? { ...msg, currentMessage: "Rejecting..." } : msg
|
|
841
|
+
);
|
|
842
|
+
});
|
|
843
|
+
await cancelUserAction(configRef.current, request.userActionId);
|
|
844
|
+
} catch (error) {
|
|
845
|
+
callbacksRef.current.onError?.(error);
|
|
846
|
+
throw error;
|
|
847
|
+
}
|
|
848
|
+
}, []);
|
|
849
|
+
const resendOtp = react.useCallback(async () => {
|
|
850
|
+
const request = userActionStateRef.current.request;
|
|
851
|
+
if (!request) return;
|
|
852
|
+
try {
|
|
853
|
+
await resendUserAction(configRef.current, request.userActionId);
|
|
854
|
+
} catch (error) {
|
|
855
|
+
callbacksRef.current.onError?.(error);
|
|
856
|
+
throw error;
|
|
857
|
+
}
|
|
858
|
+
}, []);
|
|
587
859
|
return {
|
|
588
860
|
messages,
|
|
589
861
|
sendMessage,
|
|
@@ -593,12 +865,20 @@ function useChat(config, callbacks = {}) {
|
|
|
593
865
|
getSessionId,
|
|
594
866
|
getMessages,
|
|
595
867
|
isWaitingForResponse,
|
|
596
|
-
sessionId: sessionIdRef.current
|
|
868
|
+
sessionId: sessionIdRef.current,
|
|
869
|
+
// User action (OTP) state and methods
|
|
870
|
+
userActionState,
|
|
871
|
+
approveUserAction,
|
|
872
|
+
rejectUserAction,
|
|
873
|
+
resendOtp
|
|
597
874
|
};
|
|
598
875
|
}
|
|
599
876
|
|
|
877
|
+
exports.cancelUserAction = cancelUserAction;
|
|
600
878
|
exports.generateId = generateId;
|
|
879
|
+
exports.resendUserAction = resendUserAction;
|
|
601
880
|
exports.streamWorkflowEvents = streamWorkflowEvents;
|
|
881
|
+
exports.submitUserAction = submitUserAction;
|
|
602
882
|
exports.useChat = useChat;
|
|
603
883
|
//# sourceMappingURL=index.js.map
|
|
604
884
|
//# sourceMappingURL=index.js.map
|