Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/core/filestore/file-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,10 @@ export function getFileService(): FileService {
}
return _fileService;
}

/**
* Check if cloud file storage is available (e.g., S3 bucket configured)
*/
export function isFileStorageAvailable(): boolean {
return !!process.env.AWS_BUCKET_NAME;
}
71 changes: 69 additions & 2 deletions packages/core/runs/run-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@
* Context is passed through (not stored) for stateless operation.
*/

import type { RequestOptions, RequestSource, Tool, ToolStepResult } from "@superglue/shared";
import { RunStatus, RequestSource as RSrc } from "@superglue/shared";
import type {
RequestOptions,
RequestSource,
StoredRunResults,
Tool,
ToolStepResult,
} from "@superglue/shared";
import { RunStatus, RequestSource as RSrc, sampleResultObject } from "@superglue/shared";
import type { DataStore } from "../datastore/types.js";
import { generateRunResultsUri, getRunResultsService } from "../ee/run-results-service.js";
import { isFileStorageAvailable } from "../filestore/file-service.js";
import { NotificationService } from "../notifications/index.js";
import { logMessage } from "../utils/logs.js";

Expand Down Expand Up @@ -116,6 +124,17 @@ export class RunLifecycleManager {
},
});

// Fire-and-forget: Store run results to S3 if enabled
this.maybeStoreRunResults({
runId: context.runId,
success: result.success,
data: result.data ?? null,
stepResults: result.stepResults ?? [],
toolPayload: result.payload ?? {},
error: result.error,
storedAt: new Date(),
});

// Send notification for failed runs (fire-and-forget)
if (!result.success) {
this.sendFailureNotification(context, result, completedAt);
Expand Down Expand Up @@ -243,4 +262,52 @@ export class RunLifecycleManager {
})
.catch((err) => logMessage("error", `Notification failed: ${err}`, this.metadata));
}

/**
* Check if run results storage is enabled for this org (EE feature)
* Returns true if file storage is available AND org has the feature enabled
*/
private async isRunResultsStorageEnabled(): Promise<boolean> {
if (!isFileStorageAvailable()) {
return false;
}
const orgSettings = await this.datastore.getOrgSettings({ orgId: this.orgId });
return !!orgSettings?.preferences?.storeRunResults;
}

/**
* Fire-and-forget: Check org settings and store run results to S3 if enabled
* Also updates the run with the storage URI in the database
*/
private maybeStoreRunResults(results: StoredRunResults): void {
setImmediate(async () => {
try {
const enabled = await this.isRunResultsStorageEnabled();
if (!enabled) return;

const storageUri = generateRunResultsUri(results.runId, this.orgId);
if (!storageUri) return;

// Update run with storage URI
await this.datastore.updateRun({
id: results.runId,
orgId: this.orgId,
updates: {
resultStorageUri: storageUri,
},
});

// Upload to S3 with full (non-truncated) payload and result
await getRunResultsService().storeResults(storageUri, results, { orgId: this.orgId });

logMessage("debug", `Stored run results to S3: ${storageUri}`, this.metadata);
} catch (err) {
logMessage(
"warn",
`Failed to store run results for ${results.runId}: ${err}`,
this.metadata,
);
}
});
}
}
12 changes: 12 additions & 0 deletions packages/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,18 @@ export interface Run {
requestSource?: RequestSource;
traceId?: string;
metadata: RunMetadata;
resultStorageUri?: string; // FileService URI where full results are stored (EE feature)
}

// Stored run results in FileService (EE feature)
export interface StoredRunResults {
runId: string;
success: boolean;
data: any;
stepResults: ToolStepResult[];
toolPayload: Record<string, any>;
error?: string;
storedAt: Date;
}

export interface ApiCallArgs {
Expand Down
2 changes: 1 addition & 1 deletion packages/web/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
import "./.next/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
Loading