Skip to content

Commit beed730

Browse files
authored
Merge pull request #1894 from refly-ai/main
Staging Release 20251219
2 parents a5b3db7 + 70d7872 commit beed730

File tree

55 files changed

+1958
-716
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1958
-716
lines changed

.vscode/launch.json

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -35,60 +35,6 @@
3535
"resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"],
3636
"outFiles": ["${workspaceFolder}/apps/api/dist/**/*.js"]
3737
},
38-
{
39-
"type": "node",
40-
"request": "launch",
41-
"name": "Debug API (Direct)",
42-
"program": "${workspaceFolder}/apps/api/src/main.ts",
43-
"preLaunchTask": "npm: build:api",
44-
"cwd": "${workspaceFolder}/apps/api",
45-
"console": "integratedTerminal",
46-
"runtimeArgs": ["--inspect-brk", "-r", "ts-node/register", "-r", "tsconfig-paths/register"],
47-
"skipFiles": ["<node_internals>/**"],
48-
"sourceMaps": true,
49-
"outFiles": ["${workspaceFolder}/apps/api/dist/**/*.js"]
50-
},
51-
{
52-
"type": "node",
53-
"request": "launch",
54-
"name": "Debug Fish TTS - Basic Usage",
55-
"program": "${workspaceFolder}/scripts/demo/fish-tts/config-based-demo/examples/basic-usage.ts",
56-
"cwd": "${workspaceFolder}/scripts/demo/fish-tts/config-based-demo",
57-
"console": "integratedTerminal",
58-
"runtimeArgs": ["-r", "ts-node/register"],
59-
"skipFiles": ["<node_internals>/**"],
60-
"sourceMaps": true,
61-
"env": {
62-
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
63-
}
64-
},
65-
{
66-
"type": "node",
67-
"request": "launch",
68-
"name": "Debug Fish TTS - Custom Handlers",
69-
"program": "${workspaceFolder}/scripts/demo/fish-tts/config-based-demo/examples/custom-handlers.ts",
70-
"cwd": "${workspaceFolder}/scripts/demo/fish-tts/config-based-demo",
71-
"console": "integratedTerminal",
72-
"runtimeArgs": ["-r", "ts-node/register"],
73-
"skipFiles": ["<node_internals>/**"],
74-
"sourceMaps": true,
75-
"env": {
76-
"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
77-
}
78-
},
79-
{
80-
"type": "node",
81-
"request": "launch",
82-
"name": "Debug Tool Service Tests",
83-
"program": "${workspaceFolder}/node_modules/.bin/jest",
84-
"args": ["--runInBand", "--no-cache", "--watchAll=false", "tool.service.spec.ts"],
85-
"cwd": "${workspaceFolder}/apps/api",
86-
"console": "integratedTerminal",
87-
"internalConsoleOptions": "neverOpen",
88-
"env": {
89-
"NODE_ENV": "test"
90-
}
91-
},
9238
{
9339
"type": "node",
9440
"request": "launch",

.vscode/settings.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
},
66
"files.eol": "\n",
77
"editor.formatOnSave": true,
8-
"editor.defaultFormatter": "biomejs.biome",
98
"typescript.preferences.importModuleSpecifier": "non-relative",
109
"tailwindCSS.includeLanguages": {
1110
"typescript": "tsx",
@@ -15,10 +14,7 @@
1514
"scss": "scss"
1615
},
1716
"[typescript]": {
18-
"editor.defaultFormatter": "biomejs.biome"
19-
},
20-
"[typescriptreact]": {
21-
"editor.defaultFormatter": "biomejs.biome"
17+
"editor.defaultFormatter": "prettier.prettier-vscode"
2218
},
2319

