kimi-code/packages/agent-core/test/tools/shell-cancel.test.ts
_Kerman ba64072559
Some checks failed
CI / build (push) Has been cancelled
CI / test (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
Nix Build / Check flake.nix workspace sync (push) Has been cancelled
Release / Release (push) Has been cancelled
Release / Native release artifact (push) Has been cancelled
Nix Build / nix build .#kimi-code (push) Has been cancelled
Release / Deploy docs (push) Has been cancelled
Release / Publish native release assets (push) Has been cancelled
feat: detach foreground tasks to background (#821)
2026-06-20 21:24:22 +08:00

62 lines
2 KiB
TypeScript

import { Readable, type Writable } from 'node:stream';
import type { Environment, KaosProcess } from '@moonshot-ai/kaos';
import { describe, expect, it, vi } from 'vitest';
import { BashTool } from '../../src/tools/builtin/shell/bash';
import { createBackgroundManager } from '../agent/background/helpers';
import { executeTool } from './fixtures/execute-tool';
import { createFakeKaos } from './fixtures/fake-kaos';
const posixEnv: Environment = {
osKind: 'Linux',
osArch: 'x86_64',
osVersion: 'test',
shellPath: '/bin/bash',
shellName: 'bash',
};
describe('BashTool cancellation contract', () => {
it('reports the cancellation with an "Interrupted by user" message and kills the process', async () => {
let resolveWait: (code: number) => void = () => {};
const waitPromise = new Promise<number>((resolve) => {
resolveWait = resolve;
});
const kill = vi.fn(async () => {
resolveWait(143);
});
const proc: KaosProcess = {
stdin: { end: vi.fn(), write: vi.fn() } as unknown as Writable,
stdout: Readable.from([]),
stderr: Readable.from([]),
pid: 501,
exitCode: null,
wait: vi.fn(async () => waitPromise),
kill,
dispose: vi.fn(async () => {}),
};
const execWithEnv = vi.fn().mockResolvedValue(proc);
const controller = new AbortController();
const tool = new BashTool(
createFakeKaos({ execWithEnv, osEnv: posixEnv }),
'/workspace',
createBackgroundManager().manager,
);
const running = executeTool(tool, {
turnId: '0',
toolCallId: 'tc_cancel',
args: { command: 'sleep 2 && printf should-not-exist > cancel_output.txt' },
signal: controller.signal,
});
await vi.waitFor(() => {
expect(proc.stdin.end).toHaveBeenCalled();
});
controller.abort();
const result = await running;
expect(kill).toHaveBeenCalledWith('SIGTERM');
expect(result).toMatchObject({ isError: true });
expect(result.output).toContain('Interrupted by user');
});
});