Merge remote-tracking branch 'origin/main' into pr-586-r2
# Conflicts: # packages/coding-agent/CHANGELOG.md
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { joinPatch } from "@oh-my-pi/pi-coding-agent/commit/git";
|
||||
|
||||
describe("joinPatch", () => {
|
||||
test("preserves space character in empty context line at end of patch", () => {
|
||||
// This simulates a hunk ending with an empty context line represented as " \n"
|
||||
const parts = [
|
||||
"@@ -1,2 +1,2 @@\n",
|
||||
"foo\n",
|
||||
"@@ -10,4 +10,4 @@\n",
|
||||
"line1\n",
|
||||
"-old\n",
|
||||
"+new\n",
|
||||
" \n", // Empty context line = space + newline
|
||||
];
|
||||
|
||||
const result = joinPatch(parts);
|
||||
|
||||
// The result should end with a space character (the empty context line)
|
||||
// but NOT start/end with multiple newlines
|
||||
expect(result.endsWith(" \n")).toBe(true);
|
||||
expect(result.replace(/[ \t]+$/, "")).toEqual(result); // No trailing spaces should be removed
|
||||
});
|
||||
|
||||
test("normalizes multiple trailing newlines in parts", () => {
|
||||
const parts = ["line1\n", "line2\n", "line3"];
|
||||
const result = joinPatch(parts);
|
||||
|
||||
// Should join with single newlines and end with one newline
|
||||
expect(result.endsWith("\n")).toBe(true);
|
||||
});
|
||||
|
||||
test("adds newline to parts that are missing them", () => {
|
||||
const parts = ["line1", "line2"];
|
||||
const result = joinPatch(parts);
|
||||
|
||||
// Should add newlines to both parts
|
||||
expect(result.includes("line1\n")).toBe(true);
|
||||
expect(result.endsWith("line2\n")).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { Effort, type OpenAICompat, type ThinkingConfig } from "@oh-my-pi/pi-ai";
|
||||
import { kNoAuth, MODEL_ROLES, ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
|
||||
import { _resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
||||
import { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
|
||||
import { hookFetch, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
|
||||
@@ -18,6 +19,7 @@ describe("ModelRegistry", () => {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
_resetSettingsForTest();
|
||||
tempDir = path.join(os.tmpdir(), `pi-test-model-registry-${Snowflake.next()}`);
|
||||
fs.mkdirSync(tempDir, { recursive: true });
|
||||
modelsJsonPath = path.join(tempDir, "models.json");
|
||||
@@ -25,6 +27,7 @@ describe("ModelRegistry", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
_resetSettingsForTest();
|
||||
authStorage.close();
|
||||
if (tempDir && fs.existsSync(tempDir)) {
|
||||
fs.rmSync(tempDir, { recursive: true });
|
||||
@@ -1034,6 +1037,38 @@ describe("ModelRegistry", () => {
|
||||
expect(model.baseUrl).toBe(initialBaseUrl);
|
||||
});
|
||||
});
|
||||
|
||||
describe("disabled provider filtering", () => {
|
||||
test("getAvailable and getDiscoverableProviders exclude disabled providers from settings", async () => {
|
||||
writeRawModelsJson({
|
||||
ollama: {
|
||||
baseUrl: "http://127.0.0.1:11434/v1",
|
||||
api: "openai-completions",
|
||||
auth: "none",
|
||||
discovery: { type: "ollama" },
|
||||
},
|
||||
});
|
||||
await authStorage.set("github-copilot", [
|
||||
{
|
||||
type: "oauth",
|
||||
access: "tid=1;proxy-ep=proxy.individual.githubcopilot.com;exp=9999999999",
|
||||
refresh: "refresh-individual",
|
||||
expires: Date.now() + 60_000,
|
||||
},
|
||||
]);
|
||||
await Settings.init({
|
||||
inMemory: true,
|
||||
overrides: {
|
||||
disabledProviders: ["github-copilot", "ollama"],
|
||||
},
|
||||
});
|
||||
|
||||
const registry = new ModelRegistry(authStorage, modelsJsonPath);
|
||||
|
||||
expect(registry.getAvailable().some(model => model.provider === "github-copilot")).toBe(false);
|
||||
expect(registry.getDiscoverableProviders()).not.toContain("ollama");
|
||||
});
|
||||
});
|
||||
describe("runtime discovery", () => {
|
||||
test("auto-discovers ollama models without provider config", async () => {
|
||||
using _hook = hookFetch(input => {
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { hookFetch } from "@oh-my-pi/pi-utils";
|
||||
import { executeCodeSearch } from "../../src/web/search/code-search";
|
||||
|
||||
function getFirstTextContent(result: { content: Array<{ type: string; text?: string }> }): string {
|
||||
const firstContent = result.content[0];
|
||||
if (firstContent?.type === "text") return firstContent.text ?? "";
|
||||
return "";
|
||||
}
|
||||
|
||||
describe("code_search", () => {
|
||||
it("normalizes Exa response and surfaces it as code search result", async () => {
|
||||
using _hook = hookFetch(
|
||||
() =>
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
result: {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Need the official or source-backed way to silence direnv loading output.",
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||
),
|
||||
);
|
||||
|
||||
const result = await executeCodeSearch({ query: "DIRENV_LOG_FORMAT direnv loading silence" });
|
||||
const output = getFirstTextContent(result);
|
||||
expect(output).toContain("Code search via exa");
|
||||
expect(output).toContain("Need the official or source-backed way to silence direnv loading output.");
|
||||
expect(result.details?.provider).toBe("exa");
|
||||
expect(result.details?.response?.sources[0]?.snippet).toContain(
|
||||
"Need the official or source-backed way to silence direnv loading output.",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user