
























@@ -60,6 +60,52 @@ function createLogger(): RuntimeLogger {
6060};
6161}
626263+type MockCalls = {
64+mock: { calls: unknown[][] };
65+};
66+67+function requireRecord(value: unknown, label: string): Record<string, unknown> {
68+expect(typeof value, label).toBe("object");
69+expect(value, label).not.toBeNull();
70+return value as Record<string, unknown>;
71+}
72+73+function requireArray(value: unknown, label: string): unknown[] {
74+expect(Array.isArray(value), label).toBe(true);
75+return value as unknown[];
76+}
77+78+function expectFields(record: Record<string, unknown>, expected: Record<string, unknown>) {
79+for (const [key, value] of Object.entries(expected)) {
80+expect(record[key], key).toEqual(value);
81+}
82+}
83+84+function expectSingleCallFirstArg(
85+mock: MockCalls,
86+expected: Record<string, unknown>,
87+label = "mock first argument",
88+): Record<string, unknown> {
89+expect(mock.mock.calls).toHaveLength(1);
90+const [firstArg] = mock.mock.calls[0] ?? [];
91+const record = requireRecord(firstArg, label);
92+expectFields(record, expected);
93+return record;
94+}
95+96+function expectSingleLogPayload(
97+loggerMethod: MockCalls,
98+message: string,
99+expected: Record<string, unknown>,
100+): Record<string, unknown> {
101+expect(loggerMethod.mock.calls).toHaveLength(1);
102+const [actualMessage, payload] = loggerMethod.mock.calls[0] ?? [];
103+expect(actualMessage).toBe(message);
104+const payloadRecord = requireRecord(payload, "log payload");
105+expectFields(payloadRecord, expected);
106+return payloadRecord;
107+}
108+63109function primeCompletionMocks() {
64110hoisted.prepareSimpleCompletionModelForAgent.mockResolvedValue(createPreparedModel());
65111hoisted.resolveSimpleCompletionSelectionForAgent.mockImplementation(
@@ -112,15 +158,13 @@ describe("runtime.llm.complete", () => {
112158purpose: "memory-maintenance",
113159});
114160115-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
116-expect.objectContaining({
117- cfg,
118-agentId: "ada",
119-allowMissingApiKeyModes: ["aws-sdk"],
120-}),
121-);
161+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
162+ cfg,
163+agentId: "ada",
164+allowMissingApiKeyModes: ["aws-sdk"],
165+});
122166expect(result.agentId).toBe("ada");
123-expect(result.audit).toMatchObject({
167+expectFields(requireRecord(result.audit, "audit"), {
124168caller: { kind: "context-engine", id: "context-engine.after-turn" },
125169purpose: "memory-maintenance",
126170sessionKey: "agent:ada:session:abc",
@@ -220,13 +264,11 @@ describe("runtime.llm.complete", () => {
220264messages: [{ role: "user", content: "summarize" }],
221265});
222266223-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
224-expect.objectContaining({
225-agentId: "main",
226-modelRef: "openai-codex/gpt-5.4-mini",
227-}),
228-);
229-expect(result.audit).toMatchObject({
267+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
268+agentId: "main",
269+modelRef: "openai-codex/gpt-5.4-mini",
270+});
271+expectFields(requireRecord(result.audit, "audit"), {
230272caller: { kind: "context-engine", id: "context-engine.compaction" },
231273sessionKey: "agent:main:session:abc",
232274});
@@ -297,11 +339,9 @@ describe("runtime.llm.complete", () => {
297339kind: "context-engine",
298340id: "context-engine.compaction",
299341});
300-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
301-expect.objectContaining({
302-modelRef: "openai-codex/gpt-5.4-mini",
303-}),
304-);
342+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
343+modelRef: "openai-codex/gpt-5.4-mini",
344+});
305345});
306346307347it("allows the bound context-engine agent and denies cross-agent overrides", async () => {
@@ -315,11 +355,9 @@ describe("runtime.llm.complete", () => {
315355agentId: "main",
316356messages: [{ role: "user", content: "summarize" }],
317357});
318-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
319-expect.objectContaining({
320-agentId: "main",
321-}),
322-);
358+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
359+agentId: "main",
360+});
323361324362await expect(
325363runtimeContext.llm!.complete({
@@ -346,12 +384,10 @@ describe("runtime.llm.complete", () => {
346384messages: [{ role: "user", content: "draft" }],
347385});
348386349-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
350-expect.objectContaining({
351- cfg,
352-agentId: "worker",
353-}),
354-);
387+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
388+ cfg,
389+agentId: "worker",
390+});
355391});
356392357393it("allows host model overrides only when explicit authority allowlists the model", async () => {
@@ -369,11 +405,9 @@ describe("runtime.llm.complete", () => {
369405model: "openai/gpt-5.4",
370406messages: [{ role: "user", content: "Ping" }],
371407});
372-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
373-expect.objectContaining({
374-modelRef: "openai/gpt-5.4",
375-}),
376-);
408+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
409+modelRef: "openai/gpt-5.4",
410+});
377411378412await expect(
379413llm.complete({
@@ -404,43 +438,49 @@ describe("runtime.llm.complete", () => {
404438purpose: "test-purpose",
405439});
406440407-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
408-expect.objectContaining({ cfg, agentId: "main" }),
409-);
410-expect(hoisted.completeWithPreparedSimpleCompletionModel).toHaveBeenCalledWith(
411-expect.objectContaining({
441+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
442+ cfg,
443+agentId: "main",
444+});
445+const completionArg = expectSingleCallFirstArg(
446+hoisted.completeWithPreparedSimpleCompletionModel,
447+{
412448 cfg,
413-context: expect.objectContaining({
414-systemPrompt: "Be terse.",
415-messages: [expect.objectContaining({ role: "user", content: "Ping" })],
416-}),
417-options: expect.objectContaining({
418-maxTokens: 64,
419-temperature: 0.2,
420-}),
421-}),
449+},
422450);
423-expect(result).toMatchObject({
451+const context = requireRecord(completionArg.context, "completion context");
452+expect(context.systemPrompt).toBe("Be terse.");
453+const [message] = requireArray(context.messages, "completion messages");
454+expectFields(requireRecord(message, "completion message"), {
455+role: "user",
456+content: "Ping",
457+});
458+expectFields(requireRecord(completionArg.options, "completion options"), {
459+maxTokens: 64,
460+temperature: 0.2,
461+});
462+expectFields(requireRecord(result, "completion result"), {
424463text: "done",
425464provider: "openai",
426465model: "gpt-5.5",
427-usage: {
428-inputTokens: 11,
429-outputTokens: 7,
430-cacheReadTokens: 5,
431-cacheWriteTokens: 2,
432-totalTokens: 25,
433-costUsd: 0.0042,
434-},
435466});
436-expect(logger.info).toHaveBeenCalledWith(
467+expectFields(requireRecord(result.usage, "completion usage"), {
468+inputTokens: 11,
469+outputTokens: 7,
470+cacheReadTokens: 5,
471+cacheWriteTokens: 2,
472+totalTokens: 25,
473+costUsd: 0.0042,
474+});
475+const logPayload = expectSingleLogPayload(
476+logger.info as unknown as MockCalls,
437477"plugin llm completion",
438-expect.objectContaining({
478+{
439479caller: { kind: "host", id: "runtime-test" },
440480purpose: "test-purpose",
441-usage: expect.objectContaining({ costUsd: 0.0042 }),
442-}),
481+},
443482);
483+expectFields(requireRecord(logPayload.usage, "log usage"), { costUsd: 0.0042 });
444484});
445485446486it("uses scoped plugin identity and ignores caller-shaped spoofing input", async () => {
@@ -463,13 +503,10 @@ describe("runtime.llm.complete", () => {
463503);
464504465505expect(result.audit.caller).toEqual({ kind: "plugin", id: "trusted-plugin" });
466-expect(logger.info).toHaveBeenCalledWith(
467-"plugin llm completion",
468-expect.objectContaining({
469-caller: { kind: "plugin", id: "trusted-plugin" },
470-purpose: "identity-test",
471-}),
472-);
506+expectSingleLogPayload(logger.info as unknown as MockCalls, "plugin llm completion", {
507+caller: { kind: "plugin", id: "trusted-plugin" },
508+purpose: "identity-test",
509+});
473510});
474511475512it("denies plugin model overrides by default", async () => {
@@ -532,11 +569,9 @@ describe("runtime.llm.complete", () => {
532569messages: [{ role: "user", content: "Ping" }],
533570}),
534571);
535-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
536-expect.objectContaining({
537-agentId: "worker",
538-}),
539-);
572+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
573+agentId: "worker",
574+});
540575});
541576542577it("allows plugin model overrides only when configured and allowlisted", async () => {
@@ -565,12 +600,10 @@ describe("runtime.llm.complete", () => {
565600messages: [{ role: "user", content: "Ping" }],
566601}),
567602);
568-expect(hoisted.prepareSimpleCompletionModelForAgent).toHaveBeenCalledWith(
569-expect.objectContaining({
570-agentId: "main",
571-modelRef: "openai/gpt-5.4",
572-}),
573-);
603+expectSingleCallFirstArg(hoisted.prepareSimpleCompletionModelForAgent, {
604+agentId: "main",
605+modelRef: "openai/gpt-5.4",
606+});
574607575608await expect(
576609withPluginRuntimePluginIdScope("trusted-plugin", () =>
@@ -599,9 +632,8 @@ describe("runtime.llm.complete", () => {
599632}),
600633).rejects.toThrow("Plugin LLM completion denied: not trusted");
601634expect(hoisted.prepareSimpleCompletionModelForAgent).not.toHaveBeenCalled();
602-expect(logger.warn).toHaveBeenCalledWith(
603-"plugin llm completion denied",
604-expect.objectContaining({ reason: "not trusted" }),
605-);
635+expectSingleLogPayload(logger.warn as unknown as MockCalls, "plugin llm completion denied", {
636+reason: "not trusted",
637+});
606638});
607639});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。