diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..19f7f68 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node +{ + "name": "Node.js & TypeScript", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye" + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "yarn install", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.yarn/cache/@types-node-npm-20.10.0-22577c30ff-c7d5ddbdbf.zip b/.yarn/cache/@types-node-npm-20.10.0-22577c30ff-c7d5ddbdbf.zip new file mode 100644 index 0000000..f554ca5 Binary files /dev/null and b/.yarn/cache/@types-node-npm-20.10.0-22577c30ff-c7d5ddbdbf.zip differ diff --git a/.yarn/cache/@types-node-npm-20.10.3-d385a9ec0a-7cb506abb0.zip b/.yarn/cache/@types-node-npm-20.10.3-d385a9ec0a-7cb506abb0.zip new file mode 100644 index 0000000..f427939 Binary files /dev/null and b/.yarn/cache/@types-node-npm-20.10.3-d385a9ec0a-7cb506abb0.zip differ diff --git a/.yarn/cache/@types-react-npm-18.2.42-88ab7806ab-b6ee1873ba.zip b/.yarn/cache/@types-react-npm-18.2.42-88ab7806ab-b6ee1873ba.zip new file mode 100644 index 0000000..753004f Binary files /dev/null and b/.yarn/cache/@types-react-npm-18.2.42-88ab7806ab-b6ee1873ba.zip differ diff --git a/.yarn/cache/typescript-npm-5.3.2-a11892b3bc-415e5fb661.zip b/.yarn/cache/typescript-npm-5.3.2-a11892b3bc-415e5fb661.zip new file mode 100644 index 0000000..94c0370 Binary files /dev/null and b/.yarn/cache/typescript-npm-5.3.2-a11892b3bc-415e5fb661.zip differ diff --git a/.yarn/cache/typescript-patch-71fdfda6a2-1b45cdfb57.zip b/.yarn/cache/typescript-patch-71fdfda6a2-1b45cdfb57.zip new file mode 100644 index 0000000..f791e22 Binary files /dev/null and b/.yarn/cache/typescript-patch-71fdfda6a2-1b45cdfb57.zip differ diff --git a/package.json b/package.json index 6f6f4cc..7568f5d 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "dependencies": { - "@exadev/breadboard-kits": "^0.8.2", - "@google-labs/breadboard": "^0.5.1" + "@exadev/breadboard-kits": "^0.9.0", + "@google-labs/breadboard": "^0.6.0" }, "devDependencies": { - "@types/node": "^20.9.3", + "@types/node": "^20.10.4", "tsx": "^4.6.2", - "typescript": "^5.3.2" + "typescript": "^5.3.3" }, "engines": { "node": ">=19" diff --git a/samples/CourseCrafter/.eslintrc.cjs b/samples/CourseCrafter/.eslintrc.cjs new file mode 100644 index 0000000..30af7ce --- /dev/null +++ b/samples/CourseCrafter/.eslintrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + ], + ignorePatterns: ["dist", ".eslintrc.cjs"], + parser: "@typescript-eslint/parser", + plugins: ["react-refresh"], + rules: { + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, +}; diff --git a/samples/CourseCrafter/.gitignore b/samples/CourseCrafter/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/samples/CourseCrafter/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/samples/CourseCrafter/.tool-versions b/samples/CourseCrafter/.tool-versions new file mode 100644 index 0000000..b5ed8dc --- /dev/null +++ b/samples/CourseCrafter/.tool-versions @@ -0,0 +1 @@ +nodejs 21.4.0 diff --git a/samples/CourseCrafter/README.md b/samples/CourseCrafter/README.md new file mode 100644 index 0000000..4ec9fc2 --- /dev/null +++ b/samples/CourseCrafter/README.md @@ -0,0 +1,228 @@ +# title + +```mermaid +%%{init: 'themeVariables': { 'fontFamily': 'Fira Code, monospace' }}%% +graph TD; +promptDetails[/"input
id='promptDetails'"/]:::input -- "template->template" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +blogDetails[/"input
id='blogDetails'"/]:::input -- "url->url" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "model->model" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "task->task" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->input" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "model->model" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "task->task" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->blogContent" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +summaryLanguageModel["pipeline
id='summaryLanguageModel'"] -- "output->summary" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->blogContent" --> outputCollector{{"output
id='outputCollector'"}}:::output +summaryLanguageModel["pipeline
id='summaryLanguageModel'"] -- "output->blogSummary" --> outputCollector{{"output
id='outputCollector'"}}:::output +secrets1("secrets
id='secrets-1'"):::secrets -- "CLAUDE_KEY->apiKey" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudePromptConstructor["template
id='claudePromptConstructor'"] -- "string->userQuestion" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudePromptConstructor["template
id='claudePromptConstructor'"] -- "string->userQuestion" --> outputCollector{{"output
id='outputCollector'"}}:::output +claudeAPI["generateCompletion
id='claudeAPI'"] -- "completion->claudeResponse" --> outputCollector{{"output
id='outputCollector'"}}:::output +classDef default stroke:#ffab40,fill:#fff2ccff,color:#000 +classDef input stroke:#3c78d8,fill:#c9daf8ff,color:#000 +classDef output stroke:#38761d,fill:#b6d7a8ff,color:#000 +classDef passthrough stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef slot stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef config stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef secrets stroke:#db4437,fill:#f4cccc,color:#000 +classDef slotted stroke:#a64d79 +``` + +```json +{ + "title": "CourseCrafter", + "edges": [ + { + "from": "promptDetails", + "to": "claudePromptConstructor", + "out": "template", + "in": "template" + }, + { + "from": "blogDetails", + "to": "getBlogContents", + "out": "url", + "in": "url" + }, + { + "from": "taskDetails", + "to": "getBlogContents", + "out": "model", + "in": "model" + }, + { + "from": "taskDetails", + "to": "getBlogContents", + "out": "task", + "in": "task" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "blogContent", + "in": "input" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "model", + "in": "model" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "task", + "in": "task" + }, + { + "from": "getBlogContents", + "to": "claudePromptConstructor", + "out": "blogContent", + "in": "blogContent" + }, + { + "from": "summaryLanguageModel", + "to": "claudePromptConstructor", + "out": "output", + "in": "summary" + }, + { + "from": "getBlogContents", + "to": "outputCollector", + "out": "blogContent", + "in": "blogContent" + }, + { + "from": "summaryLanguageModel", + "to": "outputCollector", + "out": "output", + "in": "blogSummary" + }, + { + "from": "secrets-1", + "to": "claudeAPI", + "out": "CLAUDE_KEY", + "in": "apiKey" + }, + { + "from": "claudePromptConstructor", + "to": "claudeAPI", + "out": "string", + "in": "userQuestion" + }, + { + "from": "claudePromptConstructor", + "to": "outputCollector", + "out": "string", + "in": "userQuestion" + }, + { + "from": "claudeAPI", + "to": "outputCollector", + "out": "completion", + "in": "claudeResponse" + } + ], + "nodes": [ + { + "id": "blogDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "promptDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "taskDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "model and task" + } + } + } + } + }, + { + "id": "getBlogContents", + "type": "getBlogContentForTask" + }, + { + "id": "summaryLanguageModel", + "type": "pipeline" + }, + { + "id": "claudePromptConstructor", + "type": "template", + "configuration": { + "template": "Based on this summary and original text, give me code sample on how to achieve the discussed topic. Output result in markdown format, do not include the summary text in the output: /n{{summary}}/nthe original text is the following: /n{{blogContent}}" + } + }, + { + "id": "outputCollector", + "type": "output" + }, + { + "id": "secrets-1", + "type": "secrets", + "configuration": { + "0": "CLAUDE_API_KEY" + } + }, + { + "id": "claudeAPI", + "type": "generateCompletion", + "configuration": { + "model": "claude-2", + "url": "https://api.anthropic.com/v1/complete" + } + } + ], + "kits": [ + { + "url": "npm@exadev/breadboard-kits/CourseCrafter" + }, + { + "url": "npm:@xenova/transformers" + }, + { + "url": "npm:@paulkinlan/claude-breadboard-kit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/StringKit" + }, + { + "url": "npm:@google-labs/llm-starter" + } + ] +} +``` \ No newline at end of file diff --git a/samples/CourseCrafter/index.html b/samples/CourseCrafter/index.html new file mode 100644 index 0000000..e8d73f7 --- /dev/null +++ b/samples/CourseCrafter/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/samples/CourseCrafter/output/CourseCrafter.md b/samples/CourseCrafter/output/CourseCrafter.md new file mode 100644 index 0000000..5ee611f --- /dev/null +++ b/samples/CourseCrafter/output/CourseCrafter.md @@ -0,0 +1,207 @@ +# CourseCrafter + +## Mermaid +```mermaid +%%{init: 'themeVariables': { 'fontFamily': 'Fira Code, monospace' }}%% +graph TD; +promptDetails[/"input
id='promptDetails'"/]:::input -- "template->template" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +blogDetails[/"input
id='blogDetails'"/]:::input -- "url->url" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "model->model" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "task->task" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->input" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "model->model" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "task->task" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->blogContent" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +summaryLanguageModel["pipeline
id='summaryLanguageModel'"] -- "output->summary" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +readEnvVar1["readEnvVar
id='readEnvVar-1'"] -- "CLAUDE_API_KEY->CLAUDE_API_KEY" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudePromptConstructor["template
id='claudePromptConstructor'"] -- "string->text" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudeAPI["generateCompletion
id='claudeAPI'"] -- "completion->completion" --> output2{{"output
id='output-2'"}}:::output +classDef default stroke:#ffab40,fill:#fff2ccff,color:#000 +classDef input stroke:#3c78d8,fill:#c9daf8ff,color:#000 +classDef output stroke:#38761d,fill:#b6d7a8ff,color:#000 +classDef passthrough stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef slot stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef config stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef secrets stroke:#db4437,fill:#f4cccc,color:#000 +classDef slotted stroke:#a64d79 +``` +``` + +## JSON +```json +{ + "title": "CourseCrafter", + "edges": [ + { + "from": "promptDetails", + "to": "claudePromptConstructor", + "out": "template", + "in": "template" + }, + { + "from": "blogDetails", + "to": "getBlogContents", + "out": "url", + "in": "url" + }, + { + "from": "taskDetails", + "to": "getBlogContents", + "out": "model", + "in": "model" + }, + { + "from": "taskDetails", + "to": "getBlogContents", + "out": "task", + "in": "task" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "blogContent", + "in": "input" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "model", + "in": "model" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "task", + "in": "task" + }, + { + "from": "getBlogContents", + "to": "claudePromptConstructor", + "out": "blogContent", + "in": "blogContent" + }, + { + "from": "summaryLanguageModel", + "to": "claudePromptConstructor", + "out": "output", + "in": "summary" + }, + { + "from": "readEnvVar-1", + "to": "claudeAPI", + "out": "CLAUDE_API_KEY", + "in": "CLAUDE_API_KEY" + }, + { + "from": "claudePromptConstructor", + "to": "claudeAPI", + "out": "string", + "in": "text" + }, + { + "from": "claudeAPI", + "to": "output-2", + "out": "completion", + "in": "completion" + } + ], + "nodes": [ + { + "id": "blogDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "promptDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "taskDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "model and task" + } + } + } + } + }, + { + "id": "getBlogContents", + "type": "getBlogContentForTask" + }, + { + "id": "summaryLanguageModel", + "type": "pipeline" + }, + { + "id": "claudePromptConstructor", + "type": "template" + }, + { + "id": "claudeAPI", + "type": "generateCompletion", + "configuration": { + "model": "claude-2", + "url": "https://api.anthropic.com/v1/complete" + } + }, + { + "id": "readEnvVar-1", + "type": "readEnvVar", + "configuration": { + "key": "CLAUDE_API_KEY" + } + }, + { + "id": "output-2", + "type": "output" + } + ], + "kits": [ + { + "url": "npm@exadev/breadboard-kits/CourseCrafter" + }, + { + "url": "npm:@xenova/transformers" + }, + { + "url": "npm:@paulkinlan/claude-breadboard-kit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/StringKit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/ConfigKit" + } + ] +} +``` \ No newline at end of file diff --git a/samples/CourseCrafter/package.json b/samples/CourseCrafter/package.json new file mode 100644 index 0000000..7046c76 --- /dev/null +++ b/samples/CourseCrafter/package.json @@ -0,0 +1,40 @@ +{ + "name": "coursecrafter", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "run-board": "npx -y tsx src/breadboard/runBoard.ts", + "watch-board": "npx -y tsx watch src/breadboard/runBoard.ts", + "run-board-multiple": "npx -y tsx src/breadboard-multiple-url/runBoard.ts", + "watch-board-multiple": "npx -y tsx watch src/breadboard-multiple-url/runBoard.ts" + }, + "dependencies": { + "@exadev/breadboard-kits": "^0.9.0", + "@google-labs/breadboard": "^0.6.0", + "@google-labs/core-kit": "0.1.0", + "@google-labs/llm-starter": "0.3.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.45", + "@types/react-dom": "^18.2.17", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-react-swc": "^3.5.0", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "typescript": "^5.3.3", + "vite": "^5.0.8" + }, + "engines": { + "node": ">=19" + }, + "engineStrict": true +} diff --git a/samples/CourseCrafter/public/vite.svg b/samples/CourseCrafter/public/vite.svg new file mode 100644 index 0000000..3a5f68c --- /dev/null +++ b/samples/CourseCrafter/public/vite.svg @@ -0,0 +1,20 @@ + diff --git a/samples/CourseCrafter/src/App.css b/samples/CourseCrafter/src/App.css new file mode 100644 index 0000000..df674c0 --- /dev/null +++ b/samples/CourseCrafter/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/samples/CourseCrafter/src/App.tsx b/samples/CourseCrafter/src/App.tsx new file mode 100644 index 0000000..de38df1 --- /dev/null +++ b/samples/CourseCrafter/src/App.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react'; +import reactLogo from './assets/react.svg'; +import viteLogo from '/vite.svg'; +import './App.css'; + +function App() { + const [count, setCount] = useState(0); + + return ( + <> +
+ + Vite logo + + + React logo + +
+

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ); +} + +export default App; diff --git a/samples/CourseCrafter/src/assets/react.svg b/samples/CourseCrafter/src/assets/react.svg new file mode 100644 index 0000000..14285ab --- /dev/null +++ b/samples/CourseCrafter/src/assets/react.svg @@ -0,0 +1,6 @@ + diff --git a/samples/CourseCrafter/src/breadboard-multiple-url/README.md b/samples/CourseCrafter/src/breadboard-multiple-url/README.md new file mode 100644 index 0000000..c60634e --- /dev/null +++ b/samples/CourseCrafter/src/breadboard-multiple-url/README.md @@ -0,0 +1,190 @@ +# CourseCrafter + +```mermaid +%%{init: 'themeVariables': { 'fontFamily': 'Fira Code, monospace' }}%% +graph TD; +promptDetails[/"input
id='promptDetails'"/]:::input -- "template->template" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +blogDetails[/"input
id='blogDetails'"/]:::input -- "list->list" --> getBlogsContent["getBlogsContent
id='getBlogsContent'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "model->model" --> summaryLanguageModel["pipelineBulk
id='summaryLanguageModel'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "task->task" --> summaryLanguageModel["pipelineBulk
id='summaryLanguageModel'"] +getBlogsContent["getBlogsContent
id='getBlogsContent'"] -- "blogOutput->inputs" --> summaryLanguageModel["pipelineBulk
id='summaryLanguageModel'"] +getBlogsContent["getBlogsContent
id='getBlogsContent'"] -- "blogOutput->blogContents" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +summaryLanguageModel["pipelineBulk
id='summaryLanguageModel'"] -- "summaries->summaries" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +readEnvVar1["readEnvVar
id='readEnvVar-1'"] -- "CLAUDE_API_KEY->CLAUDE_API_KEY" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudePromptConstructor["template
id='claudePromptConstructor'"] -- "string->text" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudeAPI["generateCompletion
id='claudeAPI'"] -- "completion->completion" --> output2{{"output
id='output-2'"}}:::output +classDef default stroke:#ffab40,fill:#fff2ccff,color:#000 +classDef input stroke:#3c78d8,fill:#c9daf8ff,color:#000 +classDef output stroke:#38761d,fill:#b6d7a8ff,color:#000 +classDef passthrough stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef slot stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef config stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef secrets stroke:#db4437,fill:#f4cccc,color:#000 +classDef slotted stroke:#a64d79 +``` + +```json +{ + "title": "CourseCrafter", + "edges": [ + { + "from": "promptDetails", + "to": "claudePromptConstructor", + "out": "template", + "in": "template" + }, + { + "from": "blogDetails", + "to": "getBlogsContent", + "out": "list", + "in": "list" + }, + { + "from": "taskDetails", + "to": "summaryLanguageModel", + "out": "model", + "in": "model" + }, + { + "from": "taskDetails", + "to": "summaryLanguageModel", + "out": "task", + "in": "task" + }, + { + "from": "getBlogsContent", + "to": "summaryLanguageModel", + "out": "blogOutput", + "in": "inputs" + }, + { + "from": "getBlogsContent", + "to": "claudePromptConstructor", + "out": "blogOutput", + "in": "blogContents" + }, + { + "from": "summaryLanguageModel", + "to": "claudePromptConstructor", + "out": "summaries", + "in": "summaries" + }, + { + "from": "readEnvVar-1", + "to": "claudeAPI", + "out": "CLAUDE_API_KEY", + "in": "CLAUDE_API_KEY" + }, + { + "from": "claudePromptConstructor", + "to": "claudeAPI", + "out": "string", + "in": "text" + }, + { + "from": "claudeAPI", + "to": "output-2", + "out": "completion", + "in": "completion" + } + ], + "nodes": [ + { + "id": "blogDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "list", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "promptDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "taskDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "model and task" + } + } + } + } + }, + { + "id": "getBlogsContent", + "type": "getBlogsContent" + }, + { + "id": "summaryLanguageModel", + "type": "pipelineBulk" + }, + { + "id": "claudePromptConstructor", + "type": "template" + }, + { + "id": "claudeAPI", + "type": "generateCompletion", + "configuration": { + "model": "claude-2", + "url": "https://api.anthropic.com/v1/complete" + } + }, + { + "id": "readEnvVar-1", + "type": "readEnvVar", + "configuration": { + "key": "CLAUDE_API_KEY" + } + }, + { + "id": "output-2", + "type": "output" + } + ], + "kits": [ + { + "url": "npm@exadev/breadboard-kits/CourseCrafter" + }, + { + "url": "npm:@xenova/transformers" + }, + { + "url": "npm:@paulkinlan/claude-breadboard-kit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/StringKit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/ConfigKit" + } + ] +} +``` \ No newline at end of file diff --git a/samples/CourseCrafter/src/breadboard-multiple-url/board.ts b/samples/CourseCrafter/src/breadboard-multiple-url/board.ts new file mode 100644 index 0000000..4211e0f --- /dev/null +++ b/samples/CourseCrafter/src/breadboard-multiple-url/board.ts @@ -0,0 +1,97 @@ +import { CourseCrafterKit, StringKit, XenovaKit, ConfigKit} from "@exadev/breadboard-kits"; +import { Board } from "@google-labs/breadboard"; +import { ClaudeKit } from "@paulkinlan/claude-breadboard-kit"; + + +export function makeBoard(): Board{ + const board = new Board({ + title: "CourseCrafter", + }); + + const courseCraftKit = board.addKit(CourseCrafterKit); + const xenovaKit = board.addKit(XenovaKit); + const claudeKit = board.addKit(ClaudeKit); + const stringKit = board.addKit(StringKit); + const config = board.addKit(ConfigKit); + + const input = board.input({ + $id: "blogDetails", + schema: { + type: "object", + properties: { + text: { + type: "list", + title: "Text", + description: "urls", + }, + }, + }, + }); + + const templateInput = board.input({ + $id: "promptDetails", + schema: { + type: "object", + properties: { + text: { + type: "string", + title: "Text", + description: "urls", + }, + }, + }, + }); + + + const taskDetails = board.input({ + $id: "taskDetails", + schema: { + type: "object", + properties: { + text: { + type: "string", + title: "Text", + description: "model and task", + }, + }, + }, + }); + + const getContent = courseCraftKit.getBlogsContent({ $id: "getBlogsContent" }); + const pipeline = xenovaKit.pipelineBulk({ $id: "summaryLanguageModel" }); + const instructionTemplate = stringKit.template({$id: "claudePromptConstructor"}); + + templateInput.wire("->template", instructionTemplate); + input.wire("->list", getContent); + taskDetails.wire("->model", pipeline); + taskDetails.wire("->task", pipeline); + + // wire blog content into xenova pipeline + getContent.wire("blogOutput->inputs", pipeline); + + getContent.wire("blogOutput->blogContents", instructionTemplate); + pipeline.wire("summaries->summaries", instructionTemplate); + + const serverUrl = "https://api.anthropic.com/v1/complete"; + + const claudeParams = { + model: "claude-2", + url: `${serverUrl}`, + }; + + const claudeCompletion = claudeKit.generateCompletion({ + $id: "claudeAPI", + ...claudeParams, + }); + + const claudeApiKey = config.readEnvVar({ + key: "CLAUDE_API_KEY", + }); + + claudeApiKey.wire("CLAUDE_API_KEY", claudeCompletion); + instructionTemplate.wire("string->text", claudeCompletion); + + claudeCompletion.wire("completion->", board.output()); + + return board +} \ No newline at end of file diff --git a/samples/CourseCrafter/src/breadboard-multiple-url/outputs/blog_summary.md b/samples/CourseCrafter/src/breadboard-multiple-url/outputs/blog_summary.md new file mode 100644 index 0000000..d17cc9e --- /dev/null +++ b/samples/CourseCrafter/src/breadboard-multiple-url/outputs/blog_summary.md @@ -0,0 +1,69 @@ + Here are the outlined topics and code samples for each blog post: + +## Blog 1: Scheduler API origin trial + +- Yielding control back to main thread with `scheduler.yield()` to improve input responsiveness + +```js +// Yield with scheduler.yield +async function yieldy() { + await scheduler.yield(); +} +``` + +- `scheduler.yield()` sends remaining work to front of task queue + +```js +async function doWork() { + await yieldToMain(); + + // Remaining work +} + +function yieldToMain() { + if ('scheduler' in window && 'yield' in scheduler) { + return scheduler.yield(); + } +} +``` + +## Blog 2: Automatic picture-in-picture + +- Register media session action handler for `enterpictureinpicture` + +```js +navigator.mediaSession.setActionHandler("enterpictureinpicture", () => { + video.requestPictureInPicture(); +}); +``` + +- Use Document Picture-in-Picture API to populate custom HTML + +```js +navigator.mediaSession.setActionHandler("enterpictureinpicture", async () => { + const pipWindow = await documentPictureInPicture.requestWindow(); + // Populate HTML +}); +``` + +## Blog 3: 16-bit floats in WebGPU/WGSL + +- Enable `f16` WGSL extension + +```wgsl +enable f16; + +const c: vec3 = ...; +``` + +- Conditionally use `f16` or `f32` based on GPU feature support + +```js +const hasShaderF16 = adapter.features.has("shader-f16"); + +const header = hasShaderF16 + ? `enable f16; alias min16float = f16;` + : `alias min16float = f32;`; + +const c = vec3(...); +``` \ No newline at end of file diff --git a/samples/CourseCrafter/src/breadboard-multiple-url/runBoard.ts b/samples/CourseCrafter/src/breadboard-multiple-url/runBoard.ts new file mode 100644 index 0000000..035014e --- /dev/null +++ b/samples/CourseCrafter/src/breadboard-multiple-url/runBoard.ts @@ -0,0 +1,54 @@ +#!/usr/bin/env npx -y tsx +import { makeBoard } from "./board"; +import * as url from 'url'; +import path from "path"; +import fs from "fs"; + +import generateAndWriteCombinedMarkdown from "@exadev/breadboard-kits/util/files/generateAndWriteCombinedMarkdown"; + +const board = makeBoard() + +generateAndWriteCombinedMarkdown({ + board, + filename: "README", + dir: url.fileURLToPath(new URL('.', import.meta.url)) +}); + +// if we get weird errors, check the blog still exists +const blogURL = "https://developer.chrome.com/blog/introducing-scheduler-yield-origin-trial/" +const blogURL2 = "https://developer.chrome.com/blog/automatic-picture-in-picture/" +const blogURL3 = "https://developer.chrome.com/blog/new-in-webgpu-120/" +const urls = [blogURL, blogURL2, blogURL3]; + +for await (const runResult of board.run({ +})) { + if (runResult.type === "input") { + if(runResult.node.id == "blogDetails"){ + runResult.inputs = { + list:urls + } + } + else if (runResult.node.id == "taskDetails") { + runResult.inputs = { + model: "Xenova/distilbart-cnn-6-6", + task: "summarization" + } + } + else if (runResult.node.id == "promptDetails"){ + const prompt = ["Based these summaries of blog posts:", "{{summaries}}", "and the original text: ", "{{blogContents}}", "can you outline topics discussed in each blog? For each blog give me code sample on how to achieve the discussed topic. Output result in markdown format, do not include the summary text in the output. Separate discussed topics in bullet points."].join("/n") + + runResult.inputs = { + template: prompt, + } + } + } + else if (runResult.type === "output") { + const outputs = runResult.outputs + + const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); + const outputDir = path.join(__dirname, "outputs") + fs.mkdirSync(outputDir, { recursive: true }); + + fs.writeFileSync(path.join(outputDir, "blog_summary.md"), outputs["completion"] as string); + } +} diff --git a/samples/CourseCrafter/src/breadboard/README.md b/samples/CourseCrafter/src/breadboard/README.md new file mode 100644 index 0000000..88c3077 --- /dev/null +++ b/samples/CourseCrafter/src/breadboard/README.md @@ -0,0 +1,204 @@ +# CourseCrafter + +```mermaid +%%{init: 'themeVariables': { 'fontFamily': 'Fira Code, monospace' }}%% +graph TD; +promptDetails[/"input
id='promptDetails'"/]:::input -- "template->template" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +blogDetails[/"input
id='blogDetails'"/]:::input -- "url->url" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "model->model" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +taskDetails[/"input
id='taskDetails'"/]:::input -- "task->task" --> getBlogContents["getBlogContentForTask
id='getBlogContents'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->input" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "model->model" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "task->task" --> summaryLanguageModel["pipeline
id='summaryLanguageModel'"] +getBlogContents["getBlogContentForTask
id='getBlogContents'"] -- "blogContent->blogContent" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +summaryLanguageModel["pipeline
id='summaryLanguageModel'"] -- "output->summary" --> claudePromptConstructor["template
id='claudePromptConstructor'"] +readEnvVar1["readEnvVar
id='readEnvVar-1'"] -- "CLAUDE_API_KEY->CLAUDE_API_KEY" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudePromptConstructor["template
id='claudePromptConstructor'"] -- "string->text" --> claudeAPI["generateCompletion
id='claudeAPI'"] +claudeAPI["generateCompletion
id='claudeAPI'"] -- "completion->completion" --> output2{{"output
id='output-2'"}}:::output +classDef default stroke:#ffab40,fill:#fff2ccff,color:#000 +classDef input stroke:#3c78d8,fill:#c9daf8ff,color:#000 +classDef output stroke:#38761d,fill:#b6d7a8ff,color:#000 +classDef passthrough stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef slot stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef config stroke:#a64d79,fill:#ead1dcff,color:#000 +classDef secrets stroke:#db4437,fill:#f4cccc,color:#000 +classDef slotted stroke:#a64d79 +``` + +```json +{ + "title": "CourseCrafter", + "edges": [ + { + "from": "promptDetails", + "to": "claudePromptConstructor", + "out": "template", + "in": "template" + }, + { + "from": "blogDetails", + "to": "getBlogContents", + "out": "url", + "in": "url" + }, + { + "from": "taskDetails", + "to": "getBlogContents", + "out": "model", + "in": "model" + }, + { + "from": "taskDetails", + "to": "getBlogContents", + "out": "task", + "in": "task" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "blogContent", + "in": "input" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "model", + "in": "model" + }, + { + "from": "getBlogContents", + "to": "summaryLanguageModel", + "out": "task", + "in": "task" + }, + { + "from": "getBlogContents", + "to": "claudePromptConstructor", + "out": "blogContent", + "in": "blogContent" + }, + { + "from": "summaryLanguageModel", + "to": "claudePromptConstructor", + "out": "output", + "in": "summary" + }, + { + "from": "readEnvVar-1", + "to": "claudeAPI", + "out": "CLAUDE_API_KEY", + "in": "CLAUDE_API_KEY" + }, + { + "from": "claudePromptConstructor", + "to": "claudeAPI", + "out": "string", + "in": "text" + }, + { + "from": "claudeAPI", + "to": "output-2", + "out": "completion", + "in": "completion" + } + ], + "nodes": [ + { + "id": "blogDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "promptDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "urls" + } + } + } + } + }, + { + "id": "taskDetails", + "type": "input", + "configuration": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "title": "Text", + "description": "model and task" + } + } + } + } + }, + { + "id": "getBlogContents", + "type": "getBlogContentForTask" + }, + { + "id": "summaryLanguageModel", + "type": "pipeline" + }, + { + "id": "claudePromptConstructor", + "type": "template" + }, + { + "id": "claudeAPI", + "type": "generateCompletion", + "configuration": { + "model": "claude-2", + "url": "https://api.anthropic.com/v1/complete" + } + }, + { + "id": "readEnvVar-1", + "type": "readEnvVar", + "configuration": { + "key": "CLAUDE_API_KEY" + } + }, + { + "id": "output-2", + "type": "output" + } + ], + "kits": [ + { + "url": "npm@exadev/breadboard-kits/CourseCrafter" + }, + { + "url": "npm:@xenova/transformers" + }, + { + "url": "npm:@paulkinlan/claude-breadboard-kit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/StringKit" + }, + { + "url": "npm:@exadev/breadboard-kits/kits/ConfigKit" + } + ] +} +``` \ No newline at end of file diff --git a/samples/CourseCrafter/src/breadboard/board.ts b/samples/CourseCrafter/src/breadboard/board.ts new file mode 100644 index 0000000..de51517 --- /dev/null +++ b/samples/CourseCrafter/src/breadboard/board.ts @@ -0,0 +1,105 @@ +import { + CourseCrafterKit, + StringKit, + XenovaKit, + ConfigKit, +} from "@exadev/breadboard-kits"; +import { Board } from "@google-labs/breadboard"; +import { ClaudeKit } from "@paulkinlan/claude-breadboard-kit"; + +const board = new Board({ + title: "CourseCrafter", +}); + +const courseCraftKit = board.addKit(CourseCrafterKit); +const xenovaKit = board.addKit(XenovaKit); +const claudeKit = board.addKit(ClaudeKit); +const stringKit = board.addKit(StringKit); +const config = board.addKit(ConfigKit); + +const input = board.input({ + $id: "blogDetails", + schema: { + type: "object", + properties: { + text: { + type: "string", + title: "Text", + description: "urls", + }, + }, + }, +}); + +const templateInput = board.input({ + $id: "promptDetails", + schema: { + type: "object", + properties: { + text: { + type: "string", + title: "Text", + description: "urls", + }, + }, + }, +}); + +const taskDetails = board.input({ + $id: "taskDetails", + schema: { + type: "object", + properties: { + text: { + type: "string", + title: "Text", + description: "model and task", + }, + }, + }, +}); + +const getBlogContentForTask = courseCraftKit.getBlogContentForTask({ + $id: "getBlogContents", +}); +const pipeline = xenovaKit.pipeline({ $id: "summaryLanguageModel" }); +const instructionTemplate = stringKit.template({ + $id: "claudePromptConstructor", +}); + +templateInput.wire("->template", instructionTemplate); +input.wire("->url", getBlogContentForTask); +taskDetails.wire("->model", getBlogContentForTask); +taskDetails.wire("->task", getBlogContentForTask); + +// wire blog content into xenova pipeline +getBlogContentForTask.wire("blogContent->input", pipeline); +getBlogContentForTask.wire("model->model", pipeline); +getBlogContentForTask.wire("task->task", pipeline); + +getBlogContentForTask.wire("blogContent->blogContent", instructionTemplate); +pipeline.wire("output->summary", instructionTemplate); + +const serverUrl = "https://api.anthropic.com/v1/complete"; + +const claudeParams = { + model: "claude-2", + url: `${serverUrl}`, +}; + +const claudeCompletion = claudeKit.generateCompletion({ + $id: "claudeAPI", + ...claudeParams, +}); + +const claudeApiKey = config.readEnvVar({ + key: "CLAUDE_API_KEY", +}); + +claudeApiKey.wire("CLAUDE_API_KEY", claudeCompletion); +instructionTemplate.wire("string->text", claudeCompletion); + +claudeCompletion.wire("completion->", board.output()); + +export default board; +export { board }; diff --git a/samples/CourseCrafter/src/breadboard/outputs/blog_summary.md b/samples/CourseCrafter/src/breadboard/outputs/blog_summary.md new file mode 100644 index 0000000..37664ac --- /dev/null +++ b/samples/CourseCrafter/src/breadboard/outputs/blog_summary.md @@ -0,0 +1,43 @@ + Here is sample code to achieve explicit yielding in JavaScript using the scheduler.yield() method: + +```js +// Check if scheduler.yield is supported +if ('scheduler' in window && 'yield' in scheduler) { + + // Define an async function + async function doWork() { + + // Do some initial work + console.log('Step 1'); + + // Yield back to main thread + await scheduler.yield(); + + // Do more work after yielding + console.log('Step 2'); + } + + // Call the function + doWork(); + +} else { + + // scheduler.yield is not supported, fall back to setTimeout + function doWork() { + + console.log('Step 1'); + + setTimeout(() => { + console.log('Step 2'); + }, 0); + + } + + doWork(); + +} +``` + +This checks if the scheduler.yield() method is available, and if so uses it to explicitly yield control back to the main thread. If not, it falls back to using setTimeout as a workaround. + +The key benefit of scheduler.yield() over setTimeout is that remaining work is scheduled at the front of the task queue instead of the back. This prevents other logic like intervals or timeouts from delaying resumption of work. \ No newline at end of file diff --git a/samples/CourseCrafter/src/breadboard/runBoard.ts b/samples/CourseCrafter/src/breadboard/runBoard.ts new file mode 100755 index 0000000..dbf688b --- /dev/null +++ b/samples/CourseCrafter/src/breadboard/runBoard.ts @@ -0,0 +1,54 @@ +#!/usr/bin/env npx -y tsx +import * as url from "url"; +import path from "path"; +import fs from "fs"; + +import generateAndWriteCombinedMarkdown from "@exadev/breadboard-kits/util/files/generateAndWriteCombinedMarkdown"; +import board from "./board"; + +generateAndWriteCombinedMarkdown({ + board, + filename: "README", + dir: url.fileURLToPath(new URL(".", import.meta.url)), +}); + +const blogUrl = + "https://developer.chrome.com/blog/introducing-scheduler-yield-origin-trial/"; + +for await (const runResult of board.run({})) { + if (runResult.type === "input") { + if (runResult.node.id == "blogDetails") { + runResult.inputs = { + url: blogUrl, + }; + } else if (runResult.node.id == "taskDetails") { + runResult.inputs = { + model: "Xenova/distilbart-cnn-6-6", + task: "summarization", + }; + } else if (runResult.node.id == "promptDetails") { + const instruction = + "Based on this summary and original text, give me code sample on how to achieve the discussed topic. Output result in markdown format, do not include the summary text in the output: "; + + runResult.inputs = { + template: [ + instruction, + "{{summary}}", + "the original text is the following: ", + "{{blogContent}}", + ].join("/n"), + }; + } + } else if (runResult.type === "output") { + const outputs = runResult.outputs; + + const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); + const outputDir = path.join(__dirname, "outputs"); + fs.mkdirSync(outputDir, { recursive: true }); + + fs.writeFileSync( + path.join(outputDir, "blog_summary.md"), + outputs["completion"] as string + ); + } +} diff --git a/samples/CourseCrafter/src/index.css b/samples/CourseCrafter/src/index.css new file mode 100644 index 0000000..9cfcb00 --- /dev/null +++ b/samples/CourseCrafter/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/samples/CourseCrafter/src/main.tsx b/samples/CourseCrafter/src/main.tsx new file mode 100644 index 0000000..c84d2ee --- /dev/null +++ b/samples/CourseCrafter/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App.tsx'; +import './index.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/samples/CourseCrafter/src/vite-env.d.ts b/samples/CourseCrafter/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/samples/CourseCrafter/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/samples/CourseCrafter/tsconfig.json b/samples/CourseCrafter/tsconfig.json new file mode 100644 index 0000000..243d645 --- /dev/null +++ b/samples/CourseCrafter/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "src" + ], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} diff --git a/samples/CourseCrafter/tsconfig.node.json b/samples/CourseCrafter/tsconfig.node.json new file mode 100644 index 0000000..d37a14f --- /dev/null +++ b/samples/CourseCrafter/tsconfig.node.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": [ + "vite.config.ts" + ] +} diff --git a/samples/CourseCrafter/vite.config.ts b/samples/CourseCrafter/vite.config.ts new file mode 100644 index 0000000..41114b5 --- /dev/null +++ b/samples/CourseCrafter/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/samples/DevPulse/DevPulse React/.vscode/launch.json b/samples/DevPulse/DevPulse React/.vscode/launch.json deleted file mode 100644 index 1d63ad4..0000000 --- a/samples/DevPulse/DevPulse React/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "chrome", - "request": "launch", - "name": "Launch Chrome against localhost", - "url": "http://localhost:5173", - "webRoot": "${workspaceFolder}" - } - ] -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 83f23c4..59f9ead 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1812,7 +1812,7 @@ __metadata: languageName: node linkType: hard -"@exadev/breadboard-kits@npm:^0.8.2, @exadev/breadboard-kits@npm:^0.8.3": +"@exadev/breadboard-kits@npm:^0.8.3": version: 0.8.3 resolution: "@exadev/breadboard-kits@npm:0.8.3" dependencies: @@ -1826,7 +1826,7 @@ __metadata: languageName: node linkType: hard -"@exadev/breadboard-kits@npm:^0.9.1": +"@exadev/breadboard-kits@npm:^0.9.0, @exadev/breadboard-kits@npm:^0.9.1": version: 0.9.1 resolution: "@exadev/breadboard-kits@npm:0.9.1" dependencies: @@ -1869,6 +1869,15 @@ __metadata: languageName: node linkType: hard +"@google-labs/core-kit@npm:0.1.0, @google-labs/core-kit@npm:^0.1.0": + version: 0.1.0 + resolution: "@google-labs/core-kit@npm:0.1.0" + dependencies: + "@google-labs/breadboard": "npm:^0.6.0" + checksum: d05d81ee6318e9fdaa2699d45aee0339ef25547f234c67b0fe6d9cb0704fdaa879a36a20ca93ff9f2283c42770d9cb965ca53bdd0f09595c3b4401d51c16e26a + languageName: node + linkType: hard + "@google-labs/core-kit@npm:^0.0.1": version: 0.0.1 resolution: "@google-labs/core-kit@npm:0.0.1" @@ -1878,12 +1887,15 @@ __metadata: languageName: node linkType: hard -"@google-labs/core-kit@npm:^0.1.0": - version: 0.1.0 - resolution: "@google-labs/core-kit@npm:0.1.0" +"@google-labs/llm-starter@npm:0.3.0, @google-labs/llm-starter@npm:^0.3.0": + version: 0.3.0 + resolution: "@google-labs/llm-starter@npm:0.3.0" dependencies: "@google-labs/breadboard": "npm:^0.6.0" - checksum: d05d81ee6318e9fdaa2699d45aee0339ef25547f234c67b0fe6d9cb0704fdaa879a36a20ca93ff9f2283c42770d9cb965ca53bdd0f09595c3b4401d51c16e26a + "@rgrove/parse-xml": "npm:^4.1.0" + jsonata: "npm:^2.0.3" + url-template: "npm:^3.1.0" + checksum: 42c0610860a8bc1981506602e2ba7f376a80b32b8140b8f684c8002a08524ad502d60d2202f90a87600adf70734e06f5a89e0f7e1649668994b1a1e74d41d1f0 languageName: node linkType: hard @@ -1900,18 +1912,6 @@ __metadata: languageName: node linkType: hard -"@google-labs/llm-starter@npm:^0.3.0": - version: 0.3.0 - resolution: "@google-labs/llm-starter@npm:0.3.0" - dependencies: - "@google-labs/breadboard": "npm:^0.6.0" - "@rgrove/parse-xml": "npm:^4.1.0" - jsonata: "npm:^2.0.3" - url-template: "npm:^3.1.0" - checksum: 42c0610860a8bc1981506602e2ba7f376a80b32b8140b8f684c8002a08524ad502d60d2202f90a87600adf70734e06f5a89e0f7e1649668994b1a1e74d41d1f0 - languageName: node - linkType: hard - "@google-labs/palm-lite@npm:^0.0.2": version: 0.0.2 resolution: "@google-labs/palm-lite@npm:0.0.2" @@ -2617,12 +2617,21 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=13.7.0, @types/node@npm:^20.10.0, @types/node@npm:^20.10.4, @types/node@npm:^20.9.3": - version: 20.10.4 - resolution: "@types/node@npm:20.10.4" +"@types/node@npm:*, @types/node@npm:^20.10.0, @types/node@npm:^20.9.3": + version: 20.10.0 + resolution: "@types/node@npm:20.10.0" dependencies: undici-types: "npm:~5.26.4" - checksum: c10c1dd13f5c2341ad866777dc32946538a99e1ebd203ae127730814b8e5fa4aedfbcb01cb3e24a5466f1af64bcdfa16e7de6e745ff098fff0942aa779b7fe03 + checksum: c7d5ddbdbf3491e2363135c9611eb6bfae90eda2957279237fa232bcb29cd0df1cc3ee149d6de9915b754262a531ee2d57d33c9ecd58d763e8ad4856113822f3 + languageName: node + linkType: hard + +"@types/node@npm:>=13.7.0": + version: 20.10.3 + resolution: "@types/node@npm:20.10.3" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 7cb506abb0d570bb5133bd06a47115109a813b507323c985c3b4aef2993eed79b6bb62b82194cb5c558b4d349de3d199ee2e8c693b913065a1cd7f526cc65a68 languageName: node linkType: hard @@ -2635,6 +2644,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^20.10.4": + version: 20.10.4 + resolution: "@types/node@npm:20.10.4" + dependencies: + undici-types: "npm:~5.26.4" + checksum: c10c1dd13f5c2341ad866777dc32946538a99e1ebd203ae127730814b8e5fa4aedfbcb01cb3e24a5466f1af64bcdfa16e7de6e745ff098fff0942aa779b7fe03 + languageName: node + linkType: hard + "@types/prop-types@npm:*": version: 15.7.11 resolution: "@types/prop-types@npm:15.7.11" @@ -2651,7 +2669,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^18.2.42": +"@types/react@npm:*, @types/react@npm:^18.2.45": version: 18.2.45 resolution: "@types/react@npm:18.2.45" dependencies: @@ -2662,6 +2680,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.2.42": + version: 18.2.42 + resolution: "@types/react@npm:18.2.42" + dependencies: + "@types/prop-types": "npm:*" + "@types/scheduler": "npm:*" + csstype: "npm:^3.0.2" + checksum: b6ee1873ba551ca7bf87cefff00a615aa4322cd68d425858a2e09be260d8037d7fc68865739d2b05cc88cefa7acd009afdaea43e9856fc6302b322cc8c19464e + languageName: node + linkType: hard + "@types/resolve@npm:1.17.1": version: 1.17.1 resolution: "@types/resolve@npm:1.17.1" @@ -2706,7 +2735,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^6.12.0, @typescript-eslint/eslint-plugin@npm:^6.13.2": +"@typescript-eslint/eslint-plugin@npm:^6.12.0, @typescript-eslint/eslint-plugin@npm:^6.13.2, @typescript-eslint/eslint-plugin@npm:^6.14.0": version: 6.14.0 resolution: "@typescript-eslint/eslint-plugin@npm:6.14.0" dependencies: @@ -2731,7 +2760,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^6.12.0, @typescript-eslint/parser@npm:^6.13.2": +"@typescript-eslint/parser@npm:^6.12.0, @typescript-eslint/parser@npm:^6.13.2, @typescript-eslint/parser@npm:^6.14.0": version: 6.14.0 resolution: "@typescript-eslint/parser@npm:6.14.0" dependencies: @@ -3281,11 +3310,11 @@ __metadata: version: 0.0.0-use.local resolution: "breadboard-samples@workspace:." dependencies: - "@exadev/breadboard-kits": "npm:^0.8.2" - "@google-labs/breadboard": "npm:^0.5.1" - "@types/node": "npm:^20.9.3" + "@exadev/breadboard-kits": "npm:^0.9.0" + "@google-labs/breadboard": "npm:^0.6.0" + "@types/node": "npm:^20.10.4" tsx: "npm:^4.6.2" - typescript: "npm:^5.3.2" + typescript: "npm:^5.3.3" languageName: unknown linkType: soft @@ -3610,6 +3639,29 @@ __metadata: languageName: node linkType: hard +"coursecrafter@workspace:samples/CourseCrafter": + version: 0.0.0-use.local + resolution: "coursecrafter@workspace:samples/CourseCrafter" + dependencies: + "@exadev/breadboard-kits": "npm:^0.9.0" + "@google-labs/breadboard": "npm:^0.6.0" + "@google-labs/core-kit": "npm:0.1.0" + "@google-labs/llm-starter": "npm:0.3.0" + "@types/react": "npm:^18.2.45" + "@types/react-dom": "npm:^18.2.17" + "@typescript-eslint/eslint-plugin": "npm:^6.14.0" + "@typescript-eslint/parser": "npm:^6.14.0" + "@vitejs/plugin-react-swc": "npm:^3.5.0" + eslint: "npm:^8.55.0" + eslint-plugin-react-hooks: "npm:^4.6.0" + eslint-plugin-react-refresh: "npm:^0.4.5" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + typescript: "npm:^5.3.3" + vite: "npm:^5.0.8" + languageName: unknown + linkType: soft + "cross-spawn@npm:^6.0.5": version: 6.0.5 resolution: "cross-spawn@npm:6.0.5" @@ -8157,7 +8209,17 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.3.2, typescript@npm:^5.3.3": +"typescript@npm:^5.3.2": + version: 5.3.2 + resolution: "typescript@npm:5.3.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 415e5fb6611f5713e460bad48039f00bcfdbde53a2f911727862d5aa9c5d5edd250059a419df382d8f031709e15a169c41eb62b6a401da5eec7ac0f4e359d6ac + languageName: node + linkType: hard + +"typescript@npm:^5.3.3": version: 5.3.3 resolution: "typescript@npm:5.3.3" bin: @@ -8177,7 +8239,17 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.3.2#optional!builtin, typescript@patch:typescript@npm%3A^5.3.3#optional!builtin": +"typescript@patch:typescript@npm%3A^5.3.2#optional!builtin": + version: 5.3.2 + resolution: "typescript@patch:typescript@npm%3A5.3.2#optional!builtin::version=5.3.2&hash=e012d7" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 1b45cdfb577a78ae7a9a9d0b77a7b772142cb98ba05e4e5aefba7044a028ded885bcecef63166407a5986645cea816fe4986894336aacd5e791796ea79a6a7ed + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin": version: 5.3.3 resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin::version=5.3.3&hash=e012d7" bin: @@ -8445,7 +8517,7 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.0.2, vite@npm:^5.0.6, vite@npm:^5.0.7": +"vite@npm:^5.0.2, vite@npm:^5.0.6, vite@npm:^5.0.7, vite@npm:^5.0.8": version: 5.0.8 resolution: "vite@npm:5.0.8" dependencies: