@moikapy/lich 0.8.0 → 0.9.0
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/CHANGELOG.md +49 -1
- package/README.md +38 -19
- package/dist/{chunk-QOTECFCN.js → chunk-4N3S6ACI.js} +2 -2
- package/dist/{chunk-EDRUZF22.js → chunk-KOEZQUIX.js} +1207 -512
- package/dist/chunk-KOEZQUIX.js.map +1 -0
- package/dist/{chunk-W6JXZBUE.js → chunk-P2YEHNM4.js} +2 -2
- package/dist/chunk-P2YEHNM4.js.map +1 -0
- package/dist/{chunk-VKEOHUCB.js → chunk-TYRKVBWQ.js} +26 -8
- package/dist/chunk-TYRKVBWQ.js.map +1 -0
- package/dist/cli.js +82 -44
- package/dist/cli.js.map +1 -1
- package/dist/{gateway-WU5G4ODO.js → gateway-OSB7254F.js} +209 -47
- package/dist/gateway-OSB7254F.js.map +1 -0
- package/dist/index.d.ts +105 -60
- package/dist/index.js +12 -5
- package/dist/{store-COOLBAHB.js → store-YYLEB7JG.js} +2 -2
- package/dist/{tui-4BP3TI7J.js → tui-XXIU4W7K.js} +17 -5
- package/dist/tui-XXIU4W7K.js.map +1 -0
- package/docs/architecture/overview.md +2 -2
- package/docs/architecture/tools.md +3 -1
- package/docs/getting-started.md +6 -6
- package/docs/index.md +1 -1
- package/docs/user-guide/cli.md +9 -7
- package/docs/user-guide/games.md +2 -1
- package/docs/user-guide/library.md +1 -1
- package/docs/user-guide/redot.md +2 -2
- package/docs/user-guide/tui.md +2 -2
- package/package.json +1 -1
- package/dist/chunk-EDRUZF22.js.map +0 -1
- package/dist/chunk-VKEOHUCB.js.map +0 -1
- package/dist/chunk-W6JXZBUE.js.map +0 -1
- package/dist/gateway-WU5G4ODO.js.map +0 -1
- package/dist/tui-4BP3TI7J.js.map +0 -1
- /package/dist/{chunk-QOTECFCN.js.map → chunk-4N3S6ACI.js.map} +0 -0
- /package/dist/{store-COOLBAHB.js.map → store-YYLEB7JG.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,12 @@ interface AssistantMessage {
|
|
|
42
42
|
role: "assistant";
|
|
43
43
|
content: string;
|
|
44
44
|
tool_calls?: ToolCall[];
|
|
45
|
+
/**
|
|
46
|
+
* Opaque provider content blocks preserved for round-trip (e.g. Anthropic
|
|
47
|
+
* thinking / redacted_thinking). When present, Anthropic replays these
|
|
48
|
+
* instead of reconstructing text + tool_use from content/tool_calls.
|
|
49
|
+
*/
|
|
50
|
+
provider_content?: readonly Record<string, unknown>[];
|
|
45
51
|
}
|
|
46
52
|
interface ToolMessage {
|
|
47
53
|
role: "tool";
|
|
@@ -83,10 +89,14 @@ interface ProviderConfig {
|
|
|
83
89
|
api_key?: string;
|
|
84
90
|
api_key_env?: string;
|
|
85
91
|
timeout_ms?: number;
|
|
92
|
+
/** Anthropic-only: forward ChatOptions.temperature (default: omit). */
|
|
93
|
+
send_temperature?: boolean;
|
|
86
94
|
/** Ollama-only: request thinking mode (adds think:true to /api/chat). */
|
|
87
95
|
think?: boolean;
|
|
88
96
|
/** Ollama-only: how long the model stays loaded (e.g. "10m"). */
|
|
89
97
|
keep_alive?: string;
|
|
98
|
+
/** Ollama-only: context window size sent as options.num_ctx. */
|
|
99
|
+
num_ctx?: number;
|
|
90
100
|
/** Injectable fetch, mainly for tests. Defaults to global fetch. */
|
|
91
101
|
fetch_fn?: typeof fetch;
|
|
92
102
|
}
|
|
@@ -115,7 +125,7 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
115
125
|
agent_name: z.ZodDefault<z.ZodString>;
|
|
116
126
|
system_prompt: z.ZodOptional<z.ZodString>;
|
|
117
127
|
max_turns: z.ZodDefault<z.ZodNumber>;
|
|
118
|
-
providers: z.ZodArray<z.ZodObject<{
|
|
128
|
+
providers: z.ZodEffects<z.ZodArray<z.ZodObject<{
|
|
119
129
|
kind: z.ZodEnum<["openai_compat", "anthropic", "ollama"]>;
|
|
120
130
|
name: z.ZodString;
|
|
121
131
|
model: z.ZodString;
|
|
@@ -145,7 +155,27 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
145
155
|
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
146
156
|
/** Injectable fetch, mainly for tests; passes through untouched. */
|
|
147
157
|
fetch_fn: z.ZodOptional<z.ZodType<typeof fetch, z.ZodTypeDef, typeof fetch>>;
|
|
148
|
-
}, z.ZodTypeAny, "passthrough">>, "many"
|
|
158
|
+
}, z.ZodTypeAny, "passthrough">>, "many">, z.objectOutputType<{
|
|
159
|
+
kind: z.ZodEnum<["openai_compat", "anthropic", "ollama"]>;
|
|
160
|
+
name: z.ZodString;
|
|
161
|
+
model: z.ZodString;
|
|
162
|
+
base_url: z.ZodOptional<z.ZodString>;
|
|
163
|
+
api_key: z.ZodOptional<z.ZodString>;
|
|
164
|
+
api_key_env: z.ZodOptional<z.ZodString>;
|
|
165
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
166
|
+
/** Injectable fetch, mainly for tests; passes through untouched. */
|
|
167
|
+
fetch_fn: z.ZodOptional<z.ZodType<typeof fetch, z.ZodTypeDef, typeof fetch>>;
|
|
168
|
+
}, z.ZodTypeAny, "passthrough">[], z.objectInputType<{
|
|
169
|
+
kind: z.ZodEnum<["openai_compat", "anthropic", "ollama"]>;
|
|
170
|
+
name: z.ZodString;
|
|
171
|
+
model: z.ZodString;
|
|
172
|
+
base_url: z.ZodOptional<z.ZodString>;
|
|
173
|
+
api_key: z.ZodOptional<z.ZodString>;
|
|
174
|
+
api_key_env: z.ZodOptional<z.ZodString>;
|
|
175
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
176
|
+
/** Injectable fetch, mainly for tests; passes through untouched. */
|
|
177
|
+
fetch_fn: z.ZodOptional<z.ZodType<typeof fetch, z.ZodTypeDef, typeof fetch>>;
|
|
178
|
+
}, z.ZodTypeAny, "passthrough">[]>;
|
|
149
179
|
work_dir: z.ZodOptional<z.ZodString>;
|
|
150
180
|
tools_enabled: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodArray<z.ZodString, "many">]>>;
|
|
151
181
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
@@ -168,13 +198,13 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
168
198
|
tools_enabled: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodArray<z.ZodString, "many">]>>;
|
|
169
199
|
}, "strip", z.ZodTypeAny, {
|
|
170
200
|
tools_enabled: string[] | "all";
|
|
171
|
-
platforms: ("
|
|
201
|
+
platforms: ("telegram" | "discord" | "twitch" | "webhook")[];
|
|
172
202
|
token_envs: Record<string, string>;
|
|
173
203
|
allowed_users: Record<string, string[]>;
|
|
174
204
|
allowed_chats: Record<string, string[]>;
|
|
175
205
|
}, {
|
|
176
206
|
tools_enabled?: string[] | "all" | undefined;
|
|
177
|
-
platforms?: ("
|
|
207
|
+
platforms?: ("telegram" | "discord" | "twitch" | "webhook")[] | undefined;
|
|
178
208
|
token_envs?: Record<string, string> | undefined;
|
|
179
209
|
allowed_users?: Record<string, string[]> | undefined;
|
|
180
210
|
allowed_chats?: Record<string, string[]> | undefined;
|
|
@@ -224,9 +254,9 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
224
254
|
enabled?: boolean | undefined;
|
|
225
255
|
}>>>;
|
|
226
256
|
}, "strip", z.ZodTypeAny, {
|
|
257
|
+
plugins: string[];
|
|
258
|
+
agent_name: string;
|
|
227
259
|
max_turns: number;
|
|
228
|
-
log_level: "debug" | "info" | "warn" | "error";
|
|
229
|
-
theme: string;
|
|
230
260
|
providers: z.objectOutputType<{
|
|
231
261
|
kind: z.ZodEnum<["openai_compat", "anthropic", "ollama"]>;
|
|
232
262
|
name: z.ZodString;
|
|
@@ -238,24 +268,24 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
238
268
|
/** Injectable fetch, mainly for tests; passes through untouched. */
|
|
239
269
|
fetch_fn: z.ZodOptional<z.ZodType<typeof fetch, z.ZodTypeDef, typeof fetch>>;
|
|
240
270
|
}, z.ZodTypeAny, "passthrough">[];
|
|
241
|
-
agent_name: string;
|
|
242
271
|
tools_enabled: string[] | "all";
|
|
243
272
|
context_budget_tokens: number;
|
|
244
273
|
compress_threshold: number;
|
|
245
274
|
terminal_timeout_ms: number;
|
|
246
|
-
|
|
247
|
-
|
|
275
|
+
log_level: "debug" | "info" | "warn" | "error";
|
|
276
|
+
theme: string;
|
|
248
277
|
system_prompt?: string | undefined;
|
|
278
|
+
work_dir?: string | undefined;
|
|
279
|
+
temperature?: number | undefined;
|
|
280
|
+
max_tokens?: number | undefined;
|
|
249
281
|
session_dir?: string | undefined;
|
|
250
282
|
gateway?: {
|
|
251
283
|
tools_enabled: string[] | "all";
|
|
252
|
-
platforms: ("
|
|
284
|
+
platforms: ("telegram" | "discord" | "twitch" | "webhook")[];
|
|
253
285
|
token_envs: Record<string, string>;
|
|
254
286
|
allowed_users: Record<string, string[]>;
|
|
255
287
|
allowed_chats: Record<string, string[]>;
|
|
256
288
|
} | undefined;
|
|
257
|
-
temperature?: number | undefined;
|
|
258
|
-
max_tokens?: number | undefined;
|
|
259
289
|
mcp_servers?: Record<string, {
|
|
260
290
|
enabled: boolean;
|
|
261
291
|
command: string;
|
|
@@ -277,27 +307,27 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
277
307
|
/** Injectable fetch, mainly for tests; passes through untouched. */
|
|
278
308
|
fetch_fn: z.ZodOptional<z.ZodType<typeof fetch, z.ZodTypeDef, typeof fetch>>;
|
|
279
309
|
}, z.ZodTypeAny, "passthrough">[];
|
|
280
|
-
|
|
281
|
-
|
|
310
|
+
plugins?: string[] | undefined;
|
|
311
|
+
agent_name?: string | undefined;
|
|
282
312
|
system_prompt?: string | undefined;
|
|
313
|
+
max_turns?: number | undefined;
|
|
314
|
+
work_dir?: string | undefined;
|
|
315
|
+
tools_enabled?: string[] | "all" | undefined;
|
|
316
|
+
temperature?: number | undefined;
|
|
317
|
+
max_tokens?: number | undefined;
|
|
318
|
+
context_budget_tokens?: number | undefined;
|
|
319
|
+
compress_threshold?: number | undefined;
|
|
283
320
|
session_dir?: string | undefined;
|
|
284
|
-
|
|
285
|
-
theme?: string | undefined;
|
|
321
|
+
terminal_timeout_ms?: number | undefined;
|
|
286
322
|
gateway?: {
|
|
287
323
|
tools_enabled?: string[] | "all" | undefined;
|
|
288
|
-
platforms?: ("
|
|
324
|
+
platforms?: ("telegram" | "discord" | "twitch" | "webhook")[] | undefined;
|
|
289
325
|
token_envs?: Record<string, string> | undefined;
|
|
290
326
|
allowed_users?: Record<string, string[]> | undefined;
|
|
291
327
|
allowed_chats?: Record<string, string[]> | undefined;
|
|
292
328
|
} | undefined;
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
temperature?: number | undefined;
|
|
296
|
-
max_tokens?: number | undefined;
|
|
297
|
-
context_budget_tokens?: number | undefined;
|
|
298
|
-
compress_threshold?: number | undefined;
|
|
299
|
-
terminal_timeout_ms?: number | undefined;
|
|
300
|
-
plugins?: string[] | undefined;
|
|
329
|
+
log_level?: "debug" | "info" | "warn" | "error" | undefined;
|
|
330
|
+
theme?: string | undefined;
|
|
301
331
|
mcp_servers?: Record<string, {
|
|
302
332
|
command: string;
|
|
303
333
|
enabled?: boolean | undefined;
|
|
@@ -311,25 +341,25 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
311
341
|
work_dir: string;
|
|
312
342
|
providers: ProviderConfig[];
|
|
313
343
|
session_dir: string;
|
|
314
|
-
|
|
315
|
-
log_level: "debug" | "info" | "warn" | "error";
|
|
316
|
-
theme: string;
|
|
344
|
+
plugins: string[];
|
|
317
345
|
agent_name: string;
|
|
346
|
+
max_turns: number;
|
|
318
347
|
tools_enabled: string[] | "all";
|
|
319
348
|
context_budget_tokens: number;
|
|
320
349
|
compress_threshold: number;
|
|
321
350
|
terminal_timeout_ms: number;
|
|
322
|
-
|
|
351
|
+
log_level: "debug" | "info" | "warn" | "error";
|
|
352
|
+
theme: string;
|
|
323
353
|
system_prompt?: string | undefined;
|
|
354
|
+
temperature?: number | undefined;
|
|
355
|
+
max_tokens?: number | undefined;
|
|
324
356
|
gateway?: {
|
|
325
357
|
tools_enabled: string[] | "all";
|
|
326
|
-
platforms: ("
|
|
358
|
+
platforms: ("telegram" | "discord" | "twitch" | "webhook")[];
|
|
327
359
|
token_envs: Record<string, string>;
|
|
328
360
|
allowed_users: Record<string, string[]>;
|
|
329
361
|
allowed_chats: Record<string, string[]>;
|
|
330
362
|
} | undefined;
|
|
331
|
-
temperature?: number | undefined;
|
|
332
|
-
max_tokens?: number | undefined;
|
|
333
363
|
mcp_servers?: Record<string, {
|
|
334
364
|
enabled: boolean;
|
|
335
365
|
command: string;
|
|
@@ -351,27 +381,27 @@ declare const agent_config_schema: z.ZodEffects<z.ZodObject<{
|
|
|
351
381
|
/** Injectable fetch, mainly for tests; passes through untouched. */
|
|
352
382
|
fetch_fn: z.ZodOptional<z.ZodType<typeof fetch, z.ZodTypeDef, typeof fetch>>;
|
|
353
383
|
}, z.ZodTypeAny, "passthrough">[];
|
|
354
|
-
|
|
355
|
-
|
|
384
|
+
plugins?: string[] | undefined;
|
|
385
|
+
agent_name?: string | undefined;
|
|
356
386
|
system_prompt?: string | undefined;
|
|
387
|
+
max_turns?: number | undefined;
|
|
388
|
+
work_dir?: string | undefined;
|
|
389
|
+
tools_enabled?: string[] | "all" | undefined;
|
|
390
|
+
temperature?: number | undefined;
|
|
391
|
+
max_tokens?: number | undefined;
|
|
392
|
+
context_budget_tokens?: number | undefined;
|
|
393
|
+
compress_threshold?: number | undefined;
|
|
357
394
|
session_dir?: string | undefined;
|
|
358
|
-
|
|
359
|
-
theme?: string | undefined;
|
|
395
|
+
terminal_timeout_ms?: number | undefined;
|
|
360
396
|
gateway?: {
|
|
361
397
|
tools_enabled?: string[] | "all" | undefined;
|
|
362
|
-
platforms?: ("
|
|
398
|
+
platforms?: ("telegram" | "discord" | "twitch" | "webhook")[] | undefined;
|
|
363
399
|
token_envs?: Record<string, string> | undefined;
|
|
364
400
|
allowed_users?: Record<string, string[]> | undefined;
|
|
365
401
|
allowed_chats?: Record<string, string[]> | undefined;
|
|
366
402
|
} | undefined;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
temperature?: number | undefined;
|
|
370
|
-
max_tokens?: number | undefined;
|
|
371
|
-
context_budget_tokens?: number | undefined;
|
|
372
|
-
compress_threshold?: number | undefined;
|
|
373
|
-
terminal_timeout_ms?: number | undefined;
|
|
374
|
-
plugins?: string[] | undefined;
|
|
403
|
+
log_level?: "debug" | "info" | "warn" | "error" | undefined;
|
|
404
|
+
theme?: string | undefined;
|
|
375
405
|
mcp_servers?: Record<string, {
|
|
376
406
|
command: string;
|
|
377
407
|
enabled?: boolean | undefined;
|
|
@@ -455,8 +485,9 @@ interface HookContext {
|
|
|
455
485
|
work_dir: string;
|
|
456
486
|
/**
|
|
457
487
|
* This plugin's own per-run state sub-map. Every hook invocation receives
|
|
458
|
-
* a ctx exposing only the invoking plugin's bag; the bag is
|
|
459
|
-
*
|
|
488
|
+
* a ctx exposing only the invoking plugin's bag; the bag is scoped per
|
|
489
|
+
* Agent.run via AsyncLocalStorage (and swapped fresh at each run start).
|
|
490
|
+
* Absent only on hand-built contexts outside the runner.
|
|
460
491
|
*/
|
|
461
492
|
state?: Map<string, unknown>;
|
|
462
493
|
}
|
|
@@ -531,6 +562,8 @@ interface SessionHandle {
|
|
|
531
562
|
path: string;
|
|
532
563
|
append(record: SessionRecord): Promise<void>;
|
|
533
564
|
}
|
|
565
|
+
declare function open_session(dir: string, label?: string): Promise<SessionHandle>;
|
|
566
|
+
declare function read_session_messages(file_path: string): Promise<Message[]>;
|
|
534
567
|
|
|
535
568
|
/**
|
|
536
569
|
* Typed event emitter for the agent loop.
|
|
@@ -564,8 +597,10 @@ interface AgentEvents {
|
|
|
564
597
|
compress_start: {
|
|
565
598
|
estimated_tokens: number;
|
|
566
599
|
};
|
|
600
|
+
/** Summarizer usage is optional so the recorder never treats it as an assistant turn. */
|
|
567
601
|
compress_end: {
|
|
568
602
|
summary_chars: number;
|
|
603
|
+
usage?: Usage;
|
|
569
604
|
};
|
|
570
605
|
turn_end: {
|
|
571
606
|
turn: number;
|
|
@@ -594,6 +629,10 @@ declare class AgentEmitter {
|
|
|
594
629
|
clear(): void;
|
|
595
630
|
}
|
|
596
631
|
|
|
632
|
+
interface ChatFn {
|
|
633
|
+
(messages: readonly Message[], tools: readonly ToolDefinition[], options?: ChatOptions): Promise<ChatResult>;
|
|
634
|
+
}
|
|
635
|
+
|
|
597
636
|
/**
|
|
598
637
|
* The Think-Act-Observe agent loop.
|
|
599
638
|
*
|
|
@@ -603,6 +642,17 @@ declare class AgentEmitter {
|
|
|
603
642
|
* loop never imports provider routers or the tool executor directly.
|
|
604
643
|
*/
|
|
605
644
|
|
|
645
|
+
interface ToolRunner {
|
|
646
|
+
execute(name: string, args: Record<string, unknown>, context?: ToolContext): Promise<ToolResult>;
|
|
647
|
+
}
|
|
648
|
+
interface LoopDeps {
|
|
649
|
+
chat: ChatFn;
|
|
650
|
+
tools: ToolRunner;
|
|
651
|
+
definitions: () => ToolDefinition[];
|
|
652
|
+
emitter?: AgentEmitter;
|
|
653
|
+
/** Per-run ToolContext threaded to every tool execution (A6). */
|
|
654
|
+
tool_context?: ToolContext;
|
|
655
|
+
}
|
|
606
656
|
interface LoopParams {
|
|
607
657
|
system_prompt?: string;
|
|
608
658
|
max_turns: number;
|
|
@@ -619,6 +669,7 @@ interface LoopOutcome {
|
|
|
619
669
|
turns_used: number;
|
|
620
670
|
stopped_reason: "final" | "budget" | "aborted";
|
|
621
671
|
}
|
|
672
|
+
declare function run_conversation(deps: LoopDeps, messages: readonly Message[], params: LoopParams): Promise<LoopOutcome>;
|
|
622
673
|
|
|
623
674
|
interface AgentRunOptions {
|
|
624
675
|
input: string;
|
|
@@ -650,6 +701,7 @@ declare class Agent {
|
|
|
650
701
|
mcp?: McpRuntime;
|
|
651
702
|
});
|
|
652
703
|
run(options: AgentRunOptions): Promise<AgentRunResult>;
|
|
704
|
+
private run_body;
|
|
653
705
|
/** Close MCP sessions so stdio children do not keep the event loop alive. */
|
|
654
706
|
close(): void;
|
|
655
707
|
/** tools/list once, before the model sees definitions. Empty allowlists never connect. */
|
|
@@ -697,18 +749,6 @@ declare class ToolExecutor {
|
|
|
697
749
|
/** Register every builtin tool onto a fresh registry (idempotent per registry). */
|
|
698
750
|
declare function register_builtin_tools(registry: ToolRegistry, context?: ToolContext): void;
|
|
699
751
|
|
|
700
|
-
/**
|
|
701
|
-
* HookedToolRunner: wraps the ToolExecutor with plugin hooks.
|
|
702
|
-
*
|
|
703
|
-
* before_tool_call hooks run in registration order and may veto a call (first
|
|
704
|
-
* blocker wins; the wrapped executor is never called). Hook errors are warned
|
|
705
|
-
* and skipped, never fatal. after_tool_call hooks observe the result summary
|
|
706
|
-
* plus the executor's structured ok/error fields. Every hook invocation
|
|
707
|
-
* receives a ctx exposing only its own plugin's state sub-map: the bag is a
|
|
708
|
-
* module-internal WeakMap keyed on the plugin object, swapped fresh at each
|
|
709
|
-
* call_run_start and shared by the lifecycle and per-tool ctx build sites.
|
|
710
|
-
*/
|
|
711
|
-
|
|
712
752
|
/** Structural ToolRunner shape accepted from the wrapped executor. */
|
|
713
753
|
interface WrappedToolRunner {
|
|
714
754
|
execute(name: string, args: Record<string, unknown>, context?: ToolContext): Promise<ToolResult>;
|
|
@@ -722,6 +762,11 @@ declare class HookedToolRunner {
|
|
|
722
762
|
private readonly wrapped;
|
|
723
763
|
private readonly hooked_plugins;
|
|
724
764
|
constructor(wrapped: WrappedToolRunner, plugins: readonly Plugin[]);
|
|
765
|
+
/**
|
|
766
|
+
* Isolate plugin state for one Agent.run so concurrent runs on the same
|
|
767
|
+
* Agent cannot reset each other's bags (M-6).
|
|
768
|
+
*/
|
|
769
|
+
run_scope<T>(fn: () => Promise<T>): Promise<T>;
|
|
725
770
|
/** Run before hooks in order; the first {block: true} verdict wins. */
|
|
726
771
|
private run_before_hooks;
|
|
727
772
|
/** Fire-and-forget in spirit but awaited here so runs settle cleanly. */
|
|
@@ -737,4 +782,4 @@ declare class HookedToolRunner {
|
|
|
737
782
|
|
|
738
783
|
declare const LICH_VERSION: string;
|
|
739
784
|
|
|
740
|
-
export { type AfterToolCallInfo, Agent, type AgentConfig, AgentEmitter, type AgentEvent, type AgentEventHandler, type AgentEvents, type AgentRunOptions, type AgentRunResult, type BeforeToolCallInfo, type BeforeToolCallResult, type ChatOptions, type ChatResult, type HookContext, HookedToolRunner, LICH_VERSION, type LoadedPlugin, type LoopOutcome, type LoopParams, type Message, type Plugin, type PluginHooks, type PluginLoadError, type ProviderConfig, ProviderError, type RunEndInfo, type Tool, type ToolCall, type ToolContext, type ToolDefinition, ToolExecutor, ToolRegistry, type ToolResult, type Usage, catalog_client_entry, create_agent, create_agent_with_plugins, load_plugins, parse_agent_config, plugin_errors_summary, register_builtin_tools, run_agent };
|
|
785
|
+
export { type AfterToolCallInfo, Agent, type AgentConfig, AgentEmitter, type AgentEvent, type AgentEventHandler, type AgentEvents, type AgentRunOptions, type AgentRunResult, type AssistantMessage, type BeforeToolCallInfo, type BeforeToolCallResult, type ChatOptions, type ChatResult, type HookContext, HookedToolRunner, type JsonSchemaObject, LICH_VERSION, type LoadedPlugin, type LoopDeps, type LoopOutcome, type LoopParams, type Message, type Plugin, type PluginHooks, type PluginLoadError, type ProviderConfig, ProviderError, type RunEndInfo, type Tool, type ToolCall, type ToolContext, type ToolDefinition, ToolExecutor, ToolRegistry, type ToolResult, type ToolRunner, type Usage, catalog_client_entry, create_agent, create_agent_with_plugins, load_plugins, open_session, parse_agent_config, plugin_errors_summary, read_session_messages, register_builtin_tools, run_agent, run_conversation };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LICH_VERSION,
|
|
3
3
|
catalog_client_entry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-P2YEHNM4.js";
|
|
5
5
|
import {
|
|
6
6
|
Agent,
|
|
7
7
|
AgentEmitter,
|
|
@@ -15,9 +15,13 @@ import {
|
|
|
15
15
|
parse_agent_config,
|
|
16
16
|
plugin_errors_summary,
|
|
17
17
|
register_builtin_tools,
|
|
18
|
-
run_agent
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
run_agent,
|
|
19
|
+
run_conversation
|
|
20
|
+
} from "./chunk-KOEZQUIX.js";
|
|
21
|
+
import {
|
|
22
|
+
open_session,
|
|
23
|
+
read_session_messages
|
|
24
|
+
} from "./chunk-TYRKVBWQ.js";
|
|
21
25
|
export {
|
|
22
26
|
Agent,
|
|
23
27
|
AgentEmitter,
|
|
@@ -30,9 +34,12 @@ export {
|
|
|
30
34
|
create_agent,
|
|
31
35
|
create_agent_with_plugins,
|
|
32
36
|
load_plugins,
|
|
37
|
+
open_session,
|
|
33
38
|
parse_agent_config,
|
|
34
39
|
plugin_errors_summary,
|
|
40
|
+
read_session_messages,
|
|
35
41
|
register_builtin_tools,
|
|
36
|
-
run_agent
|
|
42
|
+
run_agent,
|
|
43
|
+
run_conversation
|
|
37
44
|
};
|
|
38
45
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fill_template,
|
|
3
3
|
load_theme
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4N3S6ACI.js";
|
|
5
5
|
import {
|
|
6
6
|
LICH_VERSION
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-P2YEHNM4.js";
|
|
8
8
|
import {
|
|
9
9
|
resolve_session_path
|
|
10
10
|
} from "./chunk-PL6MKRKE.js";
|
|
11
11
|
import {
|
|
12
12
|
create_agent_with_plugins,
|
|
13
13
|
logger
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KOEZQUIX.js";
|
|
15
15
|
import {
|
|
16
16
|
open_session,
|
|
17
17
|
read_session_messages,
|
|
18
18
|
truncate_text
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-TYRKVBWQ.js";
|
|
20
20
|
|
|
21
21
|
// src/tui.tsx
|
|
22
22
|
import { render } from "ink";
|
|
@@ -63,6 +63,18 @@ function apply_event(state, event) {
|
|
|
63
63
|
total_tokens: state.usage.total_tokens + event.result.usage.total_tokens
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
|
+
case "compress_end":
|
|
67
|
+
if (event.usage === void 0) {
|
|
68
|
+
return state;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
...state,
|
|
72
|
+
usage: {
|
|
73
|
+
prompt_tokens: state.usage.prompt_tokens + event.usage.prompt_tokens,
|
|
74
|
+
completion_tokens: state.usage.completion_tokens + event.usage.completion_tokens,
|
|
75
|
+
total_tokens: state.usage.total_tokens + event.usage.total_tokens
|
|
76
|
+
}
|
|
77
|
+
};
|
|
66
78
|
case "tool_call_start":
|
|
67
79
|
return { ...state, phase: "tool", active_tool: event.call };
|
|
68
80
|
case "tool_call_end":
|
|
@@ -629,4 +641,4 @@ async function run_tui(config, options = {}) {
|
|
|
629
641
|
export {
|
|
630
642
|
run_tui
|
|
631
643
|
};
|
|
632
|
-
//# sourceMappingURL=tui-
|
|
644
|
+
//# sourceMappingURL=tui-XXIU4W7K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tui.tsx","../src/tui/app.tsx","../src/tui/load_resume.ts","../src/tui/state.ts","../src/tui/message_view.tsx","../src/tui/status_bar.tsx","../src/tui/command_bar.tsx"],"sourcesContent":["/**\n * TUI entry: builds the agent from the parsed config and renders the ink app\n * until exit. The CLI dynamic-imports this module for `lich tui`.\n */\nimport { render } from \"ink\";\nimport { create_agent_with_plugins } from \"./agent/agent.js\";\nimport type { AgentConfig } from \"./agent/config.js\";\nimport type { Message } from \"./providers/types.js\";\nimport { open_session } from \"./session/store.js\";\nimport { TuiApp } from \"./tui/app.js\";\nimport { load_theme } from \"./util/theme.js\";\nimport { logger } from \"./util/log.js\";\n\nexport interface RunTuiOptions {\n readonly initial_history?: readonly Message[];\n readonly resumed_id?: string;\n}\n\nexport async function run_tui(config: AgentConfig, options: RunTuiOptions = {}): Promise<number> {\n const agent = await create_agent_with_plugins(config);\n try {\n const theme = load_theme(config.theme);\n const session = await open_session(config.session_dir, \"tui\").catch((error: unknown) => {\n logger.warn(\"session persistence failed; continuing without transcript\", error);\n return undefined;\n });\n const instance = render(\n <TuiApp\n agent={agent}\n theme={theme}\n session={session}\n initial_history={options.initial_history}\n resumed_id={options.resumed_id}\n />,\n );\n await instance.waitUntilExit();\n return 0;\n } finally {\n agent.close();\n }\n}\n","/**\n * Root ink component for the lich TUI: wires agent events into the UI state\n * machine, drives agent.run with history continuity, and lays out header,\n * transcript, status bar, and the command input row.\n */\nimport { useCallback, useEffect, useRef, useState, type Dispatch, type SetStateAction } from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { Agent, AgentRunResult } from \"../agent/agent.js\";\nimport type { AgentEvent } from \"../agent/events.js\";\nimport type { AgentConfig } from \"../agent/config.js\";\nimport type { Message } from \"../providers/types.js\";\nimport type { SessionHandle } from \"../session/store.js\";\nimport { LICH_VERSION } from \"../index.js\";\nimport type { ThemeSpec } from \"../util/lore.js\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { load_resume_view } from \"./load_resume.js\";\nimport {\n apply_event,\n apply_run_result,\n compress_notice_block,\n error_notice_block,\n help_block,\n HISTORY_CAP,\n INITIAL_UI_STATE,\n model_label_block,\n parse_command,\n tui_banner_text,\n resume_banner_count,\n resume_banner_line,\n resume_missing_args_block,\n run_notice_blocks,\n session_list_block,\n split_history_blocks,\n tool_result_block,\n unknown_command_block,\n usage_notice_block,\n type HistoryBlock,\n type ParsedInput,\n type SessionEntryInfo,\n type UiState,\n} from \"./state.js\";\nimport { MessageView } from \"./message_view.js\";\nimport { StatusBar } from \"./status_bar.js\";\nimport { CommandBar } from \"./command_bar.js\";\n\nconst SESSION_LIST_CAP = 10;\n\ntype SlashInput = Extract<ParsedInput, { kind: \"slash\" }>;\ntype AddBlocks = (added: readonly HistoryBlock[]) => void;\ntype SetUiState = Dispatch<SetStateAction<UiState>>;\ntype SetBlocks = Dispatch<SetStateAction<readonly HistoryBlock[]>>;\ntype SetHistory = (messages: readonly Message[]) => void;\n\ninterface AgentRunControls {\n readonly start_message_run: (text: string) => void;\n readonly set_history: SetHistory;\n}\n\n/** Map one agent event to optional transcript blocks (tool rows, notices). */\nfunction event_blocks(event: AgentEvent, theme: ThemeSpec): readonly HistoryBlock[] {\n if (event.type === \"tool_call_end\") {\n if (event.cancelled === true) {\n return [];\n }\n return [tool_result_block(event.call, event.result.ok === true, event.result.output)];\n }\n if (event.type === \"compress_end\") {\n return [compress_notice_block(event.summary_chars, theme)];\n }\n if (event.type === \"error\") {\n return [error_notice_block(event.error instanceof Error ? event.error.message : String(event.error))];\n }\n return [];\n}\n\n/** One agent turn: subscribe to events, run, unsubscribe in finally. */\nasync function run_agent_turn(\n agent: Agent,\n history: readonly Message[],\n input: string,\n on_event: (event: AgentEvent) => void,\n on_done: (result: AgentRunResult) => void,\n signal: AbortSignal,\n session: SessionHandle | undefined,\n): Promise<void> {\n const stop_listening = agent.events.on(on_event);\n try {\n const result = await agent.run({ input, history, signal, label: \"tui\", session });\n on_done(result);\n } finally {\n stop_listening();\n }\n}\n\n/** Async /sessions listing as a meta block (never throws). */\nasync function sessions_block(config: AgentConfig, theme: ThemeSpec): Promise<HistoryBlock> {\n try {\n const dir_entries = await readdir(config.session_dir, { withFileTypes: true });\n const entries: SessionEntryInfo[] = [];\n for (const entry of dir_entries) {\n if (entry.isFile() === false || entry.name.endsWith(\".jsonl\") === false) {\n continue;\n }\n const info = await stat(`${config.session_dir}/${entry.name}`);\n entries.push({ name: entry.name, size_bytes: info.size, mtime_ms: info.mtimeMs });\n }\n return session_list_block(entries, theme, SESSION_LIST_CAP);\n } catch {\n return { role: \"meta\", lines: [\"· no session files yet\"] };\n }\n}\n\nfunction run_error_text(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Runs one message exchange; owns history continuity and abort wiring. */\nfunction use_agent_run(\n agent: Agent,\n theme: ThemeSpec,\n add_blocks: AddBlocks,\n set_state: SetUiState,\n set_blocks: SetBlocks,\n initial_history: readonly Message[] | undefined,\n session: SessionHandle | undefined,\n): AgentRunControls {\n const history_ref = useRef<readonly Message[]>(initial_history ?? []);\n const controller_ref = useRef<AbortController | undefined>(undefined);\n\n const set_history = useCallback<SetHistory>((messages: readonly Message[]): void => {\n history_ref.current = messages;\n }, []);\n\n const finish_run = useCallback((result: AgentRunResult): void => {\n history_ref.current = result.messages;\n set_state((current) => apply_run_result(current, result));\n add_blocks(run_notice_blocks(result, theme));\n }, [add_blocks, set_state, theme]);\n\n const start_message_run = useCallback(\n (text: string): void => {\n add_blocks([{ role: \"user\", lines: [`${theme.user_label} › ${text}`] }]);\n set_state((current) => ({ ...current, phase: \"thinking\", active_tool: undefined }));\n const controller = new AbortController();\n controller_ref.current = controller;\n const on_event = (event: AgentEvent): void => {\n set_state((current) => apply_event(current, event));\n set_blocks((current) => [...current, ...event_blocks(event, theme)].slice(-HISTORY_CAP));\n };\n void run_agent_turn(agent, history_ref.current, text, on_event, finish_run, controller.signal, session)\n .catch((error: unknown) => {\n add_blocks([error_notice_block(run_error_text(error))]);\n set_state((current) => ({ ...current, phase: \"idle\" }));\n })\n .finally(() => {\n if (controller_ref.current === controller) {\n controller_ref.current = undefined;\n }\n });\n },\n [agent, add_blocks, finish_run, session, set_blocks, set_state, theme],\n );\n\n useEffect(() => () => controller_ref.current?.abort(), []);\n\n return { start_message_run, set_history };\n}\n\n/** Slash-command dispatch: pure client-side actions, never hits the agent. */\nfunction use_slash_commands(\n agent: Agent,\n theme: ThemeSpec,\n add_blocks: AddBlocks,\n set_blocks: SetBlocks,\n set_history: SetHistory,\n set_resume_line: Dispatch<SetStateAction<string | undefined>>,\n begin_resume_load: () => void,\n end_resume_load: () => void,\n total_tokens: number,\n): (parsed: SlashInput) => void {\n const handle = useCallback(\n (parsed: SlashInput): void => {\n if (parsed.name === \"exit\" || parsed.name === \"quit\" || parsed.name === \"q\") {\n process.exit(0);\n return;\n }\n if (parsed.name === \"help\") {\n add_blocks([help_block()]);\n } else if (parsed.name === \"model\") {\n add_blocks([model_label_block(agent.config)]);\n } else if (parsed.name === \"usage\") {\n add_blocks([usage_notice_block(total_tokens)]);\n } else if (parsed.name === \"clear\") {\n set_blocks([]);\n } else if (parsed.name === \"sessions\") {\n void sessions_block(agent.config, theme).then((block) => add_blocks([block]));\n } else if (parsed.name === \"resume\") {\n if (parsed.args.length === 0) {\n add_blocks([resume_missing_args_block()]);\n return;\n }\n begin_resume_load();\n void load_resume_view(agent.config.session_dir, parsed.args, theme)\n .then((result) => {\n if (result.ok === false) {\n add_blocks([result.block]);\n return;\n }\n set_history(result.messages);\n set_blocks(result.blocks);\n set_resume_line(result.banner_line);\n })\n .finally(() => {\n end_resume_load();\n });\n } else {\n add_blocks([unknown_command_block(parsed.name)]);\n }\n },\n [\n agent,\n add_blocks,\n begin_resume_load,\n end_resume_load,\n set_blocks,\n set_history,\n set_resume_line,\n theme,\n total_tokens,\n ],\n );\n return handle;\n}\n\ninterface TuiAppProps {\n readonly agent: Agent;\n readonly theme: ThemeSpec;\n readonly session?: SessionHandle;\n readonly initial_history?: readonly Message[];\n readonly resumed_id?: string;\n}\n\nfunction initial_blocks(history: readonly Message[] | undefined, theme: ThemeSpec): readonly HistoryBlock[] {\n if (history === undefined || history.length === 0) {\n return [];\n }\n return split_history_blocks(history, HISTORY_CAP, theme);\n}\n\nfunction initial_resume_line(\n resumed_id: string | undefined,\n history: readonly Message[] | undefined,\n): string | undefined {\n if (resumed_id === undefined) {\n return undefined;\n }\n return resume_banner_line(resumed_id, resume_banner_count(history));\n}\n\nexport function TuiApp({ agent, theme, session, initial_history, resumed_id }: TuiAppProps): React.JSX.Element {\n const [blocks, set_blocks] = useState<readonly HistoryBlock[]>(() => initial_blocks(initial_history, theme));\n const [state, set_state] = useState(INITIAL_UI_STATE);\n const [resume_line, set_resume_line] = useState<string | undefined>(() =>\n initial_resume_line(resumed_id, initial_history),\n );\n const resume_loading_ref = useRef(false);\n const [resume_loading, set_resume_loading] = useState(false);\n\n const begin_resume_load = useCallback((): void => {\n resume_loading_ref.current = true;\n set_resume_loading(true);\n }, []);\n\n const end_resume_load = useCallback((): void => {\n resume_loading_ref.current = false;\n set_resume_loading(false);\n }, []);\n\n const add_blocks = useCallback<AddBlocks>((added: readonly HistoryBlock[]): void => {\n if (added.length === 0) {\n return;\n }\n set_blocks((current) => [...current, ...added].slice(-HISTORY_CAP));\n }, []);\n\n const { start_message_run, set_history } = use_agent_run(\n agent,\n theme,\n add_blocks,\n set_state,\n set_blocks,\n initial_history,\n session,\n );\n const handle_slash = use_slash_commands(\n agent,\n theme,\n add_blocks,\n set_blocks,\n set_history,\n set_resume_line,\n begin_resume_load,\n end_resume_load,\n state.usage.total_tokens,\n );\n\n const submit = useCallback(\n (text: string): void => {\n if (resume_loading_ref.current === true) {\n return;\n }\n const parsed = parse_command(text);\n if (parsed.kind === \"message\") {\n if (parsed.text.length > 0) {\n start_message_run(parsed.text);\n }\n return;\n }\n handle_slash(parsed);\n },\n [handle_slash, start_message_run],\n );\n\n const provider = agent.config.providers[0];\n const banner = tui_banner_text(theme, LICH_VERSION, provider?.model ?? \"unknown\", provider?.kind ?? \"unknown\");\n return (\n <Box flexDirection=\"column\" minHeight={8}>\n <Text dimColor>{resume_line === undefined ? banner : `${banner}\\n${resume_line}`}</Text>\n <MessageView blocks={blocks} state={state} />\n <StatusBar state={state} model={provider?.model ?? \"unknown\"} theme={theme} />\n <CommandBar busy={state.phase !== \"idle\" || resume_loading} on_submit={submit} />\n </Box>\n );\n}\n","/**\n * Resolve and read a session transcript for the TUI `/resume` command.\n */\nimport path from \"node:path\";\nimport type { Message } from \"../providers/types.js\";\nimport { resolve_session_path } from \"../session/resolve.js\";\nimport { read_session_messages } from \"../session/store.js\";\nimport type { ThemeSpec } from \"../util/lore.js\";\nimport { error_notice_block, resume_session_view, type HistoryBlock } from \"./state.js\";\n\nexport type LoadResumeResult =\n | { ok: true; id: string; messages: readonly Message[]; blocks: readonly HistoryBlock[]; banner_line: string }\n | { ok: false; block: HistoryBlock };\n\nfunction run_error_text(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Load a transcript for `/resume`; returns view state or an error notice. */\nexport async function load_resume_view(\n session_dir: string,\n value: string,\n theme: ThemeSpec,\n): Promise<LoadResumeResult> {\n try {\n const transcript = await resolve_session_path(session_dir, value);\n const messages = await read_session_messages(transcript);\n const id = path.basename(transcript, \".jsonl\");\n const view = resume_session_view(id, messages, theme);\n return { ok: true, id, messages, blocks: view.blocks, banner_line: view.banner_line };\n } catch (error) {\n return { ok: false, block: error_notice_block(run_error_text(error)) };\n }\n}\n","/**\n * Pure state logic for the ink TUI: UI-state transitions from agent events,\n * slash-command parsing, transcript block mapping, and display formatters.\n * No ink/react imports here — this module is unit-tested without a TTY.\n */\nimport type { AgentEvent } from \"../agent/events.js\";\nimport type { AgentRunResult } from \"../agent/agent.js\";\nimport type { AssistantMessage, Message, ToolCall, Usage } from \"../providers/types.js\";\nimport { safe_json_parse, truncate_text } from \"../util/json.js\";\nimport type { ThemeSpec } from \"../util/lore.js\";\nimport { fill_template } from \"../util/theme.js\";\n\nexport type UiPhase = \"idle\" | \"thinking\" | \"tool\";\n\nexport interface UiState {\n readonly phase: UiPhase;\n readonly turns_used: number;\n readonly usage: Usage;\n readonly session_path: string | undefined;\n readonly compress_count: number;\n readonly budget_exhausted: boolean;\n readonly last_error: string | undefined;\n readonly active_tool: ToolCall | undefined;\n}\n\nexport const INITIAL_UI_STATE: UiState = {\n phase: \"idle\",\n turns_used: 0,\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n session_path: undefined,\n compress_count: 0,\n budget_exhausted: false,\n last_error: undefined,\n active_tool: undefined,\n};\n\nexport const HISTORY_CAP = 50;\nconst TOOL_ARGS_PREVIEW_CHARS = 80;\nconst TOOL_OUTPUT_PREVIEW_CHARS = 120;\nconst ERROR_PREVIEW_CHARS = 300;\n\nfunction error_text(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n\n/** Reducer over UiState; one pure mapping per AgentEvent variant. */\nexport function apply_event(state: UiState, event: AgentEvent): UiState {\n switch (event.type) {\n case \"llm_start\":\n return { ...state, phase: \"thinking\", active_tool: undefined };\n case \"llm_end\":\n return {\n ...state,\n usage: {\n prompt_tokens: state.usage.prompt_tokens + event.result.usage.prompt_tokens,\n completion_tokens: state.usage.completion_tokens + event.result.usage.completion_tokens,\n total_tokens: state.usage.total_tokens + event.result.usage.total_tokens,\n },\n };\n case \"compress_end\":\n if (event.usage === undefined) {\n return state;\n }\n return {\n ...state,\n usage: {\n prompt_tokens: state.usage.prompt_tokens + event.usage.prompt_tokens,\n completion_tokens: state.usage.completion_tokens + event.usage.completion_tokens,\n total_tokens: state.usage.total_tokens + event.usage.total_tokens,\n },\n };\n case \"tool_call_start\":\n return { ...state, phase: \"tool\", active_tool: event.call };\n case \"tool_call_end\":\n return {\n ...state,\n phase: \"thinking\",\n active_tool: undefined,\n last_error:\n event.cancelled === true || event.result.ok === true\n ? state.last_error\n : (event.result.error ?? \"tool failed\"),\n };\n case \"turn_end\":\n return { ...state, turns_used: event.turn };\n case \"compress_start\":\n return { ...state, compress_count: state.compress_count + 1 };\n case \"budget_exhausted\":\n return { ...state, budget_exhausted: true };\n case \"error\":\n return { ...state, last_error: error_text(event.error) };\n default:\n return state;\n }\n}\n\n/** Fold an AgentRunResult back into UiState after the run promise resolves. */\nexport function apply_run_result(state: UiState, result: AgentRunResult): UiState {\n return {\n ...state,\n phase: \"idle\",\n turns_used: result.outcome.turns_used,\n session_path: result.session_path ?? state.session_path,\n last_error: result.outcome.stopped_reason === \"aborted\" ? \"run aborted\" : state.last_error,\n };\n}\n\nexport type ParsedInput = { kind: \"slash\"; name: string; args: string } | { kind: \"message\"; text: string };\n\n/** Split trimmed input into slash command vs plain message (empty input = message). */\nexport function parse_command(raw_input: string): ParsedInput {\n const text = raw_input.trim();\n if (text.startsWith(\"/\") === false) {\n return { kind: \"message\", text };\n }\n const body = text.slice(1);\n const space_index = body.indexOf(\" \");\n if (space_index === -1) {\n return { kind: \"slash\", name: body, args: \"\" };\n }\n return { kind: \"slash\", name: body.slice(0, space_index), args: body.slice(space_index + 1).trim() };\n}\n\n/** Dim header: the theme welcome string, the one tagline placement. */\nexport function tui_banner_text(theme: ThemeSpec, version: string, model: string, kind: string): string {\n return fill_template(theme.welcome, { version, model, kind });\n}\n\n/** Count messages shown in the resume banner (matches split_history_blocks visibility). */\nexport function resume_banner_count(messages: readonly Message[] | undefined): number {\n if (messages === undefined) {\n return 0;\n }\n return messages.filter((message) => message.role !== \"system\").length;\n}\n\n/** Second banner line when a session transcript was loaded via `--resume` or `/resume`. */\nexport function resume_banner_line(id: string, message_count: number): string {\n return `resumed ${id} (${message_count} messages)`;\n}\n\n/** 1234567 -> \"1,234,567\" (US grouping, matching the status bar style). */\nexport function format_usage(total_tokens: number): string {\n return total_tokens.toLocaleString(\"en-US\");\n}\n\nexport type BlockRole = \"user\" | \"lich\" | \"tool\" | \"meta\" | \"error\";\n\nexport interface HistoryBlock {\n readonly role: BlockRole;\n readonly lines: readonly string[];\n}\n\nfunction assistant_tool_line(call: ToolCall): string {\n const args_json = JSON.stringify(call.args) ?? \"{}\";\n return ` \\u23bf ${truncate_text(args_json, TOOL_ARGS_PREVIEW_CHARS)}`;\n}\n\nfunction format_message_lines(message: Message, theme: ThemeSpec): string[] {\n if (message.role === \"user\") {\n return [`${theme.user_label} \\u203a ${message.content}`];\n }\n if (message.role === \"assistant\") {\n const lines = [`${theme.response_label} \\u203a ${message.content}`];\n for (const call of message.tool_calls ?? []) {\n lines.push(assistant_tool_line(call));\n }\n return lines;\n }\n if (message.role === \"tool\") {\n const flag = message.is_error === true ? \"error\" : \"ok\";\n return [` \\u23bf ${message.name}: ${flag} (${truncate_text(message.content, TOOL_OUTPUT_PREVIEW_CHARS)})`];\n }\n return [`\\u00b7 system: ${message.content}`];\n}\n\n/** Map one transcript Message to display lines with its role tag. */\nexport function format_message_block(message: Message, theme: ThemeSpec): HistoryBlock {\n if (message.role === \"tool\") {\n const ok = message.is_error !== true;\n return { role: ok === true ? \"tool\" : \"error\", lines: format_message_lines(message, theme) };\n }\n const roles: Record<Exclude<Message[\"role\"], \"tool\">, BlockRole> = {\n system: \"meta\",\n user: \"user\",\n assistant: \"lich\",\n };\n return { role: roles[message.role], lines: format_message_lines(message, theme) };\n}\n\n/** Keep the newest `cap` non-system messages as renderable blocks. */\nexport function split_history_blocks(messages: readonly Message[], cap: number, theme: ThemeSpec): HistoryBlock[] {\n const visible = messages.filter((message) => message.role !== \"system\");\n const start = Math.max(0, visible.length - cap);\n return visible.slice(start).map((message) => format_message_block(message, theme));\n}\n\n/** Meta notice + transcript blocks after a successful in-TUI `/resume`. */\nexport function resume_session_view(\n id: string,\n messages: readonly Message[],\n theme: ThemeSpec,\n cap: number = HISTORY_CAP,\n): { blocks: readonly HistoryBlock[]; banner_line: string } {\n const banner_line = resume_banner_line(id, resume_banner_count(messages));\n const notice: HistoryBlock = { role: \"meta\", lines: [`\\u00b7 ${banner_line}`] };\n const history_cap = Math.max(0, cap - 1);\n return { blocks: [notice, ...split_history_blocks(messages, history_cap, theme)], banner_line };\n}\n\n/** Missing `/resume` argument notice. */\nexport function resume_missing_args_block(): HistoryBlock {\n return { role: \"error\", lines: [\"\\u00b7 /resume requires <id|latest>\"] };\n}\n\nfunction assistant_result_block(message: AssistantMessage, theme: ThemeSpec): HistoryBlock | undefined {\n if (message.content.length === 0) {\n return undefined;\n }\n return { role: \"lich\", lines: [`${theme.response_label} \\u203a ${message.content}`] };\n}\n\n/** Post-run meta blocks: compression notices, budget, errors, final answer. */\nexport function run_notice_blocks(result: AgentRunResult, theme: ThemeSpec): HistoryBlock[] {\n const blocks: HistoryBlock[] = [];\n if (result.outcome.stopped_reason === \"budget\") {\n blocks.push({ role: \"error\", lines: [`\\u00b7 ${fill_template(theme.notices.budget_exhausted, {})}`] });\n }\n const final_block = result.outcome.final === undefined ? undefined : assistant_result_block(result.outcome.final, theme);\n if (final_block !== undefined) {\n blocks.push(final_block);\n }\n return blocks;\n}\n\nfunction truncate_tool_preview(result_content: string, ok: boolean): string {\n return ` \\u23bf ${ok === true ? \"ok\" : \"error\"} (${truncate_text(result_content, TOOL_OUTPUT_PREVIEW_CHARS)})`;\n}\n\n/** One finalized live tool row; falls back to the transcript copy when absent. */\nexport function tool_result_block(call: ToolCall, ok: boolean, result_content: string): HistoryBlock {\n const args_json = JSON.stringify(call.args) ?? \"{}\";\n const lines = [\n `\\u23fa ${call.name}(${truncate_text(args_json, TOOL_ARGS_PREVIEW_CHARS)})`,\n truncate_tool_preview(result_content, ok),\n ];\n return { role: ok === true ? \"tool\" : \"error\", lines };\n}\n\nexport function parse_tool_message_content(content: string): { ok: boolean; output: string } {\n const parsed = safe_json_parse<{ ok?: unknown; output?: unknown }>(content);\n if (parsed !== undefined && typeof parsed.ok === \"boolean\" && typeof parsed.output === \"string\") {\n return { ok: parsed.ok, output: parsed.output };\n }\n return { ok: true, output: content };\n}\n\nexport function compress_notice_block(summary_chars: number, theme: ThemeSpec): HistoryBlock {\n const line = fill_template(theme.notices.compressed, { chars: summary_chars });\n return { role: \"meta\", lines: [`\\u00b7 ${line}`] };\n}\n\nexport function error_notice_block(message: string): HistoryBlock {\n return { role: \"error\", lines: [`\\u00b7 error: ${truncate_text(message, ERROR_PREVIEW_CHARS)}`] };\n}\n\nexport function tool_args_preview(args: Record<string, unknown>): string {\n const args_json = JSON.stringify(args) ?? \"{}\";\n return truncate_text(args_json, TOOL_ARGS_PREVIEW_CHARS);\n}\n\nexport function help_block(): HistoryBlock {\n return { role: \"meta\", lines: [...HELP_LINES] };\n}\n\nexport function model_label_block(config: { providers: readonly { model: string; kind: string }[] }): HistoryBlock {\n const provider = config.providers[0];\n return {\n role: \"meta\",\n lines: [`\\u00b7 model: ${provider?.model ?? \"unknown\"} \\u00b7 provider: ${provider?.kind ?? \"unknown\"}`],\n };\n}\n\nexport function usage_notice_block(total_tokens: number): HistoryBlock {\n return { role: \"meta\", lines: [`\\u00b7 tokens used this session: ${format_usage(total_tokens)}`] };\n}\n\nexport function unknown_command_block(name: string): HistoryBlock {\n return { role: \"error\", lines: [`\\u00b7 unknown command: /${name} (try /help)`] };\n}\n\nexport interface SessionEntryInfo {\n readonly name: string;\n readonly size_bytes: number;\n readonly mtime_ms: number;\n}\n\n/** Newest-first session listing, capped at `cap` entries. */\nexport function session_list_block(entries: readonly SessionEntryInfo[], theme: ThemeSpec, cap: number = 10): HistoryBlock {\n const sorted = [...entries].sort((a, b) => b.mtime_ms - a.mtime_ms).slice(0, cap);\n if (sorted.length === 0) {\n return { role: \"meta\", lines: [\"\\u00b7 no session files yet\"] };\n }\n const label = fill_template(theme.notices.sessions, { count: sorted.length });\n const lines: string[] = [`\\u00b7 ${label}`];\n for (const entry of sorted) {\n lines.push(` ${entry.name} (${format_usage(entry.size_bytes)} bytes)`);\n }\n return { role: \"meta\", lines };\n}\n\nexport const SLASH_COMMAND_NAMES: readonly string[] = [\n \"exit\",\n \"quit\",\n \"q\",\n \"help\",\n \"model\",\n \"usage\",\n \"clear\",\n \"sessions\",\n \"resume\",\n];\n\nexport const HELP_LINES: readonly string[] = [\n \"commands: /help /model /usage /clear /sessions /resume /exit (aliases: /quit /q)\",\n \"enter submits \\u00b7 backspace deletes \\u00b7 up/down recalls history \\u00b7 pasted newlines become spaces\",\n];","/**\n * Transcript rendering: maps HistoryBlock descriptors to ink elements with\n * role-based colors, and shows an animated braille spinner while thinking.\n * Blocks are pre-capped by the app, so a plain flex column is sufficient.\n */\nimport { useEffect, useState } from \"react\";\nimport { Box, Text } from \"ink\";\nimport { tool_args_preview, type HistoryBlock, type UiState } from \"./state.js\";\n\nconst SPINNER_FRAMES: readonly string[] = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_INTERVAL_MS = 80;\n\n/** Braille spinner frames on an 80ms interval; clears on unmount. */\nfunction use_spinner(): string {\n const [frame, set_frame] = useState(SPINNER_FRAMES[0] ?? \"⠋\");\n useEffect(() => {\n const timer = setInterval(() => {\n const next = SPINNER_FRAMES[(SPINNER_FRAMES.indexOf(frame) + 1) % SPINNER_FRAMES.length];\n set_frame(next ?? \"⠋\");\n }, SPINNER_INTERVAL_MS);\n return () => {\n clearInterval(timer);\n };\n }, [frame]);\n return frame;\n}\n\nfunction ThinkingLine(): React.JSX.Element {\n const frame = use_spinner();\n return <Text dimColor>{`${frame} thinking…`}</Text>;\n}\n\nconst ROLE_COLORS: Record<HistoryBlock[\"role\"], string | undefined> = {\n user: \"white\",\n lich: \"green\",\n tool: \"cyan\",\n meta: undefined,\n error: \"red\",\n};\n\nfunction BlockLines({ block }: { block: HistoryBlock }): React.JSX.Element {\n const color = ROLE_COLORS[block.role];\n return (\n <>\n {block.lines.map((line, index) => (\n <Text key={index} color={color} dimColor={color === undefined}>{line}</Text>\n ))}\n </>\n );\n}\n\ninterface MessageViewProps {\n readonly blocks: readonly HistoryBlock[];\n readonly state: UiState;\n}\n\n/** Transcript column plus the live phase line (spinner / running tool row). */\nexport function MessageView({ blocks, state }: MessageViewProps): React.JSX.Element {\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n {blocks.map((block, index) => (\n <Box key={index} flexDirection=\"column\">\n <BlockLines block={block} />\n </Box>\n ))}\n {state.phase === \"thinking\" ? <ThinkingLine /> : null}\n {state.phase === \"tool\" && state.active_tool !== undefined ? (\n <Text color=\"cyan\">{`⏺ ${state.active_tool.name}(${tool_args_preview(state.active_tool.args)})`}</Text>\n ) : null}\n </Box>\n );\n}","/**\n * Bottom status line: model, turns, token totals, phase tag, compression\n * count, and the session path once the agent has persisted a transcript.\n */\nimport { Box, Text } from \"ink\";\nimport type { ThemeSpec } from \"../util/lore.js\";\nimport { format_usage, type UiState } from \"./state.js\";\n\ninterface StatusBarProps {\n readonly state: UiState;\n readonly model: string;\n readonly theme: ThemeSpec;\n}\n\nexport function StatusBar({ state, model, theme }: StatusBarProps): React.JSX.Element {\n const phase = theme.phase_labels[state.phase];\n return (\n <Box>\n <Text dimColor>\n {`model ${model} · turns ${state.turns_used} · tokens ${format_usage(state.usage.total_tokens)} · [${phase}]`}\n {state.compress_count > 0 ? ` · compressed ${state.compress_count}` : \"\"}\n {state.session_path !== undefined ? ` · ${state.session_path}` : \"\"}\n </Text>\n {state.budget_exhausted ? <Text color=\"red\">{` · ${theme.notices.budget_exhausted}`}</Text> : null}\n </Box>\n );\n}","/**\n * Input row: printable characters accumulate in a buffer, Enter submits,\n * Backspace/Delete edits, Up/Down walk a 20-entry recall ring, and pasted\n * newlines collapse to spaces. Ctrl+C is left to ink's default handling.\n */\nimport { useState } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\n\nconst INPUT_HISTORY_CAP = 20;\n\ninterface CommandBarProps {\n readonly busy: boolean;\n readonly on_submit: (text: string) => void;\n}\n\n/** Push onto a capped ring (newest first) without mutating the source. */\nfunction push_history(ring: readonly string[], entry: string): readonly string[] {\n return [entry, ...ring.filter((item) => item !== entry)].slice(0, INPUT_HISTORY_CAP);\n}\n\nexport function CommandBar({ busy, on_submit }: CommandBarProps): React.JSX.Element {\n const [buffer, set_buffer] = useState(\"\");\n const [recall_ring, set_recall_ring] = useState<readonly string[]>([]);\n const [recall_index, set_recall_index] = useState<number | undefined>(undefined);\n\n const submit_buffer = (): void => {\n if (busy === true) {\n return;\n }\n const text = buffer.trim();\n set_buffer(\"\");\n set_recall_index(undefined);\n if (text.length > 0) {\n set_recall_ring((current) => push_history(current, text));\n on_submit(text);\n }\n };\n\n /** Newest-first ring: Up walks toward older (higher index), Down toward newer. */\n const walk_recall = (direction: 1 | -1): void => {\n if (recall_ring.length === 0) {\n return;\n }\n if (direction === -1 && recall_index === 0) {\n set_recall_index(undefined);\n set_buffer(\"\");\n return;\n }\n if (direction === -1 && recall_index === undefined) {\n return;\n }\n const current = recall_index ?? -direction;\n const next = Math.min(Math.max(current + direction, 0), recall_ring.length - 1);\n set_recall_index(next);\n set_buffer(recall_ring[next] ?? \"\");\n };\n\n useInput((input, key) => {\n if (key.return === true) {\n submit_buffer();\n return;\n }\n if (key.upArrow === true) {\n walk_recall(1);\n return;\n }\n if (key.downArrow === true) {\n walk_recall(-1);\n return;\n }\n if (key.backspace === true || key.delete === true) {\n set_buffer((current) => current.slice(0, -1));\n return;\n }\n if (key.ctrl === true || key.escape === true || key.tab === true || key.meta === true) {\n return;\n }\n if (input.length > 0) {\n set_buffer((current) => current + input.replaceAll(\"\\n\", \" \").replaceAll(\"\\r\", \" \"));\n }\n });\n\n return (\n <Box>\n <Text dimColor>{busy ? \" … \" : \"› \"}</Text>\n <Text>{buffer}</Text>\n <Text dimColor>▌</Text>\n </Box>\n );\n}\n"],"mappings":"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","names":["useEffect","useState","Box","Text","Box","Text","jsx","jsxs","Box","Text","useState","Box","Text","jsx","jsxs","jsx","jsxs","run_error_text","useEffect","useState","Box","Text","jsx"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Lich is a small TypeScript AI agent harness: it drives a chat model in a
|
|
4
4
|
think-act-observe loop, lets the model call tools, compresses history when the
|
|
5
5
|
context budget demands it, and persists transcripts. The published npm package
|
|
6
|
-
is 0.
|
|
6
|
+
is 0.8.0, including editor MCP (`mcp_servers`, `lich mcp`). It runs on
|
|
7
7
|
Node >= 20 and on Bun, is ESM with NodeNext resolution, and its runtime
|
|
8
8
|
dependencies are `zod` (config validation), `ink`, and `react` (the TUI).
|
|
9
9
|
Everything else is Node/Bun built-ins.
|
|
@@ -100,7 +100,7 @@ Walkthrough of a single `Agent.run({ input })` call
|
|
|
100
100
|
are connected (`initialize`, `notifications/initialized`, then `tools/list`)
|
|
101
101
|
and registered as `mcp_<server>_<tool>`. An empty `tools_enabled` never
|
|
102
102
|
connects. Disabled servers are skipped. A connect failure logs a warning
|
|
103
|
-
and the run continues. This client
|
|
103
|
+
and the run continues. This client has shipped since 0.7.0 (current package 0.8.0).
|
|
104
104
|
2. **Usage collector attached.** `run()` subscribes a `collect_usage` handler
|
|
105
105
|
on `agent.events`; every `llm_end` event adds the call's token usage into a
|
|
106
106
|
per-run `Usage` total. The subscription is removed in a `finally` block.
|
|
@@ -42,7 +42,9 @@ confinement root), a process environment map (the agent injects
|
|
|
42
42
|
from `Agent.run` so tools cancel on caller abort **or** the executor deadline
|
|
43
43
|
(`tool.timeout_ms`, else
|
|
44
44
|
`DEFAULT_TOOL_TIMEOUT_MS` = 30000). `terminal` sets 300000, `run_tests` sets
|
|
45
|
-
600000, and registered MCP tools set 120000.
|
|
45
|
+
600000, and registered MCP tools set 120000. Note: `LICH_TERMINAL_TIMEOUT_MS`
|
|
46
|
+
is injected from config `terminal_timeout_ms` but the `terminal` tool ignores
|
|
47
|
+
it today — use the tool's `timeout_ms` argument (default 60000).
|
|
46
48
|
|
|
47
49
|
**Parameter schemas.** `parameters` is a `JsonSchemaObject`
|
|
48
50
|
(`src/util/json_schema.ts`) passed through verbatim into provider requests.
|
package/docs/getting-started.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
12
|
npm install -g @moikapy/lich
|
|
13
|
-
lich --version # -> 0.
|
|
13
|
+
lich --version # -> 0.8.0 (reads package.json)
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Choose a configuration path
|
|
@@ -23,11 +23,11 @@ Lich needs exactly one thing before it runs: a model. You can provide it three w
|
|
|
23
23
|
# ollama — no api key needed
|
|
24
24
|
LICH_PROVIDER_KIND=ollama LICH_MODEL=llama3.2 lich "Reply with ok"
|
|
25
25
|
|
|
26
|
-
# openai-compatible (api.openai.com/v1 by default)
|
|
27
|
-
LICH_PROVIDER_KIND=openai_compat LICH_MODEL=gpt-
|
|
26
|
+
# openai-compatible (api.openai.com/v1 by default; use a model id your provider accepts)
|
|
27
|
+
LICH_PROVIDER_KIND=openai_compat LICH_MODEL=gpt-4o-mini lich "Reply with ok"
|
|
28
28
|
|
|
29
29
|
# anthropic
|
|
30
|
-
LICH_PROVIDER_KIND=anthropic LICH_MODEL=claude-sonnet-4 lich "Reply with ok"
|
|
30
|
+
LICH_PROVIDER_KIND=anthropic LICH_MODEL=claude-sonnet-4-20250514 lich "Reply with ok"
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
Defaults per kind when `LICH_BASE_URL`/`LICH_API_KEY_ENV` are unset: `openai_compat` uses `https://api.openai.com/v1` and reads `OPENAI_API_KEY`; `anthropic` uses `https://api.anthropic.com` and reads `ANTHROPIC_API_KEY`; `ollama` uses `http://localhost:11434` and needs no key.
|
|
@@ -76,7 +76,7 @@ lich # TUI; first run on a TTY opens the setup wizard
|
|
|
76
76
|
lich tui # same TUI, no wizard
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
Type a message and press Enter. The transcript shows your line, live tool-call rows while the agent works, and the reply; the status bar at the bottom tracks turns, tokens, and the session file path. Slash commands: `/help`, `/model`, `/usage`, `/clear`, `/sessions`, `/exit`. Details in [the TUI guide](user-guide/tui.md).
|
|
79
|
+
Type a message and press Enter. The transcript shows your line, live tool-call rows while the agent works, and the reply; the status bar at the bottom tracks turns, tokens, and the session file path. Slash commands: `/help`, `/model`, `/usage`, `/clear`, `/sessions`, `/resume`, `/exit`. Details in [the TUI guide](user-guide/tui.md).
|
|
80
80
|
|
|
81
81
|
## Your first gateway webhook
|
|
82
82
|
|
|
@@ -153,7 +153,7 @@ To hack on Lich itself, run the CLI straight from a clone instead of the npm pac
|
|
|
153
153
|
```sh
|
|
154
154
|
git clone https://github.com/Moikapy/lich.git && cd lich
|
|
155
155
|
bun install
|
|
156
|
-
bun src/cli.ts --version # -> 0.
|
|
156
|
+
bun src/cli.ts --version # -> 0.8.0 (package.json)
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
`bun src/cli.ts` accepts the same arguments as the installed `lich` binary, so every command on this page works unchanged.
|