diff --git a/.agents/workflows/capture-release-evidences.md b/.agents/workflows/capture-release-evidences.md new file mode 100644 index 00000000..54b373fd --- /dev/null +++ b/.agents/workflows/capture-release-evidences.md @@ -0,0 +1,49 @@ +--- +description: Automatically run the browser_subagent to visually validate all new UI features from the current release and capture evidence WebP recordings of the changes. +--- + +# Capture Release Evidences Workflow + +Use this workflow to automatically drive the `browser_subagent` to explore the newly deployed or locally running application and record evidence of the UI changes introduced in the latest release. + +## Prerequisites + +- OmniRoute must be actively running and accessible (e.g. locally at `http://localhost:20128` or on the Local VPS at `http://192.168.0.15:20128`). +- The user must provide the target URL to be tested, or default to `http://192.168.0.15:20128`. + +## Workflow Steps + +### 1. Identify Target Features + +Review the `CHANGELOG.md` for the latest version to map out the new UI elements. For example: + +- **CLI Tools Settings** +- **New Provider/Model Listings (e.g., Gemini 3.1, Qoder PAT)** +- **New Feature Modals** + +### 2. Run the Browser Subagent + +For each identified feature, invoke the `browser_subagent` using the `default_api:browser_subagent` tool. +**Important Task Guidelines for the Subagent:** + +- `TaskName`: Give it a clear name like "Validate CLIProxyAPI Tool Tab". +- `TaskSummary`: "Navigate to the CLI Tools tab and verify the new Integration settings." +- `Task`: Provide unambiguous instructions for the subagent, such as: "Navigate to http://192.168.0.15:20128/dashboard. Click on the 'Settings' or 'CLI Tools' nav link. Scroll down to find the CLIProxyAPI integration card. Hover over it to trigger UI state. Verify the components render correctly and exit." +- `RecordingName`: Ensure it describes the feature (e.g. `v3_4_5_cli_proxy_api`). This is required and strictly automatically saved as a WebP artifacts video by the system. + +_(Note: The `browser_subagent` automatically creates a WebP recording named by the `RecordingName` parameter. No additional tools for screenshots are needed.)_ + +### 3. Generate Report Artifact + +After the `browser_subagent` finishes its sessions, generate a final Markdown artifact (using `write_to_file` and `IsArtifact=true`) to present the recordings inline to the user using the `![caption](/absolute/path/to/media.webp)` syntax. + +### Example Invocation + +\```json +{ +"TaskName": "Validating Qoder PAT Configuration UI", +"TaskSummary": "Validates the Qoder provider configuration modal", +"Task": "Go to http://192.168.0.15:20128/dashboard. Click on the 'Providers' tab. Find 'Qoder' in the list. Click 'Add Token' or 'Configure'. Type 'test_token' and submit. Return when done.", +"RecordingName": "qoder_pat_ui_validation" +} +\``` diff --git a/.agents/workflows/resolve-issues.md b/.agents/workflows/resolve-issues.md index 21a14316..77b94737 100644 --- a/.agents/workflows/resolve-issues.md +++ b/.agents/workflows/resolve-issues.md @@ -68,49 +68,78 @@ For each issue, determine its type: Focus ONLY on **Bugs** for resolution. Feature requests and questions should be skipped with a note in the final report. -### 5. Analyze Each Bug — For each bug issue: +### 5. Deep-Read Each Bug Issue (One-by-One Analysis) -#### 5a. Check Information Sufficiency +**IMPORTANT**: Read each bug issue thoroughly, one at a time, before moving to the next. This is NOT a batch process — each issue needs focused attention. -Verify the issue contains enough information to reproduce and fix: +#### 5a. Understand the Problem + +For each bug issue, perform the full analysis: + +1. **Read the entire body** — including Description, Steps to Reproduce, Expected/Actual Behavior, Error Logs, and Screenshots +2. **Read ALL comments** — including bot triage comments (Kilo, etc.) and owner/community responses. Pay attention to: + - Whether someone already responded with a fix + - Whether a community member confirmed the issue is resolved + - Whether the issue was marked as duplicate by a bot +3. **Identify the claimed error** — extract the exact error message, status code, and provider/model involved + +#### 5b. Check Information Sufficiency + +Verify the issue contains enough to act on: - [ ] Clear description of the problem -- [ ] Steps to reproduce -- [ ] Error messages or logs +- [ ] Steps to reproduce OR error logs +- [ ] Provider/model/version information - [ ] Expected vs actual behavior -#### 5b. If Information Is INSUFFICIENT +#### 5c. Determine Issue Disposition -Call the `/issue-triage` workflow (located at `~/.gemini/antigravity/global_workflows/issue-triage.md`): -// turbo +For each bug, classify into one of 5 actions: -- Post a comment asking for more details using `gh issue comment` -- Add `needs-info` label using `gh issue edit` -- Mark this issue as **DEFERRED** and move to the next one +| Disposition | When to Apply | Action | +| ---------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------- | +| **✅ CLOSE — Already Fixed** | Owner responded with fix + no user follow-up, OR community confirmed fix | Close with comment citing which version fixed it | +| **✅ CLOSE — Duplicate** | Bot flagged >85% similarity + user provides no new info | Close referencing the original issue | +| **📝 RESPOND — Needs Info** | Issue is real but missing critical reproduction details | Comment asking for specifics per `/issue-triage` | +| **📝 RESPOND — User Config** | Error is caused by unsupported env (Node version, wrong model path, missing API enablement) | Comment explaining the user-side fix | +| **🔧 FIX — Code Change** | Root cause is confirmed in the codebase | Research, implement, test, commit on release branch | -#### 5c. If Information Is SUFFICIENT +#### 5d. For "FIX — Code Change" Issues -Proceed with resolution **on the release branch**: +Before coding, perform deep source analysis: -1. **Research** — Search the codebase for files related to the issue -2. **Root Cause** — Identify the root cause by reading the relevant source files -3. **Implement Fix** — Apply the fix following existing code patterns and conventions -4. **Test** — Build the project and run tests to verify the fix -5. **Commit** — Commit with message format: `fix: (#)` +1. **Search the codebase** — `grep_search` for error strings, relevant function names, affected files +2. **Search the web** — for upstream API changes, SDK updates, or breaking changes that explain the bug +3. **Read the full source file** — don't rely on grep snippets; understand the surrounding logic +4. **Verify the root cause** — confirm the bug is reproducible based on the code, not just a user misconfiguration +5. **Implement the fix** — follow existing code patterns and conventions +6. **Run tests** — `node --import tsx/esm --test tests/unit/*.test.mjs` (must pass 100%) +7. **Commit** — `fix: (#)` -> **⚠️ Do NOT create a separate branch.** All commits go directly on the release branch. +#### 5e. For "RESPOND" Issues + +Post a substantive comment that: + +- Acknowledges the specific error they reported +- Explains the likely root cause +- Provides concrete steps to resolve (version upgrade, env var fix, model path correction) +- Asks for follow-up info if needed + +**Do NOT post generic template responses.** Every comment should reference the user's specific error messages and environment. ### 6. Generate Report & Wait for Validation Present a summary report to the user via `notify_user` with `BlockedOnUser: true`: -| Issue | Title | Status | Action | -| ----- | ----- | ------------- | ----------------------------- | -| #N | Title | ✅ Ready | Files changed (not committed) | -| #N | Title | ❓ Needs Info | Triage comment posted | -| #N | Title | ⏭️ Skipped | Feature request / not a bug | +| Issue | Title | Status | Action | +| ----- | ----- | ------------- | --------------------------- | +| #N | Title | ✅ Closed | Already fixed / duplicate | +| #N | Title | 🔧 Fixed | Code fix applied | +| #N | Title | 📝 Responded | Guidance comment posted | +| #N | Title | ❓ Needs Info | Triage comment posted | +| #N | Title | ⏭️ Skipped | Feature request / not a bug | -> **⚠️ IMPORTANT**: Do NOT commit, close issues, or generate releases at this step. +> **⚠️ IMPORTANT**: Do NOT merge or generate releases at this step. > Wait for the user to review the changes and respond with **OK** before proceeding. - If the user says **OK** or approves → Proceed to step 7 diff --git a/open-sse/translator/request/claude-to-gemini.ts b/open-sse/translator/request/claude-to-gemini.ts index ae34b6cd..76c53084 100644 --- a/open-sse/translator/request/claude-to-gemini.ts +++ b/open-sse/translator/request/claude-to-gemini.ts @@ -147,6 +147,23 @@ export function claudeToGeminiRequest(model, body, stream) { if (parts.length > 0) { // Map Claude roles to Gemini roles const geminiRole = msg.role === "assistant" ? "model" : "user"; + + // Gemini 3+ requires thoughtSignature as a sibling part in model content + // that contains functionCall parts. Inject if not already present from + // a thinking block. (#927) + if (geminiRole === "model") { + const hasFunctionCall = parts.some((p) => p.functionCall); + const hasSignature = parts.some((p) => p.thoughtSignature); + if (hasFunctionCall && !hasSignature) { + // Insert before the first functionCall part + const fcIndex = parts.findIndex((p) => p.functionCall); + parts.splice(fcIndex, 0, { + thoughtSignature: DEFAULT_THINKING_GEMINI_SIGNATURE, + text: "", + }); + } + } + result.contents.push({ role: geminiRole, parts }); } } diff --git a/open-sse/translator/request/openai-to-gemini.ts b/open-sse/translator/request/openai-to-gemini.ts index e20ff25d..eafdada2 100644 --- a/open-sse/translator/request/openai-to-gemini.ts +++ b/open-sse/translator/request/openai-to-gemini.ts @@ -168,14 +168,25 @@ function openaiToGeminiBase(model, body, stream) { } if (msg.tool_calls && Array.isArray(msg.tool_calls)) { + // Gemini 3+ requires thoughtSignature as a sibling part in model content + // that contains functionCall parts. If no reasoning_content was present + // (which already injects the signature above), inject one now. (#927) + const hasSignatureAlready = parts.some((p) => p.thoughtSignature); + if (!hasSignatureAlready) { + parts.push({ + thoughtSignature: DEFAULT_THINKING_GEMINI_SIGNATURE, + text: "", + }); + } + const toolCallIds = []; for (const tc of msg.tool_calls) { if (tc.type !== "function") continue; const args = tryParseJSON(tc.function?.arguments || "{}"); - // Do NOT include thoughtSignature on functionCall parts — it is only valid - // on thinking/reasoning parts and causes HTTP 400 "invalid argument" from the - // Gemini API when present on a functionCall part (#725). + // Do NOT include thoughtSignature ON the functionCall part itself — it is + // only valid as a separate sibling part. Including it inside functionCall + // causes HTTP 400 "invalid argument" (#725). parts.push({ functionCall: { id: tc.id, diff --git a/package-lock.json b/package-lock.json index bbab7443..46faa065 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "3.4.5", + "version": "3.4.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "3.4.5", + "version": "3.4.6", "hasInstallScript": true, "license": "MIT", "workspaces": [ @@ -21047,7 +21047,7 @@ }, "open-sse": { "name": "@omniroute/open-sse", - "version": "3.4.4" + "version": "3.4.5" } } } diff --git a/package.json b/package.json index 37164856..a135cc3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "3.4.5", + "version": "3.4.6", "description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.", "type": "module", "bin": { diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 1e0ffaea..66888bfd 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -156,6 +156,8 @@ "playground": "Playground", "searchTools": "Search Tools", "agents": "Agents", + "memory": "Memory", + "skills": "Skills", "docs": "Docs", "issues": "Issues", "endpoints": "Endpoints", @@ -3028,4 +3030,4 @@ "expires": "Expires", "actions": "Actions" } -} \ No newline at end of file +} diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index 51fe2453..53612f82 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -156,6 +156,8 @@ "playground": "Playground", "searchTools": "Search Tools", "agents": "Agentes", + "memory": "Memória", + "skills": "Habilidades", "docs": "Documentação", "issues": "Problemas", "endpoints": "Endpoints", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 78ac4eaa..98ed5304 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -156,6 +156,8 @@ "playground": "Playground", "searchTools": "Search Tools", "agents": "Agentes", + "memory": "Memória", + "skills": "Habilidades", "docs": "Documentos", "issues": "Problemas", "endpoints": "Endpoints", diff --git a/src/shared/constants/sidebarVisibility.ts b/src/shared/constants/sidebarVisibility.ts index 1b318784..c13d25c4 100644 --- a/src/shared/constants/sidebarVisibility.ts +++ b/src/shared/constants/sidebarVisibility.ts @@ -11,6 +11,8 @@ export const HIDEABLE_SIDEBAR_ITEM_IDS = [ "cache", "cli-tools", "agents", + "memory", + "skills", "translator", "playground", "media", @@ -60,6 +62,8 @@ const PRIMARY_SIDEBAR_ITEMS: readonly SidebarItemDefinition[] = [ const CLI_SIDEBAR_ITEMS: readonly SidebarItemDefinition[] = [ { id: "cli-tools", href: "/dashboard/cli-tools", i18nKey: "cliToolsShort", icon: "terminal" }, { id: "agents", href: "/dashboard/agents", i18nKey: "agents", icon: "smart_toy" }, + { id: "memory", href: "/dashboard/memory", i18nKey: "memory", icon: "psychology" }, + { id: "skills", href: "/dashboard/skills", i18nKey: "skills", icon: "auto_fix_high" }, ]; const DEBUG_SIDEBAR_ITEMS: readonly SidebarItemDefinition[] = [