mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 00:35:51 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { mock, describe, expect, test } from "bun:test";
|
||||
import { mock, describe, expect, test } from 'bun:test'
|
||||
|
||||
// Mock heavy deps
|
||||
mock.module("src/utils/model/agent.js", () => ({
|
||||
mock.module('src/utils/model/agent.js', () => ({
|
||||
getDefaultSubagentModel: () => undefined,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/utils/settings/constants.js", () => ({
|
||||
mock.module('src/utils/settings/constants.js', () => ({
|
||||
getSourceDisplayName: (source: string) => source,
|
||||
getSourceDisplayNameLowercase: (source: string) => source,
|
||||
getSourceDisplayNameCapitalized: (source: string) => source,
|
||||
@@ -15,133 +15,131 @@ mock.module("src/utils/settings/constants.js", () => ({
|
||||
parseSettingSourcesFlag: () => [],
|
||||
getEnabledSettingSources: () => [],
|
||||
isSettingSourceEnabled: () => true,
|
||||
SETTING_SOURCES: ["localSettings", "userSettings", "projectSettings"],
|
||||
SOURCES: ["localSettings", "userSettings", "projectSettings"],
|
||||
CLAUDE_CODE_SETTINGS_SCHEMA_URL: "https://json.schemastore.org/claude-code-settings.json",
|
||||
}));
|
||||
SETTING_SOURCES: ['localSettings', 'userSettings', 'projectSettings'],
|
||||
SOURCES: ['localSettings', 'userSettings', 'projectSettings'],
|
||||
CLAUDE_CODE_SETTINGS_SCHEMA_URL:
|
||||
'https://json.schemastore.org/claude-code-settings.json',
|
||||
}))
|
||||
|
||||
const {
|
||||
resolveAgentOverrides,
|
||||
compareAgentsByName,
|
||||
AGENT_SOURCE_GROUPS,
|
||||
} = await import("../agentDisplay");
|
||||
const { resolveAgentOverrides, compareAgentsByName, AGENT_SOURCE_GROUPS } =
|
||||
await import('../agentDisplay')
|
||||
|
||||
function makeAgent(agentType: string, source: string): any {
|
||||
return { agentType, source, name: agentType };
|
||||
return { agentType, source, name: agentType }
|
||||
}
|
||||
|
||||
describe("resolveAgentOverrides", () => {
|
||||
test("marks no overrides when all agents active", () => {
|
||||
const agents = [makeAgent("builder", "userSettings")];
|
||||
const result = resolveAgentOverrides(agents, agents);
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].overriddenBy).toBeUndefined();
|
||||
});
|
||||
describe('resolveAgentOverrides', () => {
|
||||
test('marks no overrides when all agents active', () => {
|
||||
const agents = [makeAgent('builder', 'userSettings')]
|
||||
const result = resolveAgentOverrides(agents, agents)
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].overriddenBy).toBeUndefined()
|
||||
})
|
||||
|
||||
test("marks inactive agent as overridden", () => {
|
||||
test('marks inactive agent as overridden', () => {
|
||||
const allAgents = [
|
||||
makeAgent("builder", "projectSettings"),
|
||||
makeAgent("builder", "userSettings"),
|
||||
];
|
||||
const activeAgents = [makeAgent("builder", "userSettings")];
|
||||
const result = resolveAgentOverrides(allAgents, activeAgents);
|
||||
const projectAgent = result.find(
|
||||
(a: any) => a.source === "projectSettings",
|
||||
);
|
||||
expect(projectAgent?.overriddenBy).toBe("userSettings");
|
||||
});
|
||||
makeAgent('builder', 'projectSettings'),
|
||||
makeAgent('builder', 'userSettings'),
|
||||
]
|
||||
const activeAgents = [makeAgent('builder', 'userSettings')]
|
||||
const result = resolveAgentOverrides(allAgents, activeAgents)
|
||||
const projectAgent = result.find((a: any) => a.source === 'projectSettings')
|
||||
expect(projectAgent?.overriddenBy).toBe('userSettings')
|
||||
})
|
||||
|
||||
test("overriddenBy shows the overriding agent source", () => {
|
||||
const allAgents = [makeAgent("tester", "localSettings")];
|
||||
const activeAgents = [makeAgent("tester", "policySettings")];
|
||||
const result = resolveAgentOverrides(allAgents, activeAgents);
|
||||
expect(result[0].overriddenBy).toBe("policySettings");
|
||||
});
|
||||
test('overriddenBy shows the overriding agent source', () => {
|
||||
const allAgents = [makeAgent('tester', 'localSettings')]
|
||||
const activeAgents = [makeAgent('tester', 'policySettings')]
|
||||
const result = resolveAgentOverrides(allAgents, activeAgents)
|
||||
expect(result[0].overriddenBy).toBe('policySettings')
|
||||
})
|
||||
|
||||
test("deduplicates agents by (agentType, source)", () => {
|
||||
test('deduplicates agents by (agentType, source)', () => {
|
||||
const agents = [
|
||||
makeAgent("builder", "userSettings"),
|
||||
makeAgent("builder", "userSettings"), // duplicate
|
||||
];
|
||||
const result = resolveAgentOverrides(agents, agents.slice(0, 1));
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
makeAgent('builder', 'userSettings'),
|
||||
makeAgent('builder', 'userSettings'), // duplicate
|
||||
]
|
||||
const result = resolveAgentOverrides(agents, agents.slice(0, 1))
|
||||
expect(result).toHaveLength(1)
|
||||
})
|
||||
|
||||
test("preserves agent definition properties", () => {
|
||||
const agents = [{ agentType: "a", source: "userSettings", name: "Agent A" }] as any[];
|
||||
const result = resolveAgentOverrides(agents, agents);
|
||||
expect((result[0] as any).name).toBe("Agent A");
|
||||
expect(result[0].agentType).toBe("a");
|
||||
});
|
||||
|
||||
test("handles empty arrays", () => {
|
||||
expect(resolveAgentOverrides([], [])).toEqual([]);
|
||||
});
|
||||
|
||||
test("handles agent from git worktree (duplicate detection)", () => {
|
||||
test('preserves agent definition properties', () => {
|
||||
const agents = [
|
||||
makeAgent("builder", "projectSettings"),
|
||||
makeAgent("builder", "projectSettings"),
|
||||
makeAgent("builder", "localSettings"),
|
||||
];
|
||||
const result = resolveAgentOverrides(agents, agents.slice(0, 1));
|
||||
{ agentType: 'a', source: 'userSettings', name: 'Agent A' },
|
||||
] as any[]
|
||||
const result = resolveAgentOverrides(agents, agents)
|
||||
expect((result[0] as any).name).toBe('Agent A')
|
||||
expect(result[0].agentType).toBe('a')
|
||||
})
|
||||
|
||||
test('handles empty arrays', () => {
|
||||
expect(resolveAgentOverrides([], [])).toEqual([])
|
||||
})
|
||||
|
||||
test('handles agent from git worktree (duplicate detection)', () => {
|
||||
const agents = [
|
||||
makeAgent('builder', 'projectSettings'),
|
||||
makeAgent('builder', 'projectSettings'),
|
||||
makeAgent('builder', 'localSettings'),
|
||||
]
|
||||
const result = resolveAgentOverrides(agents, agents.slice(0, 1))
|
||||
// Deduped: projectSettings appears once, localSettings once
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
expect(result).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe("compareAgentsByName", () => {
|
||||
test("sorts alphabetically ascending", () => {
|
||||
const a = makeAgent("alpha", "userSettings");
|
||||
const b = makeAgent("beta", "userSettings");
|
||||
expect(compareAgentsByName(a, b)).toBeLessThan(0);
|
||||
});
|
||||
describe('compareAgentsByName', () => {
|
||||
test('sorts alphabetically ascending', () => {
|
||||
const a = makeAgent('alpha', 'userSettings')
|
||||
const b = makeAgent('beta', 'userSettings')
|
||||
expect(compareAgentsByName(a, b)).toBeLessThan(0)
|
||||
})
|
||||
|
||||
test("returns negative when a.name < b.name", () => {
|
||||
const a = makeAgent("a", "s");
|
||||
const b = makeAgent("b", "s");
|
||||
expect(compareAgentsByName(a, b)).toBeLessThan(0);
|
||||
});
|
||||
test('returns negative when a.name < b.name', () => {
|
||||
const a = makeAgent('a', 's')
|
||||
const b = makeAgent('b', 's')
|
||||
expect(compareAgentsByName(a, b)).toBeLessThan(0)
|
||||
})
|
||||
|
||||
test("returns positive when a.name > b.name", () => {
|
||||
const a = makeAgent("z", "s");
|
||||
const b = makeAgent("a", "s");
|
||||
expect(compareAgentsByName(a, b)).toBeGreaterThan(0);
|
||||
});
|
||||
test('returns positive when a.name > b.name', () => {
|
||||
const a = makeAgent('z', 's')
|
||||
const b = makeAgent('a', 's')
|
||||
expect(compareAgentsByName(a, b)).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
test("returns 0 for same name", () => {
|
||||
const a = makeAgent("same", "s");
|
||||
const b = makeAgent("same", "s");
|
||||
expect(compareAgentsByName(a, b)).toBe(0);
|
||||
});
|
||||
test('returns 0 for same name', () => {
|
||||
const a = makeAgent('same', 's')
|
||||
const b = makeAgent('same', 's')
|
||||
expect(compareAgentsByName(a, b)).toBe(0)
|
||||
})
|
||||
|
||||
test("is case-insensitive (sensitivity: base)", () => {
|
||||
const a = makeAgent("Alpha", "s");
|
||||
const b = makeAgent("alpha", "s");
|
||||
expect(compareAgentsByName(a, b)).toBe(0);
|
||||
});
|
||||
});
|
||||
test('is case-insensitive (sensitivity: base)', () => {
|
||||
const a = makeAgent('Alpha', 's')
|
||||
const b = makeAgent('alpha', 's')
|
||||
expect(compareAgentsByName(a, b)).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("AGENT_SOURCE_GROUPS", () => {
|
||||
test("contains expected source groups in order", () => {
|
||||
expect(AGENT_SOURCE_GROUPS).toHaveLength(7);
|
||||
describe('AGENT_SOURCE_GROUPS', () => {
|
||||
test('contains expected source groups in order', () => {
|
||||
expect(AGENT_SOURCE_GROUPS).toHaveLength(7)
|
||||
expect(AGENT_SOURCE_GROUPS[0]).toEqual({
|
||||
label: "User agents",
|
||||
source: "userSettings",
|
||||
});
|
||||
label: 'User agents',
|
||||
source: 'userSettings',
|
||||
})
|
||||
expect(AGENT_SOURCE_GROUPS[6]).toEqual({
|
||||
label: "Built-in agents",
|
||||
source: "built-in",
|
||||
});
|
||||
});
|
||||
label: 'Built-in agents',
|
||||
source: 'built-in',
|
||||
})
|
||||
})
|
||||
|
||||
test("has unique labels", () => {
|
||||
const labels = AGENT_SOURCE_GROUPS.map((g) => g.label);
|
||||
expect(new Set(labels).size).toBe(labels.length);
|
||||
});
|
||||
test('has unique labels', () => {
|
||||
const labels = AGENT_SOURCE_GROUPS.map(g => g.label)
|
||||
expect(new Set(labels).size).toBe(labels.length)
|
||||
})
|
||||
|
||||
test("has unique sources", () => {
|
||||
const sources = AGENT_SOURCE_GROUPS.map((g) => g.source);
|
||||
expect(new Set(sources).size).toBe(sources.length);
|
||||
});
|
||||
});
|
||||
test('has unique sources', () => {
|
||||
const sources = AGENT_SOURCE_GROUPS.map(g => g.source)
|
||||
expect(new Set(sources).size).toBe(sources.length)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,69 +1,72 @@
|
||||
import { mock, describe, expect, test } from "bun:test";
|
||||
import { debugMock } from "../../../../../../tests/mocks/debug";
|
||||
import { mock, describe, expect, test } from 'bun:test'
|
||||
import { debugMock } from '../../../../../../tests/mocks/debug'
|
||||
|
||||
// ─── Mocks for agentToolUtils.ts dependencies ───
|
||||
// Only mock modules that are truly unavailable or cause side effects.
|
||||
// Do NOT mock common/shared modules (zod/v4, bootstrap/state, etc.) to avoid
|
||||
// corrupting the module cache for other test files in the same Bun process.
|
||||
|
||||
const noop = () => {};
|
||||
const noop = () => {}
|
||||
|
||||
mock.module("bun:bundle", () => ({ feature: () => false }));
|
||||
mock.module('bun:bundle', () => ({ feature: () => false }))
|
||||
|
||||
mock.module("src/constants/tools.js", () => ({
|
||||
mock.module('src/constants/tools.js', () => ({
|
||||
ALL_AGENT_DISALLOWED_TOOLS: new Set(),
|
||||
ASYNC_AGENT_ALLOWED_TOOLS: new Set(),
|
||||
CUSTOM_AGENT_DISALLOWED_TOOLS: new Set(),
|
||||
IN_PROCESS_TEAMMATE_ALLOWED_TOOLS: new Set(),
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/services/AgentSummary/agentSummary.js", () => ({
|
||||
mock.module('src/services/AgentSummary/agentSummary.js', () => ({
|
||||
startAgentSummarization: noop,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/services/analytics/index.js", () => ({
|
||||
mock.module('src/services/analytics/index.js', () => ({
|
||||
logEvent: noop,
|
||||
logEventAsync: async () => {},
|
||||
stripProtoFields: (v: any) => v,
|
||||
attachAnalyticsSink: noop,
|
||||
_resetForTesting: noop,
|
||||
AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS: undefined,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/services/api/dumpPrompts.js", () => ({
|
||||
mock.module('src/services/api/dumpPrompts.js', () => ({
|
||||
clearDumpState: noop,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/Tool.js", () => ({
|
||||
mock.module('src/Tool.js', () => ({
|
||||
toolMatchesName: () => false,
|
||||
findToolByName: noop,
|
||||
}));
|
||||
}))
|
||||
|
||||
// messages.ts is complex - provide stubs for all named exports
|
||||
mock.module("src/utils/messages.ts", () => ({
|
||||
mock.module('src/utils/messages.ts', () => ({
|
||||
extractTextContent: (content: any[]) =>
|
||||
content?.filter?.((b: any) => b.type === "text")?.map?.((b: any) => b.text)?.join("") ?? "",
|
||||
content
|
||||
?.filter?.((b: any) => b.type === 'text')
|
||||
?.map?.((b: any) => b.text)
|
||||
?.join('') ?? '',
|
||||
getLastAssistantMessage: () => null,
|
||||
SYNTHETIC_MESSAGES: new Set(),
|
||||
INTERRUPT_MESSAGE: "",
|
||||
INTERRUPT_MESSAGE_FOR_TOOL_USE: "",
|
||||
CANCEL_MESSAGE: "",
|
||||
REJECT_MESSAGE: "",
|
||||
REJECT_MESSAGE_WITH_REASON_PREFIX: "",
|
||||
SUBAGENT_REJECT_MESSAGE: "",
|
||||
SUBAGENT_REJECT_MESSAGE_WITH_REASON_PREFIX: "",
|
||||
PLAN_REJECTION_PREFIX: "",
|
||||
DENIAL_WORKAROUND_GUIDANCE: "",
|
||||
NO_RESPONSE_REQUESTED: "",
|
||||
SYNTHETIC_TOOL_RESULT_PLACEHOLDER: "",
|
||||
SYNTHETIC_MODEL: "",
|
||||
INTERRUPT_MESSAGE: '',
|
||||
INTERRUPT_MESSAGE_FOR_TOOL_USE: '',
|
||||
CANCEL_MESSAGE: '',
|
||||
REJECT_MESSAGE: '',
|
||||
REJECT_MESSAGE_WITH_REASON_PREFIX: '',
|
||||
SUBAGENT_REJECT_MESSAGE: '',
|
||||
SUBAGENT_REJECT_MESSAGE_WITH_REASON_PREFIX: '',
|
||||
PLAN_REJECTION_PREFIX: '',
|
||||
DENIAL_WORKAROUND_GUIDANCE: '',
|
||||
NO_RESPONSE_REQUESTED: '',
|
||||
SYNTHETIC_TOOL_RESULT_PLACEHOLDER: '',
|
||||
SYNTHETIC_MODEL: '',
|
||||
AUTO_REJECT_MESSAGE: noop,
|
||||
DONT_ASK_REJECT_MESSAGE: noop,
|
||||
withMemoryCorrectionHint: (s: string) => s,
|
||||
deriveShortMessageId: () => "",
|
||||
deriveShortMessageId: () => '',
|
||||
isClassifierDenial: () => false,
|
||||
buildYoloRejectionMessage: () => "",
|
||||
buildClassifierUnavailableMessage: () => "",
|
||||
buildYoloRejectionMessage: () => '',
|
||||
buildClassifierUnavailableMessage: () => '',
|
||||
isEmptyMessageText: () => true,
|
||||
createAssistantMessage: noop,
|
||||
createAssistantAPIErrorMessage: noop,
|
||||
@@ -72,9 +75,9 @@ mock.module("src/utils/messages.ts", () => ({
|
||||
createUserInterruptionMessage: noop,
|
||||
createSyntheticUserCaveatMessage: noop,
|
||||
formatCommandInputTags: noop,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/tasks/LocalAgentTask/LocalAgentTask.js", () => ({
|
||||
mock.module('src/tasks/LocalAgentTask/LocalAgentTask.js', () => ({
|
||||
completeAgentTask: noop,
|
||||
createActivityDescriptionResolver: () => ({}),
|
||||
createProgressTracker: () => ({}),
|
||||
@@ -86,11 +89,11 @@ mock.module("src/tasks/LocalAgentTask/LocalAgentTask.js", () => ({
|
||||
killAsyncAgent: noop,
|
||||
updateAgentProgress: noop,
|
||||
updateProgressFromMessage: noop,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/utils/debug.ts", debugMock);
|
||||
mock.module('src/utils/debug.ts', debugMock)
|
||||
|
||||
mock.module("src/utils/errors.js", () => ({
|
||||
mock.module('src/utils/errors.js', () => ({
|
||||
ClaudeError: class extends Error {},
|
||||
MalformedCommandError: class extends Error {},
|
||||
AbortError: class extends Error {},
|
||||
@@ -100,142 +103,137 @@ mock.module("src/utils/errors.js", () => ({
|
||||
TelemetrySafeError_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS: class extends Error {},
|
||||
isAbortError: () => false,
|
||||
hasExactErrorMessage: () => false,
|
||||
toError: (e: any) => e instanceof Error ? e : new Error(String(e)),
|
||||
toError: (e: any) => (e instanceof Error ? e : new Error(String(e))),
|
||||
errorMessage: (e: any) => String(e),
|
||||
getErrnoCode: () => undefined,
|
||||
isENOENT: () => false,
|
||||
getErrnoPath: () => undefined,
|
||||
shortErrorStack: () => "",
|
||||
shortErrorStack: () => '',
|
||||
isFsInaccessible: () => false,
|
||||
classifyAxiosError: () => ({ category: "unknown" }),
|
||||
}));
|
||||
classifyAxiosError: () => ({ category: 'unknown' }),
|
||||
}))
|
||||
|
||||
mock.module("src/utils/forkedAgent.js", () => ({}));
|
||||
mock.module('src/utils/forkedAgent.js', () => ({}))
|
||||
|
||||
mock.module("src/utils/permissions/yoloClassifier.js", () => ({
|
||||
buildTranscriptForClassifier: () => "",
|
||||
mock.module('src/utils/permissions/yoloClassifier.js', () => ({
|
||||
buildTranscriptForClassifier: () => '',
|
||||
classifyYoloAction: () => null,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/utils/task/sdkProgress.js", () => ({
|
||||
mock.module('src/utils/task/sdkProgress.js', () => ({
|
||||
emitTaskProgress: noop,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/utils/tokens.js", () => ({
|
||||
mock.module('src/utils/tokens.js', () => ({
|
||||
getTokenCountFromUsage: () => 0,
|
||||
}));
|
||||
}))
|
||||
|
||||
mock.module("src/tools/ExitPlanModeTool/constants.js", () => ({
|
||||
EXIT_PLAN_MODE_V2_TOOL_NAME: "exit_plan_mode",
|
||||
}));
|
||||
mock.module('src/tools/ExitPlanModeTool/constants.js', () => ({
|
||||
EXIT_PLAN_MODE_V2_TOOL_NAME: 'exit_plan_mode',
|
||||
}))
|
||||
|
||||
mock.module("src/tools/AgentTool/constants.js", () => ({
|
||||
AGENT_TOOL_NAME: "agent",
|
||||
LEGACY_AGENT_TOOL_NAME: "task",
|
||||
}));
|
||||
mock.module('src/tools/AgentTool/constants.js', () => ({
|
||||
AGENT_TOOL_NAME: 'agent',
|
||||
LEGACY_AGENT_TOOL_NAME: 'task',
|
||||
}))
|
||||
|
||||
mock.module("src/tools/AgentTool/loadAgentsDir.js", () => ({}));
|
||||
mock.module('src/tools/AgentTool/loadAgentsDir.js', () => ({}))
|
||||
|
||||
mock.module("src/state/AppState.js", () => ({}));
|
||||
mock.module('src/state/AppState.js', () => ({}))
|
||||
|
||||
mock.module("src/types/ids.js", () => ({
|
||||
mock.module('src/types/ids.js', () => ({
|
||||
asAgentId: (id: string) => id,
|
||||
}));
|
||||
}))
|
||||
|
||||
// Break circular dep
|
||||
mock.module("src/tools/AgentTool/AgentTool.tsx", () => ({
|
||||
mock.module('src/tools/AgentTool/AgentTool.tsx', () => ({
|
||||
AgentTool: {},
|
||||
inputSchema: {},
|
||||
outputSchema: {},
|
||||
default: {},
|
||||
}));
|
||||
}))
|
||||
|
||||
const {
|
||||
countToolUses,
|
||||
getLastToolUseName,
|
||||
} = await import("../agentToolUtils");
|
||||
const { countToolUses, getLastToolUseName } = await import('../agentToolUtils')
|
||||
|
||||
function makeAssistantMessage(content: any[]): any {
|
||||
return { type: "assistant", message: { content } };
|
||||
return { type: 'assistant', message: { content } }
|
||||
}
|
||||
|
||||
function makeUserMessage(text: string): any {
|
||||
return { type: "user", message: { content: text } };
|
||||
return { type: 'user', message: { content: text } }
|
||||
}
|
||||
|
||||
describe("countToolUses", () => {
|
||||
test("counts tool_use blocks in messages", () => {
|
||||
describe('countToolUses', () => {
|
||||
test('counts tool_use blocks in messages', () => {
|
||||
const messages = [
|
||||
makeAssistantMessage([
|
||||
{ type: "tool_use", name: "Read" },
|
||||
{ type: "text", text: "hello" },
|
||||
{ type: 'tool_use', name: 'Read' },
|
||||
{ type: 'text', text: 'hello' },
|
||||
]),
|
||||
];
|
||||
expect(countToolUses(messages)).toBe(1);
|
||||
});
|
||||
]
|
||||
expect(countToolUses(messages)).toBe(1)
|
||||
})
|
||||
|
||||
test("returns 0 for messages without tool_use", () => {
|
||||
test('returns 0 for messages without tool_use', () => {
|
||||
const messages = [makeAssistantMessage([{ type: 'text', text: 'hello' }])]
|
||||
expect(countToolUses(messages)).toBe(0)
|
||||
})
|
||||
|
||||
test('returns 0 for empty array', () => {
|
||||
expect(countToolUses([])).toBe(0)
|
||||
})
|
||||
|
||||
test('counts multiple tool_use blocks across messages', () => {
|
||||
const messages = [
|
||||
makeAssistantMessage([{ type: "text", text: "hello" }]),
|
||||
];
|
||||
expect(countToolUses(messages)).toBe(0);
|
||||
});
|
||||
makeAssistantMessage([{ type: 'tool_use', name: 'Read' }]),
|
||||
makeUserMessage('ok'),
|
||||
makeAssistantMessage([{ type: 'tool_use', name: 'Write' }]),
|
||||
]
|
||||
expect(countToolUses(messages)).toBe(2)
|
||||
})
|
||||
|
||||
test("returns 0 for empty array", () => {
|
||||
expect(countToolUses([])).toBe(0);
|
||||
});
|
||||
|
||||
test("counts multiple tool_use blocks across messages", () => {
|
||||
const messages = [
|
||||
makeAssistantMessage([{ type: "tool_use", name: "Read" }]),
|
||||
makeUserMessage("ok"),
|
||||
makeAssistantMessage([{ type: "tool_use", name: "Write" }]),
|
||||
];
|
||||
expect(countToolUses(messages)).toBe(2);
|
||||
});
|
||||
|
||||
test("counts tool_use in single message with multiple blocks", () => {
|
||||
test('counts tool_use in single message with multiple blocks', () => {
|
||||
const messages = [
|
||||
makeAssistantMessage([
|
||||
{ type: "tool_use", name: "Read" },
|
||||
{ type: "tool_use", name: "Grep" },
|
||||
{ type: "tool_use", name: "Write" },
|
||||
{ type: 'tool_use', name: 'Read' },
|
||||
{ type: 'tool_use', name: 'Grep' },
|
||||
{ type: 'tool_use', name: 'Write' },
|
||||
]),
|
||||
];
|
||||
expect(countToolUses(messages)).toBe(3);
|
||||
});
|
||||
});
|
||||
]
|
||||
expect(countToolUses(messages)).toBe(3)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getLastToolUseName", () => {
|
||||
test("returns last tool name from assistant message", () => {
|
||||
describe('getLastToolUseName', () => {
|
||||
test('returns last tool name from assistant message', () => {
|
||||
const msg = makeAssistantMessage([
|
||||
{ type: "tool_use", name: "Read" },
|
||||
{ type: "tool_use", name: "Write" },
|
||||
]);
|
||||
expect(getLastToolUseName(msg)).toBe("Write");
|
||||
});
|
||||
{ type: 'tool_use', name: 'Read' },
|
||||
{ type: 'tool_use', name: 'Write' },
|
||||
])
|
||||
expect(getLastToolUseName(msg)).toBe('Write')
|
||||
})
|
||||
|
||||
test("returns undefined for message without tool_use", () => {
|
||||
const msg = makeAssistantMessage([{ type: "text", text: "hello" }]);
|
||||
expect(getLastToolUseName(msg)).toBeUndefined();
|
||||
});
|
||||
test('returns undefined for message without tool_use', () => {
|
||||
const msg = makeAssistantMessage([{ type: 'text', text: 'hello' }])
|
||||
expect(getLastToolUseName(msg)).toBeUndefined()
|
||||
})
|
||||
|
||||
test("returns the last tool when multiple tool_uses present", () => {
|
||||
test('returns the last tool when multiple tool_uses present', () => {
|
||||
const msg = makeAssistantMessage([
|
||||
{ type: "tool_use", name: "Read" },
|
||||
{ type: "tool_use", name: "Grep" },
|
||||
{ type: "tool_use", name: "Edit" },
|
||||
]);
|
||||
expect(getLastToolUseName(msg)).toBe("Edit");
|
||||
});
|
||||
{ type: 'tool_use', name: 'Read' },
|
||||
{ type: 'tool_use', name: 'Grep' },
|
||||
{ type: 'tool_use', name: 'Edit' },
|
||||
])
|
||||
expect(getLastToolUseName(msg)).toBe('Edit')
|
||||
})
|
||||
|
||||
test("returns undefined for non-assistant message", () => {
|
||||
const msg = makeUserMessage("hello");
|
||||
expect(getLastToolUseName(msg)).toBeUndefined();
|
||||
});
|
||||
test('returns undefined for non-assistant message', () => {
|
||||
const msg = makeUserMessage('hello')
|
||||
expect(getLastToolUseName(msg)).toBeUndefined()
|
||||
})
|
||||
|
||||
test("handles message with null content", () => {
|
||||
const msg = { type: "assistant", message: { content: null } } as any;
|
||||
expect(getLastToolUseName(msg)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
test('handles message with null content', () => {
|
||||
const msg = { type: 'assistant', message: { content: null } } as any
|
||||
expect(getLastToolUseName(msg)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -67,7 +67,9 @@ describe('filterIncompleteToolCalls', () => {
|
||||
uuid: 'u1',
|
||||
message: {
|
||||
role: 'user',
|
||||
content: [{ type: 'tool_result', tool_use_id: 'done', content: 'ok' }],
|
||||
content: [
|
||||
{ type: 'tool_result', tool_use_id: 'done', content: 'ok' },
|
||||
],
|
||||
},
|
||||
},
|
||||
] as unknown as Message[]
|
||||
@@ -100,7 +102,9 @@ describe('filterIncompleteToolCalls', () => {
|
||||
uuid: 'u1',
|
||||
message: {
|
||||
role: 'user',
|
||||
content: [{ type: 'tool_result', tool_use_id: 'done', content: 'ok' }],
|
||||
content: [
|
||||
{ type: 'tool_result', tool_use_id: 'done', content: 'ok' },
|
||||
],
|
||||
},
|
||||
},
|
||||
] as unknown as Message[]
|
||||
|
||||
Reference in New Issue
Block a user