codacus commited on
Commit
4af18c0
·
unverified ·
2 Parent(s): 81d2c01 02d0be5

Merge pull request #655 from thecodacus/streaming-fixed

Browse files

fix: Add Code Streaming Sampling for Performance Optimization

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._runAction(data, isStreaming);
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
- if (action.executed) {
 
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
+ }