Skip to content

Commit

Permalink
Implement API that allows rendering Fast Access menu (fka "@" menu).
Browse files Browse the repository at this point in the history
- **Add Project state abstraction.**
- **Sketch out `AtMenu`.**
- **Make graph asset editing actually work.**
- **Populate tools in AtMenu.**
- **Populate components in AtMenu.**
- **Stub out generated assets and rename to "fastAccess"**
- **Introduce `bb-fast-access-menu`.**
- **Plumb proper node metadata and graphId.**
- **Start adding select methods on FastAccess controller.**
- **Make the component wiring work.**
- **Discard some code from direction that's proven wrong.**
- **docs(changeset): Implement API that allows rendering Fast Access
menu (fka "@" menu).**

Fixes #4227.
Progress on #4236.
  • Loading branch information
dglazkov authored Jan 29, 2025
1 parent 7b607eb commit 8e2fc1f
Show file tree
Hide file tree
Showing 18 changed files with 607 additions and 162 deletions.
8 changes: 8 additions & 0 deletions .changeset/wet-timers-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@breadboard-ai/visual-editor": minor
"@google-labs/breadboard": minor
"@breadboard-ai/shared-ui": minor
"@breadboard-ai/a2": minor
---

Implement API that allows rendering Fast Access menu (fka "@" menu).
4 changes: 2 additions & 2 deletions packages/a2/bgl/a2.bgl.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,12 @@
}
},
"text-entry": {
"code": "/**\n * @fileoverview The entry point and a describer for the \"Text\" component. Test.\n */\nimport { ok, defaultLLMContent, toText } from \"./utils\";\nimport {} from \"./common\";\nimport { Template } from \"./template\";\nexport { invoke as default, describe };\nfunction toInput(title = \"Please enter text\") {\n const toInput = {\n type: \"object\",\n properties: {\n request: {\n type: \"object\",\n title,\n behavior: [\"transient\", \"llm-content\"],\n examples: [defaultLLMContent()],\n },\n },\n };\n return toInput;\n}\nasync function invoke({ context, text, description, ...params }) {\n const haveText = text && toText(text).length > 0;\n if (haveText) {\n const template = new Template(text);\n const substituting = await template.substitute(params, async () => \"\");\n if (!ok(substituting)) {\n return substituting;\n }\n return { context: substituting, toMain: \"haveInput\" };\n }\n const title = description ? toText(description) : undefined;\n return { context: \"nothing\", toInput: toInput(title) };\n}\nasync function describe({ inputs: { text } }) {\n const template = new Template(text);\n return {\n inputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context in\",\n behavior: [\"main-port\"],\n },\n description: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Description\",\n description: \"Optionally provide a description to show to the user when run.\",\n },\n text: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Text Contents\",\n description: \"Put your text here\",\n },\n ...template.schemas(),\n },\n ...template.requireds(),\n additionalProperties: false,\n },\n outputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context out\",\n behavior: [\"main-port\"],\n },\n },\n additionalProperties: false,\n },\n };\n}\n",
"code": "/**\n * @fileoverview The entry point and a describer for the \"Text\" component. Test.\n */\nimport { ok, defaultLLMContent, toText } from \"./utils\";\nimport {} from \"./common\";\nimport { Template } from \"./template\";\nexport { invoke as default, describe };\nfunction toInput(title = \"Please enter text\") {\n const toInput = {\n type: \"object\",\n properties: {\n request: {\n type: \"object\",\n title,\n behavior: [\"transient\", \"llm-content\"],\n examples: [defaultLLMContent()],\n },\n },\n };\n return toInput;\n}\nasync function invoke({ context, text, description, ...params }) {\n const haveText = text && toText(text).length > 0;\n if (haveText) {\n const template = new Template(text);\n const substituting = await template.substitute(params, async () => \"\");\n if (!ok(substituting)) {\n return substituting;\n }\n return { context: substituting, toMain: \"haveInput\" };\n }\n const title = description ? toText(description) : undefined;\n return { context: \"nothing\", toInput: toInput(title) };\n}\nasync function describe({ inputs: { text } }) {\n const template = new Template(text);\n return {\n inputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context in\",\n behavior: [\"main-port\"],\n },\n description: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Description\",\n description: \"Optionally provide a description to show to the user when run.\",\n },\n text: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Text Contents\",\n description: \"Put your text here\",\n },\n ...template.schemas(),\n },\n ...template.requireds(),\n additionalProperties: true,\n },\n outputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context out\",\n behavior: [\"main-port\"],\n },\n },\n additionalProperties: false,\n },\n };\n}\n",
"metadata": {
"title": "Text",
"icon": "text",
"source": {
"code": "/**\n * @fileoverview The entry point and a describer for the \"Text\" component. Test.\n */\nimport { ok, defaultLLMContent, toText } from \"./utils\";\nimport { type Params } from \"./common\";\nimport { Template } from \"./template\";\n\nexport { invoke as default, describe };\n\ntype TextInputs = {\n context?: LLMContent[];\n text?: LLMContent;\n description?: LLMContent;\n} & Params;\n\ntype TextOutputs =\n | {\n toInput: Schema;\n context: \"nothing\";\n }\n | {\n toMain: string;\n context: LLMContent;\n };\n\nfunction toInput(title: string = \"Please enter text\") {\n const toInput: Schema = {\n type: \"object\",\n properties: {\n request: {\n type: \"object\",\n title,\n behavior: [\"transient\", \"llm-content\"],\n examples: [defaultLLMContent()],\n },\n },\n };\n return toInput;\n}\n\nasync function invoke({\n context,\n text,\n description,\n ...params\n}: TextInputs): Promise<Outcome<TextOutputs>> {\n const haveText = text && toText(text).length > 0;\n if (haveText) {\n const template = new Template(text);\n const substituting = await template.substitute(params, async () => \"\");\n if (!ok(substituting)) {\n return substituting;\n }\n return { context: substituting, toMain: \"haveInput\" };\n }\n const title = description ? toText(description) : undefined;\n return { context: \"nothing\", toInput: toInput(title) };\n}\n\ntype DescribeInputs = {\n inputs: {\n text?: LLMContent;\n };\n};\n\nasync function describe({ inputs: { text } }: DescribeInputs) {\n const template = new Template(text);\n return {\n inputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context in\",\n behavior: [\"main-port\"],\n },\n description: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Description\",\n description:\n \"Optionally provide a description to show to the user when run.\",\n },\n text: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Text Contents\",\n description: \"Put your text here\",\n },\n ...template.schemas(),\n },\n ...template.requireds(),\n additionalProperties: false,\n } satisfies Schema,\n outputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context out\",\n behavior: [\"main-port\"],\n },\n },\n additionalProperties: false,\n } satisfies Schema,\n };\n}\n",
"code": "/**\n * @fileoverview The entry point and a describer for the \"Text\" component. Test.\n */\nimport { ok, defaultLLMContent, toText } from \"./utils\";\nimport { type Params } from \"./common\";\nimport { Template } from \"./template\";\n\nexport { invoke as default, describe };\n\ntype TextInputs = {\n context?: LLMContent[];\n text?: LLMContent;\n description?: LLMContent;\n} & Params;\n\ntype TextOutputs =\n | {\n toInput: Schema;\n context: \"nothing\";\n }\n | {\n toMain: string;\n context: LLMContent;\n };\n\nfunction toInput(title: string = \"Please enter text\") {\n const toInput: Schema = {\n type: \"object\",\n properties: {\n request: {\n type: \"object\",\n title,\n behavior: [\"transient\", \"llm-content\"],\n examples: [defaultLLMContent()],\n },\n },\n };\n return toInput;\n}\n\nasync function invoke({\n context,\n text,\n description,\n ...params\n}: TextInputs): Promise<Outcome<TextOutputs>> {\n const haveText = text && toText(text).length > 0;\n if (haveText) {\n const template = new Template(text);\n const substituting = await template.substitute(params, async () => \"\");\n if (!ok(substituting)) {\n return substituting;\n }\n return { context: substituting, toMain: \"haveInput\" };\n }\n const title = description ? toText(description) : undefined;\n return { context: \"nothing\", toInput: toInput(title) };\n}\n\ntype DescribeInputs = {\n inputs: {\n text?: LLMContent;\n };\n};\n\nasync function describe({ inputs: { text } }: DescribeInputs) {\n const template = new Template(text);\n return {\n inputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context in\",\n behavior: [\"main-port\"],\n },\n description: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Description\",\n description:\n \"Optionally provide a description to show to the user when run.\",\n },\n text: {\n type: \"object\",\n behavior: [\"llm-content\", \"config\"],\n title: \"Text Contents\",\n description: \"Put your text here\",\n },\n ...template.schemas(),\n },\n ...template.requireds(),\n additionalProperties: true,\n } satisfies Schema,\n outputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"array\",\n items: { type: \"object\", behavior: [\"llm-content\"] },\n title: \"Context out\",\n behavior: [\"main-port\"],\n },\n },\n additionalProperties: false,\n } satisfies Schema,\n };\n}\n",
"language": "typescript"
},
"description": "The entry point and a describer for the \"Text\" component. Test.",
Expand Down
112 changes: 84 additions & 28 deletions packages/a2/bgl/organizer-demo.bgl.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"version": "0.0.1",
"nodes": [
{
"type": "input",
"id": "input",
"type": "output",
"id": "output",
"configuration": {
"schema": {
"properties": {
Expand All @@ -14,9 +14,11 @@
"title": "Context",
"items": {
"type": "object",
"behavior": ["llm-content"]
"behavior": [
"llm-content"
]
},
"default": "[{\"role\":\"user\",\"parts\":[{\"text\":\"\"}]}]"
"default": "null"
}
},
"type": "object",
Expand All @@ -25,48 +27,69 @@
},
"metadata": {
"visual": {
"x": -80,
"y": -260,
"x": 439.99999999999994,
"y": -300.0000000000001,
"collapsed": "expanded",
"outputHeight": 44
}
}
},
{
"type": "output",
"id": "output",
"id": "a2-09645fb2",
"type": "file://bgl/a2.bgl.json#21ee02e7-83fa-49d0-964c-0cab10eafc2c",
"metadata": {
"visual": {
"x": 120.00000000000006,
"y": -300.0000000000001,
"collapsed": "expanded",
"outputHeight": 44
},
"title": "Goes Here",
"description": "A block of text as input or output",
"logLevel": "info"
},
"configuration": {
"schema": {
"properties": {
"context": {
"type": "array",
"title": "Context",
"items": {
"type": "object",
"behavior": ["llm-content"]
},
"default": "null"
"text": {
"role": "user",
"parts": [
{
"text": "HELLO"
}
},
"type": "object",
"required": []
]
}
},
}
},
{
"id": "a2-f08c915e",
"type": "file://bgl/a2.bgl.json#21ee02e7-83fa-49d0-964c-0cab10eafc2c",
"metadata": {
"visual": {
"x": 260,
"x": -200,
"y": -260,
"collapsed": "expanded",
"outputHeight": 44
},
"title": "From Here",
"description": "A block of text as input or output",
"logLevel": "info"
},
"configuration": {
"text": {
"role": "user",
"parts": [
{
"text": "FOO"
}
]
}
}
}
],
"edges": [
{
"from": "input",
"out": "context",
"from": "a2-09645fb2",
"to": "output",
"out": "context",
"in": "context"
}
],
Expand All @@ -75,16 +98,49 @@
},
"assets": {
"content-1": {
"data": [{ "parts": [{ "text": "HELLO WORLD" }], "role": "user" }],
"data": [
{
"parts": [
{
"text": "HELLO WORLD"
}
],
"role": "user"
}
],
"metadata": {
"title": "Hello World"
}
},
"content-2": {
"data": [{ "parts": [{ "text": "MAXIMUM TURBO" }], "role": "user" }],
"data": [
{
"parts": [
{
"text": "MAXIMUM TURBO"
}
],
"role": "user"
}
],
"metadata": {
"title": "Maximum Turbo"
}
},
"foo": {
"data": [
{
"parts": [
{
"text": "Asset named foo"
}
],
"role": "user"
}
],
"metadata": {
"title": "Foo"
}
}
}
}
}
2 changes: 2 additions & 0 deletions packages/breadboard/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ export {
assetsFromGraphDescriptor,
} from "./data/index.js";

export { ok, err } from "./data/file-system/utils.js";

/**
* Managed Run State API
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export class AssetOrganizer extends SignalWatcher(LitElement) {

render() {
const outputs = this.asset ? { data: this.asset.data } : null;
const assets = this.state?.assets;
const assets = this.state?.graphAssets;

return html`<div id="container">
<header>
Expand Down
Loading

0 comments on commit 8e2fc1f

Please sign in to comment.