feat: add Pi provider managed resources
This commit is contained in:
102
electron/coding-runtime/pi/managed-input-revision.ts
Normal file
102
electron/coding-runtime/pi/managed-input-revision.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
export interface PiManagedInputRevision {
|
||||
provider: number;
|
||||
resources: number;
|
||||
}
|
||||
|
||||
export type PiManagedInputAction =
|
||||
| { action: 'reuse'; revision: PiManagedInputRevision }
|
||||
| { action: 'rebuild-before-prompt'; revision: PiManagedInputRevision }
|
||||
| { action: 'rebuild-after-settled'; revision: PiManagedInputRevision }
|
||||
| { action: 'defer-until-settled'; revision: PiManagedInputRevision };
|
||||
|
||||
interface WorkerRevisionState {
|
||||
applied: PiManagedInputRevision;
|
||||
activeRun: PiManagedInputRevision | null;
|
||||
}
|
||||
|
||||
function copyRevision(revision: PiManagedInputRevision): PiManagedInputRevision {
|
||||
return { provider: revision.provider, resources: revision.resources };
|
||||
}
|
||||
|
||||
function revisionsEqual(left: PiManagedInputRevision, right: PiManagedInputRevision): boolean {
|
||||
return left.provider === right.provider && left.resources === right.resources;
|
||||
}
|
||||
|
||||
export class PiManagedInputRevisionCoordinator {
|
||||
private currentRevision: PiManagedInputRevision = { provider: 1, resources: 1 };
|
||||
private readonly workers = new Map<string, WorkerRevisionState>();
|
||||
|
||||
get current(): PiManagedInputRevision {
|
||||
return copyRevision(this.currentRevision);
|
||||
}
|
||||
|
||||
markProviderStale(): PiManagedInputRevision {
|
||||
this.currentRevision = {
|
||||
provider: this.currentRevision.provider + 1,
|
||||
resources: this.currentRevision.resources,
|
||||
};
|
||||
return this.current;
|
||||
}
|
||||
|
||||
markResourcesStale(): PiManagedInputRevision {
|
||||
this.currentRevision = {
|
||||
provider: this.currentRevision.provider,
|
||||
resources: this.currentRevision.resources + 1,
|
||||
};
|
||||
return this.current;
|
||||
}
|
||||
|
||||
registerWorker(workerId: string, applied: PiManagedInputRevision = this.currentRevision): void {
|
||||
if (!workerId.trim()) throw new Error('Worker id is required');
|
||||
if (this.workers.has(workerId)) throw new Error(`Worker is already registered: ${workerId}`);
|
||||
this.workers.set(workerId, { applied: copyRevision(applied), activeRun: null });
|
||||
}
|
||||
|
||||
removeWorker(workerId: string): void {
|
||||
this.workers.delete(workerId);
|
||||
}
|
||||
|
||||
beforePrompt(workerId: string): PiManagedInputAction {
|
||||
const worker = this.requireWorker(workerId);
|
||||
if (worker.activeRun) {
|
||||
return revisionsEqual(worker.applied, this.currentRevision)
|
||||
? { action: 'reuse', revision: copyRevision(worker.activeRun) }
|
||||
: { action: 'defer-until-settled', revision: copyRevision(worker.activeRun) };
|
||||
}
|
||||
return revisionsEqual(worker.applied, this.currentRevision)
|
||||
? { action: 'reuse', revision: copyRevision(worker.applied) }
|
||||
: { action: 'rebuild-before-prompt', revision: this.current };
|
||||
}
|
||||
|
||||
applyCurrentRevision(workerId: string): PiManagedInputRevision {
|
||||
const worker = this.requireWorker(workerId);
|
||||
if (worker.activeRun) throw new Error('Cannot rebuild managed input while a run is active');
|
||||
worker.applied = this.current;
|
||||
return copyRevision(worker.applied);
|
||||
}
|
||||
|
||||
beginRun(workerId: string): PiManagedInputRevision {
|
||||
const worker = this.requireWorker(workerId);
|
||||
if (worker.activeRun) throw new Error('Worker already has an active run');
|
||||
if (!revisionsEqual(worker.applied, this.currentRevision)) {
|
||||
throw new Error('Worker managed input is stale');
|
||||
}
|
||||
worker.activeRun = copyRevision(worker.applied);
|
||||
return copyRevision(worker.activeRun);
|
||||
}
|
||||
|
||||
settleRun(workerId: string): PiManagedInputAction {
|
||||
const worker = this.requireWorker(workerId);
|
||||
if (!worker.activeRun) throw new Error('Worker has no active run');
|
||||
worker.activeRun = null;
|
||||
return revisionsEqual(worker.applied, this.currentRevision)
|
||||
? { action: 'reuse', revision: copyRevision(worker.applied) }
|
||||
: { action: 'rebuild-after-settled', revision: this.current };
|
||||
}
|
||||
|
||||
private requireWorker(workerId: string): WorkerRevisionState {
|
||||
const worker = this.workers.get(workerId);
|
||||
if (!worker) throw new Error(`Worker is not registered: ${workerId}`);
|
||||
return worker;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user