@umituz/react-native-ai-generation-content 1.83.77 → 1.83.79

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.83.77",
3
+ "version": "1.83.79",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -32,13 +32,14 @@ export interface IAIProviderLifecycle {
32
32
  reset(): void;
33
33
 
34
34
  /**
35
- * Get log entries from the current/last generation session.
36
- * Returns empty array if not supported.
35
+ * Get log entries from a specific generation session.
36
+ * If sessionId omitted, uses the most recent session (not safe for concurrent use).
37
37
  */
38
- getSessionLogs?(): ProviderLogEntry[];
38
+ getSessionLogs?(sessionId?: string): ProviderLogEntry[];
39
39
 
40
40
  /**
41
41
  * End log session and return all entries. Clears the buffer.
42
+ * If sessionId omitted, uses the most recent session (not safe for concurrent use).
42
43
  */
43
- endLogSession?(): ProviderLogEntry[];
44
+ endLogSession?(sessionId?: string): ProviderLogEntry[];
44
45
  }
@@ -25,12 +25,11 @@ export class ImageExecutor
25
25
  ): Promise<GenerationResult<ImageGenerationOutput>> {
26
26
  const TAG = 'GenericImageExecutor';
27
27
  const startTime = Date.now();
28
-
29
- startGenerationLogSession();
28
+ const sid = startGenerationLogSession();
30
29
 
31
30
  try {
32
31
  const totalImageSize = input.imageUrls?.reduce((sum, url) => sum + url.length, 0) ?? 0;
33
- addGenerationLog(TAG, 'Starting generation', 'info', {
32
+ addGenerationLog(sid, TAG, 'Starting generation', 'info', {
34
33
  model,
35
34
  imageCount: input.imageUrls?.length || 0,
36
35
  totalImageSizeKB: Math.round(totalImageSize / 1024),
@@ -40,19 +39,19 @@ export class ImageExecutor
40
39
  const provider = providerRegistry.getActiveProvider();
41
40
 
42
41
  if (!provider?.isInitialized()) {
43
- addGenerationLog(TAG, 'Provider not initialized!', 'error');
42
+ addGenerationLog(sid, TAG, 'Provider not initialized!', 'error');
44
43
  return { success: false, error: "AI provider not initialized" };
45
44
  }
46
45
 
47
46
  options?.onProgress?.(5);
48
47
  const modelInput = this.buildModelInput(input);
49
- addGenerationLog(TAG, 'Model input prepared', 'info', {
48
+ addGenerationLog(sid, TAG, 'Model input prepared', 'info', {
50
49
  imageCount: modelInput.image_urls?.length || 0,
51
50
  aspectRatio: modelInput.aspect_ratio,
52
51
  });
53
52
 
54
53
  options?.onProgress?.(10);
55
- addGenerationLog(TAG, 'Calling provider.subscribe()...');
54
+ addGenerationLog(sid, TAG, 'Calling provider.subscribe()...');
56
55
 
57
56
  const result = await provider.subscribe(model, modelInput, {
58
57
  timeoutMs: options?.timeoutMs ?? env.generationImageTimeoutMs,
@@ -65,33 +64,34 @@ export class ImageExecutor
65
64
  },
66
65
  });
67
66
 
68
- // Collect provider logs
69
- const providerLogs = provider.endLogSession?.() ?? provider.getSessionLogs?.() ?? [];
70
- addGenerationLogs(providerLogs);
67
+ // Collect provider logs — use providerSessionId for concurrent safety
68
+ const providerSessionId = (result as { __providerSessionId?: string })?.__providerSessionId;
69
+ const providerLogs = provider.endLogSession?.(providerSessionId) ?? provider.getSessionLogs?.(providerSessionId) ?? [];
70
+ addGenerationLogs(sid, providerLogs);
71
71
 
72
72
  options?.onProgress?.(90);
73
73
  const imageUrl = this.extractImageUrl(result);
74
74
  const elapsed = Date.now() - startTime;
75
75
 
76
76
  if (!imageUrl) {
77
- addGenerationLog(TAG, `No image URL in response after ${elapsed}ms`, 'error');
77
+ addGenerationLog(sid, TAG, `No image URL in response after ${elapsed}ms`, 'error');
78
78
  return { success: false, error: "No image generated" };
79
79
  }
80
80
 
81
81
  options?.onProgress?.(100);
82
- addGenerationLog(TAG, `Generation SUCCESS in ${elapsed}ms`, 'info', { imageUrl, elapsed });
82
+ addGenerationLog(sid, TAG, `Generation SUCCESS in ${elapsed}ms`, 'info', { imageUrl, elapsed });
83
83
  return { success: true, data: { imageUrl } };
84
84
  } catch (error) {
85
- // Collect provider logs even on failure
85
+ // Collect provider logs even on failure — no providerSessionId available in catch
86
86
  const provider = providerRegistry.getActiveProvider();
87
87
  if (provider) {
88
- const providerLogs = provider.endLogSession?.() ?? provider.getSessionLogs?.() ?? [];
89
- addGenerationLogs(providerLogs);
88
+ const providerLogs = provider.endLogSession?.() ?? [];
89
+ addGenerationLogs(sid, providerLogs);
90
90
  }
91
91
 
92
92
  const elapsed = Date.now() - startTime;
93
93
  const message = error instanceof Error ? error.message : "Generation failed";
94
- addGenerationLog(TAG, `Generation FAILED after ${elapsed}ms: ${message}`, 'error', { elapsed });
94
+ addGenerationLog(sid, TAG, `Generation FAILED after ${elapsed}ms: ${message}`, 'error', { elapsed });
95
95
  return { success: false, error: message };
96
96
  }
97
97
  }
@@ -18,6 +18,7 @@ interface ExecutionResult {
18
18
  success: boolean;
19
19
  imageUrl?: string;
20
20
  error?: string;
21
+ logSessionId?: string;
21
22
  }
22
23
 
23
24
  function formatBase64(base64: string): string {
@@ -54,13 +55,13 @@ export async function executeImageGeneration(
54
55
  ): Promise<ExecutionResult> {
55
56
  const TAG = 'ImageExecutor';
56
57
  const startTime = Date.now();
57
- startGenerationLogSession();
58
+ const sid = startGenerationLogSession();
58
59
  const { providerRegistry } = await import("../../../../../infrastructure/services/provider-registry.service");
59
60
 
60
61
  const provider = providerRegistry.getActiveProvider();
61
62
  if (!provider?.isInitialized()) {
62
- addGenerationLog(TAG, 'Provider not initialized!', 'error');
63
- return { success: false, error: "AI provider not initialized" };
63
+ addGenerationLog(sid, TAG, 'Provider not initialized!', 'error');
64
+ return { success: false, error: "AI provider not initialized", logSessionId: sid };
64
65
  }
65
66
 
66
67
  try {
@@ -69,14 +70,14 @@ export async function executeImageGeneration(
69
70
  const mode = imageUrls.length > 0 ? "Photo-based" : "Text-to-image";
70
71
  const totalImageSize = imageUrls.reduce((sum, url) => sum + url.length, 0);
71
72
 
72
- addGenerationLog(TAG, `${mode} generation starting`, 'info', {
73
+ addGenerationLog(sid, TAG, `${mode} generation starting`, 'info', {
73
74
  model,
74
75
  photoCount: imageUrls.length,
75
76
  totalImageSizeKB: Math.round(totalImageSize / 1024),
76
77
  promptLength: finalPrompt.length,
77
78
  timeout: GENERATION_TIMEOUT_MS,
78
79
  });
79
- addGenerationLog(TAG, `Prompt: ${finalPrompt.substring(0, 300)}${finalPrompt.length > 300 ? "..." : ""}`);
80
+ addGenerationLog(sid, TAG, `Prompt: ${finalPrompt.substring(0, 300)}${finalPrompt.length > 300 ? "..." : ""}`);
80
81
 
81
82
  const modelInput: Record<string, unknown> = {
82
83
  prompt: finalPrompt,
@@ -92,7 +93,7 @@ export async function executeImageGeneration(
92
93
  }
93
94
 
94
95
  let lastStatus = "";
95
- addGenerationLog(TAG, 'Calling provider.subscribe()...');
96
+ addGenerationLog(sid, TAG, 'Calling provider.subscribe()...');
96
97
  const result = await provider.subscribe(model, modelInput, {
97
98
  timeoutMs: GENERATION_TIMEOUT_MS,
98
99
  onQueueUpdate: (status) => {
@@ -102,9 +103,10 @@ export async function executeImageGeneration(
102
103
  },
103
104
  });
104
105
 
105
- // Collect provider logs after subscribe completes
106
- const providerLogs = provider.endLogSession?.() ?? provider.getSessionLogs?.() ?? [];
107
- addGenerationLogs(providerLogs);
106
+ // Collect provider logs use providerSessionId for concurrent safety
107
+ const providerSessionId = (result as { __providerSessionId?: string })?.__providerSessionId;
108
+ const providerLogs = provider.endLogSession?.(providerSessionId) ?? provider.getSessionLogs?.(providerSessionId) ?? [];
109
+ addGenerationLogs(sid, providerLogs);
108
110
 
109
111
  const rawResult = result as Record<string, unknown>;
110
112
  const data = (rawResult?.data ?? rawResult) as { images?: Array<{ url: string }> };
@@ -114,23 +116,23 @@ export async function executeImageGeneration(
114
116
  onProgress?.(100);
115
117
 
116
118
  if (imageUrl) {
117
- addGenerationLog(TAG, `Generation SUCCESS in ${elapsed}ms`, 'info', { imageUrl, elapsed });
118
- return { success: true, imageUrl };
119
+ addGenerationLog(sid, TAG, `Generation SUCCESS in ${elapsed}ms`, 'info', { imageUrl, elapsed });
120
+ return { success: true, imageUrl, logSessionId: sid };
119
121
  }
120
122
 
121
- addGenerationLog(TAG, `No image in response after ${elapsed}ms`, 'error', {
123
+ addGenerationLog(sid, TAG, `No image in response after ${elapsed}ms`, 'error', {
122
124
  responseKeys: Object.keys(data || {}),
123
125
  elapsed,
124
126
  });
125
- return { success: false, error: "No image generated" };
127
+ return { success: false, error: "No image generated", logSessionId: sid };
126
128
  } catch (error) {
127
- // Collect provider logs even on failure
128
- const providerLogs = provider.endLogSession?.() ?? provider.getSessionLogs?.() ?? [];
129
- addGenerationLogs(providerLogs);
129
+ // Collect provider logs even on failure — no providerSessionId available in catch
130
+ const providerLogs = provider.endLogSession?.() ?? [];
131
+ addGenerationLogs(sid, providerLogs);
130
132
 
131
133
  const elapsed = Date.now() - startTime;
132
134
  const errorMsg = error instanceof Error ? error.message : "Generation failed";
133
- addGenerationLog(TAG, `Generation FAILED after ${elapsed}ms: ${errorMsg}`, 'error', { elapsed });
134
- return { success: false, error: errorMsg };
135
+ addGenerationLog(sid, TAG, `Generation FAILED after ${elapsed}ms: ${errorMsg}`, 'error', { elapsed });
136
+ return { success: false, error: errorMsg, logSessionId: sid };
135
137
  }
136
138
  }
@@ -94,10 +94,12 @@ export function createImageStrategy(options: CreateImageStrategyOptions): Wizard
94
94
  const result = await executeImageGeneration(imageInput, model);
95
95
 
96
96
  if (!result.success || !result.imageUrl) {
97
- throw new Error(result.error || "Image generation failed");
97
+ const error = new Error(result.error || "Image generation failed");
98
+ (error as Error & { logSessionId?: string }).logSessionId = result.logSessionId;
99
+ throw error;
98
100
  }
99
101
 
100
- return { imageUrl: result.imageUrl };
102
+ return { imageUrl: result.imageUrl, logSessionId: result.logSessionId };
101
103
  },
102
104
  };
103
105
  }
@@ -20,8 +20,8 @@ export function createCreationPersistence() {
20
20
  updateToCompleted: (userId: string, creationId: string, data: CompletedCreationData) =>
21
21
  updateToCompleted(repository, userId, creationId, data),
22
22
 
23
- updateToFailed: (userId: string, creationId: string, error: string) =>
24
- updateToFailed(repository, userId, creationId, error),
23
+ updateToFailed: (userId: string, creationId: string, error: string, logSessionId?: string) =>
24
+ updateToFailed(repository, userId, creationId, error, logSessionId),
25
25
 
26
26
  updateRequestId: (userId: string, creationId: string, requestId: string, model: string) =>
27
27
  updateRequestId(repository, userId, creationId, requestId, model),
@@ -24,4 +24,6 @@ export interface CompletedCreationData {
24
24
  readonly thumbnailUrl?: string;
25
25
  /** Unix timestamp (ms) when generation was submitted; used to compute durationMs */
26
26
  readonly generationStartedAt?: number;
27
+ /** Log session ID for flushing session-scoped generation logs */
28
+ readonly logSessionId?: string;
27
29
  }
@@ -18,8 +18,10 @@ import { consumeGenerationLogs } from "../../../../../infrastructure/services/ge
18
18
  async function flushLogsToFirestore(
19
19
  userId: string,
20
20
  creationId: string,
21
+ logSessionId?: string,
21
22
  ): Promise<void> {
22
- const logs = consumeGenerationLogs();
23
+ if (!logSessionId) return;
24
+ const logs = consumeGenerationLogs(logSessionId);
23
25
  if (logs.length === 0) return;
24
26
 
25
27
  try {
@@ -69,7 +71,7 @@ export async function updateToCompleted(
69
71
  } as Partial<Creation>);
70
72
 
71
73
  // Flush generation logs to Firestore — awaited to ensure logs are persisted
72
- await flushLogsToFirestore(userId, creationId);
74
+ await flushLogsToFirestore(userId, creationId, data.logSessionId);
73
75
  }
74
76
 
75
77
  /**
@@ -79,7 +81,8 @@ export async function updateToFailed(
79
81
  repository: ICreationsRepository,
80
82
  userId: string,
81
83
  creationId: string,
82
- error: string
84
+ error: string,
85
+ logSessionId?: string,
83
86
  ): Promise<void> {
84
87
  await repository.update(userId, creationId, {
85
88
  status: "failed" as const,
@@ -88,7 +91,7 @@ export async function updateToFailed(
88
91
  } as Partial<Creation>);
89
92
 
90
93
  // Flush generation logs to Firestore — awaited to ensure logs are persisted
91
- await flushLogsToFirestore(userId, creationId);
94
+ await flushLogsToFirestore(userId, creationId, logSessionId);
92
95
  }
93
96
 
94
97
  /**
@@ -48,10 +48,11 @@ export function usePhotoBlockingGeneration(
48
48
  } = props;
49
49
 
50
50
  const creationIdRef = useRef<string | null>(null);
51
+ const logSessionIdRef = useRef<string | undefined>(undefined);
51
52
 
52
53
  const handleSuccess = useCallback(
53
54
  async (result: unknown) => {
54
- const typedResult = result as { imageUrl?: string; videoUrl?: string };
55
+ const typedResult = result as { imageUrl?: string; videoUrl?: string; logSessionId?: string };
55
56
  const creationId = creationIdRef.current;
56
57
 
57
58
  if (creationId && userId) {
@@ -60,6 +61,7 @@ export function usePhotoBlockingGeneration(
60
61
  uri: typedResult.imageUrl || typedResult.videoUrl || "",
61
62
  imageUrl: typedResult.imageUrl,
62
63
  videoUrl: typedResult.videoUrl,
64
+ logSessionId: typedResult.logSessionId,
63
65
  });
64
66
  } catch (err) {
65
67
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -85,12 +87,13 @@ export function usePhotoBlockingGeneration(
85
87
  );
86
88
 
87
89
  const handleError = useCallback(
88
- async (err: { message: string }) => {
90
+ async (err: { message: string; originalError?: Error & { logSessionId?: string } }) => {
89
91
  const creationId = creationIdRef.current;
92
+ const logSessionId = err.originalError?.logSessionId;
90
93
 
91
94
  if (creationId && userId) {
92
95
  try {
93
- await persistence.updateToFailed(userId, creationId, err.message);
96
+ await persistence.updateToFailed(userId, creationId, err.message, logSessionId);
94
97
  } catch (updateErr) {
95
98
  if (typeof __DEV__ !== "undefined" && __DEV__) {
96
99
  console.error("[PhotoBlockingGeneration] updateToFailed error:", updateErr);
@@ -1,56 +1,71 @@
1
1
  /**
2
2
  * Generation Log Store
3
- * Temporarily holds log entries from the most recent generation session.
4
- * The persistence layer reads from here when saving completed/failed creations.
3
+ * Session-scoped log buffer for generation executors.
4
+ * Each generation gets an isolated session concurrent generations don't corrupt each other.
5
5
  *
6
6
  * Flow:
7
- * 1. Executor calls provider.subscribe() -> provider collects logs internally
8
- * 2. Executor calls provider.endLogSession() -> gets log entries
9
- * 3. Executor appends provider logs + its own entries here
10
- * 4. Persistence layer reads logs from here when writing to Firestore
11
- *
12
- * IMPORTANT: Always use addGenerationLogs/addGenerationLog to append.
13
- * clearGenerationLogs should be called at the start of a new generation.
7
+ * 1. Executor calls startGenerationLogSession() gets sessionId
8
+ * 2. Executor calls addGenerationLog(sessionId, ...) logs accumulate
9
+ * 3. Executor calls provider.endLogSession() gets provider logs
10
+ * 4. Executor calls addGenerationLogs(sessionId, providerLogs) appends
11
+ * 5. Persistence layer calls consumeGenerationLogs(sessionId) → writes to Firestore
14
12
  */
15
13
 
16
14
  import type { ProviderLogEntry } from "../../domain/interfaces/ai-provider.interface";
17
15
 
18
- let sessionLogs: ProviderLogEntry[] = [];
19
- let sessionStartTime: number = 0;
16
+ interface LogSession {
17
+ readonly startTime: number;
18
+ entries: ProviderLogEntry[];
19
+ }
20
+
21
+ let sessionCounter = 0;
22
+ const sessions = new Map<string, LogSession>();
20
23
 
21
24
  /**
22
- * Clear logs and start a new session. Call at the beginning of each generation.
25
+ * Start a new isolated log session. Returns session ID.
26
+ * Call at the beginning of each generation.
23
27
  */
24
- export function startGenerationLogSession(): void {
25
- sessionLogs = [];
26
- sessionStartTime = Date.now();
28
+ export function startGenerationLogSession(): string {
29
+ const id = `gen_${++sessionCounter}_${Date.now()}`;
30
+ sessions.set(id, { startTime: Date.now(), entries: [] });
31
+ return id;
27
32
  }
28
33
 
29
34
  /**
30
- * Append log entries to the current session (e.g. provider logs)
35
+ * Append log entries to a specific session (e.g. provider logs)
31
36
  */
32
- export function addGenerationLogs(logs: ProviderLogEntry[]): void {
33
- sessionLogs.push(...logs);
37
+ export function addGenerationLogs(sessionId: string, logs: ProviderLogEntry[]): void {
38
+ const session = sessions.get(sessionId);
39
+ if (session) {
40
+ session.entries.push(...logs);
41
+ }
34
42
  }
35
43
 
36
44
  /**
37
45
  * Add a single log entry with proper elapsed calculation
38
46
  */
39
47
  export function addGenerationLog(
48
+ sessionId: string,
40
49
  tag: string,
41
50
  message: string,
42
51
  level: ProviderLogEntry['level'] = 'info',
43
52
  data?: Record<string, unknown>,
44
53
  ): void {
54
+ const session = sessions.get(sessionId);
45
55
  const now = Date.now();
46
- sessionLogs.push({
56
+
57
+ const entry: ProviderLogEntry = {
47
58
  timestamp: now,
48
- elapsed: sessionStartTime > 0 ? now - sessionStartTime : 0,
59
+ elapsed: session ? now - session.startTime : 0,
49
60
  level,
50
61
  tag,
51
62
  message,
52
63
  ...(data && { data }),
53
- });
64
+ };
65
+
66
+ if (session) {
67
+ session.entries.push(entry);
68
+ }
54
69
 
55
70
  if (typeof __DEV__ !== 'undefined' && __DEV__) {
56
71
  const fn = level === 'error' ? console.error : level === 'warn' ? console.warn : console.log;
@@ -59,26 +74,27 @@ export function addGenerationLog(
59
74
  }
60
75
 
61
76
  /**
62
- * Get and clear all stored logs (consume pattern)
77
+ * Get and clear all stored logs for a session (consume pattern).
78
+ * Removes the session after consuming.
63
79
  */
64
- export function consumeGenerationLogs(): ProviderLogEntry[] {
65
- const logs = [...sessionLogs];
66
- sessionLogs = [];
67
- sessionStartTime = 0;
80
+ export function consumeGenerationLogs(sessionId: string): ProviderLogEntry[] {
81
+ const session = sessions.get(sessionId);
82
+ if (!session) return [];
83
+ const logs = [...session.entries];
84
+ sessions.delete(sessionId);
68
85
  return logs;
69
86
  }
70
87
 
71
88
  /**
72
89
  * Get logs without clearing
73
90
  */
74
- export function getGenerationLogs(): ProviderLogEntry[] {
75
- return [...sessionLogs];
91
+ export function getGenerationLogs(sessionId: string): ProviderLogEntry[] {
92
+ return [...(sessions.get(sessionId)?.entries ?? [])];
76
93
  }
77
94
 
78
95
  /**
79
- * Clear stored logs
96
+ * Clear a specific session's logs
80
97
  */
81
- export function clearGenerationLogs(): void {
82
- sessionLogs = [];
83
- sessionStartTime = 0;
98
+ export function clearGenerationLogs(sessionId: string): void {
99
+ sessions.delete(sessionId);
84
100
  }
@@ -38,6 +38,7 @@ export interface MultiImageGenerationResult {
38
38
  readonly success: boolean;
39
39
  readonly imageUrl?: string;
40
40
  readonly error?: string;
41
+ readonly logSessionId?: string;
41
42
  }
42
43
 
43
44
  /**
@@ -48,12 +49,12 @@ export async function executeMultiImageGeneration(
48
49
  ): Promise<MultiImageGenerationResult> {
49
50
  const TAG = 'MultiImageExecutor';
50
51
  const startTime = Date.now();
51
- startGenerationLogSession();
52
+ const sid = startGenerationLogSession();
52
53
 
53
54
  const validation = validateProvider("MultiImageExecutor");
54
55
  if (!validation.success) {
55
- addGenerationLog(TAG, 'Provider validation failed', 'error');
56
- return { success: false, error: ("error" in validation ? validation.error : "Provider validation failed") };
56
+ addGenerationLog(sid, TAG, 'Provider validation failed', 'error');
57
+ return { success: false, error: ("error" in validation ? validation.error : "Provider validation failed"), logSessionId: sid };
57
58
  }
58
59
  const provider = validation.provider;
59
60
 
@@ -61,7 +62,7 @@ export async function executeMultiImageGeneration(
61
62
  const imageUrls = input.photos.map(formatBase64);
62
63
  const totalImageSize = imageUrls.reduce((sum, url) => sum + url.length, 0);
63
64
 
64
- addGenerationLog(TAG, 'Generation starting', 'info', {
65
+ addGenerationLog(sid, TAG, 'Generation starting', 'info', {
65
66
  model: input.model,
66
67
  imageCount: imageUrls.length,
67
68
  totalImageSizeKB: Math.round(totalImageSize / 1024),
@@ -78,14 +79,15 @@ export async function executeMultiImageGeneration(
78
79
  enable_safety_checker: MODEL_INPUT_DEFAULTS.enableSafetyChecker,
79
80
  };
80
81
 
81
- addGenerationLog(TAG, 'Calling provider.subscribe()...');
82
+ addGenerationLog(sid, TAG, 'Calling provider.subscribe()...');
82
83
  const result = await provider.subscribe(input.model, modelInput, {
83
84
  timeoutMs: GENERATION_TIMEOUT_MS,
84
85
  });
85
86
 
86
- // Collect provider logs
87
- const providerLogs = provider.endLogSession?.() ?? provider.getSessionLogs?.() ?? [];
88
- addGenerationLogs(providerLogs);
87
+ // Collect provider logs — use providerSessionId for concurrent safety
88
+ const providerSessionId = (result as { __providerSessionId?: string })?.__providerSessionId;
89
+ const providerLogs = provider.endLogSession?.(providerSessionId) ?? provider.getSessionLogs?.(providerSessionId) ?? [];
90
+ addGenerationLogs(sid, providerLogs);
89
91
 
90
92
  const rawResult = result as Record<string, unknown>;
91
93
  const data = rawResult?.data ?? rawResult;
@@ -99,34 +101,35 @@ export async function executeMultiImageGeneration(
99
101
  if (typeof imageUrl === "string" && imageUrl.length > 0) {
100
102
  const urlValidation = validateURL(imageUrl);
101
103
  if (!urlValidation.isValid) {
102
- addGenerationLog(TAG, `Invalid URL in response: ${urlValidation.errors.join(", ")}`, 'error');
104
+ addGenerationLog(sid, TAG, `Invalid URL in response: ${urlValidation.errors.join(", ")}`, 'error');
103
105
  return {
104
106
  success: false,
105
- error: `Invalid image URL received: ${urlValidation.errors.join(", ")}`
107
+ error: `Invalid image URL received: ${urlValidation.errors.join(", ")}`,
108
+ logSessionId: sid,
106
109
  };
107
110
  }
108
111
  const elapsed = Date.now() - startTime;
109
- addGenerationLog(TAG, `Generation SUCCESS in ${elapsed}ms`, 'info', { imageUrl, elapsed });
110
- return { success: true, imageUrl };
112
+ addGenerationLog(sid, TAG, `Generation SUCCESS in ${elapsed}ms`, 'info', { imageUrl, elapsed });
113
+ return { success: true, imageUrl, logSessionId: sid };
111
114
  }
112
115
  }
113
116
  }
114
117
  }
115
118
 
116
119
  const elapsed = Date.now() - startTime;
117
- addGenerationLog(TAG, `No image in response after ${elapsed}ms`, 'error', {
120
+ addGenerationLog(sid, TAG, `No image in response after ${elapsed}ms`, 'error', {
118
121
  dataKeys: data && typeof data === "object" ? Object.keys(data) : [],
119
122
  elapsed,
120
123
  });
121
- return { success: false, error: "No image generated" };
124
+ return { success: false, error: "No image generated", logSessionId: sid };
122
125
  } catch (error) {
123
- // Collect provider logs even on failure
124
- const providerLogs = provider.endLogSession?.() ?? provider.getSessionLogs?.() ?? [];
125
- addGenerationLogs(providerLogs);
126
+ // Collect provider logs even on failure — no providerSessionId available in catch
127
+ const providerLogs = provider.endLogSession?.() ?? [];
128
+ addGenerationLogs(sid, providerLogs);
126
129
 
127
130
  const elapsed = Date.now() - startTime;
128
131
  const message = error instanceof Error ? error.message : "Generation failed";
129
- addGenerationLog(TAG, `Generation FAILED after ${elapsed}ms: ${message}`, 'error', { elapsed });
130
- return { success: false, error: message };
132
+ addGenerationLog(sid, TAG, `Generation FAILED after ${elapsed}ms: ${message}`, 'error', { elapsed });
133
+ return { success: false, error: message, logSessionId: sid };
131
134
  }
132
135
  }