kfc-code-cli 0.0.1-alpha.16 → 0.0.1-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.mjs +966 -955
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -198,7 +198,7 @@ const agentTypeEnum = z.enum([
|
|
|
198
198
|
"sub",
|
|
199
199
|
"independent"
|
|
200
200
|
]);
|
|
201
|
-
const
|
|
201
|
+
const WireProducerSchema = z.object({
|
|
202
202
|
kind: z.enum(["python", "typescript"]),
|
|
203
203
|
name: z.string(),
|
|
204
204
|
version: z.string()
|
|
@@ -208,9 +208,9 @@ const WireFileMetadataSchema = z.object({
|
|
|
208
208
|
protocol_version: z.string(),
|
|
209
209
|
created_at: z.number(),
|
|
210
210
|
kimi_version: z.string().optional(),
|
|
211
|
-
producer:
|
|
211
|
+
producer: WireProducerSchema.optional()
|
|
212
212
|
});
|
|
213
|
-
const
|
|
213
|
+
const TurnBeginRecordSchema = z.object({
|
|
214
214
|
type: z.literal("turn_begin"),
|
|
215
215
|
seq: z.number(),
|
|
216
216
|
time: z.number(),
|
|
@@ -220,7 +220,7 @@ const _rawTurnBeginRecordSchema = z.object({
|
|
|
220
220
|
input_kind: z.enum(["user", "system_trigger"]),
|
|
221
221
|
trigger_source: z.string().optional()
|
|
222
222
|
});
|
|
223
|
-
const
|
|
223
|
+
const TurnEndRecordSchema = z.object({
|
|
224
224
|
type: z.literal("turn_end"),
|
|
225
225
|
seq: z.number(),
|
|
226
226
|
time: z.number(),
|
|
@@ -256,7 +256,7 @@ const _userInputPartSchema = z.discriminatedUnion("type", [
|
|
|
256
256
|
video_url: z.object({ url: z.string() })
|
|
257
257
|
})
|
|
258
258
|
]);
|
|
259
|
-
const
|
|
259
|
+
const UserMessageRecordSchema = z.object({
|
|
260
260
|
type: z.literal("user_message"),
|
|
261
261
|
seq: z.number(),
|
|
262
262
|
time: z.number(),
|
|
@@ -264,7 +264,7 @@ const _rawUserMessageRecordSchema = z.object({
|
|
|
264
264
|
content: z.union([z.string(), z.array(_userInputPartSchema).readonly()]),
|
|
265
265
|
uuid: z.string().optional()
|
|
266
266
|
});
|
|
267
|
-
const
|
|
267
|
+
const ToolResultRecordSchema = z.object({
|
|
268
268
|
type: z.literal("tool_result"),
|
|
269
269
|
seq: z.number(),
|
|
270
270
|
time: z.number(),
|
|
@@ -276,29 +276,22 @@ const _rawToolResultRecordSchema = z.object({
|
|
|
276
276
|
uuid: z.string().optional(),
|
|
277
277
|
parent_uuid: z.string().optional()
|
|
278
278
|
});
|
|
279
|
-
const
|
|
279
|
+
const CompactionRecordSchema = z.object({
|
|
280
280
|
type: z.literal("compaction"),
|
|
281
281
|
seq: z.number(),
|
|
282
282
|
time: z.number(),
|
|
283
283
|
summary: z.string(),
|
|
284
|
-
compacted_range: z.object({
|
|
285
|
-
from_turn: z.number(),
|
|
286
|
-
to_turn: z.number(),
|
|
287
|
-
message_count: z.number()
|
|
288
|
-
}),
|
|
289
284
|
pre_compact_tokens: z.number(),
|
|
290
285
|
post_compact_tokens: z.number(),
|
|
291
|
-
trigger: z.enum(["auto", "manual"]),
|
|
292
|
-
archive_file: z.string().optional(),
|
|
293
286
|
uuid: z.string().optional()
|
|
294
287
|
});
|
|
295
|
-
const
|
|
288
|
+
const SystemPromptChangedRecordSchema = z.object({
|
|
296
289
|
type: z.literal("system_prompt_changed"),
|
|
297
290
|
seq: z.number(),
|
|
298
291
|
time: z.number(),
|
|
299
292
|
new_prompt: z.string()
|
|
300
293
|
});
|
|
301
|
-
const
|
|
294
|
+
const ToolsChangedRecordSchema = z.object({
|
|
302
295
|
type: z.literal("tools_changed"),
|
|
303
296
|
seq: z.number(),
|
|
304
297
|
time: z.number(),
|
|
@@ -309,14 +302,14 @@ const _rawToolsChangedRecordSchema = z.object({
|
|
|
309
302
|
]),
|
|
310
303
|
tools: z.array(z.string())
|
|
311
304
|
});
|
|
312
|
-
const
|
|
305
|
+
const SystemReminderRecordSchema = z.object({
|
|
313
306
|
type: z.literal("system_reminder"),
|
|
314
307
|
seq: z.number(),
|
|
315
308
|
time: z.number(),
|
|
316
309
|
content: z.string(),
|
|
317
310
|
consumed_at_turn: z.number().optional()
|
|
318
311
|
});
|
|
319
|
-
const
|
|
312
|
+
const NotificationRecordSchema = z.object({
|
|
320
313
|
type: z.literal("notification"),
|
|
321
314
|
seq: z.number(),
|
|
322
315
|
time: z.number(),
|
|
@@ -354,7 +347,7 @@ const _rawNotificationRecordSchema = z.object({
|
|
|
354
347
|
envelope_id: z.string().optional()
|
|
355
348
|
})
|
|
356
349
|
});
|
|
357
|
-
const
|
|
350
|
+
const ToolDeniedRecordSchema = z.object({
|
|
358
351
|
type: z.literal("tool_denied"),
|
|
359
352
|
seq: z.number(),
|
|
360
353
|
time: z.number(),
|
|
@@ -367,7 +360,7 @@ const _rawToolDeniedRecordSchema = z.object({
|
|
|
367
360
|
reason: z.string()
|
|
368
361
|
})
|
|
369
362
|
});
|
|
370
|
-
const
|
|
363
|
+
const StepBeginRecordSchema = z.object({
|
|
371
364
|
type: z.literal("step_begin"),
|
|
372
365
|
seq: z.number(),
|
|
373
366
|
time: z.number(),
|
|
@@ -375,7 +368,7 @@ const _rawStepBeginRecordSchema = z.object({
|
|
|
375
368
|
turn_id: z.string(),
|
|
376
369
|
step: z.number()
|
|
377
370
|
});
|
|
378
|
-
const
|
|
371
|
+
const StepEndRecordSchema = z.object({
|
|
379
372
|
type: z.literal("step_end"),
|
|
380
373
|
seq: z.number(),
|
|
381
374
|
time: z.number(),
|
|
@@ -398,7 +391,7 @@ const _contentPartBodySchema = z.discriminatedUnion("kind", [z.object({
|
|
|
398
391
|
think: z.string(),
|
|
399
392
|
encrypted: z.string().optional()
|
|
400
393
|
})]);
|
|
401
|
-
const
|
|
394
|
+
const ContentPartRecordSchema = z.object({
|
|
402
395
|
type: z.literal("content_part"),
|
|
403
396
|
seq: z.number(),
|
|
404
397
|
time: z.number(),
|
|
@@ -409,7 +402,7 @@ const _rawContentPartRecordSchema = z.object({
|
|
|
409
402
|
role: z.literal("assistant"),
|
|
410
403
|
part: _contentPartBodySchema
|
|
411
404
|
});
|
|
412
|
-
const
|
|
405
|
+
const ToolCallRecordSchema = z.object({
|
|
413
406
|
type: z.literal("tool_call"),
|
|
414
407
|
seq: z.number(),
|
|
415
408
|
time: z.number(),
|
|
@@ -466,7 +459,7 @@ const skillInvocationTriggerEnum = z.enum([
|
|
|
466
459
|
"claude-proactive",
|
|
467
460
|
"nested-skill"
|
|
468
461
|
]);
|
|
469
|
-
const
|
|
462
|
+
const SkillInvokedRecordSchema = z.object({
|
|
470
463
|
type: z.literal("skill_invoked"),
|
|
471
464
|
seq: z.number(),
|
|
472
465
|
time: z.number(),
|
|
@@ -481,7 +474,7 @@ const _rawSkillInvokedRecordSchema = z.object({
|
|
|
481
474
|
query_depth: z.number().optional()
|
|
482
475
|
})
|
|
483
476
|
});
|
|
484
|
-
const
|
|
477
|
+
const SkillCompletedRecordSchema = z.object({
|
|
485
478
|
type: z.literal("skill_completed"),
|
|
486
479
|
seq: z.number(),
|
|
487
480
|
time: z.number(),
|
|
@@ -497,7 +490,7 @@ const _rawSkillCompletedRecordSchema = z.object({
|
|
|
497
490
|
query_depth: z.number().optional()
|
|
498
491
|
})
|
|
499
492
|
});
|
|
500
|
-
const
|
|
493
|
+
const ApprovalRequestRecordSchema = z.object({
|
|
501
494
|
type: z.literal("approval_request"),
|
|
502
495
|
seq: z.number(),
|
|
503
496
|
time: z.number(),
|
|
@@ -512,7 +505,7 @@ const _rawApprovalRequestRecordSchema = z.object({
|
|
|
512
505
|
source: ApprovalSourceSchema
|
|
513
506
|
})
|
|
514
507
|
});
|
|
515
|
-
const
|
|
508
|
+
const ApprovalResponseRecordSchema = z.object({
|
|
516
509
|
type: z.literal("approval_response"),
|
|
517
510
|
seq: z.number(),
|
|
518
511
|
time: z.number(),
|
|
@@ -530,7 +523,7 @@ const _rawApprovalResponseRecordSchema = z.object({
|
|
|
530
523
|
synthetic: z.boolean().optional()
|
|
531
524
|
})
|
|
532
525
|
});
|
|
533
|
-
const
|
|
526
|
+
const TeamMailRecordSchema = z.object({
|
|
534
527
|
type: z.literal("team_mail"),
|
|
535
528
|
seq: z.number(),
|
|
536
529
|
time: z.number(),
|
|
@@ -543,13 +536,13 @@ const _rawTeamMailRecordSchema = z.object({
|
|
|
543
536
|
summary: z.string().optional()
|
|
544
537
|
})
|
|
545
538
|
});
|
|
546
|
-
const
|
|
539
|
+
const TokenUsageSchema = z.object({
|
|
547
540
|
input: z.number().int().nonnegative(),
|
|
548
541
|
output: z.number().int().nonnegative(),
|
|
549
542
|
cache_read: z.number().int().nonnegative().optional(),
|
|
550
543
|
cache_write: z.number().int().nonnegative().optional()
|
|
551
544
|
});
|
|
552
|
-
const
|
|
545
|
+
const SubagentSpawnedRecordSchema = z.object({
|
|
553
546
|
type: z.literal("subagent_spawned"),
|
|
554
547
|
seq: z.number(),
|
|
555
548
|
time: z.number(),
|
|
@@ -563,7 +556,7 @@ const _rawSubagentSpawnedRecordSchema = z.object({
|
|
|
563
556
|
run_in_background: z.boolean()
|
|
564
557
|
})
|
|
565
558
|
});
|
|
566
|
-
const
|
|
559
|
+
const SubagentCompletedRecordSchema = z.object({
|
|
567
560
|
type: z.literal("subagent_completed"),
|
|
568
561
|
seq: z.number(),
|
|
569
562
|
time: z.number(),
|
|
@@ -573,10 +566,10 @@ const _rawSubagentCompletedRecordSchema = z.object({
|
|
|
573
566
|
agent_id: z.string(),
|
|
574
567
|
parent_tool_call_id: z.string(),
|
|
575
568
|
result_summary: z.string(),
|
|
576
|
-
usage:
|
|
569
|
+
usage: TokenUsageSchema.optional()
|
|
577
570
|
})
|
|
578
571
|
});
|
|
579
|
-
const
|
|
572
|
+
const SubagentFailedRecordSchema = z.object({
|
|
580
573
|
type: z.literal("subagent_failed"),
|
|
581
574
|
seq: z.number(),
|
|
582
575
|
time: z.number(),
|
|
@@ -588,14 +581,14 @@ const _rawSubagentFailedRecordSchema = z.object({
|
|
|
588
581
|
error: z.string()
|
|
589
582
|
})
|
|
590
583
|
});
|
|
591
|
-
const
|
|
584
|
+
const OwnershipChangedRecordSchema = z.object({
|
|
592
585
|
type: z.literal("ownership_changed"),
|
|
593
586
|
seq: z.number(),
|
|
594
587
|
time: z.number(),
|
|
595
588
|
old_owner: z.string().nullable(),
|
|
596
589
|
new_owner: z.string()
|
|
597
590
|
});
|
|
598
|
-
const
|
|
591
|
+
const ContextEditRecordSchema = z.object({
|
|
599
592
|
type: z.literal("context_edit"),
|
|
600
593
|
seq: z.number(),
|
|
601
594
|
time: z.number(),
|
|
@@ -617,7 +610,7 @@ const _rawContextEditRecordSchema = z.object({
|
|
|
617
610
|
]).optional(),
|
|
618
611
|
cascade: z.boolean().optional()
|
|
619
612
|
});
|
|
620
|
-
const
|
|
613
|
+
const ContextClearedRecordSchema = z.object({
|
|
621
614
|
type: z.literal("context_cleared"),
|
|
622
615
|
seq: z.number(),
|
|
623
616
|
time: z.number()
|
|
@@ -638,12 +631,12 @@ const _sessionInitializedCommonShape = {
|
|
|
638
631
|
workspace_dir: z.string().optional(),
|
|
639
632
|
thinking_level: z.string().optional()
|
|
640
633
|
};
|
|
641
|
-
const
|
|
634
|
+
const SessionInitializedMainSchema = z.object({
|
|
642
635
|
..._sessionInitializedCommonShape,
|
|
643
636
|
agent_type: z.literal("main"),
|
|
644
637
|
session_id: z.string()
|
|
645
638
|
});
|
|
646
|
-
const
|
|
639
|
+
const SessionInitializedSubSchema = z.object({
|
|
647
640
|
..._sessionInitializedCommonShape,
|
|
648
641
|
agent_type: z.literal("sub"),
|
|
649
642
|
agent_id: z.string(),
|
|
@@ -653,45 +646,44 @@ const _rawSessionInitializedSubSchema = z.object({
|
|
|
653
646
|
parent_tool_call_id: z.string(),
|
|
654
647
|
run_in_background: z.boolean()
|
|
655
648
|
});
|
|
656
|
-
const
|
|
649
|
+
const SessionInitializedIndependentSchema = z.object({
|
|
657
650
|
..._sessionInitializedCommonShape,
|
|
658
651
|
agent_type: z.literal("independent"),
|
|
659
652
|
agent_id: z.string(),
|
|
660
653
|
agent_name: z.string().optional()
|
|
661
654
|
});
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
655
|
+
const SessionInitializedRecordSchema = z.discriminatedUnion("agent_type", [
|
|
656
|
+
SessionInitializedMainSchema,
|
|
657
|
+
SessionInitializedSubSchema,
|
|
658
|
+
SessionInitializedIndependentSchema
|
|
666
659
|
]);
|
|
667
|
-
const SessionInitializedRecordSchema = _rawSessionInitializedRecordSchema;
|
|
668
660
|
const WireRecordSchema = z.discriminatedUnion("type", [
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
661
|
+
TurnBeginRecordSchema,
|
|
662
|
+
TurnEndRecordSchema,
|
|
663
|
+
UserMessageRecordSchema,
|
|
664
|
+
ToolResultRecordSchema,
|
|
665
|
+
CompactionRecordSchema,
|
|
666
|
+
SystemPromptChangedRecordSchema,
|
|
667
|
+
ToolsChangedRecordSchema,
|
|
668
|
+
SystemReminderRecordSchema,
|
|
669
|
+
NotificationRecordSchema,
|
|
670
|
+
ToolDeniedRecordSchema,
|
|
671
|
+
StepBeginRecordSchema,
|
|
672
|
+
StepEndRecordSchema,
|
|
673
|
+
ContentPartRecordSchema,
|
|
674
|
+
ToolCallRecordSchema,
|
|
675
|
+
SkillInvokedRecordSchema,
|
|
676
|
+
SkillCompletedRecordSchema,
|
|
677
|
+
ApprovalRequestRecordSchema,
|
|
678
|
+
ApprovalResponseRecordSchema,
|
|
679
|
+
TeamMailRecordSchema,
|
|
680
|
+
SubagentSpawnedRecordSchema,
|
|
681
|
+
SubagentCompletedRecordSchema,
|
|
682
|
+
SubagentFailedRecordSchema,
|
|
683
|
+
OwnershipChangedRecordSchema,
|
|
684
|
+
ContextEditRecordSchema,
|
|
685
|
+
ContextClearedRecordSchema,
|
|
686
|
+
SessionInitializedRecordSchema
|
|
695
687
|
]);
|
|
696
688
|
//#endregion
|
|
697
689
|
//#region ../../packages/kimi-core/src/storage/journal/reader.ts
|
|
@@ -759,6 +751,7 @@ async function replayWire(path, options) {
|
|
|
759
751
|
}
|
|
760
752
|
const reason = `wire.jsonl mid-file corruption at line ${physicalLineNo}: ${String(error)}`;
|
|
761
753
|
return {
|
|
754
|
+
meta,
|
|
762
755
|
records,
|
|
763
756
|
protocolVersion: meta.protocol_version,
|
|
764
757
|
health: "broken",
|
|
@@ -783,6 +776,7 @@ async function replayWire(path, options) {
|
|
|
783
776
|
}
|
|
784
777
|
const reason = `wire.jsonl schema violation at line ${physicalLineNo}: ${parsed.error.message}`;
|
|
785
778
|
return {
|
|
779
|
+
meta,
|
|
786
780
|
records,
|
|
787
781
|
protocolVersion: meta.protocol_version,
|
|
788
782
|
health: "broken",
|
|
@@ -795,6 +789,7 @@ async function replayWire(path, options) {
|
|
|
795
789
|
records.push(parsed.data);
|
|
796
790
|
}
|
|
797
791
|
return {
|
|
792
|
+
meta,
|
|
798
793
|
records,
|
|
799
794
|
protocolVersion: meta.protocol_version,
|
|
800
795
|
health: "ok",
|
|
@@ -1100,7 +1095,7 @@ var WiredJournalWriter = class {
|
|
|
1100
1095
|
if (!Number.isInteger(opts.initialSeq) || opts.initialSeq < 0) throw new RangeError(`WiredJournalWriter.initialSeq must be a non-negative integer, got ${String(opts.initialSeq)}`);
|
|
1101
1096
|
this.seq = opts.initialSeq;
|
|
1102
1097
|
}
|
|
1103
|
-
if (opts.metadataAlreadyWritten
|
|
1098
|
+
if (opts.metadataAlreadyWritten) {
|
|
1104
1099
|
this.metadataWritten = true;
|
|
1105
1100
|
this.directorySynced = true;
|
|
1106
1101
|
}
|
|
@@ -1118,44 +1113,14 @@ var WiredJournalWriter = class {
|
|
|
1118
1113
|
get sessionDir() {
|
|
1119
1114
|
return dirname(this.filePath);
|
|
1120
1115
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
rotate: async () => {
|
|
1125
|
-
await this.flush();
|
|
1126
|
-
const result = await rotateJournal(this.sessionDir, { producer: this.producer });
|
|
1127
|
-
this.resetForRotation();
|
|
1128
|
-
return result;
|
|
1129
|
-
},
|
|
1130
|
-
readSessionInitialized: async () => {
|
|
1131
|
-
const lines = (await readFile(this.filePath, "utf-8")).split("\n").filter((l) => l.length > 0);
|
|
1132
|
-
if (lines.length < 2) throw new Error(`readSessionInitialized: wire.jsonl at ${this.filePath} has fewer than 2 lines`);
|
|
1133
|
-
const parsed = JSON.parse(lines[1]);
|
|
1134
|
-
const result = SessionInitializedRecordSchema.safeParse(parsed);
|
|
1135
|
-
if (!result.success) throw new Error(`readSessionInitialized: wire.jsonl line 2 at ${this.filePath} is not a valid session_initialized record: ${result.error.message}`);
|
|
1136
|
-
return result.data;
|
|
1137
|
-
},
|
|
1138
|
-
appendBoundary: async (sessionInitialized) => {
|
|
1139
|
-
const { seq: _seq, time: _time, ...input } = sessionInitialized;
|
|
1140
|
-
await this.append(input);
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
/**
|
|
1145
|
-
* Reset writer state after a compaction rotation (Slice 3.3 / M04).
|
|
1146
|
-
*
|
|
1147
|
-
* After `rotateJournal` renames the old `wire.jsonl` → `wire.N.jsonl`
|
|
1148
|
-
* and creates a fresh `wire.jsonl` with a metadata header, the writer
|
|
1149
|
-
* must restart its monotonic seq from 0 (so the first record in the
|
|
1150
|
-
* new file gets seq=1). The metadata header is already on disk, so we
|
|
1151
|
-
* mark it as written. The new file's directory entry was durably
|
|
1152
|
-
* committed by `rotateJournal`'s `syncDir`, so `directorySynced` is
|
|
1153
|
-
* also set.
|
|
1154
|
-
*/
|
|
1155
|
-
resetForRotation() {
|
|
1116
|
+
async rotate(initializeRecord) {
|
|
1117
|
+
await this.flush();
|
|
1118
|
+
const result = await rotateJournal(this.sessionDir, { producer: this.producer });
|
|
1156
1119
|
this.seq = 0;
|
|
1157
1120
|
this.metadataWritten = true;
|
|
1158
1121
|
this.directorySynced = true;
|
|
1122
|
+
await this.append(initializeRecord);
|
|
1123
|
+
return result;
|
|
1159
1124
|
}
|
|
1160
1125
|
async append(input) {
|
|
1161
1126
|
if (this.closed) throw new Error("JournalWriter: append on closed writer");
|
|
@@ -1360,6 +1325,7 @@ var NoopJournalWriter = class {
|
|
|
1360
1325
|
//#region ../../packages/kimi-core/src/storage/state/memory-store.ts
|
|
1361
1326
|
var ContextStateMemory = class {
|
|
1362
1327
|
history = [];
|
|
1328
|
+
initializeRecord;
|
|
1363
1329
|
_systemPrompt;
|
|
1364
1330
|
_model;
|
|
1365
1331
|
_activeTools;
|
|
@@ -1372,6 +1338,7 @@ var ContextStateMemory = class {
|
|
|
1372
1338
|
this._model = opts.initialModel;
|
|
1373
1339
|
this._systemPrompt = opts.initialSystemPrompt ?? "";
|
|
1374
1340
|
this._activeTools = new Set(opts.initialActiveTools ?? []);
|
|
1341
|
+
this.initializeRecord = opts.initializeRecord;
|
|
1375
1342
|
if (opts.initialHistory !== void 0) this.history = [...opts.initialHistory];
|
|
1376
1343
|
if (opts.initialTokenCount !== void 0) this._tokenCountWithPending = opts.initialTokenCount;
|
|
1377
1344
|
if (opts.initialThinkingLevel !== void 0) this._thinkingLevel = opts.initialThinkingLevel;
|
|
@@ -1478,7 +1445,7 @@ var ContextStateMemory = class {
|
|
|
1478
1445
|
text: summary.summary
|
|
1479
1446
|
}],
|
|
1480
1447
|
toolCalls: []
|
|
1481
|
-
}];
|
|
1448
|
+
}, ...summary.preservedRecent];
|
|
1482
1449
|
this.openSteps.clear();
|
|
1483
1450
|
this._tokenCountWithPending = summary.postCompactTokens;
|
|
1484
1451
|
}
|
|
@@ -1820,15 +1787,8 @@ function buildCompactionRecord(summary) {
|
|
|
1820
1787
|
return {
|
|
1821
1788
|
type: "compaction",
|
|
1822
1789
|
summary: summary.summary,
|
|
1823
|
-
compacted_range: {
|
|
1824
|
-
from_turn: summary.compactedRange.fromTurn,
|
|
1825
|
-
to_turn: summary.compactedRange.toTurn,
|
|
1826
|
-
message_count: summary.compactedRange.messageCount
|
|
1827
|
-
},
|
|
1828
1790
|
pre_compact_tokens: summary.preCompactTokens,
|
|
1829
|
-
post_compact_tokens: summary.postCompactTokens
|
|
1830
|
-
trigger: summary.trigger,
|
|
1831
|
-
archive_file: summary.archiveFile
|
|
1791
|
+
post_compact_tokens: summary.postCompactTokens
|
|
1832
1792
|
};
|
|
1833
1793
|
}
|
|
1834
1794
|
//#endregion
|
|
@@ -1990,6 +1950,12 @@ var BaseContextState = class {
|
|
|
1990
1950
|
this.memory.setThinkingLevel(level);
|
|
1991
1951
|
}
|
|
1992
1952
|
async resetToSummary(summary) {
|
|
1953
|
+
this.assertNotBroken();
|
|
1954
|
+
await this.journalWriter.rotate?.({
|
|
1955
|
+
...this.memory.initializeRecord,
|
|
1956
|
+
system_prompt: this.systemPrompt,
|
|
1957
|
+
active_tools: [...this.activeTools]
|
|
1958
|
+
});
|
|
1993
1959
|
this.assertNotBroken();
|
|
1994
1960
|
await this.journalWriter.append(buildCompactionRecord(summary));
|
|
1995
1961
|
this.memory.resetToSummary(summary);
|
|
@@ -2131,36 +2097,8 @@ function createSessionRuntimeSlot(initial) {
|
|
|
2131
2097
|
}
|
|
2132
2098
|
};
|
|
2133
2099
|
}
|
|
2134
|
-
function withCompactionConfigFallback(bundle, fallback) {
|
|
2135
|
-
if (bundle.compactionConfig !== void 0 || fallback === void 0) return bundle;
|
|
2136
|
-
return {
|
|
2137
|
-
...bundle,
|
|
2138
|
-
compactionConfig: fallback
|
|
2139
|
-
};
|
|
2140
|
-
}
|
|
2141
2100
|
function normalizeSessionRuntimeSlot(slot, fallback) {
|
|
2142
|
-
|
|
2143
|
-
const current = runtimeSlot.current();
|
|
2144
|
-
if (current.compactionConfig === void 0 && fallback.compactionConfig !== void 0) runtimeSlot.replace({
|
|
2145
|
-
...current,
|
|
2146
|
-
compactionConfig: fallback.compactionConfig
|
|
2147
|
-
});
|
|
2148
|
-
return runtimeSlot;
|
|
2149
|
-
}
|
|
2150
|
-
const DEFAULT_RESERVED_CONTEXT_SIZE$1 = 5e4;
|
|
2151
|
-
const DEFAULT_RESERVED_CONTEXT_FRACTION$1 = .25;
|
|
2152
|
-
function defaultReservedContextSize$1(maxContextSize) {
|
|
2153
|
-
return Math.max(0, Math.min(DEFAULT_RESERVED_CONTEXT_SIZE$1, Math.floor(maxContextSize * DEFAULT_RESERVED_CONTEXT_FRACTION$1)));
|
|
2154
|
-
}
|
|
2155
|
-
/** Returns true when either trigger condition fires. */
|
|
2156
|
-
function shouldCompact(context, config) {
|
|
2157
|
-
if (config === void 0) return false;
|
|
2158
|
-
const triggerRatio = config.triggerRatio ?? .85;
|
|
2159
|
-
const reservedContextSize = config.reservedContextSize ?? defaultReservedContextSize$1(config.maxContextSize);
|
|
2160
|
-
const tokens = context.tokenCountWithPending;
|
|
2161
|
-
if (tokens >= config.maxContextSize * triggerRatio) return true;
|
|
2162
|
-
if (tokens + reservedContextSize >= config.maxContextSize) return true;
|
|
2163
|
-
return false;
|
|
2101
|
+
return slot ?? createSessionRuntimeSlot(fallback);
|
|
2164
2102
|
}
|
|
2165
2103
|
//#endregion
|
|
2166
2104
|
//#region ../../packages/kimi-core/src/soul/error-utils.ts
|
|
@@ -2222,9 +2160,9 @@ function zodToSchema(schema) {
|
|
|
2222
2160
|
return { type: "object" };
|
|
2223
2161
|
}
|
|
2224
2162
|
}
|
|
2225
|
-
function buildLLMVisibleTools(tools
|
|
2163
|
+
function buildLLMVisibleTools(tools) {
|
|
2226
2164
|
if (tools === void 0) return [];
|
|
2227
|
-
return
|
|
2165
|
+
return tools.map((t) => ({
|
|
2228
2166
|
name: t.name,
|
|
2229
2167
|
description: t.description,
|
|
2230
2168
|
input_schema: zodToSchema(t.inputSchema)
|
|
@@ -2743,12 +2681,13 @@ async function raceExecuteWithGraceTimeout(executePromise, signal, toolName) {
|
|
|
2743
2681
|
* already spent.
|
|
2744
2682
|
*/
|
|
2745
2683
|
async function executeSoulStep(deps) {
|
|
2746
|
-
const { config, context, turnId, runtime, signal,
|
|
2684
|
+
const { config, context, turnId, runtime, signal, currentStep, emit, recordUsage } = deps;
|
|
2747
2685
|
if (config.beforeStep !== void 0) {
|
|
2748
2686
|
const beforeStep = await config.beforeStep({
|
|
2749
2687
|
turnId,
|
|
2750
2688
|
stepNumber: currentStep,
|
|
2751
|
-
context
|
|
2689
|
+
context,
|
|
2690
|
+
signal
|
|
2752
2691
|
}, signal);
|
|
2753
2692
|
if (beforeStep?.block === true) throw new Error(beforeStep.reason ?? `Step ${String(currentStep)} was blocked`);
|
|
2754
2693
|
}
|
|
@@ -2757,8 +2696,6 @@ async function executeSoulStep(deps) {
|
|
|
2757
2696
|
step: currentStep
|
|
2758
2697
|
});
|
|
2759
2698
|
signal.throwIfAborted();
|
|
2760
|
-
const model = overrides?.model ?? context.model;
|
|
2761
|
-
const visibleTools = buildLLMVisibleTools(config.tools, overrides?.activeTools);
|
|
2762
2699
|
const messages = context.buildMessages();
|
|
2763
2700
|
const stepUuid = randomUUID();
|
|
2764
2701
|
const toolCallByProviderId = /* @__PURE__ */ new Map();
|
|
@@ -2786,10 +2723,9 @@ async function executeSoulStep(deps) {
|
|
|
2786
2723
|
try {
|
|
2787
2724
|
response = await runtime.kosong.chat({
|
|
2788
2725
|
messages,
|
|
2789
|
-
tools:
|
|
2790
|
-
model,
|
|
2726
|
+
tools: buildLLMVisibleTools(config.tools ?? []),
|
|
2727
|
+
model: context.model,
|
|
2791
2728
|
systemPrompt: context.systemPrompt,
|
|
2792
|
-
effort: overrides?.effort,
|
|
2793
2729
|
signal,
|
|
2794
2730
|
...createChatStreamingCallbacks({
|
|
2795
2731
|
emit,
|
|
@@ -2801,19 +2737,19 @@ async function executeSoulStep(deps) {
|
|
|
2801
2737
|
}),
|
|
2802
2738
|
onToolCallReady: (toolCall, info) => {
|
|
2803
2739
|
streamingScheduler.markReady(toolCall, info);
|
|
2804
|
-
}
|
|
2805
|
-
contextWindow: config.contextWindow
|
|
2740
|
+
}
|
|
2806
2741
|
});
|
|
2807
2742
|
} finally {
|
|
2808
2743
|
streamingScheduler.finish();
|
|
2809
2744
|
}
|
|
2810
|
-
|
|
2745
|
+
const usage = response.usage;
|
|
2746
|
+
recordUsage(usage);
|
|
2811
2747
|
const pending = await classifyToolCalls(step, response);
|
|
2812
2748
|
await context.appendStepEnd({
|
|
2813
2749
|
uuid: stepUuid,
|
|
2814
2750
|
turnId,
|
|
2815
2751
|
step: currentStep,
|
|
2816
|
-
usage: toStepEndUsage(
|
|
2752
|
+
usage: toStepEndUsage(usage),
|
|
2817
2753
|
finishReason: response.stopReason
|
|
2818
2754
|
});
|
|
2819
2755
|
await executePendingCalls(step, pending);
|
|
@@ -2828,10 +2764,15 @@ async function executeSoulStep(deps) {
|
|
|
2828
2764
|
turnId,
|
|
2829
2765
|
stepNumber: currentStep,
|
|
2830
2766
|
context,
|
|
2831
|
-
|
|
2767
|
+
usage,
|
|
2768
|
+
stopReason,
|
|
2769
|
+
signal
|
|
2832
2770
|
}, signal);
|
|
2833
2771
|
} catch {}
|
|
2834
|
-
return {
|
|
2772
|
+
return {
|
|
2773
|
+
usage,
|
|
2774
|
+
stopReason
|
|
2775
|
+
};
|
|
2835
2776
|
}
|
|
2836
2777
|
function createStreamingToolCallScheduler(step, streamingPreparations) {
|
|
2837
2778
|
let nextOrdinal = 0;
|
|
@@ -2925,7 +2866,7 @@ function toStepEndUsage(usage) {
|
|
|
2925
2866
|
//#region ../../packages/kimi-core/src/soul/run-turn.ts
|
|
2926
2867
|
const DEFAULT_MAX_STEPS = 100;
|
|
2927
2868
|
const UNKNOWN_TURN_ID = "unknown-turn";
|
|
2928
|
-
async function runSoulTurn(config, context, runtime, sink, signal
|
|
2869
|
+
async function runSoulTurn(config, context, runtime, sink, signal) {
|
|
2929
2870
|
const maxSteps = config.maxSteps ?? DEFAULT_MAX_STEPS;
|
|
2930
2871
|
const usage = {
|
|
2931
2872
|
input: 0,
|
|
@@ -2939,10 +2880,6 @@ async function runSoulTurn(config, context, runtime, sink, signal, overrides) {
|
|
|
2939
2880
|
try {
|
|
2940
2881
|
while (true) {
|
|
2941
2882
|
signal.throwIfAborted();
|
|
2942
|
-
if (shouldCompact(context, config.compactionConfig)) {
|
|
2943
|
-
stopReason = "needs_compaction";
|
|
2944
|
-
break;
|
|
2945
|
-
}
|
|
2946
2883
|
if (steps >= maxSteps) throw new MaxStepsExceededError(maxSteps);
|
|
2947
2884
|
steps += 1;
|
|
2948
2885
|
const stepResult = await executeSoulStep({
|
|
@@ -2951,7 +2888,6 @@ async function runSoulTurn(config, context, runtime, sink, signal, overrides) {
|
|
|
2951
2888
|
context,
|
|
2952
2889
|
runtime,
|
|
2953
2890
|
signal,
|
|
2954
|
-
overrides,
|
|
2955
2891
|
currentStep: steps,
|
|
2956
2892
|
emit: (event) => {
|
|
2957
2893
|
safeEmit(sink, event);
|
|
@@ -2966,7 +2902,8 @@ async function runSoulTurn(config, context, runtime, sink, signal, overrides) {
|
|
|
2966
2902
|
...stepResult,
|
|
2967
2903
|
turnId,
|
|
2968
2904
|
stepNumber: steps,
|
|
2969
|
-
context
|
|
2905
|
+
context,
|
|
2906
|
+
signal
|
|
2970
2907
|
}))?.continue) break;
|
|
2971
2908
|
}
|
|
2972
2909
|
} catch (error) {
|
|
@@ -3338,11 +3275,15 @@ var SoulRegistry = class {
|
|
|
3338
3275
|
runSubagentTurnFn;
|
|
3339
3276
|
parentSessionJournal;
|
|
3340
3277
|
eventBus;
|
|
3278
|
+
notificationManager;
|
|
3279
|
+
wakeScheduler;
|
|
3341
3280
|
constructor(deps) {
|
|
3342
3281
|
this.createHandle = deps.createHandle;
|
|
3343
3282
|
this.runSubagentTurnFn = deps.runSubagentTurn;
|
|
3344
3283
|
this.parentSessionJournal = deps.parentSessionJournal;
|
|
3345
3284
|
this.eventBus = deps.eventBus;
|
|
3285
|
+
this.notificationManager = deps.notificationManager;
|
|
3286
|
+
this.wakeScheduler = deps.wakeScheduler;
|
|
3346
3287
|
}
|
|
3347
3288
|
getOrCreate(key, agentDepth = 0) {
|
|
3348
3289
|
const existing = this.handles.get(key);
|
|
@@ -3456,6 +3397,47 @@ var SoulRegistry = class {
|
|
|
3456
3397
|
data: failedPayload
|
|
3457
3398
|
});
|
|
3458
3399
|
}
|
|
3400
|
+
if (walOk && this.notificationManager !== void 0 && request.runInBackground === true) try {
|
|
3401
|
+
if (completedPayload !== void 0) await this.notificationManager.emit({
|
|
3402
|
+
category: "agent",
|
|
3403
|
+
type: "subagent.completed",
|
|
3404
|
+
source_kind: "subagent",
|
|
3405
|
+
source_id: agentId,
|
|
3406
|
+
title: `Subagent ${agentId} completed`,
|
|
3407
|
+
body: completedPayload.result_summary,
|
|
3408
|
+
severity: "success",
|
|
3409
|
+
payload: {
|
|
3410
|
+
agent_id: agentId,
|
|
3411
|
+
parent_tool_call_id: request.parentToolCallId
|
|
3412
|
+
},
|
|
3413
|
+
targets: ["llm", "wire"],
|
|
3414
|
+
dedupe_key: `subagent_completed:${agentId}`
|
|
3415
|
+
});
|
|
3416
|
+
else if (failedPayload !== void 0) await this.notificationManager.emit({
|
|
3417
|
+
category: "agent",
|
|
3418
|
+
type: "subagent.failed",
|
|
3419
|
+
source_kind: "subagent",
|
|
3420
|
+
source_id: agentId,
|
|
3421
|
+
title: `Subagent ${agentId} failed`,
|
|
3422
|
+
body: failedPayload.error,
|
|
3423
|
+
severity: "error",
|
|
3424
|
+
payload: {
|
|
3425
|
+
agent_id: agentId,
|
|
3426
|
+
parent_tool_call_id: request.parentToolCallId
|
|
3427
|
+
},
|
|
3428
|
+
targets: ["llm", "wire"],
|
|
3429
|
+
dedupe_key: `subagent_failed:${agentId}`
|
|
3430
|
+
});
|
|
3431
|
+
this.wakeScheduler?.enqueue({
|
|
3432
|
+
kind: "system_trigger",
|
|
3433
|
+
input: {
|
|
3434
|
+
text: "",
|
|
3435
|
+
parts: []
|
|
3436
|
+
},
|
|
3437
|
+
reason: completedPayload !== void 0 ? "subagent_completed" : "subagent_failed",
|
|
3438
|
+
source: agentId
|
|
3439
|
+
});
|
|
3440
|
+
} catch {}
|
|
3459
3441
|
}
|
|
3460
3442
|
queueMicrotask(() => {
|
|
3461
3443
|
this.destroy(soulKey);
|
|
@@ -3484,8 +3466,6 @@ function mergeSoulConfig(target, source) {
|
|
|
3484
3466
|
if (source.afterToolCall) target.afterToolCall = mergeCallback(target.afterToolCall, source.afterToolCall);
|
|
3485
3467
|
if (source.beforeStep) target.beforeStep = mergeCallback(target.beforeStep, source.beforeStep);
|
|
3486
3468
|
if (source.afterStep) target.afterStep = mergeCallback(target.afterStep, source.afterStep);
|
|
3487
|
-
if (source.compactionConfig !== void 0) target.compactionConfig = source.compactionConfig;
|
|
3488
|
-
if (source.contextWindow !== void 0) target.contextWindow = source.contextWindow;
|
|
3489
3469
|
function mergeCallback(f1, f2) {
|
|
3490
3470
|
if (!f1) return f2;
|
|
3491
3471
|
if (!f2) return f1;
|
|
@@ -3737,6 +3717,19 @@ async function runSubagentTurn(deps, agentId, request, signal) {
|
|
|
3737
3717
|
}
|
|
3738
3718
|
const childSystemPrompt = typeDef.systemPromptSuffix || void 0;
|
|
3739
3719
|
const childModel = request.model ?? typeDef.defaultModel ?? parentModel;
|
|
3720
|
+
const childActiveTools = childTools.map((t) => t.name);
|
|
3721
|
+
const subInitInput = {
|
|
3722
|
+
type: "session_initialized",
|
|
3723
|
+
agent_type: "sub",
|
|
3724
|
+
agent_id: agentId,
|
|
3725
|
+
agent_name: request.agentName,
|
|
3726
|
+
parent_session_id: parentSessionId,
|
|
3727
|
+
...request.parentAgentId !== void 0 && request.parentAgentId !== "" && request.parentAgentId !== "agent_main" ? { parent_agent_id: request.parentAgentId } : {},
|
|
3728
|
+
parent_tool_call_id: request.parentToolCallId,
|
|
3729
|
+
run_in_background: request.runInBackground ?? false,
|
|
3730
|
+
system_prompt: childSystemPrompt ?? "",
|
|
3731
|
+
active_tools: childActiveTools
|
|
3732
|
+
};
|
|
3740
3733
|
let childContext;
|
|
3741
3734
|
let childJournalWriter;
|
|
3742
3735
|
if (pathConfig !== void 0 && sessionId !== void 0 || sessionDir !== "") {
|
|
@@ -3755,21 +3748,9 @@ async function runSubagentTurn(deps, agentId, request, signal) {
|
|
|
3755
3748
|
}
|
|
3756
3749
|
}
|
|
3757
3750
|
});
|
|
3758
|
-
const childActiveTools = childTools.map((t) => t.name);
|
|
3759
|
-
const subInitInput = {
|
|
3760
|
-
type: "session_initialized",
|
|
3761
|
-
agent_type: "sub",
|
|
3762
|
-
agent_id: agentId,
|
|
3763
|
-
agent_name: request.agentName,
|
|
3764
|
-
parent_session_id: parentSessionId,
|
|
3765
|
-
...request.parentAgentId !== void 0 && request.parentAgentId !== "" && request.parentAgentId !== "agent_main" ? { parent_agent_id: request.parentAgentId } : {},
|
|
3766
|
-
parent_tool_call_id: request.parentToolCallId,
|
|
3767
|
-
run_in_background: request.runInBackground ?? false,
|
|
3768
|
-
system_prompt: childSystemPrompt ?? "",
|
|
3769
|
-
active_tools: childActiveTools
|
|
3770
|
-
};
|
|
3771
3751
|
await childJournalWriter.append(subInitInput);
|
|
3772
3752
|
childContext = new WiredContextState({
|
|
3753
|
+
initializeRecord: subInitInput,
|
|
3773
3754
|
journalWriter: childJournalWriter,
|
|
3774
3755
|
initialModel: childModel,
|
|
3775
3756
|
initialSystemPrompt: childSystemPrompt,
|
|
@@ -3777,6 +3758,7 @@ async function runSubagentTurn(deps, agentId, request, signal) {
|
|
|
3777
3758
|
});
|
|
3778
3759
|
childContextRef = childContext;
|
|
3779
3760
|
} else childContext = new InMemoryContextState({
|
|
3761
|
+
initializeRecord: subInitInput,
|
|
3780
3762
|
initialModel: childModel,
|
|
3781
3763
|
initialSystemPrompt: childSystemPrompt
|
|
3782
3764
|
});
|
|
@@ -5150,6 +5132,8 @@ function createSoulRegistryForSession(deps) {
|
|
|
5150
5132
|
}),
|
|
5151
5133
|
parentSessionJournal: deps.sessionJournal,
|
|
5152
5134
|
eventBus: deps.eventBus,
|
|
5135
|
+
notificationManager: deps.notificationManager,
|
|
5136
|
+
wakeScheduler: deps.wakeScheduler,
|
|
5153
5137
|
...hasSubagentInfra ? { runSubagentTurn: (agentId, request, signal) => runSubagentTurn({
|
|
5154
5138
|
store: deps.subagentStore,
|
|
5155
5139
|
typeRegistry: deps.agentTypeRegistry,
|
|
@@ -5170,6 +5154,25 @@ function createSoulRegistryForSession(deps) {
|
|
|
5170
5154
|
hasSubagentInfra
|
|
5171
5155
|
};
|
|
5172
5156
|
}
|
|
5157
|
+
//#endregion
|
|
5158
|
+
//#region ../../packages/kimi-core/src/tools/builtin/collaboration/agent.ts
|
|
5159
|
+
/**
|
|
5160
|
+
* AgentTool —— 用于派生任务子代理的协作工具(v2 §7.2)。
|
|
5161
|
+
*
|
|
5162
|
+
* 这是一个“协作工具”(v2 §9-F.5),与内建工具
|
|
5163
|
+
* (Read/Write/Edit/Bash/Grep/Glob)不同。它使用 `SubagentHost`
|
|
5164
|
+
* (通过构造函数注入,而不是通过 Runtime)来创建同进程的
|
|
5165
|
+
* 子代理 Soul 实例。
|
|
5166
|
+
*
|
|
5167
|
+
* 两种模式:
|
|
5168
|
+
* - **Foreground**(默认):阻塞父回合,`await handle.completion`
|
|
5169
|
+
* - **Background**:立即返回 agent id,结果通过通知投递
|
|
5170
|
+
*
|
|
5171
|
+
* Slice 5.3 —— 已实现前台与后台执行路径。
|
|
5172
|
+
* 与 Python 实现对齐:`kimi_cli.tools.agent.__init__.AgentTool`
|
|
5173
|
+
* (文本形式的 `ToolResult.content`;通过 `AgentToolOutputSchema`
|
|
5174
|
+
* 提供的结构化输出仅用于 drift-guard,不在运行时消费——见 TD1)。
|
|
5175
|
+
*/
|
|
5173
5176
|
const AgentToolInputSchema = z.preprocess((input) => {
|
|
5174
5177
|
if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
|
|
5175
5178
|
const record = input;
|
|
@@ -5194,15 +5197,30 @@ z.object({
|
|
|
5194
5197
|
cache_write: z.number().int().nonnegative().optional()
|
|
5195
5198
|
}).describe("Cumulative token usage")
|
|
5196
5199
|
});
|
|
5200
|
+
const AGENT_DESCRIPTION_BASE = [
|
|
5201
|
+
"Launch a subagent to handle a task. The subagent runs as a same-process Soul instance with its own context and wire file.",
|
|
5202
|
+
"",
|
|
5203
|
+
"Writing the prompt:",
|
|
5204
|
+
"- The subagent starts with zero context — it has not seen this conversation. Brief it like a colleague who just walked into the room: state the goal, list what you already know, hand over the specifics.",
|
|
5205
|
+
"- Lookups (read this file, run that test): put the exact path or command in the prompt. The subagent should not have to search for things you already know.",
|
|
5206
|
+
"- Investigations (figure out X, find why Y): give the question, not prescribed steps — fixed steps become dead weight when the premise is wrong.",
|
|
5207
|
+
"- Do not delegate understanding. If the task hinges on a file path or line number, find it yourself first and write it into the prompt.",
|
|
5208
|
+
"",
|
|
5209
|
+
"Once a subagent is running, leave that scope to it: do not redo its searches or reads in parallel, and do not abandon it midway and finish the job manually. Both undo the context savings the delegation was meant to buy.",
|
|
5210
|
+
"",
|
|
5211
|
+
"When `runInBackground=true`, the subagent runs detached from this turn. The completion arrives in a later turn as a synthetic user-role message containing its result — you do not need to poll, sleep, or check on its progress. Continue with other work or respond to the user. Never fabricate or predict what the result will say."
|
|
5212
|
+
].join("\n");
|
|
5197
5213
|
var AgentTool = class {
|
|
5198
5214
|
name = "Agent";
|
|
5199
|
-
description
|
|
5215
|
+
description;
|
|
5200
5216
|
inputSchema = AgentToolInputSchema;
|
|
5201
5217
|
constructor(subagentHost, parentAgentId, backgroundManager, typeRegistry) {
|
|
5202
5218
|
this.subagentHost = subagentHost;
|
|
5203
5219
|
this.parentAgentId = parentAgentId;
|
|
5204
5220
|
this.backgroundManager = backgroundManager;
|
|
5205
5221
|
this.typeRegistry = typeRegistry;
|
|
5222
|
+
const typeLines = typeRegistry?.list().length ? typeRegistry.buildTypeDescriptions() : "";
|
|
5223
|
+
this.description = typeLines ? `${AGENT_DESCRIPTION_BASE}\n\nAvailable agent types (pass via subagent_type):\n${typeLines}` : AGENT_DESCRIPTION_BASE;
|
|
5206
5224
|
}
|
|
5207
5225
|
async execute({ toolCallId, args, signal, wireUuid }) {
|
|
5208
5226
|
try {
|
|
@@ -5988,202 +6006,6 @@ function registerInteractiveTools(options) {
|
|
|
5988
6006
|
if (options.isToolEnabled("AskUserQuestion")) options.toolRegistry.push(new AskUserQuestionTool(questionRuntime, () => options.turnManager.getPermissionMode()));
|
|
5989
6007
|
}
|
|
5990
6008
|
//#endregion
|
|
5991
|
-
//#region ../../packages/kimi-core/src/soul-plus/compaction/tokens.ts
|
|
5992
|
-
/**
|
|
5993
|
-
* Token-estimation helper used by `CompactionOrchestrator` to seed
|
|
5994
|
-
* `postCompactTokens` after a summary is produced.
|
|
5995
|
-
*
|
|
5996
|
-
* Lives on the SoulPlus side because Soul itself never calls it —
|
|
5997
|
-
* Soul's only interest in tokens is `shouldCompact`, which reads the
|
|
5998
|
-
* precomputed `tokenCountWithPending` off `SoulContextState`.
|
|
5999
|
-
*/
|
|
6000
|
-
/**
|
|
6001
|
-
* Estimate token count from text using a character-based heuristic.
|
|
6002
|
-
* - ASCII (~4 chars per token)
|
|
6003
|
-
* - CJK and other non-ASCII (~1 char per token)
|
|
6004
|
-
* The estimate is transient — the next LLM call returns the real count
|
|
6005
|
-
* and supersedes this value. Used to keep `tokenCountWithPending`
|
|
6006
|
-
* monotonic between LLM round-trips without paying for a tokenizer.
|
|
6007
|
-
*/
|
|
6008
|
-
function estimateTokens(text) {
|
|
6009
|
-
let asciiCount = 0;
|
|
6010
|
-
let nonAsciiCount = 0;
|
|
6011
|
-
for (const char of text) if (char.codePointAt(0) <= 127) asciiCount++;
|
|
6012
|
-
else nonAsciiCount++;
|
|
6013
|
-
return Math.ceil(asciiCount / 4) + nonAsciiCount;
|
|
6014
|
-
}
|
|
6015
|
-
//#endregion
|
|
6016
|
-
//#region ../../packages/kimi-core/src/soul-plus/compaction/compaction-orchestrator.ts
|
|
6017
|
-
var CompactionOrchestrator = class {
|
|
6018
|
-
constructor(deps) {
|
|
6019
|
-
this.deps = deps;
|
|
6020
|
-
}
|
|
6021
|
-
/**
|
|
6022
|
-
* Core compaction pipeline — assumes the lifecycle machine has already
|
|
6023
|
-
* landed in `active`. Drives `active → compacting → active`:
|
|
6024
|
-
*
|
|
6025
|
-
* 1. transitionTo('compacting')
|
|
6026
|
-
* 2. emit compaction.begin
|
|
6027
|
-
* 3. provider.run(messages, signal, {userInstructions?})
|
|
6028
|
-
* 4. journalWriter.flush() (Phase 3 铁律 — before rotate)
|
|
6029
|
-
* 5. journalWriter.rotate(...)
|
|
6030
|
-
* 6. contextState.resetToSummary(storageSummary)
|
|
6031
|
-
* 7. emit compaction.end
|
|
6032
|
-
* 8. finally: transitionTo('active')
|
|
6033
|
-
*
|
|
6034
|
-
* `signal.throwIfAborted()` is checked at two points: immediately after
|
|
6035
|
-
* begin (so a pre-aborted signal never invokes the provider) and
|
|
6036
|
-
* immediately after provider.run (so a slow provider doesn't produce a
|
|
6037
|
-
* summary that races with concurrent cancel). There is no abort check
|
|
6038
|
-
* between rotate and resetToSummary — once rotate has renamed the old
|
|
6039
|
-
* wire.jsonl, aborting would leave the fresh wire.jsonl without its
|
|
6040
|
-
* CompactionRecord.
|
|
6041
|
-
*/
|
|
6042
|
-
async executeCompaction(signal, customInstruction, trigger = "auto") {
|
|
6043
|
-
const rotateCapability = this.deps.journalWriter.rotateCapability;
|
|
6044
|
-
if (!rotateCapability) throw new Error("JournalWriter missing rotate capability");
|
|
6045
|
-
const machine = this.deps.lifecycleStateMachine;
|
|
6046
|
-
machine.transitionTo("compacting");
|
|
6047
|
-
let tailUserText;
|
|
6048
|
-
try {
|
|
6049
|
-
this.deps.sink.emit({ type: "compaction.begin" });
|
|
6050
|
-
signal.throwIfAborted();
|
|
6051
|
-
const messages = this.deps.contextState.buildMessages();
|
|
6052
|
-
const preCompactTokens = this.deps.contextState.tokenCountWithPending;
|
|
6053
|
-
const summary = await (this.deps.runtimeSlot?.current().compactionProvider ?? this.deps.compactionProvider).run(messages, signal, customInstruction !== void 0 ? { userInstructions: customInstruction } : void 0);
|
|
6054
|
-
signal.throwIfAborted();
|
|
6055
|
-
const baselineInit = await rotateCapability.readSessionInitialized();
|
|
6056
|
-
const cs = this.deps.contextState;
|
|
6057
|
-
const sessionInitialized = applyRuntimeOverlay(baselineInit, {
|
|
6058
|
-
system_prompt: cs.systemPrompt,
|
|
6059
|
-
active_tools: [...cs.activeTools]
|
|
6060
|
-
});
|
|
6061
|
-
const rotateResult = await rotateCapability.rotate();
|
|
6062
|
-
await rotateCapability.appendBoundary(sessionInitialized);
|
|
6063
|
-
tailUserText = extractUnpairedTailUserText(messages);
|
|
6064
|
-
const storageSummary = bridgeSummaryMessage(summary, messages.length, preCompactTokens, trigger, rotateResult.archivePath, this.deps.contextState.systemPrompt, tailUserText);
|
|
6065
|
-
await this.deps.contextState.resetToSummary(storageSummary);
|
|
6066
|
-
this.deps.sink.emit({
|
|
6067
|
-
type: "compaction.end",
|
|
6068
|
-
tokensBefore: preCompactTokens,
|
|
6069
|
-
tokensAfter: storageSummary.postCompactTokens
|
|
6070
|
-
});
|
|
6071
|
-
} finally {
|
|
6072
|
-
machine.transitionTo("active");
|
|
6073
|
-
}
|
|
6074
|
-
if (tailUserText !== void 0) await this.deps.contextState.appendUserMessage({ text: tailUserText });
|
|
6075
|
-
}
|
|
6076
|
-
/**
|
|
6077
|
-
* Manual `/compact` slash-command entry point. Drives the full lifecycle
|
|
6078
|
-
* dance from `idle`:
|
|
6079
|
-
*
|
|
6080
|
-
* idle → active → (executeCompaction: active → compacting → active) →
|
|
6081
|
-
* completing → idle
|
|
6082
|
-
*
|
|
6083
|
-
* Throws if the machine is not `idle` at entry — `Cannot compact while
|
|
6084
|
-
* a turn is active`. PreCompact / PostCompact hooks fire here (not in
|
|
6085
|
-
* `executeCompaction`) because the hook scope covers the *entire*
|
|
6086
|
-
* compaction request, including the idle-drain bracketing.
|
|
6087
|
-
*/
|
|
6088
|
-
async triggerCompaction(customInstruction) {
|
|
6089
|
-
if (!this.deps.lifecycleStateMachine.isIdle()) throw new Error("Cannot compact while a turn is active");
|
|
6090
|
-
if (this.deps.getPendingTurnId() !== void 0) throw new Error("Cannot compact while a prompt launch is in flight");
|
|
6091
|
-
const controller = new AbortController();
|
|
6092
|
-
this.deps.lifecycleStateMachine.transitionTo("active");
|
|
6093
|
-
const sessionId = this.deps.sessionId ?? "unknown";
|
|
6094
|
-
const agentId = this.deps.agentId ?? "agent_main";
|
|
6095
|
-
if (this.deps.hookEngine !== void 0) this.deps.hookEngine.executeHooks("PreCompact", {
|
|
6096
|
-
event: "PreCompact",
|
|
6097
|
-
sessionId,
|
|
6098
|
-
turnId: "compact",
|
|
6099
|
-
agentId
|
|
6100
|
-
}, controller.signal).catch(() => {});
|
|
6101
|
-
const tokensBefore = this.deps.contextState.tokenCountWithPending;
|
|
6102
|
-
try {
|
|
6103
|
-
await this.executeCompaction(controller.signal, customInstruction, "manual");
|
|
6104
|
-
} finally {
|
|
6105
|
-
const tokensAfter = this.deps.contextState.tokenCountWithPending;
|
|
6106
|
-
if (this.deps.hookEngine !== void 0) this.deps.hookEngine.executeHooks("PostCompact", {
|
|
6107
|
-
event: "PostCompact",
|
|
6108
|
-
sessionId,
|
|
6109
|
-
turnId: "compact",
|
|
6110
|
-
agentId,
|
|
6111
|
-
tokensBefore,
|
|
6112
|
-
tokensAfter
|
|
6113
|
-
}, controller.signal).catch(() => {});
|
|
6114
|
-
if (this.deps.lifecycleStateMachine.isActive()) this.deps.lifecycleStateMachine.transitionTo("completing");
|
|
6115
|
-
if (this.deps.lifecycleStateMachine.isCompleting()) this.deps.lifecycleStateMachine.transitionTo("idle");
|
|
6116
|
-
}
|
|
6117
|
-
}
|
|
6118
|
-
};
|
|
6119
|
-
/**
|
|
6120
|
-
* Phase 23 fix — overlay the runtime-mutable subset of a baseline
|
|
6121
|
-
* `session_initialized` with the live wire-owned ContextState baseline.
|
|
6122
|
-
*
|
|
6123
|
-
* Identity-class fields (`type`, `seq`, `time`, `agent_type`, `session_id`,
|
|
6124
|
-
* `agent_id`, parent lineage) are preserved verbatim
|
|
6125
|
-
* because they cannot legally mutate at runtime — see the discriminated-union
|
|
6126
|
-
* shape in `wire-record.ts`. The mutable wire-owned fields
|
|
6127
|
-
* (`system_prompt`, `active_tools`) are overwritten so the post-rotate
|
|
6128
|
-
* baseline reflects the compaction-time snapshot rather than the original
|
|
6129
|
-
* startup config. Runtime/session fields live in state.json.
|
|
6130
|
-
*
|
|
6131
|
-
* The generic preserves the discriminated-union narrowing so each branch
|
|
6132
|
-
* (main / sub / independent) returns its own concrete type.
|
|
6133
|
-
*/
|
|
6134
|
-
function applyRuntimeOverlay(baseline, overlay) {
|
|
6135
|
-
return {
|
|
6136
|
-
...baseline,
|
|
6137
|
-
system_prompt: overlay.system_prompt,
|
|
6138
|
-
active_tools: [...overlay.active_tools]
|
|
6139
|
-
};
|
|
6140
|
-
}
|
|
6141
|
-
/**
|
|
6142
|
-
* Translate the provider's Soul-facing `RuntimeSummaryMessage` into the
|
|
6143
|
-
* storage layer's `StorageSummaryMessage`. Ported verbatim from the old
|
|
6144
|
-
* `turn-manager.ts:bridgeSummaryMessage`.
|
|
6145
|
-
*/
|
|
6146
|
-
/**
|
|
6147
|
-
* If the input message array ends on an unpaired user message (no following
|
|
6148
|
-
* assistant response), return that user's text so the caller can re-append it
|
|
6149
|
-
* to the post-compaction conversation state (决策 #101).
|
|
6150
|
-
*
|
|
6151
|
-
* Returns `undefined` when the tail is not an unpaired user message.
|
|
6152
|
-
*/
|
|
6153
|
-
function extractUnpairedTailUserText(messages) {
|
|
6154
|
-
if (messages.length === 0) return void 0;
|
|
6155
|
-
const tail = messages.at(-1);
|
|
6156
|
-
if (tail === void 0) return void 0;
|
|
6157
|
-
if (tail.role !== "user") return void 0;
|
|
6158
|
-
const content = tail.content;
|
|
6159
|
-
if (typeof content === "string") return content;
|
|
6160
|
-
if (Array.isArray(content)) {
|
|
6161
|
-
const parts = [];
|
|
6162
|
-
for (const part of content) if (typeof part === "object" && part !== null && "type" in part) {
|
|
6163
|
-
const typed = part;
|
|
6164
|
-
if (typed.type === "text" && typeof typed.text === "string") parts.push(typed.text);
|
|
6165
|
-
}
|
|
6166
|
-
return parts.length > 0 ? parts.join("") : void 0;
|
|
6167
|
-
}
|
|
6168
|
-
}
|
|
6169
|
-
function bridgeSummaryMessage(providerSummary, messagesCount, preCompactTokens, trigger, archivePath, systemPrompt, tailUserText) {
|
|
6170
|
-
const summaryTokens = estimateTokens(providerSummary.content);
|
|
6171
|
-
const systemTokens = systemPrompt ? estimateTokens(systemPrompt) : 0;
|
|
6172
|
-
const tailTokens = tailUserText ? estimateTokens(tailUserText) : 0;
|
|
6173
|
-
return {
|
|
6174
|
-
summary: providerSummary.content,
|
|
6175
|
-
compactedRange: {
|
|
6176
|
-
fromTurn: 1,
|
|
6177
|
-
toTurn: providerSummary.original_turn_count ?? messagesCount,
|
|
6178
|
-
messageCount: messagesCount
|
|
6179
|
-
},
|
|
6180
|
-
preCompactTokens,
|
|
6181
|
-
postCompactTokens: summaryTokens + systemTokens + tailTokens,
|
|
6182
|
-
trigger,
|
|
6183
|
-
archivePath
|
|
6184
|
-
};
|
|
6185
|
-
}
|
|
6186
|
-
//#endregion
|
|
6187
6009
|
//#region ../../packages/kimi-core/src/soul-plus/assembly/turn-runtime.ts
|
|
6188
6010
|
function createTurnManagerRef() {
|
|
6189
6011
|
let current;
|
|
@@ -6200,27 +6022,6 @@ function createTurnManagerRef() {
|
|
|
6200
6022
|
}
|
|
6201
6023
|
};
|
|
6202
6024
|
}
|
|
6203
|
-
function createSoulPlusCompactionOrchestrator(deps) {
|
|
6204
|
-
return new CompactionOrchestrator({
|
|
6205
|
-
contextState: deps.contextState,
|
|
6206
|
-
compactionProvider: deps.compactionProvider,
|
|
6207
|
-
runtimeSlot: deps.runtimeSlot,
|
|
6208
|
-
lifecycleStateMachine: deps.lifecycleStateMachine,
|
|
6209
|
-
sink: deps.sink,
|
|
6210
|
-
journalWriter: deps.journalWriter,
|
|
6211
|
-
sessionId: deps.sessionId,
|
|
6212
|
-
agentId: "agent_main",
|
|
6213
|
-
runtimeStateProvider: () => {
|
|
6214
|
-
const turnManager = deps.turnManagerRef.require("CompactionOrchestrator.runtimeStateProvider");
|
|
6215
|
-
return {
|
|
6216
|
-
permissionMode: turnManager.getPermissionMode(),
|
|
6217
|
-
planMode: turnManager.getPlanMode(),
|
|
6218
|
-
thinkingLevel: turnManager.getThinkingLevel()
|
|
6219
|
-
};
|
|
6220
|
-
},
|
|
6221
|
-
getPendingTurnId: () => deps.turnManagerRef.require("CompactionOrchestrator.getPendingTurnId").getCurrentTurnId()
|
|
6222
|
-
});
|
|
6223
|
-
}
|
|
6224
6025
|
function createSoulPlusToolExecutionScopeFactory(deps) {
|
|
6225
6026
|
if (deps.providedFactory !== void 0) return deps.providedFactory;
|
|
6226
6027
|
if (deps.approvalRuntime !== void 0 && deps.hookEngine !== void 0) return new DefaultToolExecutionScopeFactory({
|
|
@@ -6987,48 +6788,6 @@ var NotificationManager = class {
|
|
|
6987
6788
|
}
|
|
6988
6789
|
};
|
|
6989
6790
|
//#endregion
|
|
6990
|
-
//#region ../../packages/kimi-core/src/soul-plus/session/session-control.ts
|
|
6991
|
-
var DefaultSessionControl = class {
|
|
6992
|
-
turnManager;
|
|
6993
|
-
contextState;
|
|
6994
|
-
setPlanModeOverride;
|
|
6995
|
-
setYoloOverride;
|
|
6996
|
-
constructor(deps) {
|
|
6997
|
-
this.turnManager = deps.turnManager;
|
|
6998
|
-
this.contextState = deps.contextState;
|
|
6999
|
-
this.setPlanModeOverride = deps.setPlanModeOverride;
|
|
7000
|
-
this.setYoloOverride = deps.setYoloOverride;
|
|
7001
|
-
}
|
|
7002
|
-
async compact(customInstruction) {
|
|
7003
|
-
await this.turnManager.triggerCompaction(customInstruction);
|
|
7004
|
-
}
|
|
7005
|
-
async clear() {
|
|
7006
|
-
if (!this.turnManager.tryReserveForMaintenance()) throw new Error(`Cannot clear while session is ${this.turnManager.getLifecycleState()} — cancel the current turn or wait for compaction to finish first.`);
|
|
7007
|
-
try {
|
|
7008
|
-
await this.contextState.clear();
|
|
7009
|
-
} finally {
|
|
7010
|
-
this.turnManager.releaseMaintenance();
|
|
7011
|
-
}
|
|
7012
|
-
}
|
|
7013
|
-
async setPlanMode(enabled) {
|
|
7014
|
-
if (this.setPlanModeOverride !== void 0) {
|
|
7015
|
-
await this.setPlanModeOverride(enabled);
|
|
7016
|
-
return;
|
|
7017
|
-
}
|
|
7018
|
-
this.turnManager.setPlanMode(enabled);
|
|
7019
|
-
}
|
|
7020
|
-
async setYolo(enabled) {
|
|
7021
|
-
if (this.setYoloOverride !== void 0) {
|
|
7022
|
-
await this.setYoloOverride(enabled);
|
|
7023
|
-
return;
|
|
7024
|
-
}
|
|
7025
|
-
const previousMode = this.turnManager.getPermissionMode();
|
|
7026
|
-
const newMode = enabled ? "bypassPermissions" : "default";
|
|
7027
|
-
if (previousMode === newMode) return;
|
|
7028
|
-
this.turnManager.setPermissionMode(newMode);
|
|
7029
|
-
}
|
|
7030
|
-
};
|
|
7031
|
-
//#endregion
|
|
7032
6791
|
//#region ../../packages/kimi-core/src/soul-plus/session/session-meta-service.ts
|
|
7033
6792
|
const DEFAULT_FLUSH_DEBOUNCE_MS = 200;
|
|
7034
6793
|
var SessionMetaService = class {
|
|
@@ -20806,6 +20565,252 @@ function checkLLMCapabilities(opts) {
|
|
|
20806
20565
|
if (inputContainsAudio && !capability.audio_in) return new LLMCapabilityMismatchError(`Model "${model}" does not accept audio input`);
|
|
20807
20566
|
}
|
|
20808
20567
|
//#endregion
|
|
20568
|
+
//#region ../../packages/kimi-core/src/soul-plus/compaction/tokens.ts
|
|
20569
|
+
/**
|
|
20570
|
+
* Estimate token count from text using a character-based heuristic.
|
|
20571
|
+
* - ASCII (~4 chars per token)
|
|
20572
|
+
* - CJK and other non-ASCII (~1 char per token)
|
|
20573
|
+
* The estimate is transient — the next LLM call returns the real count
|
|
20574
|
+
* and supersedes this value. Used to keep `tokenCountWithPending`
|
|
20575
|
+
* monotonic between LLM round-trips without paying for a tokenizer.
|
|
20576
|
+
*/
|
|
20577
|
+
function estimateTokens(text) {
|
|
20578
|
+
let asciiCount = 0;
|
|
20579
|
+
let nonAsciiCount = 0;
|
|
20580
|
+
for (const char of text) if (char.codePointAt(0) <= 127) asciiCount++;
|
|
20581
|
+
else nonAsciiCount++;
|
|
20582
|
+
return Math.ceil(asciiCount / 4) + nonAsciiCount;
|
|
20583
|
+
}
|
|
20584
|
+
function estimateTokensForMessages(messages) {
|
|
20585
|
+
let total = 0;
|
|
20586
|
+
for (const message of messages) total += estimateTokensForMessage(message);
|
|
20587
|
+
return total;
|
|
20588
|
+
}
|
|
20589
|
+
function estimateTokensForMessage(message) {
|
|
20590
|
+
let total = estimateTokens(message.role);
|
|
20591
|
+
for (const part of message.content) total += estimateTokensForContentPart(part);
|
|
20592
|
+
if (message.toolCalls !== void 0) for (const call of message.toolCalls) {
|
|
20593
|
+
total += estimateTokens(call.function.name);
|
|
20594
|
+
total += estimateTokens(JSON.stringify(call.function.arguments));
|
|
20595
|
+
}
|
|
20596
|
+
return total;
|
|
20597
|
+
}
|
|
20598
|
+
function estimateTokensForContentPart(part) {
|
|
20599
|
+
if (part.type === "text") return estimateTokens(part.text);
|
|
20600
|
+
else if (part.type === "think") return estimateTokens(part.think);
|
|
20601
|
+
else return 0;
|
|
20602
|
+
}
|
|
20603
|
+
//#endregion
|
|
20604
|
+
//#region ../../packages/kimi-core/src/soul-plus/compaction/full.ts
|
|
20605
|
+
var DefaultCompactionStrategy = class {
|
|
20606
|
+
triggerRatio = .8;
|
|
20607
|
+
blockRatio = .9;
|
|
20608
|
+
maxCompactionPerTurn = 3;
|
|
20609
|
+
maxRecentSteps = 3;
|
|
20610
|
+
maxRecentUserMessages = Infinity;
|
|
20611
|
+
maxRecentSizeRatio = .2;
|
|
20612
|
+
constructor(maxContextSize) {
|
|
20613
|
+
this.maxContextSize = maxContextSize;
|
|
20614
|
+
}
|
|
20615
|
+
shouldCompact(usedSize) {
|
|
20616
|
+
return usedSize >= this.maxContextSize * this.triggerRatio;
|
|
20617
|
+
}
|
|
20618
|
+
shouldBlock(usedSize) {
|
|
20619
|
+
return usedSize >= this.maxContextSize * this.blockRatio;
|
|
20620
|
+
}
|
|
20621
|
+
splitCompactAndRecent(messages) {
|
|
20622
|
+
let splitAt = messages.length;
|
|
20623
|
+
let recentSize = 0;
|
|
20624
|
+
let userMessageCount = 0;
|
|
20625
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
20626
|
+
if (messages.length - i >= this.maxRecentSteps) break;
|
|
20627
|
+
const m1 = messages[i - 1];
|
|
20628
|
+
const m2 = messages[i];
|
|
20629
|
+
if (m2.role === "user") {
|
|
20630
|
+
userMessageCount++;
|
|
20631
|
+
if (userMessageCount > this.maxRecentUserMessages) break;
|
|
20632
|
+
}
|
|
20633
|
+
recentSize += estimateTokensForMessage(m2);
|
|
20634
|
+
if (recentSize > this.maxContextSize * this.maxRecentSizeRatio) break;
|
|
20635
|
+
if (m1?.role === m2.role) continue;
|
|
20636
|
+
if (m1?.role === "user" && m2.role === "assistant") continue;
|
|
20637
|
+
if (m2.role === "tool") continue;
|
|
20638
|
+
splitAt = i;
|
|
20639
|
+
}
|
|
20640
|
+
return [messages.slice(0, splitAt), messages.slice(splitAt)];
|
|
20641
|
+
}
|
|
20642
|
+
};
|
|
20643
|
+
var FullCompactionProvider = class {
|
|
20644
|
+
deps;
|
|
20645
|
+
compactionCountInTurn = 0;
|
|
20646
|
+
compacting = null;
|
|
20647
|
+
lastSoulConfig = null;
|
|
20648
|
+
constructor(deps) {
|
|
20649
|
+
this.deps = deps;
|
|
20650
|
+
}
|
|
20651
|
+
shouldCompact() {
|
|
20652
|
+
return this.deps.strategy.shouldCompact(this.deps.context.tokenCountWithPending);
|
|
20653
|
+
}
|
|
20654
|
+
shouldBlock() {
|
|
20655
|
+
return this.deps.strategy.shouldBlock?.(this.deps.context.tokenCountWithPending) ?? true;
|
|
20656
|
+
}
|
|
20657
|
+
beforeTurn() {
|
|
20658
|
+
this.compactionCountInTurn = 0;
|
|
20659
|
+
}
|
|
20660
|
+
async handleOverflowError(signal) {
|
|
20661
|
+
this.checkAutoCompaction();
|
|
20662
|
+
await this.block(signal);
|
|
20663
|
+
}
|
|
20664
|
+
async beforeStep(signal) {
|
|
20665
|
+
this.checkAutoCompaction();
|
|
20666
|
+
if (this.shouldBlock()) await this.block(signal);
|
|
20667
|
+
}
|
|
20668
|
+
async afterStep() {
|
|
20669
|
+
this.checkAutoCompaction();
|
|
20670
|
+
}
|
|
20671
|
+
triggerCompaction(customInstruction) {
|
|
20672
|
+
this.compactionCountInTurn = 0;
|
|
20673
|
+
if (!this.compacting) this.startCompaction(customInstruction);
|
|
20674
|
+
}
|
|
20675
|
+
checkAutoCompaction() {
|
|
20676
|
+
if (this.compacting || !this.shouldCompact()) return;
|
|
20677
|
+
const maxCompactions = this.deps.strategy.maxCompactionPerTurn;
|
|
20678
|
+
this.compactionCountInTurn += 1;
|
|
20679
|
+
if (this.compactionCountInTurn > maxCompactions) {
|
|
20680
|
+
this.deps.sink.emit({
|
|
20681
|
+
type: "session.error",
|
|
20682
|
+
error: `Compaction limit exceeded (${maxCompactions})`,
|
|
20683
|
+
error_type: "context_overflow"
|
|
20684
|
+
});
|
|
20685
|
+
throw new Error(`Compaction limit exceeded (${maxCompactions})`);
|
|
20686
|
+
}
|
|
20687
|
+
this.triggerCompaction();
|
|
20688
|
+
}
|
|
20689
|
+
async block(signal) {
|
|
20690
|
+
if (this.compacting) {
|
|
20691
|
+
signal.addEventListener("abort", () => {
|
|
20692
|
+
this.compacting?.abortController.abort();
|
|
20693
|
+
});
|
|
20694
|
+
this.deps.sink.emit({ type: "compaction.blocked" });
|
|
20695
|
+
await this.compacting.promise;
|
|
20696
|
+
}
|
|
20697
|
+
}
|
|
20698
|
+
startCompaction(customInstruction) {
|
|
20699
|
+
const abortController = new AbortController();
|
|
20700
|
+
this.compacting = {
|
|
20701
|
+
abortController,
|
|
20702
|
+
promise: this.compactionWorker(abortController.signal, customInstruction).finally(() => this.compacting = null)
|
|
20703
|
+
};
|
|
20704
|
+
}
|
|
20705
|
+
async compactionWorker(signal, customInstruction) {
|
|
20706
|
+
this.deps.sink.emit({ type: "compaction.begin" });
|
|
20707
|
+
const history = this.deps.context.getHistory();
|
|
20708
|
+
const messages = this.deps.context.buildMessages();
|
|
20709
|
+
const preCompactTokens = this.deps.context.tokenCountWithPending;
|
|
20710
|
+
const [toCompact, recent] = this.deps.strategy.splitCompactAndRecent(messages);
|
|
20711
|
+
const result = await this.deps.runtime.kosong.chat({
|
|
20712
|
+
messages: [...toCompact, {
|
|
20713
|
+
role: "user",
|
|
20714
|
+
content: [{
|
|
20715
|
+
type: "text",
|
|
20716
|
+
text: COMPACTION_INSTRUCTION(customInstruction)
|
|
20717
|
+
}],
|
|
20718
|
+
toolCalls: []
|
|
20719
|
+
}],
|
|
20720
|
+
tools: buildLLMVisibleTools(this.lastSoulConfig?.tools),
|
|
20721
|
+
model: this.deps.context.model,
|
|
20722
|
+
systemPrompt: this.deps.context.systemPrompt,
|
|
20723
|
+
signal
|
|
20724
|
+
});
|
|
20725
|
+
const summary = typeof result.message.content === "string" ? result.message.content : result.message.content.map((part) => part.type === "text" ? part.text : "").join("");
|
|
20726
|
+
const newHistory = this.deps.context.getHistory();
|
|
20727
|
+
for (let i = 0; i < history.length; i++) if (newHistory[i] !== history[i]) {
|
|
20728
|
+
this.deps.sink.emit({ type: "compaction.canceled" });
|
|
20729
|
+
return;
|
|
20730
|
+
}
|
|
20731
|
+
const postCompactTokens = estimateTokens(summary) + estimateTokensForMessages(recent);
|
|
20732
|
+
await this.deps.context.resetToSummary({
|
|
20733
|
+
summary,
|
|
20734
|
+
preCompactTokens,
|
|
20735
|
+
postCompactTokens,
|
|
20736
|
+
preservedRecent: recent
|
|
20737
|
+
});
|
|
20738
|
+
this.deps.sink.emit({
|
|
20739
|
+
type: "compaction.end",
|
|
20740
|
+
tokensBefore: preCompactTokens,
|
|
20741
|
+
tokensAfter: postCompactTokens
|
|
20742
|
+
});
|
|
20743
|
+
}
|
|
20744
|
+
};
|
|
20745
|
+
const COMPACTION_INSTRUCTION = (customInstruction = "") => `
|
|
20746
|
+
--- This message is a direct task, not part of the above conversation ---
|
|
20747
|
+
|
|
20748
|
+
You are now given a task to compact this conversation context according to specific priorities and output requirements.
|
|
20749
|
+
|
|
20750
|
+
Output text only. DO NOT CALL ANY TOOLS. Calling tools will be rejected and fails the task. You already have all the information you need in the conversation history. You have only one chance.
|
|
20751
|
+
|
|
20752
|
+
The goal of compaction is to keep essential code patterns, technical details, and architectural decisions for continuing development without losing context after the above messages are cleared work.
|
|
20753
|
+
|
|
20754
|
+
${customInstruction}
|
|
20755
|
+
|
|
20756
|
+
<!-- Compression Priorities (in order) -->
|
|
20757
|
+
|
|
20758
|
+
1. **Current Task State**: What is being worked on RIGHT NOW
|
|
20759
|
+
2. **Errors & Solutions**: All encountered errors and their resolutions
|
|
20760
|
+
3. **Code Evolution**: Final working versions only (remove intermediate attempts)
|
|
20761
|
+
4. **System Context**: Project structure, dependencies, environment setup
|
|
20762
|
+
5. **Design Decisions**: Architectural choices and their rationale
|
|
20763
|
+
6. **TODO Items**: Unfinished tasks and known issues
|
|
20764
|
+
|
|
20765
|
+
<!-- Required Output Structure -->
|
|
20766
|
+
|
|
20767
|
+
## Current Focus
|
|
20768
|
+
|
|
20769
|
+
[What we're working on now]
|
|
20770
|
+
|
|
20771
|
+
## Environment
|
|
20772
|
+
|
|
20773
|
+
- [Key setup/config points]
|
|
20774
|
+
- ...
|
|
20775
|
+
|
|
20776
|
+
## Completed Tasks
|
|
20777
|
+
|
|
20778
|
+
- [Task]: [Brief outcome]
|
|
20779
|
+
- ...
|
|
20780
|
+
|
|
20781
|
+
## Active Issues
|
|
20782
|
+
|
|
20783
|
+
- [Issue]: [Status/Next steps]
|
|
20784
|
+
- ...
|
|
20785
|
+
|
|
20786
|
+
## Code State
|
|
20787
|
+
|
|
20788
|
+
### [Critical file name]
|
|
20789
|
+
|
|
20790
|
+
[Brief description of the file's purpose and current state]
|
|
20791
|
+
|
|
20792
|
+
\`\`\`
|
|
20793
|
+
[The latest version of critical code snippets in this file, <20 lines]
|
|
20794
|
+
\`\`\`
|
|
20795
|
+
|
|
20796
|
+
### [Critical file name]
|
|
20797
|
+
|
|
20798
|
+
- [Useful classes/methods/functions]: [Brief description/usage]
|
|
20799
|
+
- ...
|
|
20800
|
+
|
|
20801
|
+
<!-- Omit non-critical code, intermediate attempts, and resolved errors -->
|
|
20802
|
+
|
|
20803
|
+
## Important Context
|
|
20804
|
+
|
|
20805
|
+
- [Any crucial information not covered above]
|
|
20806
|
+
- ...
|
|
20807
|
+
|
|
20808
|
+
## All User Messages
|
|
20809
|
+
|
|
20810
|
+
- [Detailed non tool use user message]
|
|
20811
|
+
- ...
|
|
20812
|
+
`;
|
|
20813
|
+
//#endregion
|
|
20809
20814
|
//#region ../../packages/kimi-core/src/soul-plus/turn/turn-manager.ts
|
|
20810
20815
|
/**
|
|
20811
20816
|
* TurnManager — Phase 4 coordinator (v2 §6.4 / 决策 #109).
|
|
@@ -20842,37 +20847,12 @@ function checkLLMCapabilities(opts) {
|
|
|
20842
20847
|
* 3. await lifecycle.cancelTurn(turnId) — drain
|
|
20843
20848
|
*/
|
|
20844
20849
|
/**
|
|
20845
|
-
* Phase 2 (todo Step 7): hard cap on how many compaction round-trips a
|
|
20846
|
-
* single turn is allowed. After the cap is exceeded the turn is
|
|
20847
|
-
* terminated with a `session.error` / `stopReason='error'` so a
|
|
20848
|
-
* misbehaving provider cannot lock the session in an infinite
|
|
20849
|
-
* compaction loop.
|
|
20850
|
-
*/
|
|
20851
|
-
const MAX_COMPACTIONS_PER_TURN = 3;
|
|
20852
|
-
/**
|
|
20853
20850
|
* Default context window used for `status.update.context_usage.total`
|
|
20854
20851
|
* when the session has no `compactionConfig.maxContextSize`. Matches
|
|
20855
20852
|
* the fallback used by existing config schema (200k-token window of
|
|
20856
20853
|
* typical GPT-4/Claude models).
|
|
20857
20854
|
*/
|
|
20858
20855
|
const DEFAULT_CONTEXT_WINDOW = 2e5;
|
|
20859
|
-
function zeroUsage() {
|
|
20860
|
-
return {
|
|
20861
|
-
input: 0,
|
|
20862
|
-
output: 0
|
|
20863
|
-
};
|
|
20864
|
-
}
|
|
20865
|
-
function configuredCapabilitiesToModelCapability(capabilities, maxContextTokens) {
|
|
20866
|
-
const caps = new Set(capabilities.map((cap) => cap.toLowerCase()));
|
|
20867
|
-
return {
|
|
20868
|
-
image_in: caps.has("image_in"),
|
|
20869
|
-
video_in: caps.has("video_in"),
|
|
20870
|
-
audio_in: caps.has("audio_in"),
|
|
20871
|
-
thinking: caps.has("thinking") || caps.has("always_thinking"),
|
|
20872
|
-
tool_use: caps.has("tool_use"),
|
|
20873
|
-
max_context_tokens: maxContextTokens
|
|
20874
|
-
};
|
|
20875
|
-
}
|
|
20876
20856
|
function mergeTurnRules(sessionRules, pendingOverrides) {
|
|
20877
20857
|
if (pendingOverrides === void 0) return sessionRules;
|
|
20878
20858
|
const turnRules = [];
|
|
@@ -20902,9 +20882,9 @@ var TurnManager = class {
|
|
|
20902
20882
|
thinkingLevel;
|
|
20903
20883
|
runtime;
|
|
20904
20884
|
runtimeSlot;
|
|
20905
|
-
compactionConfig;
|
|
20906
20885
|
sessionId;
|
|
20907
20886
|
executionHooks;
|
|
20887
|
+
fullCompactionProvider;
|
|
20908
20888
|
activeToolExecutionScope;
|
|
20909
20889
|
pendingLaunchController;
|
|
20910
20890
|
pendingLaunchDrain;
|
|
@@ -20933,9 +20913,17 @@ var TurnManager = class {
|
|
|
20933
20913
|
this.planMode = deps.planMode ?? false;
|
|
20934
20914
|
this.runtime = deps.runtime;
|
|
20935
20915
|
this.runtimeSlot = deps.runtimeSlot;
|
|
20936
|
-
this.compactionConfig = deps.compactionConfig;
|
|
20937
20916
|
this.sessionId = deps.sessionId ?? "unknown";
|
|
20938
20917
|
this.executionHooks = new ExecutionHookPipeline({ hookEngine: deps.hookEngine });
|
|
20918
|
+
this.fullCompactionProvider = deps.compactionConfig ? new FullCompactionProvider({
|
|
20919
|
+
strategy: new DefaultCompactionStrategy(1e6),
|
|
20920
|
+
runtime: deps.runtime,
|
|
20921
|
+
context: deps.contextState,
|
|
20922
|
+
sink: deps.sink
|
|
20923
|
+
}) : void 0;
|
|
20924
|
+
if (deps.wakeScheduler !== void 0) deps.wakeScheduler.setOnEnqueue(() => {
|
|
20925
|
+
this.processWakeQueue();
|
|
20926
|
+
});
|
|
20939
20927
|
}
|
|
20940
20928
|
setPermissionMode(mode) {
|
|
20941
20929
|
this.permissionMode = mode;
|
|
@@ -20959,16 +20947,6 @@ var TurnManager = class {
|
|
|
20959
20947
|
getThinkingLevel() {
|
|
20960
20948
|
return this.thinkingLevel;
|
|
20961
20949
|
}
|
|
20962
|
-
setCompactionConfig(config) {
|
|
20963
|
-
if (this.runtimeSlot !== void 0) {
|
|
20964
|
-
const current = this.runtimeSlot.current();
|
|
20965
|
-
this.runtimeSlot.replace({
|
|
20966
|
-
...current,
|
|
20967
|
-
...config !== void 0 ? { compactionConfig: config } : { compactionConfig: void 0 }
|
|
20968
|
-
});
|
|
20969
|
-
}
|
|
20970
|
-
this.compactionConfig = config;
|
|
20971
|
-
}
|
|
20972
20950
|
setRuntime(runtime) {
|
|
20973
20951
|
if (this.runtimeSlot !== void 0) {
|
|
20974
20952
|
const current = this.runtimeSlot.current();
|
|
@@ -21076,7 +21054,7 @@ var TurnManager = class {
|
|
|
21076
21054
|
* facade.
|
|
21077
21055
|
*/
|
|
21078
21056
|
async triggerCompaction(customInstruction) {
|
|
21079
|
-
return this.
|
|
21057
|
+
return this.fullCompactionProvider?.triggerCompaction(customInstruction);
|
|
21080
21058
|
}
|
|
21081
21059
|
/**
|
|
21082
21060
|
* Cancel an in-flight turn per v2 §7.2 three-step contract (决策 #102):
|
|
@@ -21133,12 +21111,8 @@ var TurnManager = class {
|
|
|
21133
21111
|
async handlePrompt(req) {
|
|
21134
21112
|
if (!this.deps.lifecycleStateMachine.isIdle() || this.getCurrentTurnId() !== void 0) return { error: "agent_busy" };
|
|
21135
21113
|
const input = req.data.input;
|
|
21136
|
-
const
|
|
21137
|
-
|
|
21138
|
-
const configuredCapabilities = runtimeBundle !== void 0 ? runtimeBundle.modelCapabilities : this.deps.modelCapabilities;
|
|
21139
|
-
const capability = configuredCapabilities !== void 0 ? configuredCapabilitiesToModelCapability(configuredCapabilities, runtimeBundle?.compactionConfig?.maxContextSize ?? this.compactionConfig?.maxContextSize ?? 0) : runtime.kosong.getCapability?.();
|
|
21140
|
-
const capabilityIsAuthoritative = configuredCapabilities !== void 0 || capability !== void 0 && !isUnknownCapability(capability);
|
|
21141
|
-
if (capability !== void 0 && capabilityIsAuthoritative) {
|
|
21114
|
+
const capability = ((this.runtimeSlot?.current())?.runtime ?? this.runtime).kosong.getCapability?.();
|
|
21115
|
+
if (capability !== void 0 && !isUnknownCapability(capability)) {
|
|
21142
21116
|
let inputContainsImage = false;
|
|
21143
21117
|
let inputContainsVideo = false;
|
|
21144
21118
|
for (const part of input.parts ?? []) if (part.type === "image_url") inputContainsImage = true;
|
|
@@ -21204,6 +21178,96 @@ var TurnManager = class {
|
|
|
21204
21178
|
throw error;
|
|
21205
21179
|
}
|
|
21206
21180
|
}
|
|
21181
|
+
/**
|
|
21182
|
+
* Auto-wake entry — start a turn from a `TurnTrigger` produced by
|
|
21183
|
+
* something other than user input (currently: subagent completion fan
|
|
21184
|
+
* out via SoulRegistry → NotificationManager → WakeQueueScheduler).
|
|
21185
|
+
*
|
|
21186
|
+
* Mirrors `handlePrompt` for the lifecycle / launch machinery but with
|
|
21187
|
+
* three deliberate differences:
|
|
21188
|
+
*
|
|
21189
|
+
* - `input_kind: 'system_trigger'` on the `turn_begin` WAL record so
|
|
21190
|
+
* wire consumers can distinguish auto-wake from user-driven turns.
|
|
21191
|
+
* - Skips `appendUserMessage` — the wake's payload (e.g. the
|
|
21192
|
+
* `<notification>` XML for a completed subagent) is already in
|
|
21193
|
+
* `contextState` because NotificationManager.appendNotification
|
|
21194
|
+
* ran *before* the wake was enqueued. Appending the trigger's
|
|
21195
|
+
* (typically empty) UserInput would drop a stray user message
|
|
21196
|
+
* ahead of those notifications and confuse the model.
|
|
21197
|
+
* - Skips capability checks and the `UserPromptSubmit` hook — those
|
|
21198
|
+
* are user-input concerns, not auto-wake concerns.
|
|
21199
|
+
*/
|
|
21200
|
+
async handleSystemTrigger(req) {
|
|
21201
|
+
if (!this.deps.lifecycleStateMachine.isIdle() || this.getCurrentTurnId() !== void 0) return { error: "agent_busy" };
|
|
21202
|
+
const trigger = req.trigger;
|
|
21203
|
+
const input = trigger.input;
|
|
21204
|
+
const inputKind = trigger.kind === "user_prompt" ? "user" : "system_trigger";
|
|
21205
|
+
const turnId = this.deps.lifecycle.allocateTurnId();
|
|
21206
|
+
const pendingLaunchController = new AbortController();
|
|
21207
|
+
this.pendingLaunchTurnId = turnId;
|
|
21208
|
+
this.pendingLaunchController = pendingLaunchController;
|
|
21209
|
+
let releasePendingLaunch;
|
|
21210
|
+
this.pendingLaunchDrain = new Promise((resolve) => {
|
|
21211
|
+
releasePendingLaunch = resolve;
|
|
21212
|
+
});
|
|
21213
|
+
try {
|
|
21214
|
+
await this.executePreTurnHook(turnId, input, pendingLaunchController.signal);
|
|
21215
|
+
pendingLaunchController.signal.throwIfAborted();
|
|
21216
|
+
await this.deps.sessionJournal.appendTurnBegin({
|
|
21217
|
+
type: "turn_begin",
|
|
21218
|
+
turn_id: turnId,
|
|
21219
|
+
agent_type: this.agentType,
|
|
21220
|
+
user_input: input.text,
|
|
21221
|
+
input_kind: inputKind
|
|
21222
|
+
});
|
|
21223
|
+
this.deps.lifecycleStateMachine.transitionTo("active");
|
|
21224
|
+
this.deps.lifecycle.fireLifecycleEvent({
|
|
21225
|
+
kind: "begin",
|
|
21226
|
+
turnId,
|
|
21227
|
+
userInput: input.text,
|
|
21228
|
+
userInputParts: input.parts,
|
|
21229
|
+
inputKind,
|
|
21230
|
+
agentType: this.agentType
|
|
21231
|
+
});
|
|
21232
|
+
this.launchTurn(turnId);
|
|
21233
|
+
this.pendingLaunchTurnId = void 0;
|
|
21234
|
+
this.pendingLaunchController = void 0;
|
|
21235
|
+
this.pendingLaunchDrain = void 0;
|
|
21236
|
+
releasePendingLaunch();
|
|
21237
|
+
return {
|
|
21238
|
+
turn_id: turnId,
|
|
21239
|
+
status: "started"
|
|
21240
|
+
};
|
|
21241
|
+
} catch (error) {
|
|
21242
|
+
this.pendingLaunchTurnId = void 0;
|
|
21243
|
+
this.pendingLaunchController = void 0;
|
|
21244
|
+
this.pendingLaunchDrain = void 0;
|
|
21245
|
+
releasePendingLaunch();
|
|
21246
|
+
throw error;
|
|
21247
|
+
}
|
|
21248
|
+
}
|
|
21249
|
+
/**
|
|
21250
|
+
* Drain the WakeQueueScheduler and start a turn if the lifecycle is
|
|
21251
|
+
* idle. Called synchronously from WakeQueueScheduler's onEnqueue
|
|
21252
|
+
* listener — see constructor wiring. Multiple queued triggers collapse
|
|
21253
|
+
* into a single turn: the *contextState* already carries every queued
|
|
21254
|
+
* notification's payload, so one turn-start is enough to surface them
|
|
21255
|
+
* all at once.
|
|
21256
|
+
*
|
|
21257
|
+
* Race tolerance: when called while a turn is already running we leave
|
|
21258
|
+
* the queue alone and accept a small drop window (a wake that arrives
|
|
21259
|
+
* mid-turn won't auto-fire after that turn ends). The notifications
|
|
21260
|
+
* themselves are durable in contextState, so any subsequent turn —
|
|
21261
|
+
* including a user-driven one — still sees them via `buildMessages`.
|
|
21262
|
+
*/
|
|
21263
|
+
processWakeQueue() {
|
|
21264
|
+
const scheduler = this.deps.wakeScheduler;
|
|
21265
|
+
if (scheduler === void 0) return;
|
|
21266
|
+
if (!this.deps.lifecycleStateMachine.isIdle() || this.getCurrentTurnId() !== void 0) return;
|
|
21267
|
+
const head = scheduler.drain()[0];
|
|
21268
|
+
if (head === void 0) return;
|
|
21269
|
+
this.handleSystemTrigger({ trigger: head }).catch(() => {});
|
|
21270
|
+
}
|
|
21207
21271
|
async handleCancel(req) {
|
|
21208
21272
|
const requestedId = req.data.turn_id ?? this.getCurrentTurnId();
|
|
21209
21273
|
if (requestedId === void 0) return { ok: true };
|
|
@@ -21278,38 +21342,38 @@ var TurnManager = class {
|
|
|
21278
21342
|
agent_id: this.agentId
|
|
21279
21343
|
};
|
|
21280
21344
|
const soulConfig = {
|
|
21281
|
-
beforeStep: async () => {
|
|
21345
|
+
beforeStep: async ({ signal }) => {
|
|
21282
21346
|
await this.deps.contextState.applySteerMessages();
|
|
21283
21347
|
this.deps.contextState.beforeStep?.();
|
|
21348
|
+
await this.fullCompactionProvider?.beforeStep(signal);
|
|
21349
|
+
},
|
|
21350
|
+
afterStep: async () => {
|
|
21351
|
+
await this.fullCompactionProvider?.afterStep();
|
|
21284
21352
|
},
|
|
21285
21353
|
beforeTurnCompletes: async () => {
|
|
21286
21354
|
return { continue: await this.deps.contextState.applySteerMessages() };
|
|
21287
21355
|
}
|
|
21288
21356
|
};
|
|
21357
|
+
if (this.fullCompactionProvider) this.fullCompactionProvider.lastSoulConfig = soulConfig;
|
|
21289
21358
|
const scope = this.deps.toolExecutionScopeFactory?.create({
|
|
21290
21359
|
sessionId: this.sessionId,
|
|
21291
21360
|
agentId: this.agentId,
|
|
21292
21361
|
kind: this.agentType === "sub" ? "subagent" : this.agentType === "independent" ? "independent" : "main",
|
|
21293
21362
|
subagentType: this.subagentType
|
|
21294
21363
|
});
|
|
21295
|
-
const
|
|
21296
|
-
const baseRuntime = runtimeBundle?.runtime ?? this.runtime;
|
|
21364
|
+
const baseRuntime = (this.runtimeSlot?.current())?.runtime ?? this.runtime;
|
|
21297
21365
|
const runtimeForTurn = scope?.wrapRuntime(baseRuntime) ?? baseRuntime;
|
|
21366
|
+
const tools = this.deps.tools;
|
|
21298
21367
|
if (scope !== void 0) {
|
|
21299
21368
|
this.activeToolExecutionScope = scope;
|
|
21300
21369
|
mergeSoulConfig(soulConfig, scope.buildSoulConfig({
|
|
21301
|
-
tools
|
|
21370
|
+
tools,
|
|
21302
21371
|
turnId,
|
|
21303
21372
|
permissionRules: () => mergeTurnRules(this.sessionRules, turnOverrides),
|
|
21304
21373
|
permissionMode: () => this.permissionMode,
|
|
21305
21374
|
approvalSource
|
|
21306
21375
|
}));
|
|
21307
|
-
} else mergeSoulConfig(soulConfig, { tools
|
|
21308
|
-
const compactionConfig = this.runtimeSlot !== void 0 ? runtimeBundle?.compactionConfig : this.compactionConfig;
|
|
21309
|
-
if (compactionConfig !== void 0) mergeSoulConfig(soulConfig, {
|
|
21310
|
-
compactionConfig,
|
|
21311
|
-
contextWindow: compactionConfig.maxContextSize
|
|
21312
|
-
});
|
|
21376
|
+
} else mergeSoulConfig(soulConfig, { tools });
|
|
21313
21377
|
if (this.deps.hookEngine !== void 0) mergeSoulConfig(soulConfig, {
|
|
21314
21378
|
beforeStep: async (ctx, signal) => {
|
|
21315
21379
|
const result = await this.executionHooks.run({
|
|
@@ -21345,7 +21409,6 @@ var TurnManager = class {
|
|
|
21345
21409
|
let result;
|
|
21346
21410
|
let reason;
|
|
21347
21411
|
try {
|
|
21348
|
-
let compactionCount = 0;
|
|
21349
21412
|
while (true) {
|
|
21350
21413
|
signal.throwIfAborted();
|
|
21351
21414
|
let soulResult;
|
|
@@ -21353,44 +21416,13 @@ var TurnManager = class {
|
|
|
21353
21416
|
soulResult = await runSoulTurn(soulConfig, this.deps.contextState, runtime, this.createStepStatusSink(), signal);
|
|
21354
21417
|
} catch (error) {
|
|
21355
21418
|
if (error instanceof ContextOverflowError) {
|
|
21356
|
-
|
|
21357
|
-
if (compactionCount > MAX_COMPACTIONS_PER_TURN) {
|
|
21358
|
-
this.deps.sink.emit({
|
|
21359
|
-
type: "session.error",
|
|
21360
|
-
error: `Compaction limit exceeded (${MAX_COMPACTIONS_PER_TURN})`,
|
|
21361
|
-
error_type: "context_overflow"
|
|
21362
|
-
});
|
|
21363
|
-
result = {
|
|
21364
|
-
stopReason: "error",
|
|
21365
|
-
steps: 0,
|
|
21366
|
-
usage: zeroUsage()
|
|
21367
|
-
};
|
|
21368
|
-
break;
|
|
21369
|
-
}
|
|
21370
|
-
await this.deps.compaction.executeCompaction(signal);
|
|
21419
|
+
await this.fullCompactionProvider?.handleOverflowError(signal);
|
|
21371
21420
|
continue;
|
|
21372
21421
|
}
|
|
21373
21422
|
throw error;
|
|
21374
21423
|
}
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
break;
|
|
21378
|
-
}
|
|
21379
|
-
compactionCount += 1;
|
|
21380
|
-
if (compactionCount > MAX_COMPACTIONS_PER_TURN) {
|
|
21381
|
-
this.deps.sink.emit({
|
|
21382
|
-
type: "session.error",
|
|
21383
|
-
error: `Compaction limit exceeded (${MAX_COMPACTIONS_PER_TURN})`,
|
|
21384
|
-
error_type: "context_overflow"
|
|
21385
|
-
});
|
|
21386
|
-
result = {
|
|
21387
|
-
stopReason: "error",
|
|
21388
|
-
steps: soulResult.steps,
|
|
21389
|
-
usage: soulResult.usage
|
|
21390
|
-
};
|
|
21391
|
-
break;
|
|
21392
|
-
}
|
|
21393
|
-
await this.deps.compaction.executeCompaction(signal);
|
|
21424
|
+
result = soulResult;
|
|
21425
|
+
break;
|
|
21394
21426
|
}
|
|
21395
21427
|
reason = result !== void 0 && result.stopReason === "aborted" ? "cancelled" : "done";
|
|
21396
21428
|
if (result !== void 0 && result.stopReason === "error") reason = "error";
|
|
@@ -21482,6 +21514,7 @@ var TurnManager = class {
|
|
|
21482
21514
|
input: 0,
|
|
21483
21515
|
output: 0
|
|
21484
21516
|
});
|
|
21517
|
+
this.processWakeQueue();
|
|
21485
21518
|
}
|
|
21486
21519
|
}
|
|
21487
21520
|
/**
|
|
@@ -21496,7 +21529,7 @@ var TurnManager = class {
|
|
|
21496
21529
|
*/
|
|
21497
21530
|
getStatusSnapshot(tokenUsage) {
|
|
21498
21531
|
const used = this.deps.contextState.tokenCountWithPending;
|
|
21499
|
-
const total =
|
|
21532
|
+
const total = DEFAULT_CONTEXT_WINDOW;
|
|
21500
21533
|
return {
|
|
21501
21534
|
context_usage: {
|
|
21502
21535
|
used,
|
|
@@ -21520,8 +21553,20 @@ var TurnManager = class {
|
|
|
21520
21553
|
//#region ../../packages/kimi-core/src/soul-plus/turn/wake-queue-scheduler.ts
|
|
21521
21554
|
var WakeQueueScheduler = class {
|
|
21522
21555
|
queue = [];
|
|
21556
|
+
onEnqueueListener;
|
|
21523
21557
|
enqueue(trigger) {
|
|
21524
21558
|
this.queue.push(trigger);
|
|
21559
|
+
if (this.onEnqueueListener !== void 0) try {
|
|
21560
|
+
this.onEnqueueListener();
|
|
21561
|
+
} catch {}
|
|
21562
|
+
}
|
|
21563
|
+
/**
|
|
21564
|
+
* Register a single listener fired synchronously after each `enqueue`.
|
|
21565
|
+
* Last writer wins — the canonical wiring is TurnManager registering
|
|
21566
|
+
* exactly once at construction. Pass `undefined` to clear.
|
|
21567
|
+
*/
|
|
21568
|
+
setOnEnqueue(listener) {
|
|
21569
|
+
this.onEnqueueListener = listener;
|
|
21525
21570
|
}
|
|
21526
21571
|
/**
|
|
21527
21572
|
* Remove and return every buffered trigger in FIFO order. Idempotent
|
|
@@ -21553,15 +21598,13 @@ var SoulPlus = class {
|
|
|
21553
21598
|
sessionId;
|
|
21554
21599
|
lifecycle;
|
|
21555
21600
|
journal;
|
|
21556
|
-
|
|
21601
|
+
sessionMeta;
|
|
21557
21602
|
components;
|
|
21558
21603
|
infra;
|
|
21559
21604
|
hostToolNames;
|
|
21560
21605
|
planController;
|
|
21561
21606
|
setPlanModeImpl;
|
|
21562
21607
|
stateCache;
|
|
21563
|
-
/** Lazily materialized config-channel handler used by wire/session control callers. */
|
|
21564
|
-
sessionControlInstance;
|
|
21565
21608
|
constructor(deps) {
|
|
21566
21609
|
this.sessionId = deps.sessionId;
|
|
21567
21610
|
this.stateCache = deps.stateCache;
|
|
@@ -21579,13 +21622,11 @@ var SoulPlus = class {
|
|
|
21579
21622
|
const journalWriter = contextState.journalWriter;
|
|
21580
21623
|
const runtimeSlot = deps.runtimeSlot ?? createSessionRuntimeSlot({
|
|
21581
21624
|
model: contextState.model,
|
|
21582
|
-
runtime: deps.runtime
|
|
21583
|
-
compactionProvider: deps.compactionProvider,
|
|
21584
|
-
compactionConfig: deps.compactionConfig
|
|
21625
|
+
runtime: deps.runtime
|
|
21585
21626
|
});
|
|
21586
21627
|
const runtime = runtimeSlot.current().runtime;
|
|
21587
21628
|
const approvalRuntime = deps.approvalRuntime;
|
|
21588
|
-
|
|
21629
|
+
this.sessionMeta = deps.stateCache !== void 0 && deps.initialMeta !== void 0 ? new SessionMetaService({
|
|
21589
21630
|
sessionId: deps.sessionId,
|
|
21590
21631
|
eventBus,
|
|
21591
21632
|
stateCache: deps.stateCache,
|
|
@@ -21594,21 +21635,10 @@ var SoulPlus = class {
|
|
|
21594
21635
|
const planController = new PlanSessionController({
|
|
21595
21636
|
sessionId: deps.sessionId,
|
|
21596
21637
|
paths: deps.pathConfig,
|
|
21597
|
-
sessionMeta
|
|
21638
|
+
sessionMeta: this.sessionMeta
|
|
21598
21639
|
});
|
|
21599
21640
|
this.planController = planController;
|
|
21600
|
-
const compactionProvider = deps.compactionProvider;
|
|
21601
21641
|
const turnManagerRef = createTurnManagerRef();
|
|
21602
|
-
const compaction = createSoulPlusCompactionOrchestrator({
|
|
21603
|
-
contextState,
|
|
21604
|
-
compactionProvider,
|
|
21605
|
-
runtimeSlot,
|
|
21606
|
-
lifecycleStateMachine: stateMachine,
|
|
21607
|
-
sink: eventBus,
|
|
21608
|
-
journalWriter,
|
|
21609
|
-
sessionId: deps.sessionId,
|
|
21610
|
-
turnManagerRef
|
|
21611
|
-
});
|
|
21612
21642
|
const effectiveHookEngine = deps.hookEngine ?? (approvalRuntime !== void 0 ? new HookEngine({
|
|
21613
21643
|
executors: /* @__PURE__ */ new Map(),
|
|
21614
21644
|
sink: eventBus
|
|
@@ -21621,6 +21651,14 @@ var SoulPlus = class {
|
|
|
21621
21651
|
planController,
|
|
21622
21652
|
turnManagerRef
|
|
21623
21653
|
});
|
|
21654
|
+
const notificationManager = new NotificationManager({
|
|
21655
|
+
sessionJournal,
|
|
21656
|
+
sessionEventBus: eventBus,
|
|
21657
|
+
contextState,
|
|
21658
|
+
onShellDeliver: deps.onShellDeliver,
|
|
21659
|
+
logger: deps.logger
|
|
21660
|
+
});
|
|
21661
|
+
const wakeScheduler = new WakeQueueScheduler();
|
|
21624
21662
|
const { soulRegistry, hasSubagentInfra } = createSoulRegistryForSession({
|
|
21625
21663
|
sessionId: deps.sessionId,
|
|
21626
21664
|
sessionJournal,
|
|
@@ -21634,7 +21672,9 @@ var SoulPlus = class {
|
|
|
21634
21672
|
workDir: deps.workDir,
|
|
21635
21673
|
pathConfig: deps.pathConfig,
|
|
21636
21674
|
toolExecutionScopeFactory,
|
|
21637
|
-
producer: deps.producer
|
|
21675
|
+
producer: deps.producer,
|
|
21676
|
+
notificationManager,
|
|
21677
|
+
wakeScheduler
|
|
21638
21678
|
});
|
|
21639
21679
|
registerSubagentTool({
|
|
21640
21680
|
toolRegistry,
|
|
@@ -21650,7 +21690,6 @@ var SoulPlus = class {
|
|
|
21650
21690
|
sessionJournal
|
|
21651
21691
|
});
|
|
21652
21692
|
const dynamicInjectionManager = createDefaultDynamicInjectionManager();
|
|
21653
|
-
const wakeScheduler = new WakeQueueScheduler();
|
|
21654
21693
|
const turnLifecycle = new TurnLifecycleTracker();
|
|
21655
21694
|
const turnManager = new TurnManager({
|
|
21656
21695
|
contextState,
|
|
@@ -21661,7 +21700,6 @@ var SoulPlus = class {
|
|
|
21661
21700
|
lifecycleStateMachine: stateMachine,
|
|
21662
21701
|
soulRegistry,
|
|
21663
21702
|
tools: toolRegistry,
|
|
21664
|
-
compaction,
|
|
21665
21703
|
lifecycle: turnLifecycle,
|
|
21666
21704
|
wakeScheduler,
|
|
21667
21705
|
dynamicInjectionManager,
|
|
@@ -21672,8 +21710,7 @@ var SoulPlus = class {
|
|
|
21672
21710
|
toolExecutionScopeFactory,
|
|
21673
21711
|
approvalRuntime,
|
|
21674
21712
|
hookEngine: deps.hookEngine,
|
|
21675
|
-
compactionConfig: deps.compactionConfig
|
|
21676
|
-
modelCapabilities: deps.modelCapabilities
|
|
21713
|
+
compactionConfig: deps.compactionConfig
|
|
21677
21714
|
});
|
|
21678
21715
|
turnManagerRef.bind(turnManager);
|
|
21679
21716
|
const setPlanMode = createPlanModeSetter({
|
|
@@ -21692,13 +21729,6 @@ var SoulPlus = class {
|
|
|
21692
21729
|
setPlanMode,
|
|
21693
21730
|
planController
|
|
21694
21731
|
});
|
|
21695
|
-
const notificationManager = new NotificationManager({
|
|
21696
|
-
sessionJournal,
|
|
21697
|
-
sessionEventBus: eventBus,
|
|
21698
|
-
contextState,
|
|
21699
|
-
onShellDeliver: deps.onShellDeliver,
|
|
21700
|
-
logger: deps.logger
|
|
21701
|
-
});
|
|
21702
21732
|
this.lifecycle = {
|
|
21703
21733
|
stateMachine,
|
|
21704
21734
|
gate
|
|
@@ -21708,11 +21738,6 @@ var SoulPlus = class {
|
|
|
21708
21738
|
contextState,
|
|
21709
21739
|
sessionJournal
|
|
21710
21740
|
};
|
|
21711
|
-
this.services = {
|
|
21712
|
-
approvalRuntime,
|
|
21713
|
-
compaction,
|
|
21714
|
-
sessionMeta
|
|
21715
|
-
};
|
|
21716
21741
|
this.components = {
|
|
21717
21742
|
turnManager,
|
|
21718
21743
|
soulRegistry,
|
|
@@ -21835,7 +21860,7 @@ var SoulPlus = class {
|
|
|
21835
21860
|
* create/resume paths; direct tests may omit it.
|
|
21836
21861
|
*/
|
|
21837
21862
|
getSessionMeta() {
|
|
21838
|
-
const svc = this.
|
|
21863
|
+
const svc = this.sessionMeta;
|
|
21839
21864
|
if (svc === void 0) throw new Error("SoulPlus.getSessionMeta: SessionMetaService was not wired (missing stateCache / initialMeta in SoulPlusDeps)");
|
|
21840
21865
|
return svc;
|
|
21841
21866
|
}
|
|
@@ -21844,7 +21869,7 @@ var SoulPlus = class {
|
|
|
21844
21869
|
* direct tests may not include state plumbing.
|
|
21845
21870
|
*/
|
|
21846
21871
|
tryGetSessionMeta() {
|
|
21847
|
-
return this.
|
|
21872
|
+
return this.sessionMeta;
|
|
21848
21873
|
}
|
|
21849
21874
|
async setPlanMode(enabled) {
|
|
21850
21875
|
await this.setPlanModeImpl(enabled);
|
|
@@ -21881,36 +21906,6 @@ var SoulPlus = class {
|
|
|
21881
21906
|
return this.components.skillManager;
|
|
21882
21907
|
}
|
|
21883
21908
|
/**
|
|
21884
|
-
* Access the config-channel session control handler. The handler is
|
|
21885
|
-
* lazy but stable for this SoulPlus instance.
|
|
21886
|
-
*/
|
|
21887
|
-
getSessionControl() {
|
|
21888
|
-
if (this.sessionControlInstance !== void 0) return this.sessionControlInstance;
|
|
21889
|
-
this.sessionControlInstance = new DefaultSessionControl({
|
|
21890
|
-
turnManager: this.components.turnManager,
|
|
21891
|
-
contextState: this.journal.contextState,
|
|
21892
|
-
setPlanModeOverride: (enabled) => this.setPlanMode(enabled),
|
|
21893
|
-
setYoloOverride: async (enabled) => {
|
|
21894
|
-
const permissionMode = enabled ? "bypassPermissions" : "default";
|
|
21895
|
-
await this.stateCache?.update((current) => {
|
|
21896
|
-
const now = Date.now();
|
|
21897
|
-
return {
|
|
21898
|
-
...current ?? {
|
|
21899
|
-
session_id: this.sessionId,
|
|
21900
|
-
created_at: now,
|
|
21901
|
-
updated_at: now
|
|
21902
|
-
},
|
|
21903
|
-
permission_mode: permissionMode,
|
|
21904
|
-
updated_at: now,
|
|
21905
|
-
last_exit_code: "dirty"
|
|
21906
|
-
};
|
|
21907
|
-
});
|
|
21908
|
-
this.components.turnManager.setPermissionMode(permissionMode);
|
|
21909
|
-
}
|
|
21910
|
-
});
|
|
21911
|
-
return this.sessionControlInstance;
|
|
21912
|
-
}
|
|
21913
|
-
/**
|
|
21914
21909
|
* Apply a programmatic model change and notify observers immediately.
|
|
21915
21910
|
*
|
|
21916
21911
|
* state.json is the durable truth source (updated via `stateCache.update`);
|
|
@@ -21982,6 +21977,48 @@ var SoulPlus = class {
|
|
|
21982
21977
|
}
|
|
21983
21978
|
};
|
|
21984
21979
|
//#endregion
|
|
21980
|
+
//#region ../../packages/kimi-core/src/soul-plus/session/session-control.ts
|
|
21981
|
+
var DefaultSessionControl = class {
|
|
21982
|
+
turnManager;
|
|
21983
|
+
contextState;
|
|
21984
|
+
setPlanModeOverride;
|
|
21985
|
+
setYoloOverride;
|
|
21986
|
+
constructor(deps) {
|
|
21987
|
+
this.turnManager = deps.turnManager;
|
|
21988
|
+
this.contextState = deps.contextState;
|
|
21989
|
+
this.setPlanModeOverride = deps.setPlanModeOverride;
|
|
21990
|
+
this.setYoloOverride = deps.setYoloOverride;
|
|
21991
|
+
}
|
|
21992
|
+
async compact(customInstruction) {
|
|
21993
|
+
return this.turnManager.triggerCompaction(customInstruction);
|
|
21994
|
+
}
|
|
21995
|
+
async clear() {
|
|
21996
|
+
if (!this.turnManager.tryReserveForMaintenance()) throw new Error(`Cannot clear while session is ${this.turnManager.getLifecycleState()} — cancel the current turn or wait for compaction to finish first.`);
|
|
21997
|
+
try {
|
|
21998
|
+
await this.contextState.clear();
|
|
21999
|
+
} finally {
|
|
22000
|
+
this.turnManager.releaseMaintenance();
|
|
22001
|
+
}
|
|
22002
|
+
}
|
|
22003
|
+
async setPlanMode(enabled) {
|
|
22004
|
+
if (this.setPlanModeOverride !== void 0) {
|
|
22005
|
+
await this.setPlanModeOverride(enabled);
|
|
22006
|
+
return;
|
|
22007
|
+
}
|
|
22008
|
+
this.turnManager.setPlanMode(enabled);
|
|
22009
|
+
}
|
|
22010
|
+
async setYolo(enabled) {
|
|
22011
|
+
if (this.setYoloOverride !== void 0) {
|
|
22012
|
+
await this.setYoloOverride(enabled);
|
|
22013
|
+
return;
|
|
22014
|
+
}
|
|
22015
|
+
const previousMode = this.turnManager.getPermissionMode();
|
|
22016
|
+
const newMode = enabled ? "bypassPermissions" : "default";
|
|
22017
|
+
if (previousMode === newMode) return;
|
|
22018
|
+
this.turnManager.setPermissionMode(newMode);
|
|
22019
|
+
}
|
|
22020
|
+
};
|
|
22021
|
+
//#endregion
|
|
21985
22022
|
//#region ../../packages/kimi-core/src/soul-plus/kosong/kosong-adapter.ts
|
|
21986
22023
|
/**
|
|
21987
22024
|
* KosongAdapter — wraps a `ChatProvider` from `@moonshot-ai/kosong` so it
|
|
@@ -22042,15 +22079,6 @@ var KosongAdapter = class {
|
|
|
22042
22079
|
this.maxRetries = options.maxRetries ?? 3;
|
|
22043
22080
|
this.baseRetryDelayMs = options.baseRetryDelayMs ?? 1e3;
|
|
22044
22081
|
}
|
|
22045
|
-
/**
|
|
22046
|
-
* Phase 19 Slice B — proxy the provider's declared capability matrix.
|
|
22047
|
-
* Returns `undefined` when the provider does not expose a capability
|
|
22048
|
-
* table (legacy providers / mock harnesses); callers treat `undefined`
|
|
22049
|
-
* as "no constraint" and skip the gate.
|
|
22050
|
-
*/
|
|
22051
|
-
getCapability(model) {
|
|
22052
|
-
return this.provider.getCapability?.(model);
|
|
22053
|
-
}
|
|
22054
22082
|
async chat(params) {
|
|
22055
22083
|
params.signal.throwIfAborted();
|
|
22056
22084
|
try {
|
|
@@ -22184,7 +22212,7 @@ var KosongAdapter = class {
|
|
|
22184
22212
|
}));
|
|
22185
22213
|
const usage = mapUsage(result.usage);
|
|
22186
22214
|
const stopReason = mapFinishReason(result.finishReason);
|
|
22187
|
-
|
|
22215
|
+
return {
|
|
22188
22216
|
message: {
|
|
22189
22217
|
role: "assistant",
|
|
22190
22218
|
content: contentBlocks,
|
|
@@ -22196,8 +22224,6 @@ var KosongAdapter = class {
|
|
|
22196
22224
|
actualModel: activeProvider.modelName,
|
|
22197
22225
|
stopReason
|
|
22198
22226
|
};
|
|
22199
|
-
if (params.contextWindow !== void 0 && usage.input > params.contextWindow) throw new ContextOverflowError(`Implicit context overflow: input=${String(usage.input)} exceeds contextWindow=${String(params.contextWindow)}`, usage);
|
|
22200
|
-
return response;
|
|
22201
22227
|
}
|
|
22202
22228
|
};
|
|
22203
22229
|
const PTL_MESSAGE_PATTERNS = [
|
|
@@ -22324,88 +22350,6 @@ function createRuntime(deps) {
|
|
|
22324
22350
|
return { kosong: deps.kosong };
|
|
22325
22351
|
}
|
|
22326
22352
|
//#endregion
|
|
22327
|
-
//#region ../../packages/kimi-core/src/soul-plus/compaction/compaction-provider.ts
|
|
22328
|
-
/**
|
|
22329
|
-
* KosongCompactionProvider — real CompactionProvider that uses kosong's
|
|
22330
|
-
* `generate()` to produce a conversation summary (Slice 3.3 / M05).
|
|
22331
|
-
*
|
|
22332
|
-
* Replaces `createStubCompactionProvider()` from Slice 3 for production
|
|
22333
|
-
* use. The stub remains available for tests that do not need real LLM
|
|
22334
|
-
* interaction.
|
|
22335
|
-
*
|
|
22336
|
-
* The implementation mirrors Python's `SimpleCompaction.compact()`:
|
|
22337
|
-
* 1. Format the input messages into a single compaction prompt
|
|
22338
|
-
* 2. Call the LLM (via kosong generate) with a system prompt
|
|
22339
|
-
* 3. Extract the summary text from the response
|
|
22340
|
-
* 4. Return a `SummaryMessage` with the summary and metadata
|
|
22341
|
-
*/
|
|
22342
|
-
const COMPACTION_SYSTEM_PROMPT = "You are a helpful assistant that compacts conversation context. Summarize the conversation concisely while preserving all important details, decisions, code snippets, file paths, and action items.";
|
|
22343
|
-
/**
|
|
22344
|
-
* Build the compaction prompt from conversation messages.
|
|
22345
|
-
*
|
|
22346
|
-
* Mirrors Python's `SimpleCompaction.prepare()` serialization:
|
|
22347
|
-
* - Each message becomes a block: `## Message N\nRole: X\nContent:\n<text>`
|
|
22348
|
-
* - Only TextPart is retained; think / image / audio / video are dropped.
|
|
22349
|
-
* - Tool results are folded into the assistant message that issued the
|
|
22350
|
-
* call, so the summary sees both the invocation and its result.
|
|
22351
|
-
* - Message blocks are concatenated without separators, matching Python's
|
|
22352
|
-
* `compact_message.content.extend()` behaviour.
|
|
22353
|
-
* - The instruction suffix is joined with a single `\n` to match Python's
|
|
22354
|
-
* `prompt_text = "\n" + prompts.COMPACT`.
|
|
22355
|
-
*/
|
|
22356
|
-
function buildCompactionPrompt(messages, userInstructions) {
|
|
22357
|
-
const toolResultsById = /* @__PURE__ */ new Map();
|
|
22358
|
-
for (const msg of messages) if (msg.role === "tool" && msg.toolCallId) {
|
|
22359
|
-
const text = msg.content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
22360
|
-
toolResultsById.set(msg.toolCallId, text);
|
|
22361
|
-
}
|
|
22362
|
-
const parts = [];
|
|
22363
|
-
let seq = 1;
|
|
22364
|
-
for (const msg of messages) {
|
|
22365
|
-
if (msg.role === "tool") continue;
|
|
22366
|
-
const body = msg.content.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
22367
|
-
let block = `## Message ${seq}\nRole: ${msg.role}\nContent:\n${body}`;
|
|
22368
|
-
if (msg.role === "assistant" && msg.toolCalls && msg.toolCalls.length > 0) for (const tc of msg.toolCalls) {
|
|
22369
|
-
let argsDisplay = tc.function.arguments ?? "";
|
|
22370
|
-
try {
|
|
22371
|
-
const parsed = JSON.parse(argsDisplay);
|
|
22372
|
-
argsDisplay = JSON.stringify(parsed);
|
|
22373
|
-
} catch {}
|
|
22374
|
-
const result = toolResultsById.get(tc.id);
|
|
22375
|
-
const resultStr = result !== void 0 ? ` ->\n${result}` : "";
|
|
22376
|
-
block += `\n[Tool: ${tc.function.name}(${argsDisplay})]${resultStr}`;
|
|
22377
|
-
}
|
|
22378
|
-
parts.push((block.endsWith("\n") ? block : block + "\n") + "\n");
|
|
22379
|
-
seq++;
|
|
22380
|
-
}
|
|
22381
|
-
let prompt = parts.join("") + "\nSummarize the above conversation. Preserve:\n- Key decisions and their reasoning\n- Important code snippets, file paths, and technical details\n- Action items and their status\n- Any constraints or requirements mentioned\n\nBe concise but thorough. Do not lose critical context.";
|
|
22382
|
-
if (userInstructions !== void 0 && userInstructions.length > 0) prompt += "\n\n**User's Custom Compaction Instruction:**\nThe user has specifically requested the following focus during compaction. You MUST prioritize this instruction above the default compression priorities:\n" + userInstructions;
|
|
22383
|
-
return prompt;
|
|
22384
|
-
}
|
|
22385
|
-
var KosongCompactionProvider = class {
|
|
22386
|
-
provider;
|
|
22387
|
-
constructor(provider) {
|
|
22388
|
-
this.provider = provider;
|
|
22389
|
-
}
|
|
22390
|
-
async run(messages, signal, options) {
|
|
22391
|
-
const compactionMessage = {
|
|
22392
|
-
role: "user",
|
|
22393
|
-
content: [{
|
|
22394
|
-
type: "text",
|
|
22395
|
-
text: buildCompactionPrompt(messages, options?.userInstructions)
|
|
22396
|
-
}],
|
|
22397
|
-
toolCalls: []
|
|
22398
|
-
};
|
|
22399
|
-
return {
|
|
22400
|
-
content: (await generate$1(this.provider, COMPACTION_SYSTEM_PROMPT, [], [compactionMessage], void 0, { signal })).message.content.filter((p) => p.type === "text").map((p) => p.text).join(""),
|
|
22401
|
-
original_turn_count: messages.length
|
|
22402
|
-
};
|
|
22403
|
-
}
|
|
22404
|
-
};
|
|
22405
|
-
function createKosongCompactionProvider(provider) {
|
|
22406
|
-
return new KosongCompactionProvider(provider);
|
|
22407
|
-
}
|
|
22408
|
-
//#endregion
|
|
22409
22353
|
//#region ../../packages/kimi-core/src/soul-plus/approval/wired-approval-runtime.ts
|
|
22410
22354
|
/**
|
|
22411
22355
|
* WiredApprovalRuntime — the production `ApprovalRuntime` (v2 §9-G).
|
|
@@ -22912,6 +22856,16 @@ z.discriminatedUnion("kind", [
|
|
|
22912
22856
|
detail: z.unknown().optional()
|
|
22913
22857
|
})
|
|
22914
22858
|
]);
|
|
22859
|
+
//#endregion
|
|
22860
|
+
//#region ../../packages/kimi-core/src/tools/builtin/cognition/think.ts
|
|
22861
|
+
/**
|
|
22862
|
+
* ThinkTool — no-op reasoning tool (Slice 3.5).
|
|
22863
|
+
*
|
|
22864
|
+
* Ports Python `kimi_cli/tools/think/__init__.py`. Gives the LLM a
|
|
22865
|
+
* structured place to record intermediate reasoning steps — acts as an
|
|
22866
|
+
* extended-thinking workaround for models that lack native thinking
|
|
22867
|
+
* tokens. The tool produces no side effects and always returns success.
|
|
22868
|
+
*/
|
|
22915
22869
|
const ThinkInputSchema = z.object({ thought: z.string().describe("Your thought process.") });
|
|
22916
22870
|
const DESCRIPTION$3 = "Use this tool to think about something. It will not produce any output or take any action. Use it when you need to reason through a problem step by step before deciding what to do next.";
|
|
22917
22871
|
var ThinkTool = class {
|
|
@@ -23560,9 +23514,16 @@ function infoToPersisted(info) {
|
|
|
23560
23514
|
stop_reason: info.stopReason
|
|
23561
23515
|
};
|
|
23562
23516
|
}
|
|
23517
|
+
//#endregion
|
|
23518
|
+
//#region ../../packages/kimi-core/src/tools/background/task-list.ts
|
|
23519
|
+
/**
|
|
23520
|
+
* TaskListTool — list background tasks (Slice 3.5).
|
|
23521
|
+
*
|
|
23522
|
+
* Ports Python `kimi_cli/tools/background/__init__.py:TaskList`.
|
|
23523
|
+
*/
|
|
23563
23524
|
const TaskListInputSchema = z.object({
|
|
23564
23525
|
active_only: z.boolean().optional().default(true).describe("Whether to list only non-terminal background tasks."),
|
|
23565
|
-
limit: z.number().int().min(1).max(100).
|
|
23526
|
+
limit: z.number().int().min(1).max(100).default(20).describe("Maximum number of tasks to return.").optional()
|
|
23566
23527
|
});
|
|
23567
23528
|
function formatTaskList(tasks) {
|
|
23568
23529
|
if (tasks.length === 0) return "No background tasks found.";
|
|
@@ -23585,10 +23546,17 @@ var TaskListTool = class {
|
|
|
23585
23546
|
return "Listing background tasks";
|
|
23586
23547
|
}
|
|
23587
23548
|
};
|
|
23549
|
+
//#endregion
|
|
23550
|
+
//#region ../../packages/kimi-core/src/tools/background/task-output.ts
|
|
23551
|
+
/**
|
|
23552
|
+
* TaskOutputTool — read output from a background task (Slice 3.5).
|
|
23553
|
+
*
|
|
23554
|
+
* Ports Python `kimi_cli/tools/background/__init__.py:TaskOutput`.
|
|
23555
|
+
*/
|
|
23588
23556
|
const TaskOutputInputSchema = z.object({
|
|
23589
23557
|
task_id: z.string().describe("The background task ID to inspect."),
|
|
23590
|
-
block: z.boolean().
|
|
23591
|
-
timeout: z.number().int().min(0).max(3600).
|
|
23558
|
+
block: z.boolean().default(false).describe("Whether to wait for the task to finish before returning.").optional(),
|
|
23559
|
+
timeout: z.number().int().min(0).max(3600).default(30).describe("Maximum number of seconds to wait when block=true.").optional()
|
|
23592
23560
|
});
|
|
23593
23561
|
function retrievalStatus(status, block) {
|
|
23594
23562
|
if (isBackgroundTaskTerminal(status)) return "success";
|
|
@@ -23634,9 +23602,16 @@ var TaskOutputTool = class {
|
|
|
23634
23602
|
return `Reading output of task ${args.task_id}`;
|
|
23635
23603
|
}
|
|
23636
23604
|
};
|
|
23605
|
+
//#endregion
|
|
23606
|
+
//#region ../../packages/kimi-core/src/tools/background/task-stop.ts
|
|
23607
|
+
/**
|
|
23608
|
+
* TaskStopTool — stop a running background task (Slice 3.5).
|
|
23609
|
+
*
|
|
23610
|
+
* Ports Python `kimi_cli/tools/background/__init__.py:TaskStop`.
|
|
23611
|
+
*/
|
|
23637
23612
|
const TaskStopInputSchema = z.object({
|
|
23638
23613
|
task_id: z.string().describe("The background task ID to stop."),
|
|
23639
|
-
reason: z.string().
|
|
23614
|
+
reason: z.string().default("Stopped by TaskStop").describe("Short reason recorded when the task is stopped.").optional()
|
|
23640
23615
|
});
|
|
23641
23616
|
var TaskStopTool = class {
|
|
23642
23617
|
name = "TaskStop";
|
|
@@ -23670,10 +23645,20 @@ var TaskStopTool = class {
|
|
|
23670
23645
|
return `Stopping task ${args.task_id}`;
|
|
23671
23646
|
}
|
|
23672
23647
|
};
|
|
23648
|
+
//#endregion
|
|
23649
|
+
//#region ../../packages/kimi-core/src/tools/builtin/web/web-search.ts
|
|
23650
|
+
/**
|
|
23651
|
+
* WebSearchTool — host-injected web search (Slice 3.5).
|
|
23652
|
+
*
|
|
23653
|
+
* Ports Python `kimi_cli/tools/web/search.py`. kimi-core defines the
|
|
23654
|
+
* interface; the host provides the real search implementation via
|
|
23655
|
+
* `WebSearchProvider`. If no provider is supplied, the tool should not
|
|
23656
|
+
* be registered (not exposed to the LLM).
|
|
23657
|
+
*/
|
|
23673
23658
|
const WebSearchInputSchema = z.object({
|
|
23674
23659
|
query: z.string().describe("The query text to search for."),
|
|
23675
|
-
limit: z.number().int().min(1).max(20).
|
|
23676
|
-
include_content: z.boolean().
|
|
23660
|
+
limit: z.number().int().min(1).max(20).default(5).describe("The number of results to return.").optional(),
|
|
23661
|
+
include_content: z.boolean().default(false).describe("Whether to include the content of the web pages in the results.").optional()
|
|
23677
23662
|
});
|
|
23678
23663
|
const DESCRIPTION$2 = "Search the web for information. Returns a list of search results with title, URL, and snippet. Use this when you need up-to-date information from the internet.";
|
|
23679
23664
|
var WebSearchTool = class {
|
|
@@ -23719,9 +23704,19 @@ var WebSearchTool = class {
|
|
|
23719
23704
|
return `Searching: ${args.query.length > 40 ? `${args.query.slice(0, 40)}…` : args.query}`;
|
|
23720
23705
|
}
|
|
23721
23706
|
};
|
|
23707
|
+
//#endregion
|
|
23708
|
+
//#region ../../packages/kimi-core/src/tools/builtin/web/fetch-url.ts
|
|
23709
|
+
/**
|
|
23710
|
+
* FetchURLTool — host-injected URL fetcher (Slice 3.5).
|
|
23711
|
+
*
|
|
23712
|
+
* Ports Python `kimi_cli/tools/web/fetch.py`. kimi-core defines the
|
|
23713
|
+
* interface; the host provides the real fetch implementation via
|
|
23714
|
+
* `UrlFetcher`. If no fetcher is supplied, the tool should not be
|
|
23715
|
+
* registered (not exposed to the LLM).
|
|
23716
|
+
*/
|
|
23722
23717
|
const FetchURLInputSchema = z.object({
|
|
23723
23718
|
url: z.string().describe("The URL to fetch content from."),
|
|
23724
|
-
format: z.enum(["text", "markdown"]).
|
|
23719
|
+
format: z.enum(["text", "markdown"]).default("text").describe("The format of the returned content.").optional()
|
|
23725
23720
|
});
|
|
23726
23721
|
const DESCRIPTION$1 = "Fetch content from a URL. Returns the main text content extracted from the page. Use this when you need to read a specific web page.";
|
|
23727
23722
|
var FetchURLTool = class {
|
|
@@ -24254,6 +24249,7 @@ var ReadMediaFileTool = class {
|
|
|
24254
24249
|
metadata = { source: "builtin" };
|
|
24255
24250
|
description;
|
|
24256
24251
|
inputSchema = ReadMediaFileInputSchema;
|
|
24252
|
+
isConcurrencySafe = (_input) => true;
|
|
24257
24253
|
capabilities;
|
|
24258
24254
|
constructor(kaos, workspace, capabilities, imageSizeExtractor, videoUploader) {
|
|
24259
24255
|
this.kaos = kaos;
|
|
@@ -24468,7 +24464,7 @@ async function detectEnvironmentFromNode() {
|
|
|
24468
24464
|
* 2. Public `*Schema: z.ZodType<T>` — explicit interface as type param
|
|
24469
24465
|
* 3. `AssertEqual` drift guard — compile-time proof that (1) and (2) agree
|
|
24470
24466
|
*/
|
|
24471
|
-
const
|
|
24467
|
+
const ReadInputSchema = z.object({
|
|
24472
24468
|
path: z.string(),
|
|
24473
24469
|
offset: z.number().int().nonnegative().optional(),
|
|
24474
24470
|
limit: z.number().int().positive().optional()
|
|
@@ -24477,24 +24473,21 @@ z.object({
|
|
|
24477
24473
|
content: z.string(),
|
|
24478
24474
|
lineCount: z.number().int().nonnegative()
|
|
24479
24475
|
});
|
|
24480
|
-
const
|
|
24481
|
-
const _rawWriteInputSchema = z.object({
|
|
24476
|
+
const WriteInputSchema = z.object({
|
|
24482
24477
|
path: z.string(),
|
|
24483
24478
|
content: z.string()
|
|
24484
24479
|
});
|
|
24485
24480
|
z.object({ bytesWritten: z.number().int().nonnegative() });
|
|
24486
|
-
const
|
|
24487
|
-
const _rawEditInputSchema = z.object({
|
|
24481
|
+
const EditInputSchema = z.object({
|
|
24488
24482
|
path: z.string(),
|
|
24489
24483
|
old_string: z.string().min(1),
|
|
24490
24484
|
new_string: z.string(),
|
|
24491
24485
|
replace_all: z.boolean().optional()
|
|
24492
24486
|
});
|
|
24493
24487
|
z.object({ replacementCount: z.number().int().nonnegative() });
|
|
24494
|
-
const EditInputSchema = _rawEditInputSchema;
|
|
24495
24488
|
const MAX_FG_TIMEOUT_MS = 300 * 1e3;
|
|
24496
24489
|
const MAX_BG_TIMEOUT_MS = 1440 * 60 * 1e3;
|
|
24497
|
-
const
|
|
24490
|
+
const BashInputSchema = z.object({
|
|
24498
24491
|
command: z.string().min(1, "Command cannot be empty."),
|
|
24499
24492
|
cwd: z.string().optional(),
|
|
24500
24493
|
timeout: z.number().int().positive().optional().describe(`Optional timeout in milliseconds for the command to execute. Foreground max ${String(MAX_FG_TIMEOUT_MS)}ms; background max ${String(MAX_BG_TIMEOUT_MS)}ms.`),
|
|
@@ -24514,8 +24507,7 @@ z.object({
|
|
|
24514
24507
|
stdout: z.string(),
|
|
24515
24508
|
stderr: z.string()
|
|
24516
24509
|
});
|
|
24517
|
-
const
|
|
24518
|
-
const _rawGrepInputSchema = z.object({
|
|
24510
|
+
const GrepInputSchema = z.object({
|
|
24519
24511
|
pattern: z.string(),
|
|
24520
24512
|
path: z.string().optional(),
|
|
24521
24513
|
glob: z.string().optional(),
|
|
@@ -24548,14 +24540,12 @@ z.object({
|
|
|
24548
24540
|
numMatches: z.number().int().nonnegative().optional(),
|
|
24549
24541
|
appliedLimit: z.number().int().nonnegative().optional()
|
|
24550
24542
|
});
|
|
24551
|
-
const
|
|
24552
|
-
const _rawGlobInputSchema = z.object({
|
|
24543
|
+
const GlobInputSchema = z.object({
|
|
24553
24544
|
pattern: z.string().describe("Glob pattern to match files/directories."),
|
|
24554
24545
|
path: z.string().optional().describe("Absolute path to the directory to search in. Defaults to every allowed workspace root (primary + additional dirs)."),
|
|
24555
24546
|
include_dirs: z.boolean().optional().describe("Whether to include directories in results. Defaults to true. Set false to return only files.")
|
|
24556
24547
|
});
|
|
24557
24548
|
z.object({ paths: z.array(z.string()) });
|
|
24558
|
-
const GlobInputSchema = _rawGlobInputSchema;
|
|
24559
24549
|
//#endregion
|
|
24560
24550
|
//#region ../../packages/kimi-core/src/tools/builtin/file/read.ts
|
|
24561
24551
|
const MAX_LINES = 1e3;
|
|
@@ -24567,10 +24557,21 @@ function truncateLine(line, maxLength) {
|
|
|
24567
24557
|
const target = Math.max(maxLength, 3);
|
|
24568
24558
|
return line.slice(0, target - 3) + marker;
|
|
24569
24559
|
}
|
|
24560
|
+
const READ_DESCRIPTION = [
|
|
24561
|
+
"Read a text file from the local filesystem.",
|
|
24562
|
+
"",
|
|
24563
|
+
"Trust the path the caller gives you — do not `Glob`/`ls` first to confirm it exists. A missing file returns an error you can react to; pre-checking just adds round-trips.",
|
|
24564
|
+
"",
|
|
24565
|
+
"- `path` must be absolute.",
|
|
24566
|
+
`- Returns up to ${String(MAX_LINES)} lines or ${String(MAX_BYTES / 1024)} KB per call, whichever comes first; lines longer than ${String(MAX_LINE_LENGTH)} chars are truncated mid-line.`,
|
|
24567
|
+
"- Page larger files with `offset` (0-based start line) and `limit`.",
|
|
24568
|
+
"- Output format: `<line-number>\\t<content>` per line.",
|
|
24569
|
+
"- After a successful `Edit`/`Write`, skip the verification re-read — those tools error on failure, so a clean return means the change landed."
|
|
24570
|
+
].join("\n");
|
|
24570
24571
|
var ReadTool = class {
|
|
24571
24572
|
name = "Read";
|
|
24572
24573
|
metadata = { source: "builtin" };
|
|
24573
|
-
description =
|
|
24574
|
+
description = READ_DESCRIPTION;
|
|
24574
24575
|
inputSchema = ReadInputSchema;
|
|
24575
24576
|
maxResultSizeChars = Number.POSITIVE_INFINITY;
|
|
24576
24577
|
isConcurrencySafe = (_input) => true;
|
|
@@ -24831,7 +24832,17 @@ const MAX_TIMEOUT_MS = 300 * 1e3;
|
|
|
24831
24832
|
const MAX_BACKGROUND_TIMEOUT_MS = 1440 * 60 * 1e3;
|
|
24832
24833
|
const SIGTERM_GRACE_MS$1 = 5e3;
|
|
24833
24834
|
const MAX_OUTPUT_BYTES$1 = 10 * 1024 * 1024;
|
|
24834
|
-
const BASH_DESCRIPTION = `Execute a bash command. Use this
|
|
24835
|
+
const BASH_DESCRIPTION = `Execute a bash command. Use this for shell semantics — pipes, env, processes, git, package managers, build/test runners, anything genuinely interactive or multi-step.
|
|
24836
|
+
|
|
24837
|
+
**Translate these to a dedicated tool instead:**
|
|
24838
|
+
- \`cat\` / \`head\` / \`tail\` (known path) → \`Read\`
|
|
24839
|
+
- \`sed\` / \`awk\` (in-place edit) → \`Edit\`
|
|
24840
|
+
- \`echo > file\` / \`cat <<EOF\` → \`Write\`
|
|
24841
|
+
- \`find\` / \`ls\` (locate by pattern) → \`Glob\`
|
|
24842
|
+
- \`grep\` / \`rg\` (search file contents) → \`Grep\`
|
|
24843
|
+
- \`echo\` / \`printf\` (talk to the user) → just output text directly
|
|
24844
|
+
|
|
24845
|
+
The dedicated tools render in the per-tool permission UI and keep raw stdout out of the conversation; that is why they are worth reaching for whenever one fits.
|
|
24835
24846
|
|
|
24836
24847
|
**Output:**
|
|
24837
24848
|
The stdout and stderr will be combined and returned as a string. The output may be truncated if it is too long. If the command failed, the exit code will be provided in a system tag.
|
|
@@ -24852,9 +24863,17 @@ If \`run_in_background=true\`, the command will be started as a background task
|
|
|
24852
24863
|
- Use pipe operations (\`|\`) and redirections (\`>\`, \`>>\`) to chain input and output between commands
|
|
24853
24864
|
- Always quote file paths containing spaces with double quotes (e.g., cd "/path with spaces/")
|
|
24854
24865
|
- Prefer \`run_in_background=true\` for long-running builds, tests, watchers, or servers when you need the conversation to continue before the command finishes.`;
|
|
24855
|
-
const POWERSHELL_DESCRIPTION = `Execute a Windows PowerShell command. Use this
|
|
24866
|
+
const POWERSHELL_DESCRIPTION = `Execute a Windows PowerShell command. Use this for shell semantics — pipes, env, processes, git, package managers, build/test runners, anything genuinely interactive or multi-step. You are on Windows, so use Windows commands, paths, and conventions.
|
|
24856
24867
|
|
|
24857
|
-
|
|
24868
|
+
**Translate these to a dedicated tool instead:**
|
|
24869
|
+
- \`Get-Content\` / \`type\` (known path) → \`Read\`
|
|
24870
|
+
- \`Set-Content\` / \`Add-Content\` (in-place edit) → \`Edit\`
|
|
24871
|
+
- \`Out-File\` / \`> file\` → \`Write\`
|
|
24872
|
+
- \`Get-ChildItem -Recurse\` (locate by pattern) → \`Glob\`
|
|
24873
|
+
- \`Select-String\` (search file contents) → \`Grep\`
|
|
24874
|
+
- \`Write-Host\` / \`echo\` (talk to the user) → just output text directly
|
|
24875
|
+
|
|
24876
|
+
The dedicated tools render in the per-tool permission UI and keep raw stdout out of the conversation; that is why they are worth reaching for whenever one fits.
|
|
24858
24877
|
|
|
24859
24878
|
**Output:**
|
|
24860
24879
|
The stdout and stderr streams are combined and returned as a single string. Extremely long output may be truncated. When a command fails, the exit code is provided in a system tag.
|
|
@@ -30241,7 +30260,7 @@ async function runHookWithTimeout(options) {
|
|
|
30241
30260
|
} catch {}
|
|
30242
30261
|
return FAIL_OPEN_HOOK_RESULT;
|
|
30243
30262
|
}
|
|
30244
|
-
const
|
|
30263
|
+
const WireErrorSchema = z.object({
|
|
30245
30264
|
code: z.number(),
|
|
30246
30265
|
message: z.string(),
|
|
30247
30266
|
details: z.unknown().optional()
|
|
@@ -30260,7 +30279,7 @@ const WireMessageSchema = z.object({
|
|
|
30260
30279
|
method: z.string().min(1).optional(),
|
|
30261
30280
|
request_id: z.string().min(1).optional(),
|
|
30262
30281
|
data: z.unknown().optional(),
|
|
30263
|
-
error:
|
|
30282
|
+
error: WireErrorSchema.optional(),
|
|
30264
30283
|
turn_id: z.string().optional(),
|
|
30265
30284
|
agent_type: z.enum([
|
|
30266
30285
|
"main",
|
|
@@ -30606,6 +30625,12 @@ const BUS_EVENT_TRANSLATORS = {
|
|
|
30606
30625
|
"compaction.begin": (event, ctx) => {
|
|
30607
30626
|
return draft(event, ctx, "compaction.begin", {});
|
|
30608
30627
|
},
|
|
30628
|
+
"compaction.blocked": (event, ctx) => {
|
|
30629
|
+
return draft(event, ctx, "compaction.blocked", {});
|
|
30630
|
+
},
|
|
30631
|
+
"compaction.canceled": (event, ctx) => {
|
|
30632
|
+
return draft(event, ctx, "compaction.canceled", {});
|
|
30633
|
+
},
|
|
30609
30634
|
"compaction.end": (event, ctx) => {
|
|
30610
30635
|
return draft(event, ctx, "compaction.end", {
|
|
30611
30636
|
tokens_before: event.tokensBefore,
|
|
@@ -31232,13 +31257,12 @@ var DefaultSessionApplicationService = class {
|
|
|
31232
31257
|
sessionId,
|
|
31233
31258
|
model
|
|
31234
31259
|
});
|
|
31235
|
-
const compactionConfig =
|
|
31260
|
+
const compactionConfig = this.deps.compactionConfigProvider?.({
|
|
31236
31261
|
sessionId,
|
|
31237
31262
|
model
|
|
31238
31263
|
});
|
|
31239
|
-
const runtimeSlotBundle = runtimeBundle
|
|
31264
|
+
const runtimeSlotBundle = runtimeBundle;
|
|
31240
31265
|
const runtime = runtimeSlotBundle?.runtime ?? this.deps.runtimeProvider();
|
|
31241
|
-
const compactionProvider = runtimeSlotBundle?.compactionProvider ?? this.deps.compactionProviderProvider();
|
|
31242
31266
|
const runtimeSlot = runtimeSlotBundle !== void 0 ? createSessionRuntimeSlot(runtimeSlotBundle) : void 0;
|
|
31243
31267
|
const tools = await this.deps.toolsProvider({
|
|
31244
31268
|
sessionId,
|
|
@@ -31256,7 +31280,6 @@ var DefaultSessionApplicationService = class {
|
|
|
31256
31280
|
systemPrompt,
|
|
31257
31281
|
eventBus,
|
|
31258
31282
|
workspaceDir: this.deps.workspaceDir,
|
|
31259
|
-
compactionProvider,
|
|
31260
31283
|
compactionConfig,
|
|
31261
31284
|
approvalRuntime: this.deps.approvalRuntime,
|
|
31262
31285
|
approvalRuntimeFactory: this.deps.approvalRuntimeFactory,
|
|
@@ -31291,17 +31314,11 @@ var DefaultSessionApplicationService = class {
|
|
|
31291
31314
|
hookEngine
|
|
31292
31315
|
});
|
|
31293
31316
|
const initialModel = (await new StateCache(this.deps.pathConfig.statePath(sessionId)).read())?.model ?? this.deps.defaultModelProvider();
|
|
31294
|
-
const
|
|
31295
|
-
sessionId,
|
|
31296
|
-
model: initialModel
|
|
31297
|
-
});
|
|
31298
|
-
const compactionConfig = runtimeBundle?.compactionConfig ?? this.deps.compactionConfigProvider?.({
|
|
31317
|
+
const runtimeSlotBundle = await this.deps.runtimeBundleProvider?.({
|
|
31299
31318
|
sessionId,
|
|
31300
31319
|
model: initialModel
|
|
31301
31320
|
});
|
|
31302
|
-
const runtimeSlotBundle = runtimeBundle !== void 0 ? withCompactionConfigFallback(runtimeBundle, compactionConfig) : void 0;
|
|
31303
31321
|
const runtime = runtimeSlotBundle?.runtime ?? this.deps.runtimeProvider();
|
|
31304
|
-
const compactionProvider = runtimeSlotBundle?.compactionProvider ?? this.deps.compactionProviderProvider();
|
|
31305
31322
|
const runtimeSlot = runtimeSlotBundle !== void 0 ? createSessionRuntimeSlot(runtimeSlotBundle) : void 0;
|
|
31306
31323
|
const tools = await this.deps.toolsProvider({
|
|
31307
31324
|
sessionId,
|
|
@@ -31314,8 +31331,6 @@ var DefaultSessionApplicationService = class {
|
|
|
31314
31331
|
runtimeSlot,
|
|
31315
31332
|
tools,
|
|
31316
31333
|
eventBus,
|
|
31317
|
-
compactionProvider,
|
|
31318
|
-
compactionConfig,
|
|
31319
31334
|
approvalRuntime: this.deps.approvalRuntime,
|
|
31320
31335
|
approvalRuntimeFactory: this.deps.approvalRuntimeFactory,
|
|
31321
31336
|
hookEngine,
|
|
@@ -31330,15 +31345,8 @@ var DefaultSessionApplicationService = class {
|
|
|
31330
31345
|
sessionId,
|
|
31331
31346
|
model: managed.contextState.model
|
|
31332
31347
|
});
|
|
31333
|
-
|
|
31334
|
-
|
|
31335
|
-
model: managed.contextState.model
|
|
31336
|
-
});
|
|
31337
|
-
runtimeSlot.replace(withCompactionConfigFallback(next, nextConfig));
|
|
31338
|
-
} else if (runtimeSlot === void 0) managed.soulPlus.getTurnManager().setCompactionConfig(this.deps.compactionConfigProvider?.({
|
|
31339
|
-
sessionId,
|
|
31340
|
-
model: managed.contextState.model
|
|
31341
|
-
}));
|
|
31348
|
+
runtimeSlot.replace(next);
|
|
31349
|
+
}
|
|
31342
31350
|
this.deps.sessionLifecycle?.onSessionCreated?.(managed);
|
|
31343
31351
|
return {
|
|
31344
31352
|
sessionId: managed.sessionId,
|
|
@@ -31408,7 +31416,7 @@ var DefaultSessionApplicationService = class {
|
|
|
31408
31416
|
return this.deps.sessionManager.setSessionTags(sessionId, tags);
|
|
31409
31417
|
}
|
|
31410
31418
|
async compact(sessionId, customInstruction) {
|
|
31411
|
-
|
|
31419
|
+
return this.getManaged(sessionId).sessionControl.compact(customInstruction);
|
|
31412
31420
|
}
|
|
31413
31421
|
async clear(sessionId) {
|
|
31414
31422
|
await this.getManaged(sessionId).sessionControl.clear();
|
|
@@ -31455,30 +31463,23 @@ var DefaultSessionApplicationService = class {
|
|
|
31455
31463
|
}
|
|
31456
31464
|
async setModel(sessionId, model) {
|
|
31457
31465
|
const managed = this.getManaged(sessionId);
|
|
31458
|
-
const compactionConfig = this.deps.compactionConfigProvider?.({
|
|
31459
|
-
sessionId,
|
|
31460
|
-
model
|
|
31461
|
-
});
|
|
31462
31466
|
if (this.deps.runtimeBundleProvider !== void 0) {
|
|
31463
31467
|
const next = await this.deps.runtimeBundleProvider({
|
|
31464
31468
|
sessionId,
|
|
31465
31469
|
model
|
|
31466
31470
|
});
|
|
31467
|
-
managed.runtimeSlot.replace(
|
|
31471
|
+
managed.runtimeSlot.replace(next);
|
|
31468
31472
|
} else if (this.deps.rebuildRuntimeForModel !== void 0) {
|
|
31469
31473
|
await this.deps.rebuildRuntimeForModel(sessionId, model);
|
|
31470
31474
|
managed.runtimeSlot.replace({
|
|
31471
31475
|
model,
|
|
31472
|
-
runtime: this.deps.runtimeProvider()
|
|
31473
|
-
compactionProvider: this.deps.compactionProviderProvider(),
|
|
31474
|
-
compactionConfig
|
|
31476
|
+
runtime: this.deps.runtimeProvider()
|
|
31475
31477
|
});
|
|
31476
31478
|
} else {
|
|
31477
31479
|
const current = managed.runtimeSlot.current();
|
|
31478
31480
|
managed.runtimeSlot.replace({
|
|
31479
31481
|
...current,
|
|
31480
|
-
model
|
|
31481
|
-
compactionConfig
|
|
31482
|
+
model
|
|
31482
31483
|
});
|
|
31483
31484
|
}
|
|
31484
31485
|
await managed.stateCache.update(patchDirtySessionState(sessionId, () => ({ model })));
|
|
@@ -32759,7 +32760,7 @@ function createWireApprovalRuntimeFactory(reverse, runtimesBySession) {
|
|
|
32759
32760
|
};
|
|
32760
32761
|
}
|
|
32761
32762
|
function registerDefaultWireHandlers(deps) {
|
|
32762
|
-
const { router, sessionManager, runtime, tools, eventBus, workspaceDir, defaultModel, approval, pathConfig, backgroundProcessManager, server, hookEngine, approvalStateStore, rebuildRuntimeForModel, hookTimeoutMs, mcpRegistry, authService,
|
|
32763
|
+
const { router, sessionManager, runtime, tools, eventBus, workspaceDir, defaultModel, approval, pathConfig, backgroundProcessManager, server, hookEngine, approvalStateStore, rebuildRuntimeForModel, hookTimeoutMs, mcpRegistry, authService, modelsProvider, configProvider, eventBusProvider, hookEngineProvider } = deps;
|
|
32763
32764
|
const sessionState = new MapWireSessionStateStore();
|
|
32764
32765
|
const reverse = server !== void 0 ? createReverseRpcClient({
|
|
32765
32766
|
server,
|
|
@@ -32776,7 +32777,6 @@ function registerDefaultWireHandlers(deps) {
|
|
|
32776
32777
|
...deps.enabledToolNames !== void 0 || deps.enabledToolNamesProvider !== void 0 ? { enabledToolNamesProvider: async () => deps.enabledToolNamesProvider !== void 0 ? deps.enabledToolNamesProvider() : deps.enabledToolNames } : {},
|
|
32777
32778
|
defaultModelProvider: () => deps.defaultModelProvider?.() ?? defaultModel,
|
|
32778
32779
|
...deps.defaultSystemPromptProvider !== void 0 ? { defaultSystemPromptProvider: deps.defaultSystemPromptProvider } : {},
|
|
32779
|
-
compactionProviderProvider: () => deps.compactionProviderProvider?.() ?? compactionProvider,
|
|
32780
32780
|
...deps.compactionConfigProvider !== void 0 ? { compactionConfigProvider: deps.compactionConfigProvider } : {},
|
|
32781
32781
|
...deps.runtimeBundleProvider !== void 0 ? { runtimeBundleProvider: deps.runtimeBundleProvider } : {},
|
|
32782
32782
|
eventBusProvider: () => eventBusProvider?.() ?? eventBus,
|
|
@@ -33876,10 +33876,7 @@ var SessionManager = class {
|
|
|
33876
33876
|
const sessionTools = bindSessionTodoStore(options.tools, todoStore);
|
|
33877
33877
|
const runtimeSlot = normalizeSessionRuntimeSlot(options.runtimeSlot, {
|
|
33878
33878
|
model: options.model,
|
|
33879
|
-
runtime: options.runtime
|
|
33880
|
-
compactionProvider: options.compactionProvider,
|
|
33881
|
-
...options.compactionConfig !== void 0 ? { compactionConfig: options.compactionConfig } : {},
|
|
33882
|
-
...options.modelCapabilities !== void 0 ? { modelCapabilities: options.modelCapabilities } : {}
|
|
33879
|
+
runtime: options.runtime
|
|
33883
33880
|
});
|
|
33884
33881
|
const runtimeBundle = runtimeSlot.current();
|
|
33885
33882
|
const mainInitInput = {
|
|
@@ -33893,6 +33890,7 @@ var SessionManager = class {
|
|
|
33893
33890
|
const sessionJournal = new WiredSessionJournalImpl(journalWriter);
|
|
33894
33891
|
let turnManagerRef;
|
|
33895
33892
|
const contextState = new WiredContextState({
|
|
33893
|
+
initializeRecord: mainInitInput,
|
|
33896
33894
|
journalWriter,
|
|
33897
33895
|
initialModel: options.model,
|
|
33898
33896
|
initialSystemPrompt: options.systemPrompt,
|
|
@@ -33922,10 +33920,7 @@ var SessionManager = class {
|
|
|
33922
33920
|
last_exit_code: "dirty",
|
|
33923
33921
|
producer: this.producer
|
|
33924
33922
|
};
|
|
33925
|
-
const approvalRuntime = this.buildApprovalRuntime(sessionId, sessionJournal, stateCache,
|
|
33926
|
-
...options.approvalRuntime !== void 0 ? { approvalRuntime: options.approvalRuntime } : {},
|
|
33927
|
-
...options.approvalRuntimeFactory !== void 0 ? { approvalRuntimeFactory: options.approvalRuntimeFactory } : {}
|
|
33928
|
-
});
|
|
33923
|
+
const approvalRuntime = this.buildApprovalRuntime(sessionId, sessionJournal, stateCache, options);
|
|
33929
33924
|
const soulPlus = new SoulPlus({
|
|
33930
33925
|
sessionId,
|
|
33931
33926
|
contextState,
|
|
@@ -33940,9 +33935,7 @@ var SessionManager = class {
|
|
|
33940
33935
|
onShellDeliver: options.onShellDeliver,
|
|
33941
33936
|
skillManager: options.skillManager,
|
|
33942
33937
|
questionRuntime: options.questionRuntime,
|
|
33943
|
-
compactionConfig:
|
|
33944
|
-
modelCapabilities: runtimeBundle.modelCapabilities,
|
|
33945
|
-
compactionProvider: runtimeBundle.compactionProvider,
|
|
33938
|
+
compactionConfig: options.compactionConfig,
|
|
33946
33939
|
approvalRuntime,
|
|
33947
33940
|
hookEngine: options.hookEngine,
|
|
33948
33941
|
toolExecutionScopeFactory: options.toolExecutionScopeFactory,
|
|
@@ -34045,14 +34038,15 @@ var SessionManager = class {
|
|
|
34045
34038
|
const eventBus = options.eventBus ?? new EventBusCtor();
|
|
34046
34039
|
let turnManagerRef;
|
|
34047
34040
|
const contextState = new WiredContextState({
|
|
34041
|
+
initializeRecord: replayResult.sessionInitialized,
|
|
34048
34042
|
journalWriter,
|
|
34049
34043
|
initialModel: projected.model,
|
|
34050
34044
|
initialSystemPrompt: projected.systemPrompt,
|
|
34051
|
-
|
|
34045
|
+
initialActiveTools: projected.activeTools,
|
|
34052
34046
|
currentTurnId: () => turnManagerRef?.getCurrentTurnId() ?? "no_turn",
|
|
34053
34047
|
initialHistory: projected.messages,
|
|
34054
34048
|
initialTokenCount: projected.tokenCount,
|
|
34055
|
-
|
|
34049
|
+
initialThinkingLevel: projected.thinkingLevel
|
|
34056
34050
|
});
|
|
34057
34051
|
contextStateRef = contextState;
|
|
34058
34052
|
await repairJournal({
|
|
@@ -34066,10 +34060,7 @@ var SessionManager = class {
|
|
|
34066
34060
|
const sessionTools = bindSessionTodoStore(options.tools, todoStore);
|
|
34067
34061
|
const runtimeSlot = normalizeSessionRuntimeSlot(options.runtimeSlot, {
|
|
34068
34062
|
model: projected.model,
|
|
34069
|
-
runtime: options.runtime
|
|
34070
|
-
compactionProvider: options.compactionProvider,
|
|
34071
|
-
compactionConfig: options.compactionConfig,
|
|
34072
|
-
...options.modelCapabilities !== void 0 ? { modelCapabilities: options.modelCapabilities } : {}
|
|
34063
|
+
runtime: options.runtime
|
|
34073
34064
|
});
|
|
34074
34065
|
const runtimeBundle = runtimeSlot.current();
|
|
34075
34066
|
await stateCache.write({
|
|
@@ -34110,24 +34101,21 @@ var SessionManager = class {
|
|
|
34110
34101
|
runtime: runtimeBundle.runtime,
|
|
34111
34102
|
eventBus,
|
|
34112
34103
|
tools: sessionTools,
|
|
34113
|
-
|
|
34104
|
+
enabledToolNames: options.enabledToolNames,
|
|
34114
34105
|
lifecycleStateMachine,
|
|
34115
34106
|
producer: this.producer,
|
|
34116
34107
|
onShellDeliver: options.onShellDeliver,
|
|
34117
34108
|
skillManager: options.skillManager,
|
|
34118
|
-
|
|
34119
|
-
...runtimeBundle.compactionConfig !== void 0 ? { compactionConfig: runtimeBundle.compactionConfig } : {},
|
|
34120
|
-
...runtimeBundle.modelCapabilities !== void 0 ? { modelCapabilities: runtimeBundle.modelCapabilities } : {},
|
|
34121
|
-
compactionProvider: runtimeBundle.compactionProvider,
|
|
34109
|
+
questionRuntime: options.questionRuntime,
|
|
34122
34110
|
approvalRuntime,
|
|
34123
34111
|
hookEngine: options.hookEngine,
|
|
34124
|
-
|
|
34112
|
+
toolExecutionScopeFactory: options.toolExecutionScopeFactory,
|
|
34125
34113
|
sessionRules: options.sessionRules,
|
|
34126
34114
|
permissionMode: effectivePermissionMode,
|
|
34127
34115
|
stateCache,
|
|
34128
34116
|
initialMeta,
|
|
34129
34117
|
pathConfig: this.paths,
|
|
34130
|
-
|
|
34118
|
+
approvalStateStore: options.approvalStateStore,
|
|
34131
34119
|
...options.agentTypeRegistry !== void 0 && subagentStore !== void 0 ? {
|
|
34132
34120
|
subagentStore,
|
|
34133
34121
|
agentTypeRegistry: options.agentTypeRegistry,
|
|
@@ -42206,26 +42194,26 @@ function buildInlinePrompt(content, args) {
|
|
|
42206
42194
|
* failures into {@link MCPConfigError} for a consistent error surface
|
|
42207
42195
|
* with the Python runtime.
|
|
42208
42196
|
*
|
|
42209
|
-
* The zod schemas are declared as non-exported
|
|
42197
|
+
* The zod schemas are declared as non-exported `...Schema`
|
|
42210
42198
|
* constants and re-exported as `z.ZodType<TsInterface>` values. This
|
|
42211
42199
|
* is the same idiom `storage/wire-record.ts` uses to keep
|
|
42212
42200
|
* `isolatedDeclarations` happy — without it every exported schema
|
|
42213
42201
|
* would need a gigantic generated zod type annotation.
|
|
42214
42202
|
*/
|
|
42215
|
-
const
|
|
42203
|
+
const StdioServerConfigSchema = z.object({
|
|
42216
42204
|
command: z.string().min(1, "stdio server \"command\" must be a non-empty string"),
|
|
42217
42205
|
args: z.array(z.string()).optional(),
|
|
42218
42206
|
env: z.record(z.string(), z.string()).optional(),
|
|
42219
42207
|
cwd: z.string().optional()
|
|
42220
42208
|
}).strict();
|
|
42221
|
-
const
|
|
42209
|
+
const HttpServerConfigSchema = z.object({
|
|
42222
42210
|
url: z.string().url("http server \"url\" must be a valid URL"),
|
|
42223
42211
|
transport: z.union([z.literal("http"), z.literal("sse")]),
|
|
42224
42212
|
headers: z.record(z.string(), z.string()).optional(),
|
|
42225
42213
|
auth: z.literal("oauth").optional()
|
|
42226
42214
|
}).strict();
|
|
42227
|
-
const
|
|
42228
|
-
z.object({ mcpServers: z.record(z.string().min(1),
|
|
42215
|
+
const McpServerConfigSchema = z.union([StdioServerConfigSchema, HttpServerConfigSchema]);
|
|
42216
|
+
z.object({ mcpServers: z.record(z.string().min(1), McpServerConfigSchema) }).strict();
|
|
42229
42217
|
[
|
|
42230
42218
|
"<!doctype html>",
|
|
42231
42219
|
"<html><head><meta charset=\"utf-8\"><title>Authentication complete</title></head>",
|
|
@@ -42241,11 +42229,6 @@ z.object({ mcpServers: z.record(z.string().min(1), _rawMcpServerConfigSchema) })
|
|
|
42241
42229
|
*
|
|
42242
42230
|
* Mirrors the Python `Config` / `LLMProvider` / `LLMModel` structure with
|
|
42243
42231
|
* a simplified shape suitable for the TS rewrite.
|
|
42244
|
-
*
|
|
42245
|
-
* Each exported schema is annotated with `z.ZodType<T>`
|
|
42246
|
-
* so the file compiles under `--isolatedDeclarations`. Interfaces are
|
|
42247
|
-
* hand-declared rather than `z.infer`'d to avoid the circular type reference
|
|
42248
|
-
* that isolatedDeclarations forbids.
|
|
42249
42232
|
*/
|
|
42250
42233
|
const ProviderType = z.enum([
|
|
42251
42234
|
"anthropic",
|
|
@@ -78777,30 +78760,16 @@ function resolveDefaultSoulPlusDefaultModel(options) {
|
|
|
78777
78760
|
if (defaultModel === void 0 || defaultModel.length === 0) return "";
|
|
78778
78761
|
return defaultModel;
|
|
78779
78762
|
}
|
|
78780
|
-
function getDefaultSoulPlusMaxContextSize(options, defaultModel) {
|
|
78781
|
-
return options.kimiConfig?.models?.[defaultModel]?.maxContextSize ?? 2e5;
|
|
78782
|
-
}
|
|
78783
|
-
function getDefaultSoulPlusModelCapabilities(options, defaultModel) {
|
|
78784
|
-
return options.kimiConfig?.models?.[defaultModel]?.capabilities;
|
|
78785
|
-
}
|
|
78786
78763
|
async function createDefaultSoulPlusRuntimeBundle(options) {
|
|
78787
78764
|
const defaultModel = resolveDefaultSoulPlusDefaultModel(options);
|
|
78788
|
-
|
|
78789
|
-
const modelCapabilities = getDefaultSoulPlusModelCapabilities(options, defaultModel);
|
|
78790
|
-
if (options.runtime !== void 0 && options.compactionProvider !== void 0) return {
|
|
78765
|
+
if (options.runtime !== void 0) return {
|
|
78791
78766
|
runtime: options.runtime,
|
|
78792
|
-
|
|
78793
|
-
defaultModel,
|
|
78794
|
-
maxContextSize,
|
|
78795
|
-
...modelCapabilities !== void 0 ? { modelCapabilities } : {}
|
|
78767
|
+
defaultModel
|
|
78796
78768
|
};
|
|
78797
|
-
if (options.runtime !== void 0
|
|
78769
|
+
if (options.runtime !== void 0) throw new Error("createDefaultSoulPlusWireClient: runtime and compactionProvider must be provided together");
|
|
78798
78770
|
if (defaultModel.length === 0) return {
|
|
78799
78771
|
runtime: createRuntime({ kosong: new UnconfiguredKosongAdapter() }),
|
|
78800
|
-
|
|
78801
|
-
defaultModel,
|
|
78802
|
-
maxContextSize,
|
|
78803
|
-
...modelCapabilities !== void 0 ? { modelCapabilities } : {}
|
|
78772
|
+
defaultModel
|
|
78804
78773
|
};
|
|
78805
78774
|
if (options.kimiConfig === void 0) throw new Error("createDefaultSoulPlusWireClient: provide either runtime+compactionProvider or kimiConfig");
|
|
78806
78775
|
const provider = await createProviderFromConfig(options.kimiConfig, defaultModel, {
|
|
@@ -78814,10 +78783,7 @@ async function createDefaultSoulPlusRuntimeBundle(options) {
|
|
|
78814
78783
|
provider,
|
|
78815
78784
|
tokenRefresher: options.tokenRefresher
|
|
78816
78785
|
}) }),
|
|
78817
|
-
compactionProvider: createKosongCompactionProvider(provider),
|
|
78818
78786
|
defaultModel,
|
|
78819
|
-
maxContextSize,
|
|
78820
|
-
...modelCapabilities !== void 0 ? { modelCapabilities } : {},
|
|
78821
78787
|
videoUploader
|
|
78822
78788
|
};
|
|
78823
78789
|
}
|
|
@@ -78827,11 +78793,6 @@ var UnconfiguredKosongAdapter = class {
|
|
|
78827
78793
|
throw new LLMNotSetError(LLM_NOT_CONFIGURED_MESSAGE);
|
|
78828
78794
|
}
|
|
78829
78795
|
};
|
|
78830
|
-
var UnconfiguredCompactionProvider = class {
|
|
78831
|
-
async run() {
|
|
78832
|
-
throw new LLMNotSetError(LLM_NOT_CONFIGURED_MESSAGE);
|
|
78833
|
-
}
|
|
78834
|
-
};
|
|
78835
78796
|
//#endregion
|
|
78836
78797
|
//#region ../../packages/kaos/src/errors.ts
|
|
78837
78798
|
/**
|
|
@@ -95170,7 +95131,6 @@ async function startCoreWireServer(options) {
|
|
|
95170
95131
|
sessionManager,
|
|
95171
95132
|
router,
|
|
95172
95133
|
runtime: options.runtime,
|
|
95173
|
-
compactionProvider: options.compactionProvider,
|
|
95174
95134
|
kosong: options.runtime.kosong,
|
|
95175
95135
|
tools: options.tools ?? [],
|
|
95176
95136
|
...options.toolsProvider !== void 0 ? { toolsProvider: options.toolsProvider } : {},
|
|
@@ -95188,7 +95148,6 @@ async function startCoreWireServer(options) {
|
|
|
95188
95148
|
defaultModel: options.defaultModel,
|
|
95189
95149
|
runtimeProvider: options.runtimeProvider,
|
|
95190
95150
|
...options.defaultModelProvider !== void 0 ? { defaultModelProvider: options.defaultModelProvider } : {},
|
|
95191
|
-
...options.compactionProviderProvider !== void 0 ? { compactionProviderProvider: options.compactionProviderProvider } : {},
|
|
95192
95151
|
...options.compactionConfigProvider !== void 0 ? { compactionConfigProvider: options.compactionConfigProvider } : {},
|
|
95193
95152
|
...options.runtimeBundleProvider !== void 0 ? { runtimeBundleProvider: options.runtimeBundleProvider } : {},
|
|
95194
95153
|
...options.rebuildRuntimeForModel !== void 0 ? { rebuildRuntimeForModel: options.rebuildRuntimeForModel } : {},
|
|
@@ -95276,8 +95235,6 @@ async function createInProcessWireClient(options) {
|
|
|
95276
95235
|
}
|
|
95277
95236
|
//#endregion
|
|
95278
95237
|
//#region ../../packages/kimi-sdk/src/default-soul-plus-wire-client.ts
|
|
95279
|
-
const DEFAULT_RESERVED_CONTEXT_SIZE = 5e4;
|
|
95280
|
-
const DEFAULT_RESERVED_CONTEXT_FRACTION = .25;
|
|
95281
95238
|
async function createDefaultSoulPlusWireClient(options) {
|
|
95282
95239
|
const pathConfig = options.pathConfig ?? new PathConfig();
|
|
95283
95240
|
const configPath = options.configPath ?? join(pathConfig.home, "config.toml");
|
|
@@ -95301,10 +95258,6 @@ async function createDefaultSoulPlusWireClient(options) {
|
|
|
95301
95258
|
let authService;
|
|
95302
95259
|
let activeVideoUploader;
|
|
95303
95260
|
let activeDefaultModel = defaultModel;
|
|
95304
|
-
let activeMaxContextSize = getDefaultSoulPlusMaxContextSize({
|
|
95305
|
-
kimiConfig: effectiveConfig,
|
|
95306
|
-
defaultModel
|
|
95307
|
-
}, defaultModel);
|
|
95308
95261
|
const backgroundManager = new BackgroundProcessManager();
|
|
95309
95262
|
let defaultsPromise;
|
|
95310
95263
|
const builtinByModel = /* @__PURE__ */ new Map();
|
|
@@ -95352,10 +95305,7 @@ async function createDefaultSoulPlusWireClient(options) {
|
|
|
95352
95305
|
activeVideoUploader = next.videoUploader;
|
|
95353
95306
|
return {
|
|
95354
95307
|
model: next.defaultModel,
|
|
95355
|
-
runtime: next.runtime
|
|
95356
|
-
compactionProvider: next.compactionProvider,
|
|
95357
|
-
compactionConfig: buildCompactionConfig(effectiveConfig, next.defaultModel, next.maxContextSize),
|
|
95358
|
-
...next.modelCapabilities !== void 0 ? { modelCapabilities: next.modelCapabilities } : {}
|
|
95308
|
+
runtime: next.runtime
|
|
95359
95309
|
};
|
|
95360
95310
|
};
|
|
95361
95311
|
const reloadConfigFromDisk = async () => {
|
|
@@ -95365,10 +95315,6 @@ async function createDefaultSoulPlusWireClient(options) {
|
|
|
95365
95315
|
defaultModel = resolved.defaultModel;
|
|
95366
95316
|
activeDefaultModel = defaultModel;
|
|
95367
95317
|
builtinByModel.clear();
|
|
95368
|
-
activeMaxContextSize = getDefaultSoulPlusMaxContextSize({
|
|
95369
|
-
kimiConfig: effectiveConfig,
|
|
95370
|
-
defaultModel
|
|
95371
|
-
}, defaultModel);
|
|
95372
95318
|
};
|
|
95373
95319
|
authService = createDefaultSoulPlusOAuthService({
|
|
95374
95320
|
kimiConfig: effectiveConfig,
|
|
@@ -95378,15 +95324,14 @@ async function createDefaultSoulPlusWireClient(options) {
|
|
|
95378
95324
|
forceManagedKimiCodeOAuth: defaultModel.length === 0,
|
|
95379
95325
|
onConfigProvisioned: reloadConfigFromDisk
|
|
95380
95326
|
});
|
|
95381
|
-
const fallbackRuntimeBundle = await createDefaultSoulPlusRuntimeBundle({
|
|
95382
|
-
defaultModel: "",
|
|
95383
|
-
kimiConfig: effectiveConfig
|
|
95384
|
-
});
|
|
95385
95327
|
const handle = await createInProcessWireClient({
|
|
95386
95328
|
pathConfig,
|
|
95387
|
-
runtime:
|
|
95388
|
-
|
|
95329
|
+
runtime: (await createDefaultSoulPlusRuntimeBundle({
|
|
95330
|
+
defaultModel: "",
|
|
95331
|
+
kimiConfig: effectiveConfig
|
|
95332
|
+
})).runtime,
|
|
95389
95333
|
runtimeBundleProvider: ({ model }) => buildRuntimeBundle(model),
|
|
95334
|
+
compactionConfigProvider: () => {},
|
|
95390
95335
|
workspaceDir: options.workspaceDir,
|
|
95391
95336
|
defaultModel: activeDefaultModel,
|
|
95392
95337
|
defaultModelProvider: () => activeDefaultModel,
|
|
@@ -95415,9 +95360,6 @@ async function createDefaultSoulPlusWireClient(options) {
|
|
|
95415
95360
|
get defaultModel() {
|
|
95416
95361
|
return activeDefaultModel;
|
|
95417
95362
|
},
|
|
95418
|
-
get maxContextSize() {
|
|
95419
|
-
return activeMaxContextSize;
|
|
95420
|
-
},
|
|
95421
95363
|
get defaultThinking() {
|
|
95422
95364
|
return effectiveConfig.defaultThinking ?? false;
|
|
95423
95365
|
},
|
|
@@ -95441,21 +95383,6 @@ async function createDefaultSoulPlusWireClient(options) {
|
|
|
95441
95383
|
}
|
|
95442
95384
|
};
|
|
95443
95385
|
}
|
|
95444
|
-
function buildCompactionConfig(config, model, maxContextSize) {
|
|
95445
|
-
const loop = config.loopControl;
|
|
95446
|
-
const resolvedMaxContextSize = config.models?.[model] !== void 0 ? getDefaultSoulPlusMaxContextSize({
|
|
95447
|
-
kimiConfig: config,
|
|
95448
|
-
defaultModel: model
|
|
95449
|
-
}, model) : maxContextSize;
|
|
95450
|
-
return {
|
|
95451
|
-
maxContextSize: resolvedMaxContextSize,
|
|
95452
|
-
...loop?.compactionTriggerRatio !== void 0 ? { triggerRatio: loop.compactionTriggerRatio } : {},
|
|
95453
|
-
reservedContextSize: loop?.reservedContextSize ?? defaultReservedContextSize(resolvedMaxContextSize)
|
|
95454
|
-
};
|
|
95455
|
-
}
|
|
95456
|
-
function defaultReservedContextSize(maxContextSize) {
|
|
95457
|
-
return Math.max(0, Math.min(DEFAULT_RESERVED_CONTEXT_SIZE, Math.floor(maxContextSize * DEFAULT_RESERVED_CONTEXT_FRACTION)));
|
|
95458
|
-
}
|
|
95459
95386
|
function inferUserAgent(defaultHeaders) {
|
|
95460
95387
|
return defaultHeaders?.["User-Agent"] ?? "KimiCLI/unknown";
|
|
95461
95388
|
}
|
|
@@ -95605,7 +95532,7 @@ function pinoToLogger(p) {
|
|
|
95605
95532
|
async function createKimiAgent() {
|
|
95606
95533
|
const workDir = process.cwd();
|
|
95607
95534
|
const version = getVersion();
|
|
95608
|
-
const { client, dispose,
|
|
95535
|
+
const { client, dispose, defaultModel, defaultThinking, defaultYolo, defaultPlanMode, availableModels, syncSessionRuntime } = await createDefaultSoulPlusWireClient({
|
|
95609
95536
|
workspaceDir: workDir,
|
|
95610
95537
|
userAgent: `KimiCLI/${version}`,
|
|
95611
95538
|
defaultHeaders: buildKimiDefaultHeaders(version),
|
|
@@ -95621,7 +95548,7 @@ async function createKimiAgent() {
|
|
|
95621
95548
|
planMode: defaultPlanMode
|
|
95622
95549
|
},
|
|
95623
95550
|
availableModels,
|
|
95624
|
-
maxContextSize,
|
|
95551
|
+
maxContextSize: 1e6,
|
|
95625
95552
|
syncSessionRuntime,
|
|
95626
95553
|
dispose
|
|
95627
95554
|
};
|
|
@@ -95854,6 +95781,28 @@ function shellQuote(path) {
|
|
|
95854
95781
|
return `'${path.replace(/'/g, "'\\''")}'`;
|
|
95855
95782
|
}
|
|
95856
95783
|
//#endregion
|
|
95784
|
+
//#region src/tui/commands/parser.ts
|
|
95785
|
+
/**
|
|
95786
|
+
* Slash command input parser.
|
|
95787
|
+
*
|
|
95788
|
+
* Splits a `/<name> [args]` line into the command name + the trimmed
|
|
95789
|
+
* argument tail. Returns null when the input is not a slash command
|
|
95790
|
+
* (no leading `/` or only whitespace after `/`).
|
|
95791
|
+
*/
|
|
95792
|
+
function parseSlashInput(input) {
|
|
95793
|
+
if (!input.startsWith("/")) return null;
|
|
95794
|
+
const trimmed = input.slice(1).trim();
|
|
95795
|
+
if (trimmed.length === 0) return null;
|
|
95796
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
95797
|
+
const name = spaceIdx === -1 ? trimmed : trimmed.slice(0, spaceIdx);
|
|
95798
|
+
const args = spaceIdx === -1 ? "" : trimmed.slice(spaceIdx + 1).trim();
|
|
95799
|
+
if (name.includes("/")) return null;
|
|
95800
|
+
return {
|
|
95801
|
+
name,
|
|
95802
|
+
args
|
|
95803
|
+
};
|
|
95804
|
+
}
|
|
95805
|
+
//#endregion
|
|
95857
95806
|
//#region src/tui/components/media/image-thumbnail.ts
|
|
95858
95807
|
/**
|
|
95859
95808
|
* Transcript-side rendering of a pasted image.
|
|
@@ -95888,8 +95837,10 @@ var ImageThumbnail = class extends Container {
|
|
|
95888
95837
|
}
|
|
95889
95838
|
};
|
|
95890
95839
|
//#endregion
|
|
95840
|
+
//#region src/tui/symbols.ts
|
|
95841
|
+
const STATUS_BULLET = "⏺︎ ";
|
|
95842
|
+
//#endregion
|
|
95891
95843
|
//#region src/tui/components/messages/assistant-message.ts
|
|
95892
|
-
const BULLET$1 = "⏺ ";
|
|
95893
95844
|
const INDENT$1 = " ";
|
|
95894
95845
|
var AssistantMessageComponent = class {
|
|
95895
95846
|
contentContainer;
|
|
@@ -95917,12 +95868,12 @@ var AssistantMessageComponent = class {
|
|
|
95917
95868
|
}
|
|
95918
95869
|
render(width) {
|
|
95919
95870
|
if (this.lastText.trim().length === 0) return [];
|
|
95920
|
-
const prefix = this.showBullet ?
|
|
95921
|
-
const contentWidth = Math.max(1, width - prefix
|
|
95871
|
+
const prefix = this.showBullet ? STATUS_BULLET : INDENT$1;
|
|
95872
|
+
const contentWidth = Math.max(1, width - visibleWidth(prefix));
|
|
95922
95873
|
const contentLines = this.contentContainer.render(contentWidth);
|
|
95923
95874
|
const lines = [""];
|
|
95924
95875
|
for (let i = 0; i < contentLines.length; i++) {
|
|
95925
|
-
const p = i === 0 && this.showBullet ? chalk.hex(this.bulletColor)(
|
|
95876
|
+
const p = i === 0 && this.showBullet ? chalk.hex(this.bulletColor)(STATUS_BULLET) : INDENT$1;
|
|
95926
95877
|
lines.push(p + contentLines[i]);
|
|
95927
95878
|
}
|
|
95928
95879
|
return lines;
|
|
@@ -95961,7 +95912,6 @@ var SkillActivationComponent = class extends Container {
|
|
|
95961
95912
|
};
|
|
95962
95913
|
//#endregion
|
|
95963
95914
|
//#region src/tui/components/messages/thinking.ts
|
|
95964
|
-
const BULLET = "⏺ ";
|
|
95965
95915
|
const INDENT = " ";
|
|
95966
95916
|
const PREVIEW_LINES = 3;
|
|
95967
95917
|
const SPINNER_FRAMES = [
|
|
@@ -96023,7 +95973,7 @@ var ThinkingComponent = class {
|
|
|
96023
95973
|
}
|
|
96024
95974
|
const rendered = [""];
|
|
96025
95975
|
for (let i = 0; i < contentLines.length; i++) {
|
|
96026
|
-
const p = i === 0 && this.showMarker ? chalk.hex(this.color)(
|
|
95976
|
+
const p = i === 0 && this.showMarker ? chalk.hex(this.color)(STATUS_BULLET) : INDENT;
|
|
96027
95977
|
rendered.push(p + contentLines[i]);
|
|
96028
95978
|
}
|
|
96029
95979
|
if (this.expanded || contentLines.length <= PREVIEW_LINES) return rendered;
|
|
@@ -97074,8 +97024,8 @@ var ToolCallComponent = class extends Container {
|
|
|
97074
97024
|
const isFinished = result !== void 0;
|
|
97075
97025
|
const isError = result?.is_error ?? false;
|
|
97076
97026
|
let bullet;
|
|
97077
|
-
if (isFinished) bullet = isError ? chalk.hex(colors.error)("✗ ") : chalk.hex(colors.success)(
|
|
97078
|
-
else bullet = chalk.hex(colors.roleAssistant)(
|
|
97027
|
+
if (isFinished) bullet = isError ? chalk.hex(colors.error)("✗ ") : chalk.hex(colors.success)(STATUS_BULLET);
|
|
97028
|
+
else bullet = chalk.hex(colors.roleAssistant)(STATUS_BULLET);
|
|
97079
97029
|
if (toolCall.name === "ExitPlanMode") {
|
|
97080
97030
|
const label = chalk.hex(colors.primary).bold("Current plan");
|
|
97081
97031
|
if (!isFinished || result === void 0 || result.is_error === true) return label;
|
|
@@ -97509,7 +97459,7 @@ function finalizeTurn(ectx, sendQueued) {
|
|
|
97509
97459
|
streamingPhase: "idle"
|
|
97510
97460
|
});
|
|
97511
97461
|
ectx.resetLivePane();
|
|
97512
|
-
setTimeout(() => sendQueued(next
|
|
97462
|
+
setTimeout(() => sendQueued(next), 0);
|
|
97513
97463
|
return;
|
|
97514
97464
|
}
|
|
97515
97465
|
ectx.setAppState({
|
|
@@ -98075,11 +98025,8 @@ function clearTranscriptAndRedraw(state) {
|
|
|
98075
98025
|
/** Use primary color for slash commands or while plan mode is active. */
|
|
98076
98026
|
function updateEditorBorderHighlight(state, text) {
|
|
98077
98027
|
const trimmed = (text ?? state.editor.getText()).trimStart();
|
|
98078
|
-
|
|
98079
|
-
|
|
98080
|
-
state.editor.borderColor = (s) => chalk.hex(primary)(s);
|
|
98081
|
-
} else state.editor.borderColor = state.editorTheme.borderColor;
|
|
98082
|
-
state.editor.slashHighlightHex = state.colors.primary;
|
|
98028
|
+
const colorToken = state.appState.planMode || trimmed.startsWith("/") ? state.colors.primary : state.colors.border;
|
|
98029
|
+
state.editor.borderColor = (s) => chalk.hex(colorToken)(s);
|
|
98083
98030
|
state.ui.requestRender();
|
|
98084
98031
|
}
|
|
98085
98032
|
/**
|
|
@@ -98095,7 +98042,6 @@ function applyTheme(state, theme, hooks, resolved) {
|
|
|
98095
98042
|
state.resolvedTheme = resolvedTheme;
|
|
98096
98043
|
state.styles = createThemeStyles(state.colors);
|
|
98097
98044
|
state.markdownTheme = createMarkdownTheme(state.colors);
|
|
98098
|
-
state.editorTheme = createEditorTheme(state.colors);
|
|
98099
98045
|
updateEditorBorderHighlight(state);
|
|
98100
98046
|
hooks.syncFooter();
|
|
98101
98047
|
hooks.refreshActivityPane();
|
|
@@ -98417,6 +98363,7 @@ function createAuthCommands(deps = {}) {
|
|
|
98417
98363
|
aliases: [],
|
|
98418
98364
|
description: "Clear OAuth credentials",
|
|
98419
98365
|
mode: "both",
|
|
98366
|
+
availability: "idle-only",
|
|
98420
98367
|
priority: 40,
|
|
98421
98368
|
async execute(_args, _ctx) {
|
|
98422
98369
|
if (deps.client === void 0) return ok$2("OAuth is unavailable: no wire client is attached.");
|
|
@@ -98429,6 +98376,7 @@ function createAuthCommands(deps = {}) {
|
|
|
98429
98376
|
aliases: [],
|
|
98430
98377
|
description: "Start OAuth device code login flow",
|
|
98431
98378
|
mode: "both",
|
|
98379
|
+
availability: "idle-only",
|
|
98432
98380
|
priority: 40,
|
|
98433
98381
|
async execute(_args, ctx) {
|
|
98434
98382
|
if (deps.client === void 0) return ok$2("OAuth is unavailable: no wire client is attached.");
|
|
@@ -98488,6 +98436,7 @@ const shellCommands = [
|
|
|
98488
98436
|
aliases: ["h", "?"],
|
|
98489
98437
|
description: "Show available commands and shortcuts",
|
|
98490
98438
|
mode: "both",
|
|
98439
|
+
availability: "always",
|
|
98491
98440
|
priority: 80,
|
|
98492
98441
|
async execute(_args, _ctx) {
|
|
98493
98442
|
return ok$1("__show_help__");
|
|
@@ -98498,6 +98447,7 @@ const shellCommands = [
|
|
|
98498
98447
|
aliases: [],
|
|
98499
98448
|
description: "Show version information",
|
|
98500
98449
|
mode: "both",
|
|
98450
|
+
availability: "always",
|
|
98501
98451
|
priority: 20,
|
|
98502
98452
|
async execute(_args, ctx) {
|
|
98503
98453
|
return ok$1(`Kimi Code v${ctx.appState.version}`);
|
|
@@ -98521,6 +98471,7 @@ const shellCommands = [
|
|
|
98521
98471
|
aliases: ["resume"],
|
|
98522
98472
|
description: "Browse and resume sessions",
|
|
98523
98473
|
mode: "both",
|
|
98474
|
+
availability: "always",
|
|
98524
98475
|
priority: 80,
|
|
98525
98476
|
async execute(_args, _ctx) {
|
|
98526
98477
|
return ok$1("__show_sessions__");
|
|
@@ -98531,6 +98482,7 @@ const shellCommands = [
|
|
|
98531
98482
|
aliases: ["rename"],
|
|
98532
98483
|
description: "Set or show session title",
|
|
98533
98484
|
mode: "both",
|
|
98485
|
+
availability: "always",
|
|
98534
98486
|
priority: 60,
|
|
98535
98487
|
async execute(args, ctx) {
|
|
98536
98488
|
const trimmed = args.trim();
|
|
@@ -98552,6 +98504,7 @@ const shellCommands = [
|
|
|
98552
98504
|
aliases: ["yes"],
|
|
98553
98505
|
description: "Toggle auto-approve mode",
|
|
98554
98506
|
mode: "both",
|
|
98507
|
+
availability: "always",
|
|
98555
98508
|
priority: 100,
|
|
98556
98509
|
async execute(args, ctx) {
|
|
98557
98510
|
let enabled;
|
|
@@ -98569,6 +98522,7 @@ const shellCommands = [
|
|
|
98569
98522
|
aliases: [],
|
|
98570
98523
|
description: "Toggle plan mode",
|
|
98571
98524
|
mode: "both",
|
|
98525
|
+
availability: (args) => args.trim().toLowerCase() === "clear" ? "idle-only" : "always",
|
|
98572
98526
|
priority: 100,
|
|
98573
98527
|
async execute(args, ctx) {
|
|
98574
98528
|
const subcmd = args.trim().toLowerCase();
|
|
@@ -98597,6 +98551,7 @@ const shellCommands = [
|
|
|
98597
98551
|
aliases: [],
|
|
98598
98552
|
description: "Switch LLM model",
|
|
98599
98553
|
mode: "both",
|
|
98554
|
+
availability: "always",
|
|
98600
98555
|
priority: 100,
|
|
98601
98556
|
async execute(args, ctx) {
|
|
98602
98557
|
const trimmed = args.trim();
|
|
@@ -98610,6 +98565,7 @@ const shellCommands = [
|
|
|
98610
98565
|
aliases: ["status"],
|
|
98611
98566
|
description: "Show session tokens + context window + plan quotas",
|
|
98612
98567
|
mode: "both",
|
|
98568
|
+
availability: "always",
|
|
98613
98569
|
priority: 60,
|
|
98614
98570
|
async execute() {
|
|
98615
98571
|
return ok$1("__show_usage__");
|
|
@@ -98620,6 +98576,7 @@ const shellCommands = [
|
|
|
98620
98576
|
aliases: [],
|
|
98621
98577
|
description: "Set the external editor for Ctrl-G",
|
|
98622
98578
|
mode: "both",
|
|
98579
|
+
availability: "always",
|
|
98623
98580
|
priority: 60,
|
|
98624
98581
|
async execute(args, _ctx) {
|
|
98625
98582
|
const trimmed = args.trim();
|
|
@@ -98632,6 +98589,7 @@ const shellCommands = [
|
|
|
98632
98589
|
aliases: [],
|
|
98633
98590
|
description: "Set the terminal UI theme",
|
|
98634
98591
|
mode: "both",
|
|
98592
|
+
availability: "always",
|
|
98635
98593
|
priority: 60,
|
|
98636
98594
|
async execute(args) {
|
|
98637
98595
|
const trimmed = args.trim();
|
|
@@ -98663,28 +98621,6 @@ const soulCommands = [{
|
|
|
98663
98621
|
}
|
|
98664
98622
|
}];
|
|
98665
98623
|
//#endregion
|
|
98666
|
-
//#region src/tui/commands/parser.ts
|
|
98667
|
-
/**
|
|
98668
|
-
* Slash command input parser.
|
|
98669
|
-
*
|
|
98670
|
-
* Splits a `/<name> [args]` line into the command name + the trimmed
|
|
98671
|
-
* argument tail. Returns null when the input is not a slash command
|
|
98672
|
-
* (no leading `/` or only whitespace after `/`).
|
|
98673
|
-
*/
|
|
98674
|
-
function parseSlashInput(input) {
|
|
98675
|
-
if (!input.startsWith("/")) return null;
|
|
98676
|
-
const trimmed = input.slice(1).trim();
|
|
98677
|
-
if (trimmed.length === 0) return null;
|
|
98678
|
-
const spaceIdx = trimmed.indexOf(" ");
|
|
98679
|
-
const name = spaceIdx === -1 ? trimmed : trimmed.slice(0, spaceIdx);
|
|
98680
|
-
const args = spaceIdx === -1 ? "" : trimmed.slice(spaceIdx + 1).trim();
|
|
98681
|
-
if (name.includes("/")) return null;
|
|
98682
|
-
return {
|
|
98683
|
-
name,
|
|
98684
|
-
args
|
|
98685
|
-
};
|
|
98686
|
-
}
|
|
98687
|
-
//#endregion
|
|
98688
98624
|
//#region src/tui/commands/index.ts
|
|
98689
98625
|
function fuzzyScore(query, target) {
|
|
98690
98626
|
if (query.length === 0) return 1;
|
|
@@ -98782,8 +98718,8 @@ function createDefaultRegistry(authDeps) {
|
|
|
98782
98718
|
/**
|
|
98783
98719
|
* Custom editor extending pi-tui Editor with app-level keybindings.
|
|
98784
98720
|
*/
|
|
98785
|
-
const ANSI_SGR = /\
|
|
98786
|
-
const KITTY_CSI_U = /^\
|
|
98721
|
+
const ANSI_SGR = /\u001B\[[0-9;]*m/g;
|
|
98722
|
+
const KITTY_CSI_U = /^\u001B\[(\d+);(\d+)((?::\d+)*)u$/;
|
|
98787
98723
|
const CAPS_LOCK_BIT = 64;
|
|
98788
98724
|
const CTRL_BIT = 4;
|
|
98789
98725
|
const SHIFT_BIT = 1;
|
|
@@ -98815,7 +98751,7 @@ function normalizeCapsLockedCtrl(data) {
|
|
|
98815
98751
|
if (codepoint < 65 || codepoint > 90) return data;
|
|
98816
98752
|
const loweredCodepoint = codepoint + 32;
|
|
98817
98753
|
const strippedModifier = (modifier & ~CAPS_LOCK_BIT) + 1;
|
|
98818
|
-
return `\
|
|
98754
|
+
return `\u001B[${String(loweredCodepoint)};${String(strippedModifier)}${tail}u`;
|
|
98819
98755
|
}
|
|
98820
98756
|
/** Convert a visible-char index (ANSI-stripped) back to an index into the raw ANSI-bearing string. */
|
|
98821
98757
|
function mapVisibleIdxToRaw(line, visibleIdx) {
|
|
@@ -98859,15 +98795,23 @@ var CustomEditor = class extends Editor {
|
|
|
98859
98795
|
* the next keystroke.
|
|
98860
98796
|
*/
|
|
98861
98797
|
onPasteImage;
|
|
98862
|
-
/**
|
|
98863
|
-
* Hex colour used to highlight a leading `/slash-command` token in
|
|
98864
|
-
* the input. Host sets this on theme change; undefined disables the
|
|
98865
|
-
* highlight entirely.
|
|
98866
|
-
*/
|
|
98867
|
-
slashHighlightHex;
|
|
98868
98798
|
autocompleteVisibleLastRender = false;
|
|
98869
98799
|
hasRenderedOnce = false;
|
|
98870
98800
|
autocompleteViewportRefreshQueued = false;
|
|
98801
|
+
/**
|
|
98802
|
+
* `colors` is the live `ColorPalette` reference — the host mutates it
|
|
98803
|
+
* in place on theme switch (`Object.assign(state.colors, ...)`), so
|
|
98804
|
+
* reading `this.colors.<token>` at render time always sees the
|
|
98805
|
+
* current theme without any setter plumbing. The `EditorTheme` that
|
|
98806
|
+
* pi-tui's `Editor` requires is derived from the same palette, and
|
|
98807
|
+
* `paddingX: 2` reserves the two leading columns where `render()`
|
|
98808
|
+
* paints the terminal-style `> ` prompt — both are implementation
|
|
98809
|
+
* details, not caller knobs.
|
|
98810
|
+
*/
|
|
98811
|
+
constructor(tui, colors) {
|
|
98812
|
+
super(tui, createEditorTheme(colors), { paddingX: 2 });
|
|
98813
|
+
this.colors = colors;
|
|
98814
|
+
}
|
|
98871
98815
|
render(width) {
|
|
98872
98816
|
const lines = super.render(width);
|
|
98873
98817
|
const autocompleteVisible = this.isShowingAutocomplete();
|
|
@@ -98876,14 +98820,19 @@ var CustomEditor = class extends Editor {
|
|
|
98876
98820
|
lines,
|
|
98877
98821
|
firstContentIdx: 1
|
|
98878
98822
|
};
|
|
98879
|
-
const hex = this.slashHighlightHex;
|
|
98880
|
-
if (hex === void 0) return arrangedLines;
|
|
98881
|
-
if (!this.getText().trimStart().startsWith("/")) return arrangedLines;
|
|
98882
98823
|
if (arrangedLines.length < 3) return arrangedLines;
|
|
98883
|
-
|
|
98884
|
-
|
|
98885
|
-
|
|
98886
|
-
|
|
98824
|
+
if (this.getText().trimStart().startsWith("/")) {
|
|
98825
|
+
const original = arrangedLines[firstContentIdx];
|
|
98826
|
+
if (original !== void 0) {
|
|
98827
|
+
const highlighted = highlightFirstSlashToken(original, this.colors.primary);
|
|
98828
|
+
if (highlighted !== void 0) arrangedLines[firstContentIdx] = highlighted;
|
|
98829
|
+
}
|
|
98830
|
+
}
|
|
98831
|
+
const firstContent = arrangedLines[firstContentIdx];
|
|
98832
|
+
if (firstContent !== void 0) {
|
|
98833
|
+
const withPrompt = injectPromptSymbol(firstContent);
|
|
98834
|
+
if (withPrompt !== void 0) arrangedLines[firstContentIdx] = withPrompt;
|
|
98835
|
+
}
|
|
98887
98836
|
return arrangedLines;
|
|
98888
98837
|
}
|
|
98889
98838
|
handleInput(data) {
|
|
@@ -98966,6 +98915,7 @@ function highlightFirstSlashToken(line, hex) {
|
|
|
98966
98915
|
if (ch === " " || ch === " ") break;
|
|
98967
98916
|
endVisible++;
|
|
98968
98917
|
}
|
|
98918
|
+
if (visible.slice(slashIdx, endVisible).slice(1).includes("/")) return void 0;
|
|
98969
98919
|
const rawStart = mapVisibleIdxToRaw(line, slashIdx);
|
|
98970
98920
|
const rawEnd = mapVisibleIdxToRaw(line, endVisible);
|
|
98971
98921
|
const before = line.slice(0, rawStart);
|
|
@@ -98973,6 +98923,21 @@ function highlightFirstSlashToken(line, hex) {
|
|
|
98973
98923
|
const after = line.slice(rawEnd);
|
|
98974
98924
|
return before + chalk.hex(hex).bold(token) + after;
|
|
98975
98925
|
}
|
|
98926
|
+
/**
|
|
98927
|
+
* Overlay a terminal-style `> ` prompt symbol on the first content line.
|
|
98928
|
+
* Relies on the editor being configured with `paddingX >= 2` so the line
|
|
98929
|
+
* starts with at least two literal spaces — those slots are replaced with
|
|
98930
|
+
* the prompt token, preserving overall line width and cursor positioning.
|
|
98931
|
+
* Emits no SGR so the terminal's default foreground colour renders the
|
|
98932
|
+
* symbol (white-on-dark / black-on-light, matching the user's typed text).
|
|
98933
|
+
* Returns `undefined` if the line is too short or doesn't begin with the
|
|
98934
|
+
* expected padding.
|
|
98935
|
+
*/
|
|
98936
|
+
function injectPromptSymbol(line) {
|
|
98937
|
+
if (line.length < 2) return void 0;
|
|
98938
|
+
if (line[0] !== " " || line[1] !== " ") return void 0;
|
|
98939
|
+
return "> " + line.slice(2);
|
|
98940
|
+
}
|
|
98976
98941
|
function moveAutocompleteAboveEditor(lines) {
|
|
98977
98942
|
const bottomBorderIdx = findLastEditorBorderIndex(lines);
|
|
98978
98943
|
if (bottomBorderIdx < 1 || bottomBorderIdx >= lines.length - 1) return {
|
|
@@ -99465,7 +99430,6 @@ function createTUIState(options) {
|
|
|
99465
99430
|
const colors = { ...getColorPalette(resolvedTheme) };
|
|
99466
99431
|
const styles = createThemeStyles(colors);
|
|
99467
99432
|
const markdownTheme = createMarkdownTheme(colors);
|
|
99468
|
-
const editorTheme = createEditorTheme(colors);
|
|
99469
99433
|
const terminal = new ProcessTerminal();
|
|
99470
99434
|
const ui = new TUI(terminal);
|
|
99471
99435
|
const transcriptContainer = new Container();
|
|
@@ -99474,8 +99438,7 @@ function createTUIState(options) {
|
|
|
99474
99438
|
const todoPanel = new TodoPanelComponent(colors);
|
|
99475
99439
|
const queueContainer = new Container();
|
|
99476
99440
|
const editorContainer = new Container();
|
|
99477
|
-
const editor = new CustomEditor(ui,
|
|
99478
|
-
editor.slashHighlightHex = colors.primary;
|
|
99441
|
+
const editor = new CustomEditor(ui, colors);
|
|
99479
99442
|
const footer = new FooterComponent({ ...initialAppState }, colors);
|
|
99480
99443
|
const registry = createDefaultRegistry({ client: options.client });
|
|
99481
99444
|
const approvalController = new ApprovalController();
|
|
@@ -99498,7 +99461,6 @@ function createTUIState(options) {
|
|
|
99498
99461
|
colors,
|
|
99499
99462
|
styles,
|
|
99500
99463
|
markdownTheme,
|
|
99501
|
-
editorTheme,
|
|
99502
99464
|
resolvedTheme,
|
|
99503
99465
|
appState: { ...initialAppState },
|
|
99504
99466
|
startupState: "pending",
|
|
@@ -99663,27 +99625,33 @@ function addTranscriptEntry(state, entry) {
|
|
|
99663
99625
|
}
|
|
99664
99626
|
//#endregion
|
|
99665
99627
|
//#region src/tui/actions/queue-ops.ts
|
|
99666
|
-
function
|
|
99628
|
+
function nextQueueId(state) {
|
|
99667
99629
|
state.queueIdCounter += 1;
|
|
99630
|
+
return `q-${String(state.queueIdCounter)}`;
|
|
99631
|
+
}
|
|
99632
|
+
function enqueueMessage(state, text) {
|
|
99668
99633
|
state.queuedMessages.push({
|
|
99669
|
-
id:
|
|
99634
|
+
id: nextQueueId(state),
|
|
99635
|
+
kind: "message",
|
|
99670
99636
|
text
|
|
99671
99637
|
});
|
|
99672
99638
|
}
|
|
99639
|
+
function queuedMessageText(item) {
|
|
99640
|
+
if (item.kind === "message") return item.text;
|
|
99641
|
+
const args = item.skillArgs.trim();
|
|
99642
|
+
return args.length > 0 ? `/${item.skillName} ${args}` : `/${item.skillName}`;
|
|
99643
|
+
}
|
|
99673
99644
|
function recallLastQueued(state) {
|
|
99674
99645
|
if (state.queuedMessages.length === 0) return void 0;
|
|
99675
99646
|
const last = state.queuedMessages.at(-1);
|
|
99676
99647
|
state.queuedMessages = state.queuedMessages.slice(0, -1);
|
|
99677
|
-
return last
|
|
99648
|
+
return queuedMessageText(last);
|
|
99678
99649
|
}
|
|
99679
99650
|
function dequeueFirst(state) {
|
|
99680
99651
|
if (state.queuedMessages.length === 0) return void 0;
|
|
99681
99652
|
const first = state.queuedMessages[0];
|
|
99682
99653
|
state.queuedMessages = state.queuedMessages.slice(1);
|
|
99683
|
-
return first
|
|
99684
|
-
}
|
|
99685
|
-
function clearQueue(state) {
|
|
99686
|
-
state.queuedMessages.length = 0;
|
|
99654
|
+
return first;
|
|
99687
99655
|
}
|
|
99688
99656
|
//#endregion
|
|
99689
99657
|
//#region src/tui/actions/wire-ops.ts
|
|
@@ -99861,10 +99829,13 @@ function handleUserInput(state, text, hooks, onSlash) {
|
|
|
99861
99829
|
return;
|
|
99862
99830
|
}
|
|
99863
99831
|
persistInputHistory(state, text);
|
|
99864
|
-
if (text
|
|
99832
|
+
if (parseSlashInput(text) !== null) {
|
|
99865
99833
|
onSlash(text);
|
|
99866
99834
|
return;
|
|
99867
99835
|
}
|
|
99836
|
+
sendNormalUserInput(state, text, hooks);
|
|
99837
|
+
}
|
|
99838
|
+
function sendNormalUserInput(state, text, hooks) {
|
|
99868
99839
|
const extraction = extractImageAttachments(text, state.imageStore);
|
|
99869
99840
|
const addEntry = (e) => addTranscriptEntry(state, e);
|
|
99870
99841
|
if (extraction.hasImages) sendMessage(state, addEntry, text, {
|
|
@@ -100035,7 +100006,7 @@ var AgentGroupComponent = class extends Container {
|
|
|
100035
100006
|
const failed = snapshots.filter((s) => s.phase === "failed").length;
|
|
100036
100007
|
const finished = done + failed;
|
|
100037
100008
|
const allDone = finished === total;
|
|
100038
|
-
const bullet = allDone ? chalk.hex(colors.success)(
|
|
100009
|
+
const bullet = allDone ? chalk.hex(colors.success)(STATUS_BULLET) : chalk.hex(colors.roleAssistant)(STATUS_BULLET);
|
|
100039
100010
|
if (allDone) {
|
|
100040
100011
|
const types = new Set(snapshots.map((s) => s.agentName).filter((n) => n !== void 0));
|
|
100041
100012
|
const headerLabel = types.size === 1 ? `${String(total)} ${[...types][0]} agents finished` : `${String(total)} agents finished`;
|
|
@@ -100494,11 +100465,9 @@ function isRecord$1(value) {
|
|
|
100494
100465
|
function applyContextUsage(patch, value) {
|
|
100495
100466
|
if (!isRecord$1(value)) return;
|
|
100496
100467
|
const used = value["used"];
|
|
100497
|
-
const total = value["total"];
|
|
100498
100468
|
const percent = value["percent"];
|
|
100499
100469
|
if (typeof percent === "number") patch.contextUsage = Number.isFinite(percent) ? percent / 100 : 0;
|
|
100500
100470
|
if (typeof used === "number" && Number.isFinite(used)) patch.contextTokens = used;
|
|
100501
|
-
if (typeof total === "number" && Number.isFinite(total) && total > 0) patch.maxContextTokens = total;
|
|
100502
100471
|
}
|
|
100503
100472
|
function applySessionResumeSnapshot(state, hooks, sessionId, snapshot) {
|
|
100504
100473
|
const patch = { sessionId };
|
|
@@ -100653,8 +100622,8 @@ var CompactionComponent = class extends Container {
|
|
|
100653
100622
|
this.stopBlink();
|
|
100654
100623
|
}
|
|
100655
100624
|
buildHeader() {
|
|
100656
|
-
if (this.done) return `${chalk.hex(this.colors.success)(
|
|
100657
|
-
return `${this.blinkOn ? chalk.hex(this.colors.roleAssistant)(
|
|
100625
|
+
if (this.done) return `${chalk.hex(this.colors.success)(STATUS_BULLET)}${chalk.hex(this.colors.success).bold("Compaction complete")}${this.tokensBefore !== void 0 && this.tokensAfter !== void 0 ? chalk.dim(` (${String(this.tokensBefore)} → ${String(this.tokensAfter)} tokens)`) : ""}`;
|
|
100626
|
+
return `${this.blinkOn ? chalk.hex(this.colors.roleAssistant)(STATUS_BULLET) : " "}${chalk.hex(this.colors.primary).bold("Compacting context...")}`;
|
|
100658
100627
|
}
|
|
100659
100628
|
startBlink() {
|
|
100660
100629
|
this.blinkTimer = setInterval(() => {
|
|
@@ -100861,9 +100830,9 @@ var ReadGroupComponent = class extends Container {
|
|
|
100861
100830
|
buildHeader(total, pending, failed, totalLines) {
|
|
100862
100831
|
const colors = this.colors;
|
|
100863
100832
|
const dim = chalk.dim;
|
|
100864
|
-
if (pending > 0) return `${chalk.hex(colors.roleAssistant)(
|
|
100833
|
+
if (pending > 0) return `${chalk.hex(colors.roleAssistant)(STATUS_BULLET)}${chalk.hex(colors.primary).bold(`Reading ${String(total)} files…`)}`;
|
|
100865
100834
|
if (failed === total) return `${chalk.hex(colors.error)("✗ ")}${chalk.hex(colors.error).bold(`Read ${String(total)} files`)}${chalk.hex(colors.error)(" · failed")}`;
|
|
100866
|
-
return `${chalk.hex(colors.success)(
|
|
100835
|
+
return `${chalk.hex(colors.success)(STATUS_BULLET)}${chalk.hex(colors.primary).bold(`Read ${String(total)} files`)}${dim(` · ${String(totalLines)} ${totalLines === 1 ? "line" : "lines"}`)}${failed > 0 ? chalk.hex(colors.error)(` · ${String(failed)} failed`) : ""}`;
|
|
100867
100836
|
}
|
|
100868
100837
|
buildBodyLine(snap, isLast) {
|
|
100869
100838
|
const colors = this.colors;
|
|
@@ -101215,6 +101184,24 @@ async function applyThemeChoice(state, theme, hooks) {
|
|
|
101215
101184
|
emitStatus(state, `Theme set to "${theme}"${theme === "auto" ? ` (detected: ${resolved})` : ""}.`);
|
|
101216
101185
|
}
|
|
101217
101186
|
//#endregion
|
|
101187
|
+
//#region src/tui/panes/queue-pane.ts
|
|
101188
|
+
/**
|
|
101189
|
+
* Queue pane — renders `state.queuedMessages` in the queue container
|
|
101190
|
+
* above the input. No-op when the queue is empty.
|
|
101191
|
+
*
|
|
101192
|
+
* Extracted from `KimiTUI.updateQueueDisplay`.
|
|
101193
|
+
*/
|
|
101194
|
+
function updateQueueDisplay(state) {
|
|
101195
|
+
state.queueContainer.clear();
|
|
101196
|
+
const queued = state.queuedMessages;
|
|
101197
|
+
if (queued.length === 0) return;
|
|
101198
|
+
const accent = chalk.hex(state.colors.accent);
|
|
101199
|
+
const dim = chalk.hex(state.colors.textDim);
|
|
101200
|
+
for (const item of queued) state.queueContainer.addChild(new Text(accent(` ❯ ${queuedMessageText(item)}`), 0, 0));
|
|
101201
|
+
const hint = state.appState.isCompacting && !state.appState.isStreaming ? " ↑ to edit · will send after compaction" : " ↑ to edit · ctrl-s to steer immediately";
|
|
101202
|
+
state.queueContainer.addChild(new Text(dim(hint), 0, 0));
|
|
101203
|
+
}
|
|
101204
|
+
//#endregion
|
|
101218
101205
|
//#region src/tui/commands/skill-commands.ts
|
|
101219
101206
|
const SKILL_ACTIVATION_SENTINEL_PREFIX = "__activate_skill__:";
|
|
101220
101207
|
async function fetchSkills(client, sessionId) {
|
|
@@ -101237,6 +101224,7 @@ function buildSkillCommand(skill) {
|
|
|
101237
101224
|
aliases: [],
|
|
101238
101225
|
description: skill.description ?? "",
|
|
101239
101226
|
mode: "both",
|
|
101227
|
+
availability: "idle-only",
|
|
101240
101228
|
async execute(args) {
|
|
101241
101229
|
const trimmed = args.trim();
|
|
101242
101230
|
const prompt = trimmed.length > 0 ? `${skill.content}\n\nUser request:\n${trimmed}` : skill.content;
|
|
@@ -101312,18 +101300,24 @@ async function dispatchSlashCommand(input, state, buildCtx, addEntry) {
|
|
|
101312
101300
|
const ctx = buildCtx();
|
|
101313
101301
|
const result = await tryDispatchSkill(state.client, state.appState.sessionId, parsed.name, parsed.args);
|
|
101314
101302
|
if (result.kind === "activate") {
|
|
101315
|
-
ctx.
|
|
101303
|
+
activateSkillIfIdle(state, ctx, addEntry, parsed.name, result.name, result.args, result.prompt);
|
|
101316
101304
|
return true;
|
|
101317
101305
|
}
|
|
101306
|
+
ctx.sendAsMessage(input);
|
|
101307
|
+
refreshQueueIfBusy(state);
|
|
101308
|
+
return true;
|
|
101309
|
+
}
|
|
101310
|
+
const ctx = buildCtx();
|
|
101311
|
+
if (isBusy(state) && resolveAvailability(def, parsed.args) === "idle-only") {
|
|
101318
101312
|
addEntry({
|
|
101319
|
-
id: `slash-${Date.now()}`,
|
|
101313
|
+
id: `slash-blocked-${Date.now()}`,
|
|
101320
101314
|
kind: "status",
|
|
101321
101315
|
renderMode: "plain",
|
|
101322
|
-
content:
|
|
101316
|
+
content: busyMessage(parsed.name, state),
|
|
101317
|
+
color: state.colors.error
|
|
101323
101318
|
});
|
|
101324
101319
|
return true;
|
|
101325
101320
|
}
|
|
101326
|
-
const ctx = buildCtx();
|
|
101327
101321
|
const baseCtx = {
|
|
101328
101322
|
client: ctx.client,
|
|
101329
101323
|
appState: ctx.appState,
|
|
@@ -101396,6 +101390,7 @@ async function dispatchSlashCommand(input, state, buildCtx, addEntry) {
|
|
|
101396
101390
|
if (result.message.startsWith("__send_as_message__:")) {
|
|
101397
101391
|
const msg = result.message.slice(20);
|
|
101398
101392
|
ctx.sendAsMessage(msg);
|
|
101393
|
+
refreshQueueIfBusy(state);
|
|
101399
101394
|
return true;
|
|
101400
101395
|
}
|
|
101401
101396
|
if (result.message.startsWith("__activate_skill__:")) {
|
|
@@ -101413,7 +101408,7 @@ async function dispatchSlashCommand(input, state, buildCtx, addEntry) {
|
|
|
101413
101408
|
});
|
|
101414
101409
|
return true;
|
|
101415
101410
|
}
|
|
101416
|
-
ctx.
|
|
101411
|
+
activateSkillIfIdle(state, ctx, addEntry, parsed.name, payload.name, payload.args, payload.prompt);
|
|
101417
101412
|
return true;
|
|
101418
101413
|
}
|
|
101419
101414
|
addEntry({
|
|
@@ -101427,6 +101422,35 @@ async function dispatchSlashCommand(input, state, buildCtx, addEntry) {
|
|
|
101427
101422
|
}
|
|
101428
101423
|
return true;
|
|
101429
101424
|
}
|
|
101425
|
+
function resolveAvailability(def, args) {
|
|
101426
|
+
const availability = def.availability ?? "idle-only";
|
|
101427
|
+
return typeof availability === "function" ? availability(args) : availability;
|
|
101428
|
+
}
|
|
101429
|
+
function isBusy(state) {
|
|
101430
|
+
return state.appState.isStreaming || state.appState.isCompacting;
|
|
101431
|
+
}
|
|
101432
|
+
function busyMessage(commandName, state) {
|
|
101433
|
+
if (state.appState.isStreaming) return `Cannot /${commandName} while streaming — press Esc or Ctrl-C first.`;
|
|
101434
|
+
return `Cannot /${commandName} while compacting — wait for compaction to finish first.`;
|
|
101435
|
+
}
|
|
101436
|
+
function activateSkillIfIdle(state, ctx, addEntry, commandName, name, args, prompt) {
|
|
101437
|
+
if (isBusy(state)) {
|
|
101438
|
+
addEntry({
|
|
101439
|
+
id: `slash-blocked-${Date.now()}`,
|
|
101440
|
+
kind: "status",
|
|
101441
|
+
renderMode: "plain",
|
|
101442
|
+
content: busyMessage(commandName, state),
|
|
101443
|
+
color: state.colors.error
|
|
101444
|
+
});
|
|
101445
|
+
return;
|
|
101446
|
+
}
|
|
101447
|
+
ctx.activateSkill(name, args, prompt);
|
|
101448
|
+
}
|
|
101449
|
+
function refreshQueueIfBusy(state) {
|
|
101450
|
+
if (!isBusy(state)) return;
|
|
101451
|
+
updateQueueDisplay(state);
|
|
101452
|
+
state.ui.requestRender();
|
|
101453
|
+
}
|
|
101430
101454
|
//#endregion
|
|
101431
101455
|
//#region src/tui/handlers/turn-lifecycle.ts
|
|
101432
101456
|
function handleTurnBegin(ectx, _data) {
|
|
@@ -101707,7 +101731,7 @@ function handleCompactionEnd(ectx, data, sendQueued) {
|
|
|
101707
101731
|
if (ectx.state.queuedMessages.length > 0) {
|
|
101708
101732
|
const [next, ...rest] = ectx.state.queuedMessages;
|
|
101709
101733
|
ectx.state.queuedMessages = rest;
|
|
101710
|
-
setTimeout(() => sendQueued(next
|
|
101734
|
+
setTimeout(() => sendQueued(next), 0);
|
|
101711
101735
|
}
|
|
101712
101736
|
} else ectx.setAppState({ isCompacting: false });
|
|
101713
101737
|
}
|
|
@@ -102539,24 +102563,6 @@ function stopPhaseSpinner(state) {
|
|
|
102539
102563
|
}
|
|
102540
102564
|
}
|
|
102541
102565
|
//#endregion
|
|
102542
|
-
//#region src/tui/panes/queue-pane.ts
|
|
102543
|
-
/**
|
|
102544
|
-
* Queue pane — renders `state.queuedMessages` in the queue container
|
|
102545
|
-
* above the input. No-op when the queue is empty.
|
|
102546
|
-
*
|
|
102547
|
-
* Extracted from `KimiTUI.updateQueueDisplay`.
|
|
102548
|
-
*/
|
|
102549
|
-
function updateQueueDisplay(state) {
|
|
102550
|
-
state.queueContainer.clear();
|
|
102551
|
-
const queued = state.queuedMessages;
|
|
102552
|
-
if (queued.length === 0) return;
|
|
102553
|
-
const accent = chalk.hex(state.colors.accent);
|
|
102554
|
-
const dim = chalk.hex(state.colors.textDim);
|
|
102555
|
-
for (const item of queued) state.queueContainer.addChild(new Text(accent(` ❯ ${item.text}`), 0, 0));
|
|
102556
|
-
const hint = state.appState.isCompacting && !state.appState.isStreaming ? " ↑ to edit · will send after compaction" : " ↑ to edit · ctrl-s to steer immediately";
|
|
102557
|
-
state.queueContainer.addChild(new Text(dim(hint), 0, 0));
|
|
102558
|
-
}
|
|
102559
|
-
//#endregion
|
|
102560
102566
|
//#region src/tui/reverse-rpc/approval/adapter.ts
|
|
102561
102567
|
const DEFAULT_APPROVAL_CHOICES = [
|
|
102562
102568
|
{
|
|
@@ -104280,6 +104286,7 @@ var BottomPinnedLayout = class {
|
|
|
104280
104286
|
render(width) {
|
|
104281
104287
|
const bodyLines = this.body.render(width);
|
|
104282
104288
|
const bottomLines = this.bottom.flatMap((component) => component.render(width));
|
|
104289
|
+
if (bodyLines.length + bottomLines.length < this.terminal.rows) return [...bodyLines, ...bottomLines];
|
|
104283
104290
|
const spacerHeight = Math.max(0, this.terminal.rows - bodyLines.length - bottomLines.length);
|
|
104284
104291
|
return [
|
|
104285
104292
|
...bodyLines,
|
|
@@ -104351,8 +104358,8 @@ function setupEditor(state, cb) {
|
|
|
104351
104358
|
editor.onCtrlS = () => {
|
|
104352
104359
|
if (!state.appState.isStreaming || state.appState.isCompacting) return;
|
|
104353
104360
|
const text = editor.getText().trim();
|
|
104354
|
-
const queuedTexts = state.queuedMessages.map((m) => m.text);
|
|
104355
|
-
|
|
104361
|
+
const queuedTexts = state.queuedMessages.filter((m) => m.kind === "message").map((m) => m.text);
|
|
104362
|
+
state.queuedMessages = state.queuedMessages.filter((m) => m.kind !== "message");
|
|
104356
104363
|
const parts = [];
|
|
104357
104364
|
for (const q of queuedTexts) {
|
|
104358
104365
|
const trimmed = q.trim();
|
|
@@ -104665,8 +104672,12 @@ var KimiTUI = class {
|
|
|
104665
104672
|
}
|
|
104666
104673
|
startWireSubscription() {
|
|
104667
104674
|
const ectx = buildEventCtx(this.state, this.stateHooks, this.streamCallbacks, (entry) => this.addEntry(entry));
|
|
104668
|
-
const sendQueued = (
|
|
104669
|
-
|
|
104675
|
+
const sendQueued = (item) => {
|
|
104676
|
+
if (item.kind === "skill") {
|
|
104677
|
+
sendSkillActivation(this.state, (e) => this.addEntry(e), item.skillName, item.skillArgs, item.fullPrompt);
|
|
104678
|
+
return;
|
|
104679
|
+
}
|
|
104680
|
+
sendMessageInternal(this.state, (e) => this.addEntry(e), item.text);
|
|
104670
104681
|
};
|
|
104671
104682
|
subscribeToWire(this.state, (event) => {
|
|
104672
104683
|
dispatchEvent(event, ectx, sendQueued);
|