feat: update webui extensions, models, and agent config
This commit is contained in:
@@ -125,6 +125,21 @@ export const IMAGE_MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"microsoft/mai-image-2.5": {
|
||||
id: "microsoft/mai-image-2.5",
|
||||
name: "Microsoft: MAI-Image-2.5",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 5,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"openai/gpt-5-image": {
|
||||
id: "openai/gpt-5-image",
|
||||
name: "OpenAI: GPT-5 Image",
|
||||
@@ -425,6 +440,36 @@ export const IMAGE_MODELS = {
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"sourceful/riverflow-v2.5-fast": {
|
||||
id: "sourceful/riverflow-v2.5-fast",
|
||||
name: "Sourceful: Riverflow V2.5 Fast",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"sourceful/riverflow-v2.5-pro": {
|
||||
id: "sourceful/riverflow-v2.5-pro",
|
||||
name: "Sourceful: Riverflow V2.5 Pro",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"x-ai/grok-imagine-image-quality": {
|
||||
id: "x-ai/grok-imagine-image-quality",
|
||||
name: "xAI: Grok Imagine Image Quality",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -126,9 +126,9 @@ describe("Context overflow error handling", () => {
|
||||
describe("GitHub Copilot (OAuth)", () => {
|
||||
// OpenAI model via Copilot
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should detect overflow via isContextOverflow",
|
||||
"claude-sonnet-4.6 - should detect overflow via isContextOverflow",
|
||||
async () => {
|
||||
const model = getModel("github-copilot", "gpt-4o");
|
||||
const model = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
const result = await testContextOverflow(model, githubCopilotToken!);
|
||||
logResult(result);
|
||||
|
||||
@@ -297,8 +297,8 @@ describe("Context overflow error handling", () => {
|
||||
// =============================================================================
|
||||
|
||||
describe.skipIf(!process.env.CEREBRAS_API_KEY)("Cerebras", () => {
|
||||
it("qwen-3-235b - should detect overflow via isContextOverflow", async () => {
|
||||
const model = getModel("cerebras", "qwen-3-235b-a22b-instruct-2507");
|
||||
it("gpt-oss-120b - should detect overflow via isContextOverflow", async () => {
|
||||
const model = getModel("cerebras", "gpt-oss-120b");
|
||||
const result = await testContextOverflow(model, process.env.CEREBRAS_API_KEY!);
|
||||
logResult(result);
|
||||
|
||||
|
||||
@@ -630,37 +630,37 @@ describe("AI Providers Empty Message Tests", () => {
|
||||
|
||||
describe("GitHub Copilot Provider Empty Messages", () => {
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle empty content array",
|
||||
"claude-sonnet-4.6 - should handle empty content array",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testEmptyMessage(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle empty string content",
|
||||
"claude-sonnet-4.6 - should handle empty string content",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testEmptyStringMessage(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle whitespace-only content",
|
||||
"claude-sonnet-4.6 - should handle whitespace-only content",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testWhitespaceOnlyMessage(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle empty assistant message in conversation",
|
||||
"claude-sonnet-4.6 - should handle empty assistant message in conversation",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testEmptyAssistantMessage(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("Fireworks models", () => {
|
||||
});
|
||||
|
||||
it("registers the Fire Pass turbo router model", () => {
|
||||
const model = getModel("fireworks", "accounts/fireworks/routers/kimi-k2p5-turbo");
|
||||
const model = getModel("fireworks", "accounts/fireworks/routers/kimi-k2p6-turbo");
|
||||
|
||||
expect(model).toBeDefined();
|
||||
expect(model.api).toBe("anthropic-messages");
|
||||
|
||||
@@ -443,19 +443,19 @@ describe("Tool Results with Images", () => {
|
||||
|
||||
describe("GitHub Copilot Provider", () => {
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle tool result with only image",
|
||||
"claude-sonnet-4.6 - should handle tool result with only image",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await handleToolWithImageResult(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle tool result with text and image",
|
||||
"claude-sonnet-4.6 - should handle tool result with text and image",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await handleToolWithTextAndImageResult(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
@@ -149,7 +149,7 @@ describe("Token Statistics on Abort", () => {
|
||||
});
|
||||
|
||||
describe.skipIf(!process.env.CEREBRAS_API_KEY)("Cerebras Provider", () => {
|
||||
const llm = getModel("cerebras", "qwen-3-235b-a22b-instruct-2507");
|
||||
const llm = getModel("cerebras", "gpt-oss-120b");
|
||||
|
||||
it("should include token stats when aborted mid-stream", { retry: 3, timeout: 30000 }, async () => {
|
||||
await testTokensOnAbort(llm);
|
||||
@@ -289,10 +289,10 @@ describe("Token Statistics on Abort", () => {
|
||||
|
||||
describe("GitHub Copilot Provider", () => {
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should include token stats when aborted mid-stream",
|
||||
"claude-sonnet-4.6 - should include token stats when aborted mid-stream",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testTokensOnAbort(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
@@ -297,10 +297,10 @@ describe("Tool Call Without Result Tests", () => {
|
||||
|
||||
describe("GitHub Copilot Provider", () => {
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should filter out tool calls without corresponding tool results",
|
||||
"claude-sonnet-4.6 - should filter out tool calls without corresponding tool results",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const model = getModel("github-copilot", "gpt-4o");
|
||||
const model = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testToolCallWithoutResult(model, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
@@ -666,10 +666,10 @@ describe("totalTokens field", () => {
|
||||
);
|
||||
|
||||
it(
|
||||
"google/gemini-2.0-flash-001 - should return totalTokens equal to sum of components",
|
||||
"google/gemini-2.5-flash - should return totalTokens equal to sum of components",
|
||||
{ retry: 3, timeout: 60000 },
|
||||
async () => {
|
||||
const llm = getModel("openrouter", "google/gemini-2.0-flash-001");
|
||||
const llm = getModel("openrouter", "google/gemini-2.5-flash");
|
||||
|
||||
console.log(`\nOpenRouter / ${llm.id}:`);
|
||||
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: process.env.OPENROUTER_API_KEY });
|
||||
@@ -706,10 +706,10 @@ describe("totalTokens field", () => {
|
||||
|
||||
describe("GitHub Copilot (OAuth)", () => {
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should return totalTokens equal to sum of components",
|
||||
"claude-sonnet-4.6 - should return totalTokens equal to sum of components",
|
||||
{ retry: 3, timeout: 60000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
|
||||
console.log(`\nGitHub Copilot / ${llm.id}:`);
|
||||
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: githubCopilotToken });
|
||||
|
||||
@@ -396,28 +396,28 @@ describe("AI Providers Unicode Surrogate Pair Tests", () => {
|
||||
|
||||
describe("GitHub Copilot Provider Unicode Handling", () => {
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle emoji in tool results",
|
||||
"claude-sonnet-4.6 - should handle emoji in tool results",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testEmojiInToolResults(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle real-world LinkedIn comment data with emoji",
|
||||
"claude-sonnet-4.6 - should handle real-world LinkedIn comment data with emoji",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testRealWorldLinkedInData(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(!githubCopilotToken)(
|
||||
"gpt-4o - should handle unpaired high surrogate (0xD83D) in tool results",
|
||||
"claude-sonnet-4.6 - should handle unpaired high surrogate (0xD83D) in tool results",
|
||||
{ retry: 3, timeout: 30000 },
|
||||
async () => {
|
||||
const llm = getModel("github-copilot", "gpt-4o");
|
||||
const llm = getModel("github-copilot", "claude-sonnet-4.6");
|
||||
await testUnpairedHighSurrogate(llm, { apiKey: githubCopilotToken });
|
||||
},
|
||||
);
|
||||
|
||||
@@ -426,7 +426,15 @@ Response:
|
||||
Execute a shell command and add output to conversation context.
|
||||
|
||||
```json
|
||||
{"type": "bash", "command": "ls -la"}
|
||||
{"type": "bash", "command": "ls -la", "excludeFromContext": false}
|
||||
```
|
||||
|
||||
Optional `excludeFromContext` (default `false`): when `true`, the command output is shown in the UI but excluded from the LLM context on the next prompt (equivalent to `!!cmd` in the TUI).
|
||||
|
||||
During execution, `bash_update` events stream partial stdout:
|
||||
|
||||
```json
|
||||
{"type": "bash_update", "command": "ls -la", "partialOutput": "total 48\n"}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
6
packages/coding-agent/npm-shrinkwrap.json
generated
6
packages/coding-agent/npm-shrinkwrap.json
generated
@@ -1321,8 +1321,7 @@
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
},
|
||||
"peer": true
|
||||
}
|
||||
},
|
||||
"node_modules/json-bigint": {
|
||||
"version": "1.0.0",
|
||||
@@ -1775,8 +1774,7 @@
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
},
|
||||
"peer": true
|
||||
}
|
||||
},
|
||||
"node_modules/zod-to-json-schema": {
|
||||
"version": "3.25.2",
|
||||
|
||||
@@ -546,7 +546,15 @@ export async function runRpcMode(runtimeHost: AgentSessionRuntime): Promise<neve
|
||||
// =================================================================
|
||||
|
||||
case "bash": {
|
||||
const result = await session.executeBash(command.command);
|
||||
let partialOutput = "";
|
||||
const result = await session.executeBash(
|
||||
command.command,
|
||||
(chunk) => {
|
||||
partialOutput += chunk;
|
||||
output({ type: "bash_update", command: command.command, partialOutput });
|
||||
},
|
||||
{ excludeFromContext: command.excludeFromContext },
|
||||
);
|
||||
return success(id, "bash", result);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export type RpcCommand =
|
||||
| { id?: string; type: "abort_retry" }
|
||||
|
||||
// Bash
|
||||
| { id?: string; type: "bash"; command: string }
|
||||
| { id?: string; type: "bash"; command: string; excludeFromContext?: boolean }
|
||||
| { id?: string; type: "abort_bash" }
|
||||
|
||||
// Session
|
||||
|
||||
Reference in New Issue
Block a user