mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-30 01:53:45 +00:00
Merge remote-tracking branch 'origin/main' into petri-integration
# Conflicts: # Cargo.lock # Cargo.toml # lib/components/fabro-validate/src/lib.rs # lib/components/fabro-workflow/src/handler/llm/fallback.rs # lib/components/fabro-workflow/src/handler/prompt.rs # lib/components/fabro-workflow/src/operations/start.rs # lib/components/fabro-workflow/src/pipeline/pull_request.rs # lib/components/fabro-workflow/src/transforms/model_resolution.rs # lib/components/fabro-workflow/tests/it/integration.rs # lib/components/fabro-workflow/tests/it/pebble_agent.rs
This commit is contained in:
commit
776c50307f
30 changed files with 327 additions and 173 deletions
218
Cargo.lock
generated
218
Cargo.lock
generated
|
|
@ -2043,7 +2043,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-api"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fabro-automation",
|
||||
|
|
@ -2051,9 +2051,9 @@ dependencies = [
|
|||
"fabro-environment",
|
||||
"fabro-types",
|
||||
"jsonschema",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"openapiv3",
|
||||
"pebble-coding-agent",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"prettyplease",
|
||||
"progenitor",
|
||||
"progenitor-client",
|
||||
|
|
@ -2069,7 +2069,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-auth"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2082,7 +2082,7 @@ dependencies = [
|
|||
"fabro-types",
|
||||
"fabro-vault",
|
||||
"httpmock",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
|
|
@ -2094,7 +2094,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-automation"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -2115,11 +2115,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-build-support"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
|
||||
[[package]]
|
||||
name = "fabro-checkpoint"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"fabro-config",
|
||||
"fabro-types",
|
||||
|
|
@ -2127,7 +2127,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-cli"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
|
|
@ -2187,15 +2187,15 @@ dependencies = [
|
|||
"insta",
|
||||
"jsonwebtoken",
|
||||
"libc",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"miette",
|
||||
"nix 0.30.1",
|
||||
"object_store",
|
||||
"openssl",
|
||||
"paste",
|
||||
"pebble-agent",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"pebble-cli-core",
|
||||
"pebble-coding-agent",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"predicates",
|
||||
"progenitor-client",
|
||||
"rand 0.9.4",
|
||||
|
|
@ -2230,7 +2230,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-client"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
|
@ -2244,7 +2244,7 @@ dependencies = [
|
|||
"futures",
|
||||
"httpmock",
|
||||
"libc",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"progenitor-client",
|
||||
"rand 0.9.4",
|
||||
"serde",
|
||||
|
|
@ -2259,7 +2259,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-config"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -2288,7 +2288,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-db"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -2301,7 +2301,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-dev"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
|
|
@ -2320,7 +2320,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-dump"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
|
@ -2334,7 +2334,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-environment"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -2356,7 +2356,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-github"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2381,7 +2381,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-graphviz"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fabro-types",
|
||||
|
|
@ -2395,7 +2395,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-http"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"fabro-static",
|
||||
"http 1.4.0",
|
||||
|
|
@ -2405,7 +2405,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-install"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
|
|
@ -2424,7 +2424,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-interview"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dialoguer",
|
||||
|
|
@ -2439,7 +2439,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-llm"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2455,7 +2455,7 @@ dependencies = [
|
|||
"fabro-types",
|
||||
"futures",
|
||||
"httpmock",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum 0.28.0",
|
||||
|
|
@ -2468,7 +2468,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-macros"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fabro-options-metadata",
|
||||
|
|
@ -2479,7 +2479,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-manifest"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2508,7 +2508,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-mcp-server"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -2535,7 +2535,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-mcp-store"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fabro-db",
|
||||
|
|
@ -2553,7 +2553,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-oauth"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
|
@ -2575,7 +2575,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-options-metadata"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2583,7 +2583,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-petri"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2606,8 +2606,8 @@ dependencies = [
|
|||
"fabro-vault",
|
||||
"fabro-workflow",
|
||||
"httpmock",
|
||||
"lithos-llm",
|
||||
"pebble-coding-agent",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"petri-attractor-steps",
|
||||
"petri-execution",
|
||||
"petri-frontend-attractor",
|
||||
|
|
@ -2627,7 +2627,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-proc"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -2640,7 +2640,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-redact"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"ref-cast",
|
||||
|
|
@ -2656,7 +2656,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-sandbox"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2670,7 +2670,7 @@ dependencies = [
|
|||
"fabro-types",
|
||||
"fabro-util",
|
||||
"futures",
|
||||
"pebble-coding-agent",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"reqwest 0.13.4",
|
||||
"sandbox-driver",
|
||||
"sandbox-driver-daytona",
|
||||
|
|
@ -2694,7 +2694,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-server"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2751,12 +2751,12 @@ dependencies = [
|
|||
"http-body-util",
|
||||
"httpmock",
|
||||
"jsonwebtoken",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"mime_guess",
|
||||
"multer",
|
||||
"object_store",
|
||||
"pebble-agent",
|
||||
"pebble-coding-agent",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"percent-encoding",
|
||||
"rand 0.9.4",
|
||||
"regex",
|
||||
|
|
@ -2791,7 +2791,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-slack"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"fabro-http",
|
||||
"fabro-interview",
|
||||
|
|
@ -2812,18 +2812,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-spa"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"rust-embed",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-static"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
|
||||
[[package]]
|
||||
name = "fabro-store"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
|
|
@ -2835,9 +2835,9 @@ dependencies = [
|
|||
"futures",
|
||||
"hex",
|
||||
"insta",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"object_store",
|
||||
"pebble-coding-agent",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2855,7 +2855,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-telemetry"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
|
|
@ -2881,7 +2881,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-template"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fabro-types",
|
||||
|
|
@ -2895,7 +2895,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-test"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
|
|
@ -2920,7 +2920,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-tool"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2944,7 +2944,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-tracker"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -2958,7 +2958,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-types"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
|
@ -2966,8 +2966,8 @@ dependencies = [
|
|||
"fabro-types",
|
||||
"fabro-util",
|
||||
"hex",
|
||||
"lithos-llm",
|
||||
"pebble-coding-agent",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"sandbox-driver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2985,7 +2985,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-util"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"console 0.15.11",
|
||||
|
|
@ -3008,7 +3008,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-variable"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -3025,7 +3025,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-vault"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -3044,7 +3044,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-workflow"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -3080,13 +3080,13 @@ dependencies = [
|
|||
"hex",
|
||||
"httpmock",
|
||||
"jsonschema",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"md5",
|
||||
"miette",
|
||||
"mime_guess",
|
||||
"object_store",
|
||||
"pebble-agent",
|
||||
"pebble-coding-agent",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"rand 0.9.4",
|
||||
"regex",
|
||||
"sandbox-driver",
|
||||
|
|
@ -3108,7 +3108,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fabro-workflow-version"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"fabro-config",
|
||||
"fabro-graphviz",
|
||||
|
|
@ -4407,7 +4407,7 @@ checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
|||
[[package]]
|
||||
name = "lithos-llm"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/lithos-llm?rev=55add4596b861a0623d00c3a54aa5c147c8d504b#55add4596b861a0623d00c3a54aa5c147c8d504b"
|
||||
source = "git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb#43a42ac28e9d9bcf40a91abc02be4f12ca274ebb"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"aws-config",
|
||||
|
|
@ -4419,6 +4419,7 @@ dependencies = [
|
|||
"crc32fast",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap 2.13.0",
|
||||
"mime_guess",
|
||||
"reqwest 0.13.4",
|
||||
"serde",
|
||||
|
|
@ -4430,6 +4431,24 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lithos-llm"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/lithos-llm?rev=55add4596b861a0623d00c3a54aa5c147c8d504b#55add4596b861a0623d00c3a54aa5c147c8d504b"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"reqwest 0.13.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"toml 0.8.23",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "1.0.0"
|
||||
|
|
@ -5238,11 +5257,28 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
|||
[[package]]
|
||||
name = "pebble-agent"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/pebble?rev=a39f43e26effdf99635eaf343f095c17157c9c93#a39f43e26effdf99635eaf343f095c17157c9c93"
|
||||
source = "git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d#67c9f486dd28f15c04e8d590a91e6f5563f7605d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-util",
|
||||
"lithos-llm",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pebble-agent"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/pebble.git?rev=a39f43e26effdf99635eaf343f095c17157c9c93#a39f43e26effdf99635eaf343f095c17157c9c93"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-util",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=55add4596b861a0623d00c3a54aa5c147c8d504b)",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
|
|
@ -5255,7 +5291,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pebble-cli-core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/pebble?rev=a39f43e26effdf99635eaf343f095c17157c9c93#a39f43e26effdf99635eaf343f095c17157c9c93"
|
||||
source = "git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d#67c9f486dd28f15c04e8d590a91e6f5563f7605d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
|
@ -5265,9 +5301,9 @@ dependencies = [
|
|||
"fs2",
|
||||
"futures-util",
|
||||
"humantime",
|
||||
"lithos-llm",
|
||||
"pebble-agent",
|
||||
"pebble-coding-agent",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"rustix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -5284,12 +5320,36 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pebble-coding-agent"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/pebble?rev=a39f43e26effdf99635eaf343f095c17157c9c93#a39f43e26effdf99635eaf343f095c17157c9c93"
|
||||
source = "git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d#67c9f486dd28f15c04e8d590a91e6f5563f7605d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-util",
|
||||
"lithos-llm",
|
||||
"pebble-agent",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=43a42ac28e9d9bcf40a91abc02be4f12ca274ebb)",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble?rev=67c9f486dd28f15c04e8d590a91e6f5563f7605d)",
|
||||
"reqwest 0.13.4",
|
||||
"rmcp",
|
||||
"rustix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"sse-stream",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pebble-coding-agent"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lithoscomputer/pebble.git?rev=a39f43e26effdf99635eaf343f095c17157c9c93#a39f43e26effdf99635eaf343f095c17157c9c93"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures-util",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=55add4596b861a0623d00c3a54aa5c147c8d504b)",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble.git?rev=a39f43e26effdf99635eaf343f095c17157c9c93)",
|
||||
"reqwest 0.13.4",
|
||||
"rmcp",
|
||||
"rustix",
|
||||
|
|
@ -5329,9 +5389,9 @@ dependencies = [
|
|||
"async-trait",
|
||||
"globset",
|
||||
"jsonschema",
|
||||
"lithos-llm",
|
||||
"pebble-agent",
|
||||
"pebble-coding-agent",
|
||||
"lithos-llm 0.1.0 (git+https://github.com/lithoscomputer/lithos-llm?rev=55add4596b861a0623d00c3a54aa5c147c8d504b)",
|
||||
"pebble-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble.git?rev=a39f43e26effdf99635eaf343f095c17157c9c93)",
|
||||
"pebble-coding-agent 0.1.0 (git+https://github.com/lithoscomputer/pebble.git?rev=a39f43e26effdf99635eaf343f095c17157c9c93)",
|
||||
"petri-execution",
|
||||
"petri-executor",
|
||||
"petri-frontend",
|
||||
|
|
@ -8065,7 +8125,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "twin-github"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"base64",
|
||||
|
|
|
|||
10
Cargo.toml
10
Cargo.toml
|
|
@ -10,7 +10,7 @@ resolver = "2"
|
|||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
version = "0.357.0-nightly.0"
|
||||
version = "0.361.0-nightly.0"
|
||||
license = "MIT"
|
||||
|
||||
[workspace.dependencies]
|
||||
|
|
@ -93,7 +93,7 @@ insta = "1"
|
|||
fabro-test = { path = "lib/foundation/fabro-test" }
|
||||
# Provider-neutral LLM catalog and client. Pinned to a revision until 0.x is
|
||||
# published to crates.io.
|
||||
lithos-llm = { git = "https://github.com/lithoscomputer/lithos-llm", rev = "55add4596b861a0623d00c3a54aa5c147c8d504b", default-features = false }
|
||||
lithos-llm = { git = "https://github.com/lithoscomputer/lithos-llm", rev = "43a42ac28e9d9bcf40a91abc02be4f12ca274ebb", default-features = false }
|
||||
# Deterministic OpenAI twin used by twin-mode E2E tests; the same revision
|
||||
# lithos-llm verifies its codecs against.
|
||||
twin-openai = { git = "https://github.com/lithoscomputer/twins", rev = "ca45f0e50a6716d716aa2f638ca3cf767e88f613" }
|
||||
|
|
@ -124,9 +124,9 @@ sandbox-driver-testing = { git = "https://github.com/lithoscomputer/sandbox-driv
|
|||
# sandbox, so the pebble and sandbox-driver pins move independently. Pebble
|
||||
# pins the same lithos-llm rev as fabro, and its lockfile policy is that
|
||||
# every shared crate resolves to the version lithos-llm locks.
|
||||
pebble-agent = { git = "https://github.com/lithoscomputer/pebble", rev = "a39f43e26effdf99635eaf343f095c17157c9c93" }
|
||||
pebble-coding-agent = { git = "https://github.com/lithoscomputer/pebble", rev = "a39f43e26effdf99635eaf343f095c17157c9c93", features = ["mcp", "search-providers"] }
|
||||
pebble-cli-core = { git = "https://github.com/lithoscomputer/pebble", rev = "a39f43e26effdf99635eaf343f095c17157c9c93" }
|
||||
pebble-agent = { git = "https://github.com/lithoscomputer/pebble", rev = "67c9f486dd28f15c04e8d590a91e6f5563f7605d" }
|
||||
pebble-coding-agent = { git = "https://github.com/lithoscomputer/pebble", rev = "67c9f486dd28f15c04e8d590a91e6f5563f7605d", features = ["mcp", "search-providers"] }
|
||||
pebble-cli-core = { git = "https://github.com/lithoscomputer/pebble", rev = "67c9f486dd28f15c04e8d590a91e6f5563f7605d" }
|
||||
# petri: the workflow engine Fabro runs its workflows on. Pinned by rev, the
|
||||
# same way pebble and sandbox-driver are. Petri pins the same pebble,
|
||||
# lithos-llm and sandbox-driver revisions as this file, so the workspace links
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { TEST_PRINCIPAL, makeUsage } from "../lib/test-fixtures";
|
|||
let currentRunSummary: any = null;
|
||||
let currentRunState: any = null;
|
||||
let currentQuestions: any[] = [];
|
||||
let currentBoardRuns: any[] = [];
|
||||
let deleteRunApiResult: Promise<unknown> | null = null;
|
||||
const mountedRenderers: TestRenderer.ReactTestRenderer[] = [];
|
||||
|
||||
|
|
@ -27,6 +28,12 @@ const deleteRunApiMock = mock((_id: string) =>
|
|||
);
|
||||
const mutateRunListCachesMock = mock((_mutate: unknown) => undefined);
|
||||
const swrMutateMock = mock((_key: unknown) => Promise.resolve(undefined));
|
||||
const questionQueryMock = mock((_runId: string, _enabled: boolean) => ({ data: currentQuestions }));
|
||||
const submitAnswerMock = mock((_answer: unknown) => Promise.resolve(undefined));
|
||||
const submitAnswerHookMock = mock((_runId: string) => ({
|
||||
isMutating: false,
|
||||
trigger: submitAnswerMock,
|
||||
}));
|
||||
|
||||
mock.module("@headlessui/react", () => ({
|
||||
Dialog: ({ open, children }: any) =>
|
||||
|
|
@ -48,6 +55,10 @@ mock.module("@headlessui/react", () => ({
|
|||
}));
|
||||
|
||||
mock.module("../lib/queries", () => ({
|
||||
useAllRuns: () => ({ data: { data: currentBoardRuns }, isLoading: false }),
|
||||
useRunsPage: () => ({ data: null, isLoading: false }),
|
||||
useAuthConfig: () => ({ data: { methods: [] } }),
|
||||
useSystemInfo: () => ({ data: null }),
|
||||
useRun: () => ({
|
||||
data: currentRunSummary,
|
||||
isLoading: false,
|
||||
|
|
@ -56,9 +67,7 @@ mock.module("../lib/queries", () => ({
|
|||
data: null,
|
||||
isLoading: false,
|
||||
}),
|
||||
useRunQuestions: () => ({
|
||||
data: currentQuestions,
|
||||
}),
|
||||
useRunQuestions: questionQueryMock,
|
||||
useRunPullRequest: () => ({
|
||||
data: null,
|
||||
isLoading: false,
|
||||
|
|
@ -79,6 +88,11 @@ mock.module("../lib/run-events", () => ({
|
|||
useRunEvents: () => undefined,
|
||||
}));
|
||||
|
||||
mock.module("../lib/board-events", () => ({
|
||||
shouldRefreshBoardForEvent: () => false,
|
||||
useBoardEvents: () => undefined,
|
||||
}));
|
||||
|
||||
mock.module("../hooks/use-run-toasts", () => ({
|
||||
useRunToasts: () => undefined,
|
||||
}));
|
||||
|
|
@ -168,7 +182,7 @@ mock.module("../lib/mutations", () => ({
|
|||
useInterruptRun: mutationState,
|
||||
usePreviewRun: mutationState,
|
||||
useSteerRun: mutationState,
|
||||
useSubmitInterviewAnswer: mutationState,
|
||||
useSubmitInterviewAnswer: submitAnswerHookMock,
|
||||
useUpdateRunTitle: mutationState,
|
||||
useUnarchiveRun: mutationState,
|
||||
}));
|
||||
|
|
@ -186,6 +200,7 @@ const {
|
|||
default: RunDetail,
|
||||
resolveDockClearance,
|
||||
} = await import("./run-detail");
|
||||
const { default: Runs } = await import("./runs");
|
||||
mock.restore();
|
||||
type LifecycleToastState = import("./run-detail/lifecycle-toasts").LifecycleToastState;
|
||||
type RunDetailActionResult = import("./run-detail/lifecycle-toasts").RunDetailActionResult;
|
||||
|
|
@ -333,7 +348,7 @@ async function renderRunDetailHarness({
|
|||
[
|
||||
{
|
||||
path: "/runs",
|
||||
element: h("div", { "data-route": "runs-index" }, "Runs"),
|
||||
element: h(Runs),
|
||||
},
|
||||
{
|
||||
path: "/runs/:id",
|
||||
|
|
@ -634,6 +649,10 @@ describe("RunDetail full-height child routes", () => {
|
|||
currentRunSummary = null;
|
||||
currentRunState = null;
|
||||
currentQuestions = [];
|
||||
currentBoardRuns = [];
|
||||
questionQueryMock.mockClear();
|
||||
submitAnswerMock.mockClear();
|
||||
submitAnswerHookMock.mockClear();
|
||||
deleteRunApiResult = null;
|
||||
deleteRunApiMock.mockClear();
|
||||
mutateRunListCachesMock.mockClear();
|
||||
|
|
@ -641,6 +660,55 @@ describe("RunDetail full-height child routes", () => {
|
|||
delete (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT;
|
||||
});
|
||||
|
||||
test("Answer Question on a blocked board card opens that run's pending interview", async () => {
|
||||
currentBoardRuns = [
|
||||
{ ...makeRunSummary(), id: "other-run" },
|
||||
makeRunSummary({ status: "blocked" }),
|
||||
];
|
||||
const { renderer, router } = await renderRunDetailHarness({
|
||||
initialEntry: "/runs?view=columns",
|
||||
status: "blocked",
|
||||
questions: [makeQuestion()],
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
findButtonByText(renderer, "Answer Question")!.props.onClick();
|
||||
});
|
||||
|
||||
expect(router.state.location.pathname).toBe("/runs/run_1");
|
||||
expect(questionQueryMock).toHaveBeenCalledWith("run_1", true);
|
||||
const interview = renderer.root.findByProps({ "aria-label": "Interview question" });
|
||||
expect(textFromTestNode(interview)).toContain("Approve?");
|
||||
const answer = interview.findByProps({ "aria-label": "Answer yes" });
|
||||
expect(answer.props.disabled).toBe(false);
|
||||
await act(async () => {
|
||||
answer.props.onClick();
|
||||
});
|
||||
expect(submitAnswerHookMock).toHaveBeenCalledWith("run_1");
|
||||
expect(submitAnswerMock).toHaveBeenCalledWith({ questionId: "q_1", answer: { kind: "yes" } });
|
||||
});
|
||||
|
||||
for (const status of ["blocked", "running"]) {
|
||||
test(`a stale blocked card opens the ${status} run without an already answered question`, async () => {
|
||||
currentBoardRuns = [makeRunSummary({ status: "blocked" })];
|
||||
const { renderer, router } = await renderRunDetailHarness({
|
||||
initialEntry: "/runs?view=columns",
|
||||
status,
|
||||
questions: [],
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
findButtonByText(renderer, "Answer Question")!.props.onClick();
|
||||
});
|
||||
|
||||
expect(router.state.location.pathname).toBe("/runs/run_1");
|
||||
expect(questionQueryMock).toHaveBeenCalledWith("run_1", status === "blocked");
|
||||
expect(textFromNode(renderer.toJSON())).toContain("Overview");
|
||||
expect(renderer.root.findAllByProps({ "aria-label": "Interview question" })).toHaveLength(0);
|
||||
expect(submitAnswerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
|
||||
test("uses a full-height flex wrapper for fullHeight child routes", async () => {
|
||||
const renderer = await renderRunDetail({
|
||||
initialEntry: "/runs/run_1/files",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useCallback, useMemo, useRef } from "react";
|
||||
import { Link, Navigate } from "react-router";
|
||||
import { Link, Navigate, useNavigate } from "react-router";
|
||||
import { CheckIcon, ChevronDownIcon, CommandLineIcon } from "@heroicons/react/24/outline";
|
||||
import { EllipsisVerticalIcon } from "@heroicons/react/20/solid";
|
||||
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
||||
|
|
@ -360,6 +360,7 @@ function PrCard({
|
|||
// piece as a sibling `<div>` below the card body recreates a recurring bug
|
||||
// where stats stack onto separate lines instead of sitting next to size/actions.
|
||||
function PrCardFooter({ pr, actions }: { pr: RunItem; actions?: string[] }) {
|
||||
const navigate = useNavigate();
|
||||
const hasActions = actions != null && actions.length > 0;
|
||||
const hasStats =
|
||||
pr.resources != null ||
|
||||
|
|
@ -399,6 +400,7 @@ function PrCardFooter({ pr, actions }: { pr: RunItem; actions?: string[] }) {
|
|||
key={label}
|
||||
type="button"
|
||||
disabled={pr.actionDisabled}
|
||||
onClick={label === "Answer Question" ? () => navigate(`/runs/${pr.id}`) : undefined}
|
||||
className={`inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-[11px] font-medium transition-colors disabled:cursor-not-allowed disabled:text-fg-muted disabled:border-line ${
|
||||
label === "Merge"
|
||||
? "border-mint/20 text-mint hover:border-mint/50 hover:text-fg"
|
||||
|
|
|
|||
|
|
@ -8657,8 +8657,8 @@ components:
|
|||
example: "Anthropic"
|
||||
adapter:
|
||||
type: string
|
||||
description: "lithos adapter id the provider speaks, such as `anthropic`, `openai`, `gemini`, or `openai-compatible`."
|
||||
example: "anthropic"
|
||||
description: "lithos adapter id the provider uses: `http` or `bedrock`, or a custom adapter's id."
|
||||
example: "http"
|
||||
base_url:
|
||||
type: string
|
||||
description: Effective API base URL, including any operator override.
|
||||
|
|
|
|||
|
|
@ -80,13 +80,11 @@ Claude Fable 5 is available as an explicit model but is not the default Anthropi
|
|||
|
||||
Fabro's catalog is the [lithos-llm](https://docs.rs/lithos-llm) built-in catalog. The `[llm]` table in settings is a second layer over it: a lithos catalog overlay that adds providers and models or changes existing entries. Later layers win. Tables merge key by key and every other value replaces. Models are nested under their provider, so two providers can expose the same model id without overwriting each other.
|
||||
|
||||
Provider and model facts use lithos field names: `adapter`, `codec`, `base_url`, `auth`, `enabled`, `limits`, `capabilities`, `pricing`, `small_default`, `probe`, `family`, and the cutoffs. The coding harness a model expects lives under `metadata.agent`, a namespace lithos ships and other agents such as Pebble read too. See [Settings Configuration](/reference/user-configuration#llm) for every key.
|
||||
Provider and model facts use lithos field names: `adapter`, `codecs`, `base_url`, `auth`, `enabled`, `limits`, `capabilities`, `pricing`, `small_default`, `probe`, `family`, and the cutoffs. The coding harness a model expects lives under `metadata.agent`, a namespace lithos ships and other agents such as Pebble read too. See [Settings Configuration](/reference/user-configuration#llm) for every key.
|
||||
|
||||
```toml title="settings.toml"
|
||||
[llm.providers.proxy]
|
||||
display_name = "Acme Gateway"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://llm-gateway.example.com/v1"
|
||||
auth = { type = "bearer" }
|
||||
aliases = ["gateway"]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ title: "Fireworks AI"
|
|||
description: "Run open-weights models on Fireworks AI's serverless inference platform"
|
||||
---
|
||||
|
||||
[Fireworks AI](https://fireworks.ai/) serves open-weights models (Kimi, DeepSeek, GLM, Qwen, GPT-OSS, and more) behind an OpenAI-compatible API. Fabro ships a disabled `fireworks` provider entry with a curated model catalog, so you can opt in from `settings.toml` without changing Fabro code.
|
||||
[Fireworks AI](https://fireworks.ai/) serves open-weights models (Kimi, DeepSeek, GLM, Qwen, GPT-OSS, and more) behind an OpenAI-compatible API. Fabro ships an enabled `fireworks` provider entry with a curated model catalog; it needs only an API key, and `settings.toml` can adjust it without changing Fabro code.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ title: "OpenRouter"
|
|||
description: "Route Fabro models through OpenRouter's multi-provider gateway"
|
||||
---
|
||||
|
||||
[OpenRouter](https://openrouter.ai/) is an aggregator that fronts hundreds of models behind one OpenAI-compatible API. Fabro ships a disabled `openrouter` provider entry with a curated model catalog, so you can opt in from `settings.toml` without changing Fabro code.
|
||||
[OpenRouter](https://openrouter.ai/) is an aggregator that fronts hundreds of models behind one OpenAI-compatible API. Fabro ships an enabled `openrouter` provider entry with a curated model catalog; it needs only an API key, and `settings.toml` can adjust it without changing Fabro code.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ fabro [OPTIONS] [COMMAND]
|
|||
|
||||
| Command | Description |
|
||||
| --- | --- |
|
||||
| `fabro approve` | Approve pending workflow runs |
|
||||
| `fabro approve` | Approve a pending run for execution |
|
||||
| `fabro archive` | Mark terminal runs as archived (reviewed, no further action needed). Archived runs are hidden from default listings |
|
||||
| `fabro artifact` | Inspect and copy run artifacts (screenshots, reports, traces) |
|
||||
| `fabro ask` | Ask Fabro a read-only question about a run |
|
||||
|
|
@ -71,7 +71,7 @@ fabro [OPTIONS] [COMMAND]
|
|||
| `fabro auth` | Manage CLI authentication state |
|
||||
| `fabro completion` | Generate shell completions |
|
||||
| `fabro create` | Register a workflow version and create a submitted run |
|
||||
| `fabro deny` | Deny pending workflow runs |
|
||||
| `fabro deny` | Deny execution of a pending run |
|
||||
| `fabro discord` | Open the Discord community in the browser |
|
||||
| `fabro docs` | Open the docs website in the browser |
|
||||
| `fabro doctor` | Check environment and integration health |
|
||||
|
|
@ -113,7 +113,7 @@ fabro [OPTIONS] [COMMAND]
|
|||
|
||||
### `fabro approve`
|
||||
|
||||
Approve pending workflow runs
|
||||
Approve a pending run for execution
|
||||
|
||||
```bash
|
||||
fabro approve [OPTIONS] <RUNS>...
|
||||
|
|
@ -373,7 +373,7 @@ fabro create [OPTIONS] <WORKFLOW>
|
|||
|
||||
### `fabro deny`
|
||||
|
||||
Deny pending workflow runs
|
||||
Deny execution of a pending run
|
||||
|
||||
```bash
|
||||
fabro deny [OPTIONS] <RUNS>...
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ let result = client.complete_with_context(request, context).await;
|
|||
|
||||
### Provider adapters
|
||||
|
||||
Providers are lithos adapters selected by the catalog `adapter` id: `anthropic`, `openai`, `gemini`, `openai-compatible`, and `bedrock`. A new OpenAI-compatible endpoint needs a catalog entry, not code.
|
||||
A provider names one lithos adapter in `adapter` (`http`, the default, or `bedrock`) and lists the wire codecs its host speaks in `codecs` (`openai-chat`, the default, `openai-responses`, `anthropic-messages`, `gemini-generate`, or `bedrock-converse`). A new OpenAI-compatible endpoint needs a catalog entry, not code.
|
||||
|
||||
To add a custom transport, implement the lithos `ProviderAdapter` trait and register it with `ClientOptions::with_adapter`. `fabro_llm::gateway::GatewayAdapter` is Fabro's own example: it posts each request to a Fabro server's completions endpoint, which returns lithos `Response` JSON and streams lithos `StreamEvent` JSON verbatim.
|
||||
|
||||
|
|
|
|||
|
|
@ -89,8 +89,6 @@ level = "info"
|
|||
|
||||
[llm.providers.proxy]
|
||||
display_name = "Acme Gateway"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://llm-gateway.example.com/v1"
|
||||
auth = { type = "bearer" }
|
||||
aliases = ["gateway"]
|
||||
|
|
@ -154,8 +152,6 @@ Several built-in providers ship with `enabled = false`. Turn one on by setting
|
|||
```toml title="settings.toml"
|
||||
[llm.providers.proxy]
|
||||
display_name = "Acme Gateway"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://llm-gateway.example.com/v1"
|
||||
auth = { type = "bearer" }
|
||||
priority = 50
|
||||
|
|
@ -195,11 +191,11 @@ Define or override an LLM provider. The keys are the lithos provider record.
|
|||
| Key | Type / values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `display_name` | string | required for new providers | Human-readable provider name. |
|
||||
| `adapter` | string | required for new providers | lithos adapter id: `anthropic`, `openai`, `gemini`, `openai-compatible`, or `bedrock`. |
|
||||
| `codec` | string | required for new providers | Wire codec: `anthropic-messages`, `openai-responses`, `openai-chat`, `gemini-generate`, or `bedrock-converse`. |
|
||||
| `base_url` | string | required for new providers | Provider API base URL. The `openai-compatible` adapter appends `/v1/chat/completions` unless the URL already ends in a version segment. |
|
||||
| `adapter` | string | `"http"` | lithos adapter id: `http` or `bedrock`. Any other id names a custom adapter the application registered. |
|
||||
| `codecs` | array<string> | `["openai-chat"]` | Wire codecs the host speaks, in preference order: `openai-chat`, `openai-responses`, `anthropic-messages`, `gemini-generate`, or `bedrock-converse`. A Chat Completions host needs no line. |
|
||||
| `base_url` | string | required for new providers | Provider API base URL. The `openai-chat` codec appends `/v1/chat/completions` unless the URL already ends in a version segment. |
|
||||
| `auth` | table | required for new providers | Auth scheme: `{ type = "bearer" }`, `{ type = "header", name = "x-api-key" }`, `{ type = "headers" }`, `{ type = "none" }`, or `{ type = "aws" }`. |
|
||||
| `enabled` | boolean | `true` | Set `false` to hide a provider from Fabro. `bedrock`, `bedrock-openai`, `fireworks`, `litellm`, `modal`, `ollama`, and `openrouter` ship disabled. |
|
||||
| `enabled` | boolean | `true` | Set `false` to hide a provider from Fabro. `bedrock`, `bedrock-openai`, `litellm`, `modal`, and `ollama` ship disabled. |
|
||||
| `priority` | integer | `0` | Higher-priority ready providers win unqualified model and default selection. |
|
||||
| `aliases` | array<string> | `[]` | Additional provider names accepted by model routing and fallback config. |
|
||||
| `default_model` | string | None | The provider's default model id. |
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@ approve -> skip [label="[S] Skip"]
|
|||
|
||||
When execution reaches the gate, the user sees the previous stage's output followed by the node's label ("Approve Plan") and the available options. In the CLI, this appears as an interactive menu. In the web UI, blocked runs show an interview dock on the run page where the user can answer the pending question.
|
||||
|
||||
<Note>
|
||||
`fabro approve` and `fabro deny` grant or deny permission to **start a run** waiting
|
||||
for execution approval. To answer a human gate during execution, run
|
||||
`fabro attach <run>` for an interactive prompt or use the run page's interview dock.
|
||||
API clients can list pending questions with `GET /api/v1/runs/{id}/questions` and
|
||||
answer a specific question with `POST /api/v1/runs/{id}/questions/{qid}/answer`.
|
||||
</Note>
|
||||
|
||||
### Keyboard accelerators
|
||||
|
||||
The prefixes `[A]`, `[R]`, `[S]` in edge labels serve as keyboard accelerators. Fabro supports three formats:
|
||||
|
|
|
|||
|
|
@ -1395,9 +1395,9 @@ pub(crate) enum RunsCommands {
|
|||
Rm(RunsRemoveArgs),
|
||||
/// Show detailed information about a workflow run
|
||||
Inspect(InspectArgs),
|
||||
/// Approve pending workflow runs.
|
||||
/// Approve a pending run for execution.
|
||||
Approve(RunsApproveArgs),
|
||||
/// Deny pending workflow runs.
|
||||
/// Deny execution of a pending run.
|
||||
Deny(RunsDenyArgs),
|
||||
/// Mark terminal runs as archived (reviewed, no further action needed).
|
||||
/// Archived runs are hidden from default listings.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fn help() {
|
|||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
Approve pending workflow runs
|
||||
Approve a pending run for execution
|
||||
|
||||
Usage: fabro approve [OPTIONS] <RUNS>...
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fn help() {
|
|||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
Deny pending workflow runs
|
||||
Deny execution of a pending run
|
||||
|
||||
Usage: fabro deny [OPTIONS] <RUNS>...
|
||||
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ fn exec_accepts_configured_custom_provider_from_settings() {
|
|||
let context = test_context!();
|
||||
context.write_home(
|
||||
".fabro/settings.toml",
|
||||
"_version = 1\n\n[llm.providers.acme-aws]\ndisplay_name = \"Acme AWS\"\nadapter = \"openai-compatible\"\ncodec = \"openai-chat\"\nbase_url = \"https://bedrock.example.invalid/v1\"\nauth = { type = \"bearer\" }\nallow_passthrough = true\n\n[llm.providers.acme-aws.metadata.agent]\nprofile = \"openai\"\n\n[cli.exec.model]\nprovider = \"acme-aws\"\nname = \"acme-claude-sonnet-4-6\"\n",
|
||||
"_version = 1\n\n[llm.providers.acme-aws]\ndisplay_name = \"Acme AWS\"\nbase_url = \"https://bedrock.example.invalid/v1\"\nauth = { type = \"bearer\" }\nallow_passthrough = true\n\n[llm.providers.acme-aws.metadata.agent]\nprofile = \"openai\"\n\n[cli.exec.model]\nprovider = \"acme-aws\"\nname = \"acme-claude-sonnet-4-6\"\n",
|
||||
);
|
||||
|
||||
let mut cmd = context.exec_cmd();
|
||||
|
|
@ -398,7 +398,7 @@ fn exec_server_target_accepts_configured_custom_provider_from_settings() {
|
|||
let context = test_context!();
|
||||
context.write_home(
|
||||
".fabro/settings.toml",
|
||||
"_version = 1\n\n[llm.providers.acme-aws]\ndisplay_name = \"Acme AWS\"\nadapter = \"openai-compatible\"\ncodec = \"openai-chat\"\nbase_url = \"https://bedrock.example.invalid/v1\"\nauth = { type = \"bearer\" }\nallow_passthrough = true\n\n[llm.providers.acme-aws.metadata.agent]\nprofile = \"openai\"\n\n[cli.exec.model]\nprovider = \"acme-aws\"\nname = \"acme-claude-sonnet-4-6\"\n",
|
||||
"_version = 1\n\n[llm.providers.acme-aws]\ndisplay_name = \"Acme AWS\"\nbase_url = \"https://bedrock.example.invalid/v1\"\nauth = { type = \"bearer\" }\nallow_passthrough = true\n\n[llm.providers.acme-aws.metadata.agent]\nprofile = \"openai\"\n\n[cli.exec.model]\nprovider = \"acme-aws\"\nname = \"acme-claude-sonnet-4-6\"\n",
|
||||
);
|
||||
let server = MockServer::start();
|
||||
server.mock(|when, then| {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ fn help() {
|
|||
dump Export a run's durable state to a directory
|
||||
rm Remove one or more workflow runs
|
||||
inspect Show detailed information about a workflow run
|
||||
approve Approve pending workflow runs
|
||||
deny Deny pending workflow runs
|
||||
approve Approve a pending run for execution
|
||||
deny Deny execution of a pending run
|
||||
archive Mark terminal runs as archived (reviewed, no further action needed). Archived runs are hidden from default listings
|
||||
unarchive Restore archived runs to their prior terminal status
|
||||
model List and test LLM models
|
||||
|
|
|
|||
|
|
@ -2991,8 +2991,6 @@ digraph Demo {
|
|||
r#"
|
||||
[providers.acme]
|
||||
display_name = "Acme"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://api.acme.test/v1"
|
||||
auth = { type = "bearer" }
|
||||
default_model = "acme-large"
|
||||
|
|
|
|||
|
|
@ -1459,8 +1459,8 @@ mod tests {
|
|||
}
|
||||
|
||||
/// OpenAI and OpenRouter both offer `gpt-5.6-sol` under the `gpt-56-sol`
|
||||
/// alias; OpenRouter ships disabled, so enable it the way an operator
|
||||
/// would.
|
||||
/// alias; both ship enabled, and the overlay makes it the default on
|
||||
/// each.
|
||||
fn portable_session_catalog() -> Catalog {
|
||||
fabro_llm::test_support::test_catalog_with_overlay(
|
||||
r#"
|
||||
|
|
|
|||
|
|
@ -322,8 +322,6 @@ fn acme_overlay(base_url: &str) -> String {
|
|||
r#"
|
||||
[providers.acme]
|
||||
display_name = "Acme"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = {base_url}
|
||||
auth = {{ type = "bearer" }}
|
||||
priority = 120
|
||||
|
|
@ -5268,8 +5266,6 @@ async fn model_api_keeps_duplicate_ids_provider_scoped_and_selects_ready_priorit
|
|||
r#"
|
||||
[providers.direct]
|
||||
display_name = "Direct"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = {direct}
|
||||
auth = {{ type = "bearer" }}
|
||||
priority = 120
|
||||
|
|
@ -5287,8 +5283,6 @@ capabilities = {{ text = true }}
|
|||
|
||||
[providers.aggregator]
|
||||
display_name = "Aggregator"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = {aggregator}
|
||||
auth = {{ type = "bearer" }}
|
||||
priority = 110
|
||||
|
|
@ -5451,8 +5445,6 @@ async fn test_model_forwards_and_validates_reasoning_effort() {
|
|||
r#"
|
||||
[providers.acme]
|
||||
display_name = "Acme"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = {base_url}
|
||||
auth = {{ type = "bearer" }}
|
||||
priority = 120
|
||||
|
|
@ -6003,8 +5995,8 @@ async fn test_providers_registration_issue_returns_error_without_probe() {
|
|||
// An adapter lithos does not ship cannot be built, so the provider is
|
||||
// configured (it has a vault key) yet unavailable.
|
||||
let overlay = acme_overlay("https://api.acme.test/v1").replace(
|
||||
"adapter = \"openai-compatible\"",
|
||||
"adapter = \"not-an-adapter\"",
|
||||
"display_name = \"Acme\"",
|
||||
"display_name = \"Acme\"\nadapter = \"not-an-adapter\"",
|
||||
);
|
||||
let state = TestAppStateBuilder::new()
|
||||
.runtime_settings(default_test_server_settings(), RunLayer::default())
|
||||
|
|
@ -6077,8 +6069,7 @@ async fn test_providers_mixed_results_preserve_catalog_order_and_counts() {
|
|||
r#"
|
||||
[providers.zeta]
|
||||
display_name = "Zeta"
|
||||
adapter = "openai"
|
||||
codec = "openai-responses"
|
||||
codecs = ["openai-responses"]
|
||||
base_url = {base_url}
|
||||
auth = {{ type = "bearer" }}
|
||||
priority = 50
|
||||
|
|
@ -6093,8 +6084,7 @@ probe = true
|
|||
|
||||
[providers.alpha]
|
||||
display_name = "Alpha"
|
||||
adapter = "openai"
|
||||
codec = "openai-responses"
|
||||
codecs = ["openai-responses"]
|
||||
base_url = {base_url}
|
||||
auth = {{ type = "bearer" }}
|
||||
priority = 40
|
||||
|
|
|
|||
|
|
@ -72,16 +72,31 @@ async fn paginated_endpoints_return_correct_shape() {
|
|||
let app = fabro_server::test_support::build_test_router(state);
|
||||
|
||||
for ep in ENDPOINTS {
|
||||
// Large limit: paginated shape, has_more = false (all fixture items fit).
|
||||
// Using an explicit large limit instead of the server default so the test
|
||||
// stays robust when datasets (e.g. the built-in model catalog) grow.
|
||||
let json = get_json(app.clone(), &format!("{}?page[limit]=100", ep.path)).await;
|
||||
assert_paginated_shape(&json, ep.name);
|
||||
assert_eq!(
|
||||
json["meta"]["has_more"], false,
|
||||
"{}: large limit should have has_more=false",
|
||||
ep.name
|
||||
);
|
||||
// Walk the collection at the largest page the API allows: every page
|
||||
// has the paginated shape, and the last one reports has_more = false.
|
||||
// The built-in model catalog is larger than one page, so the walk
|
||||
// follows `page[offset]` rather than assuming one page fits.
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let json = get_json(
|
||||
app.clone(),
|
||||
&format!("{}?page[limit]=100&page[offset]={offset}", ep.path),
|
||||
)
|
||||
.await;
|
||||
assert_paginated_shape(&json, &format!("{} offset={offset}", ep.name));
|
||||
let page_len = json["data"].as_array().unwrap().len();
|
||||
assert!(page_len <= 100, "{}: page exceeded the limit", ep.name);
|
||||
if json["meta"]["has_more"] == false {
|
||||
break;
|
||||
}
|
||||
assert!(
|
||||
page_len == 100,
|
||||
"{}: has_more=true on a page shorter than the limit",
|
||||
ep.name
|
||||
);
|
||||
offset += page_len;
|
||||
assert!(offset < 10_000, "{}: has_more never turned false", ep.name);
|
||||
}
|
||||
|
||||
// limit=1: at most 1 item, has_more = true (all fixtures have >1 item)
|
||||
let json = get_json(app.clone(), &format!("{}?page[limit]=1", ep.path)).await;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ fabro-redact.workspace = true
|
|||
fabro-static.workspace = true
|
||||
fabro-types = { path = "../../foundation/fabro-types" }
|
||||
futures.workspace = true
|
||||
lithos-llm = { workspace = true, features = ["builtin-catalog", "openai", "anthropic", "gemini", "openai-compatible", "bedrock", "bedrock-aws", "local-files"] }
|
||||
lithos-llm = { workspace = true, features = ["builtin-catalog", "bedrock", "bedrock-aws", "local-files"] }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
strum.workspace = true
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ use fabro_static::EnvVars;
|
|||
use fabro_types::AgentProfileKind;
|
||||
pub use lithos_llm::catalog::Offering;
|
||||
use lithos_llm::catalog::{
|
||||
Catalog, CatalogBuilder, CatalogError, CatalogModel, CatalogProvider, Metadata,
|
||||
Catalog, CatalogBuilder, CatalogError, CatalogModel, CatalogProvider, CodecId, Metadata,
|
||||
adapter_ids, codec_ids,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
|
|
@ -101,11 +102,16 @@ fn implied_agent_profiles(catalog: &Catalog) -> String {
|
|||
}
|
||||
|
||||
/// The profile a provider's wire protocol implies, for a provider whose
|
||||
/// catalog entry does not name one.
|
||||
/// catalog entry does not name one. The protocol is the provider's first
|
||||
/// codec, the one the client sends a generation call on; the `bedrock`
|
||||
/// adapter speaks Converse to Anthropic-shaped models.
|
||||
fn adapter_agent_profile(provider: &CatalogProvider) -> AgentProfileKind {
|
||||
match provider.adapter().as_str() {
|
||||
"anthropic" | "bedrock" => AgentProfileKind::Anthropic,
|
||||
"gemini" => AgentProfileKind::Gemini,
|
||||
if provider.adapter().as_str() == adapter_ids::BEDROCK {
|
||||
return AgentProfileKind::Anthropic;
|
||||
}
|
||||
match provider.codecs().first().map(CodecId::as_str) {
|
||||
Some(codec_ids::ANTHROPIC_MESSAGES) => AgentProfileKind::Anthropic,
|
||||
Some(codec_ids::GEMINI_GENERATE) => AgentProfileKind::Gemini,
|
||||
_ => AgentProfileKind::OpenAi,
|
||||
}
|
||||
}
|
||||
|
|
@ -241,7 +247,7 @@ enabled = false
|
|||
Some(AgentProfileKind::OpenAi)
|
||||
);
|
||||
assert_eq!(
|
||||
agent_profile(&catalog, "openrouter", None),
|
||||
agent_profile(&catalog, "bedrock-openai", None),
|
||||
None,
|
||||
"disabled providers have no profile to offer"
|
||||
);
|
||||
|
|
@ -282,8 +288,6 @@ enabled = false
|
|||
r#"
|
||||
[providers.acme]
|
||||
display_name = "Acme"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://api.acme.test/v1"
|
||||
auth = { type = "bearer" }
|
||||
default_model = "acme-llama"
|
||||
|
|
@ -308,4 +312,27 @@ capabilities = { text = true, tools = true }
|
|||
Some(AgentProfileKind::OpenAi)
|
||||
);
|
||||
}
|
||||
|
||||
/// The implied profile follows the provider's first codec, so a host that
|
||||
/// speaks Anthropic Messages gets the Anthropic harness.
|
||||
#[test]
|
||||
fn the_implied_profile_follows_the_first_codec() {
|
||||
let overlay = LlmLayer(
|
||||
toml::from_str(
|
||||
r#"
|
||||
[providers.acme]
|
||||
display_name = "Acme"
|
||||
codecs = ["anthropic-messages"]
|
||||
base_url = "https://api.acme.test"
|
||||
auth = { type = "header", name = "x-api-key" }
|
||||
"#,
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
let catalog = build_catalog(&overlay, &|_| None).unwrap();
|
||||
assert_eq!(
|
||||
agent_profile(&catalog, "acme", None),
|
||||
Some(AgentProfileKind::Anthropic)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,12 +407,12 @@ mod tests {
|
|||
fn disabled_providers_are_not_selectable() {
|
||||
let catalog = test_catalog();
|
||||
assert!(matches!(
|
||||
select(&catalog, "gpt-5.4", None, &eligible(&["openrouter"])),
|
||||
select(&catalog, "gpt-5.4", None, &eligible(&["bedrock-openai"])),
|
||||
Err(ModelSelectionError::NoEligibleOffering { .. })
|
||||
));
|
||||
let enabled = test_catalog_with_overlay("[providers.openrouter]\nenabled = true\n");
|
||||
let entry = select(&enabled, "gpt-5.4", None, &eligible(&["openrouter"])).unwrap();
|
||||
assert_eq!(entry.provider.id(), &ProviderId::new("openrouter"));
|
||||
let enabled = test_catalog_with_overlay("[providers.bedrock-openai]\nenabled = true\n");
|
||||
let entry = select(&enabled, "gpt-5.4", None, &eligible(&["bedrock-openai"])).unwrap();
|
||||
assert_eq!(entry.provider.id(), &ProviderId::new("bedrock-openai"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -748,8 +748,6 @@ mod tests {
|
|||
r#"
|
||||
[providers.mock]
|
||||
display_name = "Mock"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "http://mock.invalid/v1"
|
||||
auth = { type = "bearer" }
|
||||
allow_passthrough = true
|
||||
|
|
|
|||
|
|
@ -383,8 +383,6 @@ mod tests {
|
|||
r#"
|
||||
[providers.gateway]
|
||||
display_name = "Gateway"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://gateway.test/v1"
|
||||
auth = { type = "bearer" }
|
||||
default_headers = { "x-portkey-api-key" = "{{ secrets.PORTKEY_API_KEY }}", "x-portkey-config" = "@prod" }
|
||||
|
|
|
|||
|
|
@ -690,8 +690,6 @@ methods = ["dev-token"]
|
|||
|
||||
[llm.providers.acme]
|
||||
display_name = "Acme"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://api.acme.test/v1"
|
||||
auth = { type = "bearer" }
|
||||
enabled = true
|
||||
|
|
|
|||
|
|
@ -229,8 +229,6 @@ Several built-in providers ship with `enabled = false`. Turn one on by setting
|
|||
```toml title="settings.toml"
|
||||
[llm.providers.proxy]
|
||||
display_name = "Acme Gateway"
|
||||
adapter = "openai-compatible"
|
||||
codec = "openai-chat"
|
||||
base_url = "https://llm-gateway.example.com/v1"
|
||||
auth = { type = "bearer" }
|
||||
priority = 50
|
||||
|
|
@ -270,11 +268,11 @@ Define or override an LLM provider. The keys are the lithos provider record.
|
|||
| Key | Type / values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `display_name` | string | required for new providers | Human-readable provider name. |
|
||||
| `adapter` | string | required for new providers | lithos adapter id: `anthropic`, `openai`, `gemini`, `openai-compatible`, or `bedrock`. |
|
||||
| `codec` | string | required for new providers | Wire codec: `anthropic-messages`, `openai-responses`, `openai-chat`, `gemini-generate`, or `bedrock-converse`. |
|
||||
| `base_url` | string | required for new providers | Provider API base URL. The `openai-compatible` adapter appends `/v1/chat/completions` unless the URL already ends in a version segment. |
|
||||
| `adapter` | string | `"http"` | lithos adapter id: `http` or `bedrock`. Any other id names a custom adapter the application registered. |
|
||||
| `codecs` | array<string> | `["openai-chat"]` | Wire codecs the host speaks, in preference order: `openai-chat`, `openai-responses`, `anthropic-messages`, `gemini-generate`, or `bedrock-converse`. A Chat Completions host needs no line. |
|
||||
| `base_url` | string | required for new providers | Provider API base URL. The `openai-chat` codec appends `/v1/chat/completions` unless the URL already ends in a version segment. |
|
||||
| `auth` | table | required for new providers | Auth scheme: `{ type = "bearer" }`, `{ type = "header", name = "x-api-key" }`, `{ type = "headers" }`, `{ type = "none" }`, or `{ type = "aws" }`. |
|
||||
| `enabled` | boolean | `true` | Set `false` to hide a provider from Fabro. `bedrock`, `bedrock-openai`, `fireworks`, `litellm`, `modal`, `ollama`, and `openrouter` ship disabled. |
|
||||
| `enabled` | boolean | `true` | Set `false` to hide a provider from Fabro. `bedrock`, `bedrock-openai`, `litellm`, `modal`, and `ollama` ship disabled. |
|
||||
| `priority` | integer | `0` | Higher-priority ready providers win unqualified model and default selection. |
|
||||
| `aliases` | array<string> | `[]` | Additional provider names accepted by model routing and fallback config. |
|
||||
| `default_model` | string | None | The provider's default model id. |
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ pub struct Model {
|
|||
pub struct Provider {
|
||||
pub id: ProviderId,
|
||||
pub display_name: String,
|
||||
/// lithos adapter id, such as `openai` or `openai-compatible`.
|
||||
/// lithos adapter id: `http` or `bedrock`, or a custom adapter's id.
|
||||
pub adapter: String,
|
||||
pub base_url: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export interface Provider {
|
|||
*/
|
||||
'display_name': string;
|
||||
/**
|
||||
* lithos adapter id the provider speaks, such as `anthropic`, `openai`, `gemini`, or `openai-compatible`.
|
||||
* lithos adapter id the provider uses: `http` or `bedrock`, or a custom adapter's id.
|
||||
*/
|
||||
'adapter': string;
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue