refactor(agent-core-v2): remove domain barrels via debarrel tool

- add scripts/debarrel.mjs (ts-morph) to rewrite #/<dir> imports to
  precise leaf specifiers and regenerate src/index.ts
- rewrite src and test consumers across the package to import from leaf
  files instead of domain barrels
- delete src/app/event/index.ts barrel and load its leaves from the
  package entry
- extract applyPromptMetadataUpdate so /api/v1 prompt submission derives
  the easy session title, matching /api/v2
- rename the v2 prefix to beta in the CLI prefix tests
This commit is contained in:
haozhe.yang 2026-07-07 13:33:18 +08:00
parent 41ed52cd62
commit b37345e5d5
315 changed files with 1400 additions and 915 deletions

View file

@ -422,36 +422,36 @@ describe('main entry command handling', () => {
});
});
describe('kimi v2 prefix', () => {
describe('kimi beta prefix', () => {
const ON = { KIMI_CODE_EXPERIMENTAL_FLAG: '1' };
const OFF: Readonly<Record<string, string | undefined>> = {};
describe('applyV2Prefix', () => {
it('passes argv through unchanged when there is no v2 token', () => {
it('passes argv through unchanged when there is no beta token', () => {
const argv = ['node', 'kimi', 'server', 'run'];
expect(applyV2Prefix(argv, ON)).toEqual({ argv });
expect(applyV2Prefix(argv, OFF)).toEqual({ argv });
});
it('strips the v2 token when the experimental flag is on', () => {
expect(applyV2Prefix(['node', 'kimi', 'v2', 'server', 'run'], ON)).toEqual({
it('strips the beta token when the experimental flag is on', () => {
expect(applyV2Prefix(['node', 'kimi', 'beta', 'server', 'run'], ON)).toEqual({
argv: ['node', 'kimi', 'server', 'run'],
});
});
it('strips a lone v2 token (default chat) when the flag is on', () => {
expect(applyV2Prefix(['node', 'kimi', 'v2'], ON)).toEqual({
it('strips a lone beta token (default chat) when the flag is on', () => {
expect(applyV2Prefix(['node', 'kimi', 'beta'], ON)).toEqual({
argv: ['node', 'kimi'],
});
});
it('rejects the v2 prefix with a hint when the flag is off', () => {
const outcome = applyV2Prefix(['node', 'kimi', 'v2', 'server', 'run'], OFF);
it('rejects the beta prefix with a hint when the flag is off', () => {
const outcome = applyV2Prefix(['node', 'kimi', 'beta', 'server', 'run'], OFF);
expect('error' in outcome && outcome.error).toMatch(/KIMI_CODE_EXPERIMENTAL_FLAG/);
});
it('does not treat a later v2 token as the prefix', () => {
const argv = ['node', 'kimi', 'server', 'v2'];
it('does not treat a later beta token as the prefix', () => {
const argv = ['node', 'kimi', 'server', 'beta'];
expect(applyV2Prefix(argv, ON)).toEqual({ argv });
});
});
@ -472,7 +472,7 @@ describe('kimi v2 prefix', () => {
it('parses the stripped argv when the flag is on', () => {
vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '1');
process.argv = ['node', 'kimi', 'v2', 'server', 'run'];
process.argv = ['node', 'kimi', 'beta', 'server', 'run'];
main();
@ -481,7 +481,7 @@ describe('kimi v2 prefix', () => {
it('exits with a hint and never parses when the flag is off', () => {
vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '');
process.argv = ['node', 'kimi', 'v2', 'server', 'run'];
process.argv = ['node', 'kimi', 'beta', 'server', 'run'];
const writes: string[] = [];
vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => {
writes.push(String(chunk));

View file

@ -693,11 +693,11 @@ describe('server-v2 routing (KIMI_CODE_EXPERIMENTAL_FLAG)', () => {
}
});
it('is the canonical experimental-v2 gate shared with the `kimi v2` prefix', async () => {
it('is the canonical experimental-v2 gate shared with the `kimi beta` prefix', async () => {
const { isServerV2Enabled } = await import('#/cli/sub/server/run');
const { isKimiV2Enabled, KIMI_V2_ENV } = await import('#/cli/experimental-v2');
expect(KIMI_V2_ENV).toBe('KIMI_CODE_EXPERIMENTAL_FLAG');
// Server routing and the `kimi v2` prefix must agree on the exact same gate.
// Server routing and the `kimi beta` prefix must agree on the exact same gate.
expect(isServerV2Enabled).toBe(isKimiV2Enabled);
});
});

View file

@ -0,0 +1,515 @@
#!/usr/bin/env node
/**
* debarrel.mjs agent-core-v2 barrel removal tool (ts-morph).
*
* Rewrites `#/<dir>` barrel imports/exports to precise leaf-file specifiers and
* regenerates the package entry `src/index.ts` so it loads every domain leaf
* (triggering all top-level `register*` side effects) without domain barrels.
*
* Modes:
* (default) rewrite all consumer files (src + test) EXCEPT src/index.ts
* --only=<reldir> limit consumer rewriting to one barrel, e.g. app/event
* --entry regenerate src/index.ts only (no consumer rewriting)
* --delete-barrels delete every domain barrel (src/**/index.ts except entry)
* --list-registers print the top-level register* files (coverage set)
* --verify-coverage exit non-zero if any register file is unreachable from entry
* --dry-run report planned edits without writing
*/
import { Project } from 'ts-morph';
import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PKG = path.resolve(__dirname, '..');
const SRC = path.join(PKG, 'src');
const ENTRY = path.join(SRC, 'index.ts');
const args = process.argv.slice(2);
const DRY = args.includes('--dry-run');
const ONLY = (args.find((a) => a.startsWith('--only=')) || '').slice('--only='.length) || null;
const ENTRY_ONLY = args.includes('--entry');
const DELETE_BARRELS = args.includes('--delete-barrels');
const LIST_REGS = args.includes('--list-registers');
const VERIFY = args.includes('--verify-coverage');
const project = new Project({ tsConfigFilePath: path.join(PKG, 'tsconfig.json') });
const relSpec = (absFile) =>
'#/' + path.relative(SRC, absFile).split(path.sep).join('/').replace(/\.ts$/, '');
const isUnderSrc = (abs) => abs === SRC || abs.startsWith(SRC + path.sep);
const isIndexBasename = (abs) => path.basename(abs) === 'index.ts';
const isBarrelFile = (sf) => {
const f = sf.getFilePath();
return isUnderSrc(f) && isIndexBasename(f) && f !== ENTRY;
};
const resolvedFile = (decl) => decl.getModuleSpecifierSourceFile() || null;
const barrelOfDecl = (decl) => {
const sf = resolvedFile(decl);
return sf && isBarrelFile(sf) ? sf : null;
};
// Resolve a name exported by `barrel` to the leaf file that declares it and the
// name that leaf uses to export it (handles `export { A as B }` at barrel level).
function resolveName(barrel, name) {
const decls = barrel.getExportedDeclarations().get(name);
if (!decls || decls.length === 0) return null;
const decl = decls[0];
const leaf = decl.getSourceFile();
const sym = decl.getSymbol();
let leafName = null;
for (const [ln, lds] of leaf.getExportedDeclarations()) {
if (lds.some((d) => d.getSymbol() === sym)) {
leafName = ln;
break;
}
}
if (leafName == null) leafName = (sym && sym.getName()) || name;
return { leafFile: leaf.getFilePath(), leafName };
}
// Ordered re-export clauses of a barrel (recursively inlines nested barrels),
// preserving source order so `export *` collision resolution is unchanged.
function expandBarrelClauses(barrel) {
const clauses = [];
for (const ed of barrel.getExportDeclarations()) {
const target = resolvedFile(ed);
if (!target) continue;
if (isBarrelFile(target)) {
clauses.push(...expandBarrelClauses(target));
continue;
}
const file = target.getFilePath();
const isStar =
ed.getNamedExports().length === 0 && !ed.getNamespaceExport();
if (isStar) {
clauses.push({ kind: 'star', file });
} else if (ed.getNamespaceExport()) {
clauses.push({ kind: 'namespace', file, name: ed.getNamespaceExport().getName() });
} else {
const declType = ed.isTypeOnly();
const specs = ed.getNamedExports().map((s) => ({
name: s.getName(),
alias: s.getAliasNode()?.getText(),
isTypeOnly: declType || s.isTypeOnly(),
}));
clauses.push({ kind: 'named', file, isTypeOnly: declType, specs });
}
}
return clauses;
}
function allLeavesUnderDir(dirAbs) {
const out = [];
const walk = (d) => {
for (const ent of fs.readdirSync(d, { withFileTypes: true })) {
const p = path.join(d, ent.name);
if (ent.isDirectory()) walk(p);
else if (
ent.isFile() &&
p.endsWith('.ts') &&
!p.endsWith('.test.ts') &&
!p.endsWith('.d.ts') &&
path.basename(p) !== 'index.ts'
) {
out.push(p);
}
}
};
walk(dirAbs);
return out.sort();
}
// ---------------------------------------------------------------------------
// Consumer rewriting (imports + named exports + export *) for a single file.
// ---------------------------------------------------------------------------
function rewriteConsumerFile(sf, onlyBarrelPath) {
const report = { imports: 0, exports: 0, manuals: [], sideEffects: 0 };
// Imports.
for (const decl of [...sf.getImportDeclarations()]) {
const barrel = barrelOfDecl(decl);
if (!barrel) continue;
if (onlyBarrelPath && barrel.getFilePath() !== onlyBarrelPath) continue;
if (decl.getNamespaceImport()) {
report.manuals.push({ sf: sf.getFilePath(), text: decl.getText(), why: 'namespace import' });
continue;
}
const hasDefault = !!decl.getDefaultImport();
const named = decl.getNamedImports();
if (!hasDefault && named.length === 0) {
// side-effect: import '#/B' -> load each leaf of B.
const leaves = [...new Set(expandBarrelClauses(barrel).map((c) => c.file))];
const idx = sf.getImportDeclarations().indexOf(decl);
sf.insertImportDeclarations(
idx,
leaves.map((leaf) => ({ moduleSpecifier: relSpec(leaf) })),
);
decl.remove();
report.sideEffects += leaves.length;
report.imports++;
continue;
}
const declType = decl.isTypeOnly();
const groups = new Map(); // leafFile -> [{name, alias, isTypeOnly}]
const add = (leaf, spec) => {
if (!groups.has(leaf)) groups.set(leaf, []);
groups.get(leaf).push(spec);
};
if (hasDefault) {
const r = resolveName(barrel, 'default');
if (!r) report.manuals.push({ sf: sf.getFilePath(), text: decl.getText(), why: 'default import unresolved' });
else add(r.leafFile, { default: decl.getDefaultImport().getText() });
}
for (const s of named) {
const lookup = s.getName(); // module-exported name
const local = s.getAliasNode()?.getText() || s.getName();
const r = resolveName(barrel, lookup);
if (!r) {
report.manuals.push({ sf: sf.getFilePath(), text: s.getText(), why: 'named import unresolved' });
continue;
}
add(r.leafFile, {
name: r.leafName,
alias: local !== r.leafName ? local : undefined,
isTypeOnly: declType || s.isTypeOnly(),
});
}
const structures = buildImportStructures(groups);
const idx = sf.getImportDeclarations().indexOf(decl);
if (structures.length) sf.insertImportDeclarations(idx, structures);
decl.remove();
report.imports++;
}
// Exports.
for (const decl of [...sf.getExportDeclarations()]) {
const barrel = barrelOfDecl(decl);
if (!barrel) continue;
if (onlyBarrelPath && barrel.getFilePath() !== onlyBarrelPath) continue;
const isStar = decl.getNamedExports().length === 0 && !decl.getNamespaceExport();
if (isStar) {
const clauses = expandBarrelClauses(barrel);
decl.replaceWithText(clauses.map(exportClauseToText).join('\n'));
report.exports++;
continue;
}
if (decl.getNamespaceExport()) {
report.manuals.push({ sf: sf.getFilePath(), text: decl.getText(), why: 'namespace export' });
continue;
}
// named re-export
const declType = decl.isTypeOnly();
const groups = new Map();
for (const s of decl.getNamedExports()) {
const lookup = s.getName(); // name the consumer re-exports (= barrel's exported name)
const exportedAs = s.getAliasNode()?.getText() || s.getName();
const r = resolveName(barrel, lookup);
if (!r) {
report.manuals.push({ sf: sf.getFilePath(), text: s.getText(), why: 'named export unresolved' });
continue;
}
if (!groups.has(r.leafFile)) groups.set(r.leafFile, { specs: [], allType: true });
const g = groups.get(r.leafFile);
const t = declType || s.isTypeOnly();
g.allType = g.allType && t;
g.specs.push({
name: r.leafName,
alias: exportedAs !== r.leafName ? exportedAs : undefined,
isTypeOnly: t,
});
}
const lines = [];
for (const [leaf, { specs, allType }] of groups) {
lines.push(renderNamedExport(relSpec(leaf), specs, allType));
}
decl.replaceWithText(lines.join('\n'));
report.exports++;
}
return report;
}
function buildImportStructures(groups) {
const structures = [];
for (const [leaf, specs] of groups) {
const spec = relSpec(leaf);
const defaults = specs.filter((s) => s.default);
const namedSpecs = specs.filter((s) => !s.default);
for (const d of defaults) {
structures.push({ moduleSpecifier: spec, defaultImport: d.default });
}
const values = namedSpecs.filter((s) => !s.isTypeOnly);
const types = namedSpecs.filter((s) => s.isTypeOnly);
if (values.length)
structures.push({
moduleSpecifier: spec,
namedImports: values.map((v) => ({ name: v.name, alias: v.alias })),
});
if (types.length)
structures.push({
moduleSpecifier: spec,
isTypeOnly: true,
namedImports: types.map((t) => ({ name: t.name, alias: t.alias })),
});
}
return structures;
}
function renderNamedExport(spec, specs, allType) {
const body = specs
.map((s) => `${allType ? '' : s.isTypeOnly ? 'type ' : ''}${s.name}${s.alias ? ' as ' + s.alias : ''}`)
.join(', ');
return `${allType ? 'export type' : 'export'} { ${body} } from '${spec}';`;
}
function exportClauseToText(c) {
if (c.kind === 'star') return `export * from '${relSpec(c.file)}';`;
if (c.kind === 'namespace') return `export * as ${c.name} from '${relSpec(c.file)}';`;
return renderNamedExport(relSpec(c.file), c.specs, c.isTypeOnly);
}
// ---------------------------------------------------------------------------
// Entry (src/index.ts) regeneration.
// ---------------------------------------------------------------------------
function regenerateEntry() {
const entrySf = project.getSourceFileOrThrow(ENTRY);
const original = entrySf.getFullText();
const headerMatch = original.match(/^\s*\/\*\*[\s\S]*?\*\//);
const header = headerMatch ? headerMatch[0] : '/** agent-core-v2 public surface. */';
// First pass: classify each referenced barrel and how it is referenced.
/** @type {Array<{decl: any, barrel: any, mode: 'star'|'named'|'side'}>} */
const refs = [];
for (const decl of [...entrySf.getExportDeclarations(), ...entrySf.getImportDeclarations()]) {
const barrel = barrelOfDecl(decl);
if (!barrel) continue;
let mode;
if (decl.getKindName() === 'ImportDeclaration') mode = 'side';
else {
const isStar = decl.getNamedExports().length === 0 && !decl.getNamespaceExport();
mode = isStar ? 'star' : 'named';
}
refs.push({ decl, barrel, mode });
}
const publicLines = [];
const loadingLines = [];
const processed = new Set();
for (const { decl, barrel, mode } of refs) {
const bf = barrel.getFilePath();
const dirAbs = path.dirname(bf);
const allLeaves = allLeavesUnderDir(dirAbs);
const clauses = expandBarrelClauses(barrel);
const starLeaves = new Set(clauses.filter((c) => c.kind === 'star').map((c) => c.file));
if (mode === 'star') {
// Public: replay the barrel's clauses in order against precise leaves.
for (const c of clauses) publicLines.push(exportClauseToText(c));
} else if (mode === 'named') {
const declType = decl.isTypeOnly();
const groups = new Map();
for (const s of decl.getNamedExports()) {
const lookup = s.getName();
const exportedAs = s.getAliasNode()?.getText() || s.getName();
const r = resolveName(barrel, lookup);
if (!r) continue;
if (!groups.has(r.leafFile)) groups.set(r.leafFile, { specs: [], allType: true });
const g = groups.get(r.leafFile);
const t = declType || s.isTypeOnly();
g.allType = g.allType && t;
g.specs.push({
name: r.leafName,
alias: exportedAs !== r.leafName ? exportedAs : undefined,
isTypeOnly: t,
});
}
for (const [leaf, { specs, allType }] of groups) {
publicLines.push(renderNamedExport(relSpec(leaf), specs, allType));
}
}
// Loading: any leaf of this domain not already pulled in by an `export *`
// line must be imported for its side effects (registers).
for (const leaf of allLeaves) {
const key = leaf;
if (starLeaves.has(leaf)) continue; // loaded by export *
if (processed.has(key)) continue;
processed.add(key);
loadingLines.push(`import '${relSpec(leaf)}';`);
}
}
const body = [
header,
'',
'// Public surface — precise re-exports of each domain leaf (no barrels).',
...publicLines,
'',
'// Side-effect loading — ensure every domain leaf (and its top-level',
'// `register*` calls) is evaluated when the package is imported.',
...loadingLines,
'',
].join('\n');
if (!DRY) fs.writeFileSync(ENTRY, body);
return { publicLines: publicLines.length, loadingLines: loadingLines.length };
}
// ---------------------------------------------------------------------------
// Register-file enumeration + coverage verification.
// ---------------------------------------------------------------------------
const REGISTER_NAMES = new Set([
'registerScopedService',
'registerTool',
'registerErrorDomain',
'registerConfigSection',
'registerAgentProfile',
'registerFlagDefinition',
]);
function isModuleScoped(call) {
let n = call.getParent();
while (n) {
const k = n.getKindName();
if (
k === 'FunctionDeclaration' ||
k === 'FunctionExpression' ||
k === 'ArrowFunction' ||
k === 'MethodDeclaration' ||
k === 'Constructor' ||
k === 'ClassDeclaration'
) {
return false;
}
n = n.getParent();
}
return true;
}
function findRegisterFiles() {
const files = [];
for (const sf of project.getSourceFiles()) {
const f = sf.getFilePath();
if (!isUnderSrc(f) || f.endsWith('.test.ts')) continue;
let hit = false;
sf.forEachDescendant((node) => {
if (hit) return;
if (node.getKindName() !== 'CallExpression') return;
const expr = node.getExpression();
if (expr.getKindName() !== 'Identifier') return;
if (!REGISTER_NAMES.has(expr.getText())) return;
if (isModuleScoped(node)) hit = true;
});
if (hit) files.push(f);
}
return files.sort();
}
function reachedFromEntry() {
const reached = new Set();
const visit = (sf) => {
const f = sf.getFilePath();
if (reached.has(f)) return;
reached.add(f);
if (!isUnderSrc(f)) return;
const edges = [...sf.getImportDeclarations(), ...sf.getExportDeclarations()];
for (const d of edges) {
if (d.isTypeOnly && d.isTypeOnly()) continue; // type-only edges don't execute
const t = resolvedFile(d);
if (t && isUnderSrc(t.getFilePath())) visit(t);
}
};
visit(project.getSourceFileOrThrow(ENTRY));
return reached;
}
function verifyCoverage() {
const regs = findRegisterFiles();
const reached = reachedFromEntry();
const missing = regs.filter((f) => !reached.has(f));
console.log(`register files: ${regs.length}; reachable from entry: ${reached.size}; missing: ${missing.length}`);
if (missing.length) {
console.log('MISSING (not reachable from src/index.ts):');
for (const m of missing) console.log(' ' + path.relative(PKG, m));
return false;
}
return true;
}
function deleteBarrels() {
let n = 0;
for (const sf of project.getSourceFiles()) {
if (!isBarrelFile(sf)) continue;
const f = sf.getFilePath();
if (!DRY) fs.unlinkSync(f);
n++;
}
return n;
}
// ---------------------------------------------------------------------------
// Main dispatch.
// ---------------------------------------------------------------------------
function main() {
if (LIST_REGS) {
for (const f of findRegisterFiles()) console.log(path.relative(PKG, f));
return;
}
if (VERIFY) {
const ok = verifyCoverage();
process.exit(ok ? 0 : 1);
}
if (ENTRY_ONLY) {
const r = regenerateEntry();
console.log(`entry regenerated: ${r.publicLines} public lines, ${r.loadingLines} loading lines${DRY ? ' (dry-run)' : ''}`);
return;
}
let onlyBarrelPath = null;
if (ONLY) {
onlyBarrelPath = path.join(SRC, ONLY, 'index.ts');
if (!fs.existsSync(onlyBarrelPath)) {
console.error(`--only target not a barrel: ${path.relative(PKG, onlyBarrelPath)}`);
process.exit(2);
}
}
const totals = { files: 0, imports: 0, exports: 0, sideEffects: 0, manuals: [] };
for (const sf of project.getSourceFiles()) {
const f = sf.getFilePath();
if (!isUnderSrc(f) && !f.startsWith(path.join(PKG, 'test') + path.sep)) continue;
if (f === ENTRY) continue; // entry handled by --entry
const before = sf.getFullText();
const r = rewriteConsumerFile(sf, onlyBarrelPath);
if (sf.getFullText() !== before) {
totals.files++;
totals.imports += r.imports;
totals.exports += r.exports;
totals.sideEffects += r.sideEffects;
}
totals.manuals.push(...r.manuals);
}
if (!DRY) project.saveSync();
console.log(
`rewrote ${totals.files} files: ${totals.imports} barrel imports, ${totals.exports} barrel exports, ${totals.sideEffects} side-effect loads${DRY ? ' (dry-run)' : ''}`,
);
if (totals.manuals.length) {
console.log(`MANUAL (${totals.manuals.length}) — could not auto-split:`);
for (const m of totals.manuals)
console.log(` ${path.relative(PKG, m.sf)} :: ${m.why} :: ${m.text.replace(/\s+/g, ' ').slice(0, 120)}`);
}
if (DELETE_BARRELS) {
const n = deleteBarrels();
console.log(`deleted ${n} domain barrels${DRY ? ' (dry-run)' : ''}`);
}
}
main();

View file

@ -3,13 +3,7 @@
* portable `ErrorPayload` that crosses process / language boundaries.
*/
import {
APIConnectionError,
APIEmptyResponseError,
APIStatusError,
APITimeoutError,
ChatProviderError,
} from '#/app/llmProtocol';
import { APIConnectionError, APIEmptyResponseError, APIStatusError, APITimeoutError, ChatProviderError } from '#/app/llmProtocol/errors';
import { CoreErrors, errorInfo, isErrorCode } from './codes';
import type { ErrorCode } from './codes';

View file

@ -23,7 +23,7 @@
* caller read a region of the original back at full fidelity.
*/
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { sniffImageDimensions } from './file-type';

View file

@ -2,7 +2,8 @@
* Character-based token-count estimates for messages, tools, and content parts.
*/
import type { ContentPart, Message, Tool } from '#/app/llmProtocol';
import type { ContentPart, Message } from '#/app/llmProtocol/message';
import type { Tool } from '#/app/llmProtocol/tool';
const messageTokenEstimateCache = new WeakMap<Message, number>();

View file

@ -5,9 +5,9 @@
* loads them back on read. Bound at Agent scope.
*/
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
export const BLOBREF_PROTOCOL = 'blobref:';
export const MISSING_MEDIA_PLACEHOLDER = '[media missing]';

View file

@ -8,7 +8,7 @@
*/
import { createHash } from 'node:crypto';
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IAgentScopeContext } from '#/agent/scopeContext';

View file

@ -1,5 +1,5 @@
import { createDecorator } from "#/_base/di";
import type { IDisposable } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { IDisposable } from "#/_base/di/lifecycle";
export interface ContextInjectionContext {
/** Live positions of this variant's injections in the current history, ascending. */

View file

@ -1,7 +1,4 @@
import {
Disposable,
toDisposable,
} from "#/_base/di";
import { Disposable, toDisposable } from "#/_base/di/lifecycle";
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
@ -9,7 +6,7 @@ import { IAgentContextMemoryService } from '#/agent/contextMemory';
import { IAgentLoopService } from '#/agent/loop';
import { IAgentSystemReminderService } from '#/agent/systemReminder';
import { IAgentTurnService } from '#/agent/turn';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import type { ContextMessage } from '#/agent/contextMemory';
import {
IAgentContextInjectorService,

View file

@ -17,11 +17,11 @@ import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { escapeXmlAttr } from '#/_base/utils/xml-escape';
import { IAgentContextMemoryService } from '#/agent/contextMemory';
import { ILogService } from '#/_base/log';
import { IPluginService } from '#/app/plugin';
import { ILogService } from '#/_base/log/log';
import { IPluginService } from '#/app/plugin/plugin';
import type { EnabledPluginSessionStart } from '#/app/plugin/types';
import { ISessionSkillCatalog } from '#/session/sessionSkillCatalog';
import { ISessionContext } from '#/session/sessionContext';
import { ISessionSkillCatalog } from '#/session/sessionSkillCatalog/skillCatalog';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import type { SkillCatalog, SkillDefinition } from '#/app/skillCatalog/types';
import { IAgentSystemReminderService } from '#/agent/systemReminder';

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { UndoCut } from './contextOps';
import type { ContextMessage } from './types';

View file

@ -14,10 +14,10 @@
* Agent scope.
*/
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import { IAgentWireService, type IWireService } from '#/wire';
import { IAgentContextMemoryService, type ContextCompactionInput } from './contextMemory';

View file

@ -31,7 +31,7 @@
* data that was compacted away during the session.
*/
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { defineModel, defineOp, type PartsTransformer } from '#/wire';
import type { PersistedRecord } from '#/wire';

View file

@ -32,7 +32,7 @@
* concurrent replays of different agent scopes never share fold state.
*/
import { createToolMessage, type ContentPart, type ToolCall } from '#/app/llmProtocol';
import { createToolMessage, type ContentPart, type ToolCall } from '#/app/llmProtocol/message';
import type { ContextMessage } from './types';

View file

@ -1,4 +1,4 @@
import type { ContentPart, Message } from '#/app/llmProtocol';
import type { ContentPart, Message } from '#/app/llmProtocol/message';
import type { AgentTaskStatus } from '#/agent/task';
import type { CronJobOrigin, CronMissedOrigin } from '@moonshot-ai/protocol';

View file

@ -1,5 +1,5 @@
import { createDecorator } from "#/_base/di";
import type { Message } from '#/app/llmProtocol';
import { createDecorator } from "#/_base/di/instantiation";
import type { Message } from '#/app/llmProtocol/message';
import type { ContextMessage } from '#/agent/contextMemory';

View file

@ -1,12 +1,10 @@
import {
IInstantiationService,
} from "#/_base/di";
import { IInstantiationService } from "#/_base/di/instantiation";
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import type { ContextMessage } from '#/agent/contextMemory/types';
import { ErrorCodes, KimiError } from '#/errors';
import { IAgentMicroCompactionService } from '#/agent/microCompaction';
import type { ContentPart, Message } from '#/app/llmProtocol';
import type { ContentPart, Message } from '#/app/llmProtocol/message';
import { IAgentContextProjectorService } from './contextProjector';
export class AgentContextProjectorService implements IAgentContextProjectorService {

View file

@ -1,5 +1,6 @@
import { createDecorator } from '#/_base/di';
import type { Message, TokenUsage } from '#/app/llmProtocol';
import { createDecorator } from '#/_base/di/instantiation';
import type { Message } from '#/app/llmProtocol/message';
import type { TokenUsage } from '#/app/llmProtocol/usage';
export interface ContextSizeStatus {
readonly contextTokens: number;

View file

@ -14,13 +14,14 @@
* persisted (see `contextSizeOps`). Bound at Agent scope.
*/
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { estimateTokensForMessage } from '#/_base/utils/tokens';
import type { ContextMessage } from '#/agent/contextMemory';
import { IAgentContextMemoryService } from '#/agent/contextMemory';
import type { Message, TokenUsage } from '#/app/llmProtocol';
import type { Message } from '#/app/llmProtocol/message';
import type { TokenUsage } from '#/app/llmProtocol/usage';
import { IAgentWireService, type IWireService } from '#/wire';
import { IAgentContextSizeService, type ContextSizeStatus } from './contextSize';

View file

@ -7,7 +7,7 @@
* to invoke configured external commands.
*/
import { createDecorator } from '#/_base/di';
import { createDecorator } from '#/_base/di/instantiation';
import type { HookEngine } from './engine';
export interface RenderedExternalHookResult {

View file

@ -13,7 +13,8 @@
* this service directly.
*/
import { Disposable, IInstantiationService } from '#/_base/di';
import { IInstantiationService } from '#/_base/di/instantiation';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { isUserCancellation } from '#/_base/utils/abort';
@ -34,7 +35,7 @@ import {
type PromptSubmitContext,
} from '#/agent/prompt';
import type { HookResultEvent, TurnEndReason } from '@moonshot-ai/protocol';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import type {
ExecutableToolResult,
ToolDidExecuteContext,
@ -44,9 +45,9 @@ import { IAgentToolExecutorService } from '#/agent/toolExecutor';
import {
IAgentTurnService,
} from '#/agent/turn';
import { IBootstrapService } from '#/app/bootstrap';
import { IConfigService } from '#/app/config';
import { IPluginService } from '#/app/plugin';
import { IBootstrapService } from '#/app/bootstrap/bootstrap';
import { IConfigService } from '#/app/config/config';
import { IPluginService } from '#/app/plugin/plugin';
import { toKimiErrorPayload } from '#/errors';
import { HOOKS_SECTION, type HookDefConfig } from './configSection';

View file

@ -1,4 +1,4 @@
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
export const HOOK_EVENT_TYPES = [
'PreToolUse',

View file

@ -2,7 +2,7 @@
* `fullCompaction` domain error codes.
*/
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
export const FullCompactionErrors = {
codes: {

View file

@ -2,7 +2,7 @@ import type {
CompactionResult,
CompactionSource,
} from './types';
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { Hooks } from '#/hooks';
export type FullCompactionCompleteData = Omit<CompactionResult, 'summary'>;

View file

@ -1,6 +1,4 @@
import {
Disposable,
} from "#/_base/di";
import { Disposable } from "#/_base/di/lifecycle";
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { renderPrompt } from "#/_base/utils/render-prompt";
@ -18,16 +16,13 @@ import { IAgentLoopService, type TurnErrorContext } from '#/agent/loop';
import { isAbortError, isContextOverflowError } from '#/agent/loop/errors';
import { IAgentProfileService } from '#/agent/profile';
import { IAgentTurnService } from '#/agent/turn';
import { ISessionTodoService, renderTodoList, type TodoItem } from '#/session/todo';
import {
APIContextOverflowError,
APIEmptyResponseError,
createUserMessage,
type Message,
type TokenUsage
} from '#/app/llmProtocol';
import { IEventBus } from '#/app/event';
import { ITelemetryService } from '#/app/telemetry';
import { ISessionTodoService } from '#/session/todo/sessionTodo';
import { renderTodoList, type TodoItem } from '#/session/todo/todoItem';
import { APIContextOverflowError, APIEmptyResponseError } from '#/app/llmProtocol/errors';
import { createUserMessage, type Message } from '#/app/llmProtocol/message';
import { type TokenUsage } from '#/app/llmProtocol/usage';
import { IEventBus } from '#/app/event/eventBus';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { ErrorCodes, KimiError, isKimiError, toKimiErrorPayload } from "#/errors";
import { IAgentWireService, type IWireService } from '#/wire';
import compactionInstructionTemplate from './compaction-instruction.md?raw';

View file

@ -1,7 +1,7 @@
import type { Message } from '#/app/llmProtocol';
import type { Message } from '#/app/llmProtocol/message';
import type { ProfileModelContext } from '#/agent/profile';
import type { CompactionSource } from './types';
import { estimateTokensForMessage } from '#/_base/utils';
import { estimateTokensForMessage } from '#/_base/utils/tokens';
export interface CompactionConfig {
triggerRatio: number;

View file

@ -2,7 +2,7 @@
* `goal` domain error codes.
*/
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
export const GoalErrors = {
codes: {

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type {
CreateGoalInput,
GoalActor,

View file

@ -21,7 +21,7 @@
import { randomUUID } from 'node:crypto';
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IAgentContextInjectorService } from '#/agent/contextInjector';
@ -43,12 +43,12 @@ import {
} from '#/agent/loop';
import { IAgentSystemReminderService } from '#/agent/systemReminder';
import { IAgentTurnService, type TurnResult } from '#/agent/turn';
import type { TokenUsage } from '#/app/llmProtocol';
import type { TelemetryProperties } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry';
import type { TokenUsage } from '#/app/llmProtocol/usage';
import type { TelemetryProperties } from '#/app/telemetry/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { ErrorCodes, KimiError, toKimiErrorPayload, type KimiErrorPayload } from '#/errors';
import { IAgentWireService, type IWireService } from '#/wire';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import { IAgentGoalService, type GoalReasonInput } from './goal';
import { clearGoal, createGoal, GoalModel, updateGoal, type GoalState } from './goalOps';

View file

@ -1,5 +1,5 @@
import type { GoalSnapshot } from '#/agent/goal';
import { Disposable } from "#/_base/di";
import { Disposable } from "#/_base/di/lifecycle";
import { renderPrompt } from "#/_base/utils/render-prompt";
import { IAgentContextInjectorService } from '#/agent/contextInjector/contextInjector';
import GOAL_ACTIVE_REMINDER from './goal-active-reminder.md?raw';

View file

@ -1,12 +1,9 @@
import { createDecorator } from '#/_base/di';
import type {
FinishReason,
Message,
StreamedMessagePart,
TokenUsage,
Tool,
} from '#/app/llmProtocol';
import type { LogContext } from '#/_base/log';
import { createDecorator } from '#/_base/di/instantiation';
import type { FinishReason } from '#/app/llmProtocol/finishReason';
import type { Message, StreamedMessagePart } from '#/app/llmProtocol/message';
import type { Tool } from '#/app/llmProtocol/tool';
import type { TokenUsage } from '#/app/llmProtocol/usage';
import type { LogContext } from '#/_base/log/log';
export type LLMRequestLogFields = Readonly<LogContext>;

View file

@ -22,26 +22,18 @@ import { IAgentContextSizeService } from '#/agent/contextSize';
import { IAgentProfileService } from '#/agent/profile';
import { IAgentToolRegistryService } from '#/agent/toolRegistry';
import { IAgentUsageService } from '#/agent/usage';
import { IConfigService } from '#/app/config';
import {
APIConnectionError,
APIContextOverflowError,
APIEmptyResponseError,
APIStatusError,
APITimeoutError,
emptyUsage,
isContextOverflowStatusError,
isRetryableGenerateError,
type Message,
type ThinkingEffort,
type TokenUsage,
type Tool,
} from '#/app/llmProtocol';
import { ILogService, type LogContext } from '#/_base/log';
import type { KimiModelOverrides, Model, ModelRequestEvent } from '#/app/model';
import { IConfigService } from '#/app/config/config';
import { APIConnectionError, APIContextOverflowError, APIEmptyResponseError, APIStatusError, APITimeoutError, isContextOverflowStatusError, isRetryableGenerateError } from '#/app/llmProtocol/errors';
import { type Message } from '#/app/llmProtocol/message';
import { type ThinkingEffort } from '#/app/llmProtocol/thinkingEffort';
import { type Tool } from '#/app/llmProtocol/tool';
import { emptyUsage, type TokenUsage } from '#/app/llmProtocol/usage';
import { ILogService, type LogContext } from '#/_base/log/log';
import type { Model, LLMEvent as ModelRequestEvent } from '#/app/model/modelInstance';
import type { KimiModelOverrides } from '#/app/model/modelOverrides';
import { applyCompletionBudget, resolveCompletionBudget } from '#/app/model/completionBudget';
import type { Protocol } from '#/app/protocol';
import { ITelemetryService } from '#/app/telemetry';
import type { Protocol } from '#/app/protocol/protocol';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import type {
LLMRequestFinish,

View file

@ -2,8 +2,9 @@
* `loop` domain error codes and loop-local error helpers.
*/
import { KimiError, isKimiError, registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { APIContextOverflowError } from '#/app/llmProtocol';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
import { KimiError, isKimiError } from '#/_base/errors/errors';
import { APIContextOverflowError } from '#/app/llmProtocol/errors';
export const LoopErrors = {
codes: {

View file

@ -1,5 +1,6 @@
import { createDecorator } from '#/_base/di';
import type { FinishReason, TokenUsage } from '#/app/llmProtocol';
import { createDecorator } from '#/_base/di/instantiation';
import type { FinishReason } from '#/app/llmProtocol/finishReason';
import type { TokenUsage } from '#/app/llmProtocol/usage';
import type { Hooks } from '#/hooks';
import type { TurnEndReason } from '@moonshot-ai/protocol';

View file

@ -14,15 +14,11 @@ import type {
import { IAgentLLMRequesterService, type LLMRequestFinish } from '#/agent/llmRequester';
import type { ToolResult } from '#/agent/tool';
import { IAgentToolExecutorService } from '#/agent/toolExecutor';
import { IConfigService } from '#/app/config';
import { IEventBus } from '#/app/event';
import {
createToolMessage,
type ContentPart,
type FinishReason,
type StreamedMessagePart,
type TokenUsage,
} from '#/app/llmProtocol';
import { IConfigService } from '#/app/config/config';
import { IEventBus } from '#/app/event/eventBus';
import { type FinishReason } from '#/app/llmProtocol/finishReason';
import { createToolMessage, type ContentPart, type StreamedMessagePart } from '#/app/llmProtocol/message';
import { type TokenUsage } from '#/app/llmProtocol/usage';
import { ErrorCodes, KimiError } from '#/errors';
import { OrderedHookSlot } from '#/hooks';

View file

@ -1,7 +1,7 @@
import { readFile, stat } from 'node:fs/promises';
import { dirname, isAbsolute, join, normalize, resolve } from 'pathe';
import { resolveKimiHome } from '#/app/bootstrap';
import { resolveKimiHome } from '#/app/bootstrap/bootstrap';
import { McpServerConfigSchema, type McpServerConfig } from './config-schema';
import { ErrorCodes, KimiError } from '#/errors';
import { z } from 'zod';

View file

@ -11,8 +11,8 @@
import { ErrorCodes, KimiError } from '#/errors';
import type { McpServerConfig } from './config-schema';
import type { ILogger as Logger } from '#/_base/log';
import type { Tool } from '#/app/llmProtocol';
import type { ILogger as Logger } from '#/_base/log/log';
import type { Tool } from '#/app/llmProtocol/tool';
import { abortable } from '#/_base/utils/abort';
import { HttpMcpClient } from './client-http';

View file

@ -2,7 +2,7 @@
* `mcp` domain error codes.
*/
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
export const McpErrors = {
codes: {

View file

@ -1,6 +1,7 @@
import type { Tool as KosongTool } from '#/app/llmProtocol';
import type { Tool as KosongTool } from '#/app/llmProtocol/tool';
import { createDecorator, type IDisposable } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import { type IDisposable } from "#/_base/di/lifecycle";
import type {
McpConnectionManager,
McpServerEntry,

View file

@ -1,18 +1,15 @@
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import type { Tool as KosongTool } from '#/app/llmProtocol';
import type { Tool as KosongTool } from '#/app/llmProtocol/tool';
import {
Disposable,
type IDisposable,
} from "#/_base/di";
import { Disposable, type IDisposable } from "#/_base/di/lifecycle";
import { ErrorCodes, makeErrorPayload } from "#/errors";
import type {
ErrorEvent,
McpServerStatusEvent,
ToolListUpdatedEvent,
} from '@moonshot-ai/protocol';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import { IAgentToolExecutorService } from '#/agent/toolExecutor';
import { IAgentToolRegistryService } from '#/agent/toolRegistry';
import { createMcpAuthTool } from '#/agent/mcp/tools/auth';

View file

@ -25,7 +25,7 @@
* helpers stay private so callers cannot bypass the limits.
*/
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { compressImageContentParts } from '#/_base/tools/support/image-compress';
import { persistOriginalImage } from '#/_base/tools/support/image-originals';

View file

@ -6,7 +6,7 @@
* and normalizes the result.
*/
import type { Tool as KosongTool } from '#/app/llmProtocol';
import type { Tool as KosongTool } from '#/app/llmProtocol/tool';
import type { ExecutableTool, ExecutableToolResult } from '#/agent/tool';
import { mcpResultToExecutableOutput } from '#/agent/mcp/output';

View file

@ -13,10 +13,10 @@
* closure; media tooling doesn't need to know about tokens.
*/
import type { ModelCapability } from '#/app/llmProtocol';
import type { Model } from '#/app/model';
import type { ModelCapability } from '#/app/llmProtocol/capability';
import type { Model } from '#/app/model/modelInstance';
import { toDisposable, type IDisposable } from '#/_base/di';
import { toDisposable, type IDisposable } from '#/_base/di/lifecycle';
import type { WorkspaceConfig } from '#/_base/tools/support/workspace';
import type { IHostFileSystem } from '#/os/interface/hostFileSystem';
import type { IHostEnvironment } from '#/os/interface/hostEnvironment';

View file

@ -27,12 +27,9 @@
* only registered when the active model supports image or video input.
*/
import type {
ContentPart,
ModelCapability,
VideoUploadInput as ProviderVideoUploadInput,
VideoURLPart,
} from '#/app/llmProtocol';
import type { ModelCapability } from '#/app/llmProtocol/capability';
import type { ContentPart, VideoURLPart } from '#/app/llmProtocol/message';
import type { VideoUploadInput as ProviderVideoUploadInput } from '#/app/llmProtocol/request';
import { z } from 'zod';
import { IHostFileSystem } from '#/os/interface/hostFileSystem';

View file

@ -5,7 +5,7 @@
* flag is available process-wide before any consumer resolves `IFlagService`.
*/
import { type FlagDefinitionInput, registerFlagDefinition } from '#/app/flag';
import { type FlagDefinitionInput, registerFlagDefinition } from '#/app/flag/flagRegistry';
export const microCompactionFlag: FlagDefinitionInput = {
id: 'micro_compaction',

View file

@ -5,7 +5,7 @@
* `IAgentMicroCompactionService` used by context projection. Bound at Agent scope.
*/
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { ContextMessage } from '#/agent/contextMemory';
export interface MicroCompactionConfig {

View file

@ -15,26 +15,24 @@
* Agent scope.
*/
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import {
Disposable,
} from "#/_base/di";
import { Disposable } from "#/_base/di/lifecycle";
import {
estimateTokensForContentParts,
estimateTokensForMessages,
} from "#/_base/utils/tokens";
import type { TelemetryProperties } from '#/app/telemetry';
import { IConfigService } from '#/app/config';
import { IEventBus } from '#/app/event';
import type { TelemetryProperties } from '#/app/telemetry/telemetry';
import { IConfigService } from '#/app/config/config';
import { IEventBus } from '#/app/event/eventBus';
import { IAgentContextMemoryService } from '#/agent/contextMemory';
import { IAgentContextSizeService } from '#/agent/contextSize';
import { IFlagService } from '#/app/flag';
import { IFlagService } from '#/app/flag/flag';
import { IAgentLoopService } from '#/agent/loop';
import { IAgentProfileService } from '#/agent/profile';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import type { ContextMessage } from '#/agent/contextMemory';
import { IAgentWireService, type IWireService } from '#/wire';
import {

View file

@ -3,7 +3,7 @@ import type {
ApprovalResponse,
PermissionData,
} from '#/agent/permissionPolicy';
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type {
AuthorizeToolExecutionResult,
ResolvedToolExecutionHookContext,

View file

@ -5,10 +5,8 @@ import {
type PermissionPolicyResolution,
type PermissionPolicyResult,
} from '#/agent/permissionPolicy';
import {
Disposable,
IInstantiationService,
} from "#/_base/di";
import { IInstantiationService } from "#/_base/di/instantiation";
import { Disposable } from "#/_base/di/lifecycle";
import { abortable, isUserCancellation } from '#/_base/utils/abort';
import type {
AuthorizeToolExecutionResult,
@ -18,8 +16,8 @@ import type { ToolInputDisplay } from '@moonshot-ai/protocol';
import { ISessionApprovalService } from "#/session/approval/approval";
import { IAgentPermissionModeService } from '#/agent/permissionMode';
import { IAgentPermissionRulesService } from '#/agent/permissionRules';
import { ISessionContext } from '#/session/sessionContext';
import { ITelemetryService } from '#/app/telemetry';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentToolExecutorService } from '#/agent/toolExecutor';
import { IAgentScopeContext } from '#/agent/scopeContext';
import {
@ -29,7 +27,7 @@ import {
} from './permissionGate';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
declare module '#/app/event/eventBus' {
interface DomainEventMap {

View file

@ -1,5 +1,5 @@
import type { PermissionMode } from '#/agent/permissionPolicy';
import type { IDisposable } from "#/_base/di";
import type { IDisposable } from "#/_base/di/lifecycle";
import type { IAgentContextInjectorService } from '#/agent/contextInjector/contextInjector';
import type { IAgentPermissionModeService } from '#/agent/permissionMode/permissionMode';
import AUTO_MODE_ENTER_REMINDER from './permission-mode-auto-enter-reminder.md?raw';

View file

@ -1,5 +1,5 @@
import type { PermissionMode } from '#/agent/permissionPolicy';
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { Hooks } from '#/hooks';

View file

@ -10,7 +10,7 @@
*/
import type { PermissionMode } from '#/agent/permissionPolicy';
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IAgentContextInjectorService } from '#/agent/contextInjector';

View file

@ -1,4 +1,5 @@
import { createDecorator, type IDisposable } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import { type IDisposable } from "#/_base/di/lifecycle";
import type {
ResolvedToolExecutionHookContext
} from '#/agent/tool';

View file

@ -1,8 +1,5 @@
import {
Disposable,
IInstantiationService,
type IDisposable,
} from "#/_base/di";
import { IInstantiationService } from "#/_base/di/instantiation";
import { Disposable, type IDisposable } from "#/_base/di/lifecycle";
import type { ResolvedToolExecutionHookContext } from '#/agent/tool';
import { AgentSwarmExclusiveDenyPermissionPolicyService } from '#/agent/permissionPolicy/policies/agent-swarm-exclusive-deny';
import { AutoModeApprovePermissionPolicyService } from '#/agent/permissionPolicy/policies/auto-mode-approve';

View file

@ -1,8 +1,8 @@
import type { ResolvedToolExecutionHookContext } from '#/agent/tool';
import { IHostEnvironment } from '#/os/interface/hostEnvironment';
import type { IHostEnvironment as HostEnvironment } from '#/os/interface/hostEnvironment';
import { ISessionWorkspaceContext } from '#/session/workspaceContext';
import type { ISessionWorkspaceContext as WorkspaceContext } from '#/session/workspaceContext';
import { ISessionWorkspaceContext } from '#/session/workspaceContext/workspaceContext';
import type { ISessionWorkspaceContext as WorkspaceContext } from '#/session/workspaceContext/workspaceContext';
import type {
PermissionPolicy,
PermissionPolicyResult,

View file

@ -2,8 +2,8 @@ import type { ResolvedToolExecutionHookContext } from '#/agent/tool';
import { isWithinWorkspace } from '#/_base/tools/policies/path-access';
import { IHostEnvironment } from '#/os/interface/hostEnvironment';
import type { IHostEnvironment as HostEnvironment } from '#/os/interface/hostEnvironment';
import { ISessionWorkspaceContext } from '#/session/workspaceContext';
import type { ISessionWorkspaceContext as WorkspaceContext } from '#/session/workspaceContext';
import { ISessionWorkspaceContext } from '#/session/workspaceContext/workspaceContext';
import type { ISessionWorkspaceContext as WorkspaceContext } from '#/session/workspaceContext/workspaceContext';
import type {
PermissionPolicy,
PermissionPolicyResult,

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { ApprovalResponse } from "@moonshot-ai/protocol";
import type { Hooks } from '#/hooks';

View file

@ -11,7 +11,7 @@
* consumers read the getters instead. Bound at Agent scope.
*/
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
export type PlanData = null | {
readonly id: string;

View file

@ -8,15 +8,14 @@ import {
join
} from 'pathe';
import {
Disposable,
} from "#/_base/di";
import { Disposable } from "#/_base/di/lifecycle";
import { generateHeroSlug } from "#/_base/utils/hero-slug";
import { IAgentContextMemoryService, type ContextMessage } from '#/agent/contextMemory';
import { IAgentContextInjectorService } from '#/agent/contextInjector';
import { IHostFileSystem } from '#/os/interface/hostFileSystem';
import { IAgentProfileService } from '#/agent/profile';
import { IAgentTelemetryContextService, ITelemetryService } from '#/app/telemetry';
import { IAgentTelemetryContextService } from '#/app/telemetry/agentTelemetryContext';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentWireService, type IWireService } from '#/wire';
import type { ToolInputDisplay } from '@moonshot-ai/protocol';
import type { ExecutableToolResult } from '#/agent/tool';

View file

@ -11,7 +11,7 @@
* before `AgentProfileCatalogService` constructs.
*/
import { registerAgentProfile } from '#/app/agentProfileCatalog';
import { registerAgentProfile } from '#/app/agentProfileCatalog/contribution';
import {
renderSystemPrompt,
TASK_AGENT_ROLE_PREFIX,

View file

@ -11,7 +11,7 @@ import type { BuiltinTool } from '#/agent/tool';
import type { ToolExecution } from '#/agent/tool';
import { registerTool } from '#/agent/toolRegistry';
import { toInputJsonSchema } from '#/_base/tools/support/input-schema';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentPlanService } from '#/agent/plan/plan';
import DESCRIPTION from './enter-plan-mode.md?raw';

View file

@ -13,7 +13,7 @@ import type { BuiltinTool } from '#/agent/tool';
import type { ExecutableToolResult, ToolExecution } from '#/agent/tool';
import { registerTool } from '#/agent/toolRegistry';
import { toInputJsonSchema } from '#/_base/tools/support/input-schema';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentPlanService } from '#/agent/plan/plan';
import type { PlanData } from '#/agent/plan/plan';
import DESCRIPTION from './exit-plan-mode.md?raw';

View file

@ -9,8 +9,8 @@
import { z } from 'zod';
import { parseBooleanEnv } from '#/_base/utils';
import { type EnvBindings, envBindings } from '#/app/config';
import { parseBooleanEnv } from '#/_base/utils/env';
import { type EnvBindings, envBindings } from '#/app/config/config';
import { registerConfigSection } from '#/app/config/configSectionContributions';
export const THINKING_SECTION = 'thinking';

View file

@ -2,7 +2,7 @@
* `profile` domain error codes model/provider configuration failures.
*/
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
export const ProfileErrors = {
codes: {

View file

@ -1,8 +1,9 @@
import type { AgentProfile, AgentProfileContext } from '#/app/agentProfileCatalog';
import type { ModelCapability, ThinkingEffort } from '#/app/llmProtocol';
import type { Model } from '#/app/model';
import type { AgentProfile, AgentProfileContext } from '#/app/agentProfileCatalog/agentProfileCatalog';
import type { ModelCapability } from '#/app/llmProtocol/capability';
import type { ThinkingEffort } from '#/app/llmProtocol/thinkingEffort';
import type { Model } from '#/app/model/modelInstance';
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { ToolSource } from '#/agent/tool';
/**

View file

@ -26,7 +26,7 @@
* Consumed by the Agent-scope `profileService`.
*/
import type { ThinkingEffort } from '#/app/llmProtocol';
import type { ThinkingEffort } from '#/app/llmProtocol/thinkingEffort';
import { defineModel, defineOp } from '#/wire';
export interface ProfileModelState {

View file

@ -23,37 +23,33 @@
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import {
UNKNOWN_CAPABILITY,
type GenerationKwargs,
type ModelCapability,
type ThinkingEffort,
} from '#/app/llmProtocol';
import {
DEFAULT_AGENT_PROFILE_NAME,
IAgentProfileCatalogService,
} from '#/app/agentProfileCatalog';
import { IModelResolver, type KimiModelOverrides, type Model } from '#/app/model';
import { UNKNOWN_CAPABILITY, type ModelCapability } from '#/app/llmProtocol/capability';
import { type GenerationKwargs } from '#/app/llmProtocol/kimiOptions';
import { type ThinkingEffort } from '#/app/llmProtocol/thinkingEffort';
import { DEFAULT_AGENT_PROFILE_NAME, IAgentProfileCatalogService } from '#/app/agentProfileCatalog/agentProfileCatalog';
import { type Model } from '#/app/model/modelInstance';
import { type KimiModelOverrides } from '#/app/model/modelOverrides';
import { IModelResolver } from '#/app/model/modelResolver';
import picomatch from 'picomatch';
import { ErrorCodes, KimiError } from "#/errors";
import { IBootstrapService } from '#/app/bootstrap';
import { IConfigService } from '#/app/config';
import { IBootstrapService } from '#/app/bootstrap/bootstrap';
import { IConfigService } from '#/app/config/config';
import { resolveThinkingEffort } from './thinking';
import type { LoopControl } from '#/agent/loop/configSection';
import { IHostEnvironment } from '#/os/interface/hostEnvironment';
import { IHostFileSystem } from '#/os/interface/hostFileSystem';
import { ISessionContext } from '#/session/sessionContext';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { isMcpToolName } from '#/agent/tool';
import { ISessionWorkspaceContext } from '#/session/workspaceContext';
import { ISessionSkillCatalog } from '#/session/sessionSkillCatalog';
import { ISessionWorkspaceContext } from '#/session/workspaceContext/workspaceContext';
import { ISessionSkillCatalog } from '#/session/sessionSkillCatalog/skillCatalog';
import type { ResolvedAgentProfile, SystemPromptContext } from '#/agent/profile';
import type { WarningEvent } from '@moonshot-ai/protocol';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import type { ToolSource } from '#/agent/tool';
import { IAgentWireService, type IWireService } from '#/wire';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import { prepareSystemPromptContext } from './context';
import type {
ApplyProfileOptions,

View file

@ -6,7 +6,7 @@
* the `defaultThinking` toggle. Pure functions; own no scoped state.
*/
import type { ThinkingEffort } from '#/app/llmProtocol';
import type { ThinkingEffort } from '#/app/llmProtocol/thinkingEffort';
import {
type ModelThinkingMetadata,
resolveThinkingEffortForModel,

View file

@ -2,7 +2,7 @@
* `prompt` domain error codes request/input validation failures.
*/
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
export const PromptErrors = {
codes: {

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { ContextMessage } from "#/agent/contextMemory";
import type { Turn } from "#/agent/turn";
import type { Hooks } from '#/hooks';

View file

@ -16,7 +16,14 @@ import { IAgentPermissionModeService } from '#/agent/permissionMode/permissionMo
import { IAgentProfileService } from '#/agent/profile/profile';
import { IAgentPromptService } from '#/agent/prompt/prompt';
import { IAgentTurnService, type Turn, type TurnResult } from '#/agent/turn/turn';
import type { ContentPart } from '#/app/llmProtocol';
import {
applyPromptMetadataUpdate,
promptMetadataTextFromContentParts,
} from '#/agent/rpc/prompt-metadata';
import type { ContentPart } from '#/app/llmProtocol/message';
import { IEventService } from '#/app/event/event';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { ISessionMetadata } from '#/session/sessionMetadata/sessionMetadata';
import type {
PromptAbortResponse,
PromptItem,
@ -53,6 +60,9 @@ export class AgentPromptLegacyService implements IAgentPromptLegacyService {
@IAgentTurnService private readonly turnService: IAgentTurnService,
@IAgentProfileService private readonly profile: IAgentProfileService,
@IAgentPermissionModeService private readonly permissionMode: IAgentPermissionModeService,
@ISessionMetadata private readonly metadata: ISessionMetadata,
@IEventService private readonly eventService: IEventService,
@ISessionContext private readonly sessionContext: ISessionContext,
) {}
list(): PromptListResponse {
@ -144,6 +154,18 @@ export class AgentPromptLegacyService implements IAgentPromptLegacyService {
if (parts.length === 0) {
throw new KimiError(ErrorCodes.REQUEST_INVALID, 'prompt content has no supported parts');
}
// Mirror v1 (web REST submit -> core.rpc.prompt -> updatePromptMetadata):
// persist `lastPrompt` and derive an easy title from the first prompt so the
// web session title is populated as soon as the conversation starts. This is
// the entry the web actually uses (`POST /api/v1/sessions/{id}/prompts`).
await applyPromptMetadataUpdate(
{
metadata: this.metadata,
eventService: this.eventService,
sessionId: this.sessionContext.sessionId,
},
promptMetadataTextFromContentParts(parts),
);
const turn = await this.prompt.prompt({
id: record.promptId,
role: 'user',

View file

@ -12,8 +12,8 @@ import { z } from 'zod';
import { toInputJsonSchema } from '#/_base/tools/support/input-schema';
import { IAgentTaskService } from '#/agent/task';
import { ITelemetryService } from '#/app/telemetry';
import type { TelemetryProperties } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import type { TelemetryProperties } from '#/app/telemetry/telemetry';
import type {
BuiltinTool,
ExecutableToolContext,

View file

@ -9,7 +9,7 @@ import type { PlanData } from '#/agent/plan';
import type { ToolInfo } from '#/agent/tool';
import type { SessionSummary } from '#/agent/rpc/core-api';
import type { UsageStatus } from '@moonshot-ai/protocol';
import type { SessionMeta } from '#/session/sessionMetadata';
import type { SessionMeta } from '#/session/sessionMetadata/sessionMetadata';
/**
* Wire projection of the agent's role in the resume DTO: `'main'` when

View file

@ -14,24 +14,19 @@ import type { PermissionData, PermissionMode } from '#/agent/permissionPolicy';
import type { PlanData } from '#/agent/plan';
import type { SwarmModeTrigger } from '#/agent/swarm';
import type { ToolInfo } from '#/agent/tool';
import type { ResolvedConfig } from '#/app/config';
import type { ResolvedConfig } from '#/app/config/config';
import type { McpServerConfig } from '#/agent/mcp';
import type { ExperimentalFeatureState } from '#/app/flag';
import type { ExperimentalFeatureState } from '#/app/flag/flag';
import type { ResumeSessionResult } from '#/agent/replayBuilder/types';
import type { SessionMeta } from '#/session/sessionMetadata';
import type { ContentPart } from '#/app/llmProtocol';
import type { SessionMeta } from '#/session/sessionMetadata/sessionMetadata';
import type { ContentPart } from '#/app/llmProtocol/message';
import type { SessionWarning, UsageStatus } from '@moonshot-ai/protocol';
import type { ExportSessionPayload, ExportSessionResult } from '#/app/sessionExport';
import type { PluginCommandDef, PluginInfo, PluginSummary, ReloadSummary } from '#/app/plugin';
import type { ExportSessionPayload, ExportSessionResult } from '#/app/sessionExport/sessionExport';
import type { PluginCommandDef, PluginInfo, PluginSummary, ReloadSummary } from '#/app/plugin/types';
import type { WithAgentId, WithSessionId } from './types';
export type {
ExportSessionManifest,
ExportSessionPayload,
ExportSessionResult,
ShellEnvironment,
} from '#/app/sessionExport';
export type { ExportSessionManifest, ExportSessionPayload, ExportSessionResult, ShellEnvironment } from '#/app/sessionExport/sessionExport';
export type JsonPrimitive = string | number | boolean | null;
export type JsonValue = JsonPrimitive | JsonValue[] | { readonly [key: string]: JsonValue };

View file

@ -1,4 +1,6 @@
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import type { IEventService } from '#/app/event/event';
import type { ISessionMetadata } from '#/session/sessionMetadata/sessionMetadata';
import type {
ActivatePluginCommandPayload,
@ -14,12 +16,27 @@ export function titleFromPromptMetadataText(text: string): string {
}
export function promptMetadataTextFromPayload(payload: PromptPayload): string | undefined {
const parts: string[] = [];
for (const part of payload.input) {
return promptMetadataTextFromContentParts(payload.input);
}
/**
* Extract the title/lastPrompt source text from already-projected core
* `ContentPart`s (the `{ text | image_url | video_url | ... }` shape). Shared by
* the `/api/v2` RPC entry (`PromptPayload.input`) and the `/api/v1` legacy
* entry (`PromptSubmission.content` projected via `contentToCoreParts`), so the
* easy-title derivation is identical on both surfaces mirroring v1, where
* the web REST submit funnels through the same `core.rpc.prompt` that derives
* the title.
*/
export function promptMetadataTextFromContentParts(
parts: readonly ContentPart[],
): string | undefined {
const texts: string[] = [];
for (const part of parts) {
const text = promptPartText(part);
if (text !== undefined) parts.push(text);
if (text !== undefined) texts.push(text);
}
return sanitizeAndTruncatePromptText(parts.join('\n'), MAX_LAST_PROMPT_LENGTH);
return sanitizeAndTruncatePromptText(texts.join('\n'), MAX_LAST_PROMPT_LENGTH);
}
export function promptMetadataTextFromSkill(payload: ActivateSkillPayload): string | undefined {
@ -41,6 +58,58 @@ export function promptMetadataTextFromPluginCommand(
);
}
/** Mirrors v1's `isUntitled`: empty / missing / the default "New Session". */
export function isUntitled(title: string | undefined): boolean {
return title === undefined || title.trim().length === 0 || title === 'New Session';
}
export interface PromptMetadataUpdateTarget {
readonly metadata: ISessionMetadata;
readonly eventService: IEventService;
readonly sessionId: string;
}
/**
* Mirror v1's `Session.updatePromptMetadata`: persist the prompt text as
* `lastPrompt` and, when the session is still untitled and has no custom title,
* derive an easy `title` from it. Then broadcast `session.meta.updated` on the
* global `IEventService` so the web session list / title updates live (the edge
* fans it out to every connection, not just this session's subscribers).
*
* Single source of truth shared by the `/api/v2` RPC entry (`AgentRPCService`)
* and the `/api/v1` legacy entry (`AgentPromptLegacyService`); v1 keeps this
* logic in the one `core.rpc.prompt` that both the TUI and the web funnel
* through.
*/
export async function applyPromptMetadataUpdate(
target: PromptMetadataUpdateTarget,
text: string | undefined,
): Promise<void> {
if (text === undefined) return;
const current = await target.metadata.read();
const patch: { lastPrompt: string; title?: string; isCustomTitle?: boolean } = {
lastPrompt: text,
};
if (!current.isCustomTitle && isUntitled(current.title)) {
patch.title = titleFromPromptMetadataText(text);
patch.isCustomTitle = false;
}
await target.metadata.update(patch);
target.eventService.publish({
type: 'session.meta.updated',
payload: {
agentId: 'main',
sessionId: target.sessionId,
title: patch.title,
patch: {
title: patch.title,
isCustomTitle: patch.isCustomTitle,
lastPrompt: text,
},
},
});
}
function promptPartText(part: ContentPart): string | undefined {
switch (part.type) {
case 'text':

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type {
AgentAPI,
SessionAPI,

View file

@ -12,21 +12,23 @@ import type {
ShellOutputEvent,
ShellStartedEvent,
} from '@moonshot-ai/protocol';
import { IEventBus, IEventService } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import { IEventService } from '#/app/event/event';
import { ErrorCodes, KimiError } from '#/errors';
import { userCancellationReason } from '#/_base/utils/abort';
import { IAgentPermissionGate } from '#/agent/permissionGate';
import { IAgentPermissionModeService } from '#/agent/permissionMode/permissionMode';
import { IAgentPlanService } from '#/agent/plan';
import { IHostEnvironment } from '#/os/interface/hostEnvironment';
import { expandCommandArguments, IPluginService } from '#/app/plugin';
import { expandCommandArguments } from '#/app/plugin/commands';
import { IPluginService } from '#/app/plugin/plugin';
import { IAgentProfileService } from '#/agent/profile';
import { IAgentPromptService } from '#/agent/prompt';
import { ISessionMetadata, type SessionMetaPatch } from '#/session/sessionMetadata';
import { ISessionContext } from '#/session/sessionContext';
import { ISessionMetadata } from '#/session/sessionMetadata/sessionMetadata';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { IAgentSkillService } from '#/agent/skill';
import { IAgentSwarmService } from '#/agent/swarm';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentToolRegistryService } from '#/agent/toolRegistry';
import type { ToolUpdate } from '#/agent/tool';
import { IAgentTurnService } from '#/agent/turn';
@ -61,10 +63,10 @@ import type {
} from './core-api';
import { IAgentRPCService } from './rpc';
import {
applyPromptMetadataUpdate,
promptMetadataTextFromPayload,
promptMetadataTextFromPluginCommand,
promptMetadataTextFromSkill,
titleFromPromptMetadataText,
} from './prompt-metadata';
declare module '#/app/event/eventBus' {
@ -340,37 +342,19 @@ export class AgentRPCService implements IAgentRPCService {
}
/**
* Mirror v1's `Session.updatePromptMetadata`: persist the prompt text as
* `lastPrompt` and, when the session is still untitled and has no custom
* title, derive an easy `title` from it. Then broadcast `session.meta.updated`
* on the global `IEventService` so the web session list / title updates live
* (the edge fans it out to every connection, not just this session's
* subscribers) exactly like v1's `session.rpc.emitEvent`.
* Delegate to the shared `applyPromptMetadataUpdate` helper (same one the
* `/api/v1` legacy entry uses), so the easy-title / `lastPrompt` derivation
* and the `session.meta.updated` broadcast stay identical on both surfaces.
*/
private async updatePromptMetadata(text: string | undefined): Promise<void> {
if (text === undefined) return;
const current = await this.metadata.read();
const patch: { lastPrompt: string; title?: string; isCustomTitle?: boolean } = {
lastPrompt: text,
};
if (!current.isCustomTitle && isUntitled(current.title)) {
patch.title = titleFromPromptMetadataText(text);
patch.isCustomTitle = false;
}
await this.metadata.update(patch satisfies SessionMetaPatch);
this.eventService.publish({
type: 'session.meta.updated',
payload: {
agentId: 'main',
await applyPromptMetadataUpdate(
{
metadata: this.metadata,
eventService: this.eventService,
sessionId: this.sessionContext.sessionId,
title: patch.title,
patch: {
title: patch.title,
isCustomTitle: patch.isCustomTitle,
lastPrompt: text,
},
},
});
text,
);
}
createGoal(payload: CreateGoalPayload) {
@ -434,10 +418,6 @@ export class AgentRPCService implements IAgentRPCService {
}
}
function isUntitled(title: string | undefined): boolean {
return typeof title !== 'string' || title.trim().length === 0 || title === 'New Session';
}
registerScopedService(
LifecycleScope.Agent,
IAgentRPCService,

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { SkillActivationOrigin } from '#/agent/contextMemory';
import type { Turn } from '#/agent/turn';

View file

@ -15,16 +15,16 @@ import { randomUUID } from 'node:crypto';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import type { ContextMessage, SkillActivationOrigin } from '#/agent/contextMemory';
import { renderUserSlashSkillPrompt } from './prompt';
import { ISessionContext } from '#/session/sessionContext';
import { Disposable } from '#/_base/di';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { Disposable } from '#/_base/di/lifecycle';
import { ErrorCodes, KimiError } from '#/errors';
import { isUserActivatableSkillType, type SkillDefinition } from '#/app/skillCatalog/types';
import { IAgentPromptService } from '#/agent/prompt';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import type { Turn } from '#/agent/turn';
import { IAgentWireService, type IWireService } from '#/wire';
import { IAgentSkillService, type SkillActivationInput } from './skill';

View file

@ -32,8 +32,8 @@ import type { BuiltinTool } from '#/agent/tool';
import type { ExecutableToolResult, ToolDeliveryMessage, ToolExecution } from '#/agent/tool';
import { registerTool } from '#/agent/toolRegistry';
import { isInlineSkillType } from '#/app/skillCatalog/types';
import { ISessionSkillCatalog } from '#/session/sessionSkillCatalog';
import { ISessionContext } from '#/session/sessionContext';
import { ISessionSkillCatalog } from '#/session/sessionSkillCatalog/skillCatalog';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { renderPrompt } from '#/_base/utils/render-prompt';
import { toInputJsonSchema } from '#/_base/tools/support/input-schema';
import { matchesGlobRuleSubject } from '#/_base/tools/support/rule-match';

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
export type SwarmModeTrigger = 'manual' | 'task' | 'tool';

View file

@ -12,12 +12,12 @@
* `tools/agent-swarm.ts`.
*/
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IAgentSystemReminderService } from '#/agent/systemReminder';
import { IAgentTurnService } from '#/agent/turn';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import { IAgentWireService, type IWireService } from '#/wire';
import SWARM_MODE_ENTER_REMINDER from './enter-reminder.md?raw';
import SWARM_MODE_EXIT_REMINDER from './exit-reminder.md?raw';

View file

@ -15,8 +15,7 @@ import { registerTool } from '#/agent/toolRegistry';
import { ToolAccesses } from '#/agent/tool';
import type { ExecutableToolContext, ExecutableToolResult, ToolExecution } from '#/agent/tool';
import { toInputJsonSchema } from '#/_base/tools/support/input-schema';
import { ISessionSwarmService } from '#/session/swarm';
import type { SessionSwarmTask } from '#/session/swarm';
import { ISessionSwarmService, type SessionSwarmTask } from '#/session/swarm/sessionSwarm';
import { IAgentScopeContext } from '#/agent/scopeContext';
import { IAgentSwarmService } from '#/agent/swarm/swarm';
import AGENT_SWARM_DESCRIPTION from './agent-swarm.md?raw';

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { ContextMessage, PromptOrigin } from '#/agent/contextMemory';

View file

@ -1,6 +1,4 @@
import {
Disposable,
} from "#/_base/di";
import { Disposable } from "#/_base/di/lifecycle";
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { IAgentContextMemoryService } from '#/agent/contextMemory';

View file

@ -2,7 +2,7 @@
* `task` domain error codes.
*/
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors';
import { registerErrorDomain, type ErrorDomain } from '#/_base/errors/codes';
export const TaskErrors = {
codes: {

View file

@ -8,8 +8,8 @@
* Bound at Agent scope.
*/
import { createDecorator } from '#/_base/di';
import type { ITaskHandle } from '#/app/task';
import { createDecorator } from '#/_base/di/instantiation';
import type { ITaskHandle } from '#/app/task/task';
import type { Hooks } from '#/hooks';
import type {
AgentTask,

View file

@ -15,13 +15,13 @@ import { randomBytes } from 'node:crypto';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { escapeXml, escapeXmlAttr } from '#/_base/utils/xml-escape';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import type { TaskOrigin } from '#/agent/contextMemory';
import { ITaskService, type ITaskHandle, TERMINAL_TASK_STATES } from '#/app/task';
import { ITaskService, type ITaskHandle, TERMINAL_TASK_STATES } from '#/app/task/task';
import {
TERMINAL_STATUSES,
type AgentTaskInfoBase,
@ -30,12 +30,12 @@ import {
import { renderNotificationXml } from './notificationXml';
import { IAgentContextMemoryService } from '#/agent/contextMemory';
import { IConfigService } from '#/app/config';
import { IConfigService } from '#/app/config/config';
import { IAgentPromptService } from '#/agent/prompt';
import { ISessionContext } from '#/session/sessionContext';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { IAtomicDocumentStore } from '#/persistence/interface/atomicDocumentStore';
import { IFileSystemStorageService } from '#/persistence/interface/storage';
import { ITelemetryService } from '#/app/telemetry';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentWireService, type IWireService } from '#/wire';
import {
IAgentTaskService,

View file

@ -12,7 +12,8 @@
* in `tool-access`, execution hook contexts in `toolHooks`. No scoped service.
*/
import type { ContentPart, Tool, ToolCall } from '#/app/llmProtocol';
import type { ContentPart, ToolCall } from '#/app/llmProtocol/message';
import type { Tool } from '#/app/llmProtocol/tool';
import type { ToolInputDisplay } from '@moonshot-ai/protocol';
import type { ToolAccesses } from './tool-access';

View file

@ -9,7 +9,7 @@
* `loop` / `turn`. Pure contract (types only); no scoped service.
*/
import type { ToolCall } from '#/app/llmProtocol';
import type { ToolCall } from '#/app/llmProtocol/message';
import type { ExecutableTool, ExecutableToolResult, RunnableToolExecution } from './toolContract';

View file

@ -10,7 +10,7 @@
* instance per agent.
*/
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { createDecorator, type ServiceIdentifier } from '#/_base/di/instantiation';

View file

@ -17,7 +17,7 @@ import { canonicalTelemetryArgs } from '#/_base/utils/canonical-args';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentLoopService } from '#/agent/loop';
import { IAgentToolExecutorService } from '#/agent/toolExecutor';
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import { IAgentToolDedupeService, type ToolDedupResult } from './toolDedupe';
const REMINDER_TEXT_1 =

View file

@ -1,10 +1,10 @@
import { createDecorator } from '#/_base/di';
import { createDecorator } from '#/_base/di/instantiation';
import type {
ToolResult,
ToolDidExecuteContext,
ToolWillExecuteContext,
} from '#/agent/tool';
import type { ToolCall } from '#/app/llmProtocol';
import type { ToolCall } from '#/app/llmProtocol/message';
import type { OrderedHookSlot } from '#/hooks';
export interface ToolExecutorExecuteOptions {

View file

@ -1,6 +1,6 @@
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import type { ContentPart } from '#/app/llmProtocol';
import type { ContentPart } from '#/app/llmProtocol/message';
import type {
ToolCallStartedEvent,
ToolInputDisplay,
@ -17,7 +17,7 @@ import {
import { PathSecurityError } from '#/_base/tools/policies/path-access';
import { isUserCancellation } from "#/_base/utils/abort";
import { isAbortError } from '#/agent/loop/errors';
import { IEventBus } from '#/app/event';
import { IEventBus } from '#/app/event/eventBus';
import {
ToolAccesses,
type ExecutableTool,
@ -30,9 +30,9 @@ import {
type ToolWillExecuteContext,
} from '#/agent/tool';
import { IAgentToolRegistryService } from '#/agent/toolRegistry';
import type { ToolCall } from '#/app/llmProtocol';
import { ILogService } from '#/_base/log';
import { ITelemetryService } from '#/app/telemetry';
import type { ToolCall } from '#/app/llmProtocol/message';
import { ILogService } from '#/_base/log/log';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { OrderedHookSlot } from '#/hooks';
import {
IAgentToolExecutorService,

View file

@ -8,7 +8,8 @@
* scope.
*/
import { createDecorator, type IDisposable } from '#/_base/di';
import { createDecorator } from '#/_base/di/instantiation';
import { type IDisposable } from '#/_base/di/lifecycle';
import type { ExecutableTool, ToolInfo, ToolSource } from '#/agent/tool';
import type { Hooks } from '#/hooks';

View file

@ -1,8 +1,4 @@
import {
Disposable,
toDisposable,
type IDisposable,
} from "#/_base/di";
import { Disposable, toDisposable, type IDisposable } from "#/_base/di/lifecycle";
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import type { ExecutableTool, ToolInfo, ToolSource } from '#/agent/tool';

View file

@ -1,4 +1,4 @@
import { createDecorator } from "#/_base/di";
import { createDecorator } from "#/_base/di/instantiation";
import type { Hooks } from '#/hooks';
export interface ToolStoreData { }

View file

@ -9,7 +9,7 @@
* former `!restoring` gate). Bound at Agent scope.
*/
import { Disposable } from '#/_base/di';
import { Disposable } from '#/_base/di/lifecycle';
import { InstantiationType } from '#/_base/di/extensions';
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
import { OrderedHookSlot } from '#/hooks';

Some files were not shown because too many files have changed in this diff Show more