2420
"typescript.tsserver.maxTsServerMemory": 8192,
@@ -38,7 +34,5 @@
3834
},
3935
"typescript.tsdk": "node_modules/typescript/lib",
4036
"eslint.enable": false,
41-
"[sql]": {
42-
"editor.defaultFormatter": "cweijan.vscode-postgresql-client2"
43-
}
37+
"cSpell.words": ["Volcengine"]
4438
}

apps/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"sync-db-schema": "prisma format && prisma generate && node -r ts-node/register --env-file=.env src/scripts/sync-db-schema.ts",
2222
"dev": "prisma format && prisma generate && nodemon src/main.ts",
2323
"dev:debug": "nodemon --inspect src/main.ts",
24+
"dev:node": "node --trace-warnings --inspect=0.0.0.0:9229 -r ts-node/register -r tsconfig-paths/register src/main.ts",
2425
"start": "node -r ./scripts/preload.js dist/main.js",
2526
"test": "jest",
2627
"test:watch": "jest --watch",

apps/api/src/modules/drive/drive.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ export class DriveService implements OnModuleInit {
270270

271271
// Move object in storage
272272
await this.internalOss.moveObject(originalStorageKey, archiveStorageKey);
273+
await this.externalOss.moveObject(originalStorageKey, archiveStorageKey);
273274

274275
this.logger.debug(`Successfully archived file ${file.fileId} to ${archiveStorageKey}`);
275276
return { success: true, fileId: file.fileId };

apps/api/src/modules/share/share-duplication.service.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,30 @@ export class ShareDuplicationService {
970970

971971
await Promise.all([...libDupPromises, ...skillDupPromises]);
972972

973+
// Update resultId for duplicated drive files
974+
// The files were duplicated with old resultId, now we need to update them with new resultId
975+
if (fileIdMap.size > 0) {
976+
const newFileIds = Array.from(fileIdMap.values());
977+
const driveFilesToUpdate = await this.prisma.driveFile.findMany({
978+
where: { fileId: { in: newFileIds } },
979+
select: { pk: true, fileId: true, resultId: true },
980+
});
981+
982+
const updatePromises = driveFilesToUpdate
983+
.filter((file) => file.resultId && replaceEntityMap[file.resultId])
984+
.map((file) =>
985+
this.prisma.driveFile.update({
986+
where: { pk: file.pk },
987+
data: { resultId: replaceEntityMap[file.resultId!] },
988+
}),
989+
);
990+
991+
if (updatePromises.length > 0) {
992+
await Promise.all(updatePromises);
993+
this.logger.log(`Updated resultId for ${updatePromises.length} duplicated drive files`);
994+
}
995+
}
996+
973997
// Update canvas state and save
974998
state.nodes = nodes;
975999
state.edges = edges;

apps/api/src/modules/tool/dynamic-tooling/adapters/http-adapter.ts

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { supportedMimeTypes } from 'file-type';
1414
import { AdapterType, HttpMethod, AdapterError } from '../../constant/constant';
1515
import { BaseAdapter, type IHttpAdapter } from '../core/adapter';
1616
import { HttpClient } from './http-client';
17+
import { getToolName, getToolsetKey } from '../../tool-context';
18+
import { isVolcengineAuth, VolcenginePollingHelper, applyVolcengineSigning } from './volcengine';
1719

1820
/**
1921
* HTTP adapter for making HTTP API calls with intelligent polling support
@@ -86,6 +88,22 @@ export class HttpAdapter extends BaseAdapter implements IHttpAdapter {
8688
initialResponse: AdapterResponse,
8789
request: AdapterRequest,
8890
): Promise<AdapterResponse> {
91+
const toolsetKey = getToolsetKey() || '';
92+
// Use Volcengine-specific polling for Volcengine toolsets
93+
// This handles task_id extraction from data.task_id (not request_id)
94+
if (toolsetKey.startsWith('volcengine')) {
95+
const volcengineHelper = new VolcenginePollingHelper();
96+
return await volcengineHelper.handleVolcenginePolling(initialResponse, {
97+
httpClient: this.httpClient,
98+
pollingConfig: this.pollingConfig!,
99+
credentials: request.credentials || {},
100+
params: (request.params as Record<string, unknown>) || {},
101+
headers: request.headers,
102+
timeout: request.timeout,
103+
toolName: getToolName() || undefined,
104+
});
105+
}
106+
89107
// Auto-detect task ID from initial response
90108
const taskId = this.autoDetectTaskId(initialResponse.data);
91109
if (!taskId) {
@@ -119,10 +137,6 @@ export class HttpAdapter extends BaseAdapter implements IHttpAdapter {
119137
...request.headers,
120138
};
121139

122-
// Add authentication headers from credentials
123-
if (request.credentials) {
124-
this.addAuthHeaders(headers, request.credentials);
125-
}
126140
// Prepare request data
127141
let requestData: unknown;
128142
const contentType = headers['Content-Type'] || headers['content-type'];
@@ -144,11 +158,44 @@ export class HttpAdapter extends BaseAdapter implements IHttpAdapter {
144158
}
145159
}
146160

147-
// Execute request based on HTTP method
161+
// Add authentication headers from credentials
162+
// Skip addAuthHeaders for Volcengine auth since it has its own signing
163+
const skipAuth =
164+
getToolsetKey().startsWith('volcengine') ||
165+
(request.credentials && isVolcengineAuth(request.credentials as Record<string, unknown>));
166+
167+
if (request.credentials && !skipAuth) {
168+
this.addAuthHeaders(headers, request.credentials);
169+
}
170+
171+
// Apply Volcengine HMAC-SHA256 signing for initial request
148172
const method = request.method?.toUpperCase() || HttpMethod.POST;
173+
let finalEndpoint = request.endpoint;
174+
175+
if (skipAuth && request.credentials) {
176+
const signResult = applyVolcengineSigning({
177+
credentials: request.credentials as Record<string, unknown>,
178+
params: (params as Record<string, unknown>) || {},
179+
endpoint: request.endpoint,
180+
method,
181+
requestData,
182+
headers,
183+
});
184+
185+
if (signResult.signed) {
186+
// Apply signed headers
187+
for (const [key, value] of Object.entries(signResult.headers)) {
188+
if (value !== undefined) {
189+
headers[key] = value;
190+
}
191+
}
192+
// Use the signed URL (includes Action, Version, and proper query string)
193+
finalEndpoint = signResult.endpoint;
194+
}
195+
}
149196
const response = await this.sendHttpRequest(
150197
method,
151-
request.endpoint,
198+
finalEndpoint,
152199
params,
153200
requestData,
154201
headers,
@@ -526,31 +573,6 @@ export class HttpAdapter extends BaseAdapter implements IHttpAdapter {
526573
return null;
527574
}
528575

529-
/**
530-
* Auto-download file if response contains URL pointing to binary content
531-
* If URL returns non-binary content (like JSON), return original data
532-
*/
533-
private async autoDownloadIfNeeded(data: any, taskId: string): Promise<any> {
534-
// Recursively find all URLs
535-
const urls = this.findAllUrls(data);
536-
537-
if (urls.length === 0) {
538-
return data;
539-
}
540-
541-
// Check if the URL points to downloadable binary content
542-
const primaryUrl = urls[0];
543-
const isDownloadable = await this.isDownloadableUrl(primaryUrl.value);
544-
545-
if (!isDownloadable) {
546-
this.logger.log(`URL ${primaryUrl.path} does not point to binary content, skipping download`);
547-
return data;
548-
}
549-
550-
this.logger.log(`🔽 Downloading from: ${primaryUrl.path} = ${primaryUrl.value}`);
551-
return await this.downloadFile(primaryUrl.value, data, taskId);
552-
}
553-
554576
/**
555577
* Check if URL points to downloadable binary content using HEAD request
556578
*/

0 commit comments

Comments
 (0)