mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-03-10 06:00:19 +00:00
Merge branch 'main' into feat/image-select
This commit is contained in:
commit
7a31db904d
@ -1 +1 @@
|
|||||||
{ "commit": "a936c5a99036e0ea65c976e19b3bdb39f8d7cd40" }
|
{ "commit": "6ffcdd8b3c54e2560b327ca1b4f4eb33ba54c0db" }
|
||||||
|
@ -436,12 +436,15 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (isStreaming) {
|
if (isStreaming) {
|
||||||
handleStop?.();
|
handleStop?.();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// ignore if using input method engine
|
||||||
|
if (event.nativeEvent.isComposing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
handleSendMessage?.(event);
|
handleSendMessage?.(event);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -15,6 +15,7 @@ export default function ConnectionsTab() {
|
|||||||
hasToken: !!githubToken,
|
hasToken: !!githubToken,
|
||||||
});
|
});
|
||||||
toast.success('GitHub credentials saved successfully!');
|
toast.success('GitHub credentials saved successfully!');
|
||||||
|
Cookies.set('git:github.com', JSON.stringify({ username: githubToken, password: 'x-oauth-basic' }));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -16,6 +16,7 @@ import * as nodePath from 'node:path';
|
|||||||
import { extractRelativePath } from '~/utils/diff';
|
import { extractRelativePath } from '~/utils/diff';
|
||||||
import { description } from '~/lib/persistence';
|
import { description } from '~/lib/persistence';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
|
import { createSampler } from '~/utils/sampler';
|
||||||
|
|
||||||
export interface ArtifactState {
|
export interface ArtifactState {
|
||||||
id: string;
|
id: string;
|
||||||
@ -280,7 +281,7 @@ export class WorkbenchStore {
|
|||||||
|
|
||||||
runAction(data: ActionCallbackData, isStreaming: boolean = false) {
|
runAction(data: ActionCallbackData, isStreaming: boolean = false) {
|
||||||
if (isStreaming) {
|
if (isStreaming) {
|
||||||
this._runAction(data, isStreaming);
|
this.actionStreamSampler(data, isStreaming);
|
||||||
} else {
|
} else {
|
||||||
this.addToExecutionQueue(() => this._runAction(data, isStreaming));
|
this.addToExecutionQueue(() => this._runAction(data, isStreaming));
|
||||||
}
|
}
|
||||||
@ -296,7 +297,8 @@ export class WorkbenchStore {
|
|||||||
|
|
||||||
const action = artifact.runner.actions.get()[data.actionId];
|
const action = artifact.runner.actions.get()[data.actionId];
|
||||||
|
|
||||||
if (action.executed) {
|
|
||||||
|
if (!action || action.executed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,6 +331,10 @@ export class WorkbenchStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actionStreamSampler = createSampler(async (data: ActionCallbackData, isStreaming: boolean = false) => {
|
||||||
|
return await this._runAction(data, isStreaming);
|
||||||
|
}, 100); // TODO: remove this magic number to have it configurable
|
||||||
|
|
||||||
#getArtifact(id: string) {
|
#getArtifact(id: string) {
|
||||||
const artifacts = this.artifacts.get();
|
const artifacts = this.artifacts.get();
|
||||||
return artifacts[id];
|
return artifacts[id];
|
||||||
|
49
app/utils/sampler.ts
Normal file
49
app/utils/sampler.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Creates a function that samples calls at regular intervals and captures trailing calls.
|
||||||
|
* - Drops calls that occur between sampling intervals
|
||||||
|
* - Takes one call per sampling interval if available
|
||||||
|
* - Captures the last call if no call was made during the interval
|
||||||
|
*
|
||||||
|
* @param fn The function to sample
|
||||||
|
* @param sampleInterval How often to sample calls (in ms)
|
||||||
|
* @returns The sampled function
|
||||||
|
*/
|
||||||
|
export function createSampler<T extends (...args: any[]) => any>(fn: T, sampleInterval: number): T {
|
||||||
|
let lastArgs: Parameters<T> | null = null;
|
||||||
|
let lastTime = 0;
|
||||||
|
let timeout: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
// Create a function with the same type as the input function
|
||||||
|
const sampled = function (this: any, ...args: Parameters<T>) {
|
||||||
|
const now = Date.now();
|
||||||
|
lastArgs = args;
|
||||||
|
|
||||||
|
// If we're within the sample interval, just store the args
|
||||||
|
if (now - lastTime < sampleInterval) {
|
||||||
|
// Set up trailing call if not already set
|
||||||
|
if (!timeout) {
|
||||||
|
timeout = setTimeout(
|
||||||
|
() => {
|
||||||
|
timeout = null;
|
||||||
|
lastTime = Date.now();
|
||||||
|
|
||||||
|
if (lastArgs) {
|
||||||
|
fn.apply(this, lastArgs);
|
||||||
|
lastArgs = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sampleInterval - (now - lastTime),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're outside the interval, execute immediately
|
||||||
|
lastTime = now;
|
||||||
|
fn.apply(this, args);
|
||||||
|
lastArgs = null;
|
||||||
|
} as T;
|
||||||
|
|
||||||
|
return sampled;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user