Drop-in from fai/platform .forgejo/workflow-templates/
sign-bundle-keypair.yml. Triggers on v*.*.* tag push: builds
wasm32-wasip2, fetches the fai CLI from get.fai.flemming.ai,
packs the bundle, ECDSA P-256 signs it against the org-level
Forgejo secret FAI_SIGNING_KEY, round-trip-verifies against
infra/cosign/official.pub on fai/platform main, and attaches
bundle + .sig to the Forgejo Release via the API.
Signed-off-by: flemming-it <sf@flemming.it>
Brings module.yaml in line with F∆I 0.12.0's capability naming
convention. The legacy schema_version 1 (with implicit provider)
still loads in 0.12.0 via the grace-period default, but this
bump makes the publisher identity explicit and unblocks
storage-layout migration via 'fai migrate'.
See fai/platform docs/reference/capability-namespaces.yaml +
docs/operations/migration-to-0.12.md.
Signed-off-by: flemming-it <sf@flemming.it>
The fai-module-sdk repo was renamed from `fai/module-sdk` to
`fai/module-sdk-rust` to align with the three SDK families
convention (base + language suffix). Pin updated accordingly.
The old git.flemming.ws URL is also retired in this pass.
Signed-off-by: flemming-it <sf@flemming.it>
The previous workflow was a copy of the pre-SDK template — it
did the own-repo checkout but had no provision for fetching
fai-module-sdk from git.flemming.ws/fai/module-sdk. After the
v0.3.0 SDK migration, every CI run failed at the cargo fetch
stage because the runner had no credential for the cross-org
private repo.
Adopt the same pattern that text-extract and llm-chat already
use: a MODULE_SDK_PAT actions secret, CARGO_NET_GIT_FETCH_WITH_CLI=true,
and a 'git config url.X.insteadOf Y' that injects the token
into any outgoing git.flemming.ws URL transparently.
Bumps the module to 0.3.2 (patch — CI infrastructure only,
behaviour unchanged).
Signed-off-by: flemming-it <sf@flemming.it>
Closes Compliance Gap 1 from fai/platform :: docs/advanced/
compliance-gaps.md. The module now probes the LLM endpoint's
/api/show on every successful chat invocation and surfaces
the model's SHA-256 digest as a separate output field.
The probe is strictly best-effort:
- derive_show_url returns None unless the configured endpoint
ends in /api/chat, so non-Ollama deployments (OpenAI,
Anthropic) skip the probe entirely.
- probe_model_digest swallows every failure path (network
error, non-200 status, malformed JSON, missing digest field)
and yields None. The plan generation succeeds either way.
- extract_show_digest looks for digest at top level, then
details.digest, then model_info.digest — the fields shift
across Ollama versions, so the lookup is tolerant.
A new generate_plan_with_identity returns a PlanWithIdentity
struct ({plan_json, model_digest}). The original generate_plan
remains as a #[allow(dead_code)] convenience wrapper that
returns just the plan JSON.
The invoke entry point in lib.rs now emits four outputs:
plan (json) — unchanged
model_endpoint (text) — unchanged
model_name (text) — unchanged
model_digest (text) — NEW; empty for non-Ollama or stub paths
module.yaml documents the new output and bumps the orchestrator
capability version to 0.3.0 (additive minor; downstream flows
that referenced @^0 keep working).
Eight new tests in src/llm.rs cover the new code paths:
- URL transform (/api/chat → /api/show)
- URL transform skipped for non-Ollama endpoints
- Digest extraction at all three documented JSON locations
- Digest extraction graceful failure (missing, empty, bad JSON)
- End-to-end probe success
- End-to-end probe skipped for non-Ollama
- End-to-end probe failure swallowed without breaking plan
Total tests: 26 (was 18). Wasm artifact builds with v1.0
imports baked in. Platform-side integration tests in
fai/platform :: orchestrator_llm_path.rs pass against the
new module unchanged.
Bumps the module to 0.3.1 (patch — output schema additively
extended, behaviour unchanged for existing flows).
Signed-off-by: flemming-it <sf@flemming.it>
The module now uses the #[fai_module] macro from
fai-module-sdk v0.1.2. The behavior is unchanged from v0.2.1 —
deterministic stub when llm_endpoint is empty, real Ollama-shaped
HTTP otherwise. The migration drops:
- The hand-written wit_bindgen::generate! invocation
- The exports::fai::platform::invoke::Guest impl boilerplate
- The unsafe_op_in_unsafe_fn allow workaround
- The manual export!() macro call
- The text_input helper that matched Payload variants by hand
- The wit/ directory mirror of the platform's frozen WIT
In their place, the module body is one annotated function:
#[fai_module]
pub fn invoke(_ctx: Context, inputs: Inputs)
-> Result<Outputs, ModuleError>
{ ... }
Compared with v0.2.1, lib.rs lost ~70 lines of WASM plumbing.
The SDK macro emits the WIT glue only on target_arch = wasm32
so the host build now compiles cleanly without a manual gate.
That removed two #[cfg(target_arch = wasm32)] blocks in the
process.
The Cargo.toml dep on wit-bindgen is replaced by a single git
dep on fai-module-sdk (branch=main, transitively pinning v0.1.2).
The macros crate comes through transitively. waki stays as a
target-gated dep — the SDK does not (yet) abstract HTTP.
Output payload extends the v0.2.1 schema additively: alongside
the existing 'plan' (JSON Plan), the module now emits
'model_endpoint' and 'model_name' so consumers (and audit logs)
can identify which LLM produced which plan. Existing flows that
only consume 'plan' are unaffected.
Wasm artifact verified to build with v1.0 imports. Platform-side
integration tests in fai/platform :: orchestrator_llm_path.rs
and orchestrator_module.rs pass against the migrated wasm with
no platform-side changes. Total platform suite: 151 green.
The wit/ directory is removed because the SDK ships the WIT
inline via include_str! at proc-macro compile time. Module repos
no longer maintain their own mirror copy.
Bumps the module to 0.3.0 (minor — output schema additively
extended).
Signed-off-by: flemming-it <sf@flemming.it>
The platform repo froze its WIT contract at v1.0 and a
matching update is required here so the orchestrator-llm
component links against the same package version the hub
provides at runtime.
The wit/world.wit copy in this repo is a byte-for-byte
mirror of fai/platform :: wit/world.wit. Once the planned
fai-module-sdk crate ships, the mirror disappears — modules
will pull WIT bindings transitively through the SDK.
Bumps the module patch version 0.2.0 -> 0.2.1.
Signed-off-by: flemming-it <sf@flemming.it>
The dead-code lint Stefan flagged was a real signal — pretending
otherwise with #[allow(dead_code)] would have hidden a future
genuinely-dead helper. Two structural changes:
1. Gate `mod llm;` in lib.rs to `cfg(any(target_arch = "wasm32",
test))`. The LLM client only has callers on wasm32 (WakiClient)
and in the host test harness; on a host non-test build the
module is genuinely unreachable, so we don't compile it.
2. Add a test that covers every LlmError Display message so the
`Status` and `MissingInput` variants are constructed in the
test build (they were used by WakiClient on wasm32 but never
touched by host tests). The test doubles as a regression net
for the user-facing error strings.
18 host tests green (was 17). Drops the previous
allow(dead_code) escape hatch entirely.
Signed-off-by: flemming-it <sf@flemming.it>
Same suppression as in fai/platform's modules/echo: wit_bindgen
0.36's export! macro expands into unsafe fns whose bodies call
further unsafe fns without explicit unsafe blocks, and Rust 2024
makes that an error under -D warnings. Drop once wit_bindgen
ships a fix.
Gated on target_arch wasm32 so the host build (tests, plan
validation) stays strict.
Signed-off-by: flemming-it <sf@flemming.it>
Mirrors the workflow in fai/platform: Linux x86_64 only, manual
checkout via the external URL to bypass DinD network isolation,
fmt/clippy/build/test on host, plus an explicit wasm32-wasip2
release build to confirm the module still produces a valid WASM
component.
See fai/platform docs/architecture/ci.md for the rationale on
why we don't use actions/checkout.
Signed-off-by: flemming-it <sf@flemming.it>
The orchestrator now calls a configured Ollama-compatible LLM
endpoint over wasi-http and emits the LLM-generated plan back
to the hub. When llm_endpoint is empty, the v0.1.0 deterministic
stub is preserved as fallback (useful for tests and air-gapped
environments).
- module.yaml: bump to 0.2.0; new inputs llm_endpoint,
llm_model, llm_api_key; net: permissions for OpenAI,
Anthropic, localhost, 127.0.0.1 (Ollama defaults)
- src/llm.rs: LlmClient trait, OllamaParams, build_user_prompt,
build_ollama_body, extract_ollama_content, generate_plan;
9 unit tests for prompt-building and response-parsing
- src/plan.rs: tagged enum with Explain/SaveFlow/RunFlow/
InstallModule variants; parse_and_validate; build_stub_plan
(renamed from build_plan); validate(); 6 unit tests
- src/lib.rs: WakiClient implementing LlmClient over the waki
WASI-0.2 HTTP crate (wasm32-only); empty endpoint → stub
- Cargo.toml: 0.2.0; thiserror dep; waki dep gated on wasm32
17 host-side tests pass. WASM bundle is 386KB (was 74KB; the
delta is wasi-http via waki, expected). The deny path is
exercised by the platform-side integration test in
fai_platform/crates/fai_hub/tests/orchestrator_llm_path.rs.
Signed-off-by: flemming-it <sf@flemming.it>
The orchestrator-llm module turns a goal text into a Plan JSON
that the F∆I hub can apply. v0.1.0 is a deterministic stub —
it always emits a three-step plan (explain, explain-stub-notice,
save_flow with debug.echo) regardless of the goal.
Why ship a stub: it validates the module → plan → apply pipeline
end-to-end before adding LLM integration. The output is a
structurally valid Plan that round-trips cleanly through
fai_hub::plan::Plan deserialization.
v0.2.0 will replace the stub body with an actual LLM call once
the F∆I platform exposes outbound HTTP to permitted modules via
wasi-http.
Files:
- module.yaml — capability orchestrator.plan@0.1.0, no permissions
- wit/world.wit — copy of fai:platform@0.1.0
- src/lib.rs — wit_bindgen Guest impl that delegates to plan.rs
- src/plan.rs — pure plan-builder (host + WASM compatible)
- tests/plan_compatibility.rs — plan JSON shape assertions
- rust-toolchain.toml — pin to Rust 1.86 with wasm32-wasip2 target
- README.md — usage and status
Signed-off-by: flemming-it <sf@flemming.it>