From 29d72eff737a59c21e18eb34b80f1676df3bcadb Mon Sep 17 00:00:00 2001 From: Speculator55005 <50082482+fas89@users.noreply.github.com> Date: Thu, 12 Nov 2026 06:20:58 +0100 Subject: [PATCH] docs(ai): keyless auto-pick, --agent AI mode, an isolated claude -p and the Ollama endpoint (forge-cli#850) forge-cli #850 (merged as 28a1f2e2, not yet in a release) changed how forge picks and calls an LLM. llm-providers.md gains three sections: the non-interactive pick when nothing is configured, how forge runs claude -p, and where Ollama calls go. The forge, ai, doctor, litellm-backend, environment-variables, network-safety, production-troubleshooting and upgrading pages are matched to it, and the "Ollama is localhost only" claims are corrected. Every new claim carries the "On forge-cli main" marker and says what 0.28.0 did. Checked against forge-cli main 28a1f2e2 by running the CLI (clean HOME, null keyring, stub agent CLIs, the local Ollama), and against v0.28.0 for each "Through 0.28.0" sentence. --- docs/advanced/environment-variables.md | 6 +- docs/advanced/litellm-backend.md | 6 +- docs/advanced/llm-providers.md | 97 ++++++++++++++++++++- docs/advanced/network-safety.md | 8 +- docs/advanced/production-troubleshooting.md | 4 + docs/cli/ai.md | 10 ++- docs/cli/doctor.md | 2 +- docs/cli/forge.md | 15 +++- docs/upgrading.md | 10 +++ 9 files changed, 141 insertions(+), 17 deletions(-) diff --git a/docs/advanced/environment-variables.md b/docs/advanced/environment-variables.md index 9894052..88b1d54 100644 --- a/docs/advanced/environment-variables.md +++ b/docs/advanced/environment-variables.md @@ -214,14 +214,14 @@ See [cost tracking](./cost-tracking.md). ## LLM provider and routing -See [LLM providers](./llm-providers.md) and the [LiteLLM backend](./litellm-backend.md). +See [LLM providers](./llm-providers.md) and the [LiteLLM backend](./litellm-backend.md). With nothing here or in a provider key set, a non-interactive run picks a provider itself; see [When nothing is configured](./llm-providers.md#when-nothing-is-configured). *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* | Variable | Effect | |---|---| | `FLUID_LLM_PROVIDER` | Default provider. | | `FLUID_LLM_MODEL` | Default model. | | `FLUID_LLM_API_KEY` | API key used when no provider-specific key is set. | -| `FLUID_LLM_ENDPOINT` | Overrides the model endpoint. | +| `FLUID_LLM_ENDPOINT` | Overrides the model endpoint. The routing model's calls use it too, unless `FLUID_LLM_ROUTING_ENDPOINT` names another. *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* | | `FLUID_LLM_TIMEOUT_SECONDS` | Per-call timeout. Default `120`. | | `FLUID_LLM_STREAMING` | Default on; `0`, `false`, `no` or `off` disables streaming. | | `FLUID_LLM_ROUTING_ENDPOINT`, `FLUID_LLM_ROUTING_MODEL` | Optional routing endpoint and model. | @@ -258,7 +258,7 @@ Provider-specific keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, | `FLUID_FORGE_TOOL_SEARCH` | Enables lazy tool-search deferral in the agent loop. | | `FLUID_GITHUB_MCP`, `FLUID_SNOWFLAKE_MCP`, `FLUID_DBT_MCP` | Enable delegation to the hosted GitHub, Snowflake and dbt MCP servers. | | `FLUID_HOSTED_MCP_TIMEOUT_SECONDS` | Per-operation timeout for hosted MCP calls. | -| `FLUID_COPILOT_AGENT_LOOP` | `1`, `true`, `yes` or `on` selects the multi-turn agent loop. Same as `--agent-loop`. | +| `FLUID_COPILOT_AGENT_LOOP` | `1`, `true`, `yes` or `on` selects the multi-turn agent loop. Same as `--agent-loop`. The loop also keeps a non-interactive run from picking a coding agent; see [When nothing is configured](./llm-providers.md#when-nothing-is-configured). *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* | | `FLUID_COPILOT_JUDGE`, `FLUID_COPILOT_ENRICHMENT`, `FLUID_JUDGE_SELF_CRITIQUE`, `FLUID_COPILOT_SELF_EVAL`, `FLUID_COPILOT_CHECKPOINT`, `FLUID_COPILOT_PII_CLASSIFIER` | On by default; `0`, `false`, `no` or `off` skips that stage. | | `FLUID_COPILOT_POST_SYNTHESIS`, `FLUID_COPILOT_EPISODIC_MEMORY` | On by default; only the value `0` turns them off. | | `FLUID_COPILOT_SEMANTIC_MEMORY` | Opts in to semantic-memory writes and lookups. | diff --git a/docs/advanced/litellm-backend.md b/docs/advanced/litellm-backend.md index 626bfc9..91c7b1c 100644 --- a/docs/advanced/litellm-backend.md +++ b/docs/advanced/litellm-backend.md @@ -15,7 +15,7 @@ LiteLLM was a hard dependency of core `data-product-forge` (`litellm>=1.83.14,<2 | `openai` | `openai` | `gpt-4.1-mini` | | `anthropic`, `claude` | `anthropic` | `claude-haiku-4-5` | | `gemini` | `gemini` | `gemini-2.5-flash` | -| `ollama` | `ollama` (localhost only) | `gemma3:4b` | +| `ollama` | `ollama` | `gemma3:4b` | A forge run normally gets its model from `fluid ai models`, which is `claude-sonnet-4-6` for Anthropic, `gemini-2.5-pro` for Gemini and `gemma4:latest` for Ollama; the fallback column applies only when nothing names a model. @@ -43,7 +43,7 @@ LiteLLM reports the cost of each call, and Forge folds it into `.fluid/agents//`). | | `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` | Provider keys. LiteLLM reads the same names the underlying SDKs use. | -| `OLLAMA_HOST` | Ollama endpoint. Local addresses only. | +| `OLLAMA_HOST` | Ollama's address. See [The Ollama endpoint](./llm-providers.md#the-ollama-endpoint). | | `LITELLM_*` | Any LiteLLM-specific variable. LiteLLM reads these directly; Forge does not filter them. | See the [environment variables index](./environment-variables.md) for everything else. @@ -63,7 +63,7 @@ If you point LiteLLM at a model the catalog doesn't know, the run-start banner s ## Caveats - Tool-use behaviour matches LiteLLM's wrapper. Provider failures surface as the typed errors described in [Typed Errors](./typed-errors.md) (`RateLimitError`, `ContextOverflowError` and the others). -- Ollama is restricted to `localhost` (`127.0.0.1` / `::1`) by the SSRF guard. See [network safety](./network-safety.md). +- Forge's Ollama calls go to `OLLAMA_HOST` whatever its host; only the probe for a running Ollama, model discovery and the interactive Ollama setup stay on `localhost`. See [The Ollama endpoint](./llm-providers.md#the-ollama-endpoint). *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* ## See also diff --git a/docs/advanced/llm-providers.md b/docs/advanced/llm-providers.md index 7869086..540daef 100644 --- a/docs/advanced/llm-providers.md +++ b/docs/advanced/llm-providers.md @@ -14,6 +14,8 @@ FLUID_LLM_MODEL=gemma4:latest \ fluid forge data-model from-intent intent.yaml -o customer_orders.fluid.yaml ``` +A run that names no provider and cannot ask a question picks one itself; see [When nothing is configured](#when-nothing-is-configured). *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* + ## Supported providers The `openai`, `anthropic`, `gemini` and `ollama` providers run through LiteLLM and need `pip install 'data-product-forge[litellm]'` (alias `[ai]`). *(since 0.28.0, [forge-cli #837](https://github.com/Agenticstiger/forge-cli/pull/837))* `mcp-sampling` works only inside `fluid mcp serve`, which needs `[mcp]`. The four local agent CLIs need neither extra; only Claude Code needs no setup of its own, since the others reuse their own CLI login or key. @@ -23,9 +25,9 @@ The `openai`, `anthropic`, `gemini` and `ollama` providers run through LiteLLM a | Anthropic | `anthropic` (alias `claude`) | `claude-sonnet-4-6` | Tool-forced structured output and provider-native prompt caching. Streamed runs report token usage in cost summaries. | | OpenAI | `openai` | `gpt-4.1-mini` | Strict JSON Schema output where available. Tiered runs use `gpt-4.1` for deep logical modeling. Set `FLUID_OPENAI_STRICT_SCHEMA=1` to harden the response-format schema for `gpt-4o`, `gpt-4.1` and o-series models that reject permissive nested objects. | | Gemini | `gemini` | `gemini-2.5-pro` | Uses Gemini response schema where suitable and validator repair when needed. | -| Ollama | `ollama` | `gemma4:latest` | Local-only; JSON mode is model-gated. The capability and token-budget catalogs cover `gemma` 1 to 4, `qwen3-coder`, `qwen3`, `qwen2.5`, `llama3.1`, `llama3.2`, `llama3.3`, `mistral`, `mixtral`, `deepseek` and `phi`. See [Capability Warnings](capability-warnings.md) for tool-use accuracy notes per family. | +| Ollama | `ollama` | `gemma4:latest` | Calls go to the [Ollama endpoint](#the-ollama-endpoint). JSON mode is model-gated. The capability and token-budget catalogs cover `gemma` 1 to 4, `qwen3-coder`, `qwen3`, `qwen2.5`, `llama3.1`, `llama3.2`, `llama3.3`, `mistral`, `mixtral`, `deepseek` and `phi`. See [Capability Warnings](capability-warnings.md) for tool-use accuracy notes per family. | | MCP sampling | `mcp-sampling` | none | No key of its own. When forge runs inside an MCP client, the model request goes back through the connection and the client's own LLM answers it. | -| Local agent CLIs | `claude-code`, `codex`, `cursor`, `kiro` | the agent's own | Forge shells out to a coding-agent CLI you already have installed. Claude Code uses your subscription login; the others reuse `CODEX_API_KEY`, `CURSOR_API_KEY` and `KIRO_API_KEY`. | +| Local agent CLIs | `claude-code`, `codex`, `cursor`, `kiro` | the agent's own | Forge shells out to a coding-agent CLI you already have installed. Claude Code uses your subscription login; the others reuse `CODEX_API_KEY`, `CURSOR_API_KEY` and `KIRO_API_KEY`. Forge runs `claude -p` apart from your own Claude Code setup; see [Claude Code](#claude-code). | Those are the values `fluid forge --llm-provider` and `fluid forge data-model ... --llm-provider` accept. Other names LiteLLM understands, such as `bedrock`, `vertex` and `azure`, are rejected by the argument parser as of 0.18.1: @@ -44,6 +46,95 @@ fluid ai models --json # the same plan as JSON, one object per provider `fluid ai models` prints one plan per provider and cannot be narrowed to one. As of 0.18.1 its `--provider` flag does not work: `fluid ai models --provider gemini` exits 2 with `Unknown provider 'gemini' — installed providers: aws, datamesh_manager, gcp, local, redshift, snowflake`, because the CLI checks the value against the infrastructure providers. Filter the JSON instead, for example with `jq .gemini`. `fluid ai test` and `fluid ai setup` take `--provider` and are not affected. +## When nothing is configured + +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* + +A run that cannot ask a question picks an LLM itself when nothing names one. That is a run whose stdin is not a terminal, or one with `--non-interactive`, which `fluid forge --agent` sets when it runs AI mode. Forge uses the first of these it finds: + +1. A local Ollama answering on `http://localhost:11434`, so local data stays on the machine. +2. The first coding-agent CLI on `PATH`, in this order: `claude` (`claude-code`), `codex`, `cursor-agent` (`cursor`) and `kiro-cli` (`kiro`). + +When it picks an agent, forge logs a warning that names it: + +```text +No LLM provider is configured; using claude-code, the first coding agent found on PATH. Override with --llm-provider. +``` + +With neither, the run falls back to `gemini`, which needs a Gemini key and the `litellm` extra. Through 0.28.0 a run with no Ollama running always fell back to `gemini`, even with a signed-in Claude Code on `PATH`. + +Any of these configures an LLM, and then no agent is picked: + +- `--llm-provider`, `FLUID_LLM_PROVIDER` or `FLUID_FORGE_AGENT`. The provider they name is used. +- `--llm-endpoint`, `--llm-model`, `--llm-routing-endpoint` or `--llm-routing-model`. +- `FLUID_LLM_API_KEY`, `FLUID_LLM_ENDPOINT`, `FLUID_LLM_MODEL`, `FLUID_LLM_ROUTING_ENDPOINT`, `FLUID_LLM_ROUTING_MODEL` or `OLLAMA_HOST`. +- A provider key: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `GOOGLE_API_KEY` or `GITHUB_API_KEY`. +- An OpenAI, Anthropic or Gemini key in the OS keyring. +- A provider saved with `fluid ai setup`. A non-interactive run does not use the saved provider itself, so name it with `--llm-provider` or `FLUID_LLM_PROVIDER`. +- The agent loop: `--agent-loop`, or `FLUID_COPILOT_AGENT_LOOP` set to `1`, `true`, `yes` or `on`. The loop needs tool use, which these agents do not offer. + +The pick works on the base install, because the agent CLIs need no `litellm` extra. A running local Ollama still comes first there, so that run asks for the extra instead of sending the prompt to an agent. + +An interactive run does not pick an agent: `fluid forge` in a terminal offers Claude Code in its inline setup instead. With nothing configured, [`fluid doctor`](../cli/doctor.md) run without a terminal reports the provider this pick chooses. When the pick finds nothing, its Provider row says `Not selected`. + +## Claude Code + +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* + +`--llm-provider claude-code` runs `claude -p` on your machine. Forge keeps each call apart from your own Claude Code setup, as Anthropic's [Agent SDK](https://github.com/anthropics/claude-agent-sdk-python) does: + +| Flag or variable | Effect | +| --- | --- | +| `--system-prompt` | Forge's prompt replaces Claude Code's own system prompt. | +| `--tools ""` | No built-in tools. | +| `--strict-mcp-config` | No MCP servers. Forge passes no `--mcp-config`. | +| `--setting-sources=` | None of your user, project or local settings: no hooks, plugins or `CLAUDE.md`. | +| `--no-session-persistence` | The call is not saved as a session. | +| `CLAUDECODE` | Removed from the environment `claude` starts in. Claude Code sets it in the shells it starts. | + +Forge passes each flag only when the installed `claude --help` lists it, so an older Claude Code still runs. Without `--system-prompt`, forge appends its prompt with `--append-system-prompt`, as it did through 0.28.0. The [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference) describes each flag. + +### Signing in + +A subscription login (run `claude` once and sign in) and an `ANTHROPIC_API_KEY` in the environment work as before. Authentication kept in your own Claude Code settings does not reach forge's calls: an `apiKeyHelper`, or `CLAUDE_CODE_USE_BEDROCK`, `CLAUDE_CODE_USE_VERTEX` and their variables in the `env` block of `settings.json`. Export those variables in the shell that runs forge, or set `ANTHROPIC_API_KEY`. Claude Code's [authentication](https://code.claude.com/docs/en/authentication) page lists the variables each method needs. + +### When the call fails + +`claude -p` reports a failure as a JSON result with `is_error: true` on stdout, and leaves stderr empty. Forge reads that result. A login problem reads: + +```text +claude-code is installed but not authenticated. +``` + +The hint under it says ``Run `claude` once and sign in (subscription), or set ANTHROPIC_API_KEY.`` Any other failure shows Claude Code's own message. A result with `is_error: true` fails the call even when `claude` exits `0`. Through 0.28.0 forge read only stderr, and showed `claude-code exited with code 1:` with no reason. + +## The Ollama endpoint + +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* + +Forge's Ollama calls go to the first of these that is set: + +1. `--llm-endpoint`, or `FLUID_LLM_ENDPOINT`. +2. `OLLAMA_HOST`. +3. `http://localhost:11434`, litellm's default. + +Forge reads `OLLAMA_HOST` the way Ollama's own Python client does ([`_parse_host`](https://github.com/ollama/ollama-python/blob/35d9667e84ebbd9d792826868d050027f75c1cc1/ollama/_client.py)), so a value Ollama accepts works here too: + +| `OLLAMA_HOST` | Calls go to | +| --- | --- | +| `gpu-box` | `http://gpu-box:11434` | +| `gpu-box:8080` | `http://gpu-box:8080` | +| `:8080` | `http://127.0.0.1:8080` | +| `http://gpu-box` | `http://gpu-box:80` | +| `https://gpu-box` | `https://gpu-box:443` | +| `https://gpu-box/ollama` | `https://gpu-box:443/ollama` | + +The host can be another machine. Model discovery still looks only at a local Ollama: with no model named, forge takes the largest model pulled on `localhost`, else `gemma4:latest`. With a remote `OLLAMA_HOST`, name the model with `--llm-model` or `FLUID_LLM_MODEL`. Forge's local-only checks print `OLLAMA_HOST points to a non-localhost address (...), ignoring.` for such a host. The call still goes to `OLLAMA_HOST`. + +A stated endpoint is used for the routing model's calls too, unless `--llm-routing-endpoint` or `FLUID_LLM_ROUTING_ENDPOINT` names another. A project's `.env` cannot set `OLLAMA_HOST`; see [Project dotenv trust](./project-dotenv-trust.md). + +Through 0.28.0 these calls went to a `litellm://ollama/` label unless an endpoint was stated, so they never reached the daemon. + ## Tiered mode `--tiered` chooses different models within the same provider, never across providers. A typical layout is: @@ -102,7 +193,7 @@ fluid forge data-model from-intent intent.yaml \ | `OPENAI_API_KEY` | OpenAI key | | `ANTHROPIC_API_KEY` | Anthropic key | | `GOOGLE_API_KEY` or `GEMINI_API_KEY` | Gemini key | -| `OLLAMA_HOST` | Ollama endpoint; local addresses only | +| `OLLAMA_HOST` | Ollama's address; see [The Ollama endpoint](#the-ollama-endpoint) | ### Agent-loop tuning diff --git a/docs/advanced/network-safety.md b/docs/advanced/network-safety.md index 4adae15..9d9f7b3 100644 --- a/docs/advanced/network-safety.md +++ b/docs/advanced/network-safety.md @@ -13,7 +13,7 @@ This page describes the user-visible behaviour: which flags opt in, which enviro | `fluid odps import ` | Followed `http(s)` `contractId` references | Local only; remote references are rejected | `--allow-remote` | | `BitolOdpsProvider().import_contract(...)` (Python) | `allow_remote=True` | `allow_remote=False` | `allow_remote=True` (keyword) | | `ContractResolver(...)` (Python) | `allow_remote=True` | `allow_remote=False` | `allow_remote=True` (keyword) | -| Ollama endpoint | Configurable | Localhost only | None, by design | +| Ollama endpoint | Configurable | Localhost only | None, by design. *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* Calls now go to `OLLAMA_HOST` whatever the host; see [Ollama and `OLLAMA_HOST`](#ollama-and-ollama-host). | | HTTP redirects on a safe-HTTP client | Followed | Not followed | `follow_redirects=True` (per client) | The CLI flags `--no-remote` and `--seed-no-remote` remain as hidden aliases that do nothing, so older scripts keep working. @@ -68,9 +68,11 @@ An IPv4-mapped address (`::ffff:...`) or a NAT64 address (`64:ff9b::/96`) that c As of 0.18.1, nothing in the CLI reads `FLUID_SAFE_MODE` or acts on the global `--safe-mode` flag to refuse network calls. -## Ollama is localhost only +## Ollama and `OLLAMA_HOST` -The Ollama provider uses `http://localhost:11434` unless `OLLAMA_HOST` names another localhost URL. An `OLLAMA_HOST` that points elsewhere is ignored with a warning, and the default is used. You cannot point `fluid forge --llm-provider ollama` at a remote Ollama instance this way. For a remote model, use a hosted provider (OpenAI, Anthropic, Gemini, Bedrock or Vertex). +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* Forge's Ollama calls go to `--llm-endpoint` or `FLUID_LLM_ENDPOINT`, else to `OLLAMA_HOST` whatever its host, else to `http://localhost:11434`; see [The Ollama endpoint](./llm-providers.md#the-ollama-endpoint). Three things still look only at `localhost`, and ignore a non-local `OLLAMA_HOST` with a warning: the probe that finds a running Ollama, model discovery, and the interactive Ollama setup. A project's `.env` cannot set `OLLAMA_HOST` ([Project dotenv trust](./project-dotenv-trust.md)). + +Through 0.28.0 the calls went to a `litellm://ollama/` label unless an endpoint was stated, so no `OLLAMA_HOST`, local or remote, reached a daemon. ## Contract SQL and `$ref` diff --git a/docs/advanced/production-troubleshooting.md b/docs/advanced/production-troubleshooting.md index eb32c5c..32eff2b 100644 --- a/docs/advanced/production-troubleshooting.md +++ b/docs/advanced/production-troubleshooting.md @@ -254,6 +254,10 @@ Update the key at the source `fluid ai status` reports, the provider environment [`fluid ai test`](../cli/ai.md#ai-test) is the connectivity check. As of 0.18.1, `fluid ai test` with no provider configured and no `--provider` fails with `❌ Unexpected error: name 'detect_ollama_available' is not defined` and exit code 2. Name the provider, or run `fluid ai setup` first. `fluid ai test --provider --json` prints a report with `ok`, `exit_code` and, on failure, an `error` object with `code`, `message` and `suggestions`. +### A coding agent that is not signed in + +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* With `--llm-provider claude-code`, a login problem reads `claude-code is installed but not authenticated.` Run `claude` once and sign in, or set `ANTHROPIC_API_KEY`. Authentication kept in a Claude Code setting (an `apiKeyHelper`, or Bedrock or Vertex variables in `settings.json`) does not reach forge's calls: export those variables in the shell. See [Claude Code](./llm-providers.md#claude-code). + ## An optional package is not installed **Symptom:** a command exits 1, with no traceback, and prints a message naming the feature, the package and the extra, followed by a short error code in brackets: diff --git a/docs/cli/ai.md b/docs/cli/ai.md index bd38c66..821ad9d 100644 --- a/docs/cli/ai.md +++ b/docs/cli/ai.md @@ -67,6 +67,8 @@ i No metadata-source catalogs configured yet. Run: fluid ai setup --source Sends a small request to the configured provider and reports whether it answered. Use it before a long forge run, or in CI to check a key. +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* For `openai`, `anthropic`, `gemini` and `ollama`, the request is the call `fluid forge` makes, through litellm. With no endpoint set, the report's `endpoint` is `null` and the table says `provider default`. Through 0.28.0 the probe went to a `litellm:///` label, so without `--endpoint` it failed with `AI test network error ... (UnsupportedProtocol)`. + | Option | Description | | --- | --- | | `--provider {gemini,openai,anthropic,claude,ollama}` | Test this provider instead of the configured one. | @@ -106,6 +108,8 @@ fluid ai test --provider ollama --endpoint http://127.0.0.1:9 --timeout-seconds } ``` +The model check before the call lists the models of `OLLAMA_HOST`, else of `localhost:11434`, not those at `--endpoint`. With a local Ollama running, the example above therefore exits `4` with `ai_test_model_unavailable` when that Ollama does not have the model. + The process exit code equals `exit_code`: | Code | Meaning | @@ -116,6 +120,8 @@ The process exit code equals `exit_code`: | `4` | The request failed in another way, for example an unknown model. | | `5` | A network failure, a `429` or a `5xx`. | +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* A `401` or `403` from the call exits `3`. A model the provider does not have exits `4`: it is missing from the provider's model list (`ai_test_model_unavailable`), or the call returns a `404`. A reply without `FLUID_OK` exits `4` too (`ai_test_unexpected_response`). Any other failure of the call, such as a refused connection, a timeout, a `429` or a `5xx`, exits `5` with `"code": "copilot_litellm_request_failed"` and a message that starts `litellm request failed:`. The failed run above reads that way on `main`, in place of `ai_test_network_error`. + ::: warning `fluid ai test` crashes with no provider configured As of 0.18.1, on a machine with no provider configured and no key in the environment, `fluid ai test` and `fluid ai test --json` stop with `Unexpected error: name 'detect_ollama_available' is not defined` and exit `2`, instead of the JSON report with `ai_test_no_provider`. Run `fluid ai setup` first, or pass `--provider` with a configured provider. ::: @@ -143,8 +149,8 @@ fluid ai models --json | jq '.gemini.tier_models' - `setup` is interactive and requires a TTY with `rich` installed. It walks through provider choice (Google Gemini, OpenAI, Anthropic, Ollama, or skip), validates the API key with a lightweight call, and persists settings. - Provider config is written to `~/.fluid/ai_config.json` (chmod 600). API keys are stored in the OS keyring when available and are not written to the JSON file by default. - If no keyring backend is available, the API key is kept only for the current process. Set `FLUID_ALLOW_PLAINTEXT_AI_SECRETS=1` only when you deliberately want plaintext local persistence. -- `OLLAMA_HOST` is restricted to localhost addresses for SSRF protection; non-local hosts are ignored and replaced with `http://localhost:11434`. -- The same setup flow is invoked inline on first use of [`fluid forge`](./forge.md) when no provider is configured. +- The interactive Ollama setup uses only a local Ollama: a non-local `OLLAMA_HOST` is ignored there, with a warning, and replaced with `http://localhost:11434`. *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* Forge's own Ollama calls, and `fluid ai test`, go to `OLLAMA_HOST` whatever the host; see [The Ollama endpoint](../advanced/llm-providers.md#the-ollama-endpoint). +- The same setup flow is invoked inline on first use of [`fluid forge`](./forge.md) in a terminal when no provider is configured. *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* A run without a terminal picks a provider itself instead; see [When nothing is configured](../advanced/llm-providers.md#when-nothing-is-configured). - Provider environment variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, etc.) are respected as a fallback. - For strict provider validation, run `fluid forge data-model from-intent ... --require-llm` so provider failures do not silently fall back to heuristics. - For tiered per-stage model selection, pass `--tiered` on the forge command. Tiering stays within the active provider and collapses to single-model mode when the provider has no distinct tier catalog. diff --git a/docs/cli/doctor.md b/docs/cli/doctor.md index 9d5faae..4383179 100644 --- a/docs/cli/doctor.md +++ b/docs/cli/doctor.md @@ -64,7 +64,7 @@ fluid doctor --env `fluid doctor` with neither `--scope` nor `--env` runs the default checks: -- **Forge copilot readiness**: whether an LLM provider and model are configured, and whether credentials are present. +- **Forge copilot readiness**: whether an LLM provider and model are configured, and whether credentials are present. *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* Its Endpoint row says `Provider default` when no endpoint is set and the provider picks its own address; through 0.28.0 it showed a `litellm:///` label. A ready coding agent's row says `coding-agent://`. With `FLUID_LLM_PROVIDER` set to `claude-code`, `codex`, `cursor` or `kiro`, the copilot is ready when the agent's CLI (`claude`, `codex`, `cursor-agent` or `kiro-cli`) is on `PATH`; the CLI's own sign-in is not checked. Without the CLI, the table says Setup needed and the panel names it: `The 'cursor-agent' CLI for cursor is not on PATH.` Through 0.28.0 these providers read "No API key found". With nothing configured and no terminal, readiness reports the provider a non-interactive forge run picks, or `Not selected` when that pick finds nothing (forge itself then falls back to `gemini`); see [When nothing is configured](../advanced/llm-providers.md#when-nothing-is-configured). - **Memory store backend**: which backend holds copilot memory (`file`, `sqlite`, `postgres` or `vector`), where it lives, and whether it is readable and writable. - **Provider readiness**: under `--verbose`, a **Databricks Provider** row reports `Not configured` when no `DATABRICKS_*` workspace variable is set, and otherwise whether the credential resolves under the same rules `fluid apply` uses, whether `DATABRICKS_WAREHOUSE_ID` is set and whether `databricks-sdk` is installed. It never opens a connection and never changes the exit code. See [Databricks](../providers/databricks.md#fluid-doctor-and-the-welcome-scan). - **Feature availability**: a table of CLI components (the schema manager, the sovereignty and agent-policy validators, the provider action parsers for GCP, AWS and Snowflake, the dbt engine, the copilot, the LiteLLM backend and the agent web tools), each marked available, not available or not installed. `--features-only` prints just this table. diff --git a/docs/cli/forge.md b/docs/cli/forge.md index 3352a7a..c7c9e3d 100644 --- a/docs/cli/forge.md +++ b/docs/cli/forge.md @@ -81,7 +81,7 @@ Both apply on the default AI-copilot path only. See [Single file or fragments?]( | --- | --- | | `--llm-provider NAME` | `openai`, `anthropic`, `claude`, `gemini` or `ollama`; or a keyless provider: `mcp-sampling` (the calling IDE's model) or `claude-code`, `codex`, `cursor`, `kiro` (a local agent CLI). Providers installed through the `fluid_build.llm_providers` entry point are also accepted. | | `--llm-model NAME` | Model identifier. | -| `--llm-endpoint URL` | Exact HTTP endpoint for the selected provider. | +| `--llm-endpoint URL` | Exact HTTP endpoint for the selected provider. The routing model's calls use it too, unless `--llm-routing-endpoint` names another. *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* | | `--forge-agent-mode MODE` | For the local agent CLIs: `envelope` (default; the agent returns the contract as JSON on stdout) or `agentic` (the agent writes `contract.fluid.yaml` into the workspace). | | `--llm-routing-model NAME` | A fast, cheap model for interview clarification and AI self-evaluation. | | `--llm-routing-endpoint URL` | Endpoint override for the routing model. | @@ -93,6 +93,8 @@ Both apply on the default AI-copilot path only. See [Single file or fragments?]( Show the model plan per provider with [`fluid ai models`](./ai.md), and check connectivity with [`fluid ai test`](./ai.md#ai-test). +With no AI config, a run without a terminal picks a provider itself; see [When nothing is configured](../advanced/llm-providers.md#when-nothing-is-configured). *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* + ### Prompt profiles and overlays | Option | Description | @@ -408,9 +410,18 @@ fluid forge --agent --emit-plan ``` - It bundles `--yes` and `FLUID_FORGE_NO_*=1`, and emits **JSON-Lines progress events** on stdout so the calling agent can stream status. -- It defaults to `--blank`, so it can never drop into the interactive mode picker. +- With no mode flag and no AI flag, it writes the blank contract (`--blank`), so it can never drop into the interactive mode picker. +- Any of `--llm-provider`, `--llm-model`, `--llm-endpoint` or `--context` selects AI mode instead. Forge's AI authors the contract without asking anything. A contract written under the directory you run forge in is reported in a `forge.contract_written` event; with `--target-dir` outside it, AI mode emits only `forge.start` and `forge.done`. A failed generation ends with a non-zero `exit_code` in `forge.done` and a non-zero exit status. With nothing configured, the provider is picked as in [When nothing is configured](../advanced/llm-providers.md#when-nothing-is-configured). *On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* Through 0.28.0 these flags were ignored: the run wrote the TODO placeholder contract and reported `exit_code` `0`. - `--emit-plan` makes the run emit a single deterministic `forge.plan` event — the per-product-type (SDP / ADP / CDP) field checklist for the agent to fill in — instead of authoring the contract itself. +For example, to have a signed-in Claude Code author from an intent file: + +```bash +fluid forge --agent --llm-provider claude-code --context intent.txt +``` + +`--context` takes JSON or a file path. + This is the CLI half of the agentic-IDE flow. Set the editor side up with [`fluid scaffold-ide`](./scaffold-ide.md), and the in-editor tools come from the [MCP server](./mcp.md). ## Notes diff --git a/docs/upgrading.md b/docs/upgrading.md index 225babc..d8656c0 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -822,6 +822,16 @@ pip install "data-product-forge[standard]" # litellm and mcp: the pre-0.28.0 AI - *(since 0.28.0, [forge-cli #832](https://github.com/Agenticstiger/forge-cli/pull/832))* Nine internal modules that nothing imported are removed: `fluid_build.logging_utils`, `fluid_build.cli.init_samples`, `fluid_build.copilot.schemas.table_metadata`, `fluid_build.providers.local.ducksql`, `.mocks` and `.samples`, and `fluid_build.runtimes.dataform_gcp`, `.dbt_bigquery` and `.dbt_duckdb`. No command or contract behaves differently. It matters only to code that imported one of them directly. +## On forge-cli `main` since 0.28.0 + +*On forge-cli `main`, not yet in a release ([forge-cli #850](https://github.com/Agenticstiger/forge-cli/pull/850)).* These changes to AI authoring can change what a script, a CI job or an IDE agent sees: + +- **`fluid forge --agent` honours the AI flags.** With `--llm-provider`, `--llm-model`, `--llm-endpoint` or `--context`, it authors with forge's AI instead of writing the blank TODO contract, and a failed generation exits non-zero. See [Headless agent mode](./cli/forge.md#headless-agent-mode). +- **A run with nothing configured and no terminal picks an LLM.** It uses a running local Ollama, else the first coding-agent CLI on `PATH`, where it used to fall back to `gemini`. Name the provider to keep a job from picking one. See [When nothing is configured](./advanced/llm-providers.md#when-nothing-is-configured). +- **`claude -p` no longer reads your Claude Code settings.** Authentication kept there (an `apiKeyHelper`, or Bedrock or Vertex variables in `settings.json`) must come from the shell environment. See [Claude Code](./advanced/llm-providers.md#claude-code). +- **Ollama calls reach the daemon.** They go to `--llm-endpoint`, else `OLLAMA_HOST`, else `localhost:11434`, and a remote `OLLAMA_HOST` is honoured. See [The Ollama endpoint](./advanced/llm-providers.md#the-ollama-endpoint). +- **`fluid ai test` probes the real call.** A rejected key exits `3`, a model the provider does not have exits `4`, and other failed calls exit `5`. See [`ai test`](./cli/ai.md#ai-test). + ## DuckDB 1.x to 2.x `0.22.0` raised the local engine's DuckDB range to `duckdb>=1.5.0` with no upper bound, so