Merge pull request #655 from thecodacus/streaming-fixed
Browse filesfix: Add Code Streaming Sampling for Performance Optimization
- app/lib/stores/workbench.ts +8 -2
- app/utils/sampler.ts +49 -0
app/lib/stores/workbench.ts
CHANGED
@@ -16,6 +16,7 @@ import * as nodePath from 'node:path';
|
|
16 |
import { extractRelativePath } from '~/utils/diff';
|
17 |
import { description } from '~/lib/persistence';
|
18 |
import Cookies from 'js-cookie';
|
|
|
19 |
|
20 |
export interface ArtifactState {
|
21 |
id: string;
|
@@ -280,7 +281,7 @@ export class WorkbenchStore {
|
|
280 |
|
281 |
runAction(data: ActionCallbackData, isStreaming: boolean = false) {
|
282 |
if (isStreaming) {
|
283 |
-
this.
|
284 |
} else {
|
285 |
this.addToExecutionQueue(() => this._runAction(data, isStreaming));
|
286 |
}
|
@@ -296,7 +297,8 @@ export class WorkbenchStore {
|
|
296 |
|
297 |
const action = artifact.runner.actions.get()[data.actionId];
|
298 |
|
299 |
-
|
|
|
300 |
return;
|
301 |
}
|
302 |
|
@@ -329,6 +331,10 @@ export class WorkbenchStore {
|
|
329 |
}
|
330 |
}
|
331 |
|
|
|
|
|
|
|
|
|
332 |
#getArtifact(id: string) {
|
333 |
const artifacts = this.artifacts.get();
|
334 |
return artifacts[id];
|
|
|
16 |
import { extractRelativePath } from '~/utils/diff';
|
17 |
import { description } from '~/lib/persistence';
|
18 |
import Cookies from 'js-cookie';
|
19 |
+
import { createSampler } from '~/utils/sampler';
|
20 |
|
21 |
export interface ArtifactState {
|
22 |
id: string;
|
|
|
281 |
|
282 |
runAction(data: ActionCallbackData, isStreaming: boolean = false) {
|
283 |
if (isStreaming) {
|
284 |
+
this.actionStreamSampler(data, isStreaming);
|
285 |
} else {
|
286 |
this.addToExecutionQueue(() => this._runAction(data, isStreaming));
|
287 |
}
|
|
|
297 |
|
298 |
const action = artifact.runner.actions.get()[data.actionId];
|
299 |
|
300 |
+
|
301 |
+
if (!action || action.executed) {
|
302 |
return;
|
303 |
}
|
304 |
|
|
|
331 |
}
|
332 |
}
|
333 |
|
334 |
+
actionStreamSampler = createSampler(async (data: ActionCallbackData, isStreaming: boolean = false) => {
|
335 |
+
return await this._runAction(data, isStreaming);
|
336 |
+
}, 100); // TODO: remove this magic number to have it configurable
|
337 |
+
|
338 |
#getArtifact(id: string) {
|
339 |
const artifacts = this.artifacts.get();
|
340 |
return artifacts[id];
|
app/utils/sampler.ts
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Creates a function that samples calls at regular intervals and captures trailing calls.
|
3 |
+
* - Drops calls that occur between sampling intervals
|
4 |
+
* - Takes one call per sampling interval if available
|
5 |
+
* - Captures the last call if no call was made during the interval
|
6 |
+
*
|
7 |
+
* @param fn The function to sample
|
8 |
+
* @param sampleInterval How often to sample calls (in ms)
|
9 |
+
* @returns The sampled function
|
10 |
+
*/
|
11 |
+
export function createSampler<T extends (...args: any[]) => any>(fn: T, sampleInterval: number): T {
|
12 |
+
let lastArgs: Parameters<T> | null = null;
|
13 |
+
let lastTime = 0;
|
14 |
+
let timeout: NodeJS.Timeout | null = null;
|
15 |
+
|
16 |
+
// Create a function with the same type as the input function
|
17 |
+
const sampled = function (this: any, ...args: Parameters<T>) {
|
18 |
+
const now = Date.now();
|
19 |
+
lastArgs = args;
|
20 |
+
|
21 |
+
// If we're within the sample interval, just store the args
|
22 |
+
if (now - lastTime < sampleInterval) {
|
23 |
+
// Set up trailing call if not already set
|
24 |
+
if (!timeout) {
|
25 |
+
timeout = setTimeout(
|
26 |
+
() => {
|
27 |
+
timeout = null;
|
28 |
+
lastTime = Date.now();
|
29 |
+
|
30 |
+
if (lastArgs) {
|
31 |
+
fn.apply(this, lastArgs);
|
32 |
+
lastArgs = null;
|
33 |
+
}
|
34 |
+
},
|
35 |
+
sampleInterval - (now - lastTime),
|
36 |
+
);
|
37 |
+
}
|
38 |
+
|
39 |
+
return;
|
40 |
+
}
|
41 |
+
|
42 |
+
// If we're outside the interval, execute immediately
|
43 |
+
lastTime = now;
|
44 |
+
fn.apply(this, args);
|
45 |
+
lastArgs = null;
|
46 |
+
} as T;
|
47 |
+
|
48 |
+
return sampled;
|
49 |
+
}
|