Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/split-sdk-rpc-client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@moonshot-ai/kimi-code-sdk": minor
"@moonshot-ai/kimi-code": patch
---

Allow SDK runtime creation to use a separate RPC client while preserving local CLI startup.
5 changes: 3 additions & 2 deletions apps/kimi-code/src/cli/run-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import {
} from '@moonshot-ai/kimi-telemetry';
import chalk from 'chalk';
import {
KimiHarness,
createKimiHarness,
log,
type Event,
type GoalSnapshot,
type HookResultEvent,
type KimiHarness,
type Session,
type SessionStatus,
type TelemetryClient,
Expand Down Expand Up @@ -68,7 +69,7 @@ export async function runPrompt(
withContext: withTelemetryContext,
setContext: setTelemetryContext,
};
const harness = new KimiHarness({
const harness = createKimiHarness({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mock createKimiHarness in goal prompt tests

When runPrompt is exercised by apps/kimi-code/test/cli/goal-prompt.test.ts, that suite's SDK mock still overrides only KimiHarness, not createKimiHarness; this changed call therefore instantiates the real local SDK harness instead of the fake session, so the headless goal tests no longer drive mocks.session and can fail or touch real SDK state. Update that remaining mock as the other CLI tests do before switching this path.

Useful? React with 👍 / 👎.

homeDir: telemetryBootstrap.homeDir,
identity: createKimiCodeHostIdentity(version),
uiMode: PROMPT_UI_MODE,
Expand Down
9 changes: 7 additions & 2 deletions apps/kimi-code/src/cli/run-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import {
track,
withTelemetryContext,
} from '@moonshot-ai/kimi-telemetry';
import { KimiHarness, log, type TelemetryClient } from '@moonshot-ai/kimi-code-sdk';
import {
createKimiHarness,
log,
type KimiHarness,
type TelemetryClient,
} from '@moonshot-ai/kimi-code-sdk';

import { CLI_SHUTDOWN_TIMEOUT_MS, CLI_UI_MODE } from '#/constant/app';
import { detectPendingMigration } from '#/migration/index';
Expand Down Expand Up @@ -51,7 +56,7 @@ export async function runShell(
withContext: withTelemetryContext,
setContext: setTelemetryContext,
};
const harness = new KimiHarness({
const harness = createKimiHarness({
homeDir: telemetryBootstrap.homeDir,
identity: createKimiCodeHostIdentity(version),
telemetry: telemetryClient,
Expand Down
5 changes: 3 additions & 2 deletions apps/kimi-code/src/cli/sub/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import {
withTelemetryContext,
} from '@moonshot-ai/kimi-telemetry';
import {
KimiHarness,
createKimiHarness,
type ExportSessionInput,
type ExportSessionResult,
type KimiHarness,
type SessionSummary,
type ShellEnvironment,
type TelemetryClient,
Expand Down Expand Up @@ -144,7 +145,7 @@ function createDefaultExportDeps(overrides: Partial<ExportDeps> = {}): ExportDep
};
const getHarness = (): KimiHarness => {
const currentTelemetryBootstrap = getTelemetryBootstrap();
harness ??= new KimiHarness({
harness ??= createKimiHarness({
homeDir: currentTelemetryBootstrap.homeDir,
identity,
telemetry: telemetryClient,
Expand Down
5 changes: 3 additions & 2 deletions apps/kimi-code/src/cli/sub/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ import {
catalogBaseUrl,
catalogProviderModels,
CatalogFetchError,
createKimiHarness,
DEFAULT_CATALOG_URL,
fetchCatalog,
inferWireType,
KimiHarness,
type Catalog,
type CatalogProviderEntry,
type KimiConfig,
type KimiHarness,
} from '@moonshot-ai/kimi-code-sdk';
import type { Command } from 'commander';

Expand Down Expand Up @@ -487,7 +488,7 @@ function resolveDeps(overrides: Partial<ProviderDeps> = {}): ProviderDeps {
getHarness:
overrides.getHarness ??
(() => {
harness ??= new KimiHarness({ identity });
harness ??= createKimiHarness({ identity });
return harness;
}),
stdout: overrides.stdout ?? process.stdout,
Expand Down
4 changes: 2 additions & 2 deletions apps/kimi-code/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import {
KimiHarness,
createKimiHarness,
flushDiagnosticLogs,
log,
resolveGlobalLogPath,
Expand Down Expand Up @@ -78,7 +78,7 @@ export async function handleUpgradeCommand(version: string): Promise<void> {
withContext: withTelemetryContext,
setContext: setTelemetryContext,
};
const harness = new KimiHarness({
const harness = createKimiHarness({
homeDir: telemetryBootstrap.homeDir,
identity: createKimiCodeHostIdentity(version),
telemetry: telemetryClient,
Expand Down
33 changes: 16 additions & 17 deletions apps/kimi-code/test/cli/export.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,23 @@ vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => {
return {
...actual,
resolveKimiHome: mocks.resolveKimiHome,
KimiHarness: class {
homeDir: string;
auth = {
getCachedAccessToken: mocks.harnessGetCachedAccessToken,
};
ensureConfigFile = mocks.harnessEnsureConfigFile;
getConfig = mocks.harnessGetConfig;
track = mocks.harnessTrack;
constructor(...args: unknown[]) {
const options = args[0] as { readonly homeDir?: string } | undefined;
this.homeDir = options?.homeDir ?? '/tmp/kimi-export-home';
if (mocks.harnessCreatesDeviceIdOnConstruction) {
mocks.createKimiDeviceId(this.homeDir);
}
mocks.kimiHarnessConstructor(...args);
createKimiHarness: (...args: unknown[]) => {
const options = args[0] as { readonly homeDir?: string } | undefined;
const homeDir = options?.homeDir ?? '/tmp/kimi-export-home';
if (mocks.harnessCreatesDeviceIdOnConstruction) {
mocks.createKimiDeviceId(homeDir);
}

exportSession = mocks.harnessExportSession;
mocks.kimiHarnessConstructor(...args);
return {
homeDir,
auth: {
getCachedAccessToken: mocks.harnessGetCachedAccessToken,
},
ensureConfigFile: mocks.harnessEnsureConfigFile,
getConfig: mocks.harnessGetConfig,
track: mocks.harnessTrack,
exportSession: mocks.harnessExportSession,
};
},
};
});
Expand Down
25 changes: 12 additions & 13 deletions apps/kimi-code/test/cli/goal-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,18 @@ vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => {
const actual = await importOriginal<typeof import('@moonshot-ai/kimi-code-sdk')>();
return {
...actual,
KimiHarness: class {
homeDir = '/tmp/kimi-goal-home';
auth = { getCachedAccessToken: vi.fn() };
ensureConfigFile = vi.fn();
getConfig = vi.fn(async () => ({ providers: {}, defaultModel: 'k2', telemetry: true }));
getExperimentalFlags = vi.fn(async () => mocks.experimentalFlags);
createSession = vi.fn(async () => mocks.session);
resumeSession = vi.fn(async () => mocks.session);
listSessions = vi.fn(async () => mocks.sessions);
close = vi.fn();
track = vi.fn();
constructor() {}
},
createKimiHarness: () => ({
homeDir: '/tmp/kimi-goal-home',
auth: { getCachedAccessToken: vi.fn() },
ensureConfigFile: vi.fn(),
getConfig: vi.fn(async () => ({ providers: {}, defaultModel: 'k2', telemetry: true })),
getExperimentalFlags: vi.fn(async () => mocks.experimentalFlags),
createSession: vi.fn(async () => mocks.session),
resumeSession: vi.fn(async () => mocks.session),
listSessions: vi.fn(async () => mocks.sessions),
close: vi.fn(),
track: vi.fn(),
}),
};
});

Expand Down
7 changes: 6 additions & 1 deletion apps/kimi-code/test/cli/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const mocks = vi.hoisted(() => {
track: vi.fn(),
},
KimiHarness: vi.fn(),
createKimiHarness: vi.fn(),
};
});

Expand Down Expand Up @@ -74,6 +75,10 @@ vi.mock('@moonshot-ai/kimi-code-sdk', async () => {
}
return {
...actual,
createKimiHarness: (...args: unknown[]) => {
mocks.createKimiHarness(...args);
return mocks.harness;
},
KimiHarness: MockKimiHarness,
log: mocks.log,
};
Expand Down Expand Up @@ -272,7 +277,7 @@ describe('main entry command handling', () => {

expect(exitCode).toBe(0);
expect(mocks.createCliTelemetryBootstrap).toHaveBeenCalledTimes(1);
expect(mocks.KimiHarness).toHaveBeenCalledWith(expect.objectContaining({
expect(mocks.createKimiHarness).toHaveBeenCalledWith(expect.objectContaining({
homeDir: '/tmp/kimi-home',
telemetry: {
track: mocks.track,
Expand Down
37 changes: 18 additions & 19 deletions apps/kimi-code/test/cli/run-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,26 +79,25 @@ vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => {
return {
...actual,
resolveKimiHome: mocks.resolveKimiHome,
KimiHarness: class {
homeDir: string;
auth = { getCachedAccessToken: mocks.harnessGetCachedAccessToken };
ensureConfigFile = mocks.harnessEnsureConfigFile;
getConfig = mocks.harnessGetConfig;
getExperimentalFlags = mocks.harnessGetExperimentalFlags;
createSession = mocks.harnessCreateSession;
resumeSession = mocks.harnessResumeSession;
listSessions = mocks.harnessListSessions;
close = mocks.harnessClose;
track = mocks.harnessTrack;

constructor(...args: unknown[]) {
const options = args[0] as { readonly homeDir?: string } | undefined;
this.homeDir = options?.homeDir ?? '/tmp/kimi-code-test-home';
if (mocks.harnessCreatesDeviceIdOnConstruction) {
mocks.createKimiDeviceId(this.homeDir);
}
mocks.kimiHarnessConstructor(...args);
createKimiHarness: (...args: unknown[]) => {
const options = args[0] as { readonly homeDir?: string } | undefined;
const homeDir = options?.homeDir ?? '/tmp/kimi-code-test-home';
if (mocks.harnessCreatesDeviceIdOnConstruction) {
mocks.createKimiDeviceId(homeDir);
}
mocks.kimiHarnessConstructor(...args);
return {
homeDir,
auth: { getCachedAccessToken: mocks.harnessGetCachedAccessToken },
ensureConfigFile: mocks.harnessEnsureConfigFile,
getConfig: mocks.harnessGetConfig,
getExperimentalFlags: mocks.harnessGetExperimentalFlags,
createSession: mocks.harnessCreateSession,
resumeSession: mocks.harnessResumeSession,
listSessions: mocks.harnessListSessions,
close: mocks.harnessClose,
track: mocks.harnessTrack,
};
},
};
});
Expand Down
33 changes: 16 additions & 17 deletions apps/kimi-code/test/cli/run-shell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,23 @@ vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => {
return {
...actual,
resolveKimiHome: mocks.resolveKimiHome,
KimiHarness: class {
homeDir: string;
auth = {
getCachedAccessToken: mocks.harnessGetCachedAccessToken,
};
ensureConfigFile = mocks.harnessEnsureConfigFile;
getConfig = mocks.harnessGetConfig;
close = mocks.harnessClose;
track = mocks.harnessTrack;

constructor(...args: unknown[]) {
const options = args[0] as { readonly homeDir?: string } | undefined;
this.homeDir = options?.homeDir ?? '/tmp/kimi-code-test-home';
if (mocks.harnessCreatesDeviceIdOnConstruction) {
mocks.createKimiDeviceId(this.homeDir);
}
mocks.kimiHarnessConstructor(...args);
createKimiHarness: (...args: unknown[]) => {
const options = args[0] as { readonly homeDir?: string } | undefined;
const homeDir = options?.homeDir ?? '/tmp/kimi-code-test-home';
if (mocks.harnessCreatesDeviceIdOnConstruction) {
mocks.createKimiDeviceId(homeDir);
}
mocks.kimiHarnessConstructor(...args);
return {
homeDir,
auth: {
getCachedAccessToken: mocks.harnessGetCachedAccessToken,
},
ensureConfigFile: mocks.harnessEnsureConfigFile,
getConfig: mocks.harnessGetConfig,
close: mocks.harnessClose,
track: mocks.harnessTrack,
};
},
};
});
Expand Down
4 changes: 2 additions & 2 deletions apps/kimi-code/test/e2e/local-logging-export.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';

import { registerExportCommand } from '#/cli/sub/export';
import { createKimiCodeHostIdentity } from '#/cli/version';
import { KimiHarness, log } from '@moonshot-ai/kimi-code-sdk';
import { createKimiHarness, log } from '@moonshot-ai/kimi-code-sdk';
import { __resetRootLoggerForTest } from '../../../../packages/agent-core/src/logging/logger';

const SESSION_LOG = 'logs/kimi-code.log';
Expand Down Expand Up @@ -49,7 +49,7 @@ afterEach(async () => {

describe.skipIf(!ENABLED)('local logging export e2e', () => {
it('exports session log and global log by default, and allows skipping global log', async () => {
const harness = new KimiHarness({
const harness = createKimiHarness({
homeDir,
identity: createKimiCodeHostIdentity('0.1.1'),
});
Expand Down
4 changes: 2 additions & 2 deletions apps/kimi-code/test/e2e/real-llm-smoke.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import { mkdirSync } from 'node:fs';
import process from 'node:process';

import { KimiHarness, type Event } from '@moonshot-ai/kimi-code-sdk';
import { createKimiHarness, type Event } from '@moonshot-ai/kimi-code-sdk';
import { describe, expect, test } from 'vitest';

import { createKimiCodeHostIdentity, getVersion } from '#/cli/version';
Expand All @@ -41,7 +41,7 @@ describe.skipIf(!ENABLED)('SDK e2e — real LLM smoke', () => {
`[smoke] prompt=${JSON.stringify(prompt)}\n`,
);

const harness = new KimiHarness({
const harness = createKimiHarness({
identity: createKimiCodeHostIdentity(version),
});

Expand Down
4 changes: 2 additions & 2 deletions packages/node-sdk/examples/kimi-harness-auth-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { KimiHarness } from '@moonshot-ai/kimi-code-sdk';
import { createKimiHarness, type KimiHarness } from '@moonshot-ai/kimi-code-sdk';

import { smokeIdentityFromEnv, runPromptToEnd } from './runtime-smoke-helpers';

Expand All @@ -17,7 +17,7 @@ async function main(): Promise<void> {
const forceLogin = process.env['KIMI_SDK_AUTH_SMOKE_FORCE_LOGIN'] === '1';
const prompt =
process.env['KIMI_SDK_AUTH_SMOKE_PROMPT'] ?? 'Reply with exactly: Kimi SDK auth smoke ok';
const harness = new KimiHarness({ homeDir, identity: smokeIdentityFromEnv() });
const harness = createKimiHarness({ homeDir, identity: smokeIdentityFromEnv() });

process.stdout.write(`home: ${homeDir}\n`);
process.stdout.write(`workDir: ${workDir}\n`);
Expand Down
4 changes: 2 additions & 2 deletions packages/node-sdk/examples/kimi-harness-cancel-smoke.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { KimiHarness } from '@moonshot-ai/kimi-code-sdk';
import { createKimiHarness } from '@moonshot-ai/kimi-code-sdk';

import {
smokeIdentityFromEnv,
Expand All @@ -10,7 +10,7 @@ const PROMPT =
'Write a detailed multi-paragraph explanation of how cancellation should work in an SDK streaming session.';

async function main(): Promise<void> {
const harness = new KimiHarness({ identity: smokeIdentityFromEnv() });
const harness = createKimiHarness({ identity: smokeIdentityFromEnv() });

try {
const session = await createConfiguredSession(harness);
Expand Down
4 changes: 2 additions & 2 deletions packages/node-sdk/examples/kimi-harness-config-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { mkdtemp, readFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { KimiHarness } from '@moonshot-ai/kimi-code-sdk';
import { createKimiHarness } from '@moonshot-ai/kimi-code-sdk';

import { smokeIdentityFromEnv } from './runtime-smoke-helpers';

async function main(): Promise<void> {
const homeDir = await mkdtemp(join(tmpdir(), 'kimi-harness-config-home-'));
const harness = new KimiHarness({ homeDir, identity: smokeIdentityFromEnv() });
const harness = createKimiHarness({ homeDir, identity: smokeIdentityFromEnv() });

const initial = await harness.getConfig();
if (Object.keys(initial.providers).length > 0) {
Expand Down
Loading
Loading