Skip to content

Commit

Permalink
[build] Pass context to invoke functions (breadboard-ai#1518)
Browse files Browse the repository at this point in the history
  • Loading branch information
aomarks authored Apr 25, 2024
1 parent 99fcffe commit cfbcdf2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/strong-planets-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@breadboard-ai/build": patch
---

Pass NodeHandlerContext to invoke functions
21 changes: 12 additions & 9 deletions packages/build/src/internal/define/define.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import type {
NodeDescriberContext,
NodeHandlerContext,
NodeHandlerMetadata,
} from "@google-labs/breadboard";
import type { CountUnion, Expand, MaybePromise } from "../common/type-util.js";
Expand Down Expand Up @@ -179,10 +180,7 @@ export function defineNodeType<
params.outputs["*"],
primary(params.inputs),
primary(params.outputs),
params.invoke as Function as (
staticParams: Record<string, JsonSerializable>,
dynamicParams: Record<string, JsonSerializable>
) => { [K: string]: JsonSerializable },
params.invoke as Function as VeryLooseInvokeFn,
params.describe as LooseDescribeFn
);
return Object.assign(impl.instantiate.bind(impl), {
Expand Down Expand Up @@ -245,19 +243,24 @@ type LooseInvokeFn<I extends Record<string, InputPortConfig>> = Expand<
(
staticParams: Expand<StaticInvokeParams<I>>,
dynamicParams: Expand<DynamicInvokeParams<I>>
) =>
| { [K: string]: JsonSerializable }
| Promise<{ [K: string]: JsonSerializable }>
) => MaybePromise<{ [K: string]: JsonSerializable }>
>;

export type VeryLooseInvokeFn = (
staticParams: Record<string, JsonSerializable>,
dynamicParams: Record<string, JsonSerializable>,
context: NodeHandlerContext
) => { [K: string]: JsonSerializable };

type StrictInvokeFn<
I extends Record<string, InputPortConfig>,
O extends Record<string, OutputPortConfig>,
F extends LooseInvokeFn<I>,
> = (
staticInputs: Expand<StaticInvokeParams<I>>,
dynamicInputs: Expand<DynamicInvokeParams<I>>
) => StrictInvokeFnReturn<I, O, F> | Promise<StrictInvokeFnReturn<I, O, F>>;
dynamicInputs: Expand<DynamicInvokeParams<I>>,
context: NodeHandlerContext
) => MaybePromise<StrictInvokeFnReturn<I, O, F>>;

type StrictInvokeFnReturn<
I extends Record<string, InputPortConfig>,
Expand Down
25 changes: 13 additions & 12 deletions packages/build/src/internal/define/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
InputValues,
NodeDescriberContext,
NodeDescriberResult,
NodeHandlerContext,
OutputValues,
Schema,
} from "@google-labs/breadboard";
Expand All @@ -26,7 +27,11 @@ import type {
StaticInputPortConfig,
StaticOutputPortConfig,
} from "./config.js";
import type { DynamicInputPorts, LooseDescribeFn } from "./define.js";
import type {
DynamicInputPorts,
LooseDescribeFn,
VeryLooseInvokeFn,
} from "./define.js";
import { Instance } from "./instance.js";
import { portConfigMapToJSONSchema } from "./json-schema.js";

Expand Down Expand Up @@ -71,11 +76,7 @@ export class DefinitionImpl<
readonly #reflective: boolean;
readonly #primaryInput: string | undefined;
readonly #primaryOutput: string | undefined;
// TODO(aomarks) Support promises
readonly #invoke: (
staticParams: Record<string, JsonSerializable>,
dynamicParams: Record<string, JsonSerializable>
) => { [K: string]: JsonSerializable };
readonly #invoke: VeryLooseInvokeFn;
readonly #describe?: LooseDescribeFn;

constructor(
Expand All @@ -86,10 +87,7 @@ export class DefinitionImpl<
dynamicOutputs: DynamicOutputPortConfig | undefined,
primaryInput: string | undefined,
primaryOutput: string | undefined,
invoke: (
staticParams: Record<string, JsonSerializable>,
dynamicParams: Record<string, JsonSerializable>
) => { [K: string]: JsonSerializable },
invoke: VeryLooseInvokeFn,
describe?: LooseDescribeFn
) {
this.#name = name;
Expand Down Expand Up @@ -130,10 +128,13 @@ export class DefinitionImpl<
);
}

invoke(values: InputValues): Promise<OutputValues> {
invoke(
values: InputValues,
context: NodeHandlerContext
): Promise<OutputValues> {
const { staticValues, dynamicValues } =
this.#applyDefaultsAndPartitionRuntimeInputValues(values);
return Promise.resolve(this.#invoke(staticValues, dynamicValues));
return Promise.resolve(this.#invoke(staticValues, dynamicValues, context));
}

/**
Expand Down
28 changes: 28 additions & 0 deletions packages/build/src/test/invoke_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import type { NodeHandlerContext } from "@google-labs/breadboard";
import assert from "node:assert/strict";
import { test } from "node:test";
import { defineNodeType } from "../internal/define/define.js";

test("invoke receives context", async () => {
const expected: NodeHandlerContext = {
base: new URL("http://example.com/"),
outerGraph: { nodes: [], edges: [] },
};
let actual: NodeHandlerContext | undefined;
defineNodeType({
name: "foo",
inputs: {},
outputs: {},
invoke: (_staticInputs, _dynamicInputs, context) => {
actual = context;
return {};
},
}).invoke({}, expected);
assert.deepEqual(actual, expected);
});

0 comments on commit cfbcdf2

Please sign in to comment.