From 09b7c237d167746612aefb3befb3dfccdba07b72 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 28 May 2025 20:39:46 +0000 Subject: [PATCH 01/36] refactor:moved all llm packages to "golem-llm" folder and updated CI and makefile.toml --- .github/workflows/ci.yaml | 8 +- Cargo.toml | 9 +- Makefile.toml | 249 ++++++++++-------- .../llm-anthropic}/Cargo.toml | 0 .../llm-anthropic}/src/bindings.rs | 0 .../llm-anthropic}/src/client.rs | 0 .../llm-anthropic}/src/conversions.rs | 0 .../llm-anthropic}/src/lib.rs | 0 .../llm-anthropic}/wit/anhropic.wit | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../llm-anthropic}/wit/deps/wasi:io/error.wit | 0 .../llm-anthropic}/wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../llm-anthropic}/wit/deps/wasi:io/world.wit | 0 {llm-grok => golem-llm/llm-grok}/Cargo.toml | 0 .../llm-grok}/src/bindings.rs | 0 .../llm-grok}/src/client.rs | 0 .../llm-grok}/src/conversions.rs | 0 {llm-grok => golem-llm/llm-grok}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../llm-grok}/wit/deps/wasi:io/error.wit | 0 .../llm-grok}/wit/deps/wasi:io/poll.wit | 0 .../llm-grok}/wit/deps/wasi:io/streams.wit | 0 .../llm-grok}/wit/deps/wasi:io/world.wit | 0 {llm-grok => golem-llm/llm-grok}/wit/grok.wit | 0 .../llm-ollama}/Cargo.toml | 0 .../llm-ollama}/src/bindings.rs | 0 .../llm-ollama}/src/client.rs | 0 .../llm-ollama}/src/conversions.rs | 0 .../llm-ollama}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../llm-ollama}/wit/deps/wasi:io/error.wit | 0 .../llm-ollama}/wit/deps/wasi:io/poll.wit | 0 .../llm-ollama}/wit/deps/wasi:io/streams.wit | 0 .../llm-ollama}/wit/deps/wasi:io/world.wit | 0 .../llm-ollama}/wit/ollama.wit | 0 .../llm-openai}/Cargo.toml | 0 .../llm-openai}/src/bindings.rs | 0 .../llm-openai}/src/client.rs | 0 .../llm-openai}/src/conversions.rs | 0 .../llm-openai}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../llm-openai}/wit/deps/wasi:io/error.wit | 0 .../llm-openai}/wit/deps/wasi:io/poll.wit | 0 .../llm-openai}/wit/deps/wasi:io/streams.wit | 0 .../llm-openai}/wit/deps/wasi:io/world.wit | 0 .../llm-openai}/wit/openai.wit | 0 .../llm-openrouter}/Cargo.toml | 0 .../llm-openrouter}/src/bindings.rs | 0 .../llm-openrouter}/src/client.rs | 0 .../llm-openrouter}/src/conversions.rs | 0 .../llm-openrouter}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../wit/deps/wasi:io/error.wit | 0 .../llm-openrouter}/wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../wit/deps/wasi:io/world.wit | 0 .../llm-openrouter}/wit/openrouter.wit | 0 {llm => golem-llm/llm}/Cargo.toml | 2 +- {llm => golem-llm/llm}/src/chat_stream.rs | 0 {llm => golem-llm/llm}/src/config.rs | 0 {llm => golem-llm/llm}/src/durability.rs | 0 {llm => golem-llm/llm}/src/error.rs | 0 .../llm}/src/event_source/error.rs | 0 .../llm}/src/event_source/event_stream.rs | 0 .../llm}/src/event_source/message_event.rs | 0 .../llm}/src/event_source/mod.rs | 0 .../llm}/src/event_source/ndjson_stream.rs | 0 .../llm}/src/event_source/parser.rs | 0 .../llm}/src/event_source/stream.rs | 0 .../llm}/src/event_source/utf8_stream.rs | 0 {llm => golem-llm/llm}/src/lib.rs | 0 .../llm}/wit/deps/golem-llm/golem-llm.wit | 0 .../llm}/wit/deps/wasi:io/error.wit | 0 .../llm}/wit/deps/wasi:io/poll.wit | 0 .../llm}/wit/deps/wasi:io/streams.wit | 0 .../llm}/wit/deps/wasi:io/world.wit | 0 {llm => golem-llm/llm}/wit/llm.wit | 0 {test => golem-llm/test}/.gitignore | 0 .../test}/.vscode/settings.json | 0 {test => golem-llm/test}/Cargo.lock | 0 {test => golem-llm/test}/Cargo.toml | 0 .../test}/common-rust/common-lib/Cargo.toml | 0 .../test}/common-rust/common-lib/src/lib.rs | 0 .../test}/common-rust/golem.yaml | 0 .../test}/components-rust/.gitignore | 0 .../components-rust/test-helper/Cargo.lock | 0 .../components-rust/test-helper/Cargo.toml | 0 .../components-rust/test-helper/golem.yaml | 0 .../components-rust/test-helper/src/lib.rs | 0 .../test-helper/wit/test-helper.wit | 0 .../test}/components-rust/test-llm/Cargo.lock | 0 .../test}/components-rust/test-llm/Cargo.toml | 0 .../test}/components-rust/test-llm/golem.yaml | 0 .../test}/components-rust/test-llm/src/lib.rs | 0 .../components-rust/test-llm/wit/test-llm.wit | 0 {test => golem-llm/test}/data/cat.png | Bin {test => golem-llm/test}/golem.yaml | 0 .../test}/wit/deps/golem-llm/golem-llm.wit | 0 .../test}/wit/deps/io/error.wit | 0 {test => golem-llm/test}/wit/deps/io/poll.wit | 0 .../test}/wit/deps/io/streams.wit | 0 .../test}/wit/deps/io/world.wit | 0 {wit => golem-llm/wit}/deps.lock | 0 {wit => golem-llm/wit}/deps.toml | 0 {wit => golem-llm/wit}/deps/wasi:io/error.wit | 0 {wit => golem-llm/wit}/deps/wasi:io/poll.wit | 0 .../wit}/deps/wasi:io/streams.wit | 0 {wit => golem-llm/wit}/deps/wasi:io/world.wit | 0 {wit => golem-llm/wit}/golem-llm.wit | 0 110 files changed, 142 insertions(+), 126 deletions(-) rename {llm-anthropic => golem-llm/llm-anthropic}/Cargo.toml (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/src/bindings.rs (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/src/client.rs (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/src/conversions.rs (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/src/lib.rs (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/wit/anhropic.wit (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/wit/deps/golem-llm/golem-llm.wit (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/wit/deps/wasi:io/error.wit (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/wit/deps/wasi:io/poll.wit (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/wit/deps/wasi:io/streams.wit (100%) rename {llm-anthropic => golem-llm/llm-anthropic}/wit/deps/wasi:io/world.wit (100%) rename {llm-grok => golem-llm/llm-grok}/Cargo.toml (100%) rename {llm-grok => golem-llm/llm-grok}/src/bindings.rs (100%) rename {llm-grok => golem-llm/llm-grok}/src/client.rs (100%) rename {llm-grok => golem-llm/llm-grok}/src/conversions.rs (100%) rename {llm-grok => golem-llm/llm-grok}/src/lib.rs (100%) rename {llm-grok => golem-llm/llm-grok}/wit/deps/golem-llm/golem-llm.wit (100%) rename {llm-grok => golem-llm/llm-grok}/wit/deps/wasi:io/error.wit (100%) rename {llm-grok => golem-llm/llm-grok}/wit/deps/wasi:io/poll.wit (100%) rename {llm-grok => golem-llm/llm-grok}/wit/deps/wasi:io/streams.wit (100%) rename {llm-grok => golem-llm/llm-grok}/wit/deps/wasi:io/world.wit (100%) rename {llm-grok => golem-llm/llm-grok}/wit/grok.wit (100%) rename {llm-ollama => golem-llm/llm-ollama}/Cargo.toml (100%) rename {llm-ollama => golem-llm/llm-ollama}/src/bindings.rs (100%) rename {llm-ollama => golem-llm/llm-ollama}/src/client.rs (100%) rename {llm-ollama => golem-llm/llm-ollama}/src/conversions.rs (100%) rename {llm-ollama => golem-llm/llm-ollama}/src/lib.rs (100%) rename {llm-ollama => golem-llm/llm-ollama}/wit/deps/golem-llm/golem-llm.wit (100%) rename {llm-ollama => golem-llm/llm-ollama}/wit/deps/wasi:io/error.wit (100%) rename {llm-ollama => golem-llm/llm-ollama}/wit/deps/wasi:io/poll.wit (100%) rename {llm-ollama => golem-llm/llm-ollama}/wit/deps/wasi:io/streams.wit (100%) rename {llm-ollama => golem-llm/llm-ollama}/wit/deps/wasi:io/world.wit (100%) rename {llm-ollama => golem-llm/llm-ollama}/wit/ollama.wit (100%) rename {llm-openai => golem-llm/llm-openai}/Cargo.toml (100%) rename {llm-openai => golem-llm/llm-openai}/src/bindings.rs (100%) rename {llm-openai => golem-llm/llm-openai}/src/client.rs (100%) rename {llm-openai => golem-llm/llm-openai}/src/conversions.rs (100%) rename {llm-openai => golem-llm/llm-openai}/src/lib.rs (100%) rename {llm-openai => golem-llm/llm-openai}/wit/deps/golem-llm/golem-llm.wit (100%) rename {llm-openai => golem-llm/llm-openai}/wit/deps/wasi:io/error.wit (100%) rename {llm-openai => golem-llm/llm-openai}/wit/deps/wasi:io/poll.wit (100%) rename {llm-openai => golem-llm/llm-openai}/wit/deps/wasi:io/streams.wit (100%) rename {llm-openai => golem-llm/llm-openai}/wit/deps/wasi:io/world.wit (100%) rename {llm-openai => golem-llm/llm-openai}/wit/openai.wit (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/Cargo.toml (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/src/bindings.rs (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/src/client.rs (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/src/conversions.rs (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/src/lib.rs (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/wit/deps/golem-llm/golem-llm.wit (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/wit/deps/wasi:io/error.wit (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/wit/deps/wasi:io/poll.wit (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/wit/deps/wasi:io/streams.wit (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/wit/deps/wasi:io/world.wit (100%) rename {llm-openrouter => golem-llm/llm-openrouter}/wit/openrouter.wit (100%) rename {llm => golem-llm/llm}/Cargo.toml (81%) rename {llm => golem-llm/llm}/src/chat_stream.rs (100%) rename {llm => golem-llm/llm}/src/config.rs (100%) rename {llm => golem-llm/llm}/src/durability.rs (100%) rename {llm => golem-llm/llm}/src/error.rs (100%) rename {llm => golem-llm/llm}/src/event_source/error.rs (100%) rename {llm => golem-llm/llm}/src/event_source/event_stream.rs (100%) rename {llm => golem-llm/llm}/src/event_source/message_event.rs (100%) rename {llm => golem-llm/llm}/src/event_source/mod.rs (100%) rename {llm => golem-llm/llm}/src/event_source/ndjson_stream.rs (100%) rename {llm => golem-llm/llm}/src/event_source/parser.rs (100%) rename {llm => golem-llm/llm}/src/event_source/stream.rs (100%) rename {llm => golem-llm/llm}/src/event_source/utf8_stream.rs (100%) rename {llm => golem-llm/llm}/src/lib.rs (100%) rename {llm => golem-llm/llm}/wit/deps/golem-llm/golem-llm.wit (100%) rename {llm => golem-llm/llm}/wit/deps/wasi:io/error.wit (100%) rename {llm => golem-llm/llm}/wit/deps/wasi:io/poll.wit (100%) rename {llm => golem-llm/llm}/wit/deps/wasi:io/streams.wit (100%) rename {llm => golem-llm/llm}/wit/deps/wasi:io/world.wit (100%) rename {llm => golem-llm/llm}/wit/llm.wit (100%) rename {test => golem-llm/test}/.gitignore (100%) rename {test => golem-llm/test}/.vscode/settings.json (100%) rename {test => golem-llm/test}/Cargo.lock (100%) rename {test => golem-llm/test}/Cargo.toml (100%) rename {test => golem-llm/test}/common-rust/common-lib/Cargo.toml (100%) rename {test => golem-llm/test}/common-rust/common-lib/src/lib.rs (100%) rename {test => golem-llm/test}/common-rust/golem.yaml (100%) rename {test => golem-llm/test}/components-rust/.gitignore (100%) rename {test => golem-llm/test}/components-rust/test-helper/Cargo.lock (100%) rename {test => golem-llm/test}/components-rust/test-helper/Cargo.toml (100%) rename {test => golem-llm/test}/components-rust/test-helper/golem.yaml (100%) rename {test => golem-llm/test}/components-rust/test-helper/src/lib.rs (100%) rename {test => golem-llm/test}/components-rust/test-helper/wit/test-helper.wit (100%) rename {test => golem-llm/test}/components-rust/test-llm/Cargo.lock (100%) rename {test => golem-llm/test}/components-rust/test-llm/Cargo.toml (100%) rename {test => golem-llm/test}/components-rust/test-llm/golem.yaml (100%) rename {test => golem-llm/test}/components-rust/test-llm/src/lib.rs (100%) rename {test => golem-llm/test}/components-rust/test-llm/wit/test-llm.wit (100%) rename {test => golem-llm/test}/data/cat.png (100%) rename {test => golem-llm/test}/golem.yaml (100%) rename {test => golem-llm/test}/wit/deps/golem-llm/golem-llm.wit (100%) rename {test => golem-llm/test}/wit/deps/io/error.wit (100%) rename {test => golem-llm/test}/wit/deps/io/poll.wit (100%) rename {test => golem-llm/test}/wit/deps/io/streams.wit (100%) rename {test => golem-llm/test}/wit/deps/io/world.wit (100%) rename {wit => golem-llm/wit}/deps.lock (100%) rename {wit => golem-llm/wit}/deps.toml (100%) rename {wit => golem-llm/wit}/deps/wasi:io/error.wit (100%) rename {wit => golem-llm/wit}/deps/wasi:io/poll.wit (100%) rename {wit => golem-llm/wit}/deps/wasi:io/streams.wit (100%) rename {wit => golem-llm/wit}/deps/wasi:io/world.wit (100%) rename {wit => golem-llm/wit}/golem-llm.wit (100%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a5a2ca74a..5985d7936 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -84,7 +84,7 @@ jobs: run: cargo binstall --force --locked cargo-component@0.21.1 - name: Build all test components run: cargo make build-test-components - ollama-integration-tests: + ollama-llm-integration-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -137,8 +137,8 @@ jobs: - name: Build and test Ollama integration run: | set -e - cargo make build-ollama - cd test + cargo make build-llm-ollama + cd golem-llm/test golem-cli app build -b ollama-debug golem-cli app deploy -b ollama-debug golem-cli worker new -e GOLEM_OLLAMA_BASE_URL=http://localhost:11434 test:llm/ollama-1 @@ -153,7 +153,7 @@ jobs: needs: - tests - build-test-components - - ollama-integration-tests + - ollama-llm-integration-tests runs-on: ubuntu-latest permissions: contents: write diff --git a/Cargo.toml b/Cargo.toml index f1dee241e..fd4cf28ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,7 @@ [workspace] resolver = "2" -members = [ - "llm", - "llm-anthropic", - "llm-grok", - "llm-ollama", - "llm-openai", - "llm-openrouter", -] +members = [ "golem-llm/llm", "golem-llm/llm-anthropic", "golem-llm/llm-grok", "golem-llm/llm-ollama", "golem-llm/llm-openai", "golem-llm/llm-openrouter"] [profile.release] debug = false diff --git a/Makefile.toml b/Makefile.toml index 37053ddcd..ceef9d283 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -10,117 +10,117 @@ args = ["clean"] command = "cargo" args = ["test"] -[tasks.build-ollama] +[tasks.build-llm-ollama] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama"] -[tasks.build-ollama-portable] +[tasks.build-llm-ollama-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama", "--no-default-features"] -[tasks.build-anthropic] +[tasks.build-llm-anthropic] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-anthropic"] -[tasks.build-anthropic-portable] +[tasks.build-llm-anthropic-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-anthropic", "--no-default-features"] -[tasks.build-grok] +[tasks.build-llm-grok] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok"] -[tasks.build-grok-portable] +[tasks.build-llm-grok-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok", "--no-default-features"] -[tasks.build-openai] +[tasks.build-llm-openai] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai"] -[tasks.build-openai-portable] +[tasks.build-llm-openai-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai", "--no-default-features"] -[tasks.build-openrouter] +[tasks.build-llm-openrouter] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openrouter"] -[tasks.build-openrouter-portable] +[tasks.build-llm-openrouter-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openrouter", "--no-default-features"] -[tasks.build] +[tasks.build-llm] dependencies = [ - "build-anthropic", - "build-grok", - "build-openai", - "build-openrouter", - "build-ollama", + "build-llm-anthropic", + "build-llm-grok", + "build-llm-openai", + "build-llm-openrouter", + "build-llm-ollama", ] -[tasks.build-portable] +[tasks.build-llm-portable] dependencies = [ - "build-anthropic-portable", - "build-grok-portable", - "build-openai-portable", - "build-openrouter-portable", - "build-ollama-portable", + "build-llm-anthropic-portable", + "build-llm-grok-portable", + "build-llm-openai-portable", + "build-llm-openrouter-portable", + "build-llm-ollama-portable", ] -[tasks.build-all] +[tasks.build-all-llm] script_runner = "@duckscript" script = ''' -mkdir components/debug +mkdir components/llm/debug cm_run_task clean -cm_run_task build +cm_run_task build-llm -cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/debug/golem_llm_anthropic.wasm -cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/debug/golem_llm_grok.wasm -cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/debug/golem_llm_openai.wasm -cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/debug/golem_llm_openrouter.wasm -cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/debug/golem_llm_ollama.wasm +cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/llm/debug/golem_llm_anthropic.wasm +cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/llm/debug/golem_llm_grok.wasm +cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/llm/debug/golem_llm_openai.wasm +cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/llm/debug/golem_llm_openrouter.wasm +cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/llm/debug/golem_llm_ollama.wasm cm_run_task clean -cm_run_task build-portable +cm_run_task build-llm-portable -cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/debug/golem_llm_anthropic-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/debug/golem_llm_grok-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/debug/golem_llm_openai-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/debug/golem_llm_openrouter-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/debug/golem_llm_ollama-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/llm/debug/golem_llm_anthropic-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/llm/debug/golem_llm_grok-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/llm/debug/golem_llm_openai-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/llm/debug/golem_llm_openrouter-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/llm/debug/golem_llm_ollama-portable.wasm ''' -[tasks.release-build-ollama] +[tasks.release-build-llm-ollama] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama", "--release"] -[tasks.release-build-ollama-portable] +[tasks.release-build-llm-ollama-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama", "--release", "--no-default-features"] -[tasks.release-build-anthropic] +[tasks.release-build-llm-anthropic] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-anthropic", "--release"] -[tasks.release-build-anthropic-portable] +[tasks.release-build-llm-anthropic-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = [ @@ -131,32 +131,32 @@ args = [ "--no-default-features", ] -[tasks.release-build-grok] +[tasks.release-build-llm-grok] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok", "--release"] -[tasks.release-build-grok-portable] +[tasks.release-build-llm-grok-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok", "--release", "--no-default-features"] -[tasks.release-build-openai] +[tasks.release-build-llm-openai] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai", "--release"] -[tasks.release-build-openai-portable] +[tasks.release-build-llm-openai-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai", "--release", "--no-default-features"] -[tasks.release-build-openrouter] +[tasks.release-build-llm-openrouter] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openrouter", "--release"] -[tasks.release-build-openrouter-portable] +[tasks.release-build-llm-openrouter-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = [ @@ -167,57 +167,57 @@ args = [ "--no-default-features", ] -[tasks.release-build] +[tasks.release-build-llm] dependencies = [ - "release-build-anthropic", - "release-build-grok", - "release-build-openai", - "release-build-openrouter", - "release-build-ollama", + "release-build-llm-anthropic", + "release-build-llm-grok", + "release-build-llm-openai", + "release-build-llm-openrouter", + "release-build-llm-ollama", ] -[tasks.release-build-portable] +[tasks.release-build-llm-portable] dependencies = [ - "release-build-anthropic-portable", - "release-build-grok-portable", - "release-build-openai-portable", - "release-build-openrouter-portable", - "release-build-ollama-portable", + "release-build-llm-anthropic-portable", + "release-build-llm-grok-portable", + "release-build-llm-openai-portable", + "release-build-llm-openrouter-portable", + "release-build-llm-ollama-portable", ] -[tasks.release-build-all] +[tasks.release-build-all-llm] script_runner = "@duckscript" script = ''' -mkdir components/release +mkdir components/llm/release cm_run_task set-version cm_run_task clean -cm_run_task release-build +cm_run_task release-build-llm -cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/release/golem_llm_anthropic.wasm -cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/release/golem_llm_grok.wasm -cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/release/golem_llm_openai.wasm -cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/release/golem_llm_openrouter.wasm -cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/release/golem_llm_ollama.wasm +cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/llm/release/golem_llm_anthropic.wasm +cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/llm/release/golem_llm_grok.wasm +cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/llm/release/golem_llm_openai.wasm +cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/llm/release/golem_llm_openrouter.wasm +cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/llm/release/golem_llm_ollama.wasm cm_run_task clean -cm_run_task release-build-portable +cm_run_task release-build-llm-portable -cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/release/golem_llm_anthropic-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/release/golem_llm_grok-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/release/golem_llm_openai-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/release/golem_llm_openrouter-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/release/golem_llm_ollama-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/llm/release/golem_llm_anthropic-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/llm/release/golem_llm_grok-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/llm/release/golem_llm_openai-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/llm/release/golem_llm_openrouter-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/llm/release/golem_llm_ollama-portable.wasm ''' -[tasks.wit-update] +[tasks.wit-llm-update] install_crate = { crate_name = "wit-deps-cli" } command = "wit-deps" args = ["update"] -[tasks.wit] -dependencies = ["wit-update"] +[tasks.wit-llm] +dependencies = ["wit-llm-update"] #condition = { files_modified = { input = [ # "wit/golem-llm.wit", @@ -232,42 +232,43 @@ dependencies = ["wit-update"] script_runner = "@duckscript" script = """ -rm -r llm/wit/deps -mkdir llm/wit/deps/golem-llm -cp wit/golem-llm.wit llm/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io llm/wit/deps -rm -r llm-anthropic/wit/deps -mkdir llm-anthropic/wit/deps/golem-llm -cp wit/golem-llm.wit llm-anthropic/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io llm-anthropic/wit/deps -rm -r llm-grok/wit/deps -mkdir llm-grok/wit/deps/golem-llm -cp wit/golem-llm.wit llm-grok/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io llm-grok/wit/deps -rm -r llm-openai/wit/deps -mkdir llm-openai/wit/deps/golem-llm -cp wit/golem-llm.wit llm-openai/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io llm-openai/wit/deps -rm -r llm-openrouter/wit/deps -mkdir llm-openrouter/wit/deps/golem-llm -cp wit/golem-llm.wit llm-openrouter/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io llm-openrouter/wit/deps -rm -r llm-ollama/wit/deps -mkdir llm-ollama/wit/deps/golem-llm -cp wit/golem-llm.wit llm-ollama/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io llm-ollama/wit/deps - - -rm -r test/wit -mkdir test/wit/deps/golem-llm -mkdir test/wit/deps/io -cp wit/golem-llm.wit test/wit/deps/golem-llm/golem-llm.wit -cp wit/deps/wasi:io/error.wit test/wit/deps/io/error.wit -cp wit/deps/wasi:io/poll.wit test/wit/deps/io/poll.wit -cp wit/deps/wasi:io/streams.wit test/wit/deps/io/streams.wit -cp wit/deps/wasi:io/world.wit test/wit/deps/io/world.wit +rm -r golem-llm/llm/wit/deps +mkdir golem-llm/llm/wit/deps/golem-llm +cp golem-llm/wit/golem-llm.wit golem-llm/llm/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io golem-llm/llm/wit/deps +rm -r golem-llm/llm-anthropic/wit/deps +mkdir golem-llm/llm-anthropic/wit/deps/golem-llm +cp golem-llm/wit/golem-llm.wit golem-llm/llm-anthropic/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io llm-anthropic/wit/deps +rm -r golem-llm/llm-grok/wit/deps +mkdir golem-llm/llm-grok/wit/deps/golem-llm +cp golem-llm/wit/golem-llm.wit golem-llm/llm-grok/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io golem-llm/llm-grok/wit/deps +rm -r golem-llm/llm-openai/wit/deps +mkdir golem-llm/llm-openai/wit/deps/golem-llm +cp golem-llm/wit/golem-llm.wit golem-llm/llm-openai/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io golem-llm/llm-openai/wit/deps +rm -r golem-llm/llm-openrouter/wit/deps +mkdir golem-llm/llm-openrouter/wit/deps/golem-llm +cp golem-llm/wit/golem-llm.wit golem-llm/llm-openrouter/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io golem-llm/llm-openrouter/wit/deps +rm -r golem-llm/llm-ollama/wit/deps +mkdir golem-llm/llm-ollama/wit/deps/golem-llm +cp golem-llm/wit/golem-llm.wit golem-llm/llm-ollama/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io golem-llm/llm-ollama/wit/deps + + +rm -r golem-llm/test/wit +mkdir golem-llm/test/wit/deps/golem-llm +mkdir golem-llm/test/wit/deps/io +cp golem-llm/wit/golem-llm.wit golem-llm/test/wit/deps/golem-llm/golem-llm.wit +cp golem-llm/wit/deps/wasi:io/error.wit golem-llm/test/wit/deps/io/error.wit +cp golem-llm/wit/deps/wasi:io/poll.wit golem-llm/test/wit/deps/io/poll.wit +cp golem-llm/wit/deps/wasi:io/streams.wit golem-llm/test/wit/deps/io/streams.wit +cp golem-llm/wit/deps/wasi:io/world.wit golem-llm/test/wit/deps/io/world.wit """ + [tasks.check] description = "Runs rustfmt and clippy checks without applying any fix" dependencies = ["check-clippy", "check-rustfmt"] @@ -286,7 +287,7 @@ args = ["clippy", "--all-targets", "--", "--no-deps", "-Dwarnings"] [tasks.fix] description = "Runs rustfmt and clippy checks and applies fixes" -dependencies = ["wit", "fix-clippy", "fix-rustfmt"] +dependencies = ["wit-llm", "wit-embed", "fix-clippy", "fix-rustfmt"] [tasks.fix-rustfmt] description = "Runs rustfmt checks and applies fixes" @@ -308,14 +309,14 @@ args = [ "-Dwarnings", ] -[tasks.build-test-components] +[tasks.build-llm-test-components] dependencies = ["build"] description = "Builds all test components with golem-cli" install_crate = "cargo-binstall" script = ''' cargo-binstall golem-cli@1.2.2-dev.11 --locked --force --no-confirm cargo-binstall wac-cli --locked --force --no-confirm -cd test +cd golem-llm/test golem-cli --version golem-cli app clean golem-cli app build -b anthropic-debug @@ -329,7 +330,6 @@ golem-cli app clean golem-cli app build -b ollama-debug ''' - [tasks.set-version] description = "Sets the version in all Cargo.toml files to the value of the VERSION environment variable" condition = { env_set = ["VERSION"] } @@ -356,3 +356,26 @@ foreach ($file in $cargoFiles) Set-Content $file.PSPath } ''' + + + +[tasks.build-all] +script_runner = "@duckscript" +script = """ +cm_run_task build-all-llm +""" + + +[tasks.release-build-all] +script_runner = "@duckscript" +script = """ +cm_run_task release-build-all-llm +""" + + + +[tasks.build-test-components] +script_runner = "@duckscript" +script = """ +cm_run_task build-llm-test-components +""" \ No newline at end of file diff --git a/llm-anthropic/Cargo.toml b/golem-llm/llm-anthropic/Cargo.toml similarity index 100% rename from llm-anthropic/Cargo.toml rename to golem-llm/llm-anthropic/Cargo.toml diff --git a/llm-anthropic/src/bindings.rs b/golem-llm/llm-anthropic/src/bindings.rs similarity index 100% rename from llm-anthropic/src/bindings.rs rename to golem-llm/llm-anthropic/src/bindings.rs diff --git a/llm-anthropic/src/client.rs b/golem-llm/llm-anthropic/src/client.rs similarity index 100% rename from llm-anthropic/src/client.rs rename to golem-llm/llm-anthropic/src/client.rs diff --git a/llm-anthropic/src/conversions.rs b/golem-llm/llm-anthropic/src/conversions.rs similarity index 100% rename from llm-anthropic/src/conversions.rs rename to golem-llm/llm-anthropic/src/conversions.rs diff --git a/llm-anthropic/src/lib.rs b/golem-llm/llm-anthropic/src/lib.rs similarity index 100% rename from llm-anthropic/src/lib.rs rename to golem-llm/llm-anthropic/src/lib.rs diff --git a/llm-anthropic/wit/anhropic.wit b/golem-llm/llm-anthropic/wit/anhropic.wit similarity index 100% rename from llm-anthropic/wit/anhropic.wit rename to golem-llm/llm-anthropic/wit/anhropic.wit diff --git a/llm-anthropic/wit/deps/golem-llm/golem-llm.wit b/golem-llm/llm-anthropic/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from llm-anthropic/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/llm-anthropic/wit/deps/golem-llm/golem-llm.wit diff --git a/llm-anthropic/wit/deps/wasi:io/error.wit b/golem-llm/llm-anthropic/wit/deps/wasi:io/error.wit similarity index 100% rename from llm-anthropic/wit/deps/wasi:io/error.wit rename to golem-llm/llm-anthropic/wit/deps/wasi:io/error.wit diff --git a/llm-anthropic/wit/deps/wasi:io/poll.wit b/golem-llm/llm-anthropic/wit/deps/wasi:io/poll.wit similarity index 100% rename from llm-anthropic/wit/deps/wasi:io/poll.wit rename to golem-llm/llm-anthropic/wit/deps/wasi:io/poll.wit diff --git a/llm-anthropic/wit/deps/wasi:io/streams.wit b/golem-llm/llm-anthropic/wit/deps/wasi:io/streams.wit similarity index 100% rename from llm-anthropic/wit/deps/wasi:io/streams.wit rename to golem-llm/llm-anthropic/wit/deps/wasi:io/streams.wit diff --git a/llm-anthropic/wit/deps/wasi:io/world.wit b/golem-llm/llm-anthropic/wit/deps/wasi:io/world.wit similarity index 100% rename from llm-anthropic/wit/deps/wasi:io/world.wit rename to golem-llm/llm-anthropic/wit/deps/wasi:io/world.wit diff --git a/llm-grok/Cargo.toml b/golem-llm/llm-grok/Cargo.toml similarity index 100% rename from llm-grok/Cargo.toml rename to golem-llm/llm-grok/Cargo.toml diff --git a/llm-grok/src/bindings.rs b/golem-llm/llm-grok/src/bindings.rs similarity index 100% rename from llm-grok/src/bindings.rs rename to golem-llm/llm-grok/src/bindings.rs diff --git a/llm-grok/src/client.rs b/golem-llm/llm-grok/src/client.rs similarity index 100% rename from llm-grok/src/client.rs rename to golem-llm/llm-grok/src/client.rs diff --git a/llm-grok/src/conversions.rs b/golem-llm/llm-grok/src/conversions.rs similarity index 100% rename from llm-grok/src/conversions.rs rename to golem-llm/llm-grok/src/conversions.rs diff --git a/llm-grok/src/lib.rs b/golem-llm/llm-grok/src/lib.rs similarity index 100% rename from llm-grok/src/lib.rs rename to golem-llm/llm-grok/src/lib.rs diff --git a/llm-grok/wit/deps/golem-llm/golem-llm.wit b/golem-llm/llm-grok/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from llm-grok/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/llm-grok/wit/deps/golem-llm/golem-llm.wit diff --git a/llm-grok/wit/deps/wasi:io/error.wit b/golem-llm/llm-grok/wit/deps/wasi:io/error.wit similarity index 100% rename from llm-grok/wit/deps/wasi:io/error.wit rename to golem-llm/llm-grok/wit/deps/wasi:io/error.wit diff --git a/llm-grok/wit/deps/wasi:io/poll.wit b/golem-llm/llm-grok/wit/deps/wasi:io/poll.wit similarity index 100% rename from llm-grok/wit/deps/wasi:io/poll.wit rename to golem-llm/llm-grok/wit/deps/wasi:io/poll.wit diff --git a/llm-grok/wit/deps/wasi:io/streams.wit b/golem-llm/llm-grok/wit/deps/wasi:io/streams.wit similarity index 100% rename from llm-grok/wit/deps/wasi:io/streams.wit rename to golem-llm/llm-grok/wit/deps/wasi:io/streams.wit diff --git a/llm-grok/wit/deps/wasi:io/world.wit b/golem-llm/llm-grok/wit/deps/wasi:io/world.wit similarity index 100% rename from llm-grok/wit/deps/wasi:io/world.wit rename to golem-llm/llm-grok/wit/deps/wasi:io/world.wit diff --git a/llm-grok/wit/grok.wit b/golem-llm/llm-grok/wit/grok.wit similarity index 100% rename from llm-grok/wit/grok.wit rename to golem-llm/llm-grok/wit/grok.wit diff --git a/llm-ollama/Cargo.toml b/golem-llm/llm-ollama/Cargo.toml similarity index 100% rename from llm-ollama/Cargo.toml rename to golem-llm/llm-ollama/Cargo.toml diff --git a/llm-ollama/src/bindings.rs b/golem-llm/llm-ollama/src/bindings.rs similarity index 100% rename from llm-ollama/src/bindings.rs rename to golem-llm/llm-ollama/src/bindings.rs diff --git a/llm-ollama/src/client.rs b/golem-llm/llm-ollama/src/client.rs similarity index 100% rename from llm-ollama/src/client.rs rename to golem-llm/llm-ollama/src/client.rs diff --git a/llm-ollama/src/conversions.rs b/golem-llm/llm-ollama/src/conversions.rs similarity index 100% rename from llm-ollama/src/conversions.rs rename to golem-llm/llm-ollama/src/conversions.rs diff --git a/llm-ollama/src/lib.rs b/golem-llm/llm-ollama/src/lib.rs similarity index 100% rename from llm-ollama/src/lib.rs rename to golem-llm/llm-ollama/src/lib.rs diff --git a/llm-ollama/wit/deps/golem-llm/golem-llm.wit b/golem-llm/llm-ollama/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from llm-ollama/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/llm-ollama/wit/deps/golem-llm/golem-llm.wit diff --git a/llm-ollama/wit/deps/wasi:io/error.wit b/golem-llm/llm-ollama/wit/deps/wasi:io/error.wit similarity index 100% rename from llm-ollama/wit/deps/wasi:io/error.wit rename to golem-llm/llm-ollama/wit/deps/wasi:io/error.wit diff --git a/llm-ollama/wit/deps/wasi:io/poll.wit b/golem-llm/llm-ollama/wit/deps/wasi:io/poll.wit similarity index 100% rename from llm-ollama/wit/deps/wasi:io/poll.wit rename to golem-llm/llm-ollama/wit/deps/wasi:io/poll.wit diff --git a/llm-ollama/wit/deps/wasi:io/streams.wit b/golem-llm/llm-ollama/wit/deps/wasi:io/streams.wit similarity index 100% rename from llm-ollama/wit/deps/wasi:io/streams.wit rename to golem-llm/llm-ollama/wit/deps/wasi:io/streams.wit diff --git a/llm-ollama/wit/deps/wasi:io/world.wit b/golem-llm/llm-ollama/wit/deps/wasi:io/world.wit similarity index 100% rename from llm-ollama/wit/deps/wasi:io/world.wit rename to golem-llm/llm-ollama/wit/deps/wasi:io/world.wit diff --git a/llm-ollama/wit/ollama.wit b/golem-llm/llm-ollama/wit/ollama.wit similarity index 100% rename from llm-ollama/wit/ollama.wit rename to golem-llm/llm-ollama/wit/ollama.wit diff --git a/llm-openai/Cargo.toml b/golem-llm/llm-openai/Cargo.toml similarity index 100% rename from llm-openai/Cargo.toml rename to golem-llm/llm-openai/Cargo.toml diff --git a/llm-openai/src/bindings.rs b/golem-llm/llm-openai/src/bindings.rs similarity index 100% rename from llm-openai/src/bindings.rs rename to golem-llm/llm-openai/src/bindings.rs diff --git a/llm-openai/src/client.rs b/golem-llm/llm-openai/src/client.rs similarity index 100% rename from llm-openai/src/client.rs rename to golem-llm/llm-openai/src/client.rs diff --git a/llm-openai/src/conversions.rs b/golem-llm/llm-openai/src/conversions.rs similarity index 100% rename from llm-openai/src/conversions.rs rename to golem-llm/llm-openai/src/conversions.rs diff --git a/llm-openai/src/lib.rs b/golem-llm/llm-openai/src/lib.rs similarity index 100% rename from llm-openai/src/lib.rs rename to golem-llm/llm-openai/src/lib.rs diff --git a/llm-openai/wit/deps/golem-llm/golem-llm.wit b/golem-llm/llm-openai/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from llm-openai/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/llm-openai/wit/deps/golem-llm/golem-llm.wit diff --git a/llm-openai/wit/deps/wasi:io/error.wit b/golem-llm/llm-openai/wit/deps/wasi:io/error.wit similarity index 100% rename from llm-openai/wit/deps/wasi:io/error.wit rename to golem-llm/llm-openai/wit/deps/wasi:io/error.wit diff --git a/llm-openai/wit/deps/wasi:io/poll.wit b/golem-llm/llm-openai/wit/deps/wasi:io/poll.wit similarity index 100% rename from llm-openai/wit/deps/wasi:io/poll.wit rename to golem-llm/llm-openai/wit/deps/wasi:io/poll.wit diff --git a/llm-openai/wit/deps/wasi:io/streams.wit b/golem-llm/llm-openai/wit/deps/wasi:io/streams.wit similarity index 100% rename from llm-openai/wit/deps/wasi:io/streams.wit rename to golem-llm/llm-openai/wit/deps/wasi:io/streams.wit diff --git a/llm-openai/wit/deps/wasi:io/world.wit b/golem-llm/llm-openai/wit/deps/wasi:io/world.wit similarity index 100% rename from llm-openai/wit/deps/wasi:io/world.wit rename to golem-llm/llm-openai/wit/deps/wasi:io/world.wit diff --git a/llm-openai/wit/openai.wit b/golem-llm/llm-openai/wit/openai.wit similarity index 100% rename from llm-openai/wit/openai.wit rename to golem-llm/llm-openai/wit/openai.wit diff --git a/llm-openrouter/Cargo.toml b/golem-llm/llm-openrouter/Cargo.toml similarity index 100% rename from llm-openrouter/Cargo.toml rename to golem-llm/llm-openrouter/Cargo.toml diff --git a/llm-openrouter/src/bindings.rs b/golem-llm/llm-openrouter/src/bindings.rs similarity index 100% rename from llm-openrouter/src/bindings.rs rename to golem-llm/llm-openrouter/src/bindings.rs diff --git a/llm-openrouter/src/client.rs b/golem-llm/llm-openrouter/src/client.rs similarity index 100% rename from llm-openrouter/src/client.rs rename to golem-llm/llm-openrouter/src/client.rs diff --git a/llm-openrouter/src/conversions.rs b/golem-llm/llm-openrouter/src/conversions.rs similarity index 100% rename from llm-openrouter/src/conversions.rs rename to golem-llm/llm-openrouter/src/conversions.rs diff --git a/llm-openrouter/src/lib.rs b/golem-llm/llm-openrouter/src/lib.rs similarity index 100% rename from llm-openrouter/src/lib.rs rename to golem-llm/llm-openrouter/src/lib.rs diff --git a/llm-openrouter/wit/deps/golem-llm/golem-llm.wit b/golem-llm/llm-openrouter/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from llm-openrouter/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/llm-openrouter/wit/deps/golem-llm/golem-llm.wit diff --git a/llm-openrouter/wit/deps/wasi:io/error.wit b/golem-llm/llm-openrouter/wit/deps/wasi:io/error.wit similarity index 100% rename from llm-openrouter/wit/deps/wasi:io/error.wit rename to golem-llm/llm-openrouter/wit/deps/wasi:io/error.wit diff --git a/llm-openrouter/wit/deps/wasi:io/poll.wit b/golem-llm/llm-openrouter/wit/deps/wasi:io/poll.wit similarity index 100% rename from llm-openrouter/wit/deps/wasi:io/poll.wit rename to golem-llm/llm-openrouter/wit/deps/wasi:io/poll.wit diff --git a/llm-openrouter/wit/deps/wasi:io/streams.wit b/golem-llm/llm-openrouter/wit/deps/wasi:io/streams.wit similarity index 100% rename from llm-openrouter/wit/deps/wasi:io/streams.wit rename to golem-llm/llm-openrouter/wit/deps/wasi:io/streams.wit diff --git a/llm-openrouter/wit/deps/wasi:io/world.wit b/golem-llm/llm-openrouter/wit/deps/wasi:io/world.wit similarity index 100% rename from llm-openrouter/wit/deps/wasi:io/world.wit rename to golem-llm/llm-openrouter/wit/deps/wasi:io/world.wit diff --git a/llm-openrouter/wit/openrouter.wit b/golem-llm/llm-openrouter/wit/openrouter.wit similarity index 100% rename from llm-openrouter/wit/openrouter.wit rename to golem-llm/llm-openrouter/wit/openrouter.wit diff --git a/llm/Cargo.toml b/golem-llm/llm/Cargo.toml similarity index 81% rename from llm/Cargo.toml rename to golem-llm/llm/Cargo.toml index f12ada98b..c796eba28 100644 --- a/llm/Cargo.toml +++ b/golem-llm/llm/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem-llm" -description = "WebAssembly components for working with LLM APIs, with special support for Golem Cloud" +description = "WebAssembly components for working with AI models and providers APIs, with special support for Golem Cloud" [lib] path = "src/lib.rs" diff --git a/llm/src/chat_stream.rs b/golem-llm/llm/src/chat_stream.rs similarity index 100% rename from llm/src/chat_stream.rs rename to golem-llm/llm/src/chat_stream.rs diff --git a/llm/src/config.rs b/golem-llm/llm/src/config.rs similarity index 100% rename from llm/src/config.rs rename to golem-llm/llm/src/config.rs diff --git a/llm/src/durability.rs b/golem-llm/llm/src/durability.rs similarity index 100% rename from llm/src/durability.rs rename to golem-llm/llm/src/durability.rs diff --git a/llm/src/error.rs b/golem-llm/llm/src/error.rs similarity index 100% rename from llm/src/error.rs rename to golem-llm/llm/src/error.rs diff --git a/llm/src/event_source/error.rs b/golem-llm/llm/src/event_source/error.rs similarity index 100% rename from llm/src/event_source/error.rs rename to golem-llm/llm/src/event_source/error.rs diff --git a/llm/src/event_source/event_stream.rs b/golem-llm/llm/src/event_source/event_stream.rs similarity index 100% rename from llm/src/event_source/event_stream.rs rename to golem-llm/llm/src/event_source/event_stream.rs diff --git a/llm/src/event_source/message_event.rs b/golem-llm/llm/src/event_source/message_event.rs similarity index 100% rename from llm/src/event_source/message_event.rs rename to golem-llm/llm/src/event_source/message_event.rs diff --git a/llm/src/event_source/mod.rs b/golem-llm/llm/src/event_source/mod.rs similarity index 100% rename from llm/src/event_source/mod.rs rename to golem-llm/llm/src/event_source/mod.rs diff --git a/llm/src/event_source/ndjson_stream.rs b/golem-llm/llm/src/event_source/ndjson_stream.rs similarity index 100% rename from llm/src/event_source/ndjson_stream.rs rename to golem-llm/llm/src/event_source/ndjson_stream.rs diff --git a/llm/src/event_source/parser.rs b/golem-llm/llm/src/event_source/parser.rs similarity index 100% rename from llm/src/event_source/parser.rs rename to golem-llm/llm/src/event_source/parser.rs diff --git a/llm/src/event_source/stream.rs b/golem-llm/llm/src/event_source/stream.rs similarity index 100% rename from llm/src/event_source/stream.rs rename to golem-llm/llm/src/event_source/stream.rs diff --git a/llm/src/event_source/utf8_stream.rs b/golem-llm/llm/src/event_source/utf8_stream.rs similarity index 100% rename from llm/src/event_source/utf8_stream.rs rename to golem-llm/llm/src/event_source/utf8_stream.rs diff --git a/llm/src/lib.rs b/golem-llm/llm/src/lib.rs similarity index 100% rename from llm/src/lib.rs rename to golem-llm/llm/src/lib.rs diff --git a/llm/wit/deps/golem-llm/golem-llm.wit b/golem-llm/llm/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from llm/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/llm/wit/deps/golem-llm/golem-llm.wit diff --git a/llm/wit/deps/wasi:io/error.wit b/golem-llm/llm/wit/deps/wasi:io/error.wit similarity index 100% rename from llm/wit/deps/wasi:io/error.wit rename to golem-llm/llm/wit/deps/wasi:io/error.wit diff --git a/llm/wit/deps/wasi:io/poll.wit b/golem-llm/llm/wit/deps/wasi:io/poll.wit similarity index 100% rename from llm/wit/deps/wasi:io/poll.wit rename to golem-llm/llm/wit/deps/wasi:io/poll.wit diff --git a/llm/wit/deps/wasi:io/streams.wit b/golem-llm/llm/wit/deps/wasi:io/streams.wit similarity index 100% rename from llm/wit/deps/wasi:io/streams.wit rename to golem-llm/llm/wit/deps/wasi:io/streams.wit diff --git a/llm/wit/deps/wasi:io/world.wit b/golem-llm/llm/wit/deps/wasi:io/world.wit similarity index 100% rename from llm/wit/deps/wasi:io/world.wit rename to golem-llm/llm/wit/deps/wasi:io/world.wit diff --git a/llm/wit/llm.wit b/golem-llm/llm/wit/llm.wit similarity index 100% rename from llm/wit/llm.wit rename to golem-llm/llm/wit/llm.wit diff --git a/test/.gitignore b/golem-llm/test/.gitignore similarity index 100% rename from test/.gitignore rename to golem-llm/test/.gitignore diff --git a/test/.vscode/settings.json b/golem-llm/test/.vscode/settings.json similarity index 100% rename from test/.vscode/settings.json rename to golem-llm/test/.vscode/settings.json diff --git a/test/Cargo.lock b/golem-llm/test/Cargo.lock similarity index 100% rename from test/Cargo.lock rename to golem-llm/test/Cargo.lock diff --git a/test/Cargo.toml b/golem-llm/test/Cargo.toml similarity index 100% rename from test/Cargo.toml rename to golem-llm/test/Cargo.toml diff --git a/test/common-rust/common-lib/Cargo.toml b/golem-llm/test/common-rust/common-lib/Cargo.toml similarity index 100% rename from test/common-rust/common-lib/Cargo.toml rename to golem-llm/test/common-rust/common-lib/Cargo.toml diff --git a/test/common-rust/common-lib/src/lib.rs b/golem-llm/test/common-rust/common-lib/src/lib.rs similarity index 100% rename from test/common-rust/common-lib/src/lib.rs rename to golem-llm/test/common-rust/common-lib/src/lib.rs diff --git a/test/common-rust/golem.yaml b/golem-llm/test/common-rust/golem.yaml similarity index 100% rename from test/common-rust/golem.yaml rename to golem-llm/test/common-rust/golem.yaml diff --git a/test/components-rust/.gitignore b/golem-llm/test/components-rust/.gitignore similarity index 100% rename from test/components-rust/.gitignore rename to golem-llm/test/components-rust/.gitignore diff --git a/test/components-rust/test-helper/Cargo.lock b/golem-llm/test/components-rust/test-helper/Cargo.lock similarity index 100% rename from test/components-rust/test-helper/Cargo.lock rename to golem-llm/test/components-rust/test-helper/Cargo.lock diff --git a/test/components-rust/test-helper/Cargo.toml b/golem-llm/test/components-rust/test-helper/Cargo.toml similarity index 100% rename from test/components-rust/test-helper/Cargo.toml rename to golem-llm/test/components-rust/test-helper/Cargo.toml diff --git a/test/components-rust/test-helper/golem.yaml b/golem-llm/test/components-rust/test-helper/golem.yaml similarity index 100% rename from test/components-rust/test-helper/golem.yaml rename to golem-llm/test/components-rust/test-helper/golem.yaml diff --git a/test/components-rust/test-helper/src/lib.rs b/golem-llm/test/components-rust/test-helper/src/lib.rs similarity index 100% rename from test/components-rust/test-helper/src/lib.rs rename to golem-llm/test/components-rust/test-helper/src/lib.rs diff --git a/test/components-rust/test-helper/wit/test-helper.wit b/golem-llm/test/components-rust/test-helper/wit/test-helper.wit similarity index 100% rename from test/components-rust/test-helper/wit/test-helper.wit rename to golem-llm/test/components-rust/test-helper/wit/test-helper.wit diff --git a/test/components-rust/test-llm/Cargo.lock b/golem-llm/test/components-rust/test-llm/Cargo.lock similarity index 100% rename from test/components-rust/test-llm/Cargo.lock rename to golem-llm/test/components-rust/test-llm/Cargo.lock diff --git a/test/components-rust/test-llm/Cargo.toml b/golem-llm/test/components-rust/test-llm/Cargo.toml similarity index 100% rename from test/components-rust/test-llm/Cargo.toml rename to golem-llm/test/components-rust/test-llm/Cargo.toml diff --git a/test/components-rust/test-llm/golem.yaml b/golem-llm/test/components-rust/test-llm/golem.yaml similarity index 100% rename from test/components-rust/test-llm/golem.yaml rename to golem-llm/test/components-rust/test-llm/golem.yaml diff --git a/test/components-rust/test-llm/src/lib.rs b/golem-llm/test/components-rust/test-llm/src/lib.rs similarity index 100% rename from test/components-rust/test-llm/src/lib.rs rename to golem-llm/test/components-rust/test-llm/src/lib.rs diff --git a/test/components-rust/test-llm/wit/test-llm.wit b/golem-llm/test/components-rust/test-llm/wit/test-llm.wit similarity index 100% rename from test/components-rust/test-llm/wit/test-llm.wit rename to golem-llm/test/components-rust/test-llm/wit/test-llm.wit diff --git a/test/data/cat.png b/golem-llm/test/data/cat.png similarity index 100% rename from test/data/cat.png rename to golem-llm/test/data/cat.png diff --git a/test/golem.yaml b/golem-llm/test/golem.yaml similarity index 100% rename from test/golem.yaml rename to golem-llm/test/golem.yaml diff --git a/test/wit/deps/golem-llm/golem-llm.wit b/golem-llm/test/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from test/wit/deps/golem-llm/golem-llm.wit rename to golem-llm/test/wit/deps/golem-llm/golem-llm.wit diff --git a/test/wit/deps/io/error.wit b/golem-llm/test/wit/deps/io/error.wit similarity index 100% rename from test/wit/deps/io/error.wit rename to golem-llm/test/wit/deps/io/error.wit diff --git a/test/wit/deps/io/poll.wit b/golem-llm/test/wit/deps/io/poll.wit similarity index 100% rename from test/wit/deps/io/poll.wit rename to golem-llm/test/wit/deps/io/poll.wit diff --git a/test/wit/deps/io/streams.wit b/golem-llm/test/wit/deps/io/streams.wit similarity index 100% rename from test/wit/deps/io/streams.wit rename to golem-llm/test/wit/deps/io/streams.wit diff --git a/test/wit/deps/io/world.wit b/golem-llm/test/wit/deps/io/world.wit similarity index 100% rename from test/wit/deps/io/world.wit rename to golem-llm/test/wit/deps/io/world.wit diff --git a/wit/deps.lock b/golem-llm/wit/deps.lock similarity index 100% rename from wit/deps.lock rename to golem-llm/wit/deps.lock diff --git a/wit/deps.toml b/golem-llm/wit/deps.toml similarity index 100% rename from wit/deps.toml rename to golem-llm/wit/deps.toml diff --git a/wit/deps/wasi:io/error.wit b/golem-llm/wit/deps/wasi:io/error.wit similarity index 100% rename from wit/deps/wasi:io/error.wit rename to golem-llm/wit/deps/wasi:io/error.wit diff --git a/wit/deps/wasi:io/poll.wit b/golem-llm/wit/deps/wasi:io/poll.wit similarity index 100% rename from wit/deps/wasi:io/poll.wit rename to golem-llm/wit/deps/wasi:io/poll.wit diff --git a/wit/deps/wasi:io/streams.wit b/golem-llm/wit/deps/wasi:io/streams.wit similarity index 100% rename from wit/deps/wasi:io/streams.wit rename to golem-llm/wit/deps/wasi:io/streams.wit diff --git a/wit/deps/wasi:io/world.wit b/golem-llm/wit/deps/wasi:io/world.wit similarity index 100% rename from wit/deps/wasi:io/world.wit rename to golem-llm/wit/deps/wasi:io/world.wit diff --git a/wit/golem-llm.wit b/golem-llm/wit/golem-llm.wit similarity index 100% rename from wit/golem-llm.wit rename to golem-llm/wit/golem-llm.wit From 4d0ed2570f69b74d6bc7e6896d843f01a1856408 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 28 May 2025 21:28:46 +0000 Subject: [PATCH 02/36] ci fix --- Makefile.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.toml b/Makefile.toml index ceef9d283..710e4cd8e 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -310,7 +310,7 @@ args = [ ] [tasks.build-llm-test-components] -dependencies = ["build"] +dependencies = ["build-llm"] description = "Builds all test components with golem-cli" install_crate = "cargo-binstall" script = ''' From e358a21811a7889c92d0e003d3aacf81bcb53b17 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Thu, 29 May 2025 08:54:24 +0000 Subject: [PATCH 03/36] CI fixes --- .github/workflows/ci.yaml | 12 ++++++------ README.md => golem-llm/README.md | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename README.md => golem-llm/README.md (100%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5985d7936..e7b41e9bc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -115,13 +115,13 @@ jobs: set -e docker run -d --name ollama -p 11434:11434 ollama/ollama:latest timeout 60 bash -c 'until curl -f http://localhost:11434/api/version; do sleep 2; done' - echo "Pulling Qwen2.5:1.5b" - docker exec ollama ollama pull qwen2.5:1.5b - echo "Pulling Gemma2:2b" - docker exec ollama ollama pull gemma2:2b + echo "Pulling qwen3:1.7b" + docker exec ollama ollama pull qwen3:1.7b + echo "Pulling gemma3:4b" + docker exec ollama ollama pull gemma3:4b echo "Verifying models are available" - docker exec ollama ollama list | grep -q "qwen2.5:1.5b" || exit 1 - docker exec ollama ollama list | grep -q "gemma2:2b" || exit 1 + docker exec ollama ollama list | grep -q "qwen3:1.7b" || exit 1 + docker exec ollama ollama list | grep -q "gemma3:4b" || exit 1 echo "Ollama setup completed." - name: Install and Run latest Golem Server run: | diff --git a/README.md b/golem-llm/README.md similarity index 100% rename from README.md rename to golem-llm/README.md From e78d6adb74e22fadfe69fa8fb2b952b317cc7c1c Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 30 May 2025 19:46:58 +0000 Subject: [PATCH 04/36] added embed --- golem-embed/embed/Cargo.toml | 26 ++ golem-embed/embed/src/config.rs | 22 ++ golem-embed/embed/src/error.rs | 45 +++ golem-embed/embed/src/lib.rs | 42 +++ golem-embed/embed/wit/deps.lock | 4 + .../wit/deps/golem-embed/golem-embed.wit | 125 ++++++++ golem-embed/embed/wit/deps/wasi:io/error.wit | 34 ++ golem-embed/embed/wit/deps/wasi:io/poll.wit | 47 +++ .../embed/wit/deps/wasi:io/streams.wit | 290 ++++++++++++++++++ golem-embed/embed/wit/deps/wasi:io/world.wit | 10 + golem-embed/embed/wit/embed.wit | 5 + golem-embed/wit/deps.lock | 4 + golem-embed/wit/deps.toml | 1 + golem-embed/wit/deps/wasi:io/error.wit | 34 ++ golem-embed/wit/deps/wasi:io/poll.wit | 47 +++ golem-embed/wit/deps/wasi:io/streams.wit | 290 ++++++++++++++++++ golem-embed/wit/deps/wasi:io/world.wit | 10 + golem-embed/wit/golem-embed.wit | 124 ++++++++ 18 files changed, 1160 insertions(+) create mode 100644 golem-embed/embed/Cargo.toml create mode 100644 golem-embed/embed/src/config.rs create mode 100644 golem-embed/embed/src/error.rs create mode 100644 golem-embed/embed/src/lib.rs create mode 100644 golem-embed/embed/wit/deps.lock create mode 100644 golem-embed/embed/wit/deps/golem-embed/golem-embed.wit create mode 100644 golem-embed/embed/wit/deps/wasi:io/error.wit create mode 100644 golem-embed/embed/wit/deps/wasi:io/poll.wit create mode 100644 golem-embed/embed/wit/deps/wasi:io/streams.wit create mode 100644 golem-embed/embed/wit/deps/wasi:io/world.wit create mode 100644 golem-embed/embed/wit/embed.wit create mode 100644 golem-embed/wit/deps.lock create mode 100644 golem-embed/wit/deps.toml create mode 100644 golem-embed/wit/deps/wasi:io/error.wit create mode 100644 golem-embed/wit/deps/wasi:io/poll.wit create mode 100644 golem-embed/wit/deps/wasi:io/streams.wit create mode 100644 golem-embed/wit/deps/wasi:io/world.wit create mode 100644 golem-embed/wit/golem-embed.wit diff --git a/golem-embed/embed/Cargo.toml b/golem-embed/embed/Cargo.toml new file mode 100644 index 000000000..b1864f279 --- /dev/null +++ b/golem-embed/embed/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "golem-embed" +version = "0.0.0" +edition = "2021" +license = "Apache-2.0" +homepage = "https://golem.cloud" +repository = "https://github.com/golemcloud/golem-llm" +description = "WebAssembly components for working with AI models and providers APIs, with special support for Golem Cloud" + +[lib] +path = "src/lib.rs" +crate-type = ["rlib"] + +[dependencies] +golem-rust = { workspace = true } +log = { workspace = true } +mime = "0.3.17" +nom = { version = "7.1", default-features = false } +reqwest = { workspace = true } +thiserror = "2.0.12" +wasi-logger = "0.1.2" +wit-bindgen = { version = "0.40.0" } + +[features] +default = ["durability"] +durability = ["golem-rust/durability"] diff --git a/golem-embed/embed/src/config.rs b/golem-embed/embed/src/config.rs new file mode 100644 index 000000000..252703aef --- /dev/null +++ b/golem-embed/embed/src/config.rs @@ -0,0 +1,22 @@ + +use crate::golem::embed::embed::{Error, ErrorCode}; +use std::ffi::OsStr; + +pub fn with_config_key( + key: impl AsRef, + fail: impl FnOnce(Error) -> R, + succeed: impl FnOnce(String) -> R, +) -> R { + let key_str = key.as_ref().to_string_lossy().to_string(); + match std::env::var(key) { + Ok(value) => succeed(value), + Err(_) => { + let error = Error { + code: ErrorCode::AuthenticationFailed, + message: format!("Missing config key: {key_str}"), + provider_error_json: None, + }; + fail(error) + } + } +} diff --git a/golem-embed/embed/src/error.rs b/golem-embed/embed/src/error.rs new file mode 100644 index 000000000..c0651e3d8 --- /dev/null +++ b/golem-embed/embed/src/error.rs @@ -0,0 +1,45 @@ +use crate::golem::embed::embed::{Error, ErrorCode}; +use reqwest::StatusCode; + + + + +pub fn unsupported(what: impl AsRef) -> Error { + Error { + code: ErrorCode::Unsupported, + message: format!("Unsupported: {}", what.as_ref()), + provider_error_json: None, + } +} + +pub fn model_not_found(model: impl AsRef) -> Error { + Error { + code: ErrorCode::ModelNotFound, + message: format!("Model not found: {}", model.as_ref()), + provider_error_json: None, + } +} + + +pub fn from_reqwest_error(details: impl AsRef, err: reqwest::Error) -> Error { + Error { + code: ErrorCode::InternalError, + message: format!("{}: {err}", details.as_ref()), + provider_error_json: None, + } +} + + pub fn error_code_from_status(status: StatusCode) -> ErrorCode { + if status == StatusCode::TOO_MANY_REQUESTS { + ErrorCode::RateLimitExceeded + } else if status == StatusCode::UNAUTHORIZED + || status == StatusCode::FORBIDDEN + || status == StatusCode::PAYMENT_REQUIRED + { + ErrorCode::AuthenticationFailed + } else if status.is_client_error() { + ErrorCode::InvalidRequest + } else { + ErrorCode::InternalError + } +} diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs new file mode 100644 index 000000000..61fc4fadb --- /dev/null +++ b/golem-embed/embed/src/lib.rs @@ -0,0 +1,42 @@ +pub mod error; +pub mod config; + +wit_bindgen::generate!({ + path: "./wit", + world: "embed-library", + generate_all, + generate_unused_types: true, + additional_derives: [PartialEq, golem_rust::FromValueAndType, golem_rust::IntoValue], + pub_export_macro: true, +}); + +pub use crate::exports::golem; +pub use __export_embed_library_impl as export_embed; +use exports::golem::embed::embed::{ Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}; +use std::cell::RefCell; +use std::str::FromStr; + +pub struct LoggingState { + logging_initialized: bool, +} + +impl LoggingState { + /// Initializes WASI logging based on the `GOLEM_LLM_LOG` environment variable. + pub fn init(&mut self) { + if !self.logging_initialized { + let _ = wasi_logger::Logger::install(); + let max_level: log::LevelFilter = + log::LevelFilter::from_str(&std::env::var("GOLEM_LLM_LOG").unwrap_or_default()) + .unwrap_or(log::LevelFilter::Info); + log::set_max_level(max_level); + self.logging_initialized = true; + } + } +} + +thread_local! { + /// This holds the state of our application. + pub static LOGGING_STATE: RefCell = const { RefCell::new(LoggingState { + logging_initialized: false, + }) }; +} diff --git a/golem-embed/embed/wit/deps.lock b/golem-embed/embed/wit/deps.lock new file mode 100644 index 000000000..adc795b3a --- /dev/null +++ b/golem-embed/embed/wit/deps.lock @@ -0,0 +1,4 @@ +["wasi:io"] +url = "https://github.com/WebAssembly/wasi-io/archive/v0.2.3.tar.gz" +sha256 = "1cccbfe4122686ea57a25cd368e8cdfc408cbcad089f47fb6685b6f92e96f050" +sha512 = "7a95f964c13da52611141acd89bc8876226497f128e99dd176a4270c5b5efbd8cc847b5fbd1a91258d028c646db99e0424d72590cf1caf20f9f3a3343fad5017" diff --git a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..056c95107 --- /dev/null +++ b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,125 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float32, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} \ No newline at end of file diff --git a/golem-embed/embed/wit/deps/wasi:io/error.wit b/golem-embed/embed/wit/deps/wasi:io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/embed/wit/deps/wasi:io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/embed/wit/deps/wasi:io/poll.wit b/golem-embed/embed/wit/deps/wasi:io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/embed/wit/deps/wasi:io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/embed/wit/deps/wasi:io/streams.wit b/golem-embed/embed/wit/deps/wasi:io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/embed/wit/deps/wasi:io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/embed/wit/deps/wasi:io/world.wit b/golem-embed/embed/wit/deps/wasi:io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/embed/wit/deps/wasi:io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/embed/wit/embed.wit b/golem-embed/embed/wit/embed.wit new file mode 100644 index 000000000..3e697a31f --- /dev/null +++ b/golem-embed/embed/wit/embed.wit @@ -0,0 +1,5 @@ +package golem:embed-library@1.0.0; + +world embed-library { + export golem:embed/embed@1.0.0; +} diff --git a/golem-embed/wit/deps.lock b/golem-embed/wit/deps.lock new file mode 100644 index 000000000..adc795b3a --- /dev/null +++ b/golem-embed/wit/deps.lock @@ -0,0 +1,4 @@ +["wasi:io"] +url = "https://github.com/WebAssembly/wasi-io/archive/v0.2.3.tar.gz" +sha256 = "1cccbfe4122686ea57a25cd368e8cdfc408cbcad089f47fb6685b6f92e96f050" +sha512 = "7a95f964c13da52611141acd89bc8876226497f128e99dd176a4270c5b5efbd8cc847b5fbd1a91258d028c646db99e0424d72590cf1caf20f9f3a3343fad5017" diff --git a/golem-embed/wit/deps.toml b/golem-embed/wit/deps.toml new file mode 100644 index 000000000..15e1ae691 --- /dev/null +++ b/golem-embed/wit/deps.toml @@ -0,0 +1 @@ +"wasi:io" = "https://github.com/WebAssembly/wasi-io/archive/v0.2.3.tar.gz" diff --git a/golem-embed/wit/deps/wasi:io/error.wit b/golem-embed/wit/deps/wasi:io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/wit/deps/wasi:io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/wit/deps/wasi:io/poll.wit b/golem-embed/wit/deps/wasi:io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/wit/deps/wasi:io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/wit/deps/wasi:io/streams.wit b/golem-embed/wit/deps/wasi:io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/wit/deps/wasi:io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/wit/deps/wasi:io/world.wit b/golem-embed/wit/deps/wasi:io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/wit/deps/wasi:io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/wit/golem-embed.wit b/golem-embed/wit/golem-embed.wit new file mode 100644 index 000000000..2b9073b88 --- /dev/null +++ b/golem-embed/wit/golem-embed.wit @@ -0,0 +1,124 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float32, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} \ No newline at end of file From 3fc5f4847b055c034c74a89afb67d486c5281469 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 30 May 2025 19:49:53 +0000 Subject: [PATCH 05/36] openai client generate embedings --- Cargo.lock | 28 ++ Cargo.toml | 2 +- golem-embed/embed-openai/Cargo.toml | 45 +++ golem-embed/embed-openai/src/bindings.rs | 109 +++++++ golem-embed/embed-openai/src/client.rs | 153 +++++++++ golem-embed/embed-openai/src/conversions.rs | 0 golem-embed/embed-openai/src/lib.rs | 19 ++ .../wit/deps/golem-embed/golem-embed.wit | 125 ++++++++ .../embed-openai/wit/deps/wasi:io/error.wit | 34 ++ .../embed-openai/wit/deps/wasi:io/poll.wit | 47 +++ .../embed-openai/wit/deps/wasi:io/streams.wit | 290 ++++++++++++++++++ .../embed-openai/wit/deps/wasi:io/world.wit | 10 + golem-embed/embed-openai/wit/world.wit | 5 + 13 files changed, 866 insertions(+), 1 deletion(-) create mode 100644 golem-embed/embed-openai/Cargo.toml create mode 100644 golem-embed/embed-openai/src/bindings.rs create mode 100644 golem-embed/embed-openai/src/client.rs create mode 100644 golem-embed/embed-openai/src/conversions.rs create mode 100644 golem-embed/embed-openai/src/lib.rs create mode 100644 golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit create mode 100644 golem-embed/embed-openai/wit/deps/wasi:io/error.wit create mode 100644 golem-embed/embed-openai/wit/deps/wasi:io/poll.wit create mode 100644 golem-embed/embed-openai/wit/deps/wasi:io/streams.wit create mode 100644 golem-embed/embed-openai/wit/deps/wasi:io/world.wit create mode 100644 golem-embed/embed-openai/wit/world.wit diff --git a/Cargo.lock b/Cargo.lock index 0865d6ade..052857cc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,6 +332,34 @@ dependencies = [ "syn", ] +[[package]] +name = "golem-embed" +version = "0.0.0" +dependencies = [ + "golem-rust", + "log", + "mime", + "nom", + "reqwest", + "thiserror", + "wasi-logger", + "wit-bindgen 0.40.0", +] + +[[package]] +name = "golem-embed-openai" +version = "0.0.0" +dependencies = [ + "base64 0.22.1", + "golem-embed", + "golem-rust", + "log", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + [[package]] name = "golem-llm" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index fd4cf28ce..86dc19ce0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] resolver = "2" -members = [ "golem-llm/llm", "golem-llm/llm-anthropic", "golem-llm/llm-grok", "golem-llm/llm-ollama", "golem-llm/llm-openai", "golem-llm/llm-openrouter"] +members = [ "golem-embed/embed", "golem-embed/embed-openai", "golem-llm/llm", "golem-llm/llm-anthropic", "golem-llm/llm-grok", "golem-llm/llm-ollama", "golem-llm/llm-openai", "golem-llm/llm-openrouter"] [profile.release] debug = false diff --git a/golem-embed/embed-openai/Cargo.toml b/golem-embed/embed-openai/Cargo.toml new file mode 100644 index 000000000..d00412d0e --- /dev/null +++ b/golem-embed/embed-openai/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "golem-embed-openai" +version = "0.0.0" +edition = "2021" +license = "Apache-2.0" +homepage = "https://golem.cloud" +repository = "https://github.com/golemcloud/golem-llm" +description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" + + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["durability"] +durability = ["golem-rust/durability", "golem-embed/durability"] + + +[dependencies] +golem-embed= {path="../embed", version="0.0.0", default-features= false} +golem-rust = { workspace = true } +log = { workspace = true } +reqwest = { workspace = true } +serde = {workspace = true} +base64 = { workspace = true } +serde_json = { workspace = true } +wit-bindgen-rt = { workspace = true } + + +[package.metadata.component] +package="golem:embed-openai" + +[package.metadata.component.bindings] +generate_unused_types=true + +[package.metadata.component.bindings.with] +"golem:embed/embed@1.0.0"= "golem_embed::golem::embed::embed" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.target.dependencies] +"golem:embed" = { path = "wit/deps/golem-embed" } +"wasi:io" = { path = "wit/deps/wasi:io"} diff --git a/golem-embed/embed-openai/src/bindings.rs b/golem-embed/embed-openai/src/bindings.rs new file mode 100644 index 000000000..c2eebfb65 --- /dev/null +++ b/golem-embed/embed-openai/src/bindings.rs @@ -0,0 +1,109 @@ +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! +// Options used: +// * runtime_path: "wit_bindgen_rt" +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn _export_hello_world_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::hello_world(); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn __post_return_hello_world(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(::core::mem::size_of::<*const u8>()).cast::(); + _rt::cabi_dealloc(l0, l1, 1); +} +pub trait Guest { + fn hello_world() -> _rt::String; +} +#[doc(hidden)] +macro_rules! __export_world_example_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = "hello-world")] unsafe extern "C" fn + export_hello_world() -> * mut u8 { unsafe { $($path_to_types)*:: + _export_hello_world_cabi::<$ty > () } } #[unsafe (export_name = + "cabi_post_hello-world")] unsafe extern "C" fn _post_return_hello_world(arg0 : * + mut u8,) { unsafe { $($path_to_types)*:: __post_return_hello_world::<$ty > (arg0) + } } }; + }; +} +#[doc(hidden)] +pub(crate) use __export_world_example_cabi; +#[cfg_attr(target_pointer_width = "64", repr(align(8)))] +#[cfg_attr(target_pointer_width = "32", repr(align(4)))] +struct _RetArea([::core::mem::MaybeUninit; 2 * ::core::mem::size_of::<*const u8>()]); +static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 2 * ::core::mem::size_of::<*const u8>()], +); +#[rustfmt::skip] +mod _rt { + #![allow(dead_code, clippy::all)] + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr, layout); + } + pub use alloc_crate::string::String; + pub use alloc_crate::alloc; + extern crate alloc as alloc_crate; +} +/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as +/// the root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] +macro_rules! __export_example_impl { + ($ty:ident) => { + self::export!($ty with_types_in self); + }; + ($ty:ident with_types_in $($path_to_types_root:tt)*) => { + $($path_to_types_root)*:: __export_world_example_cabi!($ty with_types_in + $($path_to_types_root)*); + }; +} +#[doc(inline)] +pub(crate) use __export_example_impl as export; +#[cfg(target_arch = "wasm32")] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:component:embed-openai:example:encoded world" +)] +#[doc(hidden)] +#[allow(clippy::octal_escapes)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 187] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07>\x01A\x02\x01A\x02\x01\ +@\0\0s\x04\0\x0bhello-world\x01\0\x04\0\x1ecomponent:embed-openai/example\x04\0\x0b\ +\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-com\ +ponent\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +#[inline(never)] +#[doc(hidden)] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs new file mode 100644 index 000000000..29f1598a0 --- /dev/null +++ b/golem-embed/embed-openai/src/client.rs @@ -0,0 +1,153 @@ +use std::fmt::Debug; + +use golem_embed::{ + error::{error_code_from_status, from_reqwest_error}, + golem::embed::embed::Error, +}; +use log::trace; +#[allow(dead_code, unused, unused_imports)] +use reqwest::Client; +use reqwest::{Method, Response}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +const BASE_URL: &str = "https://api.openai.com"; + +/// The OpenAI API client for creating embeddings. +/// +/// Based on https://platform.openai.com/docs/api-reference/embeddings/create +pub struct EmbeddingsApi { + openai_api_key: String, + client: reqwest::Client, +} + +/// OpenAI allows only allows float and base64 as output formats. +#[derive(Debug, Deserialize, Serialize, Clone)] +pub enum EncodingFormat { + Float, + Base64, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct EmbeddingRequest { + pub input: String, + pub model: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub encoding_format: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub dimension: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingResponse { + pub object: String, + pub data: Vec, + pub model: String, + pub usage: EmbeddingUsage, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingUsage { + pub prompt_tokens: u32, + pub total_tokens: u32, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingData { + pub object: String, + pub embedding: EmbeddingVector, + pub index: usize, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum EmbeddingVector { + FloatArray(Vec), + Base64(String), +} + +impl EmbeddingVector { + pub fn to_float_vec(&self) -> Result, String> { + match self { + EmbeddingVector::FloatArray(vec) => Ok(vec.clone()), + EmbeddingVector::Base64(base64_str) => { + use base64::{engine::general_purpose, Engine}; + + let bytes = general_purpose::STANDARD + .decode(base64_str) + .map_err(|e| format!("Failed to decode base64: {}", e))?; + + if bytes.len() % 4 != 0 { + return Err("Invalid base64 data: length not divisible by 4".to_string()); + } + + let mut floats: Vec = Vec::with_capacity(bytes.len() / 4); + for chunk in bytes.chunks_exact(4) { + floats.push(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])); + } + + Ok(floats) + } + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct OpenAIError { + pub error: OpenAIErrorDetails, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct OpenAIErrorDetails { + pub message: String, + #[serde(rename = "type")] + pub _type: String, + pub param: Option, + pub code: Option, +} + +impl EmbeddingsApi { + pub fn new(openai_api_key: String) -> Self { + let client = Client::builder() + .build() + .expect("Failed to initialize HTTP client"); + Self { + openai_api_key, + client, + } + } + + pub fn generate_embeding(&self, request: EmbeddingRequest) -> Result { + trace!("Sending request to OpenAI API: {request:?}"); + let response = self + .client + .request(Method::POST, format!("{BASE_URL}/v1/embeddings")) + .bearer_auth(&self.openai_api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Request failed", err))?; + parse_response(response) + } +} + +fn parse_response(response: Response) -> Result { + let status = response.status(); + if status.is_success() { + let response_data = response + .json::() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from OpenAI Embeddings API: {response_data:?}"); + Ok(response_data) + } else { + let response_data = response + .text() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from OpenAI Embeddings API: {response_data:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Request failed with {status}"), + provider_error_json: Some(response_data), + }) + } +} diff --git a/golem-embed/embed-openai/src/conversions.rs b/golem-embed/embed-openai/src/conversions.rs new file mode 100644 index 000000000..e69de29bb diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs new file mode 100644 index 000000000..614e57f24 --- /dev/null +++ b/golem-embed/embed-openai/src/lib.rs @@ -0,0 +1,19 @@ +mod client; +mod conversions; + + +#[allow(warnings)] +mod bindings; + +use bindings::Guest; + +struct Component; + +impl Guest for Component { + /// Say hello! + fn hello_world() -> String { + "Hello, World!".to_string() + } +} + +bindings::export!(Component with_types_in bindings); diff --git a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..056c95107 --- /dev/null +++ b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,125 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float32, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} \ No newline at end of file diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/error.wit b/golem-embed/embed-openai/wit/deps/wasi:io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/embed-openai/wit/deps/wasi:io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/poll.wit b/golem-embed/embed-openai/wit/deps/wasi:io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/embed-openai/wit/deps/wasi:io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/streams.wit b/golem-embed/embed-openai/wit/deps/wasi:io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/embed-openai/wit/deps/wasi:io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/world.wit b/golem-embed/embed-openai/wit/deps/wasi:io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/embed-openai/wit/deps/wasi:io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/embed-openai/wit/world.wit b/golem-embed/embed-openai/wit/world.wit new file mode 100644 index 000000000..98ec1f9f8 --- /dev/null +++ b/golem-embed/embed-openai/wit/world.wit @@ -0,0 +1,5 @@ +package golem:embed-openapi@1.0.0; + +world embed-library { + include golem:embed/embed-library@1.0.0; +} From 18bcc0a049afaff25f0f3634ea2d5a1bb807b20e Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 1 Jun 2025 10:51:07 +0000 Subject: [PATCH 06/36] wip --- Cargo.lock | 7 + Cargo.toml | 11 +- golem-embed/Makefile.toml | 208 ++++++++++++++++ golem-embed/embed-openai/Cargo.toml | 1 + golem-embed/embed-openai/src/bindings.rs | 126 +++------- golem-embed/embed-openai/src/client.rs | 147 ++++++------ golem-embed/embed-openai/src/conversions.rs | 78 ++++++ golem-embed/embed-openai/src/lib.rs | 54 ++++- golem-embed/embed-openai/wit/openai.wit | 5 + golem-embed/embed-openai/wit/world.wit | 5 - golem-embed/embed/src/lib.rs | 2 +- golem-embed/embed/wit/deps.lock | 4 - golem-embed/embed/wit/embed.wit | 2 +- Makefile.toml => golem-llm/Makefile.toml | 253 +++++++++----------- 14 files changed, 578 insertions(+), 325 deletions(-) create mode 100644 golem-embed/Makefile.toml create mode 100644 golem-embed/embed-openai/wit/openai.wit delete mode 100644 golem-embed/embed-openai/wit/world.wit delete mode 100644 golem-embed/embed/wit/deps.lock rename Makefile.toml => golem-llm/Makefile.toml (58%) diff --git a/Cargo.lock b/Cargo.lock index 052857cc8..8652cec06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,12 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +[[package]] +name = "bytemuck" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" + [[package]] name = "bytes" version = "1.10.1" @@ -351,6 +357,7 @@ name = "golem-embed-openai" version = "0.0.0" dependencies = [ "base64 0.22.1", + "bytemuck", "golem-embed", "golem-rust", "log", diff --git a/Cargo.toml b/Cargo.toml index 86dc19ce0..c78cb8917 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,16 @@ [workspace] resolver = "2" -members = [ "golem-embed/embed", "golem-embed/embed-openai", "golem-llm/llm", "golem-llm/llm-anthropic", "golem-llm/llm-grok", "golem-llm/llm-ollama", "golem-llm/llm-openai", "golem-llm/llm-openrouter"] +members = [ + "golem-embed/embed", + "golem-embed/embed-openai", + "golem-llm/llm", + "golem-llm/llm-anthropic", + "golem-llm/llm-grok", + "golem-llm/llm-ollama", + "golem-llm/llm-openai", + "golem-llm/llm-openrouter" +] [profile.release] debug = false diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml new file mode 100644 index 000000000..0b5313ba5 --- /dev/null +++ b/golem-embed/Makefile.toml @@ -0,0 +1,208 @@ +[config] +default_to_workspace = false +skip_core_tasks = true + +[tasks.clean] +command = "cargo" +args = ["clean"] + +[tasks.unit-tests] +command = "cargo" +args = ["test"] + +[tasks.build-openai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai"] + +[tasks.build-openai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai", "--no-default-features"] + +[tasks.build] +dependencies = [ + "build-openai", +] + +[tasks.build-portable] +dependencies = [ + "build-openai-portable", +] + +[tasks.build-all] +script_runner = "@duckscript" +script = ''' +mkdir components/debug + +cm_run_task clean +cm_run_task build + +cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/embed/debug/golem_llm_openai.wasm + +cm_run_task clean +cm_run_task build-portable + +cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/embed/debug/golem_llm_openai-portable.wasm +''' + +[tasks.release-build-openai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai", "--release"] + +[tasks.release-build-openai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai", "--release", "--no-default-features"] + +[tasks.release-build] +dependencies = [ + "release-build-openai", +] + +[tasks.release-build-portable] +dependencies = [ + "release-build-openai-portable", +] + +[tasks.release-build-all] +script_runner = "@duckscript" +script = ''' +mkdir components/release + +cm_run_task set-version + +cm_run_task clean +cm_run_task release-build + +cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/embed/release/golem_llm_openai.wasm + +cm_run_task clean +cm_run_task release-build-portable + +cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/embed/release/golem_llm_openai-portable.wasm +''' + +[tasks.wit-update] +install_crate = { crate_name = "wit-deps-cli" } +command = "wit-deps" +args = ["update"] + +[tasks.wit] +dependencies = ["wit-update"] + +#condition = { files_modified = { input = [ +# "wit/golem-llm.wit", +# "wit/deps/wasi:io", +#], output = [ +# "llm/wit/deps/golem-llm/golem-llm.wit", +# "llm-anthropic/wit/deps/golem-llm/golem-llm.wit", +# "llm-grok/wit/deps/golem-llm/golem-llm.wit", +# "llm-openai/wit/deps/golem-llm/golem-llm.wit", +# "llm-openrouter/wit/deps/golem-llm/golem-llm.wit", +#] } } + +script_runner = "@duckscript" +script = """ +rm -r embed/wit/deps +mkdir embed/wit/deps/golem-embed +cp wit/golem-embed.wit embed/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io embed/wit/deps + +rm -r embed-openai/wit/deps +mkdir embed-openai/wit/deps/golem-embed +cp wit/golem-embed.wit embed-openai/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io embed-openai/wit/deps + + +rm -r test/wit +mkdir test/wit/deps/golem-embed +mkdir test/wit/deps/io +cp wit/golem-embed.wit test/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io/error.wit test/wit/deps/io/error.wit +cp wit/deps/wasi:io/poll.wit test/wit/deps/io/poll.wit +cp wit/deps/wasi:io/streams.wit test/wit/deps/io/streams.wit +cp wit/deps/wasi:io/world.wit test/wit/deps/io/world.wit +""" + +[tasks.check] +description = "Runs rustfmt and clippy checks without applying any fix" +dependencies = ["check-clippy", "check-rustfmt"] + +[tasks.check-rustfmt] +description = "Runs rustfmt checks without applying any fix" +install_crate = "rustfmt" +command = "cargo" +args = ["fmt", "--all", "--", "--check"] + +[tasks.check-clippy] +description = "Runs clippy checks without applying any fix" +install_crate = "clippy" +command = "cargo" +args = ["clippy", "--all-targets", "--", "--no-deps", "-Dwarnings"] + +[tasks.fix] +description = "Runs rustfmt and clippy checks and applies fixes" +dependencies = ["wit", "fix-clippy", "fix-rustfmt"] + +[tasks.fix-rustfmt] +description = "Runs rustfmt checks and applies fixes" +install_crate = "rustfmt" +command = "cargo" +args = ["fmt", "--all"] + +[tasks.fix-clippy] +description = "Runs clippy checks and applies fixes" +install_crate = "clippy" +command = "cargo" +args = [ + "clippy", + "--fix", + "--allow-dirty", + "--allow-staged", + "--", + "--no-deps", + "-Dwarnings", +] + +[tasks.build-test-components] +dependencies = ["build"] +description = "Builds all test components with golem-cli" +install_crate = "cargo-binstall" +script = ''' +cargo-binstall golem-cli@1.2.2-dev.11 --locked --force --no-confirm +cargo-binstall wac-cli --locked --force --no-confirm +cd test +golem-cli --version +golem-cli app clean +golem-cli app build -b openai-debug +''' + + +[tasks.set-version] +description = "Sets the version in all Cargo.toml files to the value of the VERSION environment variable" +condition = { env_set = ["VERSION"] } +script = ''' +grep -rl --include 'Cargo.toml' '0\.0\.0' | xargs sed -i "s/0\.0\.0/${VERSION}/g" +''' + +[tasks.set-version.mac] +condition = { env_set = ["VERSION"] } +script = ''' +grep -rl --include '.*Cargo\.toml' '0\.0\.0' | xargs sed -i "" "s/0\.0\.0/${VERSION}/g" +''' + +[tasks.set-version.windows] +script_runner = "powershell" +script_extension = "ps1" +condition = { env_set = ["VERSION"] } +script = ''' +$cargoFiles = Get-ChildItem . Cargo.toml -rec +foreach ($file in $cargoFiles) +{ + (Get-Content $file.PSPath) | + Foreach-Object { $_ -replace "0.0.0", $Env:VERSION } | + Set-Content $file.PSPath +} +''' \ No newline at end of file diff --git a/golem-embed/embed-openai/Cargo.toml b/golem-embed/embed-openai/Cargo.toml index d00412d0e..35f261423 100644 --- a/golem-embed/embed-openai/Cargo.toml +++ b/golem-embed/embed-openai/Cargo.toml @@ -26,6 +26,7 @@ serde = {workspace = true} base64 = { workspace = true } serde_json = { workspace = true } wit-bindgen-rt = { workspace = true } +bytemuck = "1.23.0" [package.metadata.component] diff --git a/golem-embed/embed-openai/src/bindings.rs b/golem-embed/embed-openai/src/bindings.rs index c2eebfb65..44c5fb5c1 100644 --- a/golem-embed/embed-openai/src/bindings.rs +++ b/golem-embed/embed-openai/src/bindings.rs @@ -1,107 +1,41 @@ // Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" -#[doc(hidden)] -#[allow(non_snake_case)] -pub unsafe fn _export_hello_world_cabi() -> *mut u8 { - #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); - let result0 = T::hello_world(); - let ptr1 = (&raw mut _RET_AREA.0).cast::(); - let vec2 = (result0.into_bytes()).into_boxed_slice(); - let ptr2 = vec2.as_ptr().cast::(); - let len2 = vec2.len(); - ::core::mem::forget(vec2); - *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; - *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); - ptr1 -} -#[doc(hidden)] -#[allow(non_snake_case)] -pub unsafe fn __post_return_hello_world(arg0: *mut u8) { - let l0 = *arg0.add(0).cast::<*mut u8>(); - let l1 = *arg0.add(::core::mem::size_of::<*const u8>()).cast::(); - _rt::cabi_dealloc(l0, l1, 1); -} -pub trait Guest { - fn hello_world() -> _rt::String; -} -#[doc(hidden)] -macro_rules! __export_world_example_cabi { - ($ty:ident with_types_in $($path_to_types:tt)*) => { - const _ : () = { #[unsafe (export_name = "hello-world")] unsafe extern "C" fn - export_hello_world() -> * mut u8 { unsafe { $($path_to_types)*:: - _export_hello_world_cabi::<$ty > () } } #[unsafe (export_name = - "cabi_post_hello-world")] unsafe extern "C" fn _post_return_hello_world(arg0 : * - mut u8,) { unsafe { $($path_to_types)*:: __post_return_hello_world::<$ty > (arg0) - } } }; - }; -} -#[doc(hidden)] -pub(crate) use __export_world_example_cabi; -#[cfg_attr(target_pointer_width = "64", repr(align(8)))] -#[cfg_attr(target_pointer_width = "32", repr(align(4)))] -struct _RetArea([::core::mem::MaybeUninit; 2 * ::core::mem::size_of::<*const u8>()]); -static mut _RET_AREA: _RetArea = _RetArea( - [::core::mem::MaybeUninit::uninit(); 2 * ::core::mem::size_of::<*const u8>()], -); -#[rustfmt::skip] -mod _rt { - #![allow(dead_code, clippy::all)] - #[cfg(target_arch = "wasm32")] - pub fn run_ctors_once() { - wit_bindgen_rt::run_ctors_once(); - } - pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { - if size == 0 { - return; - } - let layout = alloc::Layout::from_size_align_unchecked(size, align); - alloc::dealloc(ptr, layout); - } - pub use alloc_crate::string::String; - pub use alloc_crate::alloc; - extern crate alloc as alloc_crate; -} -/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as -/// the root implementation of all generated traits. -/// -/// For more information see the documentation of `wit_bindgen::generate!`. -/// -/// ```rust -/// # macro_rules! export{ ($($t:tt)*) => (); } -/// # trait Guest {} -/// struct MyType; -/// -/// impl Guest for MyType { -/// // ... -/// } -/// -/// export!(MyType); -/// ``` -#[allow(unused_macros)] -#[doc(hidden)] -macro_rules! __export_example_impl { - ($ty:ident) => { - self::export!($ty with_types_in self); - }; - ($ty:ident with_types_in $($path_to_types_root:tt)*) => { - $($path_to_types_root)*:: __export_world_example_cabi!($ty with_types_in - $($path_to_types_root)*); - }; -} -#[doc(inline)] -pub(crate) use __export_example_impl as export; +// * with "golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" +// * generate_unused_types +use golem_embed::golem::embed::embed as __with_name0; #[cfg(target_arch = "wasm32")] #[unsafe( - link_section = "component-type:wit-bindgen:0.41.0:component:embed-openai:example:encoded world" + link_section = "component-type:wit-bindgen:0.41.0:golem:embed-openai@1.0.0:embed-library:encoded world" )] #[doc(hidden)] #[allow(clippy::octal_escapes)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 187] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07>\x01A\x02\x01A\x02\x01\ -@\0\0s\x04\0\x0bhello-world\x01\0\x04\0\x1ecomponent:embed-openai/example\x04\0\x0b\ -\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit-com\ -ponent\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1259] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xe7\x08\x01A\x02\x01\ +A\x02\x01B/\x01m\x08\x0fretrieval-query\x12retrieval-document\x13semantic-simila\ +rity\x0eclassification\x0aclustering\x12question-answering\x11fact-verification\x0e\ +code-retrieval\x04\0\x09task-type\x03\0\0\x01m\x03\x0bfloat-array\x06binary\x06b\ +ase64\x04\0\x0doutput-format\x03\0\x02\x01m\x05\x07float32\x04int8\x05uint8\x06b\ +inary\x07ubinary\x04\0\x0coutput-dtype\x03\0\x04\x01m\x08\x0finvalid-request\x0f\ +model-not-found\x0bunsupported\x15authentication-failed\x0eprovider-error\x13rat\ +e-limit-exceeded\x0einternal-error\x07unknown\x04\0\x0aerror-code\x03\0\x06\x01r\ +\x01\x03urls\x04\0\x09image-url\x03\0\x08\x01q\x02\x04text\x01s\0\x05image\x01\x09\ +\0\x04\0\x0ccontent-part\x03\0\x0a\x01r\x02\x03keys\x05values\x04\0\x02kv\x03\0\x0c\ +\x01ks\x01k\x01\x01ky\x01k\x7f\x01k\x03\x01k\x05\x01p\x0d\x01r\x08\x05model\x0e\x09\ +task-type\x0f\x0adimensions\x10\x0atruncation\x11\x0doutput-format\x12\x0coutput\ +-dtype\x13\x04user\x0e\x10provider-options\x14\x04\0\x06config\x03\0\x15\x01r\x02\ +\x0cinput-tokens\x10\x0ctotal-tokens\x10\x04\0\x05usage\x03\0\x17\x01pv\x01r\x02\ +\x05indexy\x06vector\x19\x04\0\x09embedding\x03\0\x1a\x01p\x1b\x01k\x18\x01r\x04\ +\x0aembeddings\x1c\x05usage\x1d\x05models\x16provider-metadata-json\x0e\x04\0\x12\ +embedding-response\x03\0\x1e\x01r\x03\x05indexy\x0frelevance-scorev\x08document\x0e\ +\x04\0\x0drerank-result\x03\0\x20\x01p!\x01r\x04\x07results\"\x05usage\x1d\x05mo\ +dels\x16provider-metadata-json\x0e\x04\0\x0frerank-response\x03\0#\x01r\x03\x04c\ +ode\x07\x07messages\x13provider-error-json\x0e\x04\0\x05error\x03\0%\x01p\x0b\x01\ +j\x01\x1f\x01&\x01@\x02\x06inputs'\x06config\x16\0(\x04\0\x08generate\x01)\x01ps\ +\x01j\x01$\x01&\x01@\x03\x05querys\x09documents*\x06config\x16\0+\x04\0\x06reran\ +k\x01,\x04\0\x17golem:embed/embed@1.0.0\x05\0\x04\0&golem:embed-openai/embed-lib\ +rary@1.0.0\x04\0\x0b\x13\x01\0\x0dembed-library\x03\0\0\0G\x09producers\x01\x0cp\ +rocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index 29f1598a0..6c18891e6 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -20,6 +20,83 @@ pub struct EmbeddingsApi { client: reqwest::Client, } + + +impl EmbeddingsApi { + pub fn new(openai_api_key: String) -> Self { + let client = Client::builder() + .build() + .expect("Failed to initialize HTTP client"); + Self { + openai_api_key, + client, + } + } + + pub fn generate_embeding(&self, request: EmbeddingRequest) -> Result { + trace!("Sending request to OpenAI API: {request:?}"); + let response = self + .client + .request(Method::POST, format!("{BASE_URL}/v1/embeddings")) + .bearer_auth(&self.openai_api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Request failed", err))?; + parse_response::(response) + } +} + +fn parse_response(response: Response) -> Result { + let status = response.status(); + if status.is_success() { + let response_data = response + .json::() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from OpenAI Embeddings API: {response_data:?}"); + Ok(response_data) + } else { + let response_data = response + .text() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from OpenAI Embeddings API: {response_data:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Request failed with {status}"), + provider_error_json: Some(response_data), + }) + } +} + + + +impl EmbeddingVector { + pub fn to_float_vec(&self) -> Result, String> { + match self { + EmbeddingVector::FloatArray(vec) => Ok(vec.clone()), + EmbeddingVector::Base64(base64_str) => { + use base64::{engine::general_purpose, Engine}; + + let bytes = general_purpose::STANDARD + .decode(base64_str) + .map_err(|e| format!("Failed to decode base64: {}", e))?; + + if bytes.len() % 4 != 0 { + return Err("Invalid base64 data: length not divisible by 4".to_string()); + } + + let mut floats: Vec = Vec::with_capacity(bytes.len() / 4); + for chunk in bytes.chunks_exact(4) { + floats.push(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])); + } + + Ok(floats) + } + } + } +} + + + /// OpenAI allows only allows float and base64 as output formats. #[derive(Debug, Deserialize, Serialize, Clone)] pub enum EncodingFormat { @@ -67,31 +144,6 @@ pub enum EmbeddingVector { Base64(String), } -impl EmbeddingVector { - pub fn to_float_vec(&self) -> Result, String> { - match self { - EmbeddingVector::FloatArray(vec) => Ok(vec.clone()), - EmbeddingVector::Base64(base64_str) => { - use base64::{engine::general_purpose, Engine}; - - let bytes = general_purpose::STANDARD - .decode(base64_str) - .map_err(|e| format!("Failed to decode base64: {}", e))?; - - if bytes.len() % 4 != 0 { - return Err("Invalid base64 data: length not divisible by 4".to_string()); - } - - let mut floats: Vec = Vec::with_capacity(bytes.len() / 4); - for chunk in bytes.chunks_exact(4) { - floats.push(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])); - } - - Ok(floats) - } - } - } -} #[derive(Debug, Serialize, Deserialize)] pub struct OpenAIError { @@ -106,48 +158,3 @@ pub struct OpenAIErrorDetails { pub param: Option, pub code: Option, } - -impl EmbeddingsApi { - pub fn new(openai_api_key: String) -> Self { - let client = Client::builder() - .build() - .expect("Failed to initialize HTTP client"); - Self { - openai_api_key, - client, - } - } - - pub fn generate_embeding(&self, request: EmbeddingRequest) -> Result { - trace!("Sending request to OpenAI API: {request:?}"); - let response = self - .client - .request(Method::POST, format!("{BASE_URL}/v1/embeddings")) - .bearer_auth(&self.openai_api_key) - .json(&request) - .send() - .map_err(|err| from_reqwest_error("Request failed", err))?; - parse_response(response) - } -} - -fn parse_response(response: Response) -> Result { - let status = response.status(); - if status.is_success() { - let response_data = response - .json::() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from OpenAI Embeddings API: {response_data:?}"); - Ok(response_data) - } else { - let response_data = response - .text() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from OpenAI Embeddings API: {response_data:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Request failed with {status}"), - provider_error_json: Some(response_data), - }) - } -} diff --git a/golem-embed/embed-openai/src/conversions.rs b/golem-embed/embed-openai/src/conversions.rs index e69de29bb..079df98bf 100644 --- a/golem-embed/embed-openai/src/conversions.rs +++ b/golem-embed/embed-openai/src/conversions.rs @@ -0,0 +1,78 @@ +use bytemuck::checked::cast_slice; +use golem_embed::golem::embed::embed::{Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error}; +use golem_embed::error::unsupported; + +use crate::client::{EmbeddingRequest, EmbeddingResponse, EncodingFormat}; + + + + + + +pub fn create_request(inputs: Vec, config: Config) -> Result { + let mut input = String::new(); + for content in inputs { + match content { + ContentPart::Text(text) => input.push_str(&text), + ContentPart::Image(_) => + return Err(unsupported("Image embeddings is not supported by OpenAI.")), + } + } + + + let model = config.model.unwrap_or_else(|| "text-embedding-ada-002".to_string()); + + let encoding_format = config.output_format.map(|format| match format { + golem_embed::golem::embed::embed::OutputFormat::FloatArray => EncodingFormat::Float, + golem_embed::golem::embed::embed::OutputFormat::Binary => EncodingFormat::Base64, + golem_embed::golem::embed::embed::OutputFormat::Base64 => EncodingFormat::Base64, + }); + + let dimension = config.dimensions; + + let user = config.user; + + Ok(EmbeddingRequest { + input, + model, + encoding_format, + dimension, + user, + }) + +} + + + +fn f32vec_to_binary(f32_vec: &[f32]) -> &[u8] { + cast_slice(f32_vec) +} + +pub fn process_embedding_response(response: EmbeddingResponse) -> Result { + let mut embeddings = Vec::new(); + for embeding_data in &response.data{ + let embed = embeding_data.embedding.to_float_vec().map_err(|e| Error { + code: golem_embed::golem::embed::embed::ErrorCode::ProviderError, + message: e, + provider_error_json: None, + })?; + embeddings.push(golem_embed::golem::embed::embed::Embedding { + index: embeding_data.index as u32, + vector: embed, + }); + } + + let usage = golem_embed::golem::embed::embed::Usage { + input_tokens: Some(response.usage.prompt_tokens), + total_tokens: Some(response.usage.total_tokens), + }; + + + Ok(GolemEmbeddingResponse{ + embeddings, + usage : Some(usage), + model : response.model, + provider_metadata_json: None, + }) + +} diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs index 614e57f24..cc23da05f 100644 --- a/golem-embed/embed-openai/src/lib.rs +++ b/golem-embed/embed-openai/src/lib.rs @@ -1,19 +1,55 @@ +use client::EmbeddingsApi; +use conversions::{create_request, process_embedding_response}; +use golem_embed::{config::with_config_key, golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse +}, LOGGING_STATE}; + mod client; mod conversions; +struct OpenAIComponent; + +impl OpenAIComponent { + const ENV_VAR_NAME: &'static str = "OPENAI_API_KEY"; + + fn embeddings( + client: EmbeddingsApi, + inputs: Vec, + config: Config, + ) -> Result { + let request = create_request(inputs, config); + match request { + Ok(request) => match client.generate_embeding(request) { + Ok(response) => process_embedding_response(response), + Err(err) => Err(err), + }, + Err(err) => Err(err), + } + } + -#[allow(warnings)] -mod bindings; + +} -use bindings::Guest; -struct Component; -impl Guest for Component { - /// Say hello! - fn hello_world() -> String { - "Hello, World!".to_string() +impl Guest for OpenAIComponent { + fn generate(inputs: Vec,config:Config,) -> Result { + LOGGING_STATE.with_borrow_mut(|state|state.init()); + with_config_key( + Self::ENV_VAR_NAME, + |error|Err(error), + |openai_api_key| { + let client = EmbeddingsApi::new(openai_api_key); + Self::embeddings(client, inputs, config) + }, + ) + } + + fn rerank(query:String,documents:Vec::,config:Config,) -> Result { + todo!() + } } -bindings::export!(Component with_types_in bindings); +golem_embed::export_embed!(OpenAIComponent with_types_in golem_embed); diff --git a/golem-embed/embed-openai/wit/openai.wit b/golem-embed/embed-openai/wit/openai.wit new file mode 100644 index 000000000..1eefcd1b2 --- /dev/null +++ b/golem-embed/embed-openai/wit/openai.wit @@ -0,0 +1,5 @@ +package golem:embed-openai@1.0.0; + +world embed-library { + include golem:embed/embed-library@1.0.0; +} diff --git a/golem-embed/embed-openai/wit/world.wit b/golem-embed/embed-openai/wit/world.wit deleted file mode 100644 index 98ec1f9f8..000000000 --- a/golem-embed/embed-openai/wit/world.wit +++ /dev/null @@ -1,5 +0,0 @@ -package golem:embed-openapi@1.0.0; - -world embed-library { - include golem:embed/embed-library@1.0.0; -} diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index 61fc4fadb..adaa30b57 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -2,7 +2,7 @@ pub mod error; pub mod config; wit_bindgen::generate!({ - path: "./wit", + path: "../wit", world: "embed-library", generate_all, generate_unused_types: true, diff --git a/golem-embed/embed/wit/deps.lock b/golem-embed/embed/wit/deps.lock deleted file mode 100644 index adc795b3a..000000000 --- a/golem-embed/embed/wit/deps.lock +++ /dev/null @@ -1,4 +0,0 @@ -["wasi:io"] -url = "https://github.com/WebAssembly/wasi-io/archive/v0.2.3.tar.gz" -sha256 = "1cccbfe4122686ea57a25cd368e8cdfc408cbcad089f47fb6685b6f92e96f050" -sha512 = "7a95f964c13da52611141acd89bc8876226497f128e99dd176a4270c5b5efbd8cc847b5fbd1a91258d028c646db99e0424d72590cf1caf20f9f3a3343fad5017" diff --git a/golem-embed/embed/wit/embed.wit b/golem-embed/embed/wit/embed.wit index 3e697a31f..ca3d6d946 100644 --- a/golem-embed/embed/wit/embed.wit +++ b/golem-embed/embed/wit/embed.wit @@ -1,5 +1,5 @@ package golem:embed-library@1.0.0; world embed-library { - export golem:embed/embed@1.0.0; + export golem:embed/golem-embed/embed@1.0.0; } diff --git a/Makefile.toml b/golem-llm/Makefile.toml similarity index 58% rename from Makefile.toml rename to golem-llm/Makefile.toml index 710e4cd8e..b47a7d757 100644 --- a/Makefile.toml +++ b/golem-llm/Makefile.toml @@ -10,117 +10,117 @@ args = ["clean"] command = "cargo" args = ["test"] -[tasks.build-llm-ollama] +[tasks.build-ollama] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama"] -[tasks.build-llm-ollama-portable] +[tasks.build-ollama-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama", "--no-default-features"] -[tasks.build-llm-anthropic] +[tasks.build-anthropic] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-anthropic"] -[tasks.build-llm-anthropic-portable] +[tasks.build-anthropic-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-anthropic", "--no-default-features"] -[tasks.build-llm-grok] +[tasks.build-grok] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok"] -[tasks.build-llm-grok-portable] +[tasks.build-grok-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok", "--no-default-features"] -[tasks.build-llm-openai] +[tasks.build-openai] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai"] -[tasks.build-llm-openai-portable] +[tasks.build-openai-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai", "--no-default-features"] -[tasks.build-llm-openrouter] +[tasks.build-openrouter] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openrouter"] -[tasks.build-llm-openrouter-portable] +[tasks.build-openrouter-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openrouter", "--no-default-features"] -[tasks.build-llm] +[tasks.build] dependencies = [ - "build-llm-anthropic", - "build-llm-grok", - "build-llm-openai", - "build-llm-openrouter", - "build-llm-ollama", + "build-anthropic", + "build-grok", + "build-openai", + "build-openrouter", + "build-ollama", ] -[tasks.build-llm-portable] +[tasks.build-portable] dependencies = [ - "build-llm-anthropic-portable", - "build-llm-grok-portable", - "build-llm-openai-portable", - "build-llm-openrouter-portable", - "build-llm-ollama-portable", + "build-anthropic-portable", + "build-grok-portable", + "build-openai-portable", + "build-openrouter-portable", + "build-ollama-portable", ] -[tasks.build-all-llm] +[tasks.build-all] script_runner = "@duckscript" script = ''' -mkdir components/llm/debug +mkdir components/debug cm_run_task clean -cm_run_task build-llm +cm_run_task build -cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/llm/debug/golem_llm_anthropic.wasm -cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/llm/debug/golem_llm_grok.wasm -cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/llm/debug/golem_llm_openai.wasm -cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/llm/debug/golem_llm_openrouter.wasm -cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/llm/debug/golem_llm_ollama.wasm +cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/debug/golem_llm_anthropic.wasm +cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/debug/golem_llm_grok.wasm +cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/debug/golem_llm_openai.wasm +cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/debug/golem_llm_openrouter.wasm +cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/debug/golem_llm_ollama.wasm cm_run_task clean -cm_run_task build-llm-portable +cm_run_task build-portable -cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/llm/debug/golem_llm_anthropic-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/llm/debug/golem_llm_grok-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/llm/debug/golem_llm_openai-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/llm/debug/golem_llm_openrouter-portable.wasm -cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/llm/debug/golem_llm_ollama-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_anthropic.wasm components/debug/golem_llm_anthropic-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_grok.wasm components/debug/golem_llm_grok-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/debug/golem_llm_openai-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_openrouter.wasm components/debug/golem_llm_openrouter-portable.wasm +cp target/wasm32-wasip1/debug/golem_llm_ollama.wasm components/debug/golem_llm_ollama-portable.wasm ''' -[tasks.release-build-llm-ollama] +[tasks.release-build-ollama] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama", "--release"] -[tasks.release-build-llm-ollama-portable] +[tasks.release-build-ollama-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-ollama", "--release", "--no-default-features"] -[tasks.release-build-llm-anthropic] +[tasks.release-build-anthropic] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-anthropic", "--release"] -[tasks.release-build-llm-anthropic-portable] +[tasks.release-build-anthropic-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = [ @@ -131,32 +131,32 @@ args = [ "--no-default-features", ] -[tasks.release-build-llm-grok] +[tasks.release-build-grok] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok", "--release"] -[tasks.release-build-llm-grok-portable] +[tasks.release-build-grok-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-grok", "--release", "--no-default-features"] -[tasks.release-build-llm-openai] +[tasks.release-build-openai] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai", "--release"] -[tasks.release-build-llm-openai-portable] +[tasks.release-build-openai-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openai", "--release", "--no-default-features"] -[tasks.release-build-llm-openrouter] +[tasks.release-build-openrouter] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-llm-openrouter", "--release"] -[tasks.release-build-llm-openrouter-portable] +[tasks.release-build-openrouter-portable] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = [ @@ -167,57 +167,57 @@ args = [ "--no-default-features", ] -[tasks.release-build-llm] +[tasks.release-build] dependencies = [ - "release-build-llm-anthropic", - "release-build-llm-grok", - "release-build-llm-openai", - "release-build-llm-openrouter", - "release-build-llm-ollama", + "release-build-anthropic", + "release-build-grok", + "release-build-openai", + "release-build-openrouter", + "release-build-ollama", ] -[tasks.release-build-llm-portable] +[tasks.release-build-portable] dependencies = [ - "release-build-llm-anthropic-portable", - "release-build-llm-grok-portable", - "release-build-llm-openai-portable", - "release-build-llm-openrouter-portable", - "release-build-llm-ollama-portable", + "release-build-anthropic-portable", + "release-build-grok-portable", + "release-build-openai-portable", + "release-build-openrouter-portable", + "release-build-ollama-portable", ] -[tasks.release-build-all-llm] +[tasks.release-build-all] script_runner = "@duckscript" script = ''' -mkdir components/llm/release +mkdir components/release cm_run_task set-version cm_run_task clean -cm_run_task release-build-llm +cm_run_task release-build -cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/llm/release/golem_llm_anthropic.wasm -cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/llm/release/golem_llm_grok.wasm -cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/llm/release/golem_llm_openai.wasm -cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/llm/release/golem_llm_openrouter.wasm -cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/llm/release/golem_llm_ollama.wasm +cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/release/golem_llm_anthropic.wasm +cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/release/golem_llm_grok.wasm +cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/release/golem_llm_openai.wasm +cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/release/golem_llm_openrouter.wasm +cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/release/golem_llm_ollama.wasm cm_run_task clean -cm_run_task release-build-llm-portable +cm_run_task release-build-portable -cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/llm/release/golem_llm_anthropic-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/llm/release/golem_llm_grok-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/llm/release/golem_llm_openai-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/llm/release/golem_llm_openrouter-portable.wasm -cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/llm/release/golem_llm_ollama-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_anthropic.wasm components/release/golem_llm_anthropic-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_grok.wasm components/release/golem_llm_grok-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/release/golem_llm_openai-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_openrouter.wasm components/release/golem_llm_openrouter-portable.wasm +cp target/wasm32-wasip1/release/golem_llm_ollama.wasm components/release/golem_llm_ollama-portable.wasm ''' -[tasks.wit-llm-update] +[tasks.wit-update] install_crate = { crate_name = "wit-deps-cli" } command = "wit-deps" args = ["update"] -[tasks.wit-llm] -dependencies = ["wit-llm-update"] +[tasks.wit] +dependencies = ["wit-update"] #condition = { files_modified = { input = [ # "wit/golem-llm.wit", @@ -232,43 +232,42 @@ dependencies = ["wit-llm-update"] script_runner = "@duckscript" script = """ -rm -r golem-llm/llm/wit/deps -mkdir golem-llm/llm/wit/deps/golem-llm -cp golem-llm/wit/golem-llm.wit golem-llm/llm/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io golem-llm/llm/wit/deps -rm -r golem-llm/llm-anthropic/wit/deps -mkdir golem-llm/llm-anthropic/wit/deps/golem-llm -cp golem-llm/wit/golem-llm.wit golem-llm/llm-anthropic/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io llm-anthropic/wit/deps -rm -r golem-llm/llm-grok/wit/deps -mkdir golem-llm/llm-grok/wit/deps/golem-llm -cp golem-llm/wit/golem-llm.wit golem-llm/llm-grok/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io golem-llm/llm-grok/wit/deps -rm -r golem-llm/llm-openai/wit/deps -mkdir golem-llm/llm-openai/wit/deps/golem-llm -cp golem-llm/wit/golem-llm.wit golem-llm/llm-openai/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io golem-llm/llm-openai/wit/deps -rm -r golem-llm/llm-openrouter/wit/deps -mkdir golem-llm/llm-openrouter/wit/deps/golem-llm -cp golem-llm/wit/golem-llm.wit golem-llm/llm-openrouter/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io golem-llm/llm-openrouter/wit/deps -rm -r golem-llm/llm-ollama/wit/deps -mkdir golem-llm/llm-ollama/wit/deps/golem-llm -cp golem-llm/wit/golem-llm.wit golem-llm/llm-ollama/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io golem-llm/llm-ollama/wit/deps - - -rm -r golem-llm/test/wit -mkdir golem-llm/test/wit/deps/golem-llm -mkdir golem-llm/test/wit/deps/io -cp golem-llm/wit/golem-llm.wit golem-llm/test/wit/deps/golem-llm/golem-llm.wit -cp golem-llm/wit/deps/wasi:io/error.wit golem-llm/test/wit/deps/io/error.wit -cp golem-llm/wit/deps/wasi:io/poll.wit golem-llm/test/wit/deps/io/poll.wit -cp golem-llm/wit/deps/wasi:io/streams.wit golem-llm/test/wit/deps/io/streams.wit -cp golem-llm/wit/deps/wasi:io/world.wit golem-llm/test/wit/deps/io/world.wit +rm -r llm/wit/deps +mkdir llm/wit/deps/golem-llm +cp wit/golem-llm.wit llm/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io llm/wit/deps +rm -r llm-anthropic/wit/deps +mkdir llm-anthropic/wit/deps/golem-llm +cp wit/golem-llm.wit llm-anthropic/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io llm-anthropic/wit/deps +rm -r llm-grok/wit/deps +mkdir llm-grok/wit/deps/golem-llm +cp wit/golem-llm.wit llm-grok/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io llm-grok/wit/deps +rm -r llm-openai/wit/deps +mkdir llm-openai/wit/deps/golem-llm +cp wit/golem-llm.wit llm-openai/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io llm-openai/wit/deps +rm -r llm-openrouter/wit/deps +mkdir llm-openrouter/wit/deps/golem-llm +cp wit/golem-llm.wit llm-openrouter/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io llm-openrouter/wit/deps +rm -r llm-ollama/wit/deps +mkdir llm-ollama/wit/deps/golem-llm +cp wit/golem-llm.wit llm-ollama/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io llm-ollama/wit/deps + + +rm -r test/wit +mkdir test/wit/deps/golem-llm +mkdir test/wit/deps/io +cp wit/golem-llm.wit test/wit/deps/golem-llm/golem-llm.wit +cp wit/deps/wasi:io/error.wit test/wit/deps/io/error.wit +cp wit/deps/wasi:io/poll.wit test/wit/deps/io/poll.wit +cp wit/deps/wasi:io/streams.wit test/wit/deps/io/streams.wit +cp wit/deps/wasi:io/world.wit test/wit/deps/io/world.wit """ - [tasks.check] description = "Runs rustfmt and clippy checks without applying any fix" dependencies = ["check-clippy", "check-rustfmt"] @@ -287,7 +286,7 @@ args = ["clippy", "--all-targets", "--", "--no-deps", "-Dwarnings"] [tasks.fix] description = "Runs rustfmt and clippy checks and applies fixes" -dependencies = ["wit-llm", "wit-embed", "fix-clippy", "fix-rustfmt"] +dependencies = ["wit", "fix-clippy", "fix-rustfmt"] [tasks.fix-rustfmt] description = "Runs rustfmt checks and applies fixes" @@ -309,14 +308,14 @@ args = [ "-Dwarnings", ] -[tasks.build-llm-test-components] -dependencies = ["build-llm"] +[tasks.build-test-components] +dependencies = ["build"] description = "Builds all test components with golem-cli" install_crate = "cargo-binstall" script = ''' cargo-binstall golem-cli@1.2.2-dev.11 --locked --force --no-confirm cargo-binstall wac-cli --locked --force --no-confirm -cd golem-llm/test +cd test golem-cli --version golem-cli app clean golem-cli app build -b anthropic-debug @@ -330,6 +329,7 @@ golem-cli app clean golem-cli app build -b ollama-debug ''' + [tasks.set-version] description = "Sets the version in all Cargo.toml files to the value of the VERSION environment variable" condition = { env_set = ["VERSION"] } @@ -355,27 +355,4 @@ foreach ($file in $cargoFiles) Foreach-Object { $_ -replace "0.0.0", $Env:VERSION } | Set-Content $file.PSPath } -''' - - - -[tasks.build-all] -script_runner = "@duckscript" -script = """ -cm_run_task build-all-llm -""" - - -[tasks.release-build-all] -script_runner = "@duckscript" -script = """ -cm_run_task release-build-all-llm -""" - - - -[tasks.build-test-components] -script_runner = "@duckscript" -script = """ -cm_run_task build-llm-test-components -""" \ No newline at end of file +''' \ No newline at end of file From 421703fc1e22bcc58b5df9ceaa81a2d7839962dc Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 1 Jun 2025 13:55:52 +0000 Subject: [PATCH 07/36] fix --- .../embed-openai/wit/deps/golem-embed/golem-embed.wit | 5 +++++ golem-embed/embed/src/lib.rs | 2 +- golem-embed/embed/wit/deps/golem-embed/golem-embed.wit | 4 ++++ golem-embed/embed/wit/embed.wit | 2 +- golem-embed/wit/golem-embed.wit | 5 +++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit index 056c95107..904504bc5 100644 --- a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit @@ -122,4 +122,9 @@ interface embed { documents: list, config: config ) -> result; +} + + +world embed-library { + export embed; } \ No newline at end of file diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index adaa30b57..61fc4fadb 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -2,7 +2,7 @@ pub mod error; pub mod config; wit_bindgen::generate!({ - path: "../wit", + path: "./wit", world: "embed-library", generate_all, generate_unused_types: true, diff --git a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit index 056c95107..a7e8be931 100644 --- a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit @@ -122,4 +122,8 @@ interface embed { documents: list, config: config ) -> result; +} + +world embed-library { + export embed; } \ No newline at end of file diff --git a/golem-embed/embed/wit/embed.wit b/golem-embed/embed/wit/embed.wit index ca3d6d946..3e697a31f 100644 --- a/golem-embed/embed/wit/embed.wit +++ b/golem-embed/embed/wit/embed.wit @@ -1,5 +1,5 @@ package golem:embed-library@1.0.0; world embed-library { - export golem:embed/golem-embed/embed@1.0.0; + export golem:embed/embed@1.0.0; } diff --git a/golem-embed/wit/golem-embed.wit b/golem-embed/wit/golem-embed.wit index 2b9073b88..d9b30ef9c 100644 --- a/golem-embed/wit/golem-embed.wit +++ b/golem-embed/wit/golem-embed.wit @@ -121,4 +121,9 @@ interface embed { documents: list, config: config ) -> result; +} + + +world embed-library { + export embed; } \ No newline at end of file From 739e10848049e3739f52a5db0caf987ec4ffd913 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Tue, 3 Jun 2025 10:57:49 +0000 Subject: [PATCH 08/36] wip --- Cargo.lock | 15 +- Cargo.toml | 2 +- golem-embed/Makefile.toml | 57 +- .../embed-cohere/.vscode/settings.json | 10 + golem-embed/embed-cohere/Cargo.toml | 45 + golem-embed/embed-cohere/src/bindings.rs | 43 + golem-embed/embed-cohere/src/client.rs | 324 ++++ golem-embed/embed-cohere/src/conversions.rs | 106 ++ golem-embed/embed-cohere/src/lib.rs | 68 + golem-embed/embed-cohere/wit/cohere.wit | 5 + .../wit/deps/golem-embed/golem-embed.wit | 130 ++ .../embed-cohere/wit/deps/wasi:io/error.wit | 34 + .../embed-cohere/wit/deps/wasi:io/poll.wit | 47 + .../embed-cohere/wit/deps/wasi:io/streams.wit | 290 ++++ .../embed-cohere/wit/deps/wasi:io/world.wit | 10 + golem-embed/embed-openai/Cargo.toml | 1 - golem-embed/embed-openai/src/bindings.rs | 8 +- golem-embed/embed-openai/src/client.rs | 59 +- golem-embed/embed-openai/src/conversions.rs | 50 +- golem-embed/embed-openai/src/lib.rs | 11 +- .../wit/deps/golem-embed/golem-embed.wit | 2 +- golem-embed/embed/src/lib.rs | 2 +- .../wit/deps/golem-embed/golem-embed.wit | 3 +- golem-embed/test/.gitignore | 2 + golem-embed/test/.vscode/settings.json | 3 + golem-embed/test/Cargo.lock | 1339 ++++++++++++++++ golem-embed/test/Cargo.toml | 20 + .../test/common-rust/common-lib/Cargo.toml | 4 + .../test/common-rust/common-lib/src/lib.rs | 3 + golem-embed/test/common-rust/golem.yaml | 44 + golem-embed/test/components-rust/.gitignore | 2 + .../components-rust/test-embed/Cargo.lock | 1376 +++++++++++++++++ .../components-rust/test-embed/Cargo.toml | 46 + .../components-rust/test-embed/golem.yaml | 70 + .../components-rust/test-embed/src/lib.rs | 60 + .../test-embed/wit/test-llm.wit | 14 + .../components-rust/test-helper/Cargo.lock | 1376 +++++++++++++++++ .../components-rust/test-helper/Cargo.toml | 33 + .../components-rust/test-helper/golem.yaml | 18 + .../components-rust/test-helper/src/lib.rs | 38 + .../test-helper/wit/test-helper.wit | 9 + golem-embed/test/data/cat.png | Bin 0 -> 34010 bytes golem-embed/test/golem.yaml | 12 + .../test/wit/deps/golem-embed/golem-embed.wit | 130 ++ golem-embed/test/wit/deps/io/error.wit | 34 + golem-embed/test/wit/deps/io/poll.wit | 47 + golem-embed/test/wit/deps/io/streams.wit | 290 ++++ golem-embed/test/wit/deps/io/world.wit | 10 + golem-embed/wit/golem-embed.wit | 6 +- 49 files changed, 6216 insertions(+), 92 deletions(-) create mode 100644 golem-embed/embed-cohere/.vscode/settings.json create mode 100644 golem-embed/embed-cohere/Cargo.toml create mode 100644 golem-embed/embed-cohere/src/bindings.rs create mode 100644 golem-embed/embed-cohere/src/client.rs create mode 100644 golem-embed/embed-cohere/src/conversions.rs create mode 100644 golem-embed/embed-cohere/src/lib.rs create mode 100644 golem-embed/embed-cohere/wit/cohere.wit create mode 100644 golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit create mode 100644 golem-embed/embed-cohere/wit/deps/wasi:io/error.wit create mode 100644 golem-embed/embed-cohere/wit/deps/wasi:io/poll.wit create mode 100644 golem-embed/embed-cohere/wit/deps/wasi:io/streams.wit create mode 100644 golem-embed/embed-cohere/wit/deps/wasi:io/world.wit create mode 100644 golem-embed/test/.gitignore create mode 100644 golem-embed/test/.vscode/settings.json create mode 100644 golem-embed/test/Cargo.lock create mode 100644 golem-embed/test/Cargo.toml create mode 100644 golem-embed/test/common-rust/common-lib/Cargo.toml create mode 100644 golem-embed/test/common-rust/common-lib/src/lib.rs create mode 100644 golem-embed/test/common-rust/golem.yaml create mode 100644 golem-embed/test/components-rust/.gitignore create mode 100644 golem-embed/test/components-rust/test-embed/Cargo.lock create mode 100644 golem-embed/test/components-rust/test-embed/Cargo.toml create mode 100644 golem-embed/test/components-rust/test-embed/golem.yaml create mode 100644 golem-embed/test/components-rust/test-embed/src/lib.rs create mode 100644 golem-embed/test/components-rust/test-embed/wit/test-llm.wit create mode 100644 golem-embed/test/components-rust/test-helper/Cargo.lock create mode 100644 golem-embed/test/components-rust/test-helper/Cargo.toml create mode 100644 golem-embed/test/components-rust/test-helper/golem.yaml create mode 100644 golem-embed/test/components-rust/test-helper/src/lib.rs create mode 100644 golem-embed/test/components-rust/test-helper/wit/test-helper.wit create mode 100644 golem-embed/test/data/cat.png create mode 100644 golem-embed/test/golem.yaml create mode 100644 golem-embed/test/wit/deps/golem-embed/golem-embed.wit create mode 100644 golem-embed/test/wit/deps/io/error.wit create mode 100644 golem-embed/test/wit/deps/io/poll.wit create mode 100644 golem-embed/test/wit/deps/io/streams.wit create mode 100644 golem-embed/test/wit/deps/io/world.wit diff --git a/Cargo.lock b/Cargo.lock index 8652cec06..9db93cbb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,10 +353,23 @@ dependencies = [ ] [[package]] -name = "golem-embed-openai" +name = "golem-embed-cohere" version = "0.0.0" dependencies = [ "base64 0.22.1", + "golem-embed", + "golem-rust", + "log", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + +[[package]] +name = "golem-embed-openai" +version = "0.0.0" +dependencies = [ "bytemuck", "golem-embed", "golem-rust", diff --git a/Cargo.toml b/Cargo.toml index c78cb8917..c0f2e92b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ resolver = "2" members = [ - "golem-embed/embed", + "golem-embed/embed", "golem-embed/embed-cohere", "golem-embed/embed-openai", "golem-llm/llm", "golem-llm/llm-anthropic", diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml index 0b5313ba5..7dfcfb6ac 100644 --- a/golem-embed/Makefile.toml +++ b/golem-embed/Makefile.toml @@ -20,14 +20,29 @@ install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-embed-openai", "--no-default-features"] + +[tasks.build-cohere] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere"] + +[tasks.build-cohere-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere", "--no-default-features"] + + + [tasks.build] dependencies = [ "build-openai", + "build-cohere", ] [tasks.build-portable] dependencies = [ "build-openai-portable", + "build-cohere-portable", ] [tasks.build-all] @@ -38,12 +53,14 @@ mkdir components/debug cm_run_task clean cm_run_task build -cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/embed/debug/golem_llm_openai.wasm +cp target/wasm32-wasip1/debug/golem_embed_openai.wasm components/embed/debug/golem_embed_openai.wasm +cp target/wasm32-wasip1/debug/golem_embed_cohere.wasm components/embed/debug/golem_embed_cohere.wasm cm_run_task clean cm_run_task build-portable -cp target/wasm32-wasip1/debug/golem_llm_openai.wasm components/embed/debug/golem_llm_openai-portable.wasm +cp target/wasm32-wasip1/debug/golem_embed_openai.wasm components/embed/debug/golem_embed_openai-portable.wasm +cp target/wasm32-wasip1/debug/golem_embed_cohere.wasm components/embed/debug/golem_embed_cohere-portable.wasm ''' [tasks.release-build-openai] @@ -56,14 +73,26 @@ install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-embed-openai", "--release", "--no-default-features"] +[tasks.release-build-cohere] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere", "--release"] + +[tasks.release-build-cohere-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere", "--release", "--no-default-features"] + [tasks.release-build] dependencies = [ "release-build-openai", + "release-build-cohere", ] [tasks.release-build-portable] dependencies = [ "release-build-openai-portable", + "release-build-cohere-portable", ] [tasks.release-build-all] @@ -76,12 +105,14 @@ cm_run_task set-version cm_run_task clean cm_run_task release-build -cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/embed/release/golem_llm_openai.wasm +cp target/wasm32-wasip1/release/golem_embed_openai.wasm components/embed/release/golem_embed_openai.wasm +cp target/wasm32-wasip1/release/golem_embed_cohere.wasm components/embed/release/golem_embed_cohere.wasm cm_run_task clean cm_run_task release-build-portable -cp target/wasm32-wasip1/release/golem_llm_openai.wasm components/embed/release/golem_llm_openai-portable.wasm +cp target/wasm32-wasip1/release/golem_embed_openai.wasm components/embed/release/golem_embed_openai-portable.wasm +cp target/wasm32-wasip1/release/golem_embed_cohere.wasm components/embed/release/golem_embed_cohere-portable.wasm ''' [tasks.wit-update] @@ -91,18 +122,6 @@ args = ["update"] [tasks.wit] dependencies = ["wit-update"] - -#condition = { files_modified = { input = [ -# "wit/golem-llm.wit", -# "wit/deps/wasi:io", -#], output = [ -# "llm/wit/deps/golem-llm/golem-llm.wit", -# "llm-anthropic/wit/deps/golem-llm/golem-llm.wit", -# "llm-grok/wit/deps/golem-llm/golem-llm.wit", -# "llm-openai/wit/deps/golem-llm/golem-llm.wit", -# "llm-openrouter/wit/deps/golem-llm/golem-llm.wit", -#] } } - script_runner = "@duckscript" script = """ rm -r embed/wit/deps @@ -115,6 +134,10 @@ mkdir embed-openai/wit/deps/golem-embed cp wit/golem-embed.wit embed-openai/wit/deps/golem-embed/golem-embed.wit cp wit/deps/wasi:io embed-openai/wit/deps +rm -r embed-cohere/wit/deps +mkdir embed-cohere/wit/deps/golem-embed +cp wit/golem-embed.wit embed-cohere/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io embed-cohere/wit/deps rm -r test/wit mkdir test/wit/deps/golem-embed @@ -177,6 +200,8 @@ cd test golem-cli --version golem-cli app clean golem-cli app build -b openai-debug +golem-cli app clean +golem-cli app build -b cohere-debug ''' diff --git a/golem-embed/embed-cohere/.vscode/settings.json b/golem-embed/embed-cohere/.vscode/settings.json new file mode 100644 index 000000000..b945667b6 --- /dev/null +++ b/golem-embed/embed-cohere/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "rust-analyzer.check.overrideCommand": [ + "cargo", + "component", + "check", + "--workspace", + "--all-targets", + "--message-format=json" + ], +} diff --git a/golem-embed/embed-cohere/Cargo.toml b/golem-embed/embed-cohere/Cargo.toml new file mode 100644 index 000000000..43b827751 --- /dev/null +++ b/golem-embed/embed-cohere/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "golem-embed-cohere" +version = "0.0.0" +edition = "2021" +license = "Apache-2.0" +homepage = "https://golem.cloud" +repository = "https://github.com/golemcloud/golem-llm" +description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" + + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["durability"] +durability = ["golem-rust/durability", "golem-embed/durability"] + + +[dependencies] +golem-embed= {path="../embed", version="0.0.0", default-features= false} +golem-rust = { workspace = true } +log = { workspace = true } +reqwest = { workspace = true } +serde = {workspace = true} +base64 = { workspace = true } +serde_json = { workspace = true } +wit-bindgen-rt = { workspace = true } + + +[package.metadata.component] +package="golem:embed-cohere" + +[package.metadata.component.bindings] +generate_unused_types=true + +[package.metadata.component.bindings.with] +"golem:embed/embed@1.0.0"= "golem_embed::golem::embed::embed" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.target.dependencies] +"golem:embed" = { path = "wit/deps/golem-embed" } +"wasi:io" = { path = "wit/deps/wasi:io"} diff --git a/golem-embed/embed-cohere/src/bindings.rs b/golem-embed/embed-cohere/src/bindings.rs new file mode 100644 index 000000000..3f6b7d647 --- /dev/null +++ b/golem-embed/embed-cohere/src/bindings.rs @@ -0,0 +1,43 @@ +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! +// Options used: +// * runtime_path: "wit_bindgen_rt" +// * with "golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" +// * generate_unused_types +use golem_embed::golem::embed::embed as __with_name0; +#[cfg(target_arch = "wasm32")] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:golem:embed-cohere@1.0.0:embed-library:encoded world" +)] +#[doc(hidden)] +#[allow(clippy::octal_escapes)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1263] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xeb\x08\x01A\x02\x01\ +A\x02\x01B/\x01m\x08\x0fretrieval-query\x12retrieval-document\x13semantic-simila\ +rity\x0eclassification\x0aclustering\x12question-answering\x11fact-verification\x0e\ +code-retrieval\x04\0\x09task-type\x03\0\0\x01m\x03\x0bfloat-array\x06binary\x06b\ +ase64\x04\0\x0doutput-format\x03\0\x02\x01m\x05\x0bfloat-array\x04int8\x05uint8\x06\ +binary\x07ubinary\x04\0\x0coutput-dtype\x03\0\x04\x01m\x08\x0finvalid-request\x0f\ +model-not-found\x0bunsupported\x15authentication-failed\x0eprovider-error\x13rat\ +e-limit-exceeded\x0einternal-error\x07unknown\x04\0\x0aerror-code\x03\0\x06\x01r\ +\x01\x03urls\x04\0\x09image-url\x03\0\x08\x01q\x02\x04text\x01s\0\x05image\x01\x09\ +\0\x04\0\x0ccontent-part\x03\0\x0a\x01r\x02\x03keys\x05values\x04\0\x02kv\x03\0\x0c\ +\x01ks\x01k\x01\x01ky\x01k\x7f\x01k\x03\x01k\x05\x01p\x0d\x01r\x08\x05model\x0e\x09\ +task-type\x0f\x0adimensions\x10\x0atruncation\x11\x0doutput-format\x12\x0coutput\ +-dtype\x13\x04user\x0e\x10provider-options\x14\x04\0\x06config\x03\0\x15\x01r\x02\ +\x0cinput-tokens\x10\x0ctotal-tokens\x10\x04\0\x05usage\x03\0\x17\x01pv\x01r\x02\ +\x05indexy\x06vector\x19\x04\0\x09embedding\x03\0\x1a\x01p\x1b\x01k\x18\x01r\x04\ +\x0aembeddings\x1c\x05usage\x1d\x05models\x16provider-metadata-json\x0e\x04\0\x12\ +embedding-response\x03\0\x1e\x01r\x03\x05indexy\x0frelevance-scorev\x08document\x0e\ +\x04\0\x0drerank-result\x03\0\x20\x01p!\x01r\x04\x07results\"\x05usage\x1d\x05mo\ +dels\x16provider-metadata-json\x0e\x04\0\x0frerank-response\x03\0#\x01r\x03\x04c\ +ode\x07\x07messages\x13provider-error-json\x0e\x04\0\x05error\x03\0%\x01p\x0b\x01\ +j\x01\x1f\x01&\x01@\x02\x06inputs'\x06config\x16\0(\x04\0\x08generate\x01)\x01ps\ +\x01j\x01$\x01&\x01@\x03\x05querys\x09documents*\x06config\x16\0+\x04\0\x06reran\ +k\x01,\x04\0\x17golem:embed/embed@1.0.0\x05\0\x04\0&golem:embed-cohere/embed-lib\ +rary@1.0.0\x04\0\x0b\x13\x01\0\x0dembed-library\x03\0\0\0G\x09producers\x01\x0cp\ +rocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +#[inline(never)] +#[doc(hidden)] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs new file mode 100644 index 000000000..fa10fc452 --- /dev/null +++ b/golem-embed/embed-cohere/src/client.rs @@ -0,0 +1,324 @@ +use std::fmt::Debug; + +use golem_embed::{ + error::{error_code_from_status, from_reqwest_error}, + golem::embed::embed::Error, +}; +use log::trace; +use reqwest::{Client, Method, Response}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +const BASE_URL: &str = "https://api.cohere.ai"; + +/// The Cohere API client for creating embeddings. +/// +/// Based on https://docs.cohere.com/reference/embed +pub struct EmbeddingsApi { + cohere_api_key: String, + client: Client, +} + +impl EmbeddingsApi { + pub fn new(cohere_api_key: String) -> Self { + let client = Client::builder() + .build() + .expect("Failed to initialize HTTP client"); + Self { + cohere_api_key, + client, + } + } + + pub fn generate_embeding(&self, request: EmbeddingRequest) -> Result { + trace!("Sending request to Cohere API: {request:?}"); + let response = self + .client + .request(Method::POST, format!("{BASE_URL}/v1/embed")) + .bearer_auth(&self.cohere_api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Request failed", err))?; + trace!("Recived response: {:#?}", response); + parse_response::(response) + } +} + +fn parse_response(response: Response) -> Result { + let status = response.status(); + if status.is_success() { + let response_data = response + .json::() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from Cohere API: {response_data:?}"); + Ok(response_data) + } else { + let response_data = response + .text() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from Cohere API: {response_data:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Request failed with {status}"), + provider_error_json: Some(response_data), + }) + } +} + +fn parse_json(response: &str) -> Result { + serde_json::from_str::(response) +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum InputType { + #[serde(rename = "search_document")] + SearchDocument, + #[serde(rename = "search_query")] + SearchQuery, + #[serde(rename = "classification")] + Classification, + #[serde(rename = "clustering")] + Clustering, + #[serde(rename = "image")] + Image, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum EmbeddingType { + #[serde(rename = "float")] + Float, + #[serde(rename = "int8")] + Int8, + #[serde(rename = "uint8")] + Uint8, + #[serde(rename = "binary")] + Binary, + #[serde(rename = "ubinary")] + Ubinary, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Truncate { + #[serde(rename = "NONE")] + None, + #[serde(rename = "START")] + Start, + #[serde(rename = "END")] + End, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingRequest { + pub model: String, + pub input_type: InputType, + + #[serde(skip_serializing_if = "Option::is_none")] + pub embedding_types: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub texts: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub images: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub max_tokens: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub output_dimension: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub truncate: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingResponse { + pub id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub images: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub texts: Option>, + + pub embeddings: EmbeddingData, + + #[serde(skip_serializing_if = "Option::is_none")] + pub meta: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub response_type: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ImageRespnse { + #[serde(skip_serializing_if = "Option::is_none")] + pub width: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub height: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub format: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub bit_depth: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingData { + #[serde(skip_serializing_if = "Option::is_none")] + pub float: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub int8: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub uint8: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub binary: Option>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub ubinary: Option>>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Meta { + #[serde(skip_serializing_if = "Option::is_none")] + pub api_version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub billed_units: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ApiVersion { + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BilledUnits { + #[serde(skip_serializing_if = "Option::is_none")] + pub input_tokens: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CohereError { + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, +} + +#[cfg(test)] +mod tests { + use crate::client; + + use super::*; + use golem_embed::golem::embed::embed::EmbeddingResponse; + use serde_json; + + #[test] + fn test_parse_data() { + let json_data = r#"{ + "id": "54910170-852f-4322-9767-63d36e55c3bf", + "texts": [ + "This is the sentence I want to embed.", + "Hey !" + ], + "embeddings": { + "binary": [ + [ + -54, + 99, + -87, + 60, + 15, + 10, + 93, + 97, + -42, + -51, + 9 + ] + ], + "float": [ + [ + + 0.016967773, + 0.031982422, + 0.041503906, + 0.0021514893, + 0.008178711, + -0.029541016, + -0.018432617, + -0.046875, + 0.021240234 + ], + [ + 0.013977051, + 0.012084961, + 0.005554199, + -0.053955078, + -0.026977539, + -0.008361816, + 0.02368164, + -0.013183594, + -0.063964844, + 0.026611328 + ] + ], + "int8": [ + [ + + -15, + -65, + 0, + -31, + -43, + -14, + -48, + 59, + -34, + 15, + 36, + 49, + -5, + 3, + -49, + -34, + -74, + 21 + ], + [ + + 14, + 38, + -30, + -13, + -49, + 4, + -33, + -49, + 48, + 9, + -84, + 8, + 0, + -84, + -46, + -20, + 24, + -26, + -98, + 28 + ] + ] + }, + "meta": { + "api_version": { + "version": "2" + }, + "billed_units": { + "input_tokens": 11, + "image_tokens": 0 + } + }, + "response_type": "embeddings_by_type" + }"#; + + let result = parse_json::(json_data); + print!("{:#?}", result.unwrap()); + } +} diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs new file mode 100644 index 000000000..d16f62f17 --- /dev/null +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -0,0 +1,106 @@ +use std::{fs, path::Path}; + +use base64::{engine::general_purpose, Engine}; +use golem_embed::{ + error::unsupported, + golem::embed::embed::{ + self, Config, ContentPart, Embedding, EmbeddingResponse as GolemEmbeddingResponse, Error, + OutputDtype, OutputFormat, TaskType, Usage, + }, +}; +use log::trace; +use reqwest::{Client, Url}; + +use crate::client::{EmbeddingData, EmbeddingRequest, EmbeddingResponse, EmbeddingType, InputType}; + +fn output_dtype_to_cohere_embedding_type(dtype: OutputDtype) -> EmbeddingType { + match dtype { + OutputDtype::FloatArray => EmbeddingType::Float, + OutputDtype::Int8 => EmbeddingType::Int8, + OutputDtype::Uint8 => EmbeddingType::Uint8, + OutputDtype::Binary => EmbeddingType::Binary, + OutputDtype::Ubinary => EmbeddingType::Ubinary, + } +} + +pub fn create_request(inputs: Vec, config: Config) -> Result { + let mut text_inputs = Vec::new(); + let mut image_inputs = Vec::new(); + for input in inputs { + match input { + ContentPart::Text(text) => text_inputs.push(text), + ContentPart::Image(image) => match image_to_base64(&image.url) { + Ok(base64_data) => image_inputs.push(base64_data), + Err(err) => { + trace!("Failed to encode image: {}\nError: {}\n", image.url, err); + } + }, + } + } + + if !text_inputs.is_empty() && !image_inputs.is_empty() + || text_inputs.is_empty() && image_inputs.is_empty() + { + return Err(unsupported( + "Cohere requires text or image input, not both.", + )); + } + + let input_type = if !image_inputs.is_empty() && text_inputs.is_empty() { + InputType::Image + } else { + config + .task_type + .map(|task_type| match task_type { + TaskType::RetrievalQuery => InputType::SearchQuery, + TaskType::RetrievalDocument => InputType::SearchDocument, + TaskType::Classification => InputType::Classification, + TaskType::Clustering => InputType::Clustering, + _ => InputType::SearchDocument, + }) + .unwrap() + }; + + let model = config + .model + .unwrap_or_else(|| "embed-english-v3.0".to_string()); + + let embedding_types = config + .output_dtype + .map(|dtype| vec![output_dtype_to_cohere_embedding_type(dtype)]); + + Ok(EmbeddingRequest { + model, + input_type, + embedding_types, + images: if !image_inputs.is_empty() { + Some(image_inputs) + } else { + None + }, + texts: if !text_inputs.is_empty() { + Some(text_inputs) + } else { + None + }, + truncate: None, + max_tokens: None, + output_dimension: Some(config.dimensions.unwrap().to_string()), + }) +} + +pub fn image_to_base64(source: &str) -> Result> { + let bytes = if Url::parse(source).is_ok() { + let client = Client::new(); + let response = client.get(source).send()?; + + response.bytes()?.to_vec() + } else { + let path = Path::new(source); + + fs::read(path)? + }; + + let base64_data = general_purpose::STANDARD.encode(&bytes); + Ok(base64_data) +} diff --git a/golem-embed/embed-cohere/src/lib.rs b/golem-embed/embed-cohere/src/lib.rs new file mode 100644 index 000000000..90a5749ed --- /dev/null +++ b/golem-embed/embed-cohere/src/lib.rs @@ -0,0 +1,68 @@ +use client::{EmbeddingResponse, EmbeddingsApi}; +use conversions::{create_request}; +use golem_embed::{ + config::with_config_key, + golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, Guest, + RerankResponse, + }, + LOGGING_STATE, +}; + +mod client; +mod conversions; + +struct CohereComponent; + +impl CohereComponent { + const ENV_VAR_NAME: &'static str = "COHERE_API_KEY"; + + fn embeddings( + client: EmbeddingsApi, + inputs: Vec, + config: Config, + ) -> Result { + todo!() + // let request = create_request(inputs, config); + // match request { + // Ok(request) => match client.generate_embeding(request) { + // Ok(response) => process_embedding_response(response), + // Err(err) => Err(err), + // }, + // Err(err) => Err(err), + // } + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + todo!() + } +} + +impl Guest for CohereComponent { + fn generate(inputs: Vec, config: Config) -> Result { + LOGGING_STATE.with_borrow_mut(|state| state.init()); + with_config_key( + Self::ENV_VAR_NAME, + |error| Err(error), + |cohere_api_key| { + let client = EmbeddingsApi::new(cohere_api_key); + Self::embeddings(client, inputs, config) + }, + ) + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + todo!() + } +} + + + diff --git a/golem-embed/embed-cohere/wit/cohere.wit b/golem-embed/embed-cohere/wit/cohere.wit new file mode 100644 index 000000000..7df362448 --- /dev/null +++ b/golem-embed/embed-cohere/wit/cohere.wit @@ -0,0 +1,5 @@ +package golem:embed-cohere@1.0.0; + +world embed-library { + include golem:embed/embed-library@1.0.0; +} diff --git a/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..838b3c2a5 --- /dev/null +++ b/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,130 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float-array, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} + + +world embed-library { + export embed; +} \ No newline at end of file diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/error.wit b/golem-embed/embed-cohere/wit/deps/wasi:io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/embed-cohere/wit/deps/wasi:io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/poll.wit b/golem-embed/embed-cohere/wit/deps/wasi:io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/embed-cohere/wit/deps/wasi:io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/streams.wit b/golem-embed/embed-cohere/wit/deps/wasi:io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/embed-cohere/wit/deps/wasi:io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/world.wit b/golem-embed/embed-cohere/wit/deps/wasi:io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/embed-cohere/wit/deps/wasi:io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/embed-openai/Cargo.toml b/golem-embed/embed-openai/Cargo.toml index 35f261423..d3f7f5b07 100644 --- a/golem-embed/embed-openai/Cargo.toml +++ b/golem-embed/embed-openai/Cargo.toml @@ -23,7 +23,6 @@ golem-rust = { workspace = true } log = { workspace = true } reqwest = { workspace = true } serde = {workspace = true} -base64 = { workspace = true } serde_json = { workspace = true } wit-bindgen-rt = { workspace = true } bytemuck = "1.23.0" diff --git a/golem-embed/embed-openai/src/bindings.rs b/golem-embed/embed-openai/src/bindings.rs index 44c5fb5c1..33bc32f27 100644 --- a/golem-embed/embed-openai/src/bindings.rs +++ b/golem-embed/embed-openai/src/bindings.rs @@ -10,13 +10,13 @@ use golem_embed::golem::embed::embed as __with_name0; )] #[doc(hidden)] #[allow(clippy::octal_escapes)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1259] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xe7\x08\x01A\x02\x01\ +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1263] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xeb\x08\x01A\x02\x01\ A\x02\x01B/\x01m\x08\x0fretrieval-query\x12retrieval-document\x13semantic-simila\ rity\x0eclassification\x0aclustering\x12question-answering\x11fact-verification\x0e\ code-retrieval\x04\0\x09task-type\x03\0\0\x01m\x03\x0bfloat-array\x06binary\x06b\ -ase64\x04\0\x0doutput-format\x03\0\x02\x01m\x05\x07float32\x04int8\x05uint8\x06b\ -inary\x07ubinary\x04\0\x0coutput-dtype\x03\0\x04\x01m\x08\x0finvalid-request\x0f\ +ase64\x04\0\x0doutput-format\x03\0\x02\x01m\x05\x0bfloat-array\x04int8\x05uint8\x06\ +binary\x07ubinary\x04\0\x0coutput-dtype\x03\0\x04\x01m\x08\x0finvalid-request\x0f\ model-not-found\x0bunsupported\x15authentication-failed\x0eprovider-error\x13rat\ e-limit-exceeded\x0einternal-error\x07unknown\x04\0\x0aerror-code\x03\0\x06\x01r\ \x01\x03urls\x04\0\x09image-url\x03\0\x08\x01q\x02\x04text\x01s\0\x05image\x01\x09\ diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index 6c18891e6..50661053a 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -5,6 +5,8 @@ use golem_embed::{ golem::embed::embed::Error, }; use log::trace; +use base64::{engine::general_purpose, Engine}; + #[allow(dead_code, unused, unused_imports)] use reqwest::Client; use reqwest::{Method, Response}; @@ -68,35 +70,6 @@ fn parse_response(response: Response) -> Result Result, String> { - match self { - EmbeddingVector::FloatArray(vec) => Ok(vec.clone()), - EmbeddingVector::Base64(base64_str) => { - use base64::{engine::general_purpose, Engine}; - - let bytes = general_purpose::STANDARD - .decode(base64_str) - .map_err(|e| format!("Failed to decode base64: {}", e))?; - - if bytes.len() % 4 != 0 { - return Err("Invalid base64 data: length not divisible by 4".to_string()); - } - - let mut floats: Vec = Vec::with_capacity(bytes.len() / 4); - for chunk in bytes.chunks_exact(4) { - floats.push(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])); - } - - Ok(floats) - } - } - } -} - - - /// OpenAI allows only allows float and base64 as output formats. #[derive(Debug, Deserialize, Serialize, Clone)] pub enum EncodingFormat { @@ -145,6 +118,34 @@ pub enum EmbeddingVector { } + +impl EmbeddingVector { + pub fn to_float_vec(&self) -> Result, String> { + match self { + EmbeddingVector::FloatArray(vec) => Ok(vec.clone()), + EmbeddingVector::Base64(base64_str) => { + + let bytes = general_purpose::STANDARD + .decode(base64_str) + .map_err(|e| format!("Failed to decode base64: {}", e))?; + + if bytes.len() % 4 != 0 { + return Err("Invalid base64 data: length not divisible by 4".to_string()); + } + + let mut floats: Vec = Vec::with_capacity(bytes.len() / 4); + for chunk in bytes.chunks_exact(4) { + floats.push(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])); + } + + Ok(floats) + } + } + } +} + + + #[derive(Debug, Serialize, Deserialize)] pub struct OpenAIError { pub error: OpenAIErrorDetails, diff --git a/golem-embed/embed-openai/src/conversions.rs b/golem-embed/embed-openai/src/conversions.rs index 079df98bf..8dd3afb4f 100644 --- a/golem-embed/embed-openai/src/conversions.rs +++ b/golem-embed/embed-openai/src/conversions.rs @@ -1,32 +1,31 @@ use bytemuck::checked::cast_slice; -use golem_embed::golem::embed::embed::{Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error}; use golem_embed::error::unsupported; +use golem_embed::golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, +}; use crate::client::{EmbeddingRequest, EmbeddingResponse, EncodingFormat}; - - - - - pub fn create_request(inputs: Vec, config: Config) -> Result { let mut input = String::new(); for content in inputs { match content { ContentPart::Text(text) => input.push_str(&text), - ContentPart::Image(_) => - return Err(unsupported("Image embeddings is not supported by OpenAI.")), + ContentPart::Image(_) => { + return Err(unsupported("Image embeddings is not supported by OpenAI.")) + } } } + let model = config + .model + .unwrap_or_else(|| "text-embedding-ada-002".to_string()); - let model = config.model.unwrap_or_else(|| "text-embedding-ada-002".to_string()); - - let encoding_format = config.output_format.map(|format| match format { - golem_embed::golem::embed::embed::OutputFormat::FloatArray => EncodingFormat::Float, - golem_embed::golem::embed::embed::OutputFormat::Binary => EncodingFormat::Base64, - golem_embed::golem::embed::embed::OutputFormat::Base64 => EncodingFormat::Base64, - }); + let encoding_format = match config.output_format { + Some(golem_embed::golem::embed::embed::OutputFormat::FloatArray) => Some(EncodingFormat::Float), + Some(golem_embed::golem::embed::embed::OutputFormat::Base64) => Some(EncodingFormat::Base64), + _ => return Err(unsupported("OpenAI only supports float and base64 output formats.")), + }; let dimension = config.dimensions; @@ -39,18 +38,13 @@ pub fn create_request(inputs: Vec, config: Config) -> Result &[u8] { - cast_slice(f32_vec) -} - -pub fn process_embedding_response(response: EmbeddingResponse) -> Result { +pub fn process_embedding_response( + response: EmbeddingResponse, +) -> Result { let mut embeddings = Vec::new(); - for embeding_data in &response.data{ + for embeding_data in &response.data { let embed = embeding_data.embedding.to_float_vec().map_err(|e| Error { code: golem_embed::golem::embed::embed::ErrorCode::ProviderError, message: e, @@ -67,12 +61,10 @@ pub fn process_embedding_response(response: EmbeddingResponse) -> Result,config:Config,) -> Result { + todo!() + } } diff --git a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit index 904504bc5..838b3c2a5 100644 --- a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit @@ -21,7 +21,7 @@ interface embed { } enum output-dtype { - float32, + float-array, int8, uint8, binary, diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index 61fc4fadb..adaa30b57 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -2,7 +2,7 @@ pub mod error; pub mod config; wit_bindgen::generate!({ - path: "./wit", + path: "../wit", world: "embed-library", generate_all, generate_unused_types: true, diff --git a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit index a7e8be931..b524f9071 100644 --- a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit @@ -21,7 +21,7 @@ interface embed { } enum output-dtype { - float32, + float-array, int8, uint8, binary, @@ -32,7 +32,6 @@ interface embed { invalid-request, model-not-found, unsupported, - authentication-failed, provider-error, rate-limit-exceeded, internal-error, diff --git a/golem-embed/test/.gitignore b/golem-embed/test/.gitignore new file mode 100644 index 000000000..175f32628 --- /dev/null +++ b/golem-embed/test/.gitignore @@ -0,0 +1,2 @@ +golem-temp +target diff --git a/golem-embed/test/.vscode/settings.json b/golem-embed/test/.vscode/settings.json new file mode 100644 index 000000000..7530c05d7 --- /dev/null +++ b/golem-embed/test/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.server.extraEnv": { "CARGO": "cargo-component" } +} \ No newline at end of file diff --git a/golem-embed/test/Cargo.lock b/golem-embed/test/Cargo.lock new file mode 100644 index 000000000..c506269f1 --- /dev/null +++ b/golem-embed/test/Cargo.lock @@ -0,0 +1,1339 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "auditable-serde" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7bf8143dfc3c0258df908843e169b5cc5fcf76c7718bd66135ef4a9cd558c5" +dependencies = [ + "semver", + "serde", + "serde_json", + "topological-sort", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "common-lib" +version = "0.1.0" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "git-version" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" +dependencies = [ + "git-version-macro", +] + +[[package]] +name = "git-version-macro" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "golem-rust" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46aaf34adda9057718d79e808fb323b3247cb34ec9c38ff88e74824d703980dd" +dependencies = [ + "golem-rust-macro", + "golem-wasm-rpc", + "serde", + "serde_json", + "uuid", + "wit-bindgen", +] + +[[package]] +name = "golem-rust-macro" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab4174ebe45b8a1961eedeebc215bbc475aea4bdf4f2baa80cc6222fb0058da" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "golem-wasm-rpc" +version = "1.3.0-dev.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82c94d17e7b23ad4335012364825ce9a30977aaca9ebb385c3e4274be0e0f60" +dependencies = [ + "cargo_metadata", + "chrono", + "git-version", + "uuid", + "wit-bindgen-rt 0.40.0", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "reqwest" +version = "0.12.15" +source = "git+https://github.com/zivergetech/reqwest?branch=update-may-2025#c916d796a87bdace112d24b862142597d1074305" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "mime", + "percent-encoding", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tower-service", + "url", + "wit-bindgen-rt 0.41.0", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "spdx" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" +dependencies = [ + "smallvec", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "test_embed" +version = "0.0.0" +dependencies = [ + "golem-rust", + "log", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + +[[package]] +name = "test_helper" +version = "0.0.0" +dependencies = [ + "golem-rust", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "getrandom", + "serde", + "sha1_smol", +] + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt 0.39.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce1ef0faabbbba6674e97a56bee857ccddf942785a336c8b47b42373c922a91d" +dependencies = [ + "anyhow", + "auditable-serde", + "flate2", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "url", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" +dependencies = [ + "bitflags", + "hashbrown", + "indexmap", + "semver", +] + +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7091ed6c9abfa4e0a2ef3b39d0539da992d841fcf32c255f64fb98764ffee5" +dependencies = [ + "wit-bindgen-rt 0.40.0", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "398c650cec1278cfb72e214ba26ef3440ab726e66401bd39c04f465ee3979e6b" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68faed92ae696b93ea9a7b67ba6c37bf09d72c6d9a70fa824a743c3020212f11" +dependencies = [ + "bitflags", + "futures", + "once_cell", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83903c8dcd8084a8a67ae08190122cf0e25dc37bdc239070a00f47e22d3f0aae" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7bf7f20495bcc7dc9f24c5fbcac9e919ca5ebdb7a1b1841d74447d3c8dd0c60" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "635c3adc595422cbf2341a17fb73a319669cc8d33deed3a48368a841df86b676" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.227.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf445ed5157046e4baf56f9138c124a0824d4d1657e7204d71886ad8ce2fc11" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/golem-embed/test/Cargo.toml b/golem-embed/test/Cargo.toml new file mode 100644 index 000000000..ae41bab4c --- /dev/null +++ b/golem-embed/test/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +resolver = "2" +members = ["components-rust/*", "common-rust/*"] + +[profile.release] +opt-level = "s" +lto = true + +[workspace.dependencies] +golem-rust = { version = "1.6.0", features = [ + "export_load_snapshot", + "export_save_snapshot", + "export_oplog_processor", +] } +reqwest = { git = "https://github.com/zivergetech/reqwest", branch = "update-may-2025", features = [ + "json", +] } +serde = { version = "1.0.0", features = ["derive"] } +serde_json = "1.0" +wit-bindgen-rt = { version = "0.40.0", features = ["bitflags"] } diff --git a/golem-embed/test/common-rust/common-lib/Cargo.toml b/golem-embed/test/common-rust/common-lib/Cargo.toml new file mode 100644 index 000000000..876f1d66d --- /dev/null +++ b/golem-embed/test/common-rust/common-lib/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "common-lib" +version = "0.1.0" +edition = "2021" diff --git a/golem-embed/test/common-rust/common-lib/src/lib.rs b/golem-embed/test/common-rust/common-lib/src/lib.rs new file mode 100644 index 000000000..15c6dcba7 --- /dev/null +++ b/golem-embed/test/common-rust/common-lib/src/lib.rs @@ -0,0 +1,3 @@ +pub fn example_common_function() -> &'static str { + "hello common" +} diff --git a/golem-embed/test/common-rust/golem.yaml b/golem-embed/test/common-rust/golem.yaml new file mode 100644 index 000000000..b13a83894 --- /dev/null +++ b/golem-embed/test/common-rust/golem.yaml @@ -0,0 +1,44 @@ +# Schema for IDEA: +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json +# Schema for vscode-yaml +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json + +# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference + +templates: + rust: + profiles: + debug: + build: + - command: cargo component build + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/debug/{{ component_name | to_snake_case }}.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/debug/{{ component_name | to_snake_case }}.wasm + linkedWasm: ../../golem-temp/components/{{ component_name | to_snake_case }}_debug.wasm + clean: + - src/bindings.rs + release: + build: + - command: cargo component build --release + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/release/{{ component_name | to_snake_case }}.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/release/{{ component_name | to_snake_case }}.wasm + linkedWasm: ../../golem-temp/components/{{ component_name | to_snake_case }}_release.wasm + clean: + - src/bindings.rs + defaultProfile: debug +customCommands: + cargo-clean: + - command: cargo clean diff --git a/golem-embed/test/components-rust/.gitignore b/golem-embed/test/components-rust/.gitignore new file mode 100644 index 000000000..f19eeb7b2 --- /dev/null +++ b/golem-embed/test/components-rust/.gitignore @@ -0,0 +1,2 @@ +/*/src/bindings.rs +/*/wit-generated \ No newline at end of file diff --git a/golem-embed/test/components-rust/test-embed/Cargo.lock b/golem-embed/test/components-rust/test-embed/Cargo.lock new file mode 100644 index 000000000..bc5f25f2e --- /dev/null +++ b/golem-embed/test/components-rust/test-embed/Cargo.lock @@ -0,0 +1,1376 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cc" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "test-openai" +version = "0.0.0" +dependencies = [ + "golem-rust", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "golem-rust" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c967eb388fb81f9b9f4df5d5b6634de803f21cd410c1bf687202794a4fbc0267" +dependencies = [ + "golem-rust-macro", + "serde", + "serde_json", + "uuid", + "wit-bindgen-rt", +] + +[[package]] +name = "golem-rust-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb87f831cfe4371427c63f5f4cabcc3bae1b66974c8fbcf22be9274fee3a7d1" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "git+https://github.com/zivergetech/reqwest?branch=update-jun-2024#1cf59c67b93aa6292961f8948b93df5bca2753b6" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", + "wit-bindgen-rt", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "web-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c7526379ace8709ee9ab9f2bb50f112d95581063a59ef3097d9c10153886c9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/golem-embed/test/components-rust/test-embed/Cargo.toml b/golem-embed/test/components-rust/test-embed/Cargo.toml new file mode 100644 index 000000000..7674a4f44 --- /dev/null +++ b/golem-embed/test/components-rust/test-embed/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "test_embed" +version = "0.0.0" +edition = "2021" + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] +required-features = [] + +[features] +default = ["openai"] +openai = [] + +[dependencies] +# To use common shared libs, use the following: +# common-lib = { path = "../../common-rust/common-lib" } + +golem-rust = { workspace = true } +log = { version = "0.4.27" } +reqwest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +wit-bindgen-rt = { workspace = true } + +[package.metadata.component.target] +path = "wit-generated" + +[package.metadata.component.bindings.with] +"wasi:io/poll@0.2.0" = "golem_rust::wasm_rpc::wasi::io::poll" +"wasi:clocks/wall-clock@0.2.0" = "golem_rust::wasm_rpc::wasi::clocks::wall_clock" +"golem:rpc/types@0.2.0" = "golem_rust::wasm_rpc::golem_rpc_0_2_x::types" + +[package.metadata.component.target.dependencies] +"golem:embed" = { path = "wit-generated/deps/golem-embed" } +"wasi:clocks" = { path = "wit-generated/deps/clocks" } +"wasi:io" = { path = "wit-generated/deps/io" } +"golem:rpc" = { path = "wit-generated/deps/golem-rpc" } +"test:helper-client" = { path = "wit-generated/deps/test_helper-client" } +"test:embed-exports" = { path = "wit-generated/deps/test_embed-exports" } + +[package.metadata.component.bindings] +# See https://github.com/bytecodealliance/cargo-component/blob/main/src/metadata.rs#L62 + +# derives = ["serde::Serialize", "serde::Deserialize"] +# generate_unused_types = true \ No newline at end of file diff --git a/golem-embed/test/components-rust/test-embed/golem.yaml b/golem-embed/test/components-rust/test-embed/golem.yaml new file mode 100644 index 000000000..011931c21 --- /dev/null +++ b/golem-embed/test/components-rust/test-embed/golem.yaml @@ -0,0 +1,70 @@ +# Schema for IDEA: +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json +# Schema for vscode-yaml +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json + +# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference + +components: + test:embed: + profiles: + # DEBUG PROFILES + openai-debug: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --no-default-features --features openai + sources: + - src + - wit-generated + - ../../common-rust + targets: + - target/wasm32-wasip1/debug/test_embed.wasm + - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_openai_plugged.wasm + sources: + - ../../target/wasm32-wasip1/debug/test_embed.wasm + - ../../../../target/wasm32-wasip1/debug/golem_embed_openai.wasm + targets: + - ../../target/wasm32-wasip1/debug/test_openai_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/debug/test_openai_plugged.wasm + linkedWasm: ../../golem-temp/components/test_openai_debug.wasm + clean: + - src/bindings.rs + + # RELEASE PROFILES + openai-release: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --release --no-default-features --features openai + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/release/golem_embed_openai.wasm ../../target/wasm32-wasip1/release/test_embed.wasm -o ../../target/wasm32-wasip1/release/test_openai_plugged.wasm + sources: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - ../../../target/wasm32-wasip1/release/golem_embed_openai.wasm + targets: + - ../../target/wasm32-wasip1/release/test_openai_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/release/test_openai_plugged.wasm + linkedWasm: ../../golem-temp/components/test_openai_release.wasm + clean: + - src/bindings.rs + + defaultProfile: openai-debug + +dependencies: + test:embed: + - target: test:helper + type: wasm-rpc diff --git a/golem-embed/test/components-rust/test-embed/src/lib.rs b/golem-embed/test/components-rust/test-embed/src/lib.rs new file mode 100644 index 000000000..27be5ba98 --- /dev/null +++ b/golem-embed/test/components-rust/test-embed/src/lib.rs @@ -0,0 +1,60 @@ +#[allow(static_mut_refs)] +mod bindings; + +use crate::bindings::exports::test::embed_exports::test_embed_api::*; +use crate::bindings::golem::embed::embed; +use crate::bindings::test::helper_client::test_helper_client::TestHelperApi; +use golem_rust::atomically; + +struct Component; + +#[cfg(feature = "openai")] +const MODEL: &'static str = "text-embedding-3-small"; + +#[cfg(feature = "openai")] +const IMAGE_MODEL: &'static str = "text-embedding-3-small"; + +impl Guest for Component { + /// test1 demonstrates a simple, non-streaming text question-answer interaction with the LLM. + fn test1() -> String { + let config = embed::Config { + model: Some(MODEL.to_string()), + task_type: None, + dimensions: None, + truncation: None, + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + println!("Sending text to LLM..."); + let response = embed::generate( + &[embed::ContentPart::Text("Hello, world!".to_string())], + &config, + ); + + match response { + Ok(response) => { + println!("Response: {:?}", response); + format!("Response: {:?}", response) + } + Err(error) => { + println!("Error: {:?}", error); + format!( + "Error: {:?} {} {}", + error.code, + error.message, + error.provider_error_json.unwrap_or_default() + ) + } + } + } + fn test2() -> String { + todo!() + } + fn test3() -> String { + todo!() + } +} + +bindings::export!(Component with_types_in bindings); diff --git a/golem-embed/test/components-rust/test-embed/wit/test-llm.wit b/golem-embed/test/components-rust/test-embed/wit/test-llm.wit new file mode 100644 index 000000000..6dbabfd16 --- /dev/null +++ b/golem-embed/test/components-rust/test-embed/wit/test-llm.wit @@ -0,0 +1,14 @@ +package test:embed; + +// See https://component-model.bytecodealliance.org/design/wit.html for more details about the WIT syntax + +interface test-embed-api { + test1: func() -> string; + test2: func() -> string; + test3: func() -> string; +} + +world test-embed { + import golem:embed/embed@1.0.0; + export test-embed-api; +} diff --git a/golem-embed/test/components-rust/test-helper/Cargo.lock b/golem-embed/test/components-rust/test-helper/Cargo.lock new file mode 100644 index 000000000..bd98b1898 --- /dev/null +++ b/golem-embed/test/components-rust/test-helper/Cargo.lock @@ -0,0 +1,1376 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cc" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "test-helper" +version = "0.0.0" +dependencies = [ + "golem-rust", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "golem-rust" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c967eb388fb81f9b9f4df5d5b6634de803f21cd410c1bf687202794a4fbc0267" +dependencies = [ + "golem-rust-macro", + "serde", + "serde_json", + "uuid", + "wit-bindgen-rt", +] + +[[package]] +name = "golem-rust-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb87f831cfe4371427c63f5f4cabcc3bae1b66974c8fbcf22be9274fee3a7d1" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "git+https://github.com/zivergetech/reqwest?branch=update-jun-2024#1cf59c67b93aa6292961f8948b93df5bca2753b6" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", + "wit-bindgen-rt", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "web-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c7526379ace8709ee9ab9f2bb50f112d95581063a59ef3097d9c10153886c9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/golem-embed/test/components-rust/test-helper/Cargo.toml b/golem-embed/test/components-rust/test-helper/Cargo.toml new file mode 100644 index 000000000..121fb6a40 --- /dev/null +++ b/golem-embed/test/components-rust/test-helper/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "test_helper" +version = "0.0.0" +edition = "2021" + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] +required-features = [] + +[dependencies] +# To use common shared libs, use the following: +# common-lib = { path = "../../common-rust/common-lib" } + +golem-rust = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +wit-bindgen-rt = { workspace = true } + +[package.metadata.component.target] +path = "wit-generated" + +[package.metadata.component.bindings.with] + +[package.metadata.component.target.dependencies] +"test:helper-exports" = { path = "wit-generated/deps/test_helper-exports" } + +[package.metadata.component.bindings] +# See https://github.com/bytecodealliance/cargo-component/blob/main/src/metadata.rs#L62 + +# derives = ["serde::Serialize", "serde::Deserialize"] +# generate_unused_types = true \ No newline at end of file diff --git a/golem-embed/test/components-rust/test-helper/golem.yaml b/golem-embed/test/components-rust/test-helper/golem.yaml new file mode 100644 index 000000000..4c1a11ae1 --- /dev/null +++ b/golem-embed/test/components-rust/test-helper/golem.yaml @@ -0,0 +1,18 @@ +# Schema for IDEA: +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json +# Schema for vscode-yaml +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json + +# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference + +components: + test:helper: + template: rust + +# Example for adding dependencies for Worker to Worker communication: +# See https://learn.golem.cloud/docs/app-manifest#fields_dependencies for more information +# +#dependencies: +# test:helper: +# - target: +# type: wasm-rpc diff --git a/golem-embed/test/components-rust/test-helper/src/lib.rs b/golem-embed/test/components-rust/test-helper/src/lib.rs new file mode 100644 index 000000000..52ed26b30 --- /dev/null +++ b/golem-embed/test/components-rust/test-helper/src/lib.rs @@ -0,0 +1,38 @@ +#[allow(static_mut_refs)] +mod bindings; + +use crate::bindings::exports::test::helper_exports::test_helper_api::*; +// Import for using common lib (also see Cargo.toml for adding the dependency): +// use common_lib::example_common_function; +use std::cell::RefCell; + +/// This is one of any number of data types that our application +/// uses. Golem will take care to persist all application state, +/// whether that state is local to a function being executed or +/// global across the entire program. +struct State { + total: u64, +} + +thread_local! { + /// This holds the state of our application. + static STATE: RefCell = RefCell::new(State { + total: 0, + }); +} + +struct Component; + +impl Guest for Component { + fn inc_and_get() -> u64 { + // Call code from shared lib + // println!("{}", example_common_function()); + + STATE.with_borrow_mut(|state| { + state.total += 1; + state.total + }) + } +} + +bindings::export!(Component with_types_in bindings); diff --git a/golem-embed/test/components-rust/test-helper/wit/test-helper.wit b/golem-embed/test/components-rust/test-helper/wit/test-helper.wit new file mode 100644 index 000000000..fec4ac2d2 --- /dev/null +++ b/golem-embed/test/components-rust/test-helper/wit/test-helper.wit @@ -0,0 +1,9 @@ +package test:helper; + +interface test-helper-api { + inc-and-get: func() -> u64; +} + +world test-helper { + export test-helper-api; +} diff --git a/golem-embed/test/data/cat.png b/golem-embed/test/data/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..ce3de7efdd03ee67ad2f97db01d9b353687ec3b2 GIT binary patch literal 34010 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 KMNUMnLSTX>U*<>v literal 0 HcmV?d00001 diff --git a/golem-embed/test/golem.yaml b/golem-embed/test/golem.yaml new file mode 100644 index 000000000..65b9f3aff --- /dev/null +++ b/golem-embed/test/golem.yaml @@ -0,0 +1,12 @@ +# Schema for IDEA: +# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json +# Schema for vscode-yaml +# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json + +# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference + +includes: + - common-*/golem.yaml + - components-*/*/golem.yaml +witDeps: + - wit/deps diff --git a/golem-embed/test/wit/deps/golem-embed/golem-embed.wit b/golem-embed/test/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..838b3c2a5 --- /dev/null +++ b/golem-embed/test/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,130 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float-array, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} + + +world embed-library { + export embed; +} \ No newline at end of file diff --git a/golem-embed/test/wit/deps/io/error.wit b/golem-embed/test/wit/deps/io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/test/wit/deps/io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/test/wit/deps/io/poll.wit b/golem-embed/test/wit/deps/io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/test/wit/deps/io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/test/wit/deps/io/streams.wit b/golem-embed/test/wit/deps/io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/test/wit/deps/io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/test/wit/deps/io/world.wit b/golem-embed/test/wit/deps/io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/test/wit/deps/io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/wit/golem-embed.wit b/golem-embed/wit/golem-embed.wit index d9b30ef9c..78d040320 100644 --- a/golem-embed/wit/golem-embed.wit +++ b/golem-embed/wit/golem-embed.wit @@ -21,7 +21,7 @@ interface embed { } enum output-dtype { - float32, + float-array, int8, uint8, binary, @@ -32,6 +32,7 @@ interface embed { invalid-request, model-not-found, unsupported, + authentication-failed, provider-error, rate-limit-exceeded, internal-error, @@ -123,7 +124,6 @@ interface embed { ) -> result; } - world embed-library { - export embed; + export embed; } \ No newline at end of file From 5b63d0c9f7cd904f19332eb6755c96a61fdd9a56 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Tue, 3 Jun 2025 13:21:41 +0000 Subject: [PATCH 09/36] wip --- golem-embed/embed-cohere/src/client.rs | 8 +- golem-embed/embed-cohere/src/conversions.rs | 123 ++++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index fa10fc452..139882b40 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -64,7 +64,7 @@ fn parse_response(response: Response) -> Result(response: &str) -> Result { +fn parse_json(response: &str) -> Result { serde_json::from_str::(response) } @@ -319,6 +319,10 @@ mod tests { }"#; let result = parse_json::(json_data); - print!("{:#?}", result.unwrap()); + print!("{:?}", result); + assert!(result.is_ok()); + + // TODO: print the response on the console + } } diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index d16f62f17..afd527d91 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -104,3 +104,126 @@ pub fn image_to_base64(source: &str) -> Result Result { + let mut embeddings: Vec = Vec::new(); + if let Some(emdeddings_array) = &response.embeddings.int8 { + for int_embedding in emdeddings_array { + let float_embedding = int_embedding.iter().map(|&v| v as f32).collect(); + embeddings.push(Embedding { + index: 0, + vector: float_embedding, + }); + } + } + + if let Some(emdeddings_array) = &response.embeddings.uint8 { + for uint_embedding in emdeddings_array { + let float_embedding = uint_embedding.iter().map(|&v| v as f32).collect(); + embeddings.push(Embedding { + index: 0, + vector: float_embedding, + }); + } + } + if let Some(emdeddings_array) = &response.embeddings.binary { + for binary_embedding in emdeddings_array { + let float_embedding = binary_embedding.iter().map(|&v| v as f32).collect(); + embeddings.push(Embedding { + index: 0, + vector: float_embedding, + }); + } + } + if let Some(emdeddings_array) = &response.embeddings.ubinary { + for ubinary_embedding in emdeddings_array { + let float_embedding = ubinary_embedding.iter().map(|&v| v as f32).collect(); + embeddings.push(Embedding { + index: 0, + vector: float_embedding, + }); + } + } + if let Some(emdeddings_array) = &response.embeddings.float { + for float_embedding in emdeddings_array { + embeddings.push(Embedding { + index: 0, + vector: float_embedding.to_vec(), + }); + } + } + + Ok(GolemEmbeddingResponse { + embeddings: embeddings, + usage: todo!(), + model: todo!(), + provider_metadata_json: todo!(), + }) +} + +#[cfg(test)] +mod test { + use super::*; + use serde_json; + + fn test_conversion() { + let data = EmbeddingResponse { + id: "54910170-852f-4322-9767-63d36e55c3bf".to_owned(), + images: None, + texts: Some(["This is the sentence I want to embed.", "Hey !"]), + embeddings: EmbeddingData { + float: Some([ + [ + 0.016967773, + 0.031982422, + 0.041503906, + 0.0021514893, + 0.008178711, + -0.029541016, + -0.018432617, + -0.046875, + 0.021240234, + ], + [ + 0.013977051, + 0.012084961, + 0.005554199, + -0.053955078, + -0.026977539, + -0.008361816, + 0.02368164, + -0.013183594, + -0.063964844, + 0.026611328, + ], + ]), + int8: Some([ + [ + -15, -65, 0, -31, -43, -14, -48, 59, -34, 15, 36, 49, -5, 3, -49, -34, -74, + 21, + ], + [ + 14, 38, -30, -13, -49, 4, -33, -49, 48, 9, -84, 8, 0, -84, -46, -20, 24, + -26, -98, 28, + ], + ]), + uint8: None, + binary: Some([[-54, 99, -87, 60, 15, 10, 93, 97, -42, -51, 9]]), + ubinary: None, + }, + meta: Some(Meta { + api_version: Some(ApiVersion { version: Some("2") }), + billed_units: Some(BilledUnits { + input_tokens: Some(11), + }), + }), + response_type: Some("embeddings_by_type".to_owned()), + }; + + let result = process_embedding_response(data); + print!("{:?}", result); + assert!(result.is_ok()) + } +} From da962842c1f9254f1edc980c2de3a8b06773473a Mon Sep 17 00:00:00 2001 From: Rutik Thakre Date: Tue, 3 Jun 2025 14:35:10 +0000 Subject: [PATCH 10/36] cohere generate --- Cargo.lock | 1 + golem-embed/embed-cohere/src/conversions.rs | 68 +++++++++++++++------ golem-embed/embed-cohere/src/lib.rs | 24 ++++---- golem-embed/embed-openai/Cargo.toml | 13 ++-- 4 files changed, 68 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9db93cbb9..851d96eff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,6 +370,7 @@ dependencies = [ name = "golem-embed-openai" version = "0.0.0" dependencies = [ + "base64 0.22.1", "bytemuck", "golem-embed", "golem-rust", diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index afd527d91..45e9f443a 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -107,6 +107,7 @@ pub fn image_to_base64(source: &str) -> Result Result { let mut embeddings: Vec = Vec::new(); if let Some(emdeddings_array) = &response.embeddings.int8 { @@ -117,7 +118,7 @@ pub fn process_embedding_response( vector: float_embedding, }); } - } + }; if let Some(emdeddings_array) = &response.embeddings.uint8 { for uint_embedding in emdeddings_array { @@ -127,7 +128,7 @@ pub fn process_embedding_response( vector: float_embedding, }); } - } + }; if let Some(emdeddings_array) = &response.embeddings.binary { for binary_embedding in emdeddings_array { let float_embedding = binary_embedding.iter().map(|&v| v as f32).collect(); @@ -136,7 +137,7 @@ pub fn process_embedding_response( vector: float_embedding, }); } - } + }; if let Some(emdeddings_array) = &response.embeddings.ubinary { for ubinary_embedding in emdeddings_array { let float_embedding = ubinary_embedding.iter().map(|&v| v as f32).collect(); @@ -145,7 +146,7 @@ pub fn process_embedding_response( vector: float_embedding, }); } - } + }; if let Some(emdeddings_array) = &response.embeddings.float { for float_embedding in emdeddings_array { embeddings.push(Embedding { @@ -153,29 +154,45 @@ pub fn process_embedding_response( vector: float_embedding.to_vec(), }); } - } + }; Ok(GolemEmbeddingResponse { embeddings: embeddings, - usage: todo!(), - model: todo!(), - provider_metadata_json: todo!(), + provider_metadata_json: Some(get_provider_metadata(response.clone())), + model: config + .model + .unwrap_or_else(|| "embed-english-v3.0".to_string()), + usage: Some(Usage { + input_tokens: response.meta.unwrap().billed_units.unwrap().input_tokens, + total_tokens: None, + }), }) } +pub fn get_provider_metadata(response: EmbeddingResponse) -> String { + let meta = serde_json::to_string(&response.meta.unwrap()).unwrap_or_default(); + format!(r#"{{"id":"{}","meta":"{}",}}"#, response.id, meta) +} + #[cfg(test)] -mod test { +mod tests { + use crate::client::{ApiVersion, BilledUnits, Meta}; + use super::*; use serde_json; + #[test] fn test_conversion() { let data = EmbeddingResponse { id: "54910170-852f-4322-9767-63d36e55c3bf".to_owned(), images: None, - texts: Some(["This is the sentence I want to embed.", "Hey !"]), + texts: Some(vec![ + "This is the sentence I want to embed.".to_owned(), + "Hey !".to_owned(), + ]), embeddings: EmbeddingData { - float: Some([ - [ + float: Some(vec![ + vec![ 0.016967773, 0.031982422, 0.041503906, @@ -186,7 +203,7 @@ mod test { -0.046875, 0.021240234, ], - [ + vec![ 0.013977051, 0.012084961, 0.005554199, @@ -199,22 +216,24 @@ mod test { 0.026611328, ], ]), - int8: Some([ - [ + int8: Some(vec![ + vec![ -15, -65, 0, -31, -43, -14, -48, 59, -34, 15, 36, 49, -5, 3, -49, -34, -74, 21, ], - [ + vec![ 14, 38, -30, -13, -49, 4, -33, -49, 48, 9, -84, 8, 0, -84, -46, -20, 24, -26, -98, 28, ], ]), uint8: None, - binary: Some([[-54, 99, -87, 60, 15, 10, 93, 97, -42, -51, 9]]), + binary: Some(vec![vec![-54, 99, -87, 60, 15, 10, 93, 97, -42, -51, 9]]), ubinary: None, }, meta: Some(Meta { - api_version: Some(ApiVersion { version: Some("2") }), + api_version: Some(ApiVersion { + version: Some("2".to_owned()), + }), billed_units: Some(BilledUnits { input_tokens: Some(11), }), @@ -222,7 +241,18 @@ mod test { response_type: Some("embeddings_by_type".to_owned()), }; - let result = process_embedding_response(data); + let config = Config { + model: Some("embed-english-v3.0".to_string()), + task_type: None, + dimensions: None, + truncation: None, + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + + let result = process_embedding_response(data, config); print!("{:?}", result); assert!(result.is_ok()) } diff --git a/golem-embed/embed-cohere/src/lib.rs b/golem-embed/embed-cohere/src/lib.rs index 90a5749ed..c768867e2 100644 --- a/golem-embed/embed-cohere/src/lib.rs +++ b/golem-embed/embed-cohere/src/lib.rs @@ -1,5 +1,5 @@ use client::{EmbeddingResponse, EmbeddingsApi}; -use conversions::{create_request}; +use conversions::create_request; use golem_embed::{ config::with_config_key, golem::embed::embed::{ @@ -9,6 +9,8 @@ use golem_embed::{ LOGGING_STATE, }; +use crate::conversions::process_embedding_response; + mod client; mod conversions; @@ -22,15 +24,14 @@ impl CohereComponent { inputs: Vec, config: Config, ) -> Result { - todo!() - // let request = create_request(inputs, config); - // match request { - // Ok(request) => match client.generate_embeding(request) { - // Ok(response) => process_embedding_response(response), - // Err(err) => Err(err), - // }, - // Err(err) => Err(err), - // } + let request = create_request(inputs, config.clone()); + match request { + Ok(request) => match client.generate_embeding(request) { + Ok(response) => process_embedding_response(response, config), + Err(err) => Err(err), + }, + Err(err) => Err(err), + } } fn rerank( @@ -63,6 +64,3 @@ impl Guest for CohereComponent { todo!() } } - - - diff --git a/golem-embed/embed-openai/Cargo.toml b/golem-embed/embed-openai/Cargo.toml index d3f7f5b07..78001cb85 100644 --- a/golem-embed/embed-openai/Cargo.toml +++ b/golem-embed/embed-openai/Cargo.toml @@ -18,28 +18,29 @@ durability = ["golem-rust/durability", "golem-embed/durability"] [dependencies] -golem-embed= {path="../embed", version="0.0.0", default-features= false} +golem-embed = { path = "../embed", version = "0.0.0", default-features = false } golem-rust = { workspace = true } log = { workspace = true } reqwest = { workspace = true } -serde = {workspace = true} +serde = { workspace = true } serde_json = { workspace = true } +base64 = { workspace = true } wit-bindgen-rt = { workspace = true } bytemuck = "1.23.0" [package.metadata.component] -package="golem:embed-openai" +package = "golem:embed-openai" [package.metadata.component.bindings] -generate_unused_types=true +generate_unused_types = true [package.metadata.component.bindings.with] -"golem:embed/embed@1.0.0"= "golem_embed::golem::embed::embed" +"golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" [package.metadata.component.target] path = "wit" [package.metadata.component.target.dependencies] "golem:embed" = { path = "wit/deps/golem-embed" } -"wasi:io" = { path = "wit/deps/wasi:io"} +"wasi:io" = { path = "wit/deps/wasi:io" } From a71efeec5c8d24dee8be1188ec5798a7d9757c6c Mon Sep 17 00:00:00 2001 From: Rutik Thakre Date: Tue, 3 Jun 2025 19:04:56 +0000 Subject: [PATCH 11/36] init hugging_face --- Cargo.lock | 15 + Cargo.toml | 16 +- .../embed-hugging-face/.vscode/settings.json | 10 + golem-embed/embed-hugging-face/Cargo.toml | 46 +++ .../embed-hugging-face/src/bindings.rs | 109 +++++++ golem-embed/embed-hugging-face/src/client.rs | 0 .../embed-hugging-face/src/conversitions.rs | 0 golem-embed/embed-hugging-face/src/lib.rs | 2 + .../wit/deps/golem-embed/golem-embed.wit | 130 ++++++++ .../wit/deps/wasi:io/error.wit | 34 ++ .../wit/deps/wasi:io/poll.wit | 47 +++ .../wit/deps/wasi:io/streams.wit | 290 ++++++++++++++++++ .../wit/deps/wasi:io/world.wit | 10 + .../embed-hugging-face/wit/hugging_face.wit | 5 + 14 files changed, 707 insertions(+), 7 deletions(-) create mode 100644 golem-embed/embed-hugging-face/.vscode/settings.json create mode 100644 golem-embed/embed-hugging-face/Cargo.toml create mode 100644 golem-embed/embed-hugging-face/src/bindings.rs create mode 100644 golem-embed/embed-hugging-face/src/client.rs create mode 100644 golem-embed/embed-hugging-face/src/conversitions.rs create mode 100644 golem-embed/embed-hugging-face/src/lib.rs create mode 100644 golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit create mode 100644 golem-embed/embed-hugging-face/wit/deps/wasi:io/error.wit create mode 100644 golem-embed/embed-hugging-face/wit/deps/wasi:io/poll.wit create mode 100644 golem-embed/embed-hugging-face/wit/deps/wasi:io/streams.wit create mode 100644 golem-embed/embed-hugging-face/wit/deps/wasi:io/world.wit create mode 100644 golem-embed/embed-hugging-face/wit/hugging_face.wit diff --git a/Cargo.lock b/Cargo.lock index 851d96eff..3e1631d80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -366,6 +366,21 @@ dependencies = [ "wit-bindgen-rt 0.40.0", ] +[[package]] +name = "golem-embed-hugging-face" +version = "0.0.0" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "golem-embed", + "golem-rust", + "log", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + [[package]] name = "golem-embed-openai" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index c0f2e92b0..456639987 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,17 @@ [workspace] resolver = "2" -members = [ - "golem-embed/embed", "golem-embed/embed-cohere", - "golem-embed/embed-openai", - "golem-llm/llm", +members = [ + "golem-embed/embed", + "golem-embed/embed-cohere", + "golem-embed/embed-hugging-face", + "golem-embed/embed-openai", + "golem-llm/llm", "golem-llm/llm-anthropic", - "golem-llm/llm-grok", + "golem-llm/llm-grok", "golem-llm/llm-ollama", - "golem-llm/llm-openai", - "golem-llm/llm-openrouter" + "golem-llm/llm-openai", + "golem-llm/llm-openrouter", ] [profile.release] diff --git a/golem-embed/embed-hugging-face/.vscode/settings.json b/golem-embed/embed-hugging-face/.vscode/settings.json new file mode 100644 index 000000000..b945667b6 --- /dev/null +++ b/golem-embed/embed-hugging-face/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "rust-analyzer.check.overrideCommand": [ + "cargo", + "component", + "check", + "--workspace", + "--all-targets", + "--message-format=json" + ], +} diff --git a/golem-embed/embed-hugging-face/Cargo.toml b/golem-embed/embed-hugging-face/Cargo.toml new file mode 100644 index 000000000..846e853c4 --- /dev/null +++ b/golem-embed/embed-hugging-face/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "golem-embed-hugging-face" +version = "0.0.0" +edition = "2021" +license = "Apache-2.0" +homepage = "https://golem.cloud" +repository = "https://github.com/golemcloud/golem-llm" +description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" + + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["durability"] +durability = ["golem-rust/durability", "golem-embed/durability"] + + +[dependencies] +golem-embed = { path = "../embed", version = "0.0.0", default-features = false } +golem-rust = { workspace = true } +log = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +base64 = { workspace = true } +wit-bindgen-rt = { workspace = true } +bytemuck = "1.23.0" + + +[package.metadata.component] +package = "golem:embed-hugging-face" + +[package.metadata.component.bindings] +generate_unused_types = true + +[package.metadata.component.bindings.with] +"golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.target.dependencies] +"golem:embed" = { path = "wit/deps/golem-embed" } +"wasi:io" = { path = "wit/deps/wasi:io" } diff --git a/golem-embed/embed-hugging-face/src/bindings.rs b/golem-embed/embed-hugging-face/src/bindings.rs new file mode 100644 index 000000000..7b95e9297 --- /dev/null +++ b/golem-embed/embed-hugging-face/src/bindings.rs @@ -0,0 +1,109 @@ +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! +// Options used: +// * runtime_path: "wit_bindgen_rt" +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn _export_hello_world_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::hello_world(); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn __post_return_hello_world(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(::core::mem::size_of::<*const u8>()).cast::(); + _rt::cabi_dealloc(l0, l1, 1); +} +pub trait Guest { + fn hello_world() -> _rt::String; +} +#[doc(hidden)] +macro_rules! __export_world_example_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = "hello-world")] unsafe extern "C" fn + export_hello_world() -> * mut u8 { unsafe { $($path_to_types)*:: + _export_hello_world_cabi::<$ty > () } } #[unsafe (export_name = + "cabi_post_hello-world")] unsafe extern "C" fn _post_return_hello_world(arg0 : * + mut u8,) { unsafe { $($path_to_types)*:: __post_return_hello_world::<$ty > (arg0) + } } }; + }; +} +#[doc(hidden)] +pub(crate) use __export_world_example_cabi; +#[cfg_attr(target_pointer_width = "64", repr(align(8)))] +#[cfg_attr(target_pointer_width = "32", repr(align(4)))] +struct _RetArea([::core::mem::MaybeUninit; 2 * ::core::mem::size_of::<*const u8>()]); +static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 2 * ::core::mem::size_of::<*const u8>()], +); +#[rustfmt::skip] +mod _rt { + #![allow(dead_code, clippy::all)] + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr, layout); + } + pub use alloc_crate::string::String; + pub use alloc_crate::alloc; + extern crate alloc as alloc_crate; +} +/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as +/// the root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] +macro_rules! __export_example_impl { + ($ty:ident) => { + self::export!($ty with_types_in self); + }; + ($ty:ident with_types_in $($path_to_types_root:tt)*) => { + $($path_to_types_root)*:: __export_world_example_cabi!($ty with_types_in + $($path_to_types_root)*); + }; +} +#[doc(inline)] +pub(crate) use __export_example_impl as export; +#[cfg(target_arch = "wasm32")] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:component:embed-hugging-face:example:encoded world" +)] +#[doc(hidden)] +#[allow(clippy::octal_escapes)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 193] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07D\x01A\x02\x01A\x02\x01\ +@\0\0s\x04\0\x0bhello-world\x01\0\x04\0$component:embed-hugging-face/example\x04\ +\0\x0b\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dw\ +it-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +#[inline(never)] +#[doc(hidden)] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs new file mode 100644 index 000000000..e69de29bb diff --git a/golem-embed/embed-hugging-face/src/conversitions.rs b/golem-embed/embed-hugging-face/src/conversitions.rs new file mode 100644 index 000000000..e69de29bb diff --git a/golem-embed/embed-hugging-face/src/lib.rs b/golem-embed/embed-hugging-face/src/lib.rs new file mode 100644 index 000000000..3ac1b9392 --- /dev/null +++ b/golem-embed/embed-hugging-face/src/lib.rs @@ -0,0 +1,2 @@ +mod client; +mod conversitions; diff --git a/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..838b3c2a5 --- /dev/null +++ b/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,130 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float-array, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} + + +world embed-library { + export embed; +} \ No newline at end of file diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/error.wit b/golem-embed/embed-hugging-face/wit/deps/wasi:io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/embed-hugging-face/wit/deps/wasi:io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/poll.wit b/golem-embed/embed-hugging-face/wit/deps/wasi:io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/embed-hugging-face/wit/deps/wasi:io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/streams.wit b/golem-embed/embed-hugging-face/wit/deps/wasi:io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/embed-hugging-face/wit/deps/wasi:io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/world.wit b/golem-embed/embed-hugging-face/wit/deps/wasi:io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/embed-hugging-face/wit/deps/wasi:io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/embed-hugging-face/wit/hugging_face.wit b/golem-embed/embed-hugging-face/wit/hugging_face.wit new file mode 100644 index 000000000..ea0e51730 --- /dev/null +++ b/golem-embed/embed-hugging-face/wit/hugging_face.wit @@ -0,0 +1,5 @@ +package golem:embed-hugging-face@1.0.0; + +world embed-library { + include golem:embed/embed-library@1.0.0; +} From a70afbfd9d5f05fb5f4eb6d68603df538a5fa6d3 Mon Sep 17 00:00:00 2001 From: Rutik Thakre Date: Thu, 5 Jun 2025 09:47:24 +0000 Subject: [PATCH 12/36] wip --- Cargo.lock | 15 + Cargo.toml | 2 +- golem-embed/embed-hugging-face/src/client.rs | 25 ++ golem-embed/embed-voyageai/Cargo.toml | 46 +++ golem-embed/embed-voyageai/src/bindings.rs | 109 +++++++ golem-embed/embed-voyageai/src/client.rs | 1 + .../embed-voyageai/src/conversitions.rs | 0 golem-embed/embed-voyageai/src/lib.rs | 2 + .../wit/deps/golem-embed/golem-embed.wit | 130 ++++++++ .../embed-voyageai/wit/deps/wasi:io/error.wit | 34 ++ .../embed-voyageai/wit/deps/wasi:io/poll.wit | 47 +++ .../wit/deps/wasi:io/streams.wit | 290 ++++++++++++++++++ .../embed-voyageai/wit/deps/wasi:io/world.wit | 10 + golem-embed/embed-voyageai/wit/voyageai.wit | 5 + golem-embed/test/.vscode/settings.json | 3 - 15 files changed, 715 insertions(+), 4 deletions(-) create mode 100644 golem-embed/embed-voyageai/Cargo.toml create mode 100644 golem-embed/embed-voyageai/src/bindings.rs create mode 100644 golem-embed/embed-voyageai/src/client.rs create mode 100644 golem-embed/embed-voyageai/src/conversitions.rs create mode 100644 golem-embed/embed-voyageai/src/lib.rs create mode 100644 golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit create mode 100644 golem-embed/embed-voyageai/wit/deps/wasi:io/error.wit create mode 100644 golem-embed/embed-voyageai/wit/deps/wasi:io/poll.wit create mode 100644 golem-embed/embed-voyageai/wit/deps/wasi:io/streams.wit create mode 100644 golem-embed/embed-voyageai/wit/deps/wasi:io/world.wit create mode 100644 golem-embed/embed-voyageai/wit/voyageai.wit delete mode 100644 golem-embed/test/.vscode/settings.json diff --git a/Cargo.lock b/Cargo.lock index 3e1631d80..4d028dcc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,6 +396,21 @@ dependencies = [ "wit-bindgen-rt 0.40.0", ] +[[package]] +name = "golem-embed-voyageai" +version = "0.0.0" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "golem-embed", + "golem-rust", + "log", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + [[package]] name = "golem-llm" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index 456639987..8c244eeeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "golem-embed/embed", "golem-embed/embed-cohere", "golem-embed/embed-hugging-face", - "golem-embed/embed-openai", + "golem-embed/embed-openai", "golem-embed/embed-voyageai", "golem-llm/llm", "golem-llm/llm-anthropic", "golem-llm/llm-grok", diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs index e69de29bb..48fc88156 100644 --- a/golem-embed/embed-hugging-face/src/client.rs +++ b/golem-embed/embed-hugging-face/src/client.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingRequest { + pub input: Vec, + pub normalize: Option, + /// The name of the prompt that should be used by for encoding. + /// If not set, no prompt will be applied. Must be a key in the + /// sentence-transformers configuration prompts dictionary. + /// For example if prompt_name is “query” and the prompts is {“query”: “query: ”, …}, + /// then the sentence “What is the capital of France?” will be encoded as + /// “query: What is the capital of France?” because the prompt text will + /// be prepended before any text to encode. + pub prompt_name: Option, + pub truncate: Option, + pub truncate_direction: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum TruncateDirection { + #[serde(rename = "left")] + Left, + #[serde(rename = "right")] + Right, +} diff --git a/golem-embed/embed-voyageai/Cargo.toml b/golem-embed/embed-voyageai/Cargo.toml new file mode 100644 index 000000000..5def70463 --- /dev/null +++ b/golem-embed/embed-voyageai/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "golem-embed-voyageai" +version = "0.0.0" +edition = "2021" +license = "Apache-2.0" +homepage = "https://golem.cloud" +repository = "https://github.com/golemcloud/golem-llm" +description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" + + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib"] + +[features] +default = ["durability"] +durability = ["golem-rust/durability", "golem-embed/durability"] + + +[dependencies] +golem-embed = { path = "../embed", version = "0.0.0", default-features = false } +golem-rust = { workspace = true } +log = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +base64 = { workspace = true } +wit-bindgen-rt = { workspace = true } +bytemuck = "1.23.0" + + +[package.metadata.component] +package = "golem:embed-voyageai" + +[package.metadata.component.bindings] +generate_unused_types = true + +[package.metadata.component.bindings.with] +"golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.target.dependencies] +"golem:embed" = { path = "wit/deps/golem-embed" } +"wasi:io" = { path = "wit/deps/wasi:io" } diff --git a/golem-embed/embed-voyageai/src/bindings.rs b/golem-embed/embed-voyageai/src/bindings.rs new file mode 100644 index 000000000..7bd4d38d3 --- /dev/null +++ b/golem-embed/embed-voyageai/src/bindings.rs @@ -0,0 +1,109 @@ +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! +// Options used: +// * runtime_path: "wit_bindgen_rt" +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn _export_hello_world_cabi() -> *mut u8 { + #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); + let result0 = T::hello_world(); + let ptr1 = (&raw mut _RET_AREA.0).cast::(); + let vec2 = (result0.into_bytes()).into_boxed_slice(); + let ptr2 = vec2.as_ptr().cast::(); + let len2 = vec2.len(); + ::core::mem::forget(vec2); + *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; + *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); + ptr1 +} +#[doc(hidden)] +#[allow(non_snake_case)] +pub unsafe fn __post_return_hello_world(arg0: *mut u8) { + let l0 = *arg0.add(0).cast::<*mut u8>(); + let l1 = *arg0.add(::core::mem::size_of::<*const u8>()).cast::(); + _rt::cabi_dealloc(l0, l1, 1); +} +pub trait Guest { + fn hello_world() -> _rt::String; +} +#[doc(hidden)] +macro_rules! __export_world_example_cabi { + ($ty:ident with_types_in $($path_to_types:tt)*) => { + const _ : () = { #[unsafe (export_name = "hello-world")] unsafe extern "C" fn + export_hello_world() -> * mut u8 { unsafe { $($path_to_types)*:: + _export_hello_world_cabi::<$ty > () } } #[unsafe (export_name = + "cabi_post_hello-world")] unsafe extern "C" fn _post_return_hello_world(arg0 : * + mut u8,) { unsafe { $($path_to_types)*:: __post_return_hello_world::<$ty > (arg0) + } } }; + }; +} +#[doc(hidden)] +pub(crate) use __export_world_example_cabi; +#[cfg_attr(target_pointer_width = "64", repr(align(8)))] +#[cfg_attr(target_pointer_width = "32", repr(align(4)))] +struct _RetArea([::core::mem::MaybeUninit; 2 * ::core::mem::size_of::<*const u8>()]); +static mut _RET_AREA: _RetArea = _RetArea( + [::core::mem::MaybeUninit::uninit(); 2 * ::core::mem::size_of::<*const u8>()], +); +#[rustfmt::skip] +mod _rt { + #![allow(dead_code, clippy::all)] + #[cfg(target_arch = "wasm32")] + pub fn run_ctors_once() { + wit_bindgen_rt::run_ctors_once(); + } + pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { + if size == 0 { + return; + } + let layout = alloc::Layout::from_size_align_unchecked(size, align); + alloc::dealloc(ptr, layout); + } + pub use alloc_crate::string::String; + pub use alloc_crate::alloc; + extern crate alloc as alloc_crate; +} +/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as +/// the root implementation of all generated traits. +/// +/// For more information see the documentation of `wit_bindgen::generate!`. +/// +/// ```rust +/// # macro_rules! export{ ($($t:tt)*) => (); } +/// # trait Guest {} +/// struct MyType; +/// +/// impl Guest for MyType { +/// // ... +/// } +/// +/// export!(MyType); +/// ``` +#[allow(unused_macros)] +#[doc(hidden)] +macro_rules! __export_example_impl { + ($ty:ident) => { + self::export!($ty with_types_in self); + }; + ($ty:ident with_types_in $($path_to_types_root:tt)*) => { + $($path_to_types_root)*:: __export_world_example_cabi!($ty with_types_in + $($path_to_types_root)*); + }; +} +#[doc(inline)] +pub(crate) use __export_example_impl as export; +#[cfg(target_arch = "wasm32")] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:component:embed-voyageai:example:encoded world" +)] +#[doc(hidden)] +#[allow(clippy::octal_escapes)] +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 189] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07@\x01A\x02\x01A\x02\x01\ +@\0\0s\x04\0\x0bhello-world\x01\0\x04\0\x20component:embed-voyageai/example\x04\0\ +\x0b\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit\ +-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +#[inline(never)] +#[doc(hidden)] +pub fn __link_custom_section_describing_imports() { + wit_bindgen_rt::maybe_link_cabi_realloc(); +} diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/golem-embed/embed-voyageai/src/client.rs @@ -0,0 +1 @@ + diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/golem-embed/embed-voyageai/src/conversitions.rs new file mode 100644 index 000000000..e69de29bb diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs new file mode 100644 index 000000000..3ac1b9392 --- /dev/null +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -0,0 +1,2 @@ +mod client; +mod conversitions; diff --git a/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..838b3c2a5 --- /dev/null +++ b/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,130 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float-array, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} + + +world embed-library { + export embed; +} \ No newline at end of file diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/error.wit b/golem-embed/embed-voyageai/wit/deps/wasi:io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/golem-embed/embed-voyageai/wit/deps/wasi:io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/poll.wit b/golem-embed/embed-voyageai/wit/deps/wasi:io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/golem-embed/embed-voyageai/wit/deps/wasi:io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/streams.wit b/golem-embed/embed-voyageai/wit/deps/wasi:io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/golem-embed/embed-voyageai/wit/deps/wasi:io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/world.wit b/golem-embed/embed-voyageai/wit/deps/wasi:io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/golem-embed/embed-voyageai/wit/deps/wasi:io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/golem-embed/embed-voyageai/wit/voyageai.wit b/golem-embed/embed-voyageai/wit/voyageai.wit new file mode 100644 index 000000000..175055391 --- /dev/null +++ b/golem-embed/embed-voyageai/wit/voyageai.wit @@ -0,0 +1,5 @@ +package golem:embed-voyageai@1.0.0; + +world embed-library { + include golem:embed/embed-library@1.0.0; +} diff --git a/golem-embed/test/.vscode/settings.json b/golem-embed/test/.vscode/settings.json deleted file mode 100644 index 7530c05d7..000000000 --- a/golem-embed/test/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "rust-analyzer.server.extraEnv": { "CARGO": "cargo-component" } -} \ No newline at end of file From de4c3f4b36956a9dbce5914c5b7130d5648c1b13 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 6 Jun 2025 19:57:54 +0000 Subject: [PATCH 13/36] wip --- .../embed-cohere/.vscode/settings.json | 10 - .../embed-hugging-face/.vscode/settings.json | 10 - golem-embed/embed-voyageai/src/client.rs | 182 ++++++++++++++ .../embed-voyageai/src/conversitions.rs | 233 ++++++++++++++++++ golem-embed/embed-voyageai/src/lib.rs | 51 ++++ 5 files changed, 466 insertions(+), 20 deletions(-) delete mode 100644 golem-embed/embed-cohere/.vscode/settings.json delete mode 100644 golem-embed/embed-hugging-face/.vscode/settings.json diff --git a/golem-embed/embed-cohere/.vscode/settings.json b/golem-embed/embed-cohere/.vscode/settings.json deleted file mode 100644 index b945667b6..000000000 --- a/golem-embed/embed-cohere/.vscode/settings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "rust-analyzer.check.overrideCommand": [ - "cargo", - "component", - "check", - "--workspace", - "--all-targets", - "--message-format=json" - ], -} diff --git a/golem-embed/embed-hugging-face/.vscode/settings.json b/golem-embed/embed-hugging-face/.vscode/settings.json deleted file mode 100644 index b945667b6..000000000 --- a/golem-embed/embed-hugging-face/.vscode/settings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "rust-analyzer.check.overrideCommand": [ - "cargo", - "component", - "check", - "--workspace", - "--all-targets", - "--message-format=json" - ], -} diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs index 8b1378917..d3357cc42 100644 --- a/golem-embed/embed-voyageai/src/client.rs +++ b/golem-embed/embed-voyageai/src/client.rs @@ -1 +1,183 @@ +use std::fmt::Debug; +use golem_embed::{ + error::{error_code_from_status, from_reqwest_error}, + golem::embed::embed::Error, +}; +use log::trace; +use reqwest::{Client, Method, Response}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +const BASE_URL: &str = "https://api.voyageai.com"; + +/// The VoyageAI API client for creating embeddings and reranking. +/// +/// Based on https://docs.voyageai.com/reference/embeddings-api +/// and https://docs.voyageai.com/reference/reranker-api +pub struct VoyageAIApi { + api_key: String, + client: Client, +} + +impl VoyageAIApi { + pub fn new(api_key: String) -> Self { + let client = Client::builder() + .build() + .expect("Failed to initialize HTTP client"); + Self { api_key, client } + } + + pub fn generate_embedding( + &self, + request: EmbeddingRequest, + ) -> Result { + trace!("Sending embedding request to VoyageAI API: {request:?}"); + let response = self + .client + .request(Method::POST, format!("{BASE_URL}/v1/embeddings")) + .bearer_auth(&self.api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Embedding request failed", err))?; + parse_response::(response) + } + + pub fn rerank(&self, request: RerankRequest) -> Result { + trace!("Sending rerank request to VoyageAI API: {request:?}"); + let response = self + .client + .request(Method::POST, format!("{BASE_URL}/v1/rerank")) + .bearer_auth(&self.api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Rerank request failed", err))?; + parse_response::(response) + } +} + +fn parse_response(response: Response) -> Result { + let status = response.status(); + if status.is_success() { + let response_data = response + .json::() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from VoyageAI API: {response_data:?}"); + Ok(response_data) + } else { + let response_data = response + .text() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Error response from VoyageAI API: {response_data:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Request failed with {status}"), + provider_error_json: Some(response_data), + }) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingRequest { + pub input: Vec, + pub model: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub input_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub truncation: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub output_dimension: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub output_dtype: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub encoding_format: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum EncodingFormat { + Base64, +} + + +#[derive(Debug,Serialize, Deserialize, Clone)] +pub enum InputType { + Document, + Query +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum OutputDtype{ + Float, + Int8, + Uint8, + Binary, + Ubinary, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingResponse { + pub object: String, + pub data: Vec, + pub model: String, + pub usage: EmbeddingUsage, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingData { + pub object: String, + pub embedding: Vec, + pub index: u32, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EmbeddingUsage { + pub total_tokens: u32, +} + +// Rerank API structures +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankRequest { + pub query: String, + pub documents: Vec, + pub model: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub top_k: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub return_documents: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub truncation: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankResponse { + pub object: String, + pub data: Vec, + pub model: String, + pub usage: RerankUsage, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankResult { + pub index: u32, + pub relevance_score: f32, + #[serde(skip_serializing_if = "Option::is_none")] + pub document: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankUsage { + pub total_tokens: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VoyageAIError { + pub error: VoyageAIErrorDetails, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct VoyageAIErrorDetails { + pub message: String, + #[serde(rename = "type")] + pub error_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, +} diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/golem-embed/embed-voyageai/src/conversitions.rs index e69de29bb..cf93c997c 100644 --- a/golem-embed/embed-voyageai/src/conversitions.rs +++ b/golem-embed/embed-voyageai/src/conversitions.rs @@ -0,0 +1,233 @@ +use std::{fs, path::Path}; + +use base64::{engine::general_purpose, Engine}; +use golem_embed::{ + error::unsupported, + golem::embed::embed::{ + self, Config, ContentPart, Embedding, EmbeddingResponse as GolemEmbeddingResponse, Error, + OutputDtype as GolemOutputDtype, OutputFormat as GolemOutputFormat, + RerankResponse as GolemRerankResponse, RerankResult as GolemRerankResult, TaskType, Usage, + }, +}; +use log::trace; +use reqwest::{Client, Url}; + +use crate::client::{ + EmbeddingRequest, EmbeddingResponse, InputType, RerankRequest, RerankResponse, +}; + +pub fn create_embedding_request( + inputs: Vec, + config: Config, +) -> Result { + let mut text_inputs = Vec::new(); + + for input in inputs { + match input { + ContentPart::Text(text) => text_inputs.push(text), + ContentPart::Image(image) => { + return Err(unsupported( + "VoyageAI text embeddings do not support image inputs. Use multimodal embeddings instead.", + )); + } + } + } + + let model = config.model.unwrap_or_else(|| "voyage-3.5-lite".to_string()); + + let mut input_type = None; + match config.task_type { + TaskType::RetrievalQuery => input_type = Some(InputType::Query), + TaskType::RetrievalDocument => input_type = Some(InputType::Document), + _ => return Err(unsupported("Unsupported task type")), + }?; + + let output_dtype = match config.output_dtype { + GolemOutputDtype::FloatArray => OutputDtype::FloatArray, + GolemOutputDtype::Int8 => OutputDtype::Int8, + GolemOutputDtype::Uint8 => OutputDtype::Uint8, + GolemOutputDtype::Binary => OutputDtype::Binary, + GolemOutputDtype::Ubinary => OutputDtype::Ubinary, + }; + + let encoding_format = match config.output_format { + GolemOutputFormat::Base64 => OutputFormat::Base64, + _ => None, + }; + + Ok(EmbeddingRequest { + input: text_inputs, + model, + input_type, + truncation: config.truncation, + output_dimension: config.dimensions, + output_dtype, + encoding_format, + }) +} + +pub fn process_embedding_response( + response: EmbeddingResponse, + config: Config, +) -> Result { + let mut embeddings = Vec::new(); + + for data in response.data { + embeddings.push(Embedding { + index: data.index, + vector: data.embedding, + }); + } + + let usage = Usage { + input_tokens: None, + total_tokens: Some(response.usage.total_tokens), + }; + + Ok(GolemEmbeddingResponse { + embeddings, + usage: Some(usage), + model: response.model, + provider_metadata_json: None, + }) +} + +pub fn create_rerank_request( + query: String, + documents: Vec, + config: Config, +) -> Result { + let model = config.model.unwrap_or_else(|| "rerank-2-lite".to_string()); + + Ok(RerankRequest { + query, + documents, + model, + top_k : None, + return_documents: Some(true), + truncation: config.truncation, + }) +} + +pub fn process_rerank_response( + response: RerankResponse, + config: Config, +) -> Result { + let mut results = Vec::new(); + + for result in response.results { + results.push(GolemRerankResult { + index: result.index, + relevance_score: result.relevance_score, + document: result.document.map(|doc| doc.text), + }); + } + + let usage = Usage { + input_tokens: Some(response.usage.total_tokens), + total_tokens: Some(response.usage.total_tokens), + }; + + Ok(GolemRerankResponse { + results, + usage: Some(usage), + model: response.model, + provider_metadata_json: None, + }) +} + + +#[cfg(test)] +mod tests { + use super::*; + use golem_embed::golem::embed::embed::{Config, ContentPart, TaskType}; + + #[test] + fn test_create_embedding_request() { + let inputs = vec![ + ContentPart::Text("Hello world".to_string()), + ContentPart::Text("How are you?".to_string()), + ]; + + let config = Config { + model: Some("voyage-3.5-lite".to_string()), + task_type: Some(TaskType::RetrievalDocument), + dimensions: Some(1024), + truncation: Some(true), + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + + let request = create_embedding_request(inputs, config).unwrap(); + + assert_eq!(request.model, config.model.unwrap()); + assert_eq!(request.input_type, Some(InputType::Document)); + assert_eq!(request.truncation, config.truncation); + assert_eq!(request.output_dimension, config.dimensions); + assert_eq!(request.input.len(), inputs.len()); + + } + + #[test] + fn test_create_rerank_request() { + let query = "What is AI?".to_string(); + let documents = vec![ + "AI is artificial intelligence".to_string(), + "Machine learning is a subset of AI".to_string(), + ]; + + let config = Config { + model: Some("rerank-2-lite".to_string()), + task_type: None, + dimensions: None, + truncation: Some(false), + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + + let request = create_rerank_request(query, documents, config).unwrap(); + + assert_eq!(request.model, "rerank-2-lite"); + assert_eq!(request.query, "What is AI?"); + assert_eq!(request.documents.len(), 2); + assert_eq!(request.top_k, Some(5)); + assert_eq!(request.truncation, Some(false)); + assert_eq!(request.return_documents, Some(true)); + } + + #[test] + fn test_image_input_not_supported() { + let inputs = vec![ + ContentPart::Text("Hello".to_string()), + ContentPart::Image(golem_embed::golem::embed::embed::ImageUrl { + url: "http://example.com/image.jpg".to_string(), + }), + ]; + + let config = Config { + model: None, + task_type: None, + dimensions: None, + truncation: None, + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + + let result = create_embedding_request(inputs, config); + assert!(result.is_err()); + + if let Err(error) = result { + assert_eq!( + error.code, + golem_embed::golem::embed::embed::ErrorCode::Unsupported + ); + assert!(error.message.contains("image inputs")); + } + } +} diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs index 3ac1b9392..5172a2692 100644 --- a/golem-embed/embed-voyageai/src/lib.rs +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -1,2 +1,53 @@ +use golem_embed::golem::embed::embed::{EmbeddingResponse, RerankResponse, ContentPart, Config, Error, Guest}; + mod client; mod conversitions; + + + + + +struct VoyageAIApiComponent; + +impl VoyageAIApiComponent { + const ENV_VAR_NAME: &'static str = "VOYAGEAI_API_KEY"; + + fn embeddings( + client: VoyageAIApi, + inputs: Vec, + config: Config, + ) -> Result { + let request = create_embedding_request(inputs, config.clone()); + match request { + Ok(request) => match client.generate_embedding(request) { + Ok(response) => process_embedding_response(response, config), + Err(err) => Err(err), + }, + } + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + todo!() + } +} + + +impl Guest for VoyageAIApiComponent { + fn generate(inputs: Vec, config: Config) -> Result { + let client = VoyageAIApi::new(config.api_key.clone()); + Self::embeddings(client, inputs, config) + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + todo!() + } +} + From 07e2ca9e8c98d7985e1f62db60fa837da30d82b0 Mon Sep 17 00:00:00 2001 From: Rutik Thakre Date: Sat, 7 Jun 2025 11:12:56 +0000 Subject: [PATCH 14/36] wip --- golem-embed/embed-cohere/src/client.rs | 245 +++++++++--------- golem-embed/embed-cohere/src/conversions.rs | 89 ++++++- golem-embed/embed-cohere/src/lib.rs | 28 +- golem-embed/embed-openai/src/lib.rs | 45 ++-- .../embed-voyageai/src/conversitions.rs | 77 +++--- golem-embed/embed-voyageai/src/lib.rs | 36 ++- 6 files changed, 311 insertions(+), 209 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 139882b40..3326c8f15 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -33,7 +33,7 @@ impl EmbeddingsApi { trace!("Sending request to Cohere API: {request:?}"); let response = self .client - .request(Method::POST, format!("{BASE_URL}/v1/embed")) + .request(Method::POST, format!("{BASE_URL}/v2/embed")) .bearer_auth(&self.cohere_api_key) .json(&request) .send() @@ -41,6 +41,19 @@ impl EmbeddingsApi { trace!("Recived response: {:#?}", response); parse_response::(response) } + + pub fn rerank(&self, request: RerankRequest) -> Result { + trace!("Sending request to Cohere API: {request:?}"); + let response = self + .client + .request(Method::POST, format!("{BASE_URL}/v2/rerank")) + .bearer_auth(&self.cohere_api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Request failed", err))?; + trace!("Recived response: {:#?}", response); + parse_response::(response) + } } fn parse_response(response: Response) -> Result { @@ -64,10 +77,6 @@ fn parse_response(response: Response) -> Result(response: &str) -> Result { - serde_json::from_str::(response) -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub enum InputType { #[serde(rename = "search_document")] @@ -174,31 +183,82 @@ pub struct EmbeddingData { pub ubinary: Option>>, } +#[derive(Debug, Serialize, Deserialize)] +pub struct CohereError { + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankRequest { + pub model: String, + pub query: String, + pub documents: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub top_n: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_tokens_per_doc: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankResponse { + pub results: Vec, + pub scores: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub meta: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RerankData { + pub index: u32, + pub relevance_score: f32, +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Meta { #[serde(skip_serializing_if = "Option::is_none")] pub api_version: Option, #[serde(skip_serializing_if = "Option::is_none")] pub billed_units: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub warning: Option>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct MetaTokens { + #[serde(skip_serializing_if = "Option::is_none")] + pub input_tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub output_tokens: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ApiVersion { #[serde(skip_serializing_if = "Option::is_none")] pub version: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub is_deprecated: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub is_experimental: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct BilledUnits { + #[serde(skip_serializing_if = "Option::is_none")] + pub images: Option, #[serde(skip_serializing_if = "Option::is_none")] pub input_tokens: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct CohereError { - pub message: String, #[serde(skip_serializing_if = "Option::is_none")] - pub code: Option, + pub output_tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub search_units: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub classifications: Option, } #[cfg(test)] @@ -206,123 +266,72 @@ mod tests { use crate::client; use super::*; - use golem_embed::golem::embed::embed::EmbeddingResponse; use serde_json; + fn parse_json(response: &str) -> Result { + serde_json::from_str::(response) + } + #[test] - fn test_parse_data() { + fn test_parse_embedding_response_data() { let json_data = r#"{ - "id": "54910170-852f-4322-9767-63d36e55c3bf", - "texts": [ - "This is the sentence I want to embed.", - "Hey !" - ], - "embeddings": { - "binary": [ - [ - -54, - 99, - -87, - 60, - 15, - 10, - 93, - 97, - -42, - -51, - 9 - ] - ], - "float": [ - [ - - 0.016967773, - 0.031982422, - 0.041503906, - 0.0021514893, - 0.008178711, - -0.029541016, - -0.018432617, - -0.046875, - 0.021240234 + "id": "54910170-852f-4322-9767-63d36e55c3bf", + "texts": [ + "This is the sentence I want to embed.", + "Hey !" ], - [ - 0.013977051, - 0.012084961, - 0.005554199, - -0.053955078, - -0.026977539, - -0.008361816, - 0.02368164, - -0.013183594, - -0.063964844, - 0.026611328 - ] - ], - "int8": [ - [ - - -15, - -65, - 0, - -31, - -43, - -14, - -48, - 59, - -34, - 15, - 36, - 49, - -5, - 3, - -49, - -34, - -74, - 21 - ], - [ - - 14, - 38, - -30, - -13, - -49, - 4, - -33, - -49, - 48, - 9, - -84, - 8, - 0, - -84, - -46, - -20, - 24, - -26, - -98, - 28 - ] - ] - }, - "meta": { - "api_version": { - "version": "2" - }, - "billed_units": { - "input_tokens": 11, - "image_tokens": 0 - } - }, - "response_type": "embeddings_by_type" + "embeddings": { + "binary": [[-54,99,-87,60,9]], + "float": [[0.016967773,0.031982422,0.041503906],[0.013977051,0.012084961,0.005554199,-0.053955078]], + "int8": [[-15,-65,0,-31,-43,-14],[14,38,-30,-13,-49,4,-33,-49]] + }, + "meta": { + "api_version": { + "version": "2" + }, + "billed_units": { + "input_tokens": 11, + "image_tokens": 0 + } + }, + "response_type": "embeddings_by_type" }"#; let result = parse_json::(json_data); print!("{:?}", result); assert!(result.is_ok()); + } - // TODO: print the response on the console - + #[test] + fn test_parse_rerank_response_data() { + let json_data = r#"{ + "results": [ + { + "index": 3, + "relevance_score": 0.999071 + }, + { + "index": 4, + "relevance_score": 0.7867867 + }, + { + "index": 0, + "relevance_score": 0.32713068 + } + ], + "id": "07734bd2-2473-4f07-94e1-0d9f0e6843cf", + "meta": { + "api_version": { + "version": "2", + "is_experimental": false + }, + "billed_units": { + "search_units": 1 + } + } + }"#; + let result = parse_json::(json_data); + print!("{:?}", result); + assert!(result.is_ok()); } } diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index 45e9f443a..5b14d217b 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -4,14 +4,16 @@ use base64::{engine::general_purpose, Engine}; use golem_embed::{ error::unsupported, golem::embed::embed::{ - self, Config, ContentPart, Embedding, EmbeddingResponse as GolemEmbeddingResponse, Error, - OutputDtype, OutputFormat, TaskType, Usage, + Config, ContentPart, Embedding, EmbeddingResponse as GolemEmbeddingResponse, Error, + OutputDtype, RerankResponse as GolemRerankResponse, RerankResult, TaskType, Usage, }, }; use log::trace; use reqwest::{Client, Url}; -use crate::client::{EmbeddingData, EmbeddingRequest, EmbeddingResponse, EmbeddingType, InputType}; +use crate::client::{ + EmbeddingRequest, EmbeddingResponse, EmbeddingType, InputType, RerankRequest, RerankResponse, +}; fn output_dtype_to_cohere_embedding_type(dtype: OutputDtype) -> EmbeddingType { match dtype { @@ -23,7 +25,10 @@ fn output_dtype_to_cohere_embedding_type(dtype: OutputDtype) -> EmbeddingType { } } -pub fn create_request(inputs: Vec, config: Config) -> Result { +pub fn create_embed_request( + inputs: Vec, + config: Config, +) -> Result { let mut text_inputs = Vec::new(); let mut image_inputs = Vec::new(); for input in inputs { @@ -89,6 +94,21 @@ pub fn create_request(inputs: Vec, config: Config) -> Result, + config: Config, +) -> Result { + let model = config.model.unwrap_or_else(|| "rerank-2-lite".to_string()); + Ok(RerankRequest { + model, + query, + documents, + top_n: None, + max_tokens_per_doc: None, + }) +} + pub fn image_to_base64(source: &str) -> Result> { let bytes = if Url::parse(source).is_ok() { let client = Client::new(); @@ -158,7 +178,7 @@ pub fn process_embedding_response( Ok(GolemEmbeddingResponse { embeddings: embeddings, - provider_metadata_json: Some(get_provider_metadata(response.clone())), + provider_metadata_json: Some(get_embed_provider_metadata(response.clone())), model: config .model .unwrap_or_else(|| "embed-english-v3.0".to_string()), @@ -169,20 +189,65 @@ pub fn process_embedding_response( }) } -pub fn get_provider_metadata(response: EmbeddingResponse) -> String { +pub fn get_embed_provider_metadata(response: EmbeddingResponse) -> String { let meta = serde_json::to_string(&response.meta.unwrap()).unwrap_or_default(); format!(r#"{{"id":"{}","meta":"{}",}}"#, response.id, meta) } +pub fn process_rerank_response( + response: RerankResponse, + config: Config, +) -> Result { + let results = response + .results + .iter() + .map(|result| RerankResult { + index: result.index, + + relevance_score: result.relevance_score, + document: None, + }) + .collect(); + + let usage = if let Some(meta) = response.clone().meta { + if let Some(tokens) = meta.tokens { + Some(Usage { + input_tokens: tokens.input_tokens, + total_tokens: tokens.output_tokens, + }) + } else { + None + } + } else { + None + }; + + Ok(GolemRerankResponse { + results, + usage, + model: config.model.unwrap_or_else(|| "rerank-2-lite".to_string()), + provider_metadata_json: Some(get_rerank_provider_metadata(response.clone())), + }) +} + +fn get_rerank_provider_metadata(response: RerankResponse) -> String { + let meta = serde_json::to_string(&response.meta.unwrap()).unwrap_or_default(); + format!( + r#"{{"id":"{}","meta":"{}",}}"#, + response.id.unwrap_or_default(), + meta + ) +} + #[cfg(test)] mod tests { - use crate::client::{ApiVersion, BilledUnits, Meta}; + use crate::client::{ApiVersion, BilledUnits, EmbeddingData, Meta}; use super::*; use serde_json; #[test] - fn test_conversion() { + fn test_embedding_response_conversion() { let data = EmbeddingResponse { id: "54910170-852f-4322-9767-63d36e55c3bf".to_owned(), images: None, @@ -233,10 +298,18 @@ mod tests { meta: Some(Meta { api_version: Some(ApiVersion { version: Some("2".to_owned()), + is_experimental: None, + is_deprecated: None, }), billed_units: Some(BilledUnits { input_tokens: Some(11), + classifications: None, + images: None, + output_tokens: None, + search_units: None, }), + tokens: None, + warning: None, }), response_type: Some("embeddings_by_type".to_owned()), }; diff --git a/golem-embed/embed-cohere/src/lib.rs b/golem-embed/embed-cohere/src/lib.rs index c768867e2..7af54d440 100644 --- a/golem-embed/embed-cohere/src/lib.rs +++ b/golem-embed/embed-cohere/src/lib.rs @@ -1,5 +1,5 @@ use client::{EmbeddingResponse, EmbeddingsApi}; -use conversions::create_request; +use conversions::create_embed_request; use golem_embed::{ config::with_config_key, golem::embed::embed::{ @@ -9,7 +9,9 @@ use golem_embed::{ LOGGING_STATE, }; -use crate::conversions::process_embedding_response; +use crate::conversions::{ + create_rerank_request, process_embedding_response, process_rerank_response, +}; mod client; mod conversions; @@ -24,7 +26,7 @@ impl CohereComponent { inputs: Vec, config: Config, ) -> Result { - let request = create_request(inputs, config.clone()); + let request = create_embed_request(inputs, config.clone()); match request { Ok(request) => match client.generate_embeding(request) { Ok(response) => process_embedding_response(response, config), @@ -35,11 +37,19 @@ impl CohereComponent { } fn rerank( + client: EmbeddingsApi, query: String, documents: Vec, config: Config, ) -> Result { - todo!() + let request = create_rerank_request(query, documents, config.clone()); + match request { + Ok(request) => match client.rerank(request) { + Ok(response) => process_rerank_response(response, config), + Err(err) => Err(err), + }, + Err(err) => Err(err), + } } } @@ -61,6 +71,14 @@ impl Guest for CohereComponent { documents: Vec, config: Config, ) -> Result { - todo!() + LOGGING_STATE.with_borrow_mut(|state| state.init()); + with_config_key( + Self::ENV_VAR_NAME, + |error| Err(error), + |cohere_api_key| { + let client = EmbeddingsApi::new(cohere_api_key); + Self::rerank(client, query, documents, config) + }, + ) } } diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs index 0facf860a..c54d9cb7f 100644 --- a/golem-embed/embed-openai/src/lib.rs +++ b/golem-embed/embed-openai/src/lib.rs @@ -1,13 +1,15 @@ - mod client; mod conversions; use client::EmbeddingsApi; use conversions::{create_request, process_embedding_response}; -use golem_embed::{config::with_config_key, golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse -}, LOGGING_STATE}; - +use golem_embed::{ + config::with_config_key, + golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, ErrorCode, Guest, RerankResponse, + }, + LOGGING_STATE, +}; struct OpenAIComponent; @@ -28,31 +30,30 @@ impl OpenAIComponent { Err(err) => Err(err), } } - - fn rerank(query:String,documents:Vec::,config:Config,) -> Result { - todo!() - } } - - impl Guest for OpenAIComponent { - fn generate(inputs: Vec,config:Config,) -> Result { - LOGGING_STATE.with_borrow_mut(|state|state.init()); - with_config_key( + fn generate(inputs: Vec, config: Config) -> Result { + LOGGING_STATE.with_borrow_mut(|state| state.init()); + with_config_key( Self::ENV_VAR_NAME, - |error|Err(error), + |error| Err(error), |openai_api_key| { let client = EmbeddingsApi::new(openai_api_key); Self::embeddings(client, inputs, config) }, ) - } - - fn rerank(query:String,documents:Vec::,config:Config,) -> Result { - todo!() - } -} -golem_embed::export_embed!(OpenAIComponent with_types_in golem_embed); + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + Err(Error { + code: ErrorCode::Unsupported, + message: "OpenAI does not support rerank".to_string(), + provider_error_json: None, + }) + } +} diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/golem-embed/embed-voyageai/src/conversitions.rs index cf93c997c..2e3829e8b 100644 --- a/golem-embed/embed-voyageai/src/conversitions.rs +++ b/golem-embed/embed-voyageai/src/conversitions.rs @@ -13,7 +13,8 @@ use log::trace; use reqwest::{Client, Url}; use crate::client::{ - EmbeddingRequest, EmbeddingResponse, InputType, RerankRequest, RerankResponse, + EmbeddingRequest, EmbeddingResponse, EncodingFormat, InputType, OutputDtype, RerankRequest, + RerankResponse, }; pub fn create_embedding_request( @@ -33,25 +34,28 @@ pub fn create_embedding_request( } } - let model = config.model.unwrap_or_else(|| "voyage-3.5-lite".to_string()); + let model = config + .model + .unwrap_or_else(|| "voyage-3.5-lite".to_string()); let mut input_type = None; match config.task_type { - TaskType::RetrievalQuery => input_type = Some(InputType::Query), - TaskType::RetrievalDocument => input_type = Some(InputType::Document), + Some(TaskType::RetrievalQuery) => input_type = Some(InputType::Query), + Some(TaskType::RetrievalDocument) => input_type = Some(InputType::Document), _ => return Err(unsupported("Unsupported task type")), - }?; + }; let output_dtype = match config.output_dtype { - GolemOutputDtype::FloatArray => OutputDtype::FloatArray, - GolemOutputDtype::Int8 => OutputDtype::Int8, - GolemOutputDtype::Uint8 => OutputDtype::Uint8, - GolemOutputDtype::Binary => OutputDtype::Binary, - GolemOutputDtype::Ubinary => OutputDtype::Ubinary, + Some(GolemOutputDtype::FloatArray) => Some(OutputDtype::Float), + Some(GolemOutputDtype::Int8) => Some(OutputDtype::Int8), + Some(GolemOutputDtype::Uint8) => Some(OutputDtype::Uint8), + Some(GolemOutputDtype::Binary) => Some(OutputDtype::Binary), + Some(GolemOutputDtype::Ubinary) => Some(OutputDtype::Ubinary), + _ => None, }; let encoding_format = match config.output_format { - GolemOutputFormat::Base64 => OutputFormat::Base64, + Some(GolemOutputFormat::Base64) => Some(EncodingFormat::Base64), _ => None, }; @@ -68,7 +72,6 @@ pub fn create_embedding_request( pub fn process_embedding_response( response: EmbeddingResponse, - config: Config, ) -> Result { let mut embeddings = Vec::new(); @@ -103,23 +106,19 @@ pub fn create_rerank_request( query, documents, model, - top_k : None, + top_k: None, return_documents: Some(true), truncation: config.truncation, }) } -pub fn process_rerank_response( - response: RerankResponse, - config: Config, -) -> Result { +pub fn process_rerank_response(response: RerankResponse) -> Result { let mut results = Vec::new(); - - for result in response.results { + for result in response.data { results.push(GolemRerankResult { index: result.index, relevance_score: result.relevance_score, - document: result.document.map(|doc| doc.text), + document: result.document, }); } @@ -136,7 +135,6 @@ pub fn process_rerank_response( }) } - #[cfg(test)] mod tests { use super::*; @@ -160,14 +158,12 @@ mod tests { provider_options: vec![], }; - let request = create_embedding_request(inputs, config).unwrap(); - - assert_eq!(request.model, config.model.unwrap()); - assert_eq!(request.input_type, Some(InputType::Document)); - assert_eq!(request.truncation, config.truncation); - assert_eq!(request.output_dimension, config.dimensions); - assert_eq!(request.input.len(), inputs.len()); - + let request = create_embedding_request(inputs.clone(), config.clone()); + match &request { + Ok(request) => print!("{:?}", request), + Err(err) => println!("{:?}", err), + }; + assert!(request.is_ok()); } #[test] @@ -189,14 +185,12 @@ mod tests { provider_options: vec![], }; - let request = create_rerank_request(query, documents, config).unwrap(); - - assert_eq!(request.model, "rerank-2-lite"); - assert_eq!(request.query, "What is AI?"); - assert_eq!(request.documents.len(), 2); - assert_eq!(request.top_k, Some(5)); - assert_eq!(request.truncation, Some(false)); - assert_eq!(request.return_documents, Some(true)); + let request = create_rerank_request(query, documents, config); + match &request { + Ok(request) => print!("{:?}", &request), + Err(err) => println!("{:?}", err), + }; + assert!(request.is_ok()); } #[test] @@ -220,14 +214,7 @@ mod tests { }; let result = create_embedding_request(inputs, config); + print!("{:?}", result); assert!(result.is_err()); - - if let Err(error) = result { - assert_eq!( - error.code, - golem_embed::golem::embed::embed::ErrorCode::Unsupported - ); - assert!(error.message.contains("image inputs")); - } } } diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs index 5172a2692..32da55a19 100644 --- a/golem-embed/embed-voyageai/src/lib.rs +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -1,12 +1,18 @@ -use golem_embed::golem::embed::embed::{EmbeddingResponse, RerankResponse, ContentPart, Config, Error, Guest}; +use golem_embed::golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, +}; + +use crate::{ + client::VoyageAIApi, + conversitions::{ + create_embedding_request, create_rerank_request, process_embedding_response, + process_rerank_response, + }, +}; mod client; mod conversitions; - - - - struct VoyageAIApiComponent; impl VoyageAIApiComponent { @@ -20,25 +26,33 @@ impl VoyageAIApiComponent { let request = create_embedding_request(inputs, config.clone()); match request { Ok(request) => match client.generate_embedding(request) { - Ok(response) => process_embedding_response(response, config), + Ok(response) => process_embedding_response(response), Err(err) => Err(err), }, + Err(err) => Err(err), } } fn rerank( + client: VoyageAIApi, query: String, documents: Vec, config: Config, ) -> Result { - todo!() + let request = create_rerank_request(query, documents, config); + match request { + Ok(request) => match client.rerank(request) { + Ok(response) => process_rerank_response(response), + Err(err) => Err(err), + }, + Err(err) => Err(err), + } } } - impl Guest for VoyageAIApiComponent { fn generate(inputs: Vec, config: Config) -> Result { - let client = VoyageAIApi::new(config.api_key.clone()); + let client = VoyageAIApi::new(Self::ENV_VAR_NAME.to_string()); Self::embeddings(client, inputs, config) } @@ -47,7 +61,7 @@ impl Guest for VoyageAIApiComponent { documents: Vec, config: Config, ) -> Result { - todo!() + let client = VoyageAIApi::new(Self::ENV_VAR_NAME.to_string()); + Self::rerank(client, query, documents, config) } } - From 37f30d330801df2ed540e0d54a38936e00bdfe62 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 8 Jun 2025 09:21:31 +0000 Subject: [PATCH 15/36] durability --- golem-embed/embed-openai/src/lib.rs | 17 +++ golem-embed/embed/src/durability.rs | 195 ++++++++++++++++++++++++++++ golem-embed/embed/src/lib.rs | 2 +- 3 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 golem-embed/embed/src/durability.rs diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs index c54d9cb7f..a9efe8270 100644 --- a/golem-embed/embed-openai/src/lib.rs +++ b/golem-embed/embed-openai/src/lib.rs @@ -10,6 +10,15 @@ use golem_embed::{ }, LOGGING_STATE, }; +use golem_embed::{ + config::with_config_key, + durability::{DurableEmbed, ExtendedGuest}, + golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse + }, + LOGGING_STATE +}; + struct OpenAIComponent; @@ -57,3 +66,11 @@ impl Guest for OpenAIComponent { }) } } + + + +impl ExtendedGuest for OpenAIComponent {} + +type DurableOpenAIComponent = DurableEmbed; + +golem_embed::export_embed!(DurableOpenAIComponent with_types_in golem_embed); diff --git a/golem-embed/embed/src/durability.rs b/golem-embed/embed/src/durability.rs new file mode 100644 index 000000000..fbf2517cd --- /dev/null +++ b/golem-embed/embed/src/durability.rs @@ -0,0 +1,195 @@ +use crate::golem::embed::embed::{Guest}; +use std::marker::PhantomData; + +/// Wraps an embed implementation with custom durability +pub struct DurableEmbed { + phantom: PhantomData, +} + +/// Trait to be implemented in addition to the embed `Guest` trait when wrapping it with `DurableEmbed`. +pub trait ExtendedGuest: Guest + 'static {} + +/// When the durability feature flag is off, wrapping with `DurableEmbed` is just a passthrough +#[cfg(not(feature = "durability"))] +mod passthrough_impl { + use crate::durability::{DurableEmbed, ExtendedGuest}; + use crate::golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, + }; + + impl Guest for DurableEmbed { + fn generate( + inputs: Vec, + config: Config, + ) -> Result { + Impl::generate(inputs, config) + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + Impl::rerank(query, documents, config) + } + } +} + +/// When the durability feature flag is on, wrapping with `DurableEmbed` adds custom durability +/// on top of the provider-specific embed implementation using Golem's special host functions and +/// the `golem-rust` helper library. +/// +/// There will be custom durability entries saved in the oplog, with the full embed request and configuration +/// stored as input, and the full response stored as output. To serialize these in a way it is +/// observable by oplog consumers, each relevant data type has to be converted to/from `ValueAndType` +/// which is implemented using the type classes and builder in the `golem-rust` library. +#[cfg(feature = "durability")] +mod durable_impl { + use crate::durability::{DurableEmbed, ExtendedGuest}; + use crate::golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, + }; + use golem_rust::bindings::golem::durability::durability::DurableFunctionType; + use golem_rust::durability::Durability; + use golem_rust::{with_persistence_level, FromValueAndType, IntoValue, PersistenceLevel}; + use std::fmt::{Display, Formatter}; + + impl Guest for DurableEmbed { + fn generate( + inputs: Vec, + config: Config, + ) -> Result { + let durability = Durability::, UnusedError>::new( + "golem_embed", + "generate", + DurableFunctionType::WriteRemote, + ); + if durability.is_live() { + let result = with_persistence_level(PersistenceLevel::PersistNothing, || { + Impl::generate(inputs.clone(), config.clone()) + }); + durability.persist_infallible( + GenerateInput { inputs, config }, + result.clone(), + ) + } else { + durability.replay_infallible() + } + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + let durability = Durability::, UnusedError>::new( + "golem_embed", + "rerank", + DurableFunctionType::WriteRemote, + ); + if durability.is_live() { + let result = with_persistence_level(PersistenceLevel::PersistNothing, || { + Impl::rerank(query.clone(), documents.clone(), config.clone()) + }); + durability.persist_infallible( + RerankInput { + query, + documents, + config, + }, + result.clone(), + ) + } else { + durability.replay_infallible() + } + } + } + + #[derive(Debug, Clone, PartialEq, IntoValue, FromValueAndType)] + struct GenerateInput { + inputs: Vec, + config: Config, + } + + #[derive(Debug, Clone, PartialEq, IntoValue, FromValueAndType)] + struct RerankInput { + query: String, + documents: Vec, + config: Config, + } + + #[derive(Debug, FromValueAndType, IntoValue)] + struct UnusedError; + + impl Display for UnusedError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "UnusedError") + } + } + + #[cfg(test)] + mod tests { + use crate::durability::durable_impl::{GenerateInput, RerankInput}; + use crate::golem::embed::embed::{ + Config, ContentPart, ImageUrl, TaskType, + }; + use golem_rust::value_and_type::{FromValueAndType, IntoValueAndType}; + use std::fmt::Debug; + + fn roundtrip_test( + value: T, + ) { + let vnt = value.clone().into_value_and_type(); + let extracted = T::from_value_and_type(vnt).unwrap(); + assert_eq!(value, extracted); + } + + #[test] + fn generate_input_encoding() { + let input = GenerateInput { + inputs: vec![ + ContentPart::Text("Hello world".to_string()), + ContentPart::Image(ImageUrl { + url: "https://example.com/image.png".to_string(), + }), + ], + config: Config { + model: Some("text-embedding-3-small".to_string()), + task_type: Some(TaskType::RetrievalQuery), + dimensions: Some(512), + truncation: Some(true), + output_format: None, + output_dtype: None, + user: Some("test-user".to_string()), + provider_options: vec![], + }, + }; + + roundtrip_test(input); + } + + #[test] + fn rerank_input_encoding() { + let input = RerankInput { + query: "What is machine learning?".to_string(), + documents: vec![ + "Machine learning is a subset of AI".to_string(), + "Deep learning uses neural networks".to_string(), + "NLP processes human language".to_string(), + ], + config: Config { + model: Some("rerank-english-v3.0".to_string()), + task_type: None, + dimensions: None, + truncation: None, + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }, + }; + + roundtrip_test(input); + } + } +} \ No newline at end of file diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index adaa30b57..5b0cfd9e0 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -1,5 +1,6 @@ pub mod error; pub mod config; +pub mod durability; wit_bindgen::generate!({ path: "../wit", @@ -12,7 +13,6 @@ wit_bindgen::generate!({ pub use crate::exports::golem; pub use __export_embed_library_impl as export_embed; -use exports::golem::embed::embed::{ Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}; use std::cell::RefCell; use std::str::FromStr; From 62a0ba38e76780a45aab962ec02cea6fddddc9ae Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 8 Jun 2025 09:41:21 +0000 Subject: [PATCH 16/36] fixes --- golem-embed/embed-cohere/src/lib.rs | 13 +++++++--- .../embed-voyageai/src/conversitions.rs | 25 ------------------- golem-embed/embed-voyageai/src/lib.rs | 11 ++++++-- 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/golem-embed/embed-cohere/src/lib.rs b/golem-embed/embed-cohere/src/lib.rs index 7af54d440..a50b3305f 100644 --- a/golem-embed/embed-cohere/src/lib.rs +++ b/golem-embed/embed-cohere/src/lib.rs @@ -1,12 +1,10 @@ use client::{EmbeddingResponse, EmbeddingsApi}; use conversions::create_embed_request; use golem_embed::{ - config::with_config_key, - golem::embed::embed::{ + config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, golem::embed::embed::{ Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, Guest, RerankResponse, - }, - LOGGING_STATE, + }, LOGGING_STATE }; use crate::conversions::{ @@ -82,3 +80,10 @@ impl Guest for CohereComponent { ) } } + + +impl ExtendedGuest for CohereComponent {} + +type DurableCohereComponent = DurableEmbed; + +golem_embed::export_embed!(DurableCohereComponent with_types_in golem_embed); \ No newline at end of file diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/golem-embed/embed-voyageai/src/conversitions.rs index 2e3829e8b..de91cffac 100644 --- a/golem-embed/embed-voyageai/src/conversitions.rs +++ b/golem-embed/embed-voyageai/src/conversitions.rs @@ -192,29 +192,4 @@ mod tests { }; assert!(request.is_ok()); } - - #[test] - fn test_image_input_not_supported() { - let inputs = vec![ - ContentPart::Text("Hello".to_string()), - ContentPart::Image(golem_embed::golem::embed::embed::ImageUrl { - url: "http://example.com/image.jpg".to_string(), - }), - ]; - - let config = Config { - model: None, - task_type: None, - dimensions: None, - truncation: None, - output_format: None, - output_dtype: None, - user: None, - provider_options: vec![], - }; - - let result = create_embedding_request(inputs, config); - print!("{:?}", result); - assert!(result.is_err()); - } } diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs index 32da55a19..92f447ff4 100644 --- a/golem-embed/embed-voyageai/src/lib.rs +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -1,6 +1,6 @@ -use golem_embed::golem::embed::embed::{ +use golem_embed::{durability::{DurableEmbed, ExtendedGuest}, golem::embed::embed::{ Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, -}; +}}; use crate::{ client::VoyageAIApi, @@ -65,3 +65,10 @@ impl Guest for VoyageAIApiComponent { Self::rerank(client, query, documents, config) } } + + +impl ExtendedGuest for VoyageAIApiComponent {} + +type DurableVoyageAIApiComponent = DurableEmbed; + +golem_embed::export_embed!(DurableVoyageAIApiComponent with_types_in golem_embed); \ No newline at end of file From 09572e116b2ee18e0b9c40bb675d084c7132acd5 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 8 Jun 2025 10:10:42 +0000 Subject: [PATCH 17/36] test --- golem-embed/Makefile.toml | 2 +- golem-embed/embed-openai/src/client.rs | 2 +- golem-embed/embed-openai/src/conversions.rs | 86 +++++++++++++++++++-- golem-embed/embed-openai/src/lib.rs | 15 +--- 4 files changed, 82 insertions(+), 23 deletions(-) diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml index 7dfcfb6ac..0b7488d99 100644 --- a/golem-embed/Makefile.toml +++ b/golem-embed/Makefile.toml @@ -163,7 +163,7 @@ args = ["fmt", "--all", "--", "--check"] description = "Runs clippy checks without applying any fix" install_crate = "clippy" command = "cargo" -args = ["clippy", "--all-targets", "--", "--no-deps", "-Dwarnings"] +args = ["clippy", "--all-targets", "--", "--no-deps", "-D warnings"] [tasks.fix] description = "Runs rustfmt and clippy checks and applies fixes" diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index 50661053a..14de259d4 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -71,7 +71,7 @@ fn parse_response(response: Response) -> Result, config: Config) -> Result return Err(unsupported("OpenAI only supports float and base64 output formats.")), }; - let dimension = config.dimensions; - - let user = config.user; - Ok(EmbeddingRequest { input, model, encoding_format, - dimension, - user, + dimension :config.dimensions, + user: config.user, }) } @@ -68,3 +64,77 @@ pub fn process_embedding_response( provider_metadata_json: None, }) } + +#[cfg(test)] +mod tests { + use golem_embed::golem::embed::embed::{ImageUrl, TaskType}; + + use crate::client::{EmbeddingData, EmbeddingUsage, EmbeddingVector}; + + use super::*; + + #[test] + fn test_process_embedding_response() { + let response = EmbeddingResponse { + data: vec![EmbeddingData { + embedding: EmbeddingVector::FloatArray(vec![0.1, 0.2, 0.3]), + index: 0, + object: "embedding".to_string(), + }], + model: "text-embedding-ada-002".to_string(), + usage: EmbeddingUsage { + prompt_tokens: 1, + total_tokens: 1, + }, + object: "list".to_string(), + }; + let result = process_embedding_response(response); + let embedding_response = result.unwrap(); + assert_eq!(embedding_response.embeddings.len(), 1); + assert_eq!(embedding_response.embeddings[0].index, 0); + assert_eq!(embedding_response.embeddings[0].vector, vec![0.1, 0.2, 0.3]); + assert_eq!(embedding_response.provider_metadata_json, None); + } + + #[test] + fn test_create_request() { + let inputs = vec![ContentPart::Text("Hello, world!".to_string())]; + let config = Config { + model: Some("text-embedding-ada-002".to_string()), + dimensions: Some(1536), + user: Some("test_user".to_string()), + task_type: Some(TaskType::RetrievalQuery), + truncation: Some(false), + output_format: Some(OutputFormat::FloatArray), + output_dtype: Some(OutputDtype::FloatArray), + provider_options: vec![], + }; + let request = create_request(inputs, config); + let embedding_request = request.unwrap(); + assert_eq!(embedding_request.input, "Hello, world!"); + assert_eq!(embedding_request.model, "text-embedding-ada-002"); + assert_eq!(embedding_request.dimension, Some(1536)); + assert_eq!(embedding_request.user, Some("test_user".to_string())); + assert_eq!(embedding_request.encoding_format, Some(EncodingFormat::Float)); + } + + #[test] + fn test_create_request_with_image() { + // OpenAI does not support image embeddings so this should return an error + let inputs = vec![ContentPart::Image(ImageUrl { + url: "https://example.com/image.png".to_string(), + })]; + let config = Config { + model: Some("text-embedding-ada-002".to_string()), + dimensions: Some(1536), + user: Some("test_user".to_string()), + task_type: Some(TaskType::RetrievalQuery), + truncation: Some(false), + output_format: Some(OutputFormat::FloatArray), + output_dtype: Some(OutputDtype::FloatArray), + provider_options: vec![], + }; + let request = create_request(inputs, config); + assert!(request.is_err()); + } +} \ No newline at end of file diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs index a9efe8270..68fc49596 100644 --- a/golem-embed/embed-openai/src/lib.rs +++ b/golem-embed/embed-openai/src/lib.rs @@ -5,18 +5,9 @@ use client::EmbeddingsApi; use conversions::{create_request, process_embedding_response}; use golem_embed::{ config::with_config_key, - golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse, Error, ErrorCode, Guest, RerankResponse, - }, - LOGGING_STATE, -}; -use golem_embed::{ - config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, - golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse - }, - LOGGING_STATE + golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, ErrorCode}, + LOGGING_STATE, }; @@ -66,8 +57,6 @@ impl Guest for OpenAIComponent { }) } } - - impl ExtendedGuest for OpenAIComponent {} From a9a663492106bff9373e28cda0cc8d0c890195b1 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Mon, 9 Jun 2025 07:42:05 +0000 Subject: [PATCH 18/36] fixes --- golem-embed/embed-cohere/src/client.rs | 74 -------- golem-embed/embed-cohere/src/conversions.rs | 174 ++++++++++++++++-- golem-embed/embed-cohere/src/lib.rs | 36 ++-- .../wit/deps/golem-embed/golem-embed.wit | 3 +- .../embed-hugging-face/src/conversitions.rs | 1 + golem-embed/embed-openai/src/client.rs | 10 +- golem-embed/embed-openai/src/conversions.rs | 28 ++- golem-embed/embed-openai/src/lib.rs | 17 +- .../wit/deps/golem-embed/golem-embed.wit | 3 +- golem-embed/embed-voyageai/src/client.rs | 7 +- .../embed-voyageai/src/conversitions.rs | 7 +- golem-embed/embed-voyageai/src/lib.rs | 10 +- golem-embed/embed/src/config.rs | 1 - golem-embed/embed/src/durability.rs | 23 +-- golem-embed/embed/src/error.rs | 6 +- golem-embed/embed/src/lib.rs | 2 +- .../wit/deps/golem-embed/golem-embed.wit | 3 +- .../test/wit/deps/golem-embed/golem-embed.wit | 3 +- 18 files changed, 226 insertions(+), 182 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 3326c8f15..4a72c25fa 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -261,77 +261,3 @@ pub struct BilledUnits { pub classifications: Option, } -#[cfg(test)] -mod tests { - use crate::client; - - use super::*; - use serde_json; - - fn parse_json(response: &str) -> Result { - serde_json::from_str::(response) - } - - #[test] - fn test_parse_embedding_response_data() { - let json_data = r#"{ - "id": "54910170-852f-4322-9767-63d36e55c3bf", - "texts": [ - "This is the sentence I want to embed.", - "Hey !" - ], - "embeddings": { - "binary": [[-54,99,-87,60,9]], - "float": [[0.016967773,0.031982422,0.041503906],[0.013977051,0.012084961,0.005554199,-0.053955078]], - "int8": [[-15,-65,0,-31,-43,-14],[14,38,-30,-13,-49,4,-33,-49]] - }, - "meta": { - "api_version": { - "version": "2" - }, - "billed_units": { - "input_tokens": 11, - "image_tokens": 0 - } - }, - "response_type": "embeddings_by_type" - }"#; - - let result = parse_json::(json_data); - print!("{:?}", result); - assert!(result.is_ok()); - } - - #[test] - fn test_parse_rerank_response_data() { - let json_data = r#"{ - "results": [ - { - "index": 3, - "relevance_score": 0.999071 - }, - { - "index": 4, - "relevance_score": 0.7867867 - }, - { - "index": 0, - "relevance_score": 0.32713068 - } - ], - "id": "07734bd2-2473-4f07-94e1-0d9f0e6843cf", - "meta": { - "api_version": { - "version": "2", - "is_experimental": false - }, - "billed_units": { - "search_units": 1 - } - } - }"#; - let result = parse_json::(json_data); - print!("{:?}", result); - assert!(result.is_ok()); - } -} diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index 5b14d217b..1711dedb8 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -177,7 +177,7 @@ pub fn process_embedding_response( }; Ok(GolemEmbeddingResponse { - embeddings: embeddings, + embeddings, provider_metadata_json: Some(get_embed_provider_metadata(response.clone())), model: config .model @@ -210,14 +210,10 @@ pub fn process_rerank_response( .collect(); let usage = if let Some(meta) = response.clone().meta { - if let Some(tokens) = meta.tokens { - Some(Usage { - input_tokens: tokens.input_tokens, - total_tokens: tokens.output_tokens, - }) - } else { - None - } + meta.tokens.map(|tokens| Usage { + input_tokens: tokens.input_tokens, + total_tokens: tokens.output_tokens, + }) } else { None }; @@ -241,10 +237,35 @@ fn get_rerank_provider_metadata(response: RerankResponse) -> String { #[cfg(test)] mod tests { - use crate::client::{ApiVersion, BilledUnits, EmbeddingData, Meta}; + use crate::client::{ApiVersion, BilledUnits, EmbeddingData, Meta, RerankData}; use super::*; - use serde_json; + + #[test] + fn test_create_embed_request() { + let inputs = vec![ContentPart::Text("Hello, world!".to_string())]; + let config = Config { + model: Some("embed-english-v3.0".to_string()), + task_type: Some(TaskType::RetrievalQuery), + dimensions: Some(1024), + truncation: Some(true), + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + let request = create_embed_request(inputs, config); + let request = request.unwrap(); + assert_eq!(request.model, "embed-english-v3.0"); + // assert_eq!(request.input_type, InputType::SearchQuery); + // assert_eq!(request.embedding_types, Some(vec![EmbeddingType::Float])); + assert_eq!(request.images, None); + assert_eq!(request.texts, Some(vec!["Hello, world!".to_string()])); + // assert_eq!(request.truncate, None); + assert_eq!(request.max_tokens, None); + assert_eq!(request.output_dimension, Some("1024".to_string())); + } + #[test] fn test_embedding_response_conversion() { @@ -325,8 +346,135 @@ mod tests { provider_options: vec![], }; - let result = process_embedding_response(data, config); + let result = process_embedding_response(data.clone(), config); print!("{:?}", result); - assert!(result.is_ok()) + let embedding_response = result.unwrap(); + assert_eq!(embedding_response.embeddings.len(), 2); + assert_eq!(embedding_response.embeddings[0].index, 0); + assert_eq!( + embedding_response.embeddings[0].vector, + vec![ + 0.016967773, + 0.031982422, + 0.041503906, + 0.0021514893, + 0.008178711, + -0.029541016, + -0.018432617, + -0.046875, + 0.021240234 + ] + ); + assert_eq!(embedding_response.embeddings[1].index, 1); + assert_eq!( + embedding_response.embeddings[1].vector, + vec![ + 0.013977051, + 0.012084961, + 0.005554199, + -0.053955078, + -0.026977539, + -0.008361816, + 0.02368164, + -0.013183594, + -0.063964844, + 0.026611328 + ] + ); + assert_eq!( + embedding_response.provider_metadata_json, + Some(get_embed_provider_metadata(data)) + ); + assert_eq!(embedding_response.model, "embed-english-v3.0"); + assert_eq!( + embedding_response.usage, + Some(Usage { + input_tokens: Some(11), + total_tokens: None, + }) + ); + } + + + #[test] + fn test_create_rerank_request() { + let query = "What is AI?".to_string(); + let documents = vec![ + "AI is artificial intelligence".to_string(), + "Machine learning is a subset of AI".to_string(), + ]; + let config = Config { + model: Some("rerank-2-lite".to_string()), + task_type: None, + dimensions: None, + truncation: None, + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + let request = create_rerank_request(query, documents.clone(), config); + let request = request.unwrap(); + assert_eq!(request.model, "rerank-2-lite"); + assert_eq!(request.query, "What is AI?"); + assert_eq!(request.documents, documents); + assert_eq!(request.top_n, None); + assert_eq!(request.max_tokens_per_doc, None); + } + + #[test] + fn test_rerank_response_conversion() { + let data = RerankResponse { + id: Some("54910170-852f-4322-9767-63d36e55c3bf".to_owned()), + results: vec![RerankData { + index: 0, + relevance_score: 0.9, + }], + scores: vec![0.9], + meta: Some(Meta { + api_version: Some(ApiVersion { + version: Some("2".to_owned()), + is_experimental: None, + is_deprecated: None, + }), + billed_units: Some(BilledUnits { + input_tokens: Some(11), + classifications: None, + images: None, + output_tokens: None, + search_units: None, + }), + tokens: None, + warning: None, + }), + }; + + let config = Config { + model: Some("rerank-2-lite".to_string()), + task_type: None, + dimensions: None, + truncation: None, + output_format: None, + output_dtype: None, + user: None, + provider_options: vec![], + }; + let result = process_rerank_response(data.clone(), config); + let rerank_response = result.unwrap(); + assert_eq!(rerank_response.results.len(), 1); + assert_eq!(rerank_response.results[0].index, 0); + assert_eq!(rerank_response.results[0].relevance_score, 0.9); + assert_eq!(rerank_response.model, "rerank-2-lite"); + assert_eq!( + rerank_response.provider_metadata_json, + Some(get_rerank_provider_metadata(data)) + ); + assert_eq!( + rerank_response.usage, + Some(Usage { + input_tokens: Some(11), + total_tokens: None, + }) + ); } } diff --git a/golem-embed/embed-cohere/src/lib.rs b/golem-embed/embed-cohere/src/lib.rs index a50b3305f..76b42ae6d 100644 --- a/golem-embed/embed-cohere/src/lib.rs +++ b/golem-embed/embed-cohere/src/lib.rs @@ -1,10 +1,13 @@ -use client::{EmbeddingResponse, EmbeddingsApi}; +use client::EmbeddingsApi; use conversions::create_embed_request; use golem_embed::{ - config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, golem::embed::embed::{ + config::with_config_key, + durability::{DurableEmbed, ExtendedGuest}, + golem::embed::embed::{ Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, Guest, RerankResponse, - }, LOGGING_STATE + }, + LOGGING_STATE, }; use crate::conversions::{ @@ -54,14 +57,10 @@ impl CohereComponent { impl Guest for CohereComponent { fn generate(inputs: Vec, config: Config) -> Result { LOGGING_STATE.with_borrow_mut(|state| state.init()); - with_config_key( - Self::ENV_VAR_NAME, - |error| Err(error), - |cohere_api_key| { - let client = EmbeddingsApi::new(cohere_api_key); - Self::embeddings(client, inputs, config) - }, - ) + with_config_key(Self::ENV_VAR_NAME, Err, |cohere_api_key| { + let client = EmbeddingsApi::new(cohere_api_key); + Self::embeddings(client, inputs, config) + }) } fn rerank( @@ -70,20 +69,15 @@ impl Guest for CohereComponent { config: Config, ) -> Result { LOGGING_STATE.with_borrow_mut(|state| state.init()); - with_config_key( - Self::ENV_VAR_NAME, - |error| Err(error), - |cohere_api_key| { - let client = EmbeddingsApi::new(cohere_api_key); - Self::rerank(client, query, documents, config) - }, - ) + with_config_key(Self::ENV_VAR_NAME, Err, |cohere_api_key| { + let client = EmbeddingsApi::new(cohere_api_key); + Self::rerank(client, query, documents, config) + }) } } - impl ExtendedGuest for CohereComponent {} type DurableCohereComponent = DurableEmbed; -golem_embed::export_embed!(DurableCohereComponent with_types_in golem_embed); \ No newline at end of file +golem_embed::export_embed!(DurableCohereComponent with_types_in golem_embed); diff --git a/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit index 838b3c2a5..78d040320 100644 --- a/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit @@ -124,7 +124,6 @@ interface embed { ) -> result; } - world embed-library { - export embed; + export embed; } \ No newline at end of file diff --git a/golem-embed/embed-hugging-face/src/conversitions.rs b/golem-embed/embed-hugging-face/src/conversitions.rs index e69de29bb..8b1378917 100644 --- a/golem-embed/embed-hugging-face/src/conversitions.rs +++ b/golem-embed/embed-hugging-face/src/conversitions.rs @@ -0,0 +1 @@ + diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index 14de259d4..b4890edce 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -1,11 +1,11 @@ use std::fmt::Debug; +use base64::{engine::general_purpose, Engine}; use golem_embed::{ error::{error_code_from_status, from_reqwest_error}, golem::embed::embed::Error, }; use log::trace; -use base64::{engine::general_purpose, Engine}; #[allow(dead_code, unused, unused_imports)] use reqwest::Client; @@ -22,8 +22,6 @@ pub struct EmbeddingsApi { client: reqwest::Client, } - - impl EmbeddingsApi { pub fn new(openai_api_key: String) -> Self { let client = Client::builder() @@ -69,7 +67,6 @@ fn parse_response(response: Response) -> Result Result, String> { match self { EmbeddingVector::FloatArray(vec) => Ok(vec.clone()), EmbeddingVector::Base64(base64_str) => { - let bytes = general_purpose::STANDARD .decode(base64_str) .map_err(|e| format!("Failed to decode base64: {}", e))?; @@ -144,8 +138,6 @@ impl EmbeddingVector { } } - - #[derive(Debug, Serialize, Deserialize)] pub struct OpenAIError { pub error: OpenAIErrorDetails, diff --git a/golem-embed/embed-openai/src/conversions.rs b/golem-embed/embed-openai/src/conversions.rs index c74626d1d..7af41dcd3 100644 --- a/golem-embed/embed-openai/src/conversions.rs +++ b/golem-embed/embed-openai/src/conversions.rs @@ -1,7 +1,6 @@ use golem_embed::error::unsupported; use golem_embed::golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, ErrorCode, - ImageUrl, OutputDtype, OutputFormat, TaskType, + Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, }; use crate::client::{EmbeddingRequest, EmbeddingResponse, EncodingFormat}; @@ -22,16 +21,24 @@ pub fn create_request(inputs: Vec, config: Config) -> Result Some(EncodingFormat::Float), - Some(golem_embed::golem::embed::embed::OutputFormat::Base64) => Some(EncodingFormat::Base64), - _ => return Err(unsupported("OpenAI only supports float and base64 output formats.")), + Some(golem_embed::golem::embed::embed::OutputFormat::FloatArray) => { + Some(EncodingFormat::Float) + } + Some(golem_embed::golem::embed::embed::OutputFormat::Base64) => { + Some(EncodingFormat::Base64) + } + _ => { + return Err(unsupported( + "OpenAI only supports float and base64 output formats.", + )) + } }; Ok(EmbeddingRequest { input, model, encoding_format, - dimension :config.dimensions, + dimension: config.dimensions, user: config.user, }) } @@ -67,7 +74,7 @@ pub fn process_embedding_response( #[cfg(test)] mod tests { - use golem_embed::golem::embed::embed::{ImageUrl, TaskType}; + use golem_embed::golem::embed::embed::{ImageUrl, OutputDtype, OutputFormat, TaskType}; use crate::client::{EmbeddingData, EmbeddingUsage, EmbeddingVector}; @@ -115,7 +122,10 @@ mod tests { assert_eq!(embedding_request.model, "text-embedding-ada-002"); assert_eq!(embedding_request.dimension, Some(1536)); assert_eq!(embedding_request.user, Some("test_user".to_string())); - assert_eq!(embedding_request.encoding_format, Some(EncodingFormat::Float)); + assert_eq!( + embedding_request.encoding_format, + Some(EncodingFormat::Float) + ); } #[test] @@ -137,4 +147,4 @@ mod tests { let request = create_request(inputs, config); assert!(request.is_err()); } -} \ No newline at end of file +} diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs index 68fc49596..491504c9c 100644 --- a/golem-embed/embed-openai/src/lib.rs +++ b/golem-embed/embed-openai/src/lib.rs @@ -6,11 +6,12 @@ use conversions::{create_request, process_embedding_response}; use golem_embed::{ config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, - golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, ErrorCode}, + golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, ErrorCode, Guest, RerankResponse, + }, LOGGING_STATE, }; - struct OpenAIComponent; impl OpenAIComponent { @@ -35,14 +36,10 @@ impl OpenAIComponent { impl Guest for OpenAIComponent { fn generate(inputs: Vec, config: Config) -> Result { LOGGING_STATE.with_borrow_mut(|state| state.init()); - with_config_key( - Self::ENV_VAR_NAME, - |error| Err(error), - |openai_api_key| { - let client = EmbeddingsApi::new(openai_api_key); - Self::embeddings(client, inputs, config) - }, - ) + with_config_key(Self::ENV_VAR_NAME, Err, |openai_api_key| { + let client = EmbeddingsApi::new(openai_api_key); + Self::embeddings(client, inputs, config) + }) } fn rerank( diff --git a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit index 838b3c2a5..78d040320 100644 --- a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit @@ -124,7 +124,6 @@ interface embed { ) -> result; } - world embed-library { - export embed; + export embed; } \ No newline at end of file diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs index d3357cc42..859f2baa6 100644 --- a/golem-embed/embed-voyageai/src/client.rs +++ b/golem-embed/embed-voyageai/src/client.rs @@ -97,15 +97,14 @@ pub enum EncodingFormat { Base64, } - -#[derive(Debug,Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub enum InputType { Document, - Query + Query, } #[derive(Debug, Serialize, Deserialize, Clone)] -pub enum OutputDtype{ +pub enum OutputDtype { Float, Int8, Uint8, diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/golem-embed/embed-voyageai/src/conversitions.rs index de91cffac..1d0ebd0e1 100644 --- a/golem-embed/embed-voyageai/src/conversitions.rs +++ b/golem-embed/embed-voyageai/src/conversitions.rs @@ -1,16 +1,11 @@ -use std::{fs, path::Path}; - -use base64::{engine::general_purpose, Engine}; use golem_embed::{ error::unsupported, golem::embed::embed::{ - self, Config, ContentPart, Embedding, EmbeddingResponse as GolemEmbeddingResponse, Error, + Config, ContentPart, Embedding, EmbeddingResponse as GolemEmbeddingResponse, Error, OutputDtype as GolemOutputDtype, OutputFormat as GolemOutputFormat, RerankResponse as GolemRerankResponse, RerankResult as GolemRerankResult, TaskType, Usage, }, }; -use log::trace; -use reqwest::{Client, Url}; use crate::client::{ EmbeddingRequest, EmbeddingResponse, EncodingFormat, InputType, OutputDtype, RerankRequest, diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs index 92f447ff4..a81706b91 100644 --- a/golem-embed/embed-voyageai/src/lib.rs +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -1,6 +1,7 @@ -use golem_embed::{durability::{DurableEmbed, ExtendedGuest}, golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, -}}; +use golem_embed::{ + durability::{DurableEmbed, ExtendedGuest}, + golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}, +}; use crate::{ client::VoyageAIApi, @@ -66,9 +67,8 @@ impl Guest for VoyageAIApiComponent { } } - impl ExtendedGuest for VoyageAIApiComponent {} type DurableVoyageAIApiComponent = DurableEmbed; -golem_embed::export_embed!(DurableVoyageAIApiComponent with_types_in golem_embed); \ No newline at end of file +golem_embed::export_embed!(DurableVoyageAIApiComponent with_types_in golem_embed); diff --git a/golem-embed/embed/src/config.rs b/golem-embed/embed/src/config.rs index 252703aef..903ec695b 100644 --- a/golem-embed/embed/src/config.rs +++ b/golem-embed/embed/src/config.rs @@ -1,4 +1,3 @@ - use crate::golem::embed::embed::{Error, ErrorCode}; use std::ffi::OsStr; diff --git a/golem-embed/embed/src/durability.rs b/golem-embed/embed/src/durability.rs index fbf2517cd..fa1b59434 100644 --- a/golem-embed/embed/src/durability.rs +++ b/golem-embed/embed/src/durability.rs @@ -1,4 +1,4 @@ -use crate::golem::embed::embed::{Guest}; +use crate::golem::embed::embed::Guest; use std::marker::PhantomData; /// Wraps an embed implementation with custom durability @@ -18,10 +18,7 @@ mod passthrough_impl { }; impl Guest for DurableEmbed { - fn generate( - inputs: Vec, - config: Config, - ) -> Result { + fn generate(inputs: Vec, config: Config) -> Result { Impl::generate(inputs, config) } @@ -55,10 +52,7 @@ mod durable_impl { use std::fmt::{Display, Formatter}; impl Guest for DurableEmbed { - fn generate( - inputs: Vec, - config: Config, - ) -> Result { + fn generate(inputs: Vec, config: Config) -> Result { let durability = Durability::, UnusedError>::new( "golem_embed", "generate", @@ -68,10 +62,7 @@ mod durable_impl { let result = with_persistence_level(PersistenceLevel::PersistNothing, || { Impl::generate(inputs.clone(), config.clone()) }); - durability.persist_infallible( - GenerateInput { inputs, config }, - result.clone(), - ) + durability.persist_infallible(GenerateInput { inputs, config }, result.clone()) } else { durability.replay_infallible() } @@ -130,9 +121,7 @@ mod durable_impl { #[cfg(test)] mod tests { use crate::durability::durable_impl::{GenerateInput, RerankInput}; - use crate::golem::embed::embed::{ - Config, ContentPart, ImageUrl, TaskType, - }; + use crate::golem::embed::embed::{Config, ContentPart, ImageUrl, TaskType}; use golem_rust::value_and_type::{FromValueAndType, IntoValueAndType}; use std::fmt::Debug; @@ -192,4 +181,4 @@ mod durable_impl { roundtrip_test(input); } } -} \ No newline at end of file +} diff --git a/golem-embed/embed/src/error.rs b/golem-embed/embed/src/error.rs index c0651e3d8..a576e4462 100644 --- a/golem-embed/embed/src/error.rs +++ b/golem-embed/embed/src/error.rs @@ -1,9 +1,6 @@ use crate::golem::embed::embed::{Error, ErrorCode}; use reqwest::StatusCode; - - - pub fn unsupported(what: impl AsRef) -> Error { Error { code: ErrorCode::Unsupported, @@ -20,7 +17,6 @@ pub fn model_not_found(model: impl AsRef) -> Error { } } - pub fn from_reqwest_error(details: impl AsRef, err: reqwest::Error) -> Error { Error { code: ErrorCode::InternalError, @@ -29,7 +25,7 @@ pub fn from_reqwest_error(details: impl AsRef, err: reqwest::Error) -> Erro } } - pub fn error_code_from_status(status: StatusCode) -> ErrorCode { +pub fn error_code_from_status(status: StatusCode) -> ErrorCode { if status == StatusCode::TOO_MANY_REQUESTS { ErrorCode::RateLimitExceeded } else if status == StatusCode::UNAUTHORIZED diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index 5b0cfd9e0..c48d77f16 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -1,6 +1,6 @@ -pub mod error; pub mod config; pub mod durability; +pub mod error; wit_bindgen::generate!({ path: "../wit", diff --git a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit index b524f9071..78d040320 100644 --- a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit @@ -32,6 +32,7 @@ interface embed { invalid-request, model-not-found, unsupported, + authentication-failed, provider-error, rate-limit-exceeded, internal-error, @@ -124,5 +125,5 @@ interface embed { } world embed-library { - export embed; + export embed; } \ No newline at end of file diff --git a/golem-embed/test/wit/deps/golem-embed/golem-embed.wit b/golem-embed/test/wit/deps/golem-embed/golem-embed.wit index 838b3c2a5..78d040320 100644 --- a/golem-embed/test/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/test/wit/deps/golem-embed/golem-embed.wit @@ -124,7 +124,6 @@ interface embed { ) -> result; } - world embed-library { - export embed; + export embed; } \ No newline at end of file From 815e38d5c37ab5a03c0cf26258ab4c7dc678fd7e Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Tue, 10 Jun 2025 13:36:29 +0000 Subject: [PATCH 19/36] hf --- golem-embed/Makefile.toml | 29 +++ .../embed-hugging-face/src/bindings.rs | 126 +++---------- golem-embed/embed-hugging-face/src/client.rs | 120 +++++++++++- .../embed-hugging-face/src/conversions.rs | 178 ++++++++++++++++++ .../embed-hugging-face/src/conversitions.rs | 1 - golem-embed/embed-hugging-face/src/lib.rs | 75 +++++++- 6 files changed, 428 insertions(+), 101 deletions(-) create mode 100644 golem-embed/embed-hugging-face/src/conversions.rs delete mode 100644 golem-embed/embed-hugging-face/src/conversitions.rs diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml index 0b7488d99..a191dc839 100644 --- a/golem-embed/Makefile.toml +++ b/golem-embed/Makefile.toml @@ -31,18 +31,30 @@ install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-embed-cohere", "--no-default-features"] +[tasks.build-hugging-face] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face"] + +[tasks.build-hugging-face-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face", "--no-default-features"] + [tasks.build] dependencies = [ "build-openai", "build-cohere", + "build-hugging-face", ] [tasks.build-portable] dependencies = [ "build-openai-portable", "build-cohere-portable", + "build-hugging-face-portable", ] [tasks.build-all] @@ -83,16 +95,28 @@ install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-embed-cohere", "--release", "--no-default-features"] +[tasks.release-build-hugging-face] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face", "--release"] + +[tasks.release-build-hugging-face-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face", "--release", "--no-default-features"] + [tasks.release-build] dependencies = [ "release-build-openai", "release-build-cohere", + "release-build-hugging-face", ] [tasks.release-build-portable] dependencies = [ "release-build-openai-portable", "release-build-cohere-portable", + "release-build-hugging-face-portable", ] [tasks.release-build-all] @@ -139,6 +163,11 @@ mkdir embed-cohere/wit/deps/golem-embed cp wit/golem-embed.wit embed-cohere/wit/deps/golem-embed/golem-embed.wit cp wit/deps/wasi:io embed-cohere/wit/deps +rm -r embed-hugging-face/wit/deps +mkdir embed-hugging-face/wit/deps/golem-embed +cp wit/golem-embed.wit embed-hugging-face/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io embed-hugging-face/wit/deps + rm -r test/wit mkdir test/wit/deps/golem-embed mkdir test/wit/deps/io diff --git a/golem-embed/embed-hugging-face/src/bindings.rs b/golem-embed/embed-hugging-face/src/bindings.rs index 7b95e9297..506c76faa 100644 --- a/golem-embed/embed-hugging-face/src/bindings.rs +++ b/golem-embed/embed-hugging-face/src/bindings.rs @@ -1,107 +1,41 @@ // Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" -#[doc(hidden)] -#[allow(non_snake_case)] -pub unsafe fn _export_hello_world_cabi() -> *mut u8 { - #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); - let result0 = T::hello_world(); - let ptr1 = (&raw mut _RET_AREA.0).cast::(); - let vec2 = (result0.into_bytes()).into_boxed_slice(); - let ptr2 = vec2.as_ptr().cast::(); - let len2 = vec2.len(); - ::core::mem::forget(vec2); - *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; - *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); - ptr1 -} -#[doc(hidden)] -#[allow(non_snake_case)] -pub unsafe fn __post_return_hello_world(arg0: *mut u8) { - let l0 = *arg0.add(0).cast::<*mut u8>(); - let l1 = *arg0.add(::core::mem::size_of::<*const u8>()).cast::(); - _rt::cabi_dealloc(l0, l1, 1); -} -pub trait Guest { - fn hello_world() -> _rt::String; -} -#[doc(hidden)] -macro_rules! __export_world_example_cabi { - ($ty:ident with_types_in $($path_to_types:tt)*) => { - const _ : () = { #[unsafe (export_name = "hello-world")] unsafe extern "C" fn - export_hello_world() -> * mut u8 { unsafe { $($path_to_types)*:: - _export_hello_world_cabi::<$ty > () } } #[unsafe (export_name = - "cabi_post_hello-world")] unsafe extern "C" fn _post_return_hello_world(arg0 : * - mut u8,) { unsafe { $($path_to_types)*:: __post_return_hello_world::<$ty > (arg0) - } } }; - }; -} -#[doc(hidden)] -pub(crate) use __export_world_example_cabi; -#[cfg_attr(target_pointer_width = "64", repr(align(8)))] -#[cfg_attr(target_pointer_width = "32", repr(align(4)))] -struct _RetArea([::core::mem::MaybeUninit; 2 * ::core::mem::size_of::<*const u8>()]); -static mut _RET_AREA: _RetArea = _RetArea( - [::core::mem::MaybeUninit::uninit(); 2 * ::core::mem::size_of::<*const u8>()], -); -#[rustfmt::skip] -mod _rt { - #![allow(dead_code, clippy::all)] - #[cfg(target_arch = "wasm32")] - pub fn run_ctors_once() { - wit_bindgen_rt::run_ctors_once(); - } - pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { - if size == 0 { - return; - } - let layout = alloc::Layout::from_size_align_unchecked(size, align); - alloc::dealloc(ptr, layout); - } - pub use alloc_crate::string::String; - pub use alloc_crate::alloc; - extern crate alloc as alloc_crate; -} -/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as -/// the root implementation of all generated traits. -/// -/// For more information see the documentation of `wit_bindgen::generate!`. -/// -/// ```rust -/// # macro_rules! export{ ($($t:tt)*) => (); } -/// # trait Guest {} -/// struct MyType; -/// -/// impl Guest for MyType { -/// // ... -/// } -/// -/// export!(MyType); -/// ``` -#[allow(unused_macros)] -#[doc(hidden)] -macro_rules! __export_example_impl { - ($ty:ident) => { - self::export!($ty with_types_in self); - }; - ($ty:ident with_types_in $($path_to_types_root:tt)*) => { - $($path_to_types_root)*:: __export_world_example_cabi!($ty with_types_in - $($path_to_types_root)*); - }; -} -#[doc(inline)] -pub(crate) use __export_example_impl as export; +// * with "golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" +// * generate_unused_types +use golem_embed::golem::embed::embed as __with_name0; #[cfg(target_arch = "wasm32")] #[unsafe( - link_section = "component-type:wit-bindgen:0.41.0:component:embed-hugging-face:example:encoded world" + link_section = "component-type:wit-bindgen:0.41.0:golem:embed-hugging-face@1.0.0:embed-library:encoded world" )] #[doc(hidden)] #[allow(clippy::octal_escapes)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 193] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07D\x01A\x02\x01A\x02\x01\ -@\0\0s\x04\0\x0bhello-world\x01\0\x04\0$component:embed-hugging-face/example\x04\ -\0\x0b\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dw\ -it-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1269] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xf1\x08\x01A\x02\x01\ +A\x02\x01B/\x01m\x08\x0fretrieval-query\x12retrieval-document\x13semantic-simila\ +rity\x0eclassification\x0aclustering\x12question-answering\x11fact-verification\x0e\ +code-retrieval\x04\0\x09task-type\x03\0\0\x01m\x03\x0bfloat-array\x06binary\x06b\ +ase64\x04\0\x0doutput-format\x03\0\x02\x01m\x05\x0bfloat-array\x04int8\x05uint8\x06\ +binary\x07ubinary\x04\0\x0coutput-dtype\x03\0\x04\x01m\x08\x0finvalid-request\x0f\ +model-not-found\x0bunsupported\x15authentication-failed\x0eprovider-error\x13rat\ +e-limit-exceeded\x0einternal-error\x07unknown\x04\0\x0aerror-code\x03\0\x06\x01r\ +\x01\x03urls\x04\0\x09image-url\x03\0\x08\x01q\x02\x04text\x01s\0\x05image\x01\x09\ +\0\x04\0\x0ccontent-part\x03\0\x0a\x01r\x02\x03keys\x05values\x04\0\x02kv\x03\0\x0c\ +\x01ks\x01k\x01\x01ky\x01k\x7f\x01k\x03\x01k\x05\x01p\x0d\x01r\x08\x05model\x0e\x09\ +task-type\x0f\x0adimensions\x10\x0atruncation\x11\x0doutput-format\x12\x0coutput\ +-dtype\x13\x04user\x0e\x10provider-options\x14\x04\0\x06config\x03\0\x15\x01r\x02\ +\x0cinput-tokens\x10\x0ctotal-tokens\x10\x04\0\x05usage\x03\0\x17\x01pv\x01r\x02\ +\x05indexy\x06vector\x19\x04\0\x09embedding\x03\0\x1a\x01p\x1b\x01k\x18\x01r\x04\ +\x0aembeddings\x1c\x05usage\x1d\x05models\x16provider-metadata-json\x0e\x04\0\x12\ +embedding-response\x03\0\x1e\x01r\x03\x05indexy\x0frelevance-scorev\x08document\x0e\ +\x04\0\x0drerank-result\x03\0\x20\x01p!\x01r\x04\x07results\"\x05usage\x1d\x05mo\ +dels\x16provider-metadata-json\x0e\x04\0\x0frerank-response\x03\0#\x01r\x03\x04c\ +ode\x07\x07messages\x13provider-error-json\x0e\x04\0\x05error\x03\0%\x01p\x0b\x01\ +j\x01\x1f\x01&\x01@\x02\x06inputs'\x06config\x16\0(\x04\0\x08generate\x01)\x01ps\ +\x01j\x01$\x01&\x01@\x03\x05querys\x09documents*\x06config\x16\0+\x04\0\x06reran\ +k\x01,\x04\0\x17golem:embed/embed@1.0.0\x05\0\x04\0,golem:embed-hugging-face/emb\ +ed-library@1.0.0\x04\0\x0b\x13\x01\0\x0dembed-library\x03\0\0\0G\x09producers\x01\ +\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs index 48fc88156..b04e65d26 100644 --- a/golem-embed/embed-hugging-face/src/client.rs +++ b/golem-embed/embed-hugging-face/src/client.rs @@ -1,18 +1,107 @@ -use serde::{Deserialize, Serialize}; +use std::fmt::Debug; + +use golem_embed::{ + error::{error_code_from_status, from_reqwest_error}, + golem::embed::embed::Error, +}; +use log::trace; +use reqwest::{Client, Method, Response}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +const BASE_URL: &str = "https://router.huggingface.co/hf-inference"; + +/// The Hugging Face API client for creating embeddings. +/// +/// Based on https://huggingface.co/docs/api-inference/index +/// +pub struct EmbeddingsApi { + huggingface_api_key: String, + client: Client, +} + +impl EmbeddingsApi { + pub fn new(huggingface_api_key: String) -> Self { + let client = Client::builder() + .build() + .expect("Failed to initialize HTTP client"); + Self { + huggingface_api_key, + client, + } + } + + pub fn generate_embedding( + &self, + request: EmbeddingRequest, + model: &str, + ) -> Result { + trace!("Sending request to Hugging Face API: {request:?}"); + let response = self + .client + .request(Method::POST, format!( + "{BASE_URL}/models/{model}/pipeline/feature-extraction" + )) + .bearer_auth(&self.huggingface_api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Request failed", err))?; + parse_response::(response) + } + + + pub fn rerank(&self, request: RerankRequest, model: &str) -> Result { + trace!("Sending rerank request to Hugging Face API: {request:?}"); + let response = self + .client + .request(Method::POST, format!( + "{BASE_URL}/models/{model}/pipeline/text-classification" + )) + .bearer_auth(&self.huggingface_api_key) + .json(&request) + .send() + .map_err(|err| from_reqwest_error("Request failed", err))?; + parse_response::(response) + } +} + +fn parse_response(response: Response) -> Result { + let status = response.status(); + if status.is_success() { + let response_data = response + .json::() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Response from Hugging Face API: {response_data:?}"); + Ok(response_data) + } else { + let response_data = response + .text() + .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; + trace!("Error response from Hugging Face API: {response_data:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Request failed with {status}"), + provider_error_json: Some(response_data), + }) + } +} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmbeddingRequest { pub input: Vec, + #[serde(skip_serializing_if = "Option::is_none")] pub normalize: Option, /// The name of the prompt that should be used by for encoding. /// If not set, no prompt will be applied. Must be a key in the - /// sentence-transformers configuration prompts dictionary. - /// For example if prompt_name is “query” and the prompts is {“query”: “query: ”, …}, + /// `sentence-transformers` configuration `prompts` dictionary. + /// For example if `prompt_name` is “query” and the `prompts` is {“query”: “query: ”, …}, /// then the sentence “What is the capital of France?” will be encoded as /// “query: What is the capital of France?” because the prompt text will /// be prepended before any text to encode. + #[serde(skip_serializing_if = "Option::is_none")] pub prompt_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub truncate: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub truncate_direction: Option, } @@ -23,3 +112,28 @@ pub enum TruncateDirection { #[serde(rename = "right")] Right, } + +pub type EmbeddingResponse = Vec>; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RerankRequest { + pub query: String, + pub documents: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub top_k: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub return_documents: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RerankResponse { + pub results: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RerankResult { + pub index: u32, + pub relevance_score: f32, + #[serde(skip_serializing_if = "Option::is_none")] + pub document: Option, +} diff --git a/golem-embed/embed-hugging-face/src/conversions.rs b/golem-embed/embed-hugging-face/src/conversions.rs new file mode 100644 index 000000000..cecfd2c2f --- /dev/null +++ b/golem-embed/embed-hugging-face/src/conversions.rs @@ -0,0 +1,178 @@ +use golem_embed::error::unsupported; +use golem_embed::golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, + RerankResponse as GolemRerankResponse, +}; + +use crate::client::{EmbeddingRequest, EmbeddingResponse, RerankRequest, RerankResponse}; + +pub fn create_embedding_request(inputs: Vec, config: Config) -> Result<(EmbeddingRequest, String), Error> { + let mut input_texts = Vec::new(); + for content in inputs { + match content { + ContentPart::Text(text) => input_texts.push(text), + ContentPart::Image(_) => { + return Err(unsupported("Image embeddings are not supported by Hugging Face.")) + } + } + } + + let model = config + .model + .unwrap_or_else(|| "sentence-transformers/all-MiniLM-L6-v2".to_string()); + + let request = EmbeddingRequest { + input: input_texts, + normalize: Some(true), + prompt_name: None, + truncate: config.truncation, + truncate_direction: None, + }; + + Ok((request, model)) +} + +pub fn process_embedding_response( + response: EmbeddingResponse, + model: String, +) -> Result { + let mut embeddings = Vec::new(); + for (index, embedding_vec) in response.iter().enumerate() { + embeddings.push(golem_embed::golem::embed::embed::Embedding { + index: index as u32, + vector: embedding_vec.clone(), + }); + } + + Ok(GolemEmbeddingResponse { + embeddings, + usage: None, // Hugging Face doesn't provide usage info in their response + model, + provider_metadata_json: None, + }) +} + +pub fn create_rerank_request( + query: String, + documents: Vec, + config: Config, +) -> Result<(RerankRequest, String), Error> { + let model = config + .model + .unwrap_or_else(|| "cross-encoder/ms-marco-MiniLM-L-2-v2".to_string()); + + let request = RerankRequest { + query, + documents, + top_k: config.dimensions, // Use dimensions field as top_k + return_documents: Some(true), + }; + + Ok((request, model)) +} + +pub fn process_rerank_response( + response: RerankResponse, + model: String, +) -> Result { + let mut results = Vec::new(); + for result in response.results { + results.push(golem_embed::golem::embed::embed::RerankResult { + index: result.index, + relevance_score: result.relevance_score, + document: result.document, + }); + } + + Ok(GolemRerankResponse { + results, + usage: None, // Hugging Face doesn't provide usage info + model, + provider_metadata_json: None, + }) +} + +#[cfg(test)] +mod tests { + use golem_embed::golem::embed::embed::{ImageUrl, OutputDtype, OutputFormat, TaskType}; + + use super::*; + + #[test] + fn test_create_embedding_request() { + let inputs = vec![ContentPart::Text("Hello, world!".to_string())]; + let config = Config { + model: Some("sentence-transformers/all-MiniLM-L6-v2".to_string()), + dimensions: Some(384), + user: Some("test_user".to_string()), + task_type: Some(TaskType::RetrievalQuery), + truncation: Some(false), + output_format: Some(OutputFormat::FloatArray), + output_dtype: Some(OutputDtype::FloatArray), + provider_options: vec![], + }; + let result = create_embedding_request(inputs, config); + let (request, model) = result.unwrap(); + assert_eq!(request.input, vec!["Hello, world!"]); + assert_eq!(model, "sentence-transformers/all-MiniLM-L6-v2"); + assert_eq!(request.normalize, Some(true)); + assert_eq!(request.truncate, Some(false)); + } + + #[test] + fn test_process_embedding_response() { + let response: EmbeddingResponse = vec![vec![0.1, 0.2, 0.3], vec![0.4, 0.5, 0.6]]; + let model = "sentence-transformers/all-MiniLM-L6-v2".to_string(); + let result = process_embedding_response(response, model.clone()); + let embedding_response = result.unwrap(); + assert_eq!(embedding_response.embeddings.len(), 2); + assert_eq!(embedding_response.embeddings[0].index, 0); + assert_eq!(embedding_response.embeddings[0].vector, vec![0.1, 0.2, 0.3]); + assert_eq!(embedding_response.embeddings[1].index, 1); + assert_eq!(embedding_response.embeddings[1].vector, vec![0.4, 0.5, 0.6]); + assert_eq!(embedding_response.model, model); + assert!(embedding_response.usage.is_none()); + } + + #[test] + fn test_create_embedding_request_with_image() { + let inputs = vec![ContentPart::Image(ImageUrl { + url: "https://example.com/image.png".to_string(), + })]; + let config = Config { + model: Some("sentence-transformers/all-MiniLM-L6-v2".to_string()), + dimensions: Some(384), + user: Some("test_user".to_string()), + task_type: Some(TaskType::RetrievalQuery), + truncation: Some(false), + output_format: Some(OutputFormat::FloatArray), + output_dtype: Some(OutputDtype::FloatArray), + provider_options: vec![], + }; + let request = create_embedding_request(inputs, config); + assert!(request.is_err()); + } + + #[test] + fn test_create_rerank_request() { + let query = "What is the capital of France?".to_string(); + let documents = vec!["Paris is the capital of France.".to_string()]; + let config = Config { + model: Some("cross-encoder/ms-marco-MiniLM-L-2-v2".to_string()), + dimensions: Some(10), // Use as top_k + user: Some("test_user".to_string()), + task_type: Some(TaskType::RetrievalQuery), + truncation: Some(false), + output_format: Some(OutputFormat::FloatArray), + output_dtype: Some(OutputDtype::FloatArray), + provider_options: vec![], + }; + let result = create_rerank_request(query.clone(), documents.clone(), config); + let (request, model) = result.unwrap(); + assert_eq!(request.query, query); + assert_eq!(request.documents, documents); + assert_eq!(request.top_k, Some(10)); + assert_eq!(request.return_documents, Some(true)); + assert_eq!(model, "cross-encoder/ms-marco-MiniLM-L-2-v2"); + } +} \ No newline at end of file diff --git a/golem-embed/embed-hugging-face/src/conversitions.rs b/golem-embed/embed-hugging-face/src/conversitions.rs deleted file mode 100644 index 8b1378917..000000000 --- a/golem-embed/embed-hugging-face/src/conversitions.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/golem-embed/embed-hugging-face/src/lib.rs b/golem-embed/embed-hugging-face/src/lib.rs index 3ac1b9392..593ecd6da 100644 --- a/golem-embed/embed-hugging-face/src/lib.rs +++ b/golem-embed/embed-hugging-face/src/lib.rs @@ -1,2 +1,75 @@ mod client; -mod conversitions; +mod conversions; + +use client::EmbeddingsApi; +use conversions::{ + create_embedding_request, create_rerank_request, process_embedding_response, + process_rerank_response, +}; +use golem_embed::{ + config::with_config_key, + durability::{DurableEmbed, ExtendedGuest}, + golem::embed::embed::{ + Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, + }, + LOGGING_STATE, +}; + +struct HuggingFaceComponent; + +impl HuggingFaceComponent { + const ENV_VAR_NAME: &'static str = "HUGGINGFACE_API_KEY"; + + fn embeddings( + client: EmbeddingsApi, + inputs: Vec, + config: Config, + ) -> Result { + let (request, model) = create_embedding_request(inputs, config)?; + match client.generate_embedding(request, &model) { + Ok(response) => process_embedding_response(response, model), + Err(err) => Err(err), + } + } + + fn rerank( + client: EmbeddingsApi, + query: String, + documents: Vec, + config: Config, + ) -> Result { + let (request, model) = create_rerank_request(query, documents, config)?; + match client.rerank(request, &model) { + Ok(response) => process_rerank_response(response, model), + Err(err) => Err(err), + } + } +} + +impl Guest for HuggingFaceComponent { + fn generate(inputs: Vec, config: Config) -> Result { + LOGGING_STATE.with_borrow_mut(|state| state.init()); + with_config_key(Self::ENV_VAR_NAME, Err, |huggingface_api_key| { + let client = EmbeddingsApi::new(huggingface_api_key); + Self::embeddings(client, inputs, config) + }) + } + + fn rerank( + query: String, + documents: Vec, + config: Config, + ) -> Result { + LOGGING_STATE.with_borrow_mut(|state| state.init()); + with_config_key(Self::ENV_VAR_NAME, Err, |huggingface_api_key| { + let client = EmbeddingsApi::new(huggingface_api_key); + Self::rerank(client, query, documents, config) + }) + } +} + +impl ExtendedGuest for HuggingFaceComponent {} + +type DurableHuggingFaceComponent = DurableEmbed; + +golem_embed::export_embed!(DurableHuggingFaceComponent with_types_in golem_embed); \ No newline at end of file From 9a8e03382bbea1f8f13b9d15cbf3d2204daed603 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 11 Jun 2025 17:19:47 +0000 Subject: [PATCH 20/36] testing & fixing --- golem-embed/Makefile.toml | 62 +++++-- golem-embed/embed-cohere/src/client.rs | 42 +++-- golem-embed/embed-cohere/src/conversions.rs | 4 +- golem-embed/embed-hugging-face/src/client.rs | 40 +++-- .../embed-hugging-face/src/conversions.rs | 8 +- golem-embed/embed-openai/src/client.rs | 39 +++-- golem-embed/embed-voyageai/src/bindings.rs | 126 ++++---------- golem-embed/embed-voyageai/src/client.rs | 39 +++-- .../embed-voyageai/src/conversitions.rs | 9 +- golem-embed/test/.vscode/settings.json | 5 + .../components-rust/test-embed/Cargo.toml | 5 +- .../components-rust/test-embed/golem.yaml | 156 ++++++++++++++++++ .../components-rust/test-embed/src/lib.rs | 79 +++++++-- .../wit/{test-llm.wit => test-embed.wit} | 1 - 14 files changed, 411 insertions(+), 204 deletions(-) create mode 100644 golem-embed/test/.vscode/settings.json rename golem-embed/test/components-rust/test-embed/wit/{test-llm.wit => test-embed.wit} (91%) diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml index a191dc839..3523760cd 100644 --- a/golem-embed/Makefile.toml +++ b/golem-embed/Makefile.toml @@ -10,6 +10,16 @@ args = ["clean"] command = "cargo" args = ["test"] +[tasks.build-voyageai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai"] + +[tasks.build-voyageai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai", "--no-default-features"] + [tasks.build-openai] install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" @@ -48,6 +58,7 @@ dependencies = [ "build-openai", "build-cohere", "build-hugging-face", + "build-voyageai", ] [tasks.build-portable] @@ -55,24 +66,29 @@ dependencies = [ "build-openai-portable", "build-cohere-portable", "build-hugging-face-portable", + "build-voyageai-portable" ] [tasks.build-all] script_runner = "@duckscript" script = ''' -mkdir components/debug +mkdir ../components/embed/debug cm_run_task clean cm_run_task build -cp target/wasm32-wasip1/debug/golem_embed_openai.wasm components/embed/debug/golem_embed_openai.wasm -cp target/wasm32-wasip1/debug/golem_embed_cohere.wasm components/embed/debug/golem_embed_cohere.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../components/embed/debug/golem_embed_openai.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../components/embed/debug/golem_embed_cohere.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../components/embed/debug/golem_embed_hugging_face.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../components/embed/debug/golem_embed_voyageai.wasm cm_run_task clean cm_run_task build-portable -cp target/wasm32-wasip1/debug/golem_embed_openai.wasm components/embed/debug/golem_embed_openai-portable.wasm -cp target/wasm32-wasip1/debug/golem_embed_cohere.wasm components/embed/debug/golem_embed_cohere-portable.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../components/embed/debug/golem_embed_openai-portable.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../components/embed/debug/golem_embed_cohere-portable.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../components/embed/debug/golem_embed_hugging_face-portable.wasm +cp ../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../components/embed/debug/golem_embed_voyageai.wasm ''' [tasks.release-build-openai] @@ -105,11 +121,22 @@ install_crate = { crate_name = "cargo-component", version = "0.20.0" } command = "cargo-component" args = ["build", "-p", "golem-embed-hugging-face", "--release", "--no-default-features"] +[tasks.release-build-voyageai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai", "--release"] + +[tasks.release-build-voyageai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai", "--release", "--no-default-features"] + [tasks.release-build] dependencies = [ "release-build-openai", "release-build-cohere", "release-build-hugging-face", + "release-build-voyageai", ] [tasks.release-build-portable] @@ -117,26 +144,31 @@ dependencies = [ "release-build-openai-portable", "release-build-cohere-portable", "release-build-hugging-face-portable", + "release-build-voyageai-portable", ] [tasks.release-build-all] script_runner = "@duckscript" script = ''' -mkdir components/release +mkdir ../components/release cm_run_task set-version cm_run_task clean cm_run_task release-build -cp target/wasm32-wasip1/release/golem_embed_openai.wasm components/embed/release/golem_embed_openai.wasm -cp target/wasm32-wasip1/release/golem_embed_cohere.wasm components/embed/release/golem_embed_cohere.wasm +cp ../target/wasm32-wasip1/release/golem_embed_openai.wasm ../components/embed/release/golem_embed_openai.wasm +cp ../target/wasm32-wasip1/release/golem_embed_cohere.wasm ../components/embed/release/golem_embed_cohere.wasm +cp ../target/wasm32-wasip1/release/golem_embed_hugging_face.wasm ../components/embed/release/golem_embed_hugging_face.wasm +cp ../target/wasm32-wasip1/release/golem_embed_voyageai.wasm ../components/embed/release/golem_embed_voyageai.wasm cm_run_task clean cm_run_task release-build-portable -cp target/wasm32-wasip1/release/golem_embed_openai.wasm components/embed/release/golem_embed_openai-portable.wasm -cp target/wasm32-wasip1/release/golem_embed_cohere.wasm components/embed/release/golem_embed_cohere-portable.wasm +cp ../target/wasm32-wasip1/release/golem_embed_openai.wasm ../components/embed/release/golem_embed_openai-portable.wasm +cp ../target/wasm32-wasip1/release/golem_embed_cohere.wasm ../components/embed/release/golem_embed_cohere-portable.wasm +cp ../target/wasm32-wasip1/release/golem_embed_hugging_face.wasm ../components/embed/release/golem_embed_hugging_face-portable.wasm +cp ../target/wasm32-wasip1/release/golem_embed_voyageai.wasm ../components/embed/release/golem_embed_voyageai-portable.wasm ''' [tasks.wit-update] @@ -168,6 +200,12 @@ mkdir embed-hugging-face/wit/deps/golem-embed cp wit/golem-embed.wit embed-hugging-face/wit/deps/golem-embed/golem-embed.wit cp wit/deps/wasi:io embed-hugging-face/wit/deps +rm -r embed-voyageai/wit/deps +mkdir embed-voyageai/wit/deps/golem-embed +cp wit/golem-embed.wit embed-voyageai/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io embed-voyageai/wit/deps + + rm -r test/wit mkdir test/wit/deps/golem-embed mkdir test/wit/deps/io @@ -231,6 +269,10 @@ golem-cli app clean golem-cli app build -b openai-debug golem-cli app clean golem-cli app build -b cohere-debug +golem-cli app clean +golem-cli app build -b hugging-face-debug +golem-cli app clean +golem-cli app build -b voyageai-debug ''' diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 4a72c25fa..1a093bcd1 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -58,22 +58,29 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); - if status.is_success() { - let response_data = response - .json::() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from Cohere API: {response_data:?}"); - Ok(response_data) - } else { - let response_data = response - .text() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from Cohere API: {response_data:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Request failed with {status}"), - provider_error_json: Some(response_data), - }) + match status.is_success() { + true => match response.json::() { + Ok(response_data) => { + trace!("Response from Cohere API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!( + "Failed to decode response body: {}", + response.text().unwrap_or_default() + ), + provider_error_json: Some(error.to_string()), + }) + } + }, + false => Err(Error { + code: error_code_from_status(response.status()), + message: "Failed to parse response".to_string(), + provider_error_json: response.json(), + }), } } @@ -133,7 +140,7 @@ pub struct EmbeddingRequest { pub max_tokens: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub output_dimension: Option, + pub output_dimension: Option, #[serde(skip_serializing_if = "Option::is_none")] pub truncate: Option, @@ -260,4 +267,3 @@ pub struct BilledUnits { #[serde(skip_serializing_if = "Option::is_none")] pub classifications: Option, } - diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index 1711dedb8..bfee04855 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -90,7 +90,7 @@ pub fn create_embed_request( }, truncate: None, max_tokens: None, - output_dimension: Some(config.dimensions.unwrap().to_string()), + output_dimension: Some(config.dimensions.unwrap()), }) } @@ -263,7 +263,7 @@ mod tests { assert_eq!(request.texts, Some(vec!["Hello, world!".to_string()])); // assert_eq!(request.truncate, None); assert_eq!(request.max_tokens, None); - assert_eq!(request.output_dimension, Some("1024".to_string())); + assert_eq!(request.output_dimension, Some(1024)); } diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs index b04e65d26..926242745 100644 --- a/golem-embed/embed-hugging-face/src/client.rs +++ b/golem-embed/embed-hugging-face/src/client.rs @@ -13,7 +13,6 @@ const BASE_URL: &str = "https://router.huggingface.co/hf-inference"; /// The Hugging Face API client for creating embeddings. /// /// Based on https://huggingface.co/docs/api-inference/index -/// pub struct EmbeddingsApi { huggingface_api_key: String, client: Client, @@ -66,22 +65,29 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); - if status.is_success() { - let response_data = response - .json::() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from Hugging Face API: {response_data:?}"); - Ok(response_data) - } else { - let response_data = response - .text() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Error response from Hugging Face API: {response_data:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Request failed with {status}"), - provider_error_json: Some(response_data), - }) + match status.is_success() { + true => match response.json::() { + Ok(response_data) => { + trace!("Response from Cohere API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!( + "Failed to decode response body: {}", + response.text().unwrap_or_default() + ), + provider_error_json: Some(error.to_string()), + }) + } + }, + false => Err(Error { + code: error_code_from_status(response.status()), + message: "Failed to parse response".to_string(), + provider_error_json: response.json(), + }), } } diff --git a/golem-embed/embed-hugging-face/src/conversions.rs b/golem-embed/embed-hugging-face/src/conversions.rs index cecfd2c2f..9be6b2219 100644 --- a/golem-embed/embed-hugging-face/src/conversions.rs +++ b/golem-embed/embed-hugging-face/src/conversions.rs @@ -46,7 +46,7 @@ pub fn process_embedding_response( Ok(GolemEmbeddingResponse { embeddings, - usage: None, // Hugging Face doesn't provide usage info in their response + usage: None, model, provider_metadata_json: None, }) @@ -64,7 +64,7 @@ pub fn create_rerank_request( let request = RerankRequest { query, documents, - top_k: config.dimensions, // Use dimensions field as top_k + top_k: config.dimensions, return_documents: Some(true), }; @@ -86,7 +86,7 @@ pub fn process_rerank_response( Ok(GolemRerankResponse { results, - usage: None, // Hugging Face doesn't provide usage info + usage: None, model, provider_metadata_json: None, }) @@ -159,7 +159,7 @@ mod tests { let documents = vec!["Paris is the capital of France.".to_string()]; let config = Config { model: Some("cross-encoder/ms-marco-MiniLM-L-2-v2".to_string()), - dimensions: Some(10), // Use as top_k + dimensions: Some(10), user: Some("test_user".to_string()), task_type: Some(TaskType::RetrievalQuery), truncation: Some(false), diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index b4890edce..383e43ed1 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -48,22 +48,29 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); - if status.is_success() { - let response_data = response - .json::() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from OpenAI Embeddings API: {response_data:?}"); - Ok(response_data) - } else { - let response_data = response - .text() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from OpenAI Embeddings API: {response_data:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Request failed with {status}"), - provider_error_json: Some(response_data), - }) + match status.is_success() { + true => match response.json::() { + Ok(response_data) => { + trace!("Response from Cohere API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!( + "Failed to decode response body: {}", + response.text().unwrap_or_default() + ), + provider_error_json: Some(error.to_string()), + }) + } + }, + false => Err(Error { + code: error_code_from_status(response.status()), + message: "Failed to parse response".to_string(), + provider_error_json: response.json(), + }), } } diff --git a/golem-embed/embed-voyageai/src/bindings.rs b/golem-embed/embed-voyageai/src/bindings.rs index 7bd4d38d3..8016990a7 100644 --- a/golem-embed/embed-voyageai/src/bindings.rs +++ b/golem-embed/embed-voyageai/src/bindings.rs @@ -1,107 +1,41 @@ // Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" -#[doc(hidden)] -#[allow(non_snake_case)] -pub unsafe fn _export_hello_world_cabi() -> *mut u8 { - #[cfg(target_arch = "wasm32")] _rt::run_ctors_once(); - let result0 = T::hello_world(); - let ptr1 = (&raw mut _RET_AREA.0).cast::(); - let vec2 = (result0.into_bytes()).into_boxed_slice(); - let ptr2 = vec2.as_ptr().cast::(); - let len2 = vec2.len(); - ::core::mem::forget(vec2); - *ptr1.add(::core::mem::size_of::<*const u8>()).cast::() = len2; - *ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut(); - ptr1 -} -#[doc(hidden)] -#[allow(non_snake_case)] -pub unsafe fn __post_return_hello_world(arg0: *mut u8) { - let l0 = *arg0.add(0).cast::<*mut u8>(); - let l1 = *arg0.add(::core::mem::size_of::<*const u8>()).cast::(); - _rt::cabi_dealloc(l0, l1, 1); -} -pub trait Guest { - fn hello_world() -> _rt::String; -} -#[doc(hidden)] -macro_rules! __export_world_example_cabi { - ($ty:ident with_types_in $($path_to_types:tt)*) => { - const _ : () = { #[unsafe (export_name = "hello-world")] unsafe extern "C" fn - export_hello_world() -> * mut u8 { unsafe { $($path_to_types)*:: - _export_hello_world_cabi::<$ty > () } } #[unsafe (export_name = - "cabi_post_hello-world")] unsafe extern "C" fn _post_return_hello_world(arg0 : * - mut u8,) { unsafe { $($path_to_types)*:: __post_return_hello_world::<$ty > (arg0) - } } }; - }; -} -#[doc(hidden)] -pub(crate) use __export_world_example_cabi; -#[cfg_attr(target_pointer_width = "64", repr(align(8)))] -#[cfg_attr(target_pointer_width = "32", repr(align(4)))] -struct _RetArea([::core::mem::MaybeUninit; 2 * ::core::mem::size_of::<*const u8>()]); -static mut _RET_AREA: _RetArea = _RetArea( - [::core::mem::MaybeUninit::uninit(); 2 * ::core::mem::size_of::<*const u8>()], -); -#[rustfmt::skip] -mod _rt { - #![allow(dead_code, clippy::all)] - #[cfg(target_arch = "wasm32")] - pub fn run_ctors_once() { - wit_bindgen_rt::run_ctors_once(); - } - pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) { - if size == 0 { - return; - } - let layout = alloc::Layout::from_size_align_unchecked(size, align); - alloc::dealloc(ptr, layout); - } - pub use alloc_crate::string::String; - pub use alloc_crate::alloc; - extern crate alloc as alloc_crate; -} -/// Generates `#[unsafe(no_mangle)]` functions to export the specified type as -/// the root implementation of all generated traits. -/// -/// For more information see the documentation of `wit_bindgen::generate!`. -/// -/// ```rust -/// # macro_rules! export{ ($($t:tt)*) => (); } -/// # trait Guest {} -/// struct MyType; -/// -/// impl Guest for MyType { -/// // ... -/// } -/// -/// export!(MyType); -/// ``` -#[allow(unused_macros)] -#[doc(hidden)] -macro_rules! __export_example_impl { - ($ty:ident) => { - self::export!($ty with_types_in self); - }; - ($ty:ident with_types_in $($path_to_types_root:tt)*) => { - $($path_to_types_root)*:: __export_world_example_cabi!($ty with_types_in - $($path_to_types_root)*); - }; -} -#[doc(inline)] -pub(crate) use __export_example_impl as export; +// * with "golem:embed/embed@1.0.0" = "golem_embed::golem::embed::embed" +// * generate_unused_types +use golem_embed::golem::embed::embed as __with_name0; #[cfg(target_arch = "wasm32")] #[unsafe( - link_section = "component-type:wit-bindgen:0.41.0:component:embed-voyageai:example:encoded world" + link_section = "component-type:wit-bindgen:0.41.0:golem:embed-voyageai@1.0.0:embed-library:encoded world" )] #[doc(hidden)] #[allow(clippy::octal_escapes)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 189] = *b"\ -\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07@\x01A\x02\x01A\x02\x01\ -@\0\0s\x04\0\x0bhello-world\x01\0\x04\0\x20component:embed-voyageai/example\x04\0\ -\x0b\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0dwit\ --component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1265] = *b"\ +\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xed\x08\x01A\x02\x01\ +A\x02\x01B/\x01m\x08\x0fretrieval-query\x12retrieval-document\x13semantic-simila\ +rity\x0eclassification\x0aclustering\x12question-answering\x11fact-verification\x0e\ +code-retrieval\x04\0\x09task-type\x03\0\0\x01m\x03\x0bfloat-array\x06binary\x06b\ +ase64\x04\0\x0doutput-format\x03\0\x02\x01m\x05\x0bfloat-array\x04int8\x05uint8\x06\ +binary\x07ubinary\x04\0\x0coutput-dtype\x03\0\x04\x01m\x08\x0finvalid-request\x0f\ +model-not-found\x0bunsupported\x15authentication-failed\x0eprovider-error\x13rat\ +e-limit-exceeded\x0einternal-error\x07unknown\x04\0\x0aerror-code\x03\0\x06\x01r\ +\x01\x03urls\x04\0\x09image-url\x03\0\x08\x01q\x02\x04text\x01s\0\x05image\x01\x09\ +\0\x04\0\x0ccontent-part\x03\0\x0a\x01r\x02\x03keys\x05values\x04\0\x02kv\x03\0\x0c\ +\x01ks\x01k\x01\x01ky\x01k\x7f\x01k\x03\x01k\x05\x01p\x0d\x01r\x08\x05model\x0e\x09\ +task-type\x0f\x0adimensions\x10\x0atruncation\x11\x0doutput-format\x12\x0coutput\ +-dtype\x13\x04user\x0e\x10provider-options\x14\x04\0\x06config\x03\0\x15\x01r\x02\ +\x0cinput-tokens\x10\x0ctotal-tokens\x10\x04\0\x05usage\x03\0\x17\x01pv\x01r\x02\ +\x05indexy\x06vector\x19\x04\0\x09embedding\x03\0\x1a\x01p\x1b\x01k\x18\x01r\x04\ +\x0aembeddings\x1c\x05usage\x1d\x05models\x16provider-metadata-json\x0e\x04\0\x12\ +embedding-response\x03\0\x1e\x01r\x03\x05indexy\x0frelevance-scorev\x08document\x0e\ +\x04\0\x0drerank-result\x03\0\x20\x01p!\x01r\x04\x07results\"\x05usage\x1d\x05mo\ +dels\x16provider-metadata-json\x0e\x04\0\x0frerank-response\x03\0#\x01r\x03\x04c\ +ode\x07\x07messages\x13provider-error-json\x0e\x04\0\x05error\x03\0%\x01p\x0b\x01\ +j\x01\x1f\x01&\x01@\x02\x06inputs'\x06config\x16\0(\x04\0\x08generate\x01)\x01ps\ +\x01j\x01$\x01&\x01@\x03\x05querys\x09documents*\x06config\x16\0+\x04\0\x06reran\ +k\x01,\x04\0\x17golem:embed/embed@1.0.0\x05\0\x04\0(golem:embed-voyageai/embed-l\ +ibrary@1.0.0\x04\0\x0b\x13\x01\0\x0dembed-library\x03\0\0\0G\x09producers\x01\x0c\ +processed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs index 859f2baa6..4465aef2a 100644 --- a/golem-embed/embed-voyageai/src/client.rs +++ b/golem-embed/embed-voyageai/src/client.rs @@ -57,22 +57,29 @@ impl VoyageAIApi { fn parse_response(response: Response) -> Result { let status = response.status(); - if status.is_success() { - let response_data = response - .json::() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Response from VoyageAI API: {response_data:?}"); - Ok(response_data) - } else { - let response_data = response - .text() - .map_err(|error| from_reqwest_error("Failed to decode response body", error))?; - trace!("Error response from VoyageAI API: {response_data:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Request failed with {status}"), - provider_error_json: Some(response_data), - }) + match status.is_success() { + true => match response.json::() { + Ok(response_data) => { + trace!("Response from Cohere API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!( + "Failed to decode response body: {}", + response.text().unwrap_or_default() + ), + provider_error_json: Some(error.to_string()), + }) + } + }, + false => Err(Error { + code: error_code_from_status(response.status()), + message: "Failed to parse response".to_string(), + provider_error_json: response.json(), + }), } } diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/golem-embed/embed-voyageai/src/conversitions.rs index 1d0ebd0e1..f8fb962d5 100644 --- a/golem-embed/embed-voyageai/src/conversitions.rs +++ b/golem-embed/embed-voyageai/src/conversitions.rs @@ -21,7 +21,7 @@ pub fn create_embedding_request( for input in inputs { match input { ContentPart::Text(text) => text_inputs.push(text), - ContentPart::Image(image) => { + ContentPart::Image(_) => { return Err(unsupported( "VoyageAI text embeddings do not support image inputs. Use multimodal embeddings instead.", )); @@ -33,10 +33,9 @@ pub fn create_embedding_request( .model .unwrap_or_else(|| "voyage-3.5-lite".to_string()); - let mut input_type = None; - match config.task_type { - Some(TaskType::RetrievalQuery) => input_type = Some(InputType::Query), - Some(TaskType::RetrievalDocument) => input_type = Some(InputType::Document), + let input_type = match config.task_type { + Some(TaskType::RetrievalQuery) => Some(InputType::Query), + Some(TaskType::RetrievalDocument) => Some(InputType::Document), _ => return Err(unsupported("Unsupported task type")), }; diff --git a/golem-embed/test/.vscode/settings.json b/golem-embed/test/.vscode/settings.json new file mode 100644 index 000000000..96a21fde5 --- /dev/null +++ b/golem-embed/test/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.server.extraEnv": { + "CARGO": "cargo-component" + } +} \ No newline at end of file diff --git a/golem-embed/test/components-rust/test-embed/Cargo.toml b/golem-embed/test/components-rust/test-embed/Cargo.toml index 7674a4f44..895baafa9 100644 --- a/golem-embed/test/components-rust/test-embed/Cargo.toml +++ b/golem-embed/test/components-rust/test-embed/Cargo.toml @@ -11,6 +11,9 @@ required-features = [] [features] default = ["openai"] openai = [] +cohere = [] +hugging-face = [] +voyageai = [] [dependencies] # To use common shared libs, use the following: @@ -33,8 +36,8 @@ path = "wit-generated" [package.metadata.component.target.dependencies] "golem:embed" = { path = "wit-generated/deps/golem-embed" } -"wasi:clocks" = { path = "wit-generated/deps/clocks" } "wasi:io" = { path = "wit-generated/deps/io" } +"wasi:clocks" = { path = "wit-generated/deps/clocks" } "golem:rpc" = { path = "wit-generated/deps/golem-rpc" } "test:helper-client" = { path = "wit-generated/deps/test_helper-client" } "test:embed-exports" = { path = "wit-generated/deps/test_embed-exports" } diff --git a/golem-embed/test/components-rust/test-embed/golem.yaml b/golem-embed/test/components-rust/test-embed/golem.yaml index 011931c21..8881f2456 100644 --- a/golem-embed/test/components-rust/test-embed/golem.yaml +++ b/golem-embed/test/components-rust/test-embed/golem.yaml @@ -35,6 +35,84 @@ components: clean: - src/bindings.rs + cohere-debug: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --no-default-features --features cohere + sources: + - src + - wit-generated + - ../../common-rust + targets: + - target/wasm32-wasip1/debug/test_embed.wasm + - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_cohere_plugged.wasm + sources: + - ../../target/wasm32-wasip1/debug/test_embed.wasm + - ../../../../target/wasm32-wasip1/debug/golem_embed_cohere.wasm + targets: + - ../../target/wasm32-wasip1/debug/test_cohere_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/debug/test_cohere_plugged.wasm + linkedWasm: ../../golem-temp/components/test_cohere_debug.wasm + clean: + - src/bindings.rs + + hugging-face-debug: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --no-default-features --features hugging-face + sources: + - src + - wit-generated + - ../../common-rust + targets: + - target/wasm32-wasip1/debug/test_embed.wasm + - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_hugging_face_plugged.wasm + sources: + - ../../target/wasm32-wasip1/debug/test_embed.wasm + - ../../../../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm + targets: + - ../../target/wasm32-wasip1/debug/test_hugging_face_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/debug/test_hugging_face_plugged.wasm + linkedWasm: ../../golem-temp/components/test_hugging_face_debug.wasm + clean: + - src/bindings.rs + + voyageai-debug: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --no-default-features --features voyageai + sources: + - src + - wit-generated + - ../../common-rust + targets: + - target/wasm32-wasip1/debug/test_embed.wasm + - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_voyageai_plugged.wasm + sources: + - ../../target/wasm32-wasip1/debug/test_embed.wasm + - ../../../../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm + targets: + - ../../target/wasm32-wasip1/debug/test_voyageai_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/debug/test_voyageai_plugged.wasm + linkedWasm: ../../golem-temp/components/test_voyageai_debug.wasm + clean: + - src/bindings.rs + # RELEASE PROFILES openai-release: files: @@ -62,6 +140,84 @@ components: clean: - src/bindings.rs + cohere-release: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --release --no-default-features --features cohere + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/release/golem_embed_cohere.wasm ../../target/wasm32-wasip1/release/test_embed.wasm -o ../../target/wasm32-wasip1/release/test_cohere_plugged.wasm + sources: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - ../../../target/wasm32-wasip1/release/golem_embed_cohere.wasm + targets: + - ../../target/wasm32-wasip1/release/test_cohere_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/release/test_cohere_plugged.wasm + linkedWasm: ../../golem-temp/components/test_cohere_release.wasm + clean: + - src/bindings.rs + + hugging-face-release: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --release --no-default-features --features hugging-face + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/release/golem_embed_hugging_face.wasm ../../target/wasm32-wasip1/release/test_embed.wasm -o ../../target/wasm32-wasip1/release/test_hugging_face_plugged.wasm + sources: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - ../../../target/wasm32-wasip1/release/golem_embed_hugging_face.wasm + targets: + - ../../target/wasm32-wasip1/release/test_hugging_face_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/release/test_hugging_face_plugged.wasm + linkedWasm: ../../golem-temp/components/test_hugging_face_release.wasm + clean: + - src/bindings.rs + + voyageai-release: + files: + - sourcePath: ../../data/cat.png + targetPath: /data/cat.png + permissions: read-only + build: + - command: cargo component build --release --no-default-features --features voyageai + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/release/golem_embed_voyageai.wasm ../../target/wasm32-wasip1/release/test_embed.wasm -o ../../target/wasm32-wasip1/release/test_voyageai_plugged.wasm + sources: + - ../../target/wasm32-wasip1/release/test_embed.wasm + - ../../../target/wasm32-wasip1/release/golem_embed_voyageai.wasm + targets: + - ../../target/wasm32-wasip1/release/test_voyageai_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/release/test_voyageai_plugged.wasm + linkedWasm: ../../golem-temp/components/test_voyageai_release.wasm + clean: + - src/bindings.rs + defaultProfile: openai-debug dependencies: diff --git a/golem-embed/test/components-rust/test-embed/src/lib.rs b/golem-embed/test/components-rust/test-embed/src/lib.rs index 27be5ba98..5fe3e6893 100644 --- a/golem-embed/test/components-rust/test-embed/src/lib.rs +++ b/golem-embed/test/components-rust/test-embed/src/lib.rs @@ -3,6 +3,7 @@ mod bindings; use crate::bindings::exports::test::embed_exports::test_embed_api::*; use crate::bindings::golem::embed::embed; +use crate::bindings::golem::embed::embed::{Config, ContentPart, Error, EmbeddingResponse}; use crate::bindings::test::helper_client::test_helper_client::TestHelperApi; use golem_rust::atomically; @@ -10,36 +11,46 @@ struct Component; #[cfg(feature = "openai")] const MODEL: &'static str = "text-embedding-3-small"; +#[cfg(feature = "cohere")] +const MODEL: &'static str = "embed-english-v3.0"; +#[cfg(feature = "hugging-face")] +const MODEL: &'static str = "sentence-transformers/all-MiniLM-L6-v2"; +#[cfg(feature = "voyageai")] +const MODEL: &'static str = "voyage-3.5-lite"; #[cfg(feature = "openai")] -const IMAGE_MODEL: &'static str = "text-embedding-3-small"; +const RERANKING_MODEL: &'static str = ""; +#[cfg(feature = "cohere")] +const RERANKING_MODEL: &'static str = "rerank-v3.5"; +#[cfg(feature = "hugging-face")] +const RERANKING_MODEL: &'static str = "cross-encoder/ms-marco-MiniLM-L-2-v2"; +#[cfg(feature = "voyageai")] +const RERANKING_MODEL: &'static str = "rerank-2-lite"; impl Guest for Component { - /// test1 demonstrates a simple, non-streaming text question-answer interaction with the LLM. + /// test1 demonstrates text embedding generation. fn test1() -> String { - let config = embed::Config { + let config = Config { model: Some(MODEL.to_string()), - task_type: None, - dimensions: None, - truncation: None, - output_format: None, - output_dtype: None, - user: None, + task_type: Some(embed::TaskType::RetrievalDocument), + dimensions: Some(1024), + truncation: Some(true), + output_format: Some(embed::OutputFormat::FloatArray), + output_dtype: Some(embed::OutputDtype::FloatArray), + user: Some("RutikThakre".to_string()), provider_options: vec![], }; - println!("Sending text to LLM..."); - let response = embed::generate( - &[embed::ContentPart::Text("Hello, world!".to_string())], + println!("Sending text for embedding generation..."); + let response: Result = embed::generate( + &[ContentPart::Text("Hello, world!".to_string())], &config, ); match response { Ok(response) => { - println!("Response: {:?}", response); format!("Response: {:?}", response) } Err(error) => { - println!("Error: {:?}", error); format!( "Error: {:?} {} {}", error.code, @@ -49,11 +60,43 @@ impl Guest for Component { } } } + + /// test2 demonstrates embedding's reranking fn test2() -> String { - todo!() - } - fn test3() -> String { - todo!() + let config = Config { + model: Some(RERANKING_MODEL.to_string()), + task_type: Some(embed::TaskType::RetrievalDocument), + dimensions: Some(1024), + truncation: Some(true), + output_format: Some(embed::OutputFormat::FloatArray), + output_dtype: Some(embed::OutputDtype::FloatArray), + user: Some("RutikThakre".to_string()), + provider_options: vec![], + }; + let query = "What is the capital of the United States?"; + let documents = vec![ + "Carson City is the capital city of the American state of Nevada.".to_string(), + "The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.".to_string(), + "Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district.".to_string(), + "Capitalization or capitalisation in English grammar is the use of a capital letter at the start of a word. English usage varies from capitalization in other languages.".to_string(), + "Capital punishment has existed in the United States since beforethe United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states.".to_string() + ]; + + println!("Sending request for reranking..."); + let response = embed::rerank(query, &documents, &config); + match response { + Ok(response) => { + format!("Response: {:?}", response) + } + Err(error) => { + format!( + "Error: {:?} {} {}", + error.code, + error.message, + error.provider_error_json.unwrap_or_default() + ) + } + } } } diff --git a/golem-embed/test/components-rust/test-embed/wit/test-llm.wit b/golem-embed/test/components-rust/test-embed/wit/test-embed.wit similarity index 91% rename from golem-embed/test/components-rust/test-embed/wit/test-llm.wit rename to golem-embed/test/components-rust/test-embed/wit/test-embed.wit index 6dbabfd16..b428f27a9 100644 --- a/golem-embed/test/components-rust/test-embed/wit/test-llm.wit +++ b/golem-embed/test/components-rust/test-embed/wit/test-embed.wit @@ -5,7 +5,6 @@ package test:embed; interface test-embed-api { test1: func() -> string; test2: func() -> string; - test3: func() -> string; } world test-embed { From a6a468363bbbd0662a83c77d3d9e5fdd0108ed4e Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 11 Jun 2025 19:50:09 +0000 Subject: [PATCH 21/36] build fix --- golem-embed/embed-cohere/src/client.rs | 44 ++++++++++--------- golem-embed/embed-hugging-face/src/client.rs | 44 ++++++++++--------- golem-embed/embed-openai/src/client.rs | 44 ++++++++++--------- golem-embed/embed-voyageai/src/client.rs | 44 ++++++++++--------- .../components-rust/test-embed/Cargo.toml | 2 +- 5 files changed, 97 insertions(+), 81 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 1a093bcd1..61ac71256 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -7,6 +7,7 @@ use golem_embed::{ use log::trace; use reqwest::{Client, Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json; const BASE_URL: &str = "https://api.cohere.ai"; @@ -59,28 +60,31 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); match status.is_success() { - true => match response.json::() { - Ok(response_data) => { - trace!("Response from Cohere API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!( - "Failed to decode response body: {}", - response.text().unwrap_or_default() - ), - provider_error_json: Some(error.to_string()), - }) + true => { + let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from Cohere API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), + }) + } } }, - false => Err(Error { - code: error_code_from_status(response.status()), - message: "Failed to parse response".to_string(), - provider_error_json: response.json(), - }), + false => { + let error_text = response.text().ok(); + Err(Error { + code: error_code_from_status(status), + message: "Failed to parse response".to_string(), + provider_error_json: error_text, + }) + }, } } diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs index 926242745..99a73a687 100644 --- a/golem-embed/embed-hugging-face/src/client.rs +++ b/golem-embed/embed-hugging-face/src/client.rs @@ -7,6 +7,7 @@ use golem_embed::{ use log::trace; use reqwest::{Client, Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json; const BASE_URL: &str = "https://router.huggingface.co/hf-inference"; @@ -66,28 +67,31 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); match status.is_success() { - true => match response.json::() { - Ok(response_data) => { - trace!("Response from Cohere API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!( - "Failed to decode response body: {}", - response.text().unwrap_or_default() - ), - provider_error_json: Some(error.to_string()), - }) + true => { + let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from Hugging Face API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), + }) + } } }, - false => Err(Error { - code: error_code_from_status(response.status()), - message: "Failed to parse response".to_string(), - provider_error_json: response.json(), - }), + false => { + let error_text = response.text().ok(); + Err(Error { + code: error_code_from_status(status), + message: "Failed to parse response".to_string(), + provider_error_json: error_text, + }) + }, } } diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index 383e43ed1..ddd855ecd 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -11,6 +11,7 @@ use log::trace; use reqwest::Client; use reqwest::{Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json; const BASE_URL: &str = "https://api.openai.com"; @@ -49,28 +50,31 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); match status.is_success() { - true => match response.json::() { - Ok(response_data) => { - trace!("Response from Cohere API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!( - "Failed to decode response body: {}", - response.text().unwrap_or_default() - ), - provider_error_json: Some(error.to_string()), - }) + true => { + let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from OpenAI API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), + }) + } } }, - false => Err(Error { - code: error_code_from_status(response.status()), - message: "Failed to parse response".to_string(), - provider_error_json: response.json(), - }), + false => { + let error_text = response.text().ok(); + Err(Error { + code: error_code_from_status(status), + message: "Failed to parse response".to_string(), + provider_error_json: error_text, + }) + }, } } diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs index 4465aef2a..1e78bbfd8 100644 --- a/golem-embed/embed-voyageai/src/client.rs +++ b/golem-embed/embed-voyageai/src/client.rs @@ -7,6 +7,7 @@ use golem_embed::{ use log::trace; use reqwest::{Client, Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json; const BASE_URL: &str = "https://api.voyageai.com"; @@ -58,28 +59,31 @@ impl VoyageAIApi { fn parse_response(response: Response) -> Result { let status = response.status(); match status.is_success() { - true => match response.json::() { - Ok(response_data) => { - trace!("Response from Cohere API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!( - "Failed to decode response body: {}", - response.text().unwrap_or_default() - ), - provider_error_json: Some(error.to_string()), - }) + true => { + let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from VoyageAI API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); + Err(Error { + code: error_code_from_status(status), + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), + }) + } } }, - false => Err(Error { - code: error_code_from_status(response.status()), - message: "Failed to parse response".to_string(), - provider_error_json: response.json(), - }), + false => { + let error_text = response.text().ok(); + Err(Error { + code: error_code_from_status(status), + message: "Failed to parse response".to_string(), + provider_error_json: error_text, + }) + }, } } diff --git a/golem-embed/test/components-rust/test-embed/Cargo.toml b/golem-embed/test/components-rust/test-embed/Cargo.toml index 895baafa9..177266a40 100644 --- a/golem-embed/test/components-rust/test-embed/Cargo.toml +++ b/golem-embed/test/components-rust/test-embed/Cargo.toml @@ -36,8 +36,8 @@ path = "wit-generated" [package.metadata.component.target.dependencies] "golem:embed" = { path = "wit-generated/deps/golem-embed" } -"wasi:io" = { path = "wit-generated/deps/io" } "wasi:clocks" = { path = "wit-generated/deps/clocks" } +"wasi:io" = { path = "wit-generated/deps/io" } "golem:rpc" = { path = "wit-generated/deps/golem-rpc" } "test:helper-client" = { path = "wit-generated/deps/test_helper-client" } "test:embed-exports" = { path = "wit-generated/deps/test_embed-exports" } From b0049948921c445a3f0eabd8343e3291ca627509 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 11 Jun 2025 20:13:19 +0000 Subject: [PATCH 22/36] fix cohere --- golem-embed/embed-cohere/src/client.rs | 1 - golem-embed/embed-cohere/src/conversions.rs | 1 - golem-embed/test/components-rust/test-embed/Cargo.toml | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 61ac71256..2e5bacdd0 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -215,7 +215,6 @@ pub struct RerankRequest { #[derive(Debug, Serialize, Deserialize, Clone)] pub struct RerankResponse { pub results: Vec, - pub scores: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub id: Option, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index bfee04855..a38dae9a8 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -430,7 +430,6 @@ mod tests { index: 0, relevance_score: 0.9, }], - scores: vec![0.9], meta: Some(Meta { api_version: Some(ApiVersion { version: Some("2".to_owned()), diff --git a/golem-embed/test/components-rust/test-embed/Cargo.toml b/golem-embed/test/components-rust/test-embed/Cargo.toml index 177266a40..895baafa9 100644 --- a/golem-embed/test/components-rust/test-embed/Cargo.toml +++ b/golem-embed/test/components-rust/test-embed/Cargo.toml @@ -36,8 +36,8 @@ path = "wit-generated" [package.metadata.component.target.dependencies] "golem:embed" = { path = "wit-generated/deps/golem-embed" } -"wasi:clocks" = { path = "wit-generated/deps/clocks" } "wasi:io" = { path = "wit-generated/deps/io" } +"wasi:clocks" = { path = "wit-generated/deps/clocks" } "golem:rpc" = { path = "wit-generated/deps/golem-rpc" } "test:helper-client" = { path = "wit-generated/deps/test_helper-client" } "test:embed-exports" = { path = "wit-generated/deps/test_embed-exports" } From 32ab3691d45a5354d7e396afd64f044b72196c49 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 13 Jun 2025 09:19:19 +0000 Subject: [PATCH 23/36] fixes --- golem-embed/embed-cohere/src/client.rs | 36 ++++----- golem-embed/embed-hugging-face/src/client.rs | 65 +++++----------- .../embed-hugging-face/src/conversions.rs | 67 +--------------- golem-embed/embed-hugging-face/src/lib.rs | 21 ++--- golem-embed/embed-openai/src/client.rs | 36 ++++----- golem-embed/embed-voyageai/src/client.rs | 76 ++++++++++++------- golem-embed/embed-voyageai/src/lib.rs | 19 +++-- golem-embed/embed/src/lib.rs | 2 - .../components-rust/test-embed/src/lib.rs | 4 +- 9 files changed, 118 insertions(+), 208 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 2e5bacdd0..7147e7648 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -59,32 +59,22 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); - match status.is_success() { - true => { - let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; - match serde_json::from_str::(&response_text) { - Ok(response_data) => { - trace!("Response from Cohere API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Failed to decode response body: {}", response_text), - provider_error_json: Some(error.to_string()), - }) - } - } - }, - false => { - let error_text = response.text().ok(); + let response_text = response + .text() + .map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from Hugging Face API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); Err(Error { code: error_code_from_status(status), - message: "Failed to parse response".to_string(), - provider_error_json: error_text, + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), }) - }, + } } } diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs index 99a73a687..07dc53142 100644 --- a/golem-embed/embed-hugging-face/src/client.rs +++ b/golem-embed/embed-hugging-face/src/client.rs @@ -38,9 +38,10 @@ impl EmbeddingsApi { trace!("Sending request to Hugging Face API: {request:?}"); let response = self .client - .request(Method::POST, format!( - "{BASE_URL}/models/{model}/pipeline/feature-extraction" - )) + .request( + Method::POST, + format!("{BASE_URL}/models/{model}/pipeline/feature-extraction"), + ) .bearer_auth(&self.huggingface_api_key) .json(&request) .send() @@ -48,64 +49,40 @@ impl EmbeddingsApi { parse_response::(response) } - - pub fn rerank(&self, request: RerankRequest, model: &str) -> Result { - trace!("Sending rerank request to Hugging Face API: {request:?}"); - let response = self - .client - .request(Method::POST, format!( - "{BASE_URL}/models/{model}/pipeline/text-classification" - )) - .bearer_auth(&self.huggingface_api_key) - .json(&request) - .send() - .map_err(|err| from_reqwest_error("Request failed", err))?; - parse_response::(response) - } } fn parse_response(response: Response) -> Result { let status = response.status(); - match status.is_success() { - true => { - let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; - match serde_json::from_str::(&response_text) { - Ok(response_data) => { - trace!("Response from Hugging Face API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Failed to decode response body: {}", response_text), - provider_error_json: Some(error.to_string()), - }) - } - } - }, - false => { - let error_text = response.text().ok(); + let response_text = response + .text() + .map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from Hugging Face API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); Err(Error { code: error_code_from_status(status), - message: "Failed to parse response".to_string(), - provider_error_json: error_text, + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), }) - }, + } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmbeddingRequest { - pub input: Vec, + pub inputs: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub normalize: Option, /// The name of the prompt that should be used by for encoding. /// If not set, no prompt will be applied. Must be a key in the /// `sentence-transformers` configuration `prompts` dictionary. - /// For example if `prompt_name` is “query” and the `prompts` is {“query”: “query: ”, …}, - /// then the sentence “What is the capital of France?” will be encoded as - /// “query: What is the capital of France?” because the prompt text will + /// For example if `prompt_name` is "query" and the `prompts` is {"query": "query: ", …}, + /// then the sentence "What is the capital of France?" will be encoded as + /// "query: What is the capital of France?" because the prompt text will /// be prepended before any text to encode. #[serde(skip_serializing_if = "Option::is_none")] pub prompt_name: Option, diff --git a/golem-embed/embed-hugging-face/src/conversions.rs b/golem-embed/embed-hugging-face/src/conversions.rs index 9be6b2219..3c5318fb2 100644 --- a/golem-embed/embed-hugging-face/src/conversions.rs +++ b/golem-embed/embed-hugging-face/src/conversions.rs @@ -22,7 +22,7 @@ pub fn create_embedding_request(inputs: Vec, config: Config) -> Res .unwrap_or_else(|| "sentence-transformers/all-MiniLM-L6-v2".to_string()); let request = EmbeddingRequest { - input: input_texts, + inputs: input_texts, normalize: Some(true), prompt_name: None, truncate: config.truncation, @@ -52,46 +52,6 @@ pub fn process_embedding_response( }) } -pub fn create_rerank_request( - query: String, - documents: Vec, - config: Config, -) -> Result<(RerankRequest, String), Error> { - let model = config - .model - .unwrap_or_else(|| "cross-encoder/ms-marco-MiniLM-L-2-v2".to_string()); - - let request = RerankRequest { - query, - documents, - top_k: config.dimensions, - return_documents: Some(true), - }; - - Ok((request, model)) -} - -pub fn process_rerank_response( - response: RerankResponse, - model: String, -) -> Result { - let mut results = Vec::new(); - for result in response.results { - results.push(golem_embed::golem::embed::embed::RerankResult { - index: result.index, - relevance_score: result.relevance_score, - document: result.document, - }); - } - - Ok(GolemRerankResponse { - results, - usage: None, - model, - provider_metadata_json: None, - }) -} - #[cfg(test)] mod tests { use golem_embed::golem::embed::embed::{ImageUrl, OutputDtype, OutputFormat, TaskType}; @@ -113,7 +73,7 @@ mod tests { }; let result = create_embedding_request(inputs, config); let (request, model) = result.unwrap(); - assert_eq!(request.input, vec!["Hello, world!"]); + assert_eq!(request.inputs, vec!["Hello, world!"]); assert_eq!(model, "sentence-transformers/all-MiniLM-L6-v2"); assert_eq!(request.normalize, Some(true)); assert_eq!(request.truncate, Some(false)); @@ -152,27 +112,4 @@ mod tests { let request = create_embedding_request(inputs, config); assert!(request.is_err()); } - - #[test] - fn test_create_rerank_request() { - let query = "What is the capital of France?".to_string(); - let documents = vec!["Paris is the capital of France.".to_string()]; - let config = Config { - model: Some("cross-encoder/ms-marco-MiniLM-L-2-v2".to_string()), - dimensions: Some(10), - user: Some("test_user".to_string()), - task_type: Some(TaskType::RetrievalQuery), - truncation: Some(false), - output_format: Some(OutputFormat::FloatArray), - output_dtype: Some(OutputDtype::FloatArray), - provider_options: vec![], - }; - let result = create_rerank_request(query.clone(), documents.clone(), config); - let (request, model) = result.unwrap(); - assert_eq!(request.query, query); - assert_eq!(request.documents, documents); - assert_eq!(request.top_k, Some(10)); - assert_eq!(request.return_documents, Some(true)); - assert_eq!(model, "cross-encoder/ms-marco-MiniLM-L-2-v2"); - } } \ No newline at end of file diff --git a/golem-embed/embed-hugging-face/src/lib.rs b/golem-embed/embed-hugging-face/src/lib.rs index 593ecd6da..3fc9b7f2b 100644 --- a/golem-embed/embed-hugging-face/src/lib.rs +++ b/golem-embed/embed-hugging-face/src/lib.rs @@ -32,18 +32,7 @@ impl HuggingFaceComponent { } } - fn rerank( - client: EmbeddingsApi, - query: String, - documents: Vec, - config: Config, - ) -> Result { - let (request, model) = create_rerank_request(query, documents, config)?; - match client.rerank(request, &model) { - Ok(response) => process_rerank_response(response, model), - Err(err) => Err(err), - } - } + } impl Guest for HuggingFaceComponent { @@ -60,10 +49,10 @@ impl Guest for HuggingFaceComponent { documents: Vec, config: Config, ) -> Result { - LOGGING_STATE.with_borrow_mut(|state| state.init()); - with_config_key(Self::ENV_VAR_NAME, Err, |huggingface_api_key| { - let client = EmbeddingsApi::new(huggingface_api_key); - Self::rerank(client, query, documents, config) + Err(Error { + code: ErrorCode::Unsupported, + message: "Hugging Face inference does not support rerank".to_string(), + provider_error_json: None, }) } } diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index ddd855ecd..e63baaa7d 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -49,32 +49,22 @@ impl EmbeddingsApi { fn parse_response(response: Response) -> Result { let status = response.status(); - match status.is_success() { - true => { - let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; - match serde_json::from_str::(&response_text) { - Ok(response_data) => { - trace!("Response from OpenAI API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Failed to decode response body: {}", response_text), - provider_error_json: Some(error.to_string()), - }) - } - } - }, - false => { - let error_text = response.text().ok(); + let response_text = response + .text() + .map_err(|err| from_reqwest_error("Failed to read response body", err))?; + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from Hugging Face API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); Err(Error { code: error_code_from_status(status), - message: "Failed to parse response".to_string(), - provider_error_json: error_text, + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), }) - }, + } } } diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs index 1e78bbfd8..8a21e4ca6 100644 --- a/golem-embed/embed-voyageai/src/client.rs +++ b/golem-embed/embed-voyageai/src/client.rs @@ -16,16 +16,16 @@ const BASE_URL: &str = "https://api.voyageai.com"; /// Based on https://docs.voyageai.com/reference/embeddings-api /// and https://docs.voyageai.com/reference/reranker-api pub struct VoyageAIApi { - api_key: String, + voyageai_api_key: String, client: Client, } impl VoyageAIApi { - pub fn new(api_key: String) -> Self { + pub fn new(voyageai_api_key: String) -> Self { let client = Client::builder() .build() .expect("Failed to initialize HTTP client"); - Self { api_key, client } + Self { voyageai_api_key, client } } pub fn generate_embedding( @@ -36,7 +36,7 @@ impl VoyageAIApi { let response = self .client .request(Method::POST, format!("{BASE_URL}/v1/embeddings")) - .bearer_auth(&self.api_key) + .bearer_auth(&self.voyageai_api_key) .json(&request) .send() .map_err(|err| from_reqwest_error("Embedding request failed", err))?; @@ -48,7 +48,7 @@ impl VoyageAIApi { let response = self .client .request(Method::POST, format!("{BASE_URL}/v1/rerank")) - .bearer_auth(&self.api_key) + .bearer_auth(&self.voyageai_api_key) .json(&request) .send() .map_err(|err| from_reqwest_error("Rerank request failed", err))?; @@ -58,32 +58,49 @@ impl VoyageAIApi { fn parse_response(response: Response) -> Result { let status = response.status(); - match status.is_success() { - true => { - let response_text = response.text().map_err(|err| from_reqwest_error("Failed to read response body", err))?; - match serde_json::from_str::(&response_text) { - Ok(response_data) => { - trace!("Response from VoyageAI API: {response_data:?}"); - Ok(response_data) - } - Err(error) => { - trace!("Error parsing response: {error:?}"); - Err(Error { - code: error_code_from_status(status), - message: format!("Failed to decode response body: {}", response_text), - provider_error_json: Some(error.to_string()), - }) - } + let response_text = response + .text() + .map_err(|err| from_reqwest_error("Failed to read response body", err))?; + + if !status.is_success() { + if let Ok(error_response) = serde_json::from_str::(&response_text) { + return Err(Error { + code: error_code_from_status(status), + message: error_response.error.message, + provider_error_json: Some(response_text), + }); + } + + if let Ok(detail_error) = serde_json::from_str::(&response_text) { + if let Some(detail) = detail_error.get("detail").and_then(|d| d.as_str()) { + return Err(Error { + code: error_code_from_status(status), + message: detail.to_string(), + provider_error_json: Some(response_text), + }); } - }, - false => { - let error_text = response.text().ok(); + } + + return Err(Error { + code: error_code_from_status(status), + message: format!("Request failed with status {}: {}", status, response_text), + provider_error_json: Some(response_text), + }); + } + + match serde_json::from_str::(&response_text) { + Ok(response_data) => { + trace!("Response from VoyageAI API: {response_data:?}"); + Ok(response_data) + } + Err(error) => { + trace!("Error parsing response: {error:?}"); Err(Error { code: error_code_from_status(status), - message: "Failed to parse response".to_string(), - provider_error_json: error_text, + message: format!("Failed to decode response body: {}", response_text), + provider_error_json: Some(error.to_string()), }) - }, + } } } @@ -110,11 +127,14 @@ pub enum EncodingFormat { #[derive(Debug, Serialize, Deserialize, Clone)] pub enum InputType { + #[serde(rename = "document")] Document, + #[serde(rename = "query")] Query, } #[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "lowercase")] pub enum OutputDtype { Float, Int8, @@ -143,7 +163,7 @@ pub struct EmbeddingUsage { pub total_tokens: u32, } -// Rerank API structures + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct RerankRequest { pub query: String, diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs index a81706b91..9310bffd4 100644 --- a/golem-embed/embed-voyageai/src/lib.rs +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -1,6 +1,7 @@ use golem_embed::{ + config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, - golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}, + golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}, LOGGING_STATE, }; use crate::{ @@ -53,8 +54,12 @@ impl VoyageAIApiComponent { impl Guest for VoyageAIApiComponent { fn generate(inputs: Vec, config: Config) -> Result { - let client = VoyageAIApi::new(Self::ENV_VAR_NAME.to_string()); - Self::embeddings(client, inputs, config) + LOGGING_STATE.with_borrow_mut(|state| state.init()); + + with_config_key(Self::ENV_VAR_NAME, Err, |voyageai_api_key| { + let client = VoyageAIApi::new(voyageai_api_key); + Self::embeddings(client, inputs, config) + }) } fn rerank( @@ -62,8 +67,12 @@ impl Guest for VoyageAIApiComponent { documents: Vec, config: Config, ) -> Result { - let client = VoyageAIApi::new(Self::ENV_VAR_NAME.to_string()); - Self::rerank(client, query, documents, config) + LOGGING_STATE.with_borrow_mut(|state| state.init()); + + with_config_key(Self::ENV_VAR_NAME, Err, |voyageai_api_key| { + let client = VoyageAIApi::new(voyageai_api_key); + Self::rerank(client, query, documents, config) + }) } } diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index c48d77f16..b040b99b5 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -21,7 +21,6 @@ pub struct LoggingState { } impl LoggingState { - /// Initializes WASI logging based on the `GOLEM_LLM_LOG` environment variable. pub fn init(&mut self) { if !self.logging_initialized { let _ = wasi_logger::Logger::install(); @@ -35,7 +34,6 @@ impl LoggingState { } thread_local! { - /// This holds the state of our application. pub static LOGGING_STATE: RefCell = const { RefCell::new(LoggingState { logging_initialized: false, }) }; diff --git a/golem-embed/test/components-rust/test-embed/src/lib.rs b/golem-embed/test/components-rust/test-embed/src/lib.rs index 5fe3e6893..fac64bfb8 100644 --- a/golem-embed/test/components-rust/test-embed/src/lib.rs +++ b/golem-embed/test/components-rust/test-embed/src/lib.rs @@ -16,7 +16,7 @@ const MODEL: &'static str = "embed-english-v3.0"; #[cfg(feature = "hugging-face")] const MODEL: &'static str = "sentence-transformers/all-MiniLM-L6-v2"; #[cfg(feature = "voyageai")] -const MODEL: &'static str = "voyage-3.5-lite"; +const MODEL: &'static str = "voyage-3"; #[cfg(feature = "openai")] const RERANKING_MODEL: &'static str = ""; @@ -25,7 +25,7 @@ const RERANKING_MODEL: &'static str = "rerank-v3.5"; #[cfg(feature = "hugging-face")] const RERANKING_MODEL: &'static str = "cross-encoder/ms-marco-MiniLM-L-2-v2"; #[cfg(feature = "voyageai")] -const RERANKING_MODEL: &'static str = "rerank-2-lite"; +const RERANKING_MODEL: &'static str = "rerank-1"; impl Guest for Component { /// test1 demonstrates text embedding generation. From 4c022f1ab7c4dd12241bd1ae2dd105c9494f6d50 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 13 Jun 2025 09:44:52 +0000 Subject: [PATCH 24/36] undo refactor --- Cargo.toml | 15 ++++++++------- golem-llm/Makefile.toml => Makefile.toml | 0 golem-llm/README.md => README.md | 0 .../llm-anthropic => llm-anthropic}/Cargo.toml | 0 .../src/bindings.rs | 0 .../src/client.rs | 0 .../src/conversions.rs | 0 .../llm-anthropic => llm-anthropic}/src/lib.rs | 0 .../wit/anhropic.wit | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../wit/deps/wasi:io/error.wit | 0 .../wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../wit/deps/wasi:io/world.wit | 0 {golem-llm/llm-grok => llm-grok}/Cargo.toml | 0 {golem-llm/llm-grok => llm-grok}/src/bindings.rs | 0 {golem-llm/llm-grok => llm-grok}/src/client.rs | 0 .../llm-grok => llm-grok}/src/conversions.rs | 0 {golem-llm/llm-grok => llm-grok}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../wit/deps/wasi:io/error.wit | 0 .../wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../wit/deps/wasi:io/world.wit | 0 {golem-llm/llm-grok => llm-grok}/wit/grok.wit | 0 {golem-llm/llm-ollama => llm-ollama}/Cargo.toml | 0 .../llm-ollama => llm-ollama}/src/bindings.rs | 0 .../llm-ollama => llm-ollama}/src/client.rs | 0 .../llm-ollama => llm-ollama}/src/conversions.rs | 0 {golem-llm/llm-ollama => llm-ollama}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../wit/deps/wasi:io/error.wit | 0 .../wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../wit/deps/wasi:io/world.wit | 0 .../llm-ollama => llm-ollama}/wit/ollama.wit | 0 {golem-llm/llm-openai => llm-openai}/Cargo.toml | 0 .../llm-openai => llm-openai}/src/bindings.rs | 0 .../llm-openai => llm-openai}/src/client.rs | 0 .../llm-openai => llm-openai}/src/conversions.rs | 0 {golem-llm/llm-openai => llm-openai}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../wit/deps/wasi:io/error.wit | 0 .../wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../wit/deps/wasi:io/world.wit | 0 .../llm-openai => llm-openai}/wit/openai.wit | 0 .../llm-openrouter => llm-openrouter}/Cargo.toml | 0 .../src/bindings.rs | 0 .../src/client.rs | 0 .../src/conversions.rs | 0 .../llm-openrouter => llm-openrouter}/src/lib.rs | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 .../wit/deps/wasi:io/error.wit | 0 .../wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../wit/deps/wasi:io/world.wit | 0 .../wit/openrouter.wit | 0 {golem-llm/llm => llm}/Cargo.toml | 0 {golem-llm/llm => llm}/src/chat_stream.rs | 0 {golem-llm/llm => llm}/src/config.rs | 0 {golem-llm/llm => llm}/src/durability.rs | 0 {golem-llm/llm => llm}/src/error.rs | 0 {golem-llm/llm => llm}/src/event_source/error.rs | 0 .../llm => llm}/src/event_source/event_stream.rs | 0 .../src/event_source/message_event.rs | 0 {golem-llm/llm => llm}/src/event_source/mod.rs | 0 .../src/event_source/ndjson_stream.rs | 0 .../llm => llm}/src/event_source/parser.rs | 0 .../llm => llm}/src/event_source/stream.rs | 0 .../llm => llm}/src/event_source/utf8_stream.rs | 0 {golem-llm/llm => llm}/src/lib.rs | 0 .../llm => llm}/wit/deps/golem-llm/golem-llm.wit | 0 .../llm => llm}/wit/deps/wasi:io/error.wit | 0 {golem-llm/llm => llm}/wit/deps/wasi:io/poll.wit | 0 .../llm => llm}/wit/deps/wasi:io/streams.wit | 0 .../llm => llm}/wit/deps/wasi:io/world.wit | 0 {golem-llm/llm => llm}/wit/llm.wit | 0 {golem-llm/test => test}/.gitignore | 0 {golem-llm/test => test}/.vscode/settings.json | 0 {golem-llm/test => test}/Cargo.lock | 0 {golem-llm/test => test}/Cargo.toml | 0 .../common-rust/common-lib/Cargo.toml | 0 .../common-rust/common-lib/src/lib.rs | 0 {golem-llm/test => test}/common-rust/golem.yaml | 0 .../test => test}/components-rust/.gitignore | 0 .../components-rust/test-helper/Cargo.lock | 0 .../components-rust/test-helper/Cargo.toml | 0 .../components-rust/test-helper/golem.yaml | 0 .../components-rust/test-helper/src/lib.rs | 0 .../test-helper/wit/test-helper.wit | 0 .../components-rust/test-llm/Cargo.lock | 0 .../components-rust/test-llm/Cargo.toml | 0 .../components-rust/test-llm/golem.yaml | 0 .../components-rust/test-llm/src/lib.rs | 0 .../components-rust/test-llm/wit/test-llm.wit | 0 {golem-llm/test => test}/data/cat.png | Bin {golem-llm/test => test}/golem.yaml | 0 .../wit/deps/golem-llm/golem-llm.wit | 0 {golem-llm/test => test}/wit/deps/io/error.wit | 0 {golem-llm/test => test}/wit/deps/io/poll.wit | 0 {golem-llm/test => test}/wit/deps/io/streams.wit | 0 {golem-llm/test => test}/wit/deps/io/world.wit | 0 {golem-llm/wit => wit}/deps.lock | 0 {golem-llm/wit => wit}/deps.toml | 0 {golem-llm/wit => wit}/deps/wasi:io/error.wit | 0 {golem-llm/wit => wit}/deps/wasi:io/poll.wit | 0 {golem-llm/wit => wit}/deps/wasi:io/streams.wit | 0 {golem-llm/wit => wit}/deps/wasi:io/world.wit | 0 {golem-llm/wit => wit}/golem-llm.wit | 0 110 files changed, 8 insertions(+), 7 deletions(-) rename golem-llm/Makefile.toml => Makefile.toml (100%) rename golem-llm/README.md => README.md (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/Cargo.toml (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/src/bindings.rs (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/src/client.rs (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/src/conversions.rs (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/src/lib.rs (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/wit/anhropic.wit (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/wit/deps/wasi:io/error.wit (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/wit/deps/wasi:io/poll.wit (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/wit/deps/wasi:io/streams.wit (100%) rename {golem-llm/llm-anthropic => llm-anthropic}/wit/deps/wasi:io/world.wit (100%) rename {golem-llm/llm-grok => llm-grok}/Cargo.toml (100%) rename {golem-llm/llm-grok => llm-grok}/src/bindings.rs (100%) rename {golem-llm/llm-grok => llm-grok}/src/client.rs (100%) rename {golem-llm/llm-grok => llm-grok}/src/conversions.rs (100%) rename {golem-llm/llm-grok => llm-grok}/src/lib.rs (100%) rename {golem-llm/llm-grok => llm-grok}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/llm-grok => llm-grok}/wit/deps/wasi:io/error.wit (100%) rename {golem-llm/llm-grok => llm-grok}/wit/deps/wasi:io/poll.wit (100%) rename {golem-llm/llm-grok => llm-grok}/wit/deps/wasi:io/streams.wit (100%) rename {golem-llm/llm-grok => llm-grok}/wit/deps/wasi:io/world.wit (100%) rename {golem-llm/llm-grok => llm-grok}/wit/grok.wit (100%) rename {golem-llm/llm-ollama => llm-ollama}/Cargo.toml (100%) rename {golem-llm/llm-ollama => llm-ollama}/src/bindings.rs (100%) rename {golem-llm/llm-ollama => llm-ollama}/src/client.rs (100%) rename {golem-llm/llm-ollama => llm-ollama}/src/conversions.rs (100%) rename {golem-llm/llm-ollama => llm-ollama}/src/lib.rs (100%) rename {golem-llm/llm-ollama => llm-ollama}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/llm-ollama => llm-ollama}/wit/deps/wasi:io/error.wit (100%) rename {golem-llm/llm-ollama => llm-ollama}/wit/deps/wasi:io/poll.wit (100%) rename {golem-llm/llm-ollama => llm-ollama}/wit/deps/wasi:io/streams.wit (100%) rename {golem-llm/llm-ollama => llm-ollama}/wit/deps/wasi:io/world.wit (100%) rename {golem-llm/llm-ollama => llm-ollama}/wit/ollama.wit (100%) rename {golem-llm/llm-openai => llm-openai}/Cargo.toml (100%) rename {golem-llm/llm-openai => llm-openai}/src/bindings.rs (100%) rename {golem-llm/llm-openai => llm-openai}/src/client.rs (100%) rename {golem-llm/llm-openai => llm-openai}/src/conversions.rs (100%) rename {golem-llm/llm-openai => llm-openai}/src/lib.rs (100%) rename {golem-llm/llm-openai => llm-openai}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/llm-openai => llm-openai}/wit/deps/wasi:io/error.wit (100%) rename {golem-llm/llm-openai => llm-openai}/wit/deps/wasi:io/poll.wit (100%) rename {golem-llm/llm-openai => llm-openai}/wit/deps/wasi:io/streams.wit (100%) rename {golem-llm/llm-openai => llm-openai}/wit/deps/wasi:io/world.wit (100%) rename {golem-llm/llm-openai => llm-openai}/wit/openai.wit (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/Cargo.toml (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/src/bindings.rs (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/src/client.rs (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/src/conversions.rs (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/src/lib.rs (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/wit/deps/wasi:io/error.wit (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/wit/deps/wasi:io/poll.wit (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/wit/deps/wasi:io/streams.wit (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/wit/deps/wasi:io/world.wit (100%) rename {golem-llm/llm-openrouter => llm-openrouter}/wit/openrouter.wit (100%) rename {golem-llm/llm => llm}/Cargo.toml (100%) rename {golem-llm/llm => llm}/src/chat_stream.rs (100%) rename {golem-llm/llm => llm}/src/config.rs (100%) rename {golem-llm/llm => llm}/src/durability.rs (100%) rename {golem-llm/llm => llm}/src/error.rs (100%) rename {golem-llm/llm => llm}/src/event_source/error.rs (100%) rename {golem-llm/llm => llm}/src/event_source/event_stream.rs (100%) rename {golem-llm/llm => llm}/src/event_source/message_event.rs (100%) rename {golem-llm/llm => llm}/src/event_source/mod.rs (100%) rename {golem-llm/llm => llm}/src/event_source/ndjson_stream.rs (100%) rename {golem-llm/llm => llm}/src/event_source/parser.rs (100%) rename {golem-llm/llm => llm}/src/event_source/stream.rs (100%) rename {golem-llm/llm => llm}/src/event_source/utf8_stream.rs (100%) rename {golem-llm/llm => llm}/src/lib.rs (100%) rename {golem-llm/llm => llm}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/llm => llm}/wit/deps/wasi:io/error.wit (100%) rename {golem-llm/llm => llm}/wit/deps/wasi:io/poll.wit (100%) rename {golem-llm/llm => llm}/wit/deps/wasi:io/streams.wit (100%) rename {golem-llm/llm => llm}/wit/deps/wasi:io/world.wit (100%) rename {golem-llm/llm => llm}/wit/llm.wit (100%) rename {golem-llm/test => test}/.gitignore (100%) rename {golem-llm/test => test}/.vscode/settings.json (100%) rename {golem-llm/test => test}/Cargo.lock (100%) rename {golem-llm/test => test}/Cargo.toml (100%) rename {golem-llm/test => test}/common-rust/common-lib/Cargo.toml (100%) rename {golem-llm/test => test}/common-rust/common-lib/src/lib.rs (100%) rename {golem-llm/test => test}/common-rust/golem.yaml (100%) rename {golem-llm/test => test}/components-rust/.gitignore (100%) rename {golem-llm/test => test}/components-rust/test-helper/Cargo.lock (100%) rename {golem-llm/test => test}/components-rust/test-helper/Cargo.toml (100%) rename {golem-llm/test => test}/components-rust/test-helper/golem.yaml (100%) rename {golem-llm/test => test}/components-rust/test-helper/src/lib.rs (100%) rename {golem-llm/test => test}/components-rust/test-helper/wit/test-helper.wit (100%) rename {golem-llm/test => test}/components-rust/test-llm/Cargo.lock (100%) rename {golem-llm/test => test}/components-rust/test-llm/Cargo.toml (100%) rename {golem-llm/test => test}/components-rust/test-llm/golem.yaml (100%) rename {golem-llm/test => test}/components-rust/test-llm/src/lib.rs (100%) rename {golem-llm/test => test}/components-rust/test-llm/wit/test-llm.wit (100%) rename {golem-llm/test => test}/data/cat.png (100%) rename {golem-llm/test => test}/golem.yaml (100%) rename {golem-llm/test => test}/wit/deps/golem-llm/golem-llm.wit (100%) rename {golem-llm/test => test}/wit/deps/io/error.wit (100%) rename {golem-llm/test => test}/wit/deps/io/poll.wit (100%) rename {golem-llm/test => test}/wit/deps/io/streams.wit (100%) rename {golem-llm/test => test}/wit/deps/io/world.wit (100%) rename {golem-llm/wit => wit}/deps.lock (100%) rename {golem-llm/wit => wit}/deps.toml (100%) rename {golem-llm/wit => wit}/deps/wasi:io/error.wit (100%) rename {golem-llm/wit => wit}/deps/wasi:io/poll.wit (100%) rename {golem-llm/wit => wit}/deps/wasi:io/streams.wit (100%) rename {golem-llm/wit => wit}/deps/wasi:io/world.wit (100%) rename {golem-llm/wit => wit}/golem-llm.wit (100%) diff --git a/Cargo.toml b/Cargo.toml index 8c244eeeb..a2918210d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,16 +2,17 @@ resolver = "2" members = [ + "llm", + "llm-anthropic", + "llm-grok", + "llm-ollama", + "llm-openai", + "llm-openrouter", "golem-embed/embed", "golem-embed/embed-cohere", "golem-embed/embed-hugging-face", - "golem-embed/embed-openai", "golem-embed/embed-voyageai", - "golem-llm/llm", - "golem-llm/llm-anthropic", - "golem-llm/llm-grok", - "golem-llm/llm-ollama", - "golem-llm/llm-openai", - "golem-llm/llm-openrouter", + "golem-embed/embed-openai", + "golem-embed/embed-voyageai", ] [profile.release] diff --git a/golem-llm/Makefile.toml b/Makefile.toml similarity index 100% rename from golem-llm/Makefile.toml rename to Makefile.toml diff --git a/golem-llm/README.md b/README.md similarity index 100% rename from golem-llm/README.md rename to README.md diff --git a/golem-llm/llm-anthropic/Cargo.toml b/llm-anthropic/Cargo.toml similarity index 100% rename from golem-llm/llm-anthropic/Cargo.toml rename to llm-anthropic/Cargo.toml diff --git a/golem-llm/llm-anthropic/src/bindings.rs b/llm-anthropic/src/bindings.rs similarity index 100% rename from golem-llm/llm-anthropic/src/bindings.rs rename to llm-anthropic/src/bindings.rs diff --git a/golem-llm/llm-anthropic/src/client.rs b/llm-anthropic/src/client.rs similarity index 100% rename from golem-llm/llm-anthropic/src/client.rs rename to llm-anthropic/src/client.rs diff --git a/golem-llm/llm-anthropic/src/conversions.rs b/llm-anthropic/src/conversions.rs similarity index 100% rename from golem-llm/llm-anthropic/src/conversions.rs rename to llm-anthropic/src/conversions.rs diff --git a/golem-llm/llm-anthropic/src/lib.rs b/llm-anthropic/src/lib.rs similarity index 100% rename from golem-llm/llm-anthropic/src/lib.rs rename to llm-anthropic/src/lib.rs diff --git a/golem-llm/llm-anthropic/wit/anhropic.wit b/llm-anthropic/wit/anhropic.wit similarity index 100% rename from golem-llm/llm-anthropic/wit/anhropic.wit rename to llm-anthropic/wit/anhropic.wit diff --git a/golem-llm/llm-anthropic/wit/deps/golem-llm/golem-llm.wit b/llm-anthropic/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/llm-anthropic/wit/deps/golem-llm/golem-llm.wit rename to llm-anthropic/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/llm-anthropic/wit/deps/wasi:io/error.wit b/llm-anthropic/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/llm-anthropic/wit/deps/wasi:io/error.wit rename to llm-anthropic/wit/deps/wasi:io/error.wit diff --git a/golem-llm/llm-anthropic/wit/deps/wasi:io/poll.wit b/llm-anthropic/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/llm-anthropic/wit/deps/wasi:io/poll.wit rename to llm-anthropic/wit/deps/wasi:io/poll.wit diff --git a/golem-llm/llm-anthropic/wit/deps/wasi:io/streams.wit b/llm-anthropic/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/llm-anthropic/wit/deps/wasi:io/streams.wit rename to llm-anthropic/wit/deps/wasi:io/streams.wit diff --git a/golem-llm/llm-anthropic/wit/deps/wasi:io/world.wit b/llm-anthropic/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/llm-anthropic/wit/deps/wasi:io/world.wit rename to llm-anthropic/wit/deps/wasi:io/world.wit diff --git a/golem-llm/llm-grok/Cargo.toml b/llm-grok/Cargo.toml similarity index 100% rename from golem-llm/llm-grok/Cargo.toml rename to llm-grok/Cargo.toml diff --git a/golem-llm/llm-grok/src/bindings.rs b/llm-grok/src/bindings.rs similarity index 100% rename from golem-llm/llm-grok/src/bindings.rs rename to llm-grok/src/bindings.rs diff --git a/golem-llm/llm-grok/src/client.rs b/llm-grok/src/client.rs similarity index 100% rename from golem-llm/llm-grok/src/client.rs rename to llm-grok/src/client.rs diff --git a/golem-llm/llm-grok/src/conversions.rs b/llm-grok/src/conversions.rs similarity index 100% rename from golem-llm/llm-grok/src/conversions.rs rename to llm-grok/src/conversions.rs diff --git a/golem-llm/llm-grok/src/lib.rs b/llm-grok/src/lib.rs similarity index 100% rename from golem-llm/llm-grok/src/lib.rs rename to llm-grok/src/lib.rs diff --git a/golem-llm/llm-grok/wit/deps/golem-llm/golem-llm.wit b/llm-grok/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/llm-grok/wit/deps/golem-llm/golem-llm.wit rename to llm-grok/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/llm-grok/wit/deps/wasi:io/error.wit b/llm-grok/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/llm-grok/wit/deps/wasi:io/error.wit rename to llm-grok/wit/deps/wasi:io/error.wit diff --git a/golem-llm/llm-grok/wit/deps/wasi:io/poll.wit b/llm-grok/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/llm-grok/wit/deps/wasi:io/poll.wit rename to llm-grok/wit/deps/wasi:io/poll.wit diff --git a/golem-llm/llm-grok/wit/deps/wasi:io/streams.wit b/llm-grok/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/llm-grok/wit/deps/wasi:io/streams.wit rename to llm-grok/wit/deps/wasi:io/streams.wit diff --git a/golem-llm/llm-grok/wit/deps/wasi:io/world.wit b/llm-grok/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/llm-grok/wit/deps/wasi:io/world.wit rename to llm-grok/wit/deps/wasi:io/world.wit diff --git a/golem-llm/llm-grok/wit/grok.wit b/llm-grok/wit/grok.wit similarity index 100% rename from golem-llm/llm-grok/wit/grok.wit rename to llm-grok/wit/grok.wit diff --git a/golem-llm/llm-ollama/Cargo.toml b/llm-ollama/Cargo.toml similarity index 100% rename from golem-llm/llm-ollama/Cargo.toml rename to llm-ollama/Cargo.toml diff --git a/golem-llm/llm-ollama/src/bindings.rs b/llm-ollama/src/bindings.rs similarity index 100% rename from golem-llm/llm-ollama/src/bindings.rs rename to llm-ollama/src/bindings.rs diff --git a/golem-llm/llm-ollama/src/client.rs b/llm-ollama/src/client.rs similarity index 100% rename from golem-llm/llm-ollama/src/client.rs rename to llm-ollama/src/client.rs diff --git a/golem-llm/llm-ollama/src/conversions.rs b/llm-ollama/src/conversions.rs similarity index 100% rename from golem-llm/llm-ollama/src/conversions.rs rename to llm-ollama/src/conversions.rs diff --git a/golem-llm/llm-ollama/src/lib.rs b/llm-ollama/src/lib.rs similarity index 100% rename from golem-llm/llm-ollama/src/lib.rs rename to llm-ollama/src/lib.rs diff --git a/golem-llm/llm-ollama/wit/deps/golem-llm/golem-llm.wit b/llm-ollama/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/llm-ollama/wit/deps/golem-llm/golem-llm.wit rename to llm-ollama/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/llm-ollama/wit/deps/wasi:io/error.wit b/llm-ollama/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/llm-ollama/wit/deps/wasi:io/error.wit rename to llm-ollama/wit/deps/wasi:io/error.wit diff --git a/golem-llm/llm-ollama/wit/deps/wasi:io/poll.wit b/llm-ollama/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/llm-ollama/wit/deps/wasi:io/poll.wit rename to llm-ollama/wit/deps/wasi:io/poll.wit diff --git a/golem-llm/llm-ollama/wit/deps/wasi:io/streams.wit b/llm-ollama/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/llm-ollama/wit/deps/wasi:io/streams.wit rename to llm-ollama/wit/deps/wasi:io/streams.wit diff --git a/golem-llm/llm-ollama/wit/deps/wasi:io/world.wit b/llm-ollama/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/llm-ollama/wit/deps/wasi:io/world.wit rename to llm-ollama/wit/deps/wasi:io/world.wit diff --git a/golem-llm/llm-ollama/wit/ollama.wit b/llm-ollama/wit/ollama.wit similarity index 100% rename from golem-llm/llm-ollama/wit/ollama.wit rename to llm-ollama/wit/ollama.wit diff --git a/golem-llm/llm-openai/Cargo.toml b/llm-openai/Cargo.toml similarity index 100% rename from golem-llm/llm-openai/Cargo.toml rename to llm-openai/Cargo.toml diff --git a/golem-llm/llm-openai/src/bindings.rs b/llm-openai/src/bindings.rs similarity index 100% rename from golem-llm/llm-openai/src/bindings.rs rename to llm-openai/src/bindings.rs diff --git a/golem-llm/llm-openai/src/client.rs b/llm-openai/src/client.rs similarity index 100% rename from golem-llm/llm-openai/src/client.rs rename to llm-openai/src/client.rs diff --git a/golem-llm/llm-openai/src/conversions.rs b/llm-openai/src/conversions.rs similarity index 100% rename from golem-llm/llm-openai/src/conversions.rs rename to llm-openai/src/conversions.rs diff --git a/golem-llm/llm-openai/src/lib.rs b/llm-openai/src/lib.rs similarity index 100% rename from golem-llm/llm-openai/src/lib.rs rename to llm-openai/src/lib.rs diff --git a/golem-llm/llm-openai/wit/deps/golem-llm/golem-llm.wit b/llm-openai/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/llm-openai/wit/deps/golem-llm/golem-llm.wit rename to llm-openai/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/llm-openai/wit/deps/wasi:io/error.wit b/llm-openai/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/llm-openai/wit/deps/wasi:io/error.wit rename to llm-openai/wit/deps/wasi:io/error.wit diff --git a/golem-llm/llm-openai/wit/deps/wasi:io/poll.wit b/llm-openai/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/llm-openai/wit/deps/wasi:io/poll.wit rename to llm-openai/wit/deps/wasi:io/poll.wit diff --git a/golem-llm/llm-openai/wit/deps/wasi:io/streams.wit b/llm-openai/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/llm-openai/wit/deps/wasi:io/streams.wit rename to llm-openai/wit/deps/wasi:io/streams.wit diff --git a/golem-llm/llm-openai/wit/deps/wasi:io/world.wit b/llm-openai/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/llm-openai/wit/deps/wasi:io/world.wit rename to llm-openai/wit/deps/wasi:io/world.wit diff --git a/golem-llm/llm-openai/wit/openai.wit b/llm-openai/wit/openai.wit similarity index 100% rename from golem-llm/llm-openai/wit/openai.wit rename to llm-openai/wit/openai.wit diff --git a/golem-llm/llm-openrouter/Cargo.toml b/llm-openrouter/Cargo.toml similarity index 100% rename from golem-llm/llm-openrouter/Cargo.toml rename to llm-openrouter/Cargo.toml diff --git a/golem-llm/llm-openrouter/src/bindings.rs b/llm-openrouter/src/bindings.rs similarity index 100% rename from golem-llm/llm-openrouter/src/bindings.rs rename to llm-openrouter/src/bindings.rs diff --git a/golem-llm/llm-openrouter/src/client.rs b/llm-openrouter/src/client.rs similarity index 100% rename from golem-llm/llm-openrouter/src/client.rs rename to llm-openrouter/src/client.rs diff --git a/golem-llm/llm-openrouter/src/conversions.rs b/llm-openrouter/src/conversions.rs similarity index 100% rename from golem-llm/llm-openrouter/src/conversions.rs rename to llm-openrouter/src/conversions.rs diff --git a/golem-llm/llm-openrouter/src/lib.rs b/llm-openrouter/src/lib.rs similarity index 100% rename from golem-llm/llm-openrouter/src/lib.rs rename to llm-openrouter/src/lib.rs diff --git a/golem-llm/llm-openrouter/wit/deps/golem-llm/golem-llm.wit b/llm-openrouter/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/llm-openrouter/wit/deps/golem-llm/golem-llm.wit rename to llm-openrouter/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/llm-openrouter/wit/deps/wasi:io/error.wit b/llm-openrouter/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/llm-openrouter/wit/deps/wasi:io/error.wit rename to llm-openrouter/wit/deps/wasi:io/error.wit diff --git a/golem-llm/llm-openrouter/wit/deps/wasi:io/poll.wit b/llm-openrouter/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/llm-openrouter/wit/deps/wasi:io/poll.wit rename to llm-openrouter/wit/deps/wasi:io/poll.wit diff --git a/golem-llm/llm-openrouter/wit/deps/wasi:io/streams.wit b/llm-openrouter/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/llm-openrouter/wit/deps/wasi:io/streams.wit rename to llm-openrouter/wit/deps/wasi:io/streams.wit diff --git a/golem-llm/llm-openrouter/wit/deps/wasi:io/world.wit b/llm-openrouter/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/llm-openrouter/wit/deps/wasi:io/world.wit rename to llm-openrouter/wit/deps/wasi:io/world.wit diff --git a/golem-llm/llm-openrouter/wit/openrouter.wit b/llm-openrouter/wit/openrouter.wit similarity index 100% rename from golem-llm/llm-openrouter/wit/openrouter.wit rename to llm-openrouter/wit/openrouter.wit diff --git a/golem-llm/llm/Cargo.toml b/llm/Cargo.toml similarity index 100% rename from golem-llm/llm/Cargo.toml rename to llm/Cargo.toml diff --git a/golem-llm/llm/src/chat_stream.rs b/llm/src/chat_stream.rs similarity index 100% rename from golem-llm/llm/src/chat_stream.rs rename to llm/src/chat_stream.rs diff --git a/golem-llm/llm/src/config.rs b/llm/src/config.rs similarity index 100% rename from golem-llm/llm/src/config.rs rename to llm/src/config.rs diff --git a/golem-llm/llm/src/durability.rs b/llm/src/durability.rs similarity index 100% rename from golem-llm/llm/src/durability.rs rename to llm/src/durability.rs diff --git a/golem-llm/llm/src/error.rs b/llm/src/error.rs similarity index 100% rename from golem-llm/llm/src/error.rs rename to llm/src/error.rs diff --git a/golem-llm/llm/src/event_source/error.rs b/llm/src/event_source/error.rs similarity index 100% rename from golem-llm/llm/src/event_source/error.rs rename to llm/src/event_source/error.rs diff --git a/golem-llm/llm/src/event_source/event_stream.rs b/llm/src/event_source/event_stream.rs similarity index 100% rename from golem-llm/llm/src/event_source/event_stream.rs rename to llm/src/event_source/event_stream.rs diff --git a/golem-llm/llm/src/event_source/message_event.rs b/llm/src/event_source/message_event.rs similarity index 100% rename from golem-llm/llm/src/event_source/message_event.rs rename to llm/src/event_source/message_event.rs diff --git a/golem-llm/llm/src/event_source/mod.rs b/llm/src/event_source/mod.rs similarity index 100% rename from golem-llm/llm/src/event_source/mod.rs rename to llm/src/event_source/mod.rs diff --git a/golem-llm/llm/src/event_source/ndjson_stream.rs b/llm/src/event_source/ndjson_stream.rs similarity index 100% rename from golem-llm/llm/src/event_source/ndjson_stream.rs rename to llm/src/event_source/ndjson_stream.rs diff --git a/golem-llm/llm/src/event_source/parser.rs b/llm/src/event_source/parser.rs similarity index 100% rename from golem-llm/llm/src/event_source/parser.rs rename to llm/src/event_source/parser.rs diff --git a/golem-llm/llm/src/event_source/stream.rs b/llm/src/event_source/stream.rs similarity index 100% rename from golem-llm/llm/src/event_source/stream.rs rename to llm/src/event_source/stream.rs diff --git a/golem-llm/llm/src/event_source/utf8_stream.rs b/llm/src/event_source/utf8_stream.rs similarity index 100% rename from golem-llm/llm/src/event_source/utf8_stream.rs rename to llm/src/event_source/utf8_stream.rs diff --git a/golem-llm/llm/src/lib.rs b/llm/src/lib.rs similarity index 100% rename from golem-llm/llm/src/lib.rs rename to llm/src/lib.rs diff --git a/golem-llm/llm/wit/deps/golem-llm/golem-llm.wit b/llm/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/llm/wit/deps/golem-llm/golem-llm.wit rename to llm/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/llm/wit/deps/wasi:io/error.wit b/llm/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/llm/wit/deps/wasi:io/error.wit rename to llm/wit/deps/wasi:io/error.wit diff --git a/golem-llm/llm/wit/deps/wasi:io/poll.wit b/llm/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/llm/wit/deps/wasi:io/poll.wit rename to llm/wit/deps/wasi:io/poll.wit diff --git a/golem-llm/llm/wit/deps/wasi:io/streams.wit b/llm/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/llm/wit/deps/wasi:io/streams.wit rename to llm/wit/deps/wasi:io/streams.wit diff --git a/golem-llm/llm/wit/deps/wasi:io/world.wit b/llm/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/llm/wit/deps/wasi:io/world.wit rename to llm/wit/deps/wasi:io/world.wit diff --git a/golem-llm/llm/wit/llm.wit b/llm/wit/llm.wit similarity index 100% rename from golem-llm/llm/wit/llm.wit rename to llm/wit/llm.wit diff --git a/golem-llm/test/.gitignore b/test/.gitignore similarity index 100% rename from golem-llm/test/.gitignore rename to test/.gitignore diff --git a/golem-llm/test/.vscode/settings.json b/test/.vscode/settings.json similarity index 100% rename from golem-llm/test/.vscode/settings.json rename to test/.vscode/settings.json diff --git a/golem-llm/test/Cargo.lock b/test/Cargo.lock similarity index 100% rename from golem-llm/test/Cargo.lock rename to test/Cargo.lock diff --git a/golem-llm/test/Cargo.toml b/test/Cargo.toml similarity index 100% rename from golem-llm/test/Cargo.toml rename to test/Cargo.toml diff --git a/golem-llm/test/common-rust/common-lib/Cargo.toml b/test/common-rust/common-lib/Cargo.toml similarity index 100% rename from golem-llm/test/common-rust/common-lib/Cargo.toml rename to test/common-rust/common-lib/Cargo.toml diff --git a/golem-llm/test/common-rust/common-lib/src/lib.rs b/test/common-rust/common-lib/src/lib.rs similarity index 100% rename from golem-llm/test/common-rust/common-lib/src/lib.rs rename to test/common-rust/common-lib/src/lib.rs diff --git a/golem-llm/test/common-rust/golem.yaml b/test/common-rust/golem.yaml similarity index 100% rename from golem-llm/test/common-rust/golem.yaml rename to test/common-rust/golem.yaml diff --git a/golem-llm/test/components-rust/.gitignore b/test/components-rust/.gitignore similarity index 100% rename from golem-llm/test/components-rust/.gitignore rename to test/components-rust/.gitignore diff --git a/golem-llm/test/components-rust/test-helper/Cargo.lock b/test/components-rust/test-helper/Cargo.lock similarity index 100% rename from golem-llm/test/components-rust/test-helper/Cargo.lock rename to test/components-rust/test-helper/Cargo.lock diff --git a/golem-llm/test/components-rust/test-helper/Cargo.toml b/test/components-rust/test-helper/Cargo.toml similarity index 100% rename from golem-llm/test/components-rust/test-helper/Cargo.toml rename to test/components-rust/test-helper/Cargo.toml diff --git a/golem-llm/test/components-rust/test-helper/golem.yaml b/test/components-rust/test-helper/golem.yaml similarity index 100% rename from golem-llm/test/components-rust/test-helper/golem.yaml rename to test/components-rust/test-helper/golem.yaml diff --git a/golem-llm/test/components-rust/test-helper/src/lib.rs b/test/components-rust/test-helper/src/lib.rs similarity index 100% rename from golem-llm/test/components-rust/test-helper/src/lib.rs rename to test/components-rust/test-helper/src/lib.rs diff --git a/golem-llm/test/components-rust/test-helper/wit/test-helper.wit b/test/components-rust/test-helper/wit/test-helper.wit similarity index 100% rename from golem-llm/test/components-rust/test-helper/wit/test-helper.wit rename to test/components-rust/test-helper/wit/test-helper.wit diff --git a/golem-llm/test/components-rust/test-llm/Cargo.lock b/test/components-rust/test-llm/Cargo.lock similarity index 100% rename from golem-llm/test/components-rust/test-llm/Cargo.lock rename to test/components-rust/test-llm/Cargo.lock diff --git a/golem-llm/test/components-rust/test-llm/Cargo.toml b/test/components-rust/test-llm/Cargo.toml similarity index 100% rename from golem-llm/test/components-rust/test-llm/Cargo.toml rename to test/components-rust/test-llm/Cargo.toml diff --git a/golem-llm/test/components-rust/test-llm/golem.yaml b/test/components-rust/test-llm/golem.yaml similarity index 100% rename from golem-llm/test/components-rust/test-llm/golem.yaml rename to test/components-rust/test-llm/golem.yaml diff --git a/golem-llm/test/components-rust/test-llm/src/lib.rs b/test/components-rust/test-llm/src/lib.rs similarity index 100% rename from golem-llm/test/components-rust/test-llm/src/lib.rs rename to test/components-rust/test-llm/src/lib.rs diff --git a/golem-llm/test/components-rust/test-llm/wit/test-llm.wit b/test/components-rust/test-llm/wit/test-llm.wit similarity index 100% rename from golem-llm/test/components-rust/test-llm/wit/test-llm.wit rename to test/components-rust/test-llm/wit/test-llm.wit diff --git a/golem-llm/test/data/cat.png b/test/data/cat.png similarity index 100% rename from golem-llm/test/data/cat.png rename to test/data/cat.png diff --git a/golem-llm/test/golem.yaml b/test/golem.yaml similarity index 100% rename from golem-llm/test/golem.yaml rename to test/golem.yaml diff --git a/golem-llm/test/wit/deps/golem-llm/golem-llm.wit b/test/wit/deps/golem-llm/golem-llm.wit similarity index 100% rename from golem-llm/test/wit/deps/golem-llm/golem-llm.wit rename to test/wit/deps/golem-llm/golem-llm.wit diff --git a/golem-llm/test/wit/deps/io/error.wit b/test/wit/deps/io/error.wit similarity index 100% rename from golem-llm/test/wit/deps/io/error.wit rename to test/wit/deps/io/error.wit diff --git a/golem-llm/test/wit/deps/io/poll.wit b/test/wit/deps/io/poll.wit similarity index 100% rename from golem-llm/test/wit/deps/io/poll.wit rename to test/wit/deps/io/poll.wit diff --git a/golem-llm/test/wit/deps/io/streams.wit b/test/wit/deps/io/streams.wit similarity index 100% rename from golem-llm/test/wit/deps/io/streams.wit rename to test/wit/deps/io/streams.wit diff --git a/golem-llm/test/wit/deps/io/world.wit b/test/wit/deps/io/world.wit similarity index 100% rename from golem-llm/test/wit/deps/io/world.wit rename to test/wit/deps/io/world.wit diff --git a/golem-llm/wit/deps.lock b/wit/deps.lock similarity index 100% rename from golem-llm/wit/deps.lock rename to wit/deps.lock diff --git a/golem-llm/wit/deps.toml b/wit/deps.toml similarity index 100% rename from golem-llm/wit/deps.toml rename to wit/deps.toml diff --git a/golem-llm/wit/deps/wasi:io/error.wit b/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-llm/wit/deps/wasi:io/error.wit rename to wit/deps/wasi:io/error.wit diff --git a/golem-llm/wit/deps/wasi:io/poll.wit b/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-llm/wit/deps/wasi:io/poll.wit rename to wit/deps/wasi:io/poll.wit diff --git a/golem-llm/wit/deps/wasi:io/streams.wit b/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-llm/wit/deps/wasi:io/streams.wit rename to wit/deps/wasi:io/streams.wit diff --git a/golem-llm/wit/deps/wasi:io/world.wit b/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-llm/wit/deps/wasi:io/world.wit rename to wit/deps/wasi:io/world.wit diff --git a/golem-llm/wit/golem-llm.wit b/wit/golem-llm.wit similarity index 100% rename from golem-llm/wit/golem-llm.wit rename to wit/golem-llm.wit From 1e5432e26e64c41532e3a2a37752649ec20cafc9 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 13 Jun 2025 09:55:40 +0000 Subject: [PATCH 25/36] clippy --- golem-embed/embed-cohere/src/client.rs | 1 - golem-embed/embed-cohere/src/conversions.rs | 2 -- golem-embed/embed-hugging-face/src/client.rs | 2 -- .../embed-hugging-face/src/conversions.rs | 18 +++++++++++------- golem-embed/embed-hugging-face/src/lib.rs | 11 +++-------- .../wit/deps/golem-embed/golem-embed.wit | 3 +-- golem-embed/embed-openai/src/client.rs | 1 - golem-embed/embed-voyageai/src/client.rs | 15 ++++++++------- golem-embed/embed-voyageai/src/lib.rs | 3 ++- .../wit/deps/golem-embed/golem-embed.wit | 3 +-- 10 files changed, 26 insertions(+), 33 deletions(-) diff --git a/golem-embed/embed-cohere/src/client.rs b/golem-embed/embed-cohere/src/client.rs index 7147e7648..986eb8b7d 100644 --- a/golem-embed/embed-cohere/src/client.rs +++ b/golem-embed/embed-cohere/src/client.rs @@ -7,7 +7,6 @@ use golem_embed::{ use log::trace; use reqwest::{Client, Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json; const BASE_URL: &str = "https://api.cohere.ai"; diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index a38dae9a8..655c61e88 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -266,7 +266,6 @@ mod tests { assert_eq!(request.output_dimension, Some(1024)); } - #[test] fn test_embedding_response_conversion() { let data = EmbeddingResponse { @@ -395,7 +394,6 @@ mod tests { ); } - #[test] fn test_create_rerank_request() { let query = "What is AI?".to_string(); diff --git a/golem-embed/embed-hugging-face/src/client.rs b/golem-embed/embed-hugging-face/src/client.rs index 07dc53142..4c1e42310 100644 --- a/golem-embed/embed-hugging-face/src/client.rs +++ b/golem-embed/embed-hugging-face/src/client.rs @@ -7,7 +7,6 @@ use golem_embed::{ use log::trace; use reqwest::{Client, Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json; const BASE_URL: &str = "https://router.huggingface.co/hf-inference"; @@ -48,7 +47,6 @@ impl EmbeddingsApi { .map_err(|err| from_reqwest_error("Request failed", err))?; parse_response::(response) } - } fn parse_response(response: Response) -> Result { diff --git a/golem-embed/embed-hugging-face/src/conversions.rs b/golem-embed/embed-hugging-face/src/conversions.rs index 3c5318fb2..465a7603e 100644 --- a/golem-embed/embed-hugging-face/src/conversions.rs +++ b/golem-embed/embed-hugging-face/src/conversions.rs @@ -1,18 +1,22 @@ use golem_embed::error::unsupported; use golem_embed::golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, - RerankResponse as GolemRerankResponse, + Config, ContentPart, EmbeddingResponse as GolemEmbeddingResponse, Error, }; -use crate::client::{EmbeddingRequest, EmbeddingResponse, RerankRequest, RerankResponse}; +use crate::client::{EmbeddingRequest, EmbeddingResponse}; -pub fn create_embedding_request(inputs: Vec, config: Config) -> Result<(EmbeddingRequest, String), Error> { +pub fn create_embedding_request( + inputs: Vec, + config: Config, +) -> Result<(EmbeddingRequest, String), Error> { let mut input_texts = Vec::new(); for content in inputs { match content { ContentPart::Text(text) => input_texts.push(text), ContentPart::Image(_) => { - return Err(unsupported("Image embeddings are not supported by Hugging Face.")) + return Err(unsupported( + "Image embeddings are not supported by Hugging Face.", + )) } } } @@ -46,7 +50,7 @@ pub fn process_embedding_response( Ok(GolemEmbeddingResponse { embeddings, - usage: None, + usage: None, model, provider_metadata_json: None, }) @@ -112,4 +116,4 @@ mod tests { let request = create_embedding_request(inputs, config); assert!(request.is_err()); } -} \ No newline at end of file +} diff --git a/golem-embed/embed-hugging-face/src/lib.rs b/golem-embed/embed-hugging-face/src/lib.rs index 3fc9b7f2b..120b6c691 100644 --- a/golem-embed/embed-hugging-face/src/lib.rs +++ b/golem-embed/embed-hugging-face/src/lib.rs @@ -2,15 +2,12 @@ mod client; mod conversions; use client::EmbeddingsApi; -use conversions::{ - create_embedding_request, create_rerank_request, process_embedding_response, - process_rerank_response, -}; +use conversions::{create_embedding_request, process_embedding_response}; use golem_embed::{ config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, golem::embed::embed::{ - Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse, + Config, ContentPart, EmbeddingResponse, Error, ErrorCode, Guest, RerankResponse, }, LOGGING_STATE, }; @@ -31,8 +28,6 @@ impl HuggingFaceComponent { Err(err) => Err(err), } } - - } impl Guest for HuggingFaceComponent { @@ -61,4 +56,4 @@ impl ExtendedGuest for HuggingFaceComponent {} type DurableHuggingFaceComponent = DurableEmbed; -golem_embed::export_embed!(DurableHuggingFaceComponent with_types_in golem_embed); \ No newline at end of file +golem_embed::export_embed!(DurableHuggingFaceComponent with_types_in golem_embed); diff --git a/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit index 838b3c2a5..78d040320 100644 --- a/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit @@ -124,7 +124,6 @@ interface embed { ) -> result; } - world embed-library { - export embed; + export embed; } \ No newline at end of file diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index e63baaa7d..9499bf108 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -11,7 +11,6 @@ use log::trace; use reqwest::Client; use reqwest::{Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json; const BASE_URL: &str = "https://api.openai.com"; diff --git a/golem-embed/embed-voyageai/src/client.rs b/golem-embed/embed-voyageai/src/client.rs index 8a21e4ca6..ff4811d78 100644 --- a/golem-embed/embed-voyageai/src/client.rs +++ b/golem-embed/embed-voyageai/src/client.rs @@ -7,7 +7,6 @@ use golem_embed::{ use log::trace; use reqwest::{Client, Method, Response}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json; const BASE_URL: &str = "https://api.voyageai.com"; @@ -25,7 +24,10 @@ impl VoyageAIApi { let client = Client::builder() .build() .expect("Failed to initialize HTTP client"); - Self { voyageai_api_key, client } + Self { + voyageai_api_key, + client, + } } pub fn generate_embedding( @@ -61,7 +63,7 @@ fn parse_response(response: Response) -> Result(&response_text) { return Err(Error { @@ -70,7 +72,7 @@ fn parse_response(response: Response) -> Result(&response_text) { if let Some(detail) = detail_error.get("detail").and_then(|d| d.as_str()) { return Err(Error { @@ -80,14 +82,14 @@ fn parse_response(response: Response) -> Result(&response_text) { Ok(response_data) => { trace!("Response from VoyageAI API: {response_data:?}"); @@ -163,7 +165,6 @@ pub struct EmbeddingUsage { pub total_tokens: u32, } - #[derive(Debug, Serialize, Deserialize, Clone)] pub struct RerankRequest { pub query: String, diff --git a/golem-embed/embed-voyageai/src/lib.rs b/golem-embed/embed-voyageai/src/lib.rs index 9310bffd4..73d28eeba 100644 --- a/golem-embed/embed-voyageai/src/lib.rs +++ b/golem-embed/embed-voyageai/src/lib.rs @@ -1,7 +1,8 @@ use golem_embed::{ config::with_config_key, durability::{DurableEmbed, ExtendedGuest}, - golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}, LOGGING_STATE, + golem::embed::embed::{Config, ContentPart, EmbeddingResponse, Error, Guest, RerankResponse}, + LOGGING_STATE, }; use crate::{ diff --git a/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit b/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit index 838b3c2a5..78d040320 100644 --- a/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit +++ b/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit @@ -124,7 +124,6 @@ interface embed { ) -> result; } - world embed-library { - export embed; + export embed; } \ No newline at end of file From 9f9a6ec965d96546c79d053cb68828975ef2bc24 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 13 Jun 2025 10:04:36 +0000 Subject: [PATCH 26/36] ci fix --- .github/workflows/ci.yaml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e7b41e9bc..5f97d3dc0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -84,7 +84,7 @@ jobs: run: cargo binstall --force --locked cargo-component@0.21.1 - name: Build all test components run: cargo make build-test-components - ollama-llm-integration-tests: + ollama-integration-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -115,13 +115,13 @@ jobs: set -e docker run -d --name ollama -p 11434:11434 ollama/ollama:latest timeout 60 bash -c 'until curl -f http://localhost:11434/api/version; do sleep 2; done' - echo "Pulling qwen3:1.7b" - docker exec ollama ollama pull qwen3:1.7b - echo "Pulling gemma3:4b" - docker exec ollama ollama pull gemma3:4b + echo "Pulling Qwen2.5:1.5b" + docker exec ollama ollama pull qwen2.5:1.5b + echo "Pulling Gemma2:2b" + docker exec ollama ollama pull gemma2:2b echo "Verifying models are available" - docker exec ollama ollama list | grep -q "qwen3:1.7b" || exit 1 - docker exec ollama ollama list | grep -q "gemma3:4b" || exit 1 + docker exec ollama ollama list | grep -q "qwen2.5:1.5b" || exit 1 + docker exec ollama ollama list | grep -q "gemma2:2b" || exit 1 echo "Ollama setup completed." - name: Install and Run latest Golem Server run: | @@ -137,8 +137,8 @@ jobs: - name: Build and test Ollama integration run: | set -e - cargo make build-llm-ollama - cd golem-llm/test + cargo make build-ollama + cd test golem-cli app build -b ollama-debug golem-cli app deploy -b ollama-debug golem-cli worker new -e GOLEM_OLLAMA_BASE_URL=http://localhost:11434 test:llm/ollama-1 @@ -153,7 +153,7 @@ jobs: needs: - tests - build-test-components - - ollama-llm-integration-tests + - ollama-integration-tests runs-on: ubuntu-latest permissions: contents: write @@ -183,4 +183,4 @@ jobs: - name: Login GH CLI shell: bash run: gh auth login --with-token < <(echo ${{ secrets.GITHUB_TOKEN }}) - - run: gh release upload -R golemcloud/golem-llm --clobber ${{ github.ref_name }} components/release/*.wasm + - run: gh release upload -R golemcloud/golem-llm --clobber ${{ github.ref_name }} components/release/*.wasm \ No newline at end of file From 880c52778300cf96a69cf111aafd85e4dc463c5f Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 15 Jun 2025 12:30:25 +0000 Subject: [PATCH 27/36] openai test fix --- golem-embed/embed-openai/src/client.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/golem-embed/embed-openai/src/client.rs b/golem-embed/embed-openai/src/client.rs index 9499bf108..b90bdcb13 100644 --- a/golem-embed/embed-openai/src/client.rs +++ b/golem-embed/embed-openai/src/client.rs @@ -70,7 +70,9 @@ fn parse_response(response: Response) -> Result Date: Sun, 15 Jun 2025 19:02:17 +0000 Subject: [PATCH 28/36] ci fix --- golem-embed/Makefile.toml | 2 +- golem-embed/embed-hugging-face/src/lib.rs | 6 +++--- golem-embed/embed-openai/src/lib.rs | 6 +++--- golem-embed/test/components-rust/test-embed/src/lib.rs | 2 -- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml index 3523760cd..922e92895 100644 --- a/golem-embed/Makefile.toml +++ b/golem-embed/Makefile.toml @@ -230,7 +230,7 @@ args = ["fmt", "--all", "--", "--check"] description = "Runs clippy checks without applying any fix" install_crate = "clippy" command = "cargo" -args = ["clippy", "--all-targets", "--", "--no-deps", "-D warnings"] +args = ["clippy", "--all-targets", "--", "--no-deps", "-Dwarnings"] [tasks.fix] description = "Runs rustfmt and clippy checks and applies fixes" diff --git a/golem-embed/embed-hugging-face/src/lib.rs b/golem-embed/embed-hugging-face/src/lib.rs index 120b6c691..57df0c45f 100644 --- a/golem-embed/embed-hugging-face/src/lib.rs +++ b/golem-embed/embed-hugging-face/src/lib.rs @@ -40,9 +40,9 @@ impl Guest for HuggingFaceComponent { } fn rerank( - query: String, - documents: Vec, - config: Config, + _query: String, + _documents: Vec, + _config: Config, ) -> Result { Err(Error { code: ErrorCode::Unsupported, diff --git a/golem-embed/embed-openai/src/lib.rs b/golem-embed/embed-openai/src/lib.rs index 491504c9c..8ade28eb4 100644 --- a/golem-embed/embed-openai/src/lib.rs +++ b/golem-embed/embed-openai/src/lib.rs @@ -43,9 +43,9 @@ impl Guest for OpenAIComponent { } fn rerank( - query: String, - documents: Vec, - config: Config, + _query: String, + _documents: Vec, + _config: Config, ) -> Result { Err(Error { code: ErrorCode::Unsupported, diff --git a/golem-embed/test/components-rust/test-embed/src/lib.rs b/golem-embed/test/components-rust/test-embed/src/lib.rs index fac64bfb8..a55387dce 100644 --- a/golem-embed/test/components-rust/test-embed/src/lib.rs +++ b/golem-embed/test/components-rust/test-embed/src/lib.rs @@ -4,8 +4,6 @@ mod bindings; use crate::bindings::exports::test::embed_exports::test_embed_api::*; use crate::bindings::golem::embed::embed; use crate::bindings::golem::embed::embed::{Config, ContentPart, Error, EmbeddingResponse}; -use crate::bindings::test::helper_client::test_helper_client::TestHelperApi; -use golem_rust::atomically; struct Component; From d8aafd8c56c03c63305b2591e2ee55614d4086f6 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 15 Jun 2025 19:29:36 +0000 Subject: [PATCH 29/36] unit test fix --- golem-embed/embed-cohere/src/conversions.rs | 47 ++++++++------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index 655c61e88..e08eb7b58 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -199,21 +199,25 @@ pub fn process_rerank_response( config: Config, ) -> Result { let results = response + .clone() .results .iter() .map(|result| RerankResult { index: result.index, - relevance_score: result.relevance_score, document: None, }) .collect(); let usage = if let Some(meta) = response.clone().meta { - meta.tokens.map(|tokens| Usage { - input_tokens: tokens.input_tokens, - total_tokens: tokens.output_tokens, - }) + if let Some(billed_units) = meta.billed_units { + Some(Usage { + input_tokens: billed_units.input_tokens, + total_tokens: billed_units.output_tokens, + }) + } else { + None + } } else { None }; @@ -222,7 +226,7 @@ pub fn process_rerank_response( results, usage, model: config.model.unwrap_or_else(|| "rerank-2-lite".to_string()), - provider_metadata_json: Some(get_rerank_provider_metadata(response.clone())), + provider_metadata_json: Some(get_rerank_provider_metadata(response)), }) } @@ -348,36 +352,19 @@ mod tests { let result = process_embedding_response(data.clone(), config); print!("{:?}", result); let embedding_response = result.unwrap(); - assert_eq!(embedding_response.embeddings.len(), 2); + assert_eq!(embedding_response.embeddings.len(), 5); assert_eq!(embedding_response.embeddings[0].index, 0); assert_eq!( embedding_response.embeddings[0].vector, vec![ - 0.016967773, - 0.031982422, - 0.041503906, - 0.0021514893, - 0.008178711, - -0.029541016, - -0.018432617, - -0.046875, - 0.021240234 + -15.0, -65.0, 0.0, -31.0, -43.0, -14.0, -48.0, 59.0, -34.0, 15.0, 36.0, 49.0, -5.0, 3.0, -49.0, -34.0, -74.0, 21.0 ] ); - assert_eq!(embedding_response.embeddings[1].index, 1); + assert_eq!(embedding_response.embeddings[1].index, 0); assert_eq!( embedding_response.embeddings[1].vector, vec![ - 0.013977051, - 0.012084961, - 0.005554199, - -0.053955078, - -0.026977539, - -0.008361816, - 0.02368164, - -0.013183594, - -0.063964844, - 0.026611328 + 14.0, 38.0, -30.0, -13.0, -49.0, 4.0, -33.0, -49.0, 48.0, 9.0, -84.0, 8.0, 0.0, -84.0, -46.0, -20.0, 24.0, -26.0, -98.0, 28.0 ] ); assert_eq!( @@ -438,7 +425,7 @@ mod tests { input_tokens: Some(11), classifications: None, images: None, - output_tokens: None, + output_tokens: Some(111), search_units: None, }), tokens: None, @@ -470,8 +457,8 @@ mod tests { rerank_response.usage, Some(Usage { input_tokens: Some(11), - total_tokens: None, - }) + total_tokens: Some(111), + }) ); } } From 664f4c795725aa33d6d7c36e87cab0b5fa80a199 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Sun, 15 Jun 2025 19:39:54 +0000 Subject: [PATCH 30/36] clippy --- golem-embed/embed-cohere/src/conversions.rs | 26 +++++++++------------ 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/golem-embed/embed-cohere/src/conversions.rs b/golem-embed/embed-cohere/src/conversions.rs index e08eb7b58..5843b9cbe 100644 --- a/golem-embed/embed-cohere/src/conversions.rs +++ b/golem-embed/embed-cohere/src/conversions.rs @@ -209,18 +209,12 @@ pub fn process_rerank_response( }) .collect(); - let usage = if let Some(meta) = response.clone().meta { - if let Some(billed_units) = meta.billed_units { - Some(Usage { - input_tokens: billed_units.input_tokens, - total_tokens: billed_units.output_tokens, - }) - } else { - None - } - } else { - None - }; + let usage = response.clone().meta.and_then(|meta| { + meta.billed_units.map(|billed_units| Usage { + input_tokens: billed_units.input_tokens, + total_tokens: billed_units.output_tokens, + }) + }); Ok(GolemRerankResponse { results, @@ -357,14 +351,16 @@ mod tests { assert_eq!( embedding_response.embeddings[0].vector, vec![ - -15.0, -65.0, 0.0, -31.0, -43.0, -14.0, -48.0, 59.0, -34.0, 15.0, 36.0, 49.0, -5.0, 3.0, -49.0, -34.0, -74.0, 21.0 + -15.0, -65.0, 0.0, -31.0, -43.0, -14.0, -48.0, 59.0, -34.0, 15.0, 36.0, 49.0, -5.0, + 3.0, -49.0, -34.0, -74.0, 21.0 ] ); assert_eq!(embedding_response.embeddings[1].index, 0); assert_eq!( embedding_response.embeddings[1].vector, vec![ - 14.0, 38.0, -30.0, -13.0, -49.0, 4.0, -33.0, -49.0, 48.0, 9.0, -84.0, 8.0, 0.0, -84.0, -46.0, -20.0, 24.0, -26.0, -98.0, 28.0 + 14.0, 38.0, -30.0, -13.0, -49.0, 4.0, -33.0, -49.0, 48.0, 9.0, -84.0, 8.0, 0.0, + -84.0, -46.0, -20.0, 24.0, -26.0, -98.0, 28.0 ] ); assert_eq!( @@ -458,7 +454,7 @@ mod tests { Some(Usage { input_tokens: Some(11), total_tokens: Some(111), - }) + }) ); } } From b3e7dc504cfe17be23ea4cfa23ddee7ee8958a96 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 25 Jun 2025 08:57:46 +0000 Subject: [PATCH 31/36] redme and made some fixes --- golem-embed/README.md | 187 ++++++++++++++++++++++ golem-embed/embed-cohere/Cargo.toml | 2 +- golem-embed/embed-hugging-face/Cargo.toml | 2 +- golem-embed/embed-openai/Cargo.toml | 2 +- golem-embed/embed-voyageai/Cargo.toml | 2 +- golem-embed/embed/src/lib.rs | 2 +- 6 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 golem-embed/README.md diff --git a/golem-embed/README.md b/golem-embed/README.md new file mode 100644 index 000000000..54754308a --- /dev/null +++ b/golem-embed/README.md @@ -0,0 +1,187 @@ +# golem-embed + +WebAssembly Components providing a unified API for various AI embedding and reranking providers. + +## Versions + +There are 8 published WASM files for each release: + +| Name | Description | +|-------------------------------------------|--------------------------------------------------------------------------------------------| +| `golem-embed-openai.wasm` | Embedding implementation for OpenAI, using custom Golem specific durability features | +| `golem-embed-cohere.wasm` | Embedding implementation for Cohere, using custom Golem specific durability features | +| `golem-embed-hugging-face.wasm` | Embedding implementation for Hugging Face, using custom Golem specific durability features| +| `golem-embed-voyageai.wasm` | Embedding implementation for VoyageAI, using custom Golem specific durability features | +| `golem-embed-openai-portable.wasm` | Embedding implementation for OpenAI, with no Golem specific dependencies. | +| `golem-embed-cohere-portable.wasm` | Embedding implementation for Cohere, with no Golem specific dependencies. | +| `golem-embed-hugging-face-portable.wasm` | Embedding implementation for Hugging Face, with no Golem specific dependencies. | +| `golem-embed-voyageai-portable.wasm` | Embedding implementation for VoyageAI, with no Golem specific dependencies. | + +Every component **exports** the same `golem:embed` interface, [defined here](wit/golem-embed.wit). + +The `-portable` versions only depend on `wasi:io`, `wasi:http` and `wasi:logging`. + +The default versions also depend on [Golem's host API](https://learn.golem.cloud/golem-host-functions) to implement +advanced durability related features. + +## Provider Capabilities + +Each provider supports different functionality and input types: + +| Provider |Text Embedding | Image Embedding | Reranking | +|---------------|-----------|------|-------| +| OpenAI | ✅ | ❌ | ❌ | +| Cohere | ✅ | ✅ | ✅ | +| Hugging Face | ✅ | ❌ | ❌ | +| VoyageAI | ✅ | ❌ | ✅ | + + +## Usage + +Each provider has to be configured with an API key passed as an environment variable: + +| Provider | Environment Variable | +|---------------|--------------------------| +| OpenAI | `OPENAI_API_KEY` | +| Cohere | `COHERE_API_KEY` | +| Hugging Face | `HUGGING_FACE_API_KEY` | +| VoyageAI | `VOYAGEAI_API_KEY` | + +Additionally, setting the `GOLEM_EMBED_LOG=trace` environment variable enables trace logging for all the communication +with the underlying embedding provider. + +### Using with Golem + +#### Using a template + +The easiest way to get started is to use one of the predefined **templates** Golem provides. + +**NOT AVAILABLE YET** + +#### Using a component dependency + +To existing Golem applications the `golem-embed` WASM components can be added as a **binary dependency**. + +**NOT AVAILABLE YET** + +#### Integrating the composing step to the build + +Currently it is necessary to manually add the [`wac`](https://github.com/bytecodealliance/wac) tool call to the +application manifest to link with the selected embedding implementation. The `test` directory of this repository shows an +example of this. + +The summary of the steps to be done, assuming the component was created with `golem-cli component new rust my:example`: + +1. Copy the `profiles` section from `common-rust/golem.yaml` to the component's `golem.yaml` file (for example in + `components-rust/my-example/golem.yaml`) so it can be customized. +2. Add a second **build step** after the `cargo component build` which is calling `wac` to compose with the selected ( + and downloaded) `golem-embed` binary. See the example below. +3. Modify the `componentWasm` field to point to the composed WASM file. +4. Add the `golem-embed.wit` file (from this repository) to the application's root `wit/deps/golem:embed` directory. +5. Import `golem-embed.wit` in your component's WIT file: `import golem:embed/embed@1.0.0;' + +Example app manifest build section: + +```yaml +components: + my:example: + profiles: + debug: + build: + - command: cargo component build + sources: + - src + - wit-generated + - ../../common-rust + targets: + - ../../target/wasm32-wasip1/debug/my_example.wasm + - command: wac plug --plug ../../golem_embed_openai.wasm ../../target/wasm32-wasip1/debug/my_example.wasm -o ../../target/wasm32-wasip1/debug/my_example_plugged.wasm + sources: + - ../../target/wasm32-wasip1/debug/my_example.wasm + - ../../golem_embed_openai.wasm + targets: + - ../../target/wasm32-wasip1/debug/my_example_plugged.wasm + sourceWit: wit + generatedWit: wit-generated + componentWasm: ../../target/wasm32-wasip1/debug/my_example_plugged.wasm + linkedWasm: ../../golem-temp/components/my_example_debug.wasm + clean: + - src/bindings.rs +``` + +### Using without Golem + +To use the embedding provider components in a WebAssembly project independent of Golem you need to do the following: + +1. Download one of the `-portable.wasm` versions +2. Download the `golem-embed.wit` WIT package and import it +3. Use [`wac`](https://github.com/bytecodealliance/wac) to compose your component with the selected embedding implementation. + +## Examples + +Take the [test application](test/components-rust/test-embed/src/lib.rs) as an example of using `golem-embed` from Rust. The +implemented test functions are demonstrating the following: + +| Function Name | Description | +|---------------|--------------------------------------------------------------------------------------------| +| `test1` | Simple text embedding generation | +| `test2` | Demonstrates document reranking functionality | + +### Running the examples + +To run the examples first you need a running Golem instance. This can be Golem Cloud or the single-executable `golem` +binary +started with `golem server run`. + +**NOTE**: `golem-embed` requires the latest (unstable) version of Golem currently. It's going to work with the next public +stable release 1.2.2. + +Then build and deploy the _test application_. Select one of the following profiles to choose which provider to use: +| Profile Name | Description | +|--------------|-----------------------------------------------------------------------------------------------| +| `openai-debug` | Uses the OpenAI embedding implementation and compiles the code in debug profile | +| `openai-release` | Uses the OpenAI embedding implementation and compiles the code in release profile | +| `cohere-debug` | Uses the Cohere embedding implementation and compiles the code in debug profile | +| `cohere-release` | Uses the Cohere embedding implementation and compiles the code in release profile | +| `hugging-face-debug` | Uses the Hugging Face embedding implementation and compiles the code in debug profile | +| `hugging-face-release` | Uses the Hugging Face embedding implementation and compiles the code in release profile | +| `voyageai-debug` | Uses the VoyageAI embedding implementation and compiles the code in debug profile | +| `voyageai-release` | Uses the VoyageAI embedding implementation and compiles the code in release profile | + +```bash +cd test +golem app build -b openai-debug +golem app deploy -b openai-debug +``` + +Depending on the provider selected, an environment variable has to be set for the worker to be started, containing the API key for the given provider: + +```bash +golem worker new test:embed/debug --env OPENAI_API_KEY=xxx --env GOLEM_EMBED_LOG=trace +``` + +Then you can invoke the test functions on this worker: + +```bash +golem worker invoke test:embed/debug test1 --stream +``` + +## Development + +This repository uses [cargo-make](https://github.com/sagiegurari/cargo-make) to automate build tasks. +Some of the important tasks are: + +| Command | Description | +|-------------------------------------|--------------------------------------------------------------------------------------------------------| +| `cargo make build` | Build all components with Golem bindings in Debug | +| `cargo make release-build` | Build all components with Golem bindings in Release | +| `cargo make build-portable` | Build all components with no Golem bindings in Debug | +| `cargo make release-build-portable` | Build all components with no Golem bindings in Release | +| `cargo make unit-tests` | Run all unit tests | +| `cargo make check` | Checks formatting and Clippy rules | +| `cargo make fix` | Fixes formatting and Clippy rules | +| `cargo make wit` | To be used after editing the `wit/golem-embed.wit` file - distributes the changes to all wit directories | + +The `test` directory contains a **Golem application** for testing various features of the embedding components. +Check [the Golem documentation](https://learn.golem.cloud/quickstart) to learn how to install Golem and `golem-cli` to +run these tests. \ No newline at end of file diff --git a/golem-embed/embed-cohere/Cargo.toml b/golem-embed/embed-cohere/Cargo.toml index 43b827751..8524838a7 100644 --- a/golem-embed/embed-cohere/Cargo.toml +++ b/golem-embed/embed-cohere/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem-llm" -description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" +description = "WebAssembly component for working with Cohere embeding and reranking APIs, with special support for Golem Cloud" [lib] diff --git a/golem-embed/embed-hugging-face/Cargo.toml b/golem-embed/embed-hugging-face/Cargo.toml index 846e853c4..578e78d0a 100644 --- a/golem-embed/embed-hugging-face/Cargo.toml +++ b/golem-embed/embed-hugging-face/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem-llm" -description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" +description = "WebAssembly component for working with Hugging face embeding APIs, with special support for Golem Cloud" [lib] diff --git a/golem-embed/embed-openai/Cargo.toml b/golem-embed/embed-openai/Cargo.toml index 78001cb85..afd44969b 100644 --- a/golem-embed/embed-openai/Cargo.toml +++ b/golem-embed/embed-openai/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem-llm" -description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" +description = "WebAssembly component for working with OpenAI embeding APIs, with special support for Golem Cloud" [lib] diff --git a/golem-embed/embed-voyageai/Cargo.toml b/golem-embed/embed-voyageai/Cargo.toml index 5def70463..e017ed780 100644 --- a/golem-embed/embed-voyageai/Cargo.toml +++ b/golem-embed/embed-voyageai/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem-llm" -description = "WebAssembly component for working with Ollama APIs, with special support for Golem Cloud" +description = "WebAssembly component for working with VoyageAI embeding and reranking APIs, with special support for Golem Cloud" [lib] diff --git a/golem-embed/embed/src/lib.rs b/golem-embed/embed/src/lib.rs index b040b99b5..0223ec879 100644 --- a/golem-embed/embed/src/lib.rs +++ b/golem-embed/embed/src/lib.rs @@ -25,7 +25,7 @@ impl LoggingState { if !self.logging_initialized { let _ = wasi_logger::Logger::install(); let max_level: log::LevelFilter = - log::LevelFilter::from_str(&std::env::var("GOLEM_LLM_LOG").unwrap_or_default()) + log::LevelFilter::from_str(&std::env::var("GOLEM_EMBED_LOG").unwrap_or_default()) .unwrap_or(log::LevelFilter::Info); log::set_max_level(max_level); self.logging_initialized = true; From 796d7d7ab1d6b1aaa60b7189edf0ddfb2fe7d30c Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 25 Jun 2025 12:05:49 +0000 Subject: [PATCH 32/36] rebased with latest project structure --- Cargo.toml | 10 +- embed/Makefile.toml | 169 ++ {golem-embed => embed}/README.md | 0 .../embed-cohere => embed/cohere}/Cargo.toml | 0 .../cohere}/src/bindings.rs | 0 .../cohere}/src/client.rs | 0 .../cohere}/src/conversions.rs | 0 .../embed-cohere => embed/cohere}/src/lib.rs | 0 .../cohere}/wit/cohere.wit | 0 .../wit/deps/golem-embed/golem-embed.wit | 0 .../cohere}/wit/deps/wasi:io/error.wit | 0 .../cohere}/wit/deps/wasi:io/poll.wit | 0 .../cohere}/wit/deps/wasi:io/streams.wit | 0 .../cohere}/wit/deps/wasi:io/world.wit | 0 {golem-embed => embed}/embed/Cargo.toml | 0 {golem-embed => embed}/embed/src/config.rs | 0 .../embed/src/durability.rs | 0 {golem-embed => embed}/embed/src/error.rs | 0 {golem-embed => embed}/embed/src/lib.rs | 0 .../wit/deps/golem-embed/golem-embed.wit | 0 .../embed}/wit/deps/wasi:io/error.wit | 0 .../embed}/wit/deps/wasi:io/poll.wit | 0 .../embed}/wit/deps/wasi:io/streams.wit | 0 .../embed}/wit/deps/wasi:io/world.wit | 0 {golem-embed => embed}/embed/wit/embed.wit | 0 .../hugging-face}/Cargo.toml | 0 .../hugging-face}/src/bindings.rs | 0 .../hugging-face}/src/client.rs | 0 .../hugging-face}/src/conversions.rs | 0 .../hugging-face}/src/lib.rs | 0 .../wit/deps/golem-embed/golem-embed.wit | 0 .../hugging-face}/wit/deps/wasi:io/error.wit | 0 .../hugging-face}/wit/deps/wasi:io/poll.wit | 0 .../wit/deps/wasi:io/streams.wit | 0 .../hugging-face}/wit/deps/wasi:io/world.wit | 0 .../hugging-face}/wit/hugging_face.wit | 0 .../embed-openai => embed/openai}/Cargo.toml | 0 .../openai}/src/bindings.rs | 0 .../openai}/src/client.rs | 0 .../openai}/src/conversions.rs | 0 .../embed-openai => embed/openai}/src/lib.rs | 0 .../wit/deps/golem-embed/golem-embed.wit | 0 .../openai}/wit/deps/wasi:io/error.wit | 0 .../openai}/wit/deps/wasi:io/poll.wit | 0 .../openai}/wit/deps/wasi:io/streams.wit | 0 .../openai}/wit/deps/wasi:io/world.wit | 0 .../openai}/wit/openai.wit | 0 .../voyageai}/Cargo.toml | 0 .../voyageai}/src/bindings.rs | 0 .../voyageai}/src/client.rs | 0 .../voyageai}/src/conversitions.rs | 0 .../voyageai}/src/lib.rs | 0 .../wit/deps/golem-embed/golem-embed.wit | 0 .../voyageai}/wit/deps/wasi:io/error.wit | 0 .../voyageai}/wit/deps/wasi:io/poll.wit | 0 .../voyageai}/wit/deps/wasi:io/streams.wit | 0 .../voyageai}/wit/deps/wasi:io/world.wit | 0 .../voyageai}/wit/voyageai.wit | 0 {golem-embed => embed}/wit/deps.lock | 0 {golem-embed => embed}/wit/deps.toml | 0 .../io => embed/wit/deps/wasi:io}/error.wit | 0 .../io => embed/wit/deps/wasi:io}/poll.wit | 0 .../io => embed/wit/deps/wasi:io}/streams.wit | 0 .../io => embed/wit/deps/wasi:io}/world.wit | 0 .../golem-embed => embed/wit}/golem-embed.wit | 0 golem-embed/Makefile.toml | 304 ---- golem-embed/test/.gitignore | 2 - golem-embed/test/.vscode/settings.json | 5 - golem-embed/test/Cargo.lock | 1339 ---------------- golem-embed/test/Cargo.toml | 20 - .../test/common-rust/common-lib/Cargo.toml | 4 - .../test/common-rust/common-lib/src/lib.rs | 3 - golem-embed/test/common-rust/golem.yaml | 44 - golem-embed/test/components-rust/.gitignore | 2 - .../components-rust/test-helper/Cargo.lock | 1376 ----------------- .../components-rust/test-helper/Cargo.toml | 33 - .../components-rust/test-helper/golem.yaml | 18 - .../components-rust/test-helper/src/lib.rs | 38 - .../test-helper/wit/test-helper.wit | 9 - golem-embed/test/data/cat.png | Bin 34010 -> 0 bytes golem-embed/test/golem.yaml | 12 - golem-embed/wit/deps/wasi:io/error.wit | 34 - golem-embed/wit/deps/wasi:io/poll.wit | 47 - golem-embed/wit/deps/wasi:io/streams.wit | 290 ---- golem-embed/wit/deps/wasi:io/world.wit | 10 - golem-embed/wit/golem-embed.wit | 129 -- llm/anthropic/src/bindings.rs | 11 +- llm/grok/src/bindings.rs | 11 +- .../components-rust/test-embed/Cargo.lock | 0 .../components-rust/test-embed/Cargo.toml | 0 .../components-rust/test-embed/golem.yaml | 0 .../components-rust/test-embed/src/lib.rs | 0 .../test-embed/wit/test-embed.wit | 0 93 files changed, 188 insertions(+), 3732 deletions(-) create mode 100644 embed/Makefile.toml rename {golem-embed => embed}/README.md (100%) rename {golem-embed/embed-cohere => embed/cohere}/Cargo.toml (100%) rename {golem-embed/embed-cohere => embed/cohere}/src/bindings.rs (100%) rename {golem-embed/embed-cohere => embed/cohere}/src/client.rs (100%) rename {golem-embed/embed-cohere => embed/cohere}/src/conversions.rs (100%) rename {golem-embed/embed-cohere => embed/cohere}/src/lib.rs (100%) rename {golem-embed/embed-cohere => embed/cohere}/wit/cohere.wit (100%) rename {golem-embed/embed-cohere => embed/cohere}/wit/deps/golem-embed/golem-embed.wit (100%) rename {golem-embed/embed-cohere => embed/cohere}/wit/deps/wasi:io/error.wit (100%) rename {golem-embed/embed-cohere => embed/cohere}/wit/deps/wasi:io/poll.wit (100%) rename {golem-embed/embed-cohere => embed/cohere}/wit/deps/wasi:io/streams.wit (100%) rename {golem-embed/embed-cohere => embed/cohere}/wit/deps/wasi:io/world.wit (100%) rename {golem-embed => embed}/embed/Cargo.toml (100%) rename {golem-embed => embed}/embed/src/config.rs (100%) rename {golem-embed => embed}/embed/src/durability.rs (100%) rename {golem-embed => embed}/embed/src/error.rs (100%) rename {golem-embed => embed}/embed/src/lib.rs (100%) rename {golem-embed/embed-hugging-face => embed/embed}/wit/deps/golem-embed/golem-embed.wit (100%) rename {golem-embed/embed-hugging-face => embed/embed}/wit/deps/wasi:io/error.wit (100%) rename {golem-embed/embed-hugging-face => embed/embed}/wit/deps/wasi:io/poll.wit (100%) rename {golem-embed/embed-hugging-face => embed/embed}/wit/deps/wasi:io/streams.wit (100%) rename {golem-embed/embed-hugging-face => embed/embed}/wit/deps/wasi:io/world.wit (100%) rename {golem-embed => embed}/embed/wit/embed.wit (100%) rename {golem-embed/embed-hugging-face => embed/hugging-face}/Cargo.toml (100%) rename {golem-embed/embed-hugging-face => embed/hugging-face}/src/bindings.rs (100%) rename {golem-embed/embed-hugging-face => embed/hugging-face}/src/client.rs (100%) rename {golem-embed/embed-hugging-face => embed/hugging-face}/src/conversions.rs (100%) rename {golem-embed/embed-hugging-face => embed/hugging-face}/src/lib.rs (100%) rename {golem-embed/embed-openai => embed/hugging-face}/wit/deps/golem-embed/golem-embed.wit (100%) rename {golem-embed/embed-openai => embed/hugging-face}/wit/deps/wasi:io/error.wit (100%) rename {golem-embed/embed-openai => embed/hugging-face}/wit/deps/wasi:io/poll.wit (100%) rename {golem-embed/embed-openai => embed/hugging-face}/wit/deps/wasi:io/streams.wit (100%) rename {golem-embed/embed-openai => embed/hugging-face}/wit/deps/wasi:io/world.wit (100%) rename {golem-embed/embed-hugging-face => embed/hugging-face}/wit/hugging_face.wit (100%) rename {golem-embed/embed-openai => embed/openai}/Cargo.toml (100%) rename {golem-embed/embed-openai => embed/openai}/src/bindings.rs (100%) rename {golem-embed/embed-openai => embed/openai}/src/client.rs (100%) rename {golem-embed/embed-openai => embed/openai}/src/conversions.rs (100%) rename {golem-embed/embed-openai => embed/openai}/src/lib.rs (100%) rename {golem-embed/embed-voyageai => embed/openai}/wit/deps/golem-embed/golem-embed.wit (100%) rename {golem-embed/embed-voyageai => embed/openai}/wit/deps/wasi:io/error.wit (100%) rename {golem-embed/embed-voyageai => embed/openai}/wit/deps/wasi:io/poll.wit (100%) rename {golem-embed/embed-voyageai => embed/openai}/wit/deps/wasi:io/streams.wit (100%) rename {golem-embed/embed-voyageai => embed/openai}/wit/deps/wasi:io/world.wit (100%) rename {golem-embed/embed-openai => embed/openai}/wit/openai.wit (100%) rename {golem-embed/embed-voyageai => embed/voyageai}/Cargo.toml (100%) rename {golem-embed/embed-voyageai => embed/voyageai}/src/bindings.rs (100%) rename {golem-embed/embed-voyageai => embed/voyageai}/src/client.rs (100%) rename {golem-embed/embed-voyageai => embed/voyageai}/src/conversitions.rs (100%) rename {golem-embed/embed-voyageai => embed/voyageai}/src/lib.rs (100%) rename {golem-embed/embed => embed/voyageai}/wit/deps/golem-embed/golem-embed.wit (100%) rename {golem-embed/embed => embed/voyageai}/wit/deps/wasi:io/error.wit (100%) rename {golem-embed/embed => embed/voyageai}/wit/deps/wasi:io/poll.wit (100%) rename {golem-embed/embed => embed/voyageai}/wit/deps/wasi:io/streams.wit (100%) rename {golem-embed/embed => embed/voyageai}/wit/deps/wasi:io/world.wit (100%) rename {golem-embed/embed-voyageai => embed/voyageai}/wit/voyageai.wit (100%) rename {golem-embed => embed}/wit/deps.lock (100%) rename {golem-embed => embed}/wit/deps.toml (100%) rename {golem-embed/test/wit/deps/io => embed/wit/deps/wasi:io}/error.wit (100%) rename {golem-embed/test/wit/deps/io => embed/wit/deps/wasi:io}/poll.wit (100%) rename {golem-embed/test/wit/deps/io => embed/wit/deps/wasi:io}/streams.wit (100%) rename {golem-embed/test/wit/deps/io => embed/wit/deps/wasi:io}/world.wit (100%) rename {golem-embed/test/wit/deps/golem-embed => embed/wit}/golem-embed.wit (100%) delete mode 100644 golem-embed/Makefile.toml delete mode 100644 golem-embed/test/.gitignore delete mode 100644 golem-embed/test/.vscode/settings.json delete mode 100644 golem-embed/test/Cargo.lock delete mode 100644 golem-embed/test/Cargo.toml delete mode 100644 golem-embed/test/common-rust/common-lib/Cargo.toml delete mode 100644 golem-embed/test/common-rust/common-lib/src/lib.rs delete mode 100644 golem-embed/test/common-rust/golem.yaml delete mode 100644 golem-embed/test/components-rust/.gitignore delete mode 100644 golem-embed/test/components-rust/test-helper/Cargo.lock delete mode 100644 golem-embed/test/components-rust/test-helper/Cargo.toml delete mode 100644 golem-embed/test/components-rust/test-helper/golem.yaml delete mode 100644 golem-embed/test/components-rust/test-helper/src/lib.rs delete mode 100644 golem-embed/test/components-rust/test-helper/wit/test-helper.wit delete mode 100644 golem-embed/test/data/cat.png delete mode 100644 golem-embed/test/golem.yaml delete mode 100644 golem-embed/wit/deps/wasi:io/error.wit delete mode 100644 golem-embed/wit/deps/wasi:io/poll.wit delete mode 100644 golem-embed/wit/deps/wasi:io/streams.wit delete mode 100644 golem-embed/wit/deps/wasi:io/world.wit delete mode 100644 golem-embed/wit/golem-embed.wit rename {golem-embed/test => test}/components-rust/test-embed/Cargo.lock (100%) rename {golem-embed/test => test}/components-rust/test-embed/Cargo.toml (100%) rename {golem-embed/test => test}/components-rust/test-embed/golem.yaml (100%) rename {golem-embed/test => test}/components-rust/test-embed/src/lib.rs (100%) rename {golem-embed/test => test}/components-rust/test-embed/wit/test-embed.wit (100%) diff --git a/Cargo.toml b/Cargo.toml index 8f03777aa..5f97ad91e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,11 +8,11 @@ members = [ "llm/ollama", "llm/openai", "llm/openrouter", - "golem-embed/embed", - "golem-embed/embed-cohere", - "golem-embed/embed-hugging-face", - "golem-embed/embed-openai", - "golem-embed/embed-voyageai", + "embed/embed", + "embed/cohere", + "embed/hugging-face", + "embed/openai", + "embed/voyageai", ] [profile.release] diff --git a/embed/Makefile.toml b/embed/Makefile.toml new file mode 100644 index 000000000..c69e11f89 --- /dev/null +++ b/embed/Makefile.toml @@ -0,0 +1,169 @@ +[config] +default_to_workspace = false +skip_core_tasks = true + +[tasks.build] +run_task = { name = [ + "build-openai", + "build-cohere", + "build-hugging-face", + "build-voyageai", +] } + +[tasks.build-portable] +run_task = { name = [ + "build-openai-portable", + "build-cohere-portable", + "build-hugging-face-portable", + "build-voyageai-portable", +] } + +[tasks.release-build] +run_task = { name = [ + "release-build-openai", + "release-build-cohere", + "release-build-hugging-face", + "release-build-voyageai", +] } + +[tasks.release-build-portable] +run_task = { name = [ + "release-build-openai-portable", + "release-build-cohere-portable", + "release-build-hugging-face-portable", + "release-build-voyageai-portable", +] } + +[tasks.build-openai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai"] + +[tasks.build-openai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai", "--no-default-features"] + +[tasks.build-cohere] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere"] + +[tasks.build-cohere-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere", "--no-default-features"] + +[tasks.build-hugging-face] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face"] + +[tasks.build-hugging-face-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face", "--no-default-features"] + +[tasks.build-voyageai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai"] + +[tasks.build-voyageai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai", "--no-default-features"] + +[tasks.release-build-openai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai", "--release"] + +[tasks.release-build-openai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-openai", "--release", "--no-default-features"] + +[tasks.release-build-cohere] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere", "--release"] + +[tasks.release-build-cohere-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-cohere", "--release", "--no-default-features"] + +[tasks.release-build-hugging-face] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face", "--release"] + +[tasks.release-build-hugging-face-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-hugging-face", "--release", "--no-default-features"] + +[tasks.release-build-voyageai] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai", "--release"] + +[tasks.release-build-voyageai-portable] +install_crate = { crate_name = "cargo-component", version = "0.20.0" } +command = "cargo-component" +args = ["build", "-p", "golem-embed-voyageai", "--release", "--no-default-features"] + +[tasks.wit-update] +install_crate = { crate_name = "wit-deps-cli" } +command = "wit-deps" +args = ["update"] + +[tasks.wit] +dependencies = ["wit-update"] + +script_runner = "@duckscript" +script = """ +modules = array embed embed-openai embed-cohere embed-hugging-face embed-voyageai + +for module in ${modules} + rm -r ${module}/wit/deps + mkdir ${module}/wit/deps/golem-embed + cp wit/golem-embed.wit ${module}/wit/deps/golem-embed/golem-embed.wit + cp wit/deps/wasi:io ${module}/wit/deps + + echo "Copied WIT for module embed::${module}" +end + +# Copy WIT files for integration tests +rm -r test/wit +mkdir test/wit/deps/golem-embed +mkdir test/wit/deps/io +cp wit/golem-embed.wit test/wit/deps/golem-embed/golem-embed.wit +cp wit/deps/wasi:io/error.wit test/wit/deps/io/error.wit +cp wit/deps/wasi:io/poll.wit test/wit/deps/io/poll.wit +cp wit/deps/wasi:io/streams.wit test/wit/deps/io/streams.wit +cp wit/deps/wasi:io/world.wit test/wit/deps/io/world.wit + +echo "Copied WIT for module test" +""" + +[tasks.build-test-components] +dependencies = ["build"] +install_crate = "cargo-binstall" +description = "Builds embed test components with golem-cli" +script = ''' +cargo-binstall golem-cli@1.2.2-dev.11 --locked --no-confirm +cargo-binstall wac-cli --locked --no-confirm +cd test + +golem-cli --version +golem-cli app clean +golem-cli app build -b openai-debug +golem-cli app clean +golem-cli app build -b cohere-debug +golem-cli app clean +golem-cli app build -b hugging-face-debug +golem-cli app clean +golem-cli app build -b voyageai-debug +''' \ No newline at end of file diff --git a/golem-embed/README.md b/embed/README.md similarity index 100% rename from golem-embed/README.md rename to embed/README.md diff --git a/golem-embed/embed-cohere/Cargo.toml b/embed/cohere/Cargo.toml similarity index 100% rename from golem-embed/embed-cohere/Cargo.toml rename to embed/cohere/Cargo.toml diff --git a/golem-embed/embed-cohere/src/bindings.rs b/embed/cohere/src/bindings.rs similarity index 100% rename from golem-embed/embed-cohere/src/bindings.rs rename to embed/cohere/src/bindings.rs diff --git a/golem-embed/embed-cohere/src/client.rs b/embed/cohere/src/client.rs similarity index 100% rename from golem-embed/embed-cohere/src/client.rs rename to embed/cohere/src/client.rs diff --git a/golem-embed/embed-cohere/src/conversions.rs b/embed/cohere/src/conversions.rs similarity index 100% rename from golem-embed/embed-cohere/src/conversions.rs rename to embed/cohere/src/conversions.rs diff --git a/golem-embed/embed-cohere/src/lib.rs b/embed/cohere/src/lib.rs similarity index 100% rename from golem-embed/embed-cohere/src/lib.rs rename to embed/cohere/src/lib.rs diff --git a/golem-embed/embed-cohere/wit/cohere.wit b/embed/cohere/wit/cohere.wit similarity index 100% rename from golem-embed/embed-cohere/wit/cohere.wit rename to embed/cohere/wit/cohere.wit diff --git a/golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit b/embed/cohere/wit/deps/golem-embed/golem-embed.wit similarity index 100% rename from golem-embed/embed-cohere/wit/deps/golem-embed/golem-embed.wit rename to embed/cohere/wit/deps/golem-embed/golem-embed.wit diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/error.wit b/embed/cohere/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-embed/embed-cohere/wit/deps/wasi:io/error.wit rename to embed/cohere/wit/deps/wasi:io/error.wit diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/poll.wit b/embed/cohere/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-embed/embed-cohere/wit/deps/wasi:io/poll.wit rename to embed/cohere/wit/deps/wasi:io/poll.wit diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/streams.wit b/embed/cohere/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-embed/embed-cohere/wit/deps/wasi:io/streams.wit rename to embed/cohere/wit/deps/wasi:io/streams.wit diff --git a/golem-embed/embed-cohere/wit/deps/wasi:io/world.wit b/embed/cohere/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-embed/embed-cohere/wit/deps/wasi:io/world.wit rename to embed/cohere/wit/deps/wasi:io/world.wit diff --git a/golem-embed/embed/Cargo.toml b/embed/embed/Cargo.toml similarity index 100% rename from golem-embed/embed/Cargo.toml rename to embed/embed/Cargo.toml diff --git a/golem-embed/embed/src/config.rs b/embed/embed/src/config.rs similarity index 100% rename from golem-embed/embed/src/config.rs rename to embed/embed/src/config.rs diff --git a/golem-embed/embed/src/durability.rs b/embed/embed/src/durability.rs similarity index 100% rename from golem-embed/embed/src/durability.rs rename to embed/embed/src/durability.rs diff --git a/golem-embed/embed/src/error.rs b/embed/embed/src/error.rs similarity index 100% rename from golem-embed/embed/src/error.rs rename to embed/embed/src/error.rs diff --git a/golem-embed/embed/src/lib.rs b/embed/embed/src/lib.rs similarity index 100% rename from golem-embed/embed/src/lib.rs rename to embed/embed/src/lib.rs diff --git a/golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit b/embed/embed/wit/deps/golem-embed/golem-embed.wit similarity index 100% rename from golem-embed/embed-hugging-face/wit/deps/golem-embed/golem-embed.wit rename to embed/embed/wit/deps/golem-embed/golem-embed.wit diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/error.wit b/embed/embed/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-embed/embed-hugging-face/wit/deps/wasi:io/error.wit rename to embed/embed/wit/deps/wasi:io/error.wit diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/poll.wit b/embed/embed/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-embed/embed-hugging-face/wit/deps/wasi:io/poll.wit rename to embed/embed/wit/deps/wasi:io/poll.wit diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/streams.wit b/embed/embed/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-embed/embed-hugging-face/wit/deps/wasi:io/streams.wit rename to embed/embed/wit/deps/wasi:io/streams.wit diff --git a/golem-embed/embed-hugging-face/wit/deps/wasi:io/world.wit b/embed/embed/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-embed/embed-hugging-face/wit/deps/wasi:io/world.wit rename to embed/embed/wit/deps/wasi:io/world.wit diff --git a/golem-embed/embed/wit/embed.wit b/embed/embed/wit/embed.wit similarity index 100% rename from golem-embed/embed/wit/embed.wit rename to embed/embed/wit/embed.wit diff --git a/golem-embed/embed-hugging-face/Cargo.toml b/embed/hugging-face/Cargo.toml similarity index 100% rename from golem-embed/embed-hugging-face/Cargo.toml rename to embed/hugging-face/Cargo.toml diff --git a/golem-embed/embed-hugging-face/src/bindings.rs b/embed/hugging-face/src/bindings.rs similarity index 100% rename from golem-embed/embed-hugging-face/src/bindings.rs rename to embed/hugging-face/src/bindings.rs diff --git a/golem-embed/embed-hugging-face/src/client.rs b/embed/hugging-face/src/client.rs similarity index 100% rename from golem-embed/embed-hugging-face/src/client.rs rename to embed/hugging-face/src/client.rs diff --git a/golem-embed/embed-hugging-face/src/conversions.rs b/embed/hugging-face/src/conversions.rs similarity index 100% rename from golem-embed/embed-hugging-face/src/conversions.rs rename to embed/hugging-face/src/conversions.rs diff --git a/golem-embed/embed-hugging-face/src/lib.rs b/embed/hugging-face/src/lib.rs similarity index 100% rename from golem-embed/embed-hugging-face/src/lib.rs rename to embed/hugging-face/src/lib.rs diff --git a/golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit b/embed/hugging-face/wit/deps/golem-embed/golem-embed.wit similarity index 100% rename from golem-embed/embed-openai/wit/deps/golem-embed/golem-embed.wit rename to embed/hugging-face/wit/deps/golem-embed/golem-embed.wit diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/error.wit b/embed/hugging-face/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-embed/embed-openai/wit/deps/wasi:io/error.wit rename to embed/hugging-face/wit/deps/wasi:io/error.wit diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/poll.wit b/embed/hugging-face/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-embed/embed-openai/wit/deps/wasi:io/poll.wit rename to embed/hugging-face/wit/deps/wasi:io/poll.wit diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/streams.wit b/embed/hugging-face/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-embed/embed-openai/wit/deps/wasi:io/streams.wit rename to embed/hugging-face/wit/deps/wasi:io/streams.wit diff --git a/golem-embed/embed-openai/wit/deps/wasi:io/world.wit b/embed/hugging-face/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-embed/embed-openai/wit/deps/wasi:io/world.wit rename to embed/hugging-face/wit/deps/wasi:io/world.wit diff --git a/golem-embed/embed-hugging-face/wit/hugging_face.wit b/embed/hugging-face/wit/hugging_face.wit similarity index 100% rename from golem-embed/embed-hugging-face/wit/hugging_face.wit rename to embed/hugging-face/wit/hugging_face.wit diff --git a/golem-embed/embed-openai/Cargo.toml b/embed/openai/Cargo.toml similarity index 100% rename from golem-embed/embed-openai/Cargo.toml rename to embed/openai/Cargo.toml diff --git a/golem-embed/embed-openai/src/bindings.rs b/embed/openai/src/bindings.rs similarity index 100% rename from golem-embed/embed-openai/src/bindings.rs rename to embed/openai/src/bindings.rs diff --git a/golem-embed/embed-openai/src/client.rs b/embed/openai/src/client.rs similarity index 100% rename from golem-embed/embed-openai/src/client.rs rename to embed/openai/src/client.rs diff --git a/golem-embed/embed-openai/src/conversions.rs b/embed/openai/src/conversions.rs similarity index 100% rename from golem-embed/embed-openai/src/conversions.rs rename to embed/openai/src/conversions.rs diff --git a/golem-embed/embed-openai/src/lib.rs b/embed/openai/src/lib.rs similarity index 100% rename from golem-embed/embed-openai/src/lib.rs rename to embed/openai/src/lib.rs diff --git a/golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit b/embed/openai/wit/deps/golem-embed/golem-embed.wit similarity index 100% rename from golem-embed/embed-voyageai/wit/deps/golem-embed/golem-embed.wit rename to embed/openai/wit/deps/golem-embed/golem-embed.wit diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/error.wit b/embed/openai/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-embed/embed-voyageai/wit/deps/wasi:io/error.wit rename to embed/openai/wit/deps/wasi:io/error.wit diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/poll.wit b/embed/openai/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-embed/embed-voyageai/wit/deps/wasi:io/poll.wit rename to embed/openai/wit/deps/wasi:io/poll.wit diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/streams.wit b/embed/openai/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-embed/embed-voyageai/wit/deps/wasi:io/streams.wit rename to embed/openai/wit/deps/wasi:io/streams.wit diff --git a/golem-embed/embed-voyageai/wit/deps/wasi:io/world.wit b/embed/openai/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-embed/embed-voyageai/wit/deps/wasi:io/world.wit rename to embed/openai/wit/deps/wasi:io/world.wit diff --git a/golem-embed/embed-openai/wit/openai.wit b/embed/openai/wit/openai.wit similarity index 100% rename from golem-embed/embed-openai/wit/openai.wit rename to embed/openai/wit/openai.wit diff --git a/golem-embed/embed-voyageai/Cargo.toml b/embed/voyageai/Cargo.toml similarity index 100% rename from golem-embed/embed-voyageai/Cargo.toml rename to embed/voyageai/Cargo.toml diff --git a/golem-embed/embed-voyageai/src/bindings.rs b/embed/voyageai/src/bindings.rs similarity index 100% rename from golem-embed/embed-voyageai/src/bindings.rs rename to embed/voyageai/src/bindings.rs diff --git a/golem-embed/embed-voyageai/src/client.rs b/embed/voyageai/src/client.rs similarity index 100% rename from golem-embed/embed-voyageai/src/client.rs rename to embed/voyageai/src/client.rs diff --git a/golem-embed/embed-voyageai/src/conversitions.rs b/embed/voyageai/src/conversitions.rs similarity index 100% rename from golem-embed/embed-voyageai/src/conversitions.rs rename to embed/voyageai/src/conversitions.rs diff --git a/golem-embed/embed-voyageai/src/lib.rs b/embed/voyageai/src/lib.rs similarity index 100% rename from golem-embed/embed-voyageai/src/lib.rs rename to embed/voyageai/src/lib.rs diff --git a/golem-embed/embed/wit/deps/golem-embed/golem-embed.wit b/embed/voyageai/wit/deps/golem-embed/golem-embed.wit similarity index 100% rename from golem-embed/embed/wit/deps/golem-embed/golem-embed.wit rename to embed/voyageai/wit/deps/golem-embed/golem-embed.wit diff --git a/golem-embed/embed/wit/deps/wasi:io/error.wit b/embed/voyageai/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-embed/embed/wit/deps/wasi:io/error.wit rename to embed/voyageai/wit/deps/wasi:io/error.wit diff --git a/golem-embed/embed/wit/deps/wasi:io/poll.wit b/embed/voyageai/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-embed/embed/wit/deps/wasi:io/poll.wit rename to embed/voyageai/wit/deps/wasi:io/poll.wit diff --git a/golem-embed/embed/wit/deps/wasi:io/streams.wit b/embed/voyageai/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-embed/embed/wit/deps/wasi:io/streams.wit rename to embed/voyageai/wit/deps/wasi:io/streams.wit diff --git a/golem-embed/embed/wit/deps/wasi:io/world.wit b/embed/voyageai/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-embed/embed/wit/deps/wasi:io/world.wit rename to embed/voyageai/wit/deps/wasi:io/world.wit diff --git a/golem-embed/embed-voyageai/wit/voyageai.wit b/embed/voyageai/wit/voyageai.wit similarity index 100% rename from golem-embed/embed-voyageai/wit/voyageai.wit rename to embed/voyageai/wit/voyageai.wit diff --git a/golem-embed/wit/deps.lock b/embed/wit/deps.lock similarity index 100% rename from golem-embed/wit/deps.lock rename to embed/wit/deps.lock diff --git a/golem-embed/wit/deps.toml b/embed/wit/deps.toml similarity index 100% rename from golem-embed/wit/deps.toml rename to embed/wit/deps.toml diff --git a/golem-embed/test/wit/deps/io/error.wit b/embed/wit/deps/wasi:io/error.wit similarity index 100% rename from golem-embed/test/wit/deps/io/error.wit rename to embed/wit/deps/wasi:io/error.wit diff --git a/golem-embed/test/wit/deps/io/poll.wit b/embed/wit/deps/wasi:io/poll.wit similarity index 100% rename from golem-embed/test/wit/deps/io/poll.wit rename to embed/wit/deps/wasi:io/poll.wit diff --git a/golem-embed/test/wit/deps/io/streams.wit b/embed/wit/deps/wasi:io/streams.wit similarity index 100% rename from golem-embed/test/wit/deps/io/streams.wit rename to embed/wit/deps/wasi:io/streams.wit diff --git a/golem-embed/test/wit/deps/io/world.wit b/embed/wit/deps/wasi:io/world.wit similarity index 100% rename from golem-embed/test/wit/deps/io/world.wit rename to embed/wit/deps/wasi:io/world.wit diff --git a/golem-embed/test/wit/deps/golem-embed/golem-embed.wit b/embed/wit/golem-embed.wit similarity index 100% rename from golem-embed/test/wit/deps/golem-embed/golem-embed.wit rename to embed/wit/golem-embed.wit diff --git a/golem-embed/Makefile.toml b/golem-embed/Makefile.toml deleted file mode 100644 index 922e92895..000000000 --- a/golem-embed/Makefile.toml +++ /dev/null @@ -1,304 +0,0 @@ -[config] -default_to_workspace = false -skip_core_tasks = true - -[tasks.clean] -command = "cargo" -args = ["clean"] - -[tasks.unit-tests] -command = "cargo" -args = ["test"] - -[tasks.build-voyageai] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-voyageai"] - -[tasks.build-voyageai-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-voyageai", "--no-default-features"] - -[tasks.build-openai] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-openai"] - -[tasks.build-openai-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-openai", "--no-default-features"] - - -[tasks.build-cohere] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-cohere"] - -[tasks.build-cohere-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-cohere", "--no-default-features"] - -[tasks.build-hugging-face] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-hugging-face"] - -[tasks.build-hugging-face-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-hugging-face", "--no-default-features"] - - - -[tasks.build] -dependencies = [ - "build-openai", - "build-cohere", - "build-hugging-face", - "build-voyageai", -] - -[tasks.build-portable] -dependencies = [ - "build-openai-portable", - "build-cohere-portable", - "build-hugging-face-portable", - "build-voyageai-portable" -] - -[tasks.build-all] -script_runner = "@duckscript" -script = ''' -mkdir ../components/embed/debug - -cm_run_task clean -cm_run_task build - -cp ../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../components/embed/debug/golem_embed_openai.wasm -cp ../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../components/embed/debug/golem_embed_cohere.wasm -cp ../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../components/embed/debug/golem_embed_hugging_face.wasm -cp ../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../components/embed/debug/golem_embed_voyageai.wasm - -cm_run_task clean -cm_run_task build-portable - -cp ../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../components/embed/debug/golem_embed_openai-portable.wasm -cp ../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../components/embed/debug/golem_embed_cohere-portable.wasm -cp ../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../components/embed/debug/golem_embed_hugging_face-portable.wasm -cp ../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../components/embed/debug/golem_embed_voyageai.wasm -''' - -[tasks.release-build-openai] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-openai", "--release"] - -[tasks.release-build-openai-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-openai", "--release", "--no-default-features"] - -[tasks.release-build-cohere] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-cohere", "--release"] - -[tasks.release-build-cohere-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-cohere", "--release", "--no-default-features"] - -[tasks.release-build-hugging-face] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-hugging-face", "--release"] - -[tasks.release-build-hugging-face-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-hugging-face", "--release", "--no-default-features"] - -[tasks.release-build-voyageai] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-voyageai", "--release"] - -[tasks.release-build-voyageai-portable] -install_crate = { crate_name = "cargo-component", version = "0.20.0" } -command = "cargo-component" -args = ["build", "-p", "golem-embed-voyageai", "--release", "--no-default-features"] - -[tasks.release-build] -dependencies = [ - "release-build-openai", - "release-build-cohere", - "release-build-hugging-face", - "release-build-voyageai", -] - -[tasks.release-build-portable] -dependencies = [ - "release-build-openai-portable", - "release-build-cohere-portable", - "release-build-hugging-face-portable", - "release-build-voyageai-portable", -] - -[tasks.release-build-all] -script_runner = "@duckscript" -script = ''' -mkdir ../components/release - -cm_run_task set-version - -cm_run_task clean -cm_run_task release-build - -cp ../target/wasm32-wasip1/release/golem_embed_openai.wasm ../components/embed/release/golem_embed_openai.wasm -cp ../target/wasm32-wasip1/release/golem_embed_cohere.wasm ../components/embed/release/golem_embed_cohere.wasm -cp ../target/wasm32-wasip1/release/golem_embed_hugging_face.wasm ../components/embed/release/golem_embed_hugging_face.wasm -cp ../target/wasm32-wasip1/release/golem_embed_voyageai.wasm ../components/embed/release/golem_embed_voyageai.wasm - -cm_run_task clean -cm_run_task release-build-portable - -cp ../target/wasm32-wasip1/release/golem_embed_openai.wasm ../components/embed/release/golem_embed_openai-portable.wasm -cp ../target/wasm32-wasip1/release/golem_embed_cohere.wasm ../components/embed/release/golem_embed_cohere-portable.wasm -cp ../target/wasm32-wasip1/release/golem_embed_hugging_face.wasm ../components/embed/release/golem_embed_hugging_face-portable.wasm -cp ../target/wasm32-wasip1/release/golem_embed_voyageai.wasm ../components/embed/release/golem_embed_voyageai-portable.wasm -''' - -[tasks.wit-update] -install_crate = { crate_name = "wit-deps-cli" } -command = "wit-deps" -args = ["update"] - -[tasks.wit] -dependencies = ["wit-update"] -script_runner = "@duckscript" -script = """ -rm -r embed/wit/deps -mkdir embed/wit/deps/golem-embed -cp wit/golem-embed.wit embed/wit/deps/golem-embed/golem-embed.wit -cp wit/deps/wasi:io embed/wit/deps - -rm -r embed-openai/wit/deps -mkdir embed-openai/wit/deps/golem-embed -cp wit/golem-embed.wit embed-openai/wit/deps/golem-embed/golem-embed.wit -cp wit/deps/wasi:io embed-openai/wit/deps - -rm -r embed-cohere/wit/deps -mkdir embed-cohere/wit/deps/golem-embed -cp wit/golem-embed.wit embed-cohere/wit/deps/golem-embed/golem-embed.wit -cp wit/deps/wasi:io embed-cohere/wit/deps - -rm -r embed-hugging-face/wit/deps -mkdir embed-hugging-face/wit/deps/golem-embed -cp wit/golem-embed.wit embed-hugging-face/wit/deps/golem-embed/golem-embed.wit -cp wit/deps/wasi:io embed-hugging-face/wit/deps - -rm -r embed-voyageai/wit/deps -mkdir embed-voyageai/wit/deps/golem-embed -cp wit/golem-embed.wit embed-voyageai/wit/deps/golem-embed/golem-embed.wit -cp wit/deps/wasi:io embed-voyageai/wit/deps - - -rm -r test/wit -mkdir test/wit/deps/golem-embed -mkdir test/wit/deps/io -cp wit/golem-embed.wit test/wit/deps/golem-embed/golem-embed.wit -cp wit/deps/wasi:io/error.wit test/wit/deps/io/error.wit -cp wit/deps/wasi:io/poll.wit test/wit/deps/io/poll.wit -cp wit/deps/wasi:io/streams.wit test/wit/deps/io/streams.wit -cp wit/deps/wasi:io/world.wit test/wit/deps/io/world.wit -""" - -[tasks.check] -description = "Runs rustfmt and clippy checks without applying any fix" -dependencies = ["check-clippy", "check-rustfmt"] - -[tasks.check-rustfmt] -description = "Runs rustfmt checks without applying any fix" -install_crate = "rustfmt" -command = "cargo" -args = ["fmt", "--all", "--", "--check"] - -[tasks.check-clippy] -description = "Runs clippy checks without applying any fix" -install_crate = "clippy" -command = "cargo" -args = ["clippy", "--all-targets", "--", "--no-deps", "-Dwarnings"] - -[tasks.fix] -description = "Runs rustfmt and clippy checks and applies fixes" -dependencies = ["wit", "fix-clippy", "fix-rustfmt"] - -[tasks.fix-rustfmt] -description = "Runs rustfmt checks and applies fixes" -install_crate = "rustfmt" -command = "cargo" -args = ["fmt", "--all"] - -[tasks.fix-clippy] -description = "Runs clippy checks and applies fixes" -install_crate = "clippy" -command = "cargo" -args = [ - "clippy", - "--fix", - "--allow-dirty", - "--allow-staged", - "--", - "--no-deps", - "-Dwarnings", -] - -[tasks.build-test-components] -dependencies = ["build"] -description = "Builds all test components with golem-cli" -install_crate = "cargo-binstall" -script = ''' -cargo-binstall golem-cli@1.2.2-dev.11 --locked --force --no-confirm -cargo-binstall wac-cli --locked --force --no-confirm -cd test -golem-cli --version -golem-cli app clean -golem-cli app build -b openai-debug -golem-cli app clean -golem-cli app build -b cohere-debug -golem-cli app clean -golem-cli app build -b hugging-face-debug -golem-cli app clean -golem-cli app build -b voyageai-debug -''' - - -[tasks.set-version] -description = "Sets the version in all Cargo.toml files to the value of the VERSION environment variable" -condition = { env_set = ["VERSION"] } -script = ''' -grep -rl --include 'Cargo.toml' '0\.0\.0' | xargs sed -i "s/0\.0\.0/${VERSION}/g" -''' - -[tasks.set-version.mac] -condition = { env_set = ["VERSION"] } -script = ''' -grep -rl --include '.*Cargo\.toml' '0\.0\.0' | xargs sed -i "" "s/0\.0\.0/${VERSION}/g" -''' - -[tasks.set-version.windows] -script_runner = "powershell" -script_extension = "ps1" -condition = { env_set = ["VERSION"] } -script = ''' -$cargoFiles = Get-ChildItem . Cargo.toml -rec -foreach ($file in $cargoFiles) -{ - (Get-Content $file.PSPath) | - Foreach-Object { $_ -replace "0.0.0", $Env:VERSION } | - Set-Content $file.PSPath -} -''' \ No newline at end of file diff --git a/golem-embed/test/.gitignore b/golem-embed/test/.gitignore deleted file mode 100644 index 175f32628..000000000 --- a/golem-embed/test/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -golem-temp -target diff --git a/golem-embed/test/.vscode/settings.json b/golem-embed/test/.vscode/settings.json deleted file mode 100644 index 96a21fde5..000000000 --- a/golem-embed/test/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.server.extraEnv": { - "CARGO": "cargo-component" - } -} \ No newline at end of file diff --git a/golem-embed/test/Cargo.lock b/golem-embed/test/Cargo.lock deleted file mode 100644 index c506269f1..000000000 --- a/golem-embed/test/Cargo.lock +++ /dev/null @@ -1,1339 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" - -[[package]] -name = "auditable-serde" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7bf8143dfc3c0258df908843e169b5cc5fcf76c7718bd66135ef4a9cd558c5" -dependencies = [ - "semver", - "serde", - "serde_json", - "topological-sort", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "common-lib" -version = "0.1.0" - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "flate2" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi", -] - -[[package]] -name = "git-version" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" -dependencies = [ - "git-version-macro", -] - -[[package]] -name = "git-version-macro" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "golem-rust" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46aaf34adda9057718d79e808fb323b3247cb34ec9c38ff88e74824d703980dd" -dependencies = [ - "golem-rust-macro", - "golem-wasm-rpc", - "serde", - "serde_json", - "uuid", - "wit-bindgen", -] - -[[package]] -name = "golem-rust-macro" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab4174ebe45b8a1961eedeebc215bbc475aea4bdf4f2baa80cc6222fb0058da" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "golem-wasm-rpc" -version = "1.3.0-dev.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82c94d17e7b23ad4335012364825ce9a30977aaca9ebb385c3e4274be0e0f60" -dependencies = [ - "cargo_metadata", - "chrono", - "git-version", - "uuid", - "wit-bindgen-rt 0.40.0", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "foldhash", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "prettyplease" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "reqwest" -version = "0.12.15" -source = "git+https://github.com/zivergetech/reqwest?branch=update-may-2025#c916d796a87bdace112d24b862142597d1074305" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "mime", - "percent-encoding", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tower-service", - "url", - "wit-bindgen-rt 0.41.0", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" - -[[package]] -name = "spdx" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" -dependencies = [ - "smallvec", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "test_embed" -version = "0.0.0" -dependencies = [ - "golem-rust", - "log", - "reqwest", - "serde", - "serde_json", - "wit-bindgen-rt 0.40.0", -] - -[[package]] -name = "test_helper" -version = "0.0.0" -dependencies = [ - "golem-rust", - "reqwest", - "serde", - "serde_json", - "wit-bindgen-rt 0.40.0", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "topological-sort" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "uuid" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" -dependencies = [ - "getrandom", - "serde", - "sha1_smol", -] - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt 0.39.0", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bb72f02e7fbf07183443b27b0f3d4144abf8c114189f2e088ed95b696a7822" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1ef0faabbbba6674e97a56bee857ccddf942785a336c8b47b42373c922a91d" -dependencies = [ - "anyhow", - "auditable-serde", - "flate2", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "url", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f51cad774fb3c9461ab9bccc9c62dfb7388397b5deda31bf40e8108ccd678b2" -dependencies = [ - "bitflags", - "hashbrown", - "indexmap", - "semver", -] - -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" -dependencies = [ - "windows-link", -] - -[[package]] -name = "wit-bindgen" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7091ed6c9abfa4e0a2ef3b39d0539da992d841fcf32c255f64fb98764ffee5" -dependencies = [ - "wit-bindgen-rt 0.40.0", - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398c650cec1278cfb72e214ba26ef3440ab726e66401bd39c04f465ee3979e6b" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68faed92ae696b93ea9a7b67ba6c37bf09d72c6d9a70fa824a743c3020212f11" -dependencies = [ - "bitflags", - "futures", - "once_cell", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db52a11d4dfb0a59f194c064055794ee6564eb1ced88c25da2cf76e50c5621" -dependencies = [ - "bitflags", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83903c8dcd8084a8a67ae08190122cf0e25dc37bdc239070a00f47e22d3f0aae" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7bf7f20495bcc7dc9f24c5fbcac9e919ca5ebdb7a1b1841d74447d3c8dd0c60" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "635c3adc595422cbf2341a17fb73a319669cc8d33deed3a48368a841df86b676" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.227.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf445ed5157046e4baf56f9138c124a0824d4d1657e7204d71886ad8ce2fc11" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/golem-embed/test/Cargo.toml b/golem-embed/test/Cargo.toml deleted file mode 100644 index ae41bab4c..000000000 --- a/golem-embed/test/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[workspace] -resolver = "2" -members = ["components-rust/*", "common-rust/*"] - -[profile.release] -opt-level = "s" -lto = true - -[workspace.dependencies] -golem-rust = { version = "1.6.0", features = [ - "export_load_snapshot", - "export_save_snapshot", - "export_oplog_processor", -] } -reqwest = { git = "https://github.com/zivergetech/reqwest", branch = "update-may-2025", features = [ - "json", -] } -serde = { version = "1.0.0", features = ["derive"] } -serde_json = "1.0" -wit-bindgen-rt = { version = "0.40.0", features = ["bitflags"] } diff --git a/golem-embed/test/common-rust/common-lib/Cargo.toml b/golem-embed/test/common-rust/common-lib/Cargo.toml deleted file mode 100644 index 876f1d66d..000000000 --- a/golem-embed/test/common-rust/common-lib/Cargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -[package] -name = "common-lib" -version = "0.1.0" -edition = "2021" diff --git a/golem-embed/test/common-rust/common-lib/src/lib.rs b/golem-embed/test/common-rust/common-lib/src/lib.rs deleted file mode 100644 index 15c6dcba7..000000000 --- a/golem-embed/test/common-rust/common-lib/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn example_common_function() -> &'static str { - "hello common" -} diff --git a/golem-embed/test/common-rust/golem.yaml b/golem-embed/test/common-rust/golem.yaml deleted file mode 100644 index b13a83894..000000000 --- a/golem-embed/test/common-rust/golem.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json -# Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json - -# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference - -templates: - rust: - profiles: - debug: - build: - - command: cargo component build - sources: - - src - - wit-generated - - ../../common-rust - targets: - - ../../target/wasm32-wasip1/debug/{{ component_name | to_snake_case }}.wasm - sourceWit: wit - generatedWit: wit-generated - componentWasm: ../../target/wasm32-wasip1/debug/{{ component_name | to_snake_case }}.wasm - linkedWasm: ../../golem-temp/components/{{ component_name | to_snake_case }}_debug.wasm - clean: - - src/bindings.rs - release: - build: - - command: cargo component build --release - sources: - - src - - wit-generated - - ../../common-rust - targets: - - ../../target/wasm32-wasip1/release/{{ component_name | to_snake_case }}.wasm - sourceWit: wit - generatedWit: wit-generated - componentWasm: ../../target/wasm32-wasip1/release/{{ component_name | to_snake_case }}.wasm - linkedWasm: ../../golem-temp/components/{{ component_name | to_snake_case }}_release.wasm - clean: - - src/bindings.rs - defaultProfile: debug -customCommands: - cargo-clean: - - command: cargo clean diff --git a/golem-embed/test/components-rust/.gitignore b/golem-embed/test/components-rust/.gitignore deleted file mode 100644 index f19eeb7b2..000000000 --- a/golem-embed/test/components-rust/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/*/src/bindings.rs -/*/wit-generated \ No newline at end of file diff --git a/golem-embed/test/components-rust/test-helper/Cargo.lock b/golem-embed/test/components-rust/test-helper/Cargo.lock deleted file mode 100644 index bd98b1898..000000000 --- a/golem-embed/test/components-rust/test-helper/Cargo.lock +++ /dev/null @@ -1,1376 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytes" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" - -[[package]] -name = "cc" -version = "1.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "test-helper" -version = "0.0.0" -dependencies = [ - "golem-rust", - "reqwest", - "serde", - "serde_json", - "wit-bindgen-rt", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "golem-rust" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c967eb388fb81f9b9f4df5d5b6634de803f21cd410c1bf687202794a4fbc0267" -dependencies = [ - "golem-rust-macro", - "serde", - "serde_json", - "uuid", - "wit-bindgen-rt", -] - -[[package]] -name = "golem-rust-macro" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb87f831cfe4371427c63f5f4cabcc3bae1b66974c8fbcf22be9274fee3a7d1" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "ipnet" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "js-sys" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "litemap" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "reqwest" -version = "0.11.18" -source = "git+https://github.com/zivergetech/reqwest?branch=update-jun-2024#1cf59c67b93aa6292961f8948b93df5bca2753b6" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", - "wit-bindgen-rt", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustix" -version = "0.38.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.134" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "2.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tempfile" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -dependencies = [ - "getrandom", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" - -[[package]] -name = "web-sys" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c7526379ace8709ee9ab9f2bb50f112d95581063a59ef3097d9c10153886c9" -dependencies = [ - "bitflags", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/golem-embed/test/components-rust/test-helper/Cargo.toml b/golem-embed/test/components-rust/test-helper/Cargo.toml deleted file mode 100644 index 121fb6a40..000000000 --- a/golem-embed/test/components-rust/test-helper/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "test_helper" -version = "0.0.0" -edition = "2021" - -[lib] -path = "src/lib.rs" -crate-type = ["cdylib"] -required-features = [] - -[dependencies] -# To use common shared libs, use the following: -# common-lib = { path = "../../common-rust/common-lib" } - -golem-rust = { workspace = true } -reqwest = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -wit-bindgen-rt = { workspace = true } - -[package.metadata.component.target] -path = "wit-generated" - -[package.metadata.component.bindings.with] - -[package.metadata.component.target.dependencies] -"test:helper-exports" = { path = "wit-generated/deps/test_helper-exports" } - -[package.metadata.component.bindings] -# See https://github.com/bytecodealliance/cargo-component/blob/main/src/metadata.rs#L62 - -# derives = ["serde::Serialize", "serde::Deserialize"] -# generate_unused_types = true \ No newline at end of file diff --git a/golem-embed/test/components-rust/test-helper/golem.yaml b/golem-embed/test/components-rust/test-helper/golem.yaml deleted file mode 100644 index 4c1a11ae1..000000000 --- a/golem-embed/test/components-rust/test-helper/golem.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json -# Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json - -# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference - -components: - test:helper: - template: rust - -# Example for adding dependencies for Worker to Worker communication: -# See https://learn.golem.cloud/docs/app-manifest#fields_dependencies for more information -# -#dependencies: -# test:helper: -# - target: -# type: wasm-rpc diff --git a/golem-embed/test/components-rust/test-helper/src/lib.rs b/golem-embed/test/components-rust/test-helper/src/lib.rs deleted file mode 100644 index 52ed26b30..000000000 --- a/golem-embed/test/components-rust/test-helper/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -#[allow(static_mut_refs)] -mod bindings; - -use crate::bindings::exports::test::helper_exports::test_helper_api::*; -// Import for using common lib (also see Cargo.toml for adding the dependency): -// use common_lib::example_common_function; -use std::cell::RefCell; - -/// This is one of any number of data types that our application -/// uses. Golem will take care to persist all application state, -/// whether that state is local to a function being executed or -/// global across the entire program. -struct State { - total: u64, -} - -thread_local! { - /// This holds the state of our application. - static STATE: RefCell = RefCell::new(State { - total: 0, - }); -} - -struct Component; - -impl Guest for Component { - fn inc_and_get() -> u64 { - // Call code from shared lib - // println!("{}", example_common_function()); - - STATE.with_borrow_mut(|state| { - state.total += 1; - state.total - }) - } -} - -bindings::export!(Component with_types_in bindings); diff --git a/golem-embed/test/components-rust/test-helper/wit/test-helper.wit b/golem-embed/test/components-rust/test-helper/wit/test-helper.wit deleted file mode 100644 index fec4ac2d2..000000000 --- a/golem-embed/test/components-rust/test-helper/wit/test-helper.wit +++ /dev/null @@ -1,9 +0,0 @@ -package test:helper; - -interface test-helper-api { - inc-and-get: func() -> u64; -} - -world test-helper { - export test-helper-api; -} diff --git a/golem-embed/test/data/cat.png b/golem-embed/test/data/cat.png deleted file mode 100644 index ce3de7efdd03ee67ad2f97db01d9b353687ec3b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34010 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 KMNUMnLSTX>U*<>v diff --git a/golem-embed/test/golem.yaml b/golem-embed/test/golem.yaml deleted file mode 100644 index 65b9f3aff..000000000 --- a/golem-embed/test/golem.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Schema for IDEA: -# $schema: https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json -# Schema for vscode-yaml -# yaml-language-server: $schema=https://schema.golem.cloud/app/golem/1.1.1/golem.schema.json - -# See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference - -includes: - - common-*/golem.yaml - - components-*/*/golem.yaml -witDeps: - - wit/deps diff --git a/golem-embed/wit/deps/wasi:io/error.wit b/golem-embed/wit/deps/wasi:io/error.wit deleted file mode 100644 index 97c606877..000000000 --- a/golem-embed/wit/deps/wasi:io/error.wit +++ /dev/null @@ -1,34 +0,0 @@ -package wasi:io@0.2.3; - -@since(version = 0.2.0) -interface error { - /// A resource which represents some error information. - /// - /// The only method provided by this resource is `to-debug-string`, - /// which provides some human-readable information about the error. - /// - /// In the `wasi:io` package, this resource is returned through the - /// `wasi:io/streams/stream-error` type. - /// - /// To provide more specific error information, other interfaces may - /// offer functions to "downcast" this error into more specific types. For example, - /// errors returned from streams derived from filesystem types can be described using - /// the filesystem's own error-code type. This is done using the function - /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` - /// parameter and returns an `option`. - /// - /// The set of functions which can "downcast" an `error` into a more - /// concrete type is open. - @since(version = 0.2.0) - resource error { - /// Returns a string that is suitable to assist humans in debugging - /// this error. - /// - /// WARNING: The returned string should not be consumed mechanically! - /// It may change across platforms, hosts, or other implementation - /// details. Parsing this string is a major platform-compatibility - /// hazard. - @since(version = 0.2.0) - to-debug-string: func() -> string; - } -} diff --git a/golem-embed/wit/deps/wasi:io/poll.wit b/golem-embed/wit/deps/wasi:io/poll.wit deleted file mode 100644 index 9bcbe8e03..000000000 --- a/golem-embed/wit/deps/wasi:io/poll.wit +++ /dev/null @@ -1,47 +0,0 @@ -package wasi:io@0.2.3; - -/// A poll API intended to let users wait for I/O events on multiple handles -/// at once. -@since(version = 0.2.0) -interface poll { - /// `pollable` represents a single I/O event which may be ready, or not. - @since(version = 0.2.0) - resource pollable { - - /// Return the readiness of a pollable. This function never blocks. - /// - /// Returns `true` when the pollable is ready, and `false` otherwise. - @since(version = 0.2.0) - ready: func() -> bool; - - /// `block` returns immediately if the pollable is ready, and otherwise - /// blocks until ready. - /// - /// This function is equivalent to calling `poll.poll` on a list - /// containing only this pollable. - @since(version = 0.2.0) - block: func(); - } - - /// Poll for completion on a set of pollables. - /// - /// This function takes a list of pollables, which identify I/O sources of - /// interest, and waits until one or more of the events is ready for I/O. - /// - /// The result `list` contains one or more indices of handles in the - /// argument list that is ready for I/O. - /// - /// This function traps if either: - /// - the list is empty, or: - /// - the list contains more elements than can be indexed with a `u32` value. - /// - /// A timeout can be implemented by adding a pollable from the - /// wasi-clocks API to the list. - /// - /// This function does not return a `result`; polling in itself does not - /// do any I/O so it doesn't fail. If any of the I/O sources identified by - /// the pollables has an error, it is indicated by marking the source as - /// being ready for I/O. - @since(version = 0.2.0) - poll: func(in: list>) -> list; -} diff --git a/golem-embed/wit/deps/wasi:io/streams.wit b/golem-embed/wit/deps/wasi:io/streams.wit deleted file mode 100644 index 0de084629..000000000 --- a/golem-embed/wit/deps/wasi:io/streams.wit +++ /dev/null @@ -1,290 +0,0 @@ -package wasi:io@0.2.3; - -/// WASI I/O is an I/O abstraction API which is currently focused on providing -/// stream types. -/// -/// In the future, the component model is expected to add built-in stream types; -/// when it does, they are expected to subsume this API. -@since(version = 0.2.0) -interface streams { - @since(version = 0.2.0) - use error.{error}; - @since(version = 0.2.0) - use poll.{pollable}; - - /// An error for input-stream and output-stream operations. - @since(version = 0.2.0) - variant stream-error { - /// The last operation (a write or flush) failed before completion. - /// - /// More information is available in the `error` payload. - /// - /// After this, the stream will be closed. All future operations return - /// `stream-error::closed`. - last-operation-failed(error), - /// The stream is closed: no more input will be accepted by the - /// stream. A closed output-stream will return this error on all - /// future operations. - closed - } - - /// An input bytestream. - /// - /// `input-stream`s are *non-blocking* to the extent practical on underlying - /// platforms. I/O operations always return promptly; if fewer bytes are - /// promptly available than requested, they return the number of bytes promptly - /// available, which could even be zero. To wait for data to be available, - /// use the `subscribe` function to obtain a `pollable` which can be polled - /// for using `wasi:io/poll`. - @since(version = 0.2.0) - resource input-stream { - /// Perform a non-blocking read from the stream. - /// - /// When the source of a `read` is binary data, the bytes from the source - /// are returned verbatim. When the source of a `read` is known to the - /// implementation to be text, bytes containing the UTF-8 encoding of the - /// text are returned. - /// - /// This function returns a list of bytes containing the read data, - /// when successful. The returned list will contain up to `len` bytes; - /// it may return fewer than requested, but not more. The list is - /// empty when no bytes are available for reading at this time. The - /// pollable given by `subscribe` will be ready when more bytes are - /// available. - /// - /// This function fails with a `stream-error` when the operation - /// encounters an error, giving `last-operation-failed`, or when the - /// stream is closed, giving `closed`. - /// - /// When the caller gives a `len` of 0, it represents a request to - /// read 0 bytes. If the stream is still open, this call should - /// succeed and return an empty list, or otherwise fail with `closed`. - /// - /// The `len` parameter is a `u64`, which could represent a list of u8 which - /// is not possible to allocate in wasm32, or not desirable to allocate as - /// as a return value by the callee. The callee may return a list of bytes - /// less than `len` in size while more bytes are available for reading. - @since(version = 0.2.0) - read: func( - /// The maximum number of bytes to read - len: u64 - ) -> result, stream-error>; - - /// Read bytes from a stream, after blocking until at least one byte can - /// be read. Except for blocking, behavior is identical to `read`. - @since(version = 0.2.0) - blocking-read: func( - /// The maximum number of bytes to read - len: u64 - ) -> result, stream-error>; - - /// Skip bytes from a stream. Returns number of bytes skipped. - /// - /// Behaves identical to `read`, except instead of returning a list - /// of bytes, returns the number of bytes consumed from the stream. - @since(version = 0.2.0) - skip: func( - /// The maximum number of bytes to skip. - len: u64, - ) -> result; - - /// Skip bytes from a stream, after blocking until at least one byte - /// can be skipped. Except for blocking behavior, identical to `skip`. - @since(version = 0.2.0) - blocking-skip: func( - /// The maximum number of bytes to skip. - len: u64, - ) -> result; - - /// Create a `pollable` which will resolve once either the specified stream - /// has bytes available to read or the other end of the stream has been - /// closed. - /// The created `pollable` is a child resource of the `input-stream`. - /// Implementations may trap if the `input-stream` is dropped before - /// all derived `pollable`s created with this function are dropped. - @since(version = 0.2.0) - subscribe: func() -> pollable; - } - - - /// An output bytestream. - /// - /// `output-stream`s are *non-blocking* to the extent practical on - /// underlying platforms. Except where specified otherwise, I/O operations also - /// always return promptly, after the number of bytes that can be written - /// promptly, which could even be zero. To wait for the stream to be ready to - /// accept data, the `subscribe` function to obtain a `pollable` which can be - /// polled for using `wasi:io/poll`. - /// - /// Dropping an `output-stream` while there's still an active write in - /// progress may result in the data being lost. Before dropping the stream, - /// be sure to fully flush your writes. - @since(version = 0.2.0) - resource output-stream { - /// Check readiness for writing. This function never blocks. - /// - /// Returns the number of bytes permitted for the next call to `write`, - /// or an error. Calling `write` with more bytes than this function has - /// permitted will trap. - /// - /// When this function returns 0 bytes, the `subscribe` pollable will - /// become ready when this function will report at least 1 byte, or an - /// error. - @since(version = 0.2.0) - check-write: func() -> result; - - /// Perform a write. This function never blocks. - /// - /// When the destination of a `write` is binary data, the bytes from - /// `contents` are written verbatim. When the destination of a `write` is - /// known to the implementation to be text, the bytes of `contents` are - /// transcoded from UTF-8 into the encoding of the destination and then - /// written. - /// - /// Precondition: check-write gave permit of Ok(n) and contents has a - /// length of less than or equal to n. Otherwise, this function will trap. - /// - /// returns Err(closed) without writing if the stream has closed since - /// the last call to check-write provided a permit. - @since(version = 0.2.0) - write: func( - contents: list - ) -> result<_, stream-error>; - - /// Perform a write of up to 4096 bytes, and then flush the stream. Block - /// until all of these operations are complete, or an error occurs. - /// - /// This is a convenience wrapper around the use of `check-write`, - /// `subscribe`, `write`, and `flush`, and is implemented with the - /// following pseudo-code: - /// - /// ```text - /// let pollable = this.subscribe(); - /// while !contents.is_empty() { - /// // Wait for the stream to become writable - /// pollable.block(); - /// let Ok(n) = this.check-write(); // eliding error handling - /// let len = min(n, contents.len()); - /// let (chunk, rest) = contents.split_at(len); - /// this.write(chunk ); // eliding error handling - /// contents = rest; - /// } - /// this.flush(); - /// // Wait for completion of `flush` - /// pollable.block(); - /// // Check for any errors that arose during `flush` - /// let _ = this.check-write(); // eliding error handling - /// ``` - @since(version = 0.2.0) - blocking-write-and-flush: func( - contents: list - ) -> result<_, stream-error>; - - /// Request to flush buffered output. This function never blocks. - /// - /// This tells the output-stream that the caller intends any buffered - /// output to be flushed. the output which is expected to be flushed - /// is all that has been passed to `write` prior to this call. - /// - /// Upon calling this function, the `output-stream` will not accept any - /// writes (`check-write` will return `ok(0)`) until the flush has - /// completed. The `subscribe` pollable will become ready when the - /// flush has completed and the stream can accept more writes. - @since(version = 0.2.0) - flush: func() -> result<_, stream-error>; - - /// Request to flush buffered output, and block until flush completes - /// and stream is ready for writing again. - @since(version = 0.2.0) - blocking-flush: func() -> result<_, stream-error>; - - /// Create a `pollable` which will resolve once the output-stream - /// is ready for more writing, or an error has occurred. When this - /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an - /// error. - /// - /// If the stream is closed, this pollable is always ready immediately. - /// - /// The created `pollable` is a child resource of the `output-stream`. - /// Implementations may trap if the `output-stream` is dropped before - /// all derived `pollable`s created with this function are dropped. - @since(version = 0.2.0) - subscribe: func() -> pollable; - - /// Write zeroes to a stream. - /// - /// This should be used precisely like `write` with the exact same - /// preconditions (must use check-write first), but instead of - /// passing a list of bytes, you simply pass the number of zero-bytes - /// that should be written. - @since(version = 0.2.0) - write-zeroes: func( - /// The number of zero-bytes to write - len: u64 - ) -> result<_, stream-error>; - - /// Perform a write of up to 4096 zeroes, and then flush the stream. - /// Block until all of these operations are complete, or an error - /// occurs. - /// - /// This is a convenience wrapper around the use of `check-write`, - /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with - /// the following pseudo-code: - /// - /// ```text - /// let pollable = this.subscribe(); - /// while num_zeroes != 0 { - /// // Wait for the stream to become writable - /// pollable.block(); - /// let Ok(n) = this.check-write(); // eliding error handling - /// let len = min(n, num_zeroes); - /// this.write-zeroes(len); // eliding error handling - /// num_zeroes -= len; - /// } - /// this.flush(); - /// // Wait for completion of `flush` - /// pollable.block(); - /// // Check for any errors that arose during `flush` - /// let _ = this.check-write(); // eliding error handling - /// ``` - @since(version = 0.2.0) - blocking-write-zeroes-and-flush: func( - /// The number of zero-bytes to write - len: u64 - ) -> result<_, stream-error>; - - /// Read from one stream and write to another. - /// - /// The behavior of splice is equivalent to: - /// 1. calling `check-write` on the `output-stream` - /// 2. calling `read` on the `input-stream` with the smaller of the - /// `check-write` permitted length and the `len` provided to `splice` - /// 3. calling `write` on the `output-stream` with that read data. - /// - /// Any error reported by the call to `check-write`, `read`, or - /// `write` ends the splice and reports that error. - /// - /// This function returns the number of bytes transferred; it may be less - /// than `len`. - @since(version = 0.2.0) - splice: func( - /// The stream to read from - src: borrow, - /// The number of bytes to splice - len: u64, - ) -> result; - - /// Read from one stream and write to another, with blocking. - /// - /// This is similar to `splice`, except that it blocks until the - /// `output-stream` is ready for writing, and the `input-stream` - /// is ready for reading, before performing the `splice`. - @since(version = 0.2.0) - blocking-splice: func( - /// The stream to read from - src: borrow, - /// The number of bytes to splice - len: u64, - ) -> result; - } -} diff --git a/golem-embed/wit/deps/wasi:io/world.wit b/golem-embed/wit/deps/wasi:io/world.wit deleted file mode 100644 index f1d2102dc..000000000 --- a/golem-embed/wit/deps/wasi:io/world.wit +++ /dev/null @@ -1,10 +0,0 @@ -package wasi:io@0.2.3; - -@since(version = 0.2.0) -world imports { - @since(version = 0.2.0) - import streams; - - @since(version = 0.2.0) - import poll; -} diff --git a/golem-embed/wit/golem-embed.wit b/golem-embed/wit/golem-embed.wit deleted file mode 100644 index 78d040320..000000000 --- a/golem-embed/wit/golem-embed.wit +++ /dev/null @@ -1,129 +0,0 @@ -package golem:embed@1.0.0; - -interface embed { - // --- Enums --- - - enum task-type { - retrieval-query, - retrieval-document, - semantic-similarity, - classification, - clustering, - question-answering, - fact-verification, - code-retrieval, - } - - enum output-format { - float-array, - binary, - base64, - } - - enum output-dtype { - float-array, - int8, - uint8, - binary, - ubinary, - } - - enum error-code { - invalid-request, - model-not-found, - unsupported, - authentication-failed, - provider-error, - rate-limit-exceeded, - internal-error, - unknown, - } - - // --- Content --- - - record image-url { - url: string, - } - - variant content-part { - text(string), - image(image-url), - } - - // --- Configuration --- - - record kv { - key: string, - value: string, - } - - record config { - model: option, - task-type: option, - dimensions: option, - truncation: option, - output-format: option, - output-dtype: option, - user: option, - provider-options: list, - } - - // --- Embedding Response --- - - record usage { - input-tokens: option, - total-tokens: option, - } - - record embedding { - index: u32, - vector: list, - } - - record embedding-response { - embeddings: list, - usage: option, - model: string, - provider-metadata-json: option, - } - - // --- Rerank Response --- - - record rerank-result { - index: u32, - relevance-score: f32, - document: option, - } - - record rerank-response { - results: list, - usage: option, - model: string, - provider-metadata-json: option, - } - - // --- Error Handling --- - - record error { - code: error-code, - message: string, - provider-error-json: option, - } - - // --- Core Functions --- - - generate: func( - inputs: list, - config: config - ) -> result; - - rerank: func( - query: string, - documents: list, - config: config - ) -> result; -} - -world embed-library { - export embed; -} \ No newline at end of file diff --git a/llm/anthropic/src/bindings.rs b/llm/anthropic/src/bindings.rs index 70c5f1fd5..1a54d6167 100644 --- a/llm/anthropic/src/bindings.rs +++ b/llm/anthropic/src/bindings.rs @@ -1,12 +1,15 @@ -// Generated by `wit-bindgen` 0.36.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" // * with "golem:llm/llm@1.0.0" = "golem_llm::golem::llm::llm" // * generate_unused_types use golem_llm::golem::llm::llm as __with_name0; #[cfg(target_arch = "wasm32")] -#[link_section = "component-type:wit-bindgen:0.36.0:golem:llm-anthropic@1.0.0:llm-library:encoded world"] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:golem:llm-anthropic@1.0.0:llm-library:encoded world" +)] #[doc(hidden)] +#[allow(clippy::octal_escapes)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1762] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xe0\x0c\x01A\x02\x01\ A\x02\x01BO\x01m\x04\x04user\x09assistant\x06system\x04tool\x04\0\x04role\x03\0\0\ @@ -43,8 +46,8 @@ ng-get-next\x01B\x01p\x15\x01@\x02\x08messages\xc3\0\x06config)\06\x04\0\x04send \0\x06config)\06\x04\0\x08continue\x01G\x01i=\x01@\x02\x08messages\xc3\0\x06conf\ ig)\0\xc8\0\x04\0\x06stream\x01I\x04\0\x13golem:llm/llm@1.0.0\x05\0\x04\0%golem:\ llm-anthropic/llm-library@1.0.0\x04\0\x0b\x11\x01\0\x0bllm-library\x03\0\0\0G\x09\ -producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rus\ -t\x060.36.0"; +producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rus\ +t\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/llm/grok/src/bindings.rs b/llm/grok/src/bindings.rs index 2a101583e..c2f601347 100644 --- a/llm/grok/src/bindings.rs +++ b/llm/grok/src/bindings.rs @@ -1,12 +1,15 @@ -// Generated by `wit-bindgen` 0.36.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" // * with "golem:llm/llm@1.0.0" = "golem_llm::golem::llm::llm" // * generate_unused_types use golem_llm::golem::llm::llm as __with_name0; #[cfg(target_arch = "wasm32")] -#[link_section = "component-type:wit-bindgen:0.36.0:golem:llm-grok@1.0.0:llm-library:encoded world"] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:golem:llm-grok@1.0.0:llm-library:encoded world" +)] #[doc(hidden)] +#[allow(clippy::octal_escapes)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1757] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xdb\x0c\x01A\x02\x01\ A\x02\x01BO\x01m\x04\x04user\x09assistant\x06system\x04tool\x04\0\x04role\x03\0\0\ @@ -43,8 +46,8 @@ ng-get-next\x01B\x01p\x15\x01@\x02\x08messages\xc3\0\x06config)\06\x04\0\x04send \0\x06config)\06\x04\0\x08continue\x01G\x01i=\x01@\x02\x08messages\xc3\0\x06conf\ ig)\0\xc8\0\x04\0\x06stream\x01I\x04\0\x13golem:llm/llm@1.0.0\x05\0\x04\0\x20gol\ em:llm-grok/llm-library@1.0.0\x04\0\x0b\x11\x01\0\x0bllm-library\x03\0\0\0G\x09p\ -roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\ -\x060.36.0"; +roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\ +\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/golem-embed/test/components-rust/test-embed/Cargo.lock b/test/components-rust/test-embed/Cargo.lock similarity index 100% rename from golem-embed/test/components-rust/test-embed/Cargo.lock rename to test/components-rust/test-embed/Cargo.lock diff --git a/golem-embed/test/components-rust/test-embed/Cargo.toml b/test/components-rust/test-embed/Cargo.toml similarity index 100% rename from golem-embed/test/components-rust/test-embed/Cargo.toml rename to test/components-rust/test-embed/Cargo.toml diff --git a/golem-embed/test/components-rust/test-embed/golem.yaml b/test/components-rust/test-embed/golem.yaml similarity index 100% rename from golem-embed/test/components-rust/test-embed/golem.yaml rename to test/components-rust/test-embed/golem.yaml diff --git a/golem-embed/test/components-rust/test-embed/src/lib.rs b/test/components-rust/test-embed/src/lib.rs similarity index 100% rename from golem-embed/test/components-rust/test-embed/src/lib.rs rename to test/components-rust/test-embed/src/lib.rs diff --git a/golem-embed/test/components-rust/test-embed/wit/test-embed.wit b/test/components-rust/test-embed/wit/test-embed.wit similarity index 100% rename from golem-embed/test/components-rust/test-embed/wit/test-embed.wit rename to test/components-rust/test-embed/wit/test-embed.wit From 7e765833188f81627fed2b43550f62199f642a35 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Wed, 25 Jun 2025 16:03:13 +0000 Subject: [PATCH 33/36] fixes --- Makefile.toml | 4 +- embed/Makefile.toml | 2 +- llm/ollama/src/bindings.rs | 11 +- llm/openai/src/bindings.rs | 11 +- llm/openrouter/src/bindings.rs | 11 +- test/wit/deps/golem-embed/golem-embed.wit | 129 ++++++++++++++++++++++ 6 files changed, 153 insertions(+), 15 deletions(-) create mode 100644 test/wit/deps/golem-embed/golem-embed.wit diff --git a/Makefile.toml b/Makefile.toml index 0c1024e37..c2c23f6e8 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -137,7 +137,7 @@ script = ''' is_portable = eq ${1} "--portable" -targets = array llm_openai llm_anthropic llm_grok llm_openrouter llm_ollama +targets = array llm_openai llm_anthropic llm_grok llm_openrouter llm_ollama embed_openai embed_cohere embed_hugging_face embed_voyageai for target in ${targets} if is_portable cp target/wasm32-wasip1/debug/golem_${target}.wasm components/debug/golem_${target}-portable.wasm @@ -153,7 +153,7 @@ script = ''' is_portable = eq ${1} "--portable" -targets = array llm_openai llm_anthropic llm_grok llm_openrouter llm_ollama +targets = array llm_openai llm_anthropic llm_grok llm_openrouter llm_ollama embed_openai embed_cohere embed_hugging_face embed_voyageai for target in ${targets} if is_portable cp target/wasm32-wasip1/release/golem_${target}.wasm components/release/golem_${target}-portable.wasm diff --git a/embed/Makefile.toml b/embed/Makefile.toml index c69e11f89..fa8e17d79 100644 --- a/embed/Makefile.toml +++ b/embed/Makefile.toml @@ -124,7 +124,7 @@ dependencies = ["wit-update"] script_runner = "@duckscript" script = """ -modules = array embed embed-openai embed-cohere embed-hugging-face embed-voyageai +modules = array embed openai cohere hugging-face voyageai for module in ${modules} rm -r ${module}/wit/deps diff --git a/llm/ollama/src/bindings.rs b/llm/ollama/src/bindings.rs index dbb704704..269cd07fb 100644 --- a/llm/ollama/src/bindings.rs +++ b/llm/ollama/src/bindings.rs @@ -1,12 +1,15 @@ -// Generated by `wit-bindgen` 0.36.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" // * with "golem:llm/llm@1.0.0" = "golem_llm::golem::llm::llm" // * generate_unused_types use golem_llm::golem::llm::llm as __with_name0; #[cfg(target_arch = "wasm32")] -#[link_section = "component-type:wit-bindgen:0.36.0:golem:llm-ollama@1.0.0:llm-library:encoded world"] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:golem:llm-ollama@1.0.0:llm-library:encoded world" +)] #[doc(hidden)] +#[allow(clippy::octal_escapes)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1759] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xdd\x0c\x01A\x02\x01\ A\x02\x01BO\x01m\x04\x04user\x09assistant\x06system\x04tool\x04\0\x04role\x03\0\0\ @@ -43,8 +46,8 @@ ng-get-next\x01B\x01p\x15\x01@\x02\x08messages\xc3\0\x06config)\06\x04\0\x04send \0\x06config)\06\x04\0\x08continue\x01G\x01i=\x01@\x02\x08messages\xc3\0\x06conf\ ig)\0\xc8\0\x04\0\x06stream\x01I\x04\0\x13golem:llm/llm@1.0.0\x05\0\x04\0\"golem\ :llm-ollama/llm-library@1.0.0\x04\0\x0b\x11\x01\0\x0bllm-library\x03\0\0\0G\x09p\ -roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\ -\x060.36.0"; +roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\ +\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/llm/openai/src/bindings.rs b/llm/openai/src/bindings.rs index c960248a8..6d0a77280 100644 --- a/llm/openai/src/bindings.rs +++ b/llm/openai/src/bindings.rs @@ -1,12 +1,15 @@ -// Generated by `wit-bindgen` 0.36.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" // * with "golem:llm/llm@1.0.0" = "golem_llm::golem::llm::llm" // * generate_unused_types use golem_llm::golem::llm::llm as __with_name0; #[cfg(target_arch = "wasm32")] -#[link_section = "component-type:wit-bindgen:0.36.0:golem:llm-openai@1.0.0:llm-library:encoded world"] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:golem:llm-openai@1.0.0:llm-library:encoded world" +)] #[doc(hidden)] +#[allow(clippy::octal_escapes)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1759] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xdd\x0c\x01A\x02\x01\ A\x02\x01BO\x01m\x04\x04user\x09assistant\x06system\x04tool\x04\0\x04role\x03\0\0\ @@ -43,8 +46,8 @@ ng-get-next\x01B\x01p\x15\x01@\x02\x08messages\xc3\0\x06config)\06\x04\0\x04send \0\x06config)\06\x04\0\x08continue\x01G\x01i=\x01@\x02\x08messages\xc3\0\x06conf\ ig)\0\xc8\0\x04\0\x06stream\x01I\x04\0\x13golem:llm/llm@1.0.0\x05\0\x04\0\"golem\ :llm-openai/llm-library@1.0.0\x04\0\x0b\x11\x01\0\x0bllm-library\x03\0\0\0G\x09p\ -roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\ -\x060.36.0"; +roducers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rust\ +\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/llm/openrouter/src/bindings.rs b/llm/openrouter/src/bindings.rs index ba2accf7e..1300cde97 100644 --- a/llm/openrouter/src/bindings.rs +++ b/llm/openrouter/src/bindings.rs @@ -1,12 +1,15 @@ -// Generated by `wit-bindgen` 0.36.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.41.0. DO NOT EDIT! // Options used: // * runtime_path: "wit_bindgen_rt" // * with "golem:llm/llm@1.0.0" = "golem_llm::golem::llm::llm" // * generate_unused_types use golem_llm::golem::llm::llm as __with_name0; #[cfg(target_arch = "wasm32")] -#[link_section = "component-type:wit-bindgen:0.36.0:golem:llm-openrouter@1.0.0:llm-library:encoded world"] +#[unsafe( + link_section = "component-type:wit-bindgen:0.41.0:golem:llm-openrouter@1.0.0:llm-library:encoded world" +)] #[doc(hidden)] +#[allow(clippy::octal_escapes)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 1763] = *b"\ \0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\xe1\x0c\x01A\x02\x01\ A\x02\x01BO\x01m\x04\x04user\x09assistant\x06system\x04tool\x04\0\x04role\x03\0\0\ @@ -43,8 +46,8 @@ ng-get-next\x01B\x01p\x15\x01@\x02\x08messages\xc3\0\x06config)\06\x04\0\x04send \0\x06config)\06\x04\0\x08continue\x01G\x01i=\x01@\x02\x08messages\xc3\0\x06conf\ ig)\0\xc8\0\x04\0\x06stream\x01I\x04\0\x13golem:llm/llm@1.0.0\x05\0\x04\0&golem:\ llm-openrouter/llm-library@1.0.0\x04\0\x0b\x11\x01\0\x0bllm-library\x03\0\0\0G\x09\ -producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rus\ -t\x060.36.0"; +producers\x01\x0cprocessed-by\x02\x0dwit-component\x070.227.1\x10wit-bindgen-rus\ +t\x060.41.0"; #[inline(never)] #[doc(hidden)] pub fn __link_custom_section_describing_imports() { diff --git a/test/wit/deps/golem-embed/golem-embed.wit b/test/wit/deps/golem-embed/golem-embed.wit new file mode 100644 index 000000000..78d040320 --- /dev/null +++ b/test/wit/deps/golem-embed/golem-embed.wit @@ -0,0 +1,129 @@ +package golem:embed@1.0.0; + +interface embed { + // --- Enums --- + + enum task-type { + retrieval-query, + retrieval-document, + semantic-similarity, + classification, + clustering, + question-answering, + fact-verification, + code-retrieval, + } + + enum output-format { + float-array, + binary, + base64, + } + + enum output-dtype { + float-array, + int8, + uint8, + binary, + ubinary, + } + + enum error-code { + invalid-request, + model-not-found, + unsupported, + authentication-failed, + provider-error, + rate-limit-exceeded, + internal-error, + unknown, + } + + // --- Content --- + + record image-url { + url: string, + } + + variant content-part { + text(string), + image(image-url), + } + + // --- Configuration --- + + record kv { + key: string, + value: string, + } + + record config { + model: option, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} + +world embed-library { + export embed; +} \ No newline at end of file From f4f71c76381b72886372e38b70bee78122312cf1 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 27 Jun 2025 10:48:05 +0000 Subject: [PATCH 34/36] ci fixes --- .github/workflows/ci.yaml | 2 +- Makefile.toml | 18 ++++++++++++------ embed/cohere/src/client.rs | 6 +++--- embed/openai/src/client.rs | 4 ++-- llm/llm/src/event_source/ndjson_stream.rs | 2 +- llm/llm/src/event_source/stream.rs | 6 +++--- test/Cargo.lock | 12 ++++++++++++ test/components-rust/test-embed/Cargo.toml | 2 +- test/components-rust/test-embed/golem.yaml | 18 +++++++++--------- 9 files changed, 44 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1bfd29df8..10a419c2a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -137,7 +137,7 @@ jobs: - name: Build and test Ollama integration run: | set -e - cargo make --cwd llm build-ollama + cargo make build cd test golem-cli app build -b ollama-debug golem-cli app deploy -b ollama-debug diff --git a/Makefile.toml b/Makefile.toml index c2c23f6e8..3e702b60d 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -6,6 +6,12 @@ skip_core_tasks = true command = "cargo" args = ["clean"] +[tasks.clean-all] +script_runner = "@duckscript" +script = ''' +exec find . -type d \( -name "target" -o -name "wit-generated" -o -name "golem-temp" \) -exec rm -rf {} + +''' + [tasks.unit-tests] command = "cargo" args = ["test"] @@ -13,7 +19,7 @@ args = ["test"] [tasks.build] script_runner = "@duckscript" script = ''' -domains = array llm +domains = array llm embed # if there is no domain passed run for every domain if is_empty ${1} @@ -28,7 +34,7 @@ end [tasks.release-build] script_runner = "@duckscript" script = ''' -domains = array llm +domains = array llm embed # if there is no domain passed run for every domain if is_empty ${1} @@ -44,7 +50,7 @@ end script_runner = "@duckscript" script = ''' #!/bin/bash -domains = array llm +domains = array llm embed # if there is no domain passed run for every domain if is_empty ${1} @@ -60,7 +66,7 @@ end script_runner = "@duckscript" script = ''' #!/bin/bash -domains = array llm +domains = array llm embed # if there is no domain passed run for every domain if is_empty ${1} @@ -75,7 +81,7 @@ end [tasks.wit] script_runner = "@duckscript" script = ''' -domains = array llm +domains = array llm embed # if there is no domain passed run for every domain if is_empty ${1} @@ -91,7 +97,7 @@ end description = "Builds all test components with golem-cli" script_runner = "@duckscript" script = ''' -domains = array llm +domains = array llm embed # if there is no domain passed run for every domain if is_empty ${1} diff --git a/embed/cohere/src/client.rs b/embed/cohere/src/client.rs index 986eb8b7d..f22daccc1 100644 --- a/embed/cohere/src/client.rs +++ b/embed/cohere/src/client.rs @@ -38,7 +38,7 @@ impl EmbeddingsApi { .json(&request) .send() .map_err(|err| from_reqwest_error("Request failed", err))?; - trace!("Recived response: {:#?}", response); + trace!("Recived response: {response:#?}"); parse_response::(response) } @@ -51,7 +51,7 @@ impl EmbeddingsApi { .json(&request) .send() .map_err(|err| from_reqwest_error("Request failed", err))?; - trace!("Recived response: {:#?}", response); + trace!("Recived response: {response:#?}"); parse_response::(response) } } @@ -70,7 +70,7 @@ fn parse_response(response: Response) -> Result(response: Response) -> Result { let bytes = general_purpose::STANDARD .decode(base64_str) - .map_err(|e| format!("Failed to decode base64: {}", e))?; + .map_err(|e| format!("Failed to decode base64: {e}"))?; if bytes.len() % 4 != 0 { return Err("Invalid base64 data: length not divisible by 4".to_string()); diff --git a/llm/llm/src/event_source/ndjson_stream.rs b/llm/llm/src/event_source/ndjson_stream.rs index e2f4cc1b2..1b8ef3773 100644 --- a/llm/llm/src/event_source/ndjson_stream.rs +++ b/llm/llm/src/event_source/ndjson_stream.rs @@ -126,7 +126,7 @@ fn try_parse_line( return Ok(None); } - trace!("Parsed NDJSON line: {}", line); + trace!("Parsed NDJSON line: {line}"); // Create a MessageEvent with the JSON line as data let event = MessageEvent { diff --git a/llm/llm/src/event_source/stream.rs b/llm/llm/src/event_source/stream.rs index 8f2933676..d997a41ab 100644 --- a/llm/llm/src/event_source/stream.rs +++ b/llm/llm/src/event_source/stream.rs @@ -56,9 +56,9 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Utf8(err) => f.write_fmt(format_args!("UTF8 error: {}", err)), - Self::Parser(err) => f.write_fmt(format_args!("Parse error: {}", err)), - Self::Transport(err) => f.write_fmt(format_args!("Transport error: {}", err)), + Self::Utf8(err) => f.write_fmt(format_args!("UTF8 error: {err}")), + Self::Parser(err) => f.write_fmt(format_args!("Parse error: {err}")), + Self::Transport(err) => f.write_fmt(format_args!("Transport error: {err}")) } } } diff --git a/test/Cargo.lock b/test/Cargo.lock index 22a6de76b..7150a2d2e 100644 --- a/test/Cargo.lock +++ b/test/Cargo.lock @@ -863,6 +863,18 @@ dependencies = [ "syn", ] +[[package]] +name = "test_embed" +version = "0.0.0" +dependencies = [ + "golem-rust", + "log", + "reqwest", + "serde", + "serde_json", + "wit-bindgen-rt 0.40.0", +] + [[package]] name = "test_helper" version = "0.0.0" diff --git a/test/components-rust/test-embed/Cargo.toml b/test/components-rust/test-embed/Cargo.toml index 895baafa9..177266a40 100644 --- a/test/components-rust/test-embed/Cargo.toml +++ b/test/components-rust/test-embed/Cargo.toml @@ -36,8 +36,8 @@ path = "wit-generated" [package.metadata.component.target.dependencies] "golem:embed" = { path = "wit-generated/deps/golem-embed" } -"wasi:io" = { path = "wit-generated/deps/io" } "wasi:clocks" = { path = "wit-generated/deps/clocks" } +"wasi:io" = { path = "wit-generated/deps/io" } "golem:rpc" = { path = "wit-generated/deps/golem-rpc" } "test:helper-client" = { path = "wit-generated/deps/test_helper-client" } "test:embed-exports" = { path = "wit-generated/deps/test_embed-exports" } diff --git a/test/components-rust/test-embed/golem.yaml b/test/components-rust/test-embed/golem.yaml index 8881f2456..2dc2141ad 100644 --- a/test/components-rust/test-embed/golem.yaml +++ b/test/components-rust/test-embed/golem.yaml @@ -6,7 +6,7 @@ # See https://learn.golem.cloud/docs/app-manifest#field-reference for field reference components: - test:embed: + test:embed: profiles: # DEBUG PROFILES openai-debug: @@ -22,10 +22,10 @@ components: - ../../common-rust targets: - target/wasm32-wasip1/debug/test_embed.wasm - - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_openai_plugged.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/debug/golem_embed_openai.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_openai_plugged.wasm sources: - ../../target/wasm32-wasip1/debug/test_embed.wasm - - ../../../../target/wasm32-wasip1/debug/golem_embed_openai.wasm + - ../../../target/wasm32-wasip1/debug/golem_embed_openai.wasm targets: - ../../target/wasm32-wasip1/debug/test_openai_plugged.wasm sourceWit: wit @@ -48,10 +48,10 @@ components: - ../../common-rust targets: - target/wasm32-wasip1/debug/test_embed.wasm - - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_cohere_plugged.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/debug/golem_embed_cohere.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_cohere_plugged.wasm sources: - ../../target/wasm32-wasip1/debug/test_embed.wasm - - ../../../../target/wasm32-wasip1/debug/golem_embed_cohere.wasm + - ../../../target/wasm32-wasip1/debug/golem_embed_cohere.wasm targets: - ../../target/wasm32-wasip1/debug/test_cohere_plugged.wasm sourceWit: wit @@ -74,10 +74,10 @@ components: - ../../common-rust targets: - target/wasm32-wasip1/debug/test_embed.wasm - - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_hugging_face_plugged.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_hugging_face_plugged.wasm sources: - ../../target/wasm32-wasip1/debug/test_embed.wasm - - ../../../../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm + - ../../../target/wasm32-wasip1/debug/golem_embed_hugging_face.wasm targets: - ../../target/wasm32-wasip1/debug/test_hugging_face_plugged.wasm sourceWit: wit @@ -100,10 +100,10 @@ components: - ../../common-rust targets: - target/wasm32-wasip1/debug/test_embed.wasm - - command: wac plug --plug ../../../../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_voyageai_plugged.wasm + - command: wac plug --plug ../../../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm ../../target/wasm32-wasip1/debug/test_embed.wasm -o ../../target/wasm32-wasip1/debug/test_voyageai_plugged.wasm sources: - ../../target/wasm32-wasip1/debug/test_embed.wasm - - ../../../../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm + - ../../../target/wasm32-wasip1/debug/golem_embed_voyageai.wasm targets: - ../../target/wasm32-wasip1/debug/test_voyageai_plugged.wasm sourceWit: wit From 16a36da3db054af3aeb7ca11513b6a4e5da839e9 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Fri, 27 Jun 2025 15:08:29 +0000 Subject: [PATCH 35/36] removed println --- embed/voyageai/src/conversitions.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embed/voyageai/src/conversitions.rs b/embed/voyageai/src/conversitions.rs index f8fb962d5..4fddebc10 100644 --- a/embed/voyageai/src/conversitions.rs +++ b/embed/voyageai/src/conversitions.rs @@ -154,8 +154,8 @@ mod tests { let request = create_embedding_request(inputs.clone(), config.clone()); match &request { - Ok(request) => print!("{:?}", request), - Err(err) => println!("{:?}", err), + Ok(_request) => {}, + Err(_err) => {}, }; assert!(request.is_ok()); } @@ -181,8 +181,8 @@ mod tests { let request = create_rerank_request(query, documents, config); match &request { - Ok(request) => print!("{:?}", &request), - Err(err) => println!("{:?}", err), + Ok(_request) => {}, + Err(_err) => {}, }; assert!(request.is_ok()); } From 5818aee759f836e6bed27bd0bd900d5eaa687817 Mon Sep 17 00:00:00 2001 From: Rutik7066 Date: Mon, 30 Jun 2025 17:20:43 +0000 Subject: [PATCH 36/36] lint --- embed/cohere/src/conversions.rs | 2 +- embed/hugging-face/src/client.rs | 2 +- .../test/wit/deps/golem-embed/golem-embed.wit | 129 ++++++++ embed/test/wit/deps/io/error.wit | 34 ++ embed/test/wit/deps/io/poll.wit | 47 +++ embed/test/wit/deps/io/streams.wit | 290 ++++++++++++++++++ embed/test/wit/deps/io/world.wit | 10 + embed/voyageai/src/client.rs | 4 +- embed/voyageai/src/conversitions.rs | 8 +- llm/anthropic/src/conversions.rs | 2 +- llm/grok/src/conversions.rs | 2 +- llm/llm/src/event_source/stream.rs | 2 +- llm/ollama/src/client.rs | 2 +- llm/ollama/src/conversions.rs | 2 +- llm/openai/src/conversions.rs | 2 +- llm/openrouter/src/conversions.rs | 2 +- 16 files changed, 525 insertions(+), 15 deletions(-) create mode 100644 embed/test/wit/deps/golem-embed/golem-embed.wit create mode 100644 embed/test/wit/deps/io/error.wit create mode 100644 embed/test/wit/deps/io/poll.wit create mode 100644 embed/test/wit/deps/io/streams.wit create mode 100644 embed/test/wit/deps/io/world.wit diff --git a/embed/cohere/src/conversions.rs b/embed/cohere/src/conversions.rs index 5843b9cbe..d60f24606 100644 --- a/embed/cohere/src/conversions.rs +++ b/embed/cohere/src/conversions.rs @@ -344,7 +344,7 @@ mod tests { }; let result = process_embedding_response(data.clone(), config); - print!("{:?}", result); + print!("{result:?}"); let embedding_response = result.unwrap(); assert_eq!(embedding_response.embeddings.len(), 5); assert_eq!(embedding_response.embeddings[0].index, 0); diff --git a/embed/hugging-face/src/client.rs b/embed/hugging-face/src/client.rs index 4c1e42310..190918115 100644 --- a/embed/hugging-face/src/client.rs +++ b/embed/hugging-face/src/client.rs @@ -63,7 +63,7 @@ fn parse_response(response: Response) -> Result, + task-type: option, + dimensions: option, + truncation: option, + output-format: option, + output-dtype: option, + user: option, + provider-options: list, + } + + // --- Embedding Response --- + + record usage { + input-tokens: option, + total-tokens: option, + } + + record embedding { + index: u32, + vector: list, + } + + record embedding-response { + embeddings: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Rerank Response --- + + record rerank-result { + index: u32, + relevance-score: f32, + document: option, + } + + record rerank-response { + results: list, + usage: option, + model: string, + provider-metadata-json: option, + } + + // --- Error Handling --- + + record error { + code: error-code, + message: string, + provider-error-json: option, + } + + // --- Core Functions --- + + generate: func( + inputs: list, + config: config + ) -> result; + + rerank: func( + query: string, + documents: list, + config: config + ) -> result; +} + +world embed-library { + export embed; +} \ No newline at end of file diff --git a/embed/test/wit/deps/io/error.wit b/embed/test/wit/deps/io/error.wit new file mode 100644 index 000000000..97c606877 --- /dev/null +++ b/embed/test/wit/deps/io/error.wit @@ -0,0 +1,34 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +interface error { + /// A resource which represents some error information. + /// + /// The only method provided by this resource is `to-debug-string`, + /// which provides some human-readable information about the error. + /// + /// In the `wasi:io` package, this resource is returned through the + /// `wasi:io/streams/stream-error` type. + /// + /// To provide more specific error information, other interfaces may + /// offer functions to "downcast" this error into more specific types. For example, + /// errors returned from streams derived from filesystem types can be described using + /// the filesystem's own error-code type. This is done using the function + /// `wasi:filesystem/types/filesystem-error-code`, which takes a `borrow` + /// parameter and returns an `option`. + /// + /// The set of functions which can "downcast" an `error` into a more + /// concrete type is open. + @since(version = 0.2.0) + resource error { + /// Returns a string that is suitable to assist humans in debugging + /// this error. + /// + /// WARNING: The returned string should not be consumed mechanically! + /// It may change across platforms, hosts, or other implementation + /// details. Parsing this string is a major platform-compatibility + /// hazard. + @since(version = 0.2.0) + to-debug-string: func() -> string; + } +} diff --git a/embed/test/wit/deps/io/poll.wit b/embed/test/wit/deps/io/poll.wit new file mode 100644 index 000000000..9bcbe8e03 --- /dev/null +++ b/embed/test/wit/deps/io/poll.wit @@ -0,0 +1,47 @@ +package wasi:io@0.2.3; + +/// A poll API intended to let users wait for I/O events on multiple handles +/// at once. +@since(version = 0.2.0) +interface poll { + /// `pollable` represents a single I/O event which may be ready, or not. + @since(version = 0.2.0) + resource pollable { + + /// Return the readiness of a pollable. This function never blocks. + /// + /// Returns `true` when the pollable is ready, and `false` otherwise. + @since(version = 0.2.0) + ready: func() -> bool; + + /// `block` returns immediately if the pollable is ready, and otherwise + /// blocks until ready. + /// + /// This function is equivalent to calling `poll.poll` on a list + /// containing only this pollable. + @since(version = 0.2.0) + block: func(); + } + + /// Poll for completion on a set of pollables. + /// + /// This function takes a list of pollables, which identify I/O sources of + /// interest, and waits until one or more of the events is ready for I/O. + /// + /// The result `list` contains one or more indices of handles in the + /// argument list that is ready for I/O. + /// + /// This function traps if either: + /// - the list is empty, or: + /// - the list contains more elements than can be indexed with a `u32` value. + /// + /// A timeout can be implemented by adding a pollable from the + /// wasi-clocks API to the list. + /// + /// This function does not return a `result`; polling in itself does not + /// do any I/O so it doesn't fail. If any of the I/O sources identified by + /// the pollables has an error, it is indicated by marking the source as + /// being ready for I/O. + @since(version = 0.2.0) + poll: func(in: list>) -> list; +} diff --git a/embed/test/wit/deps/io/streams.wit b/embed/test/wit/deps/io/streams.wit new file mode 100644 index 000000000..0de084629 --- /dev/null +++ b/embed/test/wit/deps/io/streams.wit @@ -0,0 +1,290 @@ +package wasi:io@0.2.3; + +/// WASI I/O is an I/O abstraction API which is currently focused on providing +/// stream types. +/// +/// In the future, the component model is expected to add built-in stream types; +/// when it does, they are expected to subsume this API. +@since(version = 0.2.0) +interface streams { + @since(version = 0.2.0) + use error.{error}; + @since(version = 0.2.0) + use poll.{pollable}; + + /// An error for input-stream and output-stream operations. + @since(version = 0.2.0) + variant stream-error { + /// The last operation (a write or flush) failed before completion. + /// + /// More information is available in the `error` payload. + /// + /// After this, the stream will be closed. All future operations return + /// `stream-error::closed`. + last-operation-failed(error), + /// The stream is closed: no more input will be accepted by the + /// stream. A closed output-stream will return this error on all + /// future operations. + closed + } + + /// An input bytestream. + /// + /// `input-stream`s are *non-blocking* to the extent practical on underlying + /// platforms. I/O operations always return promptly; if fewer bytes are + /// promptly available than requested, they return the number of bytes promptly + /// available, which could even be zero. To wait for data to be available, + /// use the `subscribe` function to obtain a `pollable` which can be polled + /// for using `wasi:io/poll`. + @since(version = 0.2.0) + resource input-stream { + /// Perform a non-blocking read from the stream. + /// + /// When the source of a `read` is binary data, the bytes from the source + /// are returned verbatim. When the source of a `read` is known to the + /// implementation to be text, bytes containing the UTF-8 encoding of the + /// text are returned. + /// + /// This function returns a list of bytes containing the read data, + /// when successful. The returned list will contain up to `len` bytes; + /// it may return fewer than requested, but not more. The list is + /// empty when no bytes are available for reading at this time. The + /// pollable given by `subscribe` will be ready when more bytes are + /// available. + /// + /// This function fails with a `stream-error` when the operation + /// encounters an error, giving `last-operation-failed`, or when the + /// stream is closed, giving `closed`. + /// + /// When the caller gives a `len` of 0, it represents a request to + /// read 0 bytes. If the stream is still open, this call should + /// succeed and return an empty list, or otherwise fail with `closed`. + /// + /// The `len` parameter is a `u64`, which could represent a list of u8 which + /// is not possible to allocate in wasm32, or not desirable to allocate as + /// as a return value by the callee. The callee may return a list of bytes + /// less than `len` in size while more bytes are available for reading. + @since(version = 0.2.0) + read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Read bytes from a stream, after blocking until at least one byte can + /// be read. Except for blocking, behavior is identical to `read`. + @since(version = 0.2.0) + blocking-read: func( + /// The maximum number of bytes to read + len: u64 + ) -> result, stream-error>; + + /// Skip bytes from a stream. Returns number of bytes skipped. + /// + /// Behaves identical to `read`, except instead of returning a list + /// of bytes, returns the number of bytes consumed from the stream. + @since(version = 0.2.0) + skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Skip bytes from a stream, after blocking until at least one byte + /// can be skipped. Except for blocking behavior, identical to `skip`. + @since(version = 0.2.0) + blocking-skip: func( + /// The maximum number of bytes to skip. + len: u64, + ) -> result; + + /// Create a `pollable` which will resolve once either the specified stream + /// has bytes available to read or the other end of the stream has been + /// closed. + /// The created `pollable` is a child resource of the `input-stream`. + /// Implementations may trap if the `input-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + } + + + /// An output bytestream. + /// + /// `output-stream`s are *non-blocking* to the extent practical on + /// underlying platforms. Except where specified otherwise, I/O operations also + /// always return promptly, after the number of bytes that can be written + /// promptly, which could even be zero. To wait for the stream to be ready to + /// accept data, the `subscribe` function to obtain a `pollable` which can be + /// polled for using `wasi:io/poll`. + /// + /// Dropping an `output-stream` while there's still an active write in + /// progress may result in the data being lost. Before dropping the stream, + /// be sure to fully flush your writes. + @since(version = 0.2.0) + resource output-stream { + /// Check readiness for writing. This function never blocks. + /// + /// Returns the number of bytes permitted for the next call to `write`, + /// or an error. Calling `write` with more bytes than this function has + /// permitted will trap. + /// + /// When this function returns 0 bytes, the `subscribe` pollable will + /// become ready when this function will report at least 1 byte, or an + /// error. + @since(version = 0.2.0) + check-write: func() -> result; + + /// Perform a write. This function never blocks. + /// + /// When the destination of a `write` is binary data, the bytes from + /// `contents` are written verbatim. When the destination of a `write` is + /// known to the implementation to be text, the bytes of `contents` are + /// transcoded from UTF-8 into the encoding of the destination and then + /// written. + /// + /// Precondition: check-write gave permit of Ok(n) and contents has a + /// length of less than or equal to n. Otherwise, this function will trap. + /// + /// returns Err(closed) without writing if the stream has closed since + /// the last call to check-write provided a permit. + @since(version = 0.2.0) + write: func( + contents: list + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 bytes, and then flush the stream. Block + /// until all of these operations are complete, or an error occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write`, and `flush`, and is implemented with the + /// following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while !contents.is_empty() { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, contents.len()); + /// let (chunk, rest) = contents.split_at(len); + /// this.write(chunk ); // eliding error handling + /// contents = rest; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-and-flush: func( + contents: list + ) -> result<_, stream-error>; + + /// Request to flush buffered output. This function never blocks. + /// + /// This tells the output-stream that the caller intends any buffered + /// output to be flushed. the output which is expected to be flushed + /// is all that has been passed to `write` prior to this call. + /// + /// Upon calling this function, the `output-stream` will not accept any + /// writes (`check-write` will return `ok(0)`) until the flush has + /// completed. The `subscribe` pollable will become ready when the + /// flush has completed and the stream can accept more writes. + @since(version = 0.2.0) + flush: func() -> result<_, stream-error>; + + /// Request to flush buffered output, and block until flush completes + /// and stream is ready for writing again. + @since(version = 0.2.0) + blocking-flush: func() -> result<_, stream-error>; + + /// Create a `pollable` which will resolve once the output-stream + /// is ready for more writing, or an error has occurred. When this + /// pollable is ready, `check-write` will return `ok(n)` with n>0, or an + /// error. + /// + /// If the stream is closed, this pollable is always ready immediately. + /// + /// The created `pollable` is a child resource of the `output-stream`. + /// Implementations may trap if the `output-stream` is dropped before + /// all derived `pollable`s created with this function are dropped. + @since(version = 0.2.0) + subscribe: func() -> pollable; + + /// Write zeroes to a stream. + /// + /// This should be used precisely like `write` with the exact same + /// preconditions (must use check-write first), but instead of + /// passing a list of bytes, you simply pass the number of zero-bytes + /// that should be written. + @since(version = 0.2.0) + write-zeroes: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Perform a write of up to 4096 zeroes, and then flush the stream. + /// Block until all of these operations are complete, or an error + /// occurs. + /// + /// This is a convenience wrapper around the use of `check-write`, + /// `subscribe`, `write-zeroes`, and `flush`, and is implemented with + /// the following pseudo-code: + /// + /// ```text + /// let pollable = this.subscribe(); + /// while num_zeroes != 0 { + /// // Wait for the stream to become writable + /// pollable.block(); + /// let Ok(n) = this.check-write(); // eliding error handling + /// let len = min(n, num_zeroes); + /// this.write-zeroes(len); // eliding error handling + /// num_zeroes -= len; + /// } + /// this.flush(); + /// // Wait for completion of `flush` + /// pollable.block(); + /// // Check for any errors that arose during `flush` + /// let _ = this.check-write(); // eliding error handling + /// ``` + @since(version = 0.2.0) + blocking-write-zeroes-and-flush: func( + /// The number of zero-bytes to write + len: u64 + ) -> result<_, stream-error>; + + /// Read from one stream and write to another. + /// + /// The behavior of splice is equivalent to: + /// 1. calling `check-write` on the `output-stream` + /// 2. calling `read` on the `input-stream` with the smaller of the + /// `check-write` permitted length and the `len` provided to `splice` + /// 3. calling `write` on the `output-stream` with that read data. + /// + /// Any error reported by the call to `check-write`, `read`, or + /// `write` ends the splice and reports that error. + /// + /// This function returns the number of bytes transferred; it may be less + /// than `len`. + @since(version = 0.2.0) + splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + + /// Read from one stream and write to another, with blocking. + /// + /// This is similar to `splice`, except that it blocks until the + /// `output-stream` is ready for writing, and the `input-stream` + /// is ready for reading, before performing the `splice`. + @since(version = 0.2.0) + blocking-splice: func( + /// The stream to read from + src: borrow, + /// The number of bytes to splice + len: u64, + ) -> result; + } +} diff --git a/embed/test/wit/deps/io/world.wit b/embed/test/wit/deps/io/world.wit new file mode 100644 index 000000000..f1d2102dc --- /dev/null +++ b/embed/test/wit/deps/io/world.wit @@ -0,0 +1,10 @@ +package wasi:io@0.2.3; + +@since(version = 0.2.0) +world imports { + @since(version = 0.2.0) + import streams; + + @since(version = 0.2.0) + import poll; +} diff --git a/embed/voyageai/src/client.rs b/embed/voyageai/src/client.rs index ff4811d78..45c2654a6 100644 --- a/embed/voyageai/src/client.rs +++ b/embed/voyageai/src/client.rs @@ -85,7 +85,7 @@ fn parse_response(response: Response) -> Result(response: Response) -> Result {}, - Err(_err) => {}, + Ok(_request) => {} + Err(_err) => {} }; assert!(request.is_ok()); } @@ -181,8 +181,8 @@ mod tests { let request = create_rerank_request(query, documents, config); match &request { - Ok(_request) => {}, - Err(_err) => {}, + Ok(_request) => {} + Err(_err) => {} }; assert!(request.is_ok()); } diff --git a/llm/anthropic/src/conversions.rs b/llm/anthropic/src/conversions.rs index e332f1391..e7d3175a0 100644 --- a/llm/anthropic/src/conversions.rs +++ b/llm/anthropic/src/conversions.rs @@ -130,7 +130,7 @@ pub fn process_response(response: MessagesResponse) -> ChatEvent { Err(e) => { return ChatEvent::Error(Error { code: ErrorCode::InvalidRequest, - message: format!("Failed to decode base64 image data: {}", e), + message: format!("Failed to decode base64 image data: {e}"), provider_error_json: None, }); } diff --git a/llm/grok/src/conversions.rs b/llm/grok/src/conversions.rs index 68a5d570c..129c128ad 100644 --- a/llm/grok/src/conversions.rs +++ b/llm/grok/src/conversions.rs @@ -183,7 +183,7 @@ fn convert_content_parts(contents: Vec) -> crate::client::Content { let media_type = &image_source.mime_type; // This is already a string result.push(crate::client::ContentPart::ImageInput { image_url: crate::client::ImageUrl { - url: format!("data:{};base64,{}", media_type, base64_data), + url: format!("data:{media_type};base64,{base64_data}"), detail: image_source.detail.map(|d| d.into()), }, }); diff --git a/llm/llm/src/event_source/stream.rs b/llm/llm/src/event_source/stream.rs index d997a41ab..13a5eeb56 100644 --- a/llm/llm/src/event_source/stream.rs +++ b/llm/llm/src/event_source/stream.rs @@ -58,7 +58,7 @@ where match self { Self::Utf8(err) => f.write_fmt(format_args!("UTF8 error: {err}")), Self::Parser(err) => f.write_fmt(format_args!("Parse error: {err}")), - Self::Transport(err) => f.write_fmt(format_args!("Transport error: {err}")) + Self::Transport(err) => f.write_fmt(format_args!("Transport error: {err}")), } } } diff --git a/llm/ollama/src/client.rs b/llm/ollama/src/client.rs index e9514a8dd..e2901e70c 100644 --- a/llm/ollama/src/client.rs +++ b/llm/ollama/src/client.rs @@ -335,7 +335,7 @@ pub fn image_to_base64(source: &str) -> Result Error { Error { code: ErrorCode::InternalError, - message: format!("{}: {}", context, err), + message: format!("{context}: {err}"), provider_error_json: None, } } diff --git a/llm/ollama/src/conversions.rs b/llm/ollama/src/conversions.rs index b1db65c61..8d64e954f 100644 --- a/llm/ollama/src/conversions.rs +++ b/llm/ollama/src/conversions.rs @@ -214,7 +214,7 @@ pub fn process_response(response: CompletionsResponse) -> ChatEvent { }; ChatEvent::Message(CompleteResponse { - id: format!("ollama-{}", timestamp), + id: format!("ollama-{timestamp}"), content, tool_calls, metadata, diff --git a/llm/openai/src/conversions.rs b/llm/openai/src/conversions.rs index 43694c0f3..a4989b0c1 100644 --- a/llm/openai/src/conversions.rs +++ b/llm/openai/src/conversions.rs @@ -138,7 +138,7 @@ pub fn content_part_to_inner_input_item(content_part: ContentPart) -> InnerInput ImageReference::Inline(image_source) => { let base64_data = general_purpose::STANDARD.encode(&image_source.data); let mime_type = &image_source.mime_type; // This is already a string - let data_url = format!("data:{};base64,{}", mime_type, base64_data); + let data_url = format!("data:{mime_type};base64,{base64_data}"); InnerInputItem::ImageInput { image_url: data_url, diff --git a/llm/openrouter/src/conversions.rs b/llm/openrouter/src/conversions.rs index d4db2d34c..61b5f973b 100644 --- a/llm/openrouter/src/conversions.rs +++ b/llm/openrouter/src/conversions.rs @@ -184,7 +184,7 @@ fn convert_content_parts(contents: Vec) -> crate::client::Content { let media_type = &image_source.mime_type; // This is already a string result.push(crate::client::ContentPart::ImageInput { image_url: crate::client::ImageUrl { - url: format!("data:{};base64,{}", media_type, base64_data), + url: format!("data:{media_type};base64,{base64_data}"), detail: image_source.detail.map(|d| d.into()), }, });