mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-13 18:56:12 +00:00
* feat(agent-core-v2): add the L3 unit layer and the Feature seam - introduce the L3 Service/Fiber unit layer: the Service base class with this.provide/effect/on/get/ref capabilities, the fiber runtime with thenable FiberHandles, collection contribution points, and the per-scope-kind ScopeUnits materialization fold - provide each scope's static registration batch as one atomic provideAll cascade transaction (waiting-area activation, sticky Failed on construction error) - add the DI unit inspection surface: App-scope debug ledger / dependency graph / cascade history services and the kimi-inspect DI view - add the Feature unit seam (IFeatureManager + feature assembly), port plan mode onto it, and add the contributed-command seam (agent-command domain + node-sdk RPC types) - remove the legacy dep-graph tooling - apply the header-only comment convention across src and test: strip non-header narration, keep the file header, tooling pragmas, and NOTE comments * feat(kap-server): gate the event.di.* debug feed to kimi-inspect connections - add an opt-in target set in SessionEventBroadcaster; the global fan-out now skips event.di.* frames for connections that never opted in, so kimi-web and other clients no longer receive the high-churn DI feed - WsConnectionV1 opts a connection in when client_hello carries client_id 'kimi-inspect'; removeGlobalTarget drops the opt-in on close - temporary gate until a client-declared event-type whitelist lands * chore(agent-core-v2): fix oxlint errors in the DI unit layer - build the live-ref container chain without aliasing this (no-this-alias) - snapshot the materialized map with Array.from and document why the copy is required (no-useless-spread) * test(klient): use string scope kinds in the lifecycle handle fakes The engine's LifecycleScope is a string enum now; the facade test doubles still returned the old numeric kinds and failed the handleWireSchema output validation. * build(nix): update the pnpmDeps fetch hash
72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
import { rm } from 'node:fs/promises';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import { defineKlientConformance } from './helpers/conformance.js';
|
|
import { createKlient } from '../src/transports/memory/index.js';
|
|
import { createMemoryDispatcher } from '../src/transports/memory/dispatcher.js';
|
|
import { RPCError } from '../src/core/errors.js';
|
|
import { makeEngine } from './helpers/engine.js';
|
|
|
|
defineKlientConformance('memory', async () => {
|
|
const { homeDir, app } = await makeEngine();
|
|
const klient = createKlient({ scope: app });
|
|
return {
|
|
klient,
|
|
app,
|
|
cleanup: async () => {
|
|
await klient.close();
|
|
app.dispose();
|
|
await rm(homeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 });
|
|
},
|
|
};
|
|
});
|
|
|
|
describe('memory dispatcher specifics', () => {
|
|
it('rejects unknown services and methods with RPCError(40001)', async () => {
|
|
const { homeDir, app } = await makeEngine();
|
|
const dispatcher = createMemoryDispatcher(app);
|
|
await expect(dispatcher.call({}, 'noSuchService', 'get', [])).rejects.toMatchObject({
|
|
name: 'RPCError',
|
|
code: 40001,
|
|
});
|
|
await expect(dispatcher.call({}, 'sessionIndex', 'noSuchMethod', [])).rejects.toMatchObject({
|
|
name: 'RPCError',
|
|
code: 40001,
|
|
});
|
|
app.dispose();
|
|
await rm(homeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 });
|
|
});
|
|
|
|
it('reads non-function members as properties', async () => {
|
|
const { homeDir, app } = await makeEngine();
|
|
const dispatcher = createMemoryDispatcher(app);
|
|
await expect(dispatcher.call({}, 'bootstrapService', 'platform', [])).resolves.toBe(
|
|
process.platform,
|
|
);
|
|
app.dispose();
|
|
await rm(homeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 });
|
|
});
|
|
|
|
it('rejects session/agent scopes for now', async () => {
|
|
const { homeDir, app } = await makeEngine();
|
|
const dispatcher = createMemoryDispatcher(app);
|
|
await expect(
|
|
dispatcher.call({ sessionId: 's1' }, 'sessionIndex', 'list', [{}]),
|
|
).rejects.toBeInstanceOf(RPCError);
|
|
app.dispose();
|
|
await rm(homeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 });
|
|
});
|
|
|
|
it('delivers wire-cloned payloads (no live object identity)', async () => {
|
|
const { homeDir, app } = await makeEngine();
|
|
const klient = createKlient({ scope: app });
|
|
const list = await klient.global.workspaces.list();
|
|
// Mutating the result must not affect what a second call returns.
|
|
(list as unknown[]).push({ id: 'polluted' });
|
|
const again = await klient.global.workspaces.list();
|
|
expect(again.some((w) => w.id === 'polluted')).toBe(false);
|
|
app.dispose();
|
|
await rm(homeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 });
|
|
});
|
|
});
|