| import { beforeEach, describe, expect, it, vi } from "vitest"; |
| import type { FollowupRun } from "./queue.js"; |
|
|
| const hoisted = vi.hoisted(() => { |
| const resolveRunModelFallbacksOverrideMock = vi.fn(); |
| return { resolveRunModelFallbacksOverrideMock }; |
| }); |
|
|
| vi.mock("../../agents/agent-scope.js", () => ({ |
| resolveRunModelFallbacksOverride: (...args: unknown[]) => |
| hoisted.resolveRunModelFallbacksOverrideMock(...args), |
| })); |
|
|
| const { |
| buildThreadingToolContext, |
| buildEmbeddedRunBaseParams, |
| buildEmbeddedRunContexts, |
| resolveModelFallbackOptions, |
| resolveProviderScopedAuthProfile, |
| } = await import("./agent-runner-utils.js"); |
|
|
| function makeRun(overrides: Partial<FollowupRun["run"]> = {}): FollowupRun["run"] { |
| return { |
| sessionId: "session-1", |
| agentId: "agent-1", |
| config: { models: { providers: {} } }, |
| provider: "openai", |
| model: "gpt-4.1", |
| agentDir: "/tmp/agent", |
| sessionKey: "agent:test:session", |
| sessionFile: "/tmp/session.json", |
| workspaceDir: "/tmp/workspace", |
| skillsSnapshot: [], |
| ownerNumbers: ["+15550001"], |
| enforceFinalTag: false, |
| thinkLevel: "medium", |
| verboseLevel: "off", |
| reasoningLevel: "none", |
| execOverrides: {}, |
| bashElevated: false, |
| timeoutMs: 60_000, |
| ...overrides, |
| } as unknown as FollowupRun["run"]; |
| } |
|
|
| describe("agent-runner-utils", () => { |
| beforeEach(() => { |
| hoisted.resolveRunModelFallbacksOverrideMock.mockClear(); |
| }); |
|
|
| it("resolves model fallback options from run context", () => { |
| hoisted.resolveRunModelFallbacksOverrideMock.mockReturnValue(["fallback-model"]); |
| const run = makeRun(); |
|
|
| const resolved = resolveModelFallbackOptions(run); |
|
|
| expect(hoisted.resolveRunModelFallbacksOverrideMock).toHaveBeenCalledWith({ |
| cfg: run.config, |
| agentId: run.agentId, |
| sessionKey: run.sessionKey, |
| }); |
| expect(resolved).toEqual({ |
| cfg: run.config, |
| provider: run.provider, |
| model: run.model, |
| agentDir: run.agentDir, |
| fallbacksOverride: ["fallback-model"], |
| }); |
| }); |
|
|
| it("passes through missing agentId for helper-based fallback resolution", () => { |
| hoisted.resolveRunModelFallbacksOverrideMock.mockReturnValue(["fallback-model"]); |
| const run = makeRun({ agentId: undefined }); |
|
|
| const resolved = resolveModelFallbackOptions(run); |
|
|
| expect(hoisted.resolveRunModelFallbacksOverrideMock).toHaveBeenCalledWith({ |
| cfg: run.config, |
| agentId: undefined, |
| sessionKey: run.sessionKey, |
| }); |
| expect(resolved.fallbacksOverride).toEqual(["fallback-model"]); |
| }); |
|
|
| it("builds embedded run base params with auth profile and run metadata", () => { |
| const run = makeRun({ enforceFinalTag: true }); |
| const authProfile = resolveProviderScopedAuthProfile({ |
| provider: "openai", |
| primaryProvider: "openai", |
| authProfileId: "profile-openai", |
| authProfileIdSource: "user", |
| }); |
|
|
| const resolved = buildEmbeddedRunBaseParams({ |
| run, |
| provider: "openai", |
| model: "gpt-4.1-mini", |
| runId: "run-1", |
| authProfile, |
| }); |
|
|
| expect(resolved).toMatchObject({ |
| sessionFile: run.sessionFile, |
| workspaceDir: run.workspaceDir, |
| agentDir: run.agentDir, |
| config: run.config, |
| skillsSnapshot: run.skillsSnapshot, |
| ownerNumbers: run.ownerNumbers, |
| enforceFinalTag: true, |
| provider: "openai", |
| model: "gpt-4.1-mini", |
| authProfileId: "profile-openai", |
| authProfileIdSource: "user", |
| thinkLevel: run.thinkLevel, |
| verboseLevel: run.verboseLevel, |
| reasoningLevel: run.reasoningLevel, |
| execOverrides: run.execOverrides, |
| bashElevated: run.bashElevated, |
| timeoutMs: run.timeoutMs, |
| runId: "run-1", |
| }); |
| }); |
|
|
| it("builds embedded contexts and scopes auth profile by provider", () => { |
| const run = makeRun({ |
| authProfileId: "profile-openai", |
| authProfileIdSource: "auto", |
| }); |
|
|
| const resolved = buildEmbeddedRunContexts({ |
| run, |
| sessionCtx: { |
| Provider: "OpenAI", |
| To: "channel-1", |
| SenderId: "sender-1", |
| }, |
| hasRepliedRef: undefined, |
| provider: "anthropic", |
| }); |
|
|
| expect(resolved.authProfile).toEqual({ |
| authProfileId: undefined, |
| authProfileIdSource: undefined, |
| }); |
| expect(resolved.embeddedContext).toMatchObject({ |
| sessionId: run.sessionId, |
| sessionKey: run.sessionKey, |
| agentId: run.agentId, |
| messageProvider: "openai", |
| messageTo: "channel-1", |
| }); |
| expect(resolved.senderContext).toEqual({ |
| senderId: "sender-1", |
| senderName: undefined, |
| senderUsername: undefined, |
| senderE164: undefined, |
| }); |
| }); |
|
|
| it("prefers OriginatingChannel over Provider for messageProvider", () => { |
| const run = makeRun(); |
|
|
| const resolved = buildEmbeddedRunContexts({ |
| run, |
| sessionCtx: { |
| Provider: "heartbeat", |
| OriginatingChannel: "Telegram", |
| OriginatingTo: "268300329", |
| }, |
| hasRepliedRef: undefined, |
| provider: "openai", |
| }); |
|
|
| expect(resolved.embeddedContext.messageProvider).toBe("telegram"); |
| expect(resolved.embeddedContext.messageTo).toBe("268300329"); |
| }); |
|
|
| it("uses OriginatingTo for threading tool context on telegram native commands", () => { |
| const context = buildThreadingToolContext({ |
| sessionCtx: { |
| Provider: "telegram", |
| To: "slash:8460800771", |
| OriginatingChannel: "telegram", |
| OriginatingTo: "telegram:-1003841603622", |
| MessageThreadId: 928, |
| MessageSid: "2284", |
| }, |
| config: { channels: { telegram: { allowFrom: ["*"] } } }, |
| hasRepliedRef: undefined, |
| }); |
|
|
| expect(context).toMatchObject({ |
| currentChannelId: "telegram:-1003841603622", |
| currentThreadTs: "928", |
| currentMessageId: "2284", |
| }); |
| }); |
|
|
| it("uses OriginatingTo for threading tool context on discord native commands", () => { |
| const context = buildThreadingToolContext({ |
| sessionCtx: { |
| Provider: "discord", |
| To: "slash:1177378744822943744", |
| OriginatingChannel: "discord", |
| OriginatingTo: "channel:123456789012345678", |
| MessageSid: "msg-9", |
| }, |
| config: {}, |
| hasRepliedRef: undefined, |
| }); |
|
|
| expect(context).toMatchObject({ |
| currentChannelId: "channel:123456789012345678", |
| currentMessageId: "msg-9", |
| }); |
| }); |
| }); |
|
|