Skip to content

Refactoring: Introduced RunState as a facade for (RunObserver and TopGraphObserver) #4982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/bbrt/src/components/board-visualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { MAIN_BOARD_ID } from "../../../shared-ui/dist/constants/constants.js";
import type { GraphOpts } from "../../../shared-ui/dist/elements/editor/types.js";
import { TopGraphObserver } from "../../../shared-ui/dist/utils/utils.js";
import { getTopGraphRunResult } from "../../../shared-ui/dist/utils/utils.js";
import { loadSharedUi } from "../util/load-shared-ui.js";

@customElement("bbrt-board-visualizer")
Expand Down Expand Up @@ -44,7 +44,7 @@ export class BBRTBoardVisualizer extends LitElement {
return html`<bb-graph-renderer
.configs=${new Map([[MAIN_BOARD_ID, this.#config(graph)]])}
.topGraphUrl=${graph.url ?? "no-url"}
.topGraphResult=${TopGraphObserver.entryResult(graph)}
.topGraphResult=${getTopGraphRunResult(graph)}
.assetPrefix=${""}
.invertZoomScrollDirection=${false}
.readOnly=${false}
Expand Down
1 change: 0 additions & 1 deletion packages/breadboard/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ export {
*/
export {
createGraphStore,
createRunObserver,
inspect,
} from "./inspector/index.js";
export * from "./inspector/types.js";
Expand Down
7 changes: 0 additions & 7 deletions packages/breadboard/src/inspector/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ export const inspect = (
return new Graph("", new MutableGraphImpl(graph, store));
};

export const createRunObserver = (
store: MutableGraphStore,
options?: RunObserverOptions
): InspectableRunObserver => {
return new RunObserver(store, options || {});
};

export { Run } from "./run/run.js";

export function createGraphStore(args: GraphStoreArgs): MutableGraphStore {
Expand Down
2 changes: 1 addition & 1 deletion packages/breadboard/src/inspector/run/past-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class PastRun implements InspectableRun {
const observer = new RunObserver(graphStore, {
logLevel: "debug",
});
for await (const result of this.replay()) {
for await (const result of this.#replay.replay()) {
await observer.observe(result);
}
this.#backingRun = (await observer.runs())[0];
Expand Down
10 changes: 5 additions & 5 deletions packages/breadboard/tests/inspector/observer-load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import {
InspectableRunEvent,
InspectableRunObserver,
} from "../../src/inspector/types.js";
import { createRunObserver } from "../../src/index.js";
import { HarnessRunResult } from "../../src/harness/types.js";
import { replaceSecrets } from "../../src/inspector/run/serializer.js";
import {
createDefaultDataStore,
createDefaultRunStore,
} from "../../src/data/index.js";
import { makeTestGraphStore } from "../helpers/_graph-store.js";
import { RunObserver } from "../../src/inspector/run/run.js";

const BASE_PATH = new URL(
"../../../tests/inspector/data/loader",
Expand Down Expand Up @@ -89,7 +89,7 @@ const GEMINI_SENTINEL = "103e9083-13fd-46b4-a9ee-683a09e31a26";

test("run save/load: loadRawRun works as expected", async (t) => {
const store = makeTestGraphStore();
const observer = createRunObserver(store, {
const observer = new RunObserver(store, {
logLevel: "debug",
});
const run1 = await loadRawRun(observer, "ad-writer-2.1.raw.json");
Expand All @@ -99,7 +99,7 @@ test("run save/load: loadRawRun works as expected", async (t) => {

test("run save/load: observer.save -> run.load roundtrip", async (t) => {
const store = makeTestGraphStore();
const observer = createRunObserver(store, {
const observer = new RunObserver(store, {
logLevel: "debug",
dataStore: createDefaultDataStore(),
runStore: createDefaultRunStore(),
Expand All @@ -120,7 +120,7 @@ test("run save/load: observer.save -> run.load roundtrip", async (t) => {

test("run save/load: replaceSecrets correctly replaces secrets", async (t) => {
const store = makeTestGraphStore();
const observer = createRunObserver(store, {
const observer = new RunObserver(store, {
logLevel: "debug",
});
const run1 = await loadRawRun(observer, "ad-writer-2.1.raw.json");
Expand Down Expand Up @@ -170,7 +170,7 @@ test("run save/load: replaceSecrets correctly replaces secrets", async (t) => {

test("run load/save: serialization produces consistent size", async (t) => {
const store = makeTestGraphStore();
const observer = createRunObserver(store, {
const observer = new RunObserver(store, {
logLevel: "debug",
dataStore: createDefaultDataStore(),
runStore: createDefaultRunStore(),
Expand Down
4 changes: 4 additions & 0 deletions packages/shared-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
"default": "./dist/elements/connection/connection-broker.js",
"types": "./dist/elements/connection/connection-broker.d.ts"
},
"./utils/run-state": {
"default": "./dist/utils/run-state.js",
"types": "./dist/utils/run-state.d.ts"
},
"./data/settings-store.js": {
"default": "./dist/data/settings-store.js",
"types": "./dist/data/settings-store.d.ts"
Expand Down
15 changes: 11 additions & 4 deletions packages/shared-ui/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
PortIdentifier,
NodeHandlerMetadata,
InspectableRun,
InspectableRunSequenceEntry,
} from "@google-labs/breadboard";
import {
CommentNode,
Expand Down Expand Up @@ -268,10 +269,10 @@ export type ErrorLogEntry = {

export type LogEntry = NodeLogEntry | EdgeLogEntry | ErrorLogEntry;

export type TopGraphObserverRunStatus = "running" | "paused" | "stopped";
export type GraphObserverRunStatus = "running" | "paused" | "stopped";

/**
* The result, returned by the TopGraphObserver.
* The result, returned by the GraphObserver.
*/
export type TopGraphRunResult = {
/**
Expand Down Expand Up @@ -307,7 +308,7 @@ export type TopGraphRunResult = {
* - "paused": The run is paused.
* - "stopped": The run is stopped.
*/
status: TopGraphObserverRunStatus;
status: GraphObserverRunStatus;
};

export type ComparableEdge = {
Expand All @@ -316,7 +317,7 @@ export type ComparableEdge = {

/**
* Reflects the current status of the edge:
* - "initilal" -- the edge is in its initial state: no
* - "initial" -- the edge is in its initial state: no
* values have been stored on or consumed from this edge.
* - "stored" -- a value was stored on the edge, but not yet consumed by the
* receiving node.
Expand Down Expand Up @@ -559,3 +560,9 @@ export interface Utterance {
confidence: number;
transcript: string;
}

export interface GraphObserver {
current(): TopGraphRunResult | null;
startWith(entries: InspectableRunSequenceEntry[]): void;
updateAffected(affectedNodes: NodeIdentifier[]): void;
}
4 changes: 3 additions & 1 deletion packages/shared-ui/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export {
isTextBehavior,
} from "./behaviors.js";

export {RunState} from './run-state.js';

export function itemsMatch(schema1: Schema, schema2: Schema): boolean {
if (!schema1.items) return false;
if (!schema2.items) return false;
Expand Down Expand Up @@ -101,4 +103,4 @@ export function escapeHTMLEntities(str: string) {
return str
.replace(/&(?!lt|gt)/, "&amp;")
.replace(/[<>]/g, (char) => htmlEntities[char]);
}
}
107 changes: 107 additions & 0 deletions packages/shared-ui/src/utils/run-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { NodeIdentifier } from "@breadboard-ai/types";
import { InspectableRun, InspectableRunLoadResult, InspectableRunObserver, InspectableRunSequenceEntry, MutableGraphStore, RunObserverOptions, SerializedRunLoadingOptions } from "@google-labs/breadboard";

import type { HarnessRunner , HarnessRunResult }from "@google-labs/breadboard/harness";
import { TopGraphObserver } from "./top-graph-observer";
import { RunObserver } from "../../../breadboard/dist/src/inspector/run/run";
import { GraphObserver } from "../types/types";

export class RunState implements InspectableRunObserver {
#runObserver: InspectableRunObserver | undefined = undefined;
#graphObserver: GraphObserver | undefined = undefined;

static createForPastRun(run: InspectableRun): RunState {
return new RunState(undefined, undefined, run, undefined);
}

static create(store: MutableGraphStore, options: RunObserverOptions, harness?: HarnessRunner): RunState {
return new RunState(store, options, undefined, harness);
}

private constructor(
private store: MutableGraphStore | undefined,
private options: RunObserverOptions | undefined,
private pastRun: InspectableRun | undefined,
private harness: HarnessRunner | undefined) {
if (!store && !pastRun) {
throw new Error("Must provide either a store or a past run");
}
}

async runs(): Promise<InspectableRun[]> {
if (this.pastRun) {
return [this.pastRun];
}
return this.maybeRunObserver()?.runs() ?? [];
}

resume?() {
const maybeObserver = this.maybeRunObserver();
if (maybeObserver?.resume) {
maybeObserver.resume();
}
}

async observe(result: HarnessRunResult): Promise<void> {
const maybeObserver = this.maybeRunObserver();
if (maybeObserver) {
await maybeObserver.observe(result);
}
}
load(o: unknown, options?: SerializedRunLoadingOptions): Promise<InspectableRunLoadResult> {
return this.#demandRunObserver()?.load(o, options);
}
append(history: InspectableRunSequenceEntry[]): Promise<void> {
return this.#demandRunObserver().append(history);
}
async replay(stopAt: NodeIdentifier[]): Promise<void> {
const maybeObserver = this.maybeRunObserver();
if (maybeObserver) {
await this.maybeRunObserver()?.replay(stopAt);
}
}

maybeRunObserver(): InspectableRunObserver|undefined {
if (!this.#runObserver && this.store) {
this.#runObserver = new RunObserver(this.store!, this.options ?? {});
}
return this.#runObserver;
}

#demandRunObserver(): InspectableRunObserver {
const result = this.maybeRunObserver();
if (!result) {
throw new Error("Unable to create observer");
}
return result;
}

async maybeGraphObserver(): Promise<GraphObserver|undefined> {
if (!this.#graphObserver) {
if (this.pastRun) {
this.#graphObserver = await TopGraphObserver.fromRun(this.pastRun);
} else if (this.harness) {
this.#graphObserver = new TopGraphObserver(this.harness);
}
}
return this.#graphObserver;
}

async demandGraphObserver(): Promise<GraphObserver> {
const result = await this.maybeGraphObserver();
if (!result) {
throw new Error("Unable to create TopGraphObserver");
}
return result;
}

demandGraphObserverFromHarness(): GraphObserver {
if (!this.harness) {
throw new Error("Invalid state: RunHarness is required.");
}
if (!this.#graphObserver) {
this.#graphObserver = new TopGraphObserver(this.harness);
}
return this.#graphObserver;
}
}
2 changes: 1 addition & 1 deletion packages/shared-ui/src/utils/top-graph-observer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* SPDX-License-Identifier: Apache-2.0
*/

export { TopGraphObserver } from "./top-graph-observer.js";
export { TopGraphObserver, getTopGraphRunResult } from "./top-graph-observer.js";
Loading