2026-07-20 22:43:23 +08:00
import { test } from 'node:test' ;
import assert from 'node:assert/strict' ;
import { createHash } from 'node:crypto' ;
import { mkdirSync , mkdtempSync , readFileSync , writeFileSync } from 'node:fs' ;
import { tmpdir } from 'node:os' ;
import { join } from 'node:path' ;
import { createKimiProvider } from '../packages/core/src/providers/kimi.ts' ;
2026-07-21 00:58:34 +08:00
import { assembleSessionDetail } from '../packages/core/src/session-detail.ts' ;
2026-07-20 22:43:23 +08:00
function drain ( gen ) {
const values = [];
let step = gen . next ();
while ( ! step . done ) {
values . push ( step . value );
step = gen . next ();
}
return { values , ret : step . value };
}
function writeKimiFixture () {
const root = mkdtempSync ( join ( tmpdir (), 'obelisk-kimi-' ));
const sessionDir = join ( root , 'sessions' , 'workspace-1' , 'session-native-1' );
const mainDir = join ( sessionDir , 'agents' , 'main' );
const childDir = join ( sessionDir , 'agents' , 'agent-7' );
mkdirSync ( mainDir , { recursive : true });
mkdirSync ( childDir , { recursive : true });
writeFileSync ( join ( sessionDir , 'state.json' ), JSON . stringify ({
title : 'Kimi fixture' ,
createdAt : '2026-07-20T10:00:00.000Z' ,
updatedAt : '2026-07-20T10:01:00.000Z' ,
workDir : '/tmp/kimi-project' ,
agents : {
main : { type : 'main' },
'agent-7' : { type : 'sub' , parentAgentId : 'main' , labels : { profile : 'explore' } },
},
}));
const mainRecords = [
{ type : 'metadata' , protocol_version : '1.5' , created_at : 1753005600000 },
{ type : 'config.update' , time : 1753005600100 , modelAlias : 'kimi-k2' },
{ type : 'context.append_message' , time : 1753005601000 , message : { role : 'user' , content : [{ type : 'text' , text : 'inspect the project' }], toolCalls : [], origin : { kind : 'user' } } },
{ type : 'context.append_loop_event' , time : 1753005602000 , event : { type : 'step.begin' , uuid : 'step-1' , turnId : '0' } },
{ type : 'context.append_loop_event' , time : 1753005602100 , event : { type : 'content.part' , uuid : 'thinking-1' , stepUuid : 'step-1' , part : { type : 'thinking' , thinking : 'I should inspect it' } } },
{ type : 'context.append_loop_event' , time : 1753005602200 , event : { type : 'tool.call' , uuid : 'tool-event-1' , stepUuid : 'step-1' , toolCallId : 'call-1' , name : 'Read' , args : { file_path : '/tmp/kimi-project/a.ts' } } },
{ type : 'context.append_loop_event' , time : 1753005602300 , event : { type : 'tool.result' , parentUuid : 'tool-result-1' , toolCallId : 'call-1' , result : { output : 'agent_id: agent-7\nfile body' , isError : false } } },
{ type : 'context.append_loop_event' , time : 1753005602500 , event : { type : 'content.part' , uuid : 'text-1' , stepUuid : 'step-1' , part : { type : 'text' , text : 'done' } } },
{ type : 'context.append_loop_event' , time : 1753005603000 , event : { type : 'step.end' , uuid : 'step-1' , usage : { inputOther : 7 , inputCacheRead : 3 , inputCacheCreation : 2 , output : 3 } } },
{ type : 'context.apply_compaction' , time : 1753005604000 , summary : 'Earlier work summary' , compactedCount : 2 },
];
writeFileSync ( join ( mainDir , 'wire.jsonl' ), mainRecords . map (( record ) => JSON . stringify ( record )). join ( '\n' ) + '\n' );
const childRecords = [
{ type : 'metadata' , protocol_version : '1.5' , created_at : 1753005600000 },
{ type : 'context.append_message' , time : 1753005602400 , message : { role : 'user' , content : [{ type : 'text' , text : 'child prompt' }], toolCalls : [], origin : { kind : 'system_trigger' , name : 'subagent' } } },
];
writeFileSync ( join ( childDir , 'wire.jsonl' ), childRecords . map (( record ) => JSON . stringify ( record )). join ( '\n' ) + '\n' );
return { root , sessionDir };
}
test ( 'kimi provider discovers a changed session directory and returns a stable cursor' , () => {
const { root , sessionDir } = writeKimiFixture ();
const provider = createKimiProvider ({ rootDir : root });
const units = provider . discover ({ lastCursor : () => null });
assert . equal ( units . length , 1 );
assert . equal ( units [ 0 ]. key , sessionDir );
assert . equal ( units [ 0 ]. sessionId , 'kimi:session-native-1' );
assert . match ( units [ 0 ]. meta . currentCursor , /^\d+(?:\.\d+)?:\d+$/ );
const unchanged = provider . discover ({ lastCursor : () => units [ 0 ]. meta . currentCursor });
assert . deepEqual ( unchanged , []);
});
2026-07-21 00:58:34 +08:00
test ( 'kimi provider folds main and subagent wire logs into the canonical transcript language' , () => {
2026-07-20 22:43:23 +08:00
const { root } = writeKimiFixture ();
const provider = createKimiProvider ({ rootDir : root });
const unit = provider . discover ({ lastCursor : () => null })[ 0 ];
const { values , ret } = drain ( provider . parse ( unit , null ));
const byKind = ( kind ) => values . filter (( record ) => record . kind === kind );
const goldenRecords = values . map (( record ) => record . kind === 'session'
? { ... record , jsonl_path : '<fixture-wire>' }
: record );
assert . equal (
createHash ( 'sha256' ). update ( JSON . stringify ( goldenRecords )). digest ( 'hex' ),
2026-07-21 00:58:34 +08:00
'09d76616919435a46a3395194349e696e0d8f6717a24b018515e1f3867ec347a' ,
2026-07-20 22:43:23 +08:00
'complete yielded record sequence changed' ,
);
assert . deepEqual ( values [ 0 ], { kind : 'delete-session' , sessionId : 'kimi:session-native-1' });
assert . equal ( ret , unit . meta . currentCursor );
const session = byKind ( 'session' )[ 0 ];
assert . deepEqual (
(({ id , title , project , source , countMode }) => ({ id , title , project , source , countMode }))( session ),
{
id : 'kimi:session-native-1' ,
title : 'Kimi fixture' ,
project : '-tmp-kimi-project' ,
source : 'kimi' ,
countMode : 'total' ,
},
);
const messages = byKind ( 'message' );
assert . deepEqual ( messages . map (( message ) => [ message . role , message . content_type , message . text ]), [
[ 'user' , 'text' , 'inspect the project' ],
[ 'assistant' , 'thinking' , 'I should inspect it' ],
[ 'assistant' , 'tool_use' , null ],
[ 'assistant' , 'text' , 'done' ],
[ 'user' , 'text' , 'child prompt' ],
]);
assert . equal ( messages . at ( - 1 ). agent_id , 'kimi:session-native-1:agent-7' );
assert . equal ( messages . at ( - 1 ). is_sidechain , 1 );
assert . equal ( messages . find (( message ) => message . text === 'done' ). input_tokens , 12 );
assert . equal ( messages . find (( message ) => message . text === 'done' ). output_tokens , 3 );
assert . deepEqual ( byKind ( 'tool_call' ). map (( record ) => [ record . id , record . name , record . file_path ]), [
[ 'kimi:session-native-1:main:call-1' , 'Read' , '/tmp/kimi-project/a.ts' ],
]);
assert . deepEqual ( byKind ( 'tool_result' ). map (( record ) => [ record . tool_use_id , record . is_error ]), [
[ 'kimi:session-native-1:main:call-1' , 0 ],
]);
assert . deepEqual ( byKind ( 'summary' ). map (( record ) => record . content ), [ 'Earlier work summary' ]);
assert . deepEqual ( byKind ( 'subagent' ). map (( record ) => [ record . agent_id , record . parent_tool_use_id , record . agent_type ]), [
[ 'kimi:session-native-1:agent-7' , 'kimi:session-native-1:main:call-1' , 'explore' ],
]);
2026-07-21 00:58:34 +08:00
const detail = assembleSessionDetail ( values );
assert . equal ( detail . messages . some (( message ) => message . text === 'child prompt' ), false );
assert . equal ( detail . messages . flatMap (( message ) => message . tool_calls ?? [])[ 0 ]. result . content . includes ( 'file body' ), true );
2026-07-20 22:43:23 +08:00
});
test ( 'kimi provider ignores a torn final wire line until it is completed' , () => {
const { root , sessionDir } = writeKimiFixture ();
const wirePath = join ( sessionDir , 'agents' , 'main' , 'wire.jsonl' );
writeFileSync ( wirePath , readFileSync ( wirePath , 'utf8' ) + '{"type":"context.append_message"' );
const provider = createKimiProvider ({ rootDir : root });
const unit = provider . discover ({ lastCursor : () => null })[ 0 ];
const { values , ret } = drain ( provider . parse ( unit , null ));
assert . equal ( values . filter ( record => record . kind === 'message' ). length , 5 );
assert . equal ( ret , unit . meta . currentCursor );
});
2026-07-21 19:29:14 +08:00
test ( 'kimi provider normalizes think parts and drops empty thinking placeholders' , () => {
const root = mkdtempSync ( join ( tmpdir (), 'obelisk-kimi-think-' ));
const sessionDir = join ( root , 'sessions' , 'workspace-1' , 'session-think-1' );
const mainDir = join ( sessionDir , 'agents' , 'main' );
const wirePath = join ( mainDir , 'wire.jsonl' );
mkdirSync ( mainDir , { recursive : true });
writeFileSync ( join ( sessionDir , 'state.json' ), JSON . stringify ({ workDir : '/tmp/think' }));
const records = [
{ type : 'metadata' , protocol_version : '1.5' , created_at : 1 },
{ type : 'context.append_loop_event' , time : 2 , event : { type : 'step.begin' , uuid : 'step-1' } },
{ type : 'context.append_loop_event' , time : 3 , event : {
type : 'content.part' , uuid : 'think-1' , stepUuid : 'step-1' ,
part : { type : 'think' , think : 'private reasoning' },
} },
{ type : 'context.append_loop_event' , time : 4 , event : {
type : 'content.part' , uuid : 'think-empty' , stepUuid : 'step-1' ,
part : { type : 'think' , think : '' },
} },
{ type : 'context.append_loop_event' , time : 5 , event : {
type : 'content.part' , uuid : 'answer-1' , stepUuid : 'step-1' ,
part : { type : 'text' , text : 'visible answer' },
} },
];
writeFileSync ( wirePath , records . map ( record => JSON . stringify ( record )). join ( '\n' ) + '\n' );
const provider = createKimiProvider ({ rootDir : root });
const unit = provider . discover ({ lastCursor : () => null })[ 0 ];
const { values } = drain ( provider . parse ( unit , null ));
const messages = values . filter ( record => record . kind === 'message' );
assert . deepEqual ( messages . map ( record => ({
text : record . text ,
content_type : record . content_type ,
})), [
{ text : 'private reasoning' , content_type : 'thinking' },
{ text : 'visible answer' , content_type : 'text' },
]);
assert . equal ( values . find ( record => record . kind === 'session' ). message_count , 2 );
assert . equal ( provider . raw ({
source : 'kimi' ,
messageUuid : messages [ 0 ]. uuid ,
session : { jsonl_path : wirePath },
agentId : null ,
}). messageText , 'private reasoning' );
});
2026-07-20 22:43:23 +08:00
test ( 'kimi provider replays clear and undo markers with Kimi transcript semantics' , () => {
const root = mkdtempSync ( join ( tmpdir (), 'obelisk-kimi-undo-' ));
const sessionDir = join ( root , 'sessions' , 'workspace-1' , 'session-undo-1' );
const mainDir = join ( sessionDir , 'agents' , 'main' );
mkdirSync ( mainDir , { recursive : true });
writeFileSync ( join ( sessionDir , 'state.json' ), JSON . stringify ({
workDir : '/tmp/kimi-undo' ,
agents : { main : { type : 'main' } },
}));
const records = [
{ type : 'metadata' , protocol_version : '1.5' , created_at : 1753005600000 },
{ type : 'context.append_message' , time : 1 , message : { role : 'user' , content : 'before clear' , toolCalls : [], origin : { kind : 'user' } } },
{ type : 'context.append_loop_event' , time : 2 , event : { type : 'content.part' , uuid : 'before-answer' , stepUuid : 's1' , part : { type : 'text' , text : 'kept answer' } } },
{ type : 'context.clear' , time : 3 },
{ type : 'context.append_message' , time : 4 , message : { role : 'user' , content : 'undone prompt' , toolCalls : [], origin : { kind : 'user' } } },
{ type : 'context.append_message' , time : 5 , message : { role : 'user' , content : 'persistent injection' , toolCalls : [], origin : { kind : 'injection' } } },
{ type : 'context.append_message' , time : 6 , message : { role : 'user' , content : 'ephemeral system trigger' , toolCalls : [], origin : { kind : 'system_trigger' } } },
{ type : 'context.append_loop_event' , time : 7 , event : { type : 'content.part' , uuid : 'undone-answer' , stepUuid : 's2' , part : { type : 'text' , text : 'undone answer' } } },
{ type : 'context.undo' , time : 8 , count : 1 },
];
writeFileSync ( join ( mainDir , 'wire.jsonl' ), records . map ( record => JSON . stringify ( record )). join ( '\n' ) + '\n' );
const provider = createKimiProvider ({ rootDir : root });
const unit = provider . discover ({ lastCursor : () => null })[ 0 ];
const { values } = drain ( provider . parse ( unit , null ));
assert . deepEqual (
values . filter ( record => record . kind === 'message' ). map ( record => record . text ),
[ 'before clear' , 'kept answer' , 'persistent injection' ],
);
assert . equal ( values . find ( record => record . kind === 'session' ). message_count , 3 );
});
test ( 'kimi provider scopes changed-path discovery to one session and bypasses an unchanged cursor' , () => {
const root = mkdtempSync ( join ( tmpdir (), 'obelisk-kimi-changed-path-' ));
const firstDir = join ( root , 'sessions' , 'workspace-1' , 'session-1' );
const secondDir = join ( root , 'sessions' , 'workspace-1' , 'session-2' );
for ( const sessionDir of [ firstDir , secondDir ]) {
mkdirSync ( join ( sessionDir , 'agents' , 'main' ), { recursive : true });
writeFileSync ( join ( sessionDir , 'state.json' ), JSON . stringify ({ workDir : '/tmp/project' }));
writeFileSync ( join ( sessionDir , 'agents' , 'main' , 'wire.jsonl' ), '{"type":"metadata"}\n' );
}
const provider = createKimiProvider ({ rootDir : root });
const initial = provider . discover ({ lastCursor : () => null });
const cursorByKey = new Map ( initial . map ( unit => [ unit . key , unit . meta . currentCursor ]));
const units = provider . discover ({
lastCursor : key => cursorByKey . get ( key ) ?? null ,
changedPaths : [ join ( firstDir , 'state.json' )],
});
assert . deepEqual ( units . map ( unit => unit . key ), [ firstDir ]);
});
2026-07-21 00:58:34 +08:00
test ( 'kimi provider presents user-slash activations as real user prompts' , () => {
const root = mkdtempSync ( join ( tmpdir (), 'obelisk-kimi-user-slash-' ));
const sessionDir = join ( root , 'sessions' , 'workspace-1' , 'session-user-slash-1' );
const mainDir = join ( sessionDir , 'agents' , 'main' );
mkdirSync ( mainDir , { recursive : true });
writeFileSync ( join ( sessionDir , 'state.json' ), JSON . stringify ({ workDir : '/tmp/user-slash' }));
const records = [
{ type : 'metadata' , protocol_version : '1.5' , created_at : 1 },
{ type : 'context.append_message' , time : 2 , message : {
role : 'user' , content : 'User activated the skill and loaded its full instructions.' , toolCalls : [],
origin : {
kind : 'skill_activation' , trigger : 'user-slash' , skillName : 'obelisk' ,
skillArgs : ' synthesize my history ' ,
},
} },
{ type : 'context.append_message' , time : 3 , message : {
role : 'user' , content : 'Expanded plugin command implementation.' , toolCalls : [],
origin : {
kind : 'plugin_command' , trigger : 'user-slash' , pluginId : 'demo' ,
commandName : 'ship' , commandArgs : ' --fast ' ,
},
} },
{ type : 'context.append_message' , time : 4 , message : {
role : 'user' , content : 'Model-triggered skill instructions.' , toolCalls : [],
origin : { kind : 'skill_activation' , trigger : 'model-tool' , skillName : 'review' },
} },
];
writeFileSync ( join ( mainDir , 'wire.jsonl' ), records . map ( record => JSON . stringify ( record )). join ( '\n' ) + '\n' );
const provider = createKimiProvider ({ rootDir : root });
const unit = provider . discover ({ lastCursor : () => null })[ 0 ];
const { values } = drain ( provider . parse ( unit , null ));
const messages = values . filter ( record => record . kind === 'message' );
assert . deepEqual ( messages . map ( record => ({
text : record . text ,
is_meta : record . is_meta ,
})), [
{ text : '/obelisk synthesize my history' , is_meta : 0 },
{ text : '/demo:ship --fast' , is_meta : 0 },
{ text : 'Model-triggered skill instructions.' , is_meta : 1 },
]);
assert . equal ( provider . raw ({
source : 'kimi' ,
messageUuid : messages [ 0 ]. uuid ,
session : { jsonl_path : join ( mainDir , 'wire.jsonl' ) },
agentId : null ,
}). messageText , '/obelisk synthesize my history' );
});
2026-07-20 22:43:23 +08:00
test ( 'kimi provider maps protocol-1.0 embedded tool calls and results' , () => {
const root = mkdtempSync ( join ( tmpdir (), 'obelisk-kimi-legacy-tools-' ));
const sessionDir = join ( root , 'sessions' , 'workspace-1' , 'session-tools-1' );
const mainDir = join ( sessionDir , 'agents' , 'main' );
mkdirSync ( mainDir , { recursive : true });
writeFileSync ( join ( sessionDir , 'state.json' ), JSON . stringify ({ workDir : '/tmp/tools' }));
const records = [
{ type : 'metadata' , protocol_version : '1.0' , created_at : 1 },
{ type : 'context.append_message' , time : 2 , message : {
role : 'assistant' , content : [],
toolCalls : [{ type : 'function' , id : 'legacy-call' , function : { name : 'Read' , arguments : '{"file_path":"/tmp/tools/a.ts"}' } }],
} },
{ type : 'context.append_message' , time : 3 , message : {
role : 'tool' , content : [{ type : 'text' , text : 'legacy result' }], toolCalls : [], toolCallId : 'legacy-call' ,
} },
];
writeFileSync ( join ( mainDir , 'wire.jsonl' ), records . map ( record => JSON . stringify ( record )). join ( '\n' ) + '\n' );
const provider = createKimiProvider ({ rootDir : root });
const unit = provider . discover ({ lastCursor : () => null })[ 0 ];
const { values } = drain ( provider . parse ( unit , null ));
assert . deepEqual ( values . filter ( record => record . kind === 'tool_call' ). map ( record => ({
id : record . id , name : record . name , file_path : record . file_path ,
})), [{
id : 'kimi:session-tools-1:main:legacy-call' , name : 'Read' , file_path : '/tmp/tools/a.ts' ,
}]);
assert . deepEqual ( values . filter ( record => record . kind === 'tool_result' ). map ( record => ({
tool_use_id : record . tool_use_id , content : record . content ,
})), [{
tool_use_id : 'kimi:session-tools-1:main:legacy-call' , content : 'legacy result' ,
}]);
});