feat(agent): capability registry, Pi AgentRuntimePort, fake model provider and redaction guard (W1-5)
- CapabilityRegistry: descriptor(id/version/schema/scope/risk/idempotent/preview/replay), invoke = scope limit -> input schema -> server-side authorize -> idempotency key -> handler -> output schema -> audit; capability id <-> tool name mapping (download.submit <-> download__submit) - PiAgentRuntime (pi-agent-core AgentHarness 0.87.1): whitelist tools + before_tool re-check, redacted event stream, JSONL session at sessionDir/<runId>.jsonl, resume/abort/compact, tool-call/duration/token/cost budgets -> abort + run_failed(budget) - AgentSettings -> pi-ai createProvider (anthropic / openai-compatible), compaction mapping - FakeModelProvider + createFakeRuntime (scripted, transcript-derived, survives crash/resume) - buildSystemPrompt, redactForModel; 27 tests incl. SIGKILL + resume Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
1262340856
commit
9c881e737f
24 files changed
+2419
-8
No files matched your search
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describeSettings, resolveAgentSettings } from "../src";
|
||||
import { compactionFromSettings, resolveModelFromSettings } from "../src/pi/model";
|
||||
|
||||
describe("AgentSettings → pi-ai", () => {
|
||||
it("anthropic:baseUrl 去掉 /v1,上下文预算即 contextWindow,apiKey 只在 resolve 时给出", async () => {
|
||||
const s = resolveAgentSettings({
|
||||
provider: "anthropic",
|
||||
baseUrl: "https://proxy.local/v1/",
|
||||
apiKey: "sk-ant-secret-value",
|
||||
model: "claude-sonnet-4-5",
|
||||
thinkingLevel: "high",
|
||||
contextBudgetTokens: 100_000,
|
||||
});
|
||||
const { models, model } = resolveModelFromSettings(s);
|
||||
expect(model).toMatchObject({
|
||||
api: "anthropic-messages",
|
||||
baseUrl: "https://proxy.local",
|
||||
id: "claude-sonnet-4-5",
|
||||
contextWindow: 100_000,
|
||||
reasoning: true,
|
||||
});
|
||||
expect(JSON.stringify(model)).not.toContain("sk-ant-secret-value");
|
||||
const auth = await models.getAuth(model);
|
||||
expect(JSON.stringify(auth)).toContain("sk-ant-secret-value");
|
||||
expect(JSON.stringify(describeSettings(s))).not.toContain("sk-ant-secret-value");
|
||||
expect(s.subagentsEnabled).toBe(false);
|
||||
});
|
||||
|
||||
it("openai-compatible 需要带 /v1 的 baseUrl;压缩模式映射", () => {
|
||||
const base = { provider: "openai-compatible" as const, apiKey: "k", model: "qwen3" };
|
||||
expect(() => resolveModelFromSettings(resolveAgentSettings(base))).toThrow(/baseUrl/);
|
||||
const s = resolveAgentSettings({
|
||||
...base,
|
||||
baseUrl: "http://llm.local/v1",
|
||||
contextBudgetTokens: 32_000,
|
||||
compaction: { mode: "threshold", threshold: 0.75 },
|
||||
});
|
||||
const { model } = resolveModelFromSettings(s);
|
||||
expect(model).toMatchObject({ api: "openai-completions", baseUrl: "http://llm.local/v1", reasoning: false });
|
||||
expect(compactionFromSettings(s, 32_000)).toEqual({ enabled: true, reserveTokens: 8000, keepRecentTokens: 8000 });
|
||||
const manual = resolveAgentSettings({ ...s, compaction: { mode: "manual", threshold: 0.8 } });
|
||||
expect(compactionFromSettings(manual, 32_000).enabled).toBe(false);
|
||||
expect(() => resolveAgentSettings({ ...base, model: "" })).toThrow();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user