mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
feat: report Pi and OpenCode in guided setup (#109624)
* feat(onboarding): detect Pi and OpenCode CLIs * fix(onboarding): clarify Pi and OpenCode readiness
This commit is contained in:
committed by
GitHub
parent
a1dfd47edd
commit
399345e1bb
@@ -709,17 +709,17 @@ struct OnboardingAISetupTests {
|
||||
#expect(local["modelRef"]?.value as? String == "lmstudio/qwen-local")
|
||||
}
|
||||
|
||||
@Test func `unavailable detected integration decodes for informational display`() throws {
|
||||
let candidate = try JSONDecoder().decode(
|
||||
OnboardingAISetupModel.UnavailableCandidate.self,
|
||||
@Test func `unavailable detected integrations decode for informational display`() throws {
|
||||
let candidates = try JSONDecoder().decode(
|
||||
[OnboardingAISetupModel.UnavailableCandidate].self,
|
||||
from: Data(
|
||||
#"{"id":"antigravity-cli","label":"Antigravity CLI","detail":"installed","reason":"Automatic setup cannot enforce a tool-free probe."}"#.utf8
|
||||
#"[{"id":"pi-cli","label":"Pi CLI","detail":"installed","reason":"Not a setup route."},{"id":"opencode-cli","label":"OpenCode CLI","detail":"installed","reason":"Not a setup route."}]"#.utf8
|
||||
)
|
||||
)
|
||||
|
||||
#expect(candidate.id == "antigravity-cli")
|
||||
#expect(candidate.label == "Antigravity CLI")
|
||||
#expect(candidate.detail == "installed")
|
||||
#expect(candidates.map(\.id) == ["pi-cli", "opencode-cli"])
|
||||
#expect(candidates.map(\.label) == ["Pi CLI", "OpenCode CLI"])
|
||||
#expect(candidates.allSatisfy { $0.detail == "installed" })
|
||||
}
|
||||
|
||||
@Test func `activation decodes and retains copyable setup lines`() throws {
|
||||
|
||||
@@ -38,6 +38,8 @@ automatic pass. Detected local runtimes are auto-tested after CLI and API-key
|
||||
candidates; when several local models are available, OpenClaw prefers the
|
||||
strongest tool-calling instruct family. The selected candidate must answer a
|
||||
real completion before its provider and model configuration is saved.
|
||||
Installed Gemini, Antigravity, Pi, and OpenCode CLIs are also reported when
|
||||
they cannot serve as the reusable inference route for guided setup.
|
||||
|
||||
`setup` accepts the same onboarding flags as `openclaw onboard`, including
|
||||
auth (`--auth-choice`, `--token`, provider key flags), Gateway
|
||||
|
||||
@@ -85,9 +85,11 @@ To use a Claude subscription when the Gateway host has no Claude CLI login, run
|
||||
printed token as **Anthropic setup-token** under **Connect with an API key or
|
||||
token**.
|
||||
|
||||
Gemini CLI and Antigravity remain available for normal use after setup. Their
|
||||
installed CLIs are shown for context but are not auto-tested because neither can
|
||||
enforce the tool-free inference probe.
|
||||
Installed Gemini CLI, Antigravity, Pi, and OpenCode CLIs are shown for context
|
||||
when they cannot be selected as the reusable guided-setup inference route.
|
||||
Gemini and Antigravity cannot enforce the tool-free inference probe. Pi and
|
||||
OpenCode are whole-agent harnesses rather than setup inference routes; their
|
||||
session integrations require separate runtime and plugin setup.
|
||||
|
||||
You can also sign in through the provider's own OAuth or device-pairing flow.
|
||||
The built-in choices include OpenAI/ChatGPT, OpenRouter, GitHub Copilot, Google
|
||||
|
||||
@@ -76,8 +76,10 @@ Plain `openclaw onboard` follows this path:
|
||||
2. Detect configured models, API-key environment variables, supported local AI
|
||||
CLIs, and already installed tool-capable models from reachable Ollama or LM
|
||||
Studio servers on the Gateway host. This read-only pass never downloads a
|
||||
model. Gemini CLI and Antigravity installs are reported but not auto-tested
|
||||
because they cannot enforce a tool-free probe.
|
||||
model. Gemini CLI, Antigravity, Pi, and OpenCode installs are also reported
|
||||
when they cannot serve as the reusable inference route for guided setup.
|
||||
Gemini and Antigravity cannot enforce the tool-free probe; Pi and OpenCode
|
||||
are whole-agent harnesses rather than setup inference routes.
|
||||
3. Test the first detected candidate with a real completion. On failure, show the
|
||||
reason and continue to the next usable candidate.
|
||||
4. If detection is exhausted, choose OpenAI, Anthropic, xAI (Grok), Google, or
|
||||
|
||||
@@ -406,7 +406,10 @@ describe("detectSetupInference", () => {
|
||||
credentials: false,
|
||||
},
|
||||
],
|
||||
probeLocalCommand: vi.fn(async (command) => ({ command, found: command === "agy" })),
|
||||
probeLocalCommand: vi.fn(async (command) => ({
|
||||
command,
|
||||
found: command === "agy" || command === "pi" || command === "opencode",
|
||||
})),
|
||||
resolveManifestProviderAuthChoices: () => [
|
||||
{
|
||||
pluginId: "local-plugin",
|
||||
@@ -435,6 +438,8 @@ describe("detectSetupInference", () => {
|
||||
expect(detection.unavailableCandidates).toEqual([
|
||||
expect.objectContaining({ id: "gemini-cli" }),
|
||||
expect.objectContaining({ id: "antigravity-cli" }),
|
||||
expect.objectContaining({ id: "pi-cli" }),
|
||||
expect.objectContaining({ id: "opencode-cli" }),
|
||||
]);
|
||||
expect(detect).toHaveBeenCalledOnce();
|
||||
expect(prepare).not.toHaveBeenCalled();
|
||||
@@ -677,6 +682,39 @@ describe("detectSetupInference", () => {
|
||||
expect.objectContaining({ id: "gemini-cli" }),
|
||||
]);
|
||||
});
|
||||
|
||||
it("reports installed Pi and OpenCode without offering them as setup inference routes", async () => {
|
||||
vi.mocked(detectInferenceBackends).mockResolvedValueOnce([]);
|
||||
const probeLocalCommand = vi.fn(async (command: string) => ({
|
||||
command,
|
||||
found: command === "pi" || command === "opencode",
|
||||
}));
|
||||
|
||||
const detection = await detectSetupInference({
|
||||
resolveManifestProviderAuthChoices: () => [],
|
||||
probeLocalCommand,
|
||||
});
|
||||
|
||||
expect(detection.candidates).toEqual([]);
|
||||
expect(detection.unavailableCandidates).toEqual([
|
||||
{
|
||||
id: "pi-cli",
|
||||
label: "Pi CLI",
|
||||
detail: "installed",
|
||||
reason:
|
||||
"Pi CLI is installed, but its whole-agent sessions require separate setup and are not a reusable guided-setup inference route.",
|
||||
},
|
||||
{
|
||||
id: "opencode-cli",
|
||||
label: "OpenCode CLI",
|
||||
detail: "installed",
|
||||
reason:
|
||||
"OpenCode CLI is installed, but its ACP harness requires separate setup and is not a reusable guided-setup inference route.",
|
||||
},
|
||||
]);
|
||||
expect(probeLocalCommand).toHaveBeenCalledWith("pi");
|
||||
expect(probeLocalCommand).toHaveBeenCalledWith("opencode");
|
||||
});
|
||||
});
|
||||
|
||||
async function runCodexSetupWithFinalConfig(params: {
|
||||
|
||||
@@ -365,7 +365,12 @@ export async function detectSetupInference(
|
||||
reason:
|
||||
"Can't be auto-tested safely here. Use 'Gemini CLI OAuth' or a Gemini API key instead.",
|
||||
}));
|
||||
const antigravity = await (deps.probeLocalCommand ?? probeLocalCommand)("agy");
|
||||
const probe = deps.probeLocalCommand ?? probeLocalCommand;
|
||||
const [antigravity, pi, opencode] = await Promise.all([
|
||||
probe("agy"),
|
||||
probe("pi"),
|
||||
probe("opencode"),
|
||||
]);
|
||||
if (antigravity.found) {
|
||||
unavailableCandidates.push({
|
||||
id: "antigravity-cli",
|
||||
@@ -375,6 +380,24 @@ export async function detectSetupInference(
|
||||
"Can't be auto-tested safely here. Sign in with a provider or use an API key instead.",
|
||||
});
|
||||
}
|
||||
if (pi.found) {
|
||||
unavailableCandidates.push({
|
||||
id: "pi-cli",
|
||||
label: "Pi CLI",
|
||||
detail: "installed",
|
||||
reason:
|
||||
"Pi CLI is installed, but its whole-agent sessions require separate setup and are not a reusable guided-setup inference route.",
|
||||
});
|
||||
}
|
||||
if (opencode.found) {
|
||||
unavailableCandidates.push({
|
||||
id: "opencode-cli",
|
||||
label: "OpenCode CLI",
|
||||
detail: "installed",
|
||||
reason:
|
||||
"OpenCode CLI is installed, but its ACP harness requires separate setup and is not a reusable guided-setup inference route.",
|
||||
});
|
||||
}
|
||||
const raw = detected.filter((candidate) => candidate.kind !== "gemini-cli");
|
||||
const candidates: SetupInferenceCandidate[] = raw.map((candidate) =>
|
||||
// Released macOS clients require this field. Keep it false so the wire
|
||||
|
||||
Reference in New Issue
Block a user