⚙️ refactor: OAuth Flow Signal, Type Safety, Tool Progress & Updated Packages (#6752)

* chore: bump @librechat/agents and related packages

* refactor: update message state for tool calls run step, in case no tool call chunks are received

* fix: avoid combining finalized args createContentAggregator for tool calls

* chore: bump @librechat/agents to version 2.3.99

* feat: add support for aborting flows with AbortSignal in createFlow methods

* fix: improve handling of tool call arguments in useStepHandler

* chore: bump @librechat/agents to version 2.4.0

* fix: update flow identifier format for OAuth login in createActionTool to allow uniqueness per run

* fix: improve error message handling for aborted flows in FlowStateManager

* refactor: allow possible multi-agent cross-over for oauth login

* fix: add type safety for Sandpack files in ArtifactCodeEditor
This commit is contained in:
Danny Avila 2025-04-06 03:28:05 -04:00 committed by GitHub
parent ac35b8490c
commit 9b0678da16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 953 additions and 981 deletions

View file

@ -55,13 +55,18 @@ export class FlowStateManager<T = unknown> {
/**
* Creates a new flow and waits for its completion
*/
async createFlow(flowId: string, type: string, metadata: FlowMetadata = {}): Promise<T> {
async createFlow(
flowId: string,
type: string,
metadata: FlowMetadata = {},
signal?: AbortSignal,
): Promise<T> {
const flowKey = this.getFlowKey(flowId, type);
let existingState = (await this.keyv.get(flowKey)) as FlowState<T> | undefined;
if (existingState) {
this.logger.debug(`[${flowKey}] Flow already exists`);
return this.monitorFlow(flowKey, type);
return this.monitorFlow(flowKey, type, signal);
}
await new Promise((resolve) => setTimeout(resolve, 250));
@ -69,7 +74,7 @@ export class FlowStateManager<T = unknown> {
existingState = (await this.keyv.get(flowKey)) as FlowState<T> | undefined;
if (existingState) {
this.logger.debug(`[${flowKey}] Flow exists on 2nd check`);
return this.monitorFlow(flowKey, type);
return this.monitorFlow(flowKey, type, signal);
}
const initialState: FlowState = {
@ -81,10 +86,10 @@ export class FlowStateManager<T = unknown> {
this.logger.debug('Creating initial flow state:', flowKey);
await this.keyv.set(flowKey, initialState, this.ttl);
return this.monitorFlow(flowKey, type);
return this.monitorFlow(flowKey, type, signal);
}
private monitorFlow(flowKey: string, type: string): Promise<T> {
private monitorFlow(flowKey: string, type: string, signal?: AbortSignal): Promise<T> {
return new Promise<T>((resolve, reject) => {
const checkInterval = 2000;
let elapsedTime = 0;
@ -101,6 +106,16 @@ export class FlowStateManager<T = unknown> {
return;
}
if (signal?.aborted) {
clearInterval(intervalId);
this.intervals.delete(intervalId);
this.logger.warn(`[${flowKey}] Flow aborted`);
const message = `${type} flow aborted`;
await this.keyv.delete(flowKey);
reject(new Error(message));
return;
}
if (flowState.status !== 'PENDING') {
clearInterval(intervalId);
this.intervals.delete(intervalId);
@ -197,19 +212,19 @@ export class FlowStateManager<T = unknown> {
* @param flowId - The ID of the flow
* @param type - The type of flow
* @param handler - Async function to execute if no existing flow is found
* @param metadata - Optional metadata for the flow
* @param signal - Optional AbortSignal to cancel the flow
*/
async createFlowWithHandler(
flowId: string,
type: string,
handler: () => Promise<T>,
metadata: FlowMetadata = {},
signal?: AbortSignal,
): Promise<T> {
const flowKey = this.getFlowKey(flowId, type);
let existingState = (await this.keyv.get(flowKey)) as FlowState<T> | undefined;
if (existingState) {
this.logger.debug(`[${flowKey}] Flow already exists`);
return this.monitorFlow(flowKey, type);
return this.monitorFlow(flowKey, type, signal);
}
await new Promise((resolve) => setTimeout(resolve, 250));
@ -217,13 +232,13 @@ export class FlowStateManager<T = unknown> {
existingState = (await this.keyv.get(flowKey)) as FlowState<T> | undefined;
if (existingState) {
this.logger.debug(`[${flowKey}] Flow exists on 2nd check`);
return this.monitorFlow(flowKey, type);
return this.monitorFlow(flowKey, type, signal);
}
const initialState: FlowState = {
type,
status: 'PENDING',
metadata,
metadata: {},
createdAt: Date.now(),
};
this.logger.debug(`[${flowKey}] Creating initial flow state`);