thatgfsj-code 0.7.1 → 0.7.3

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.
Files changed (64) hide show
  1. package/dist/app/index.d.ts.map +1 -1
  2. package/dist/app/index.js +5 -0
  3. package/dist/app/index.js.map +1 -1
  4. package/dist/cmd/index.d.ts +0 -5
  5. package/dist/cmd/index.d.ts.map +1 -1
  6. package/dist/cmd/index.js +36 -56
  7. package/dist/cmd/index.js.map +1 -1
  8. package/dist/prompts/index.d.ts.map +1 -1
  9. package/dist/prompts/index.js +13 -1
  10. package/dist/prompts/index.js.map +1 -1
  11. package/dist/session/index.d.ts +5 -21
  12. package/dist/session/index.d.ts.map +1 -1
  13. package/dist/session/index.js +26 -22
  14. package/dist/session/index.js.map +1 -1
  15. package/dist/tools/nwt.d.ts +5 -0
  16. package/dist/tools/nwt.d.ts.map +1 -1
  17. package/dist/tools/nwt.js +68 -0
  18. package/dist/tools/nwt.js.map +1 -1
  19. package/dist/tui/app.js +1 -1
  20. package/dist/tui/app.js.map +1 -1
  21. package/dist/tui/components/ChatList.js +1 -1
  22. package/dist/tui/components/ChatList.js.map +1 -1
  23. package/dist/tui/components/Header.js +1 -1
  24. package/dist/tui/components/Thinking.d.ts +2 -1
  25. package/dist/tui/components/Thinking.d.ts.map +1 -1
  26. package/dist/tui/components/Thinking.js +5 -1
  27. package/dist/tui/components/Thinking.js.map +1 -1
  28. package/dist/tui/hooks/useChat.d.ts +1 -1
  29. package/dist/tui/hooks/useChat.d.ts.map +1 -1
  30. package/dist/tui/hooks/useChat.js +86 -97
  31. package/dist/tui/hooks/useChat.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/app/index.ts +6 -0
  34. package/src/cmd/index.tsx +38 -51
  35. package/src/prompts/index.ts +13 -1
  36. package/src/session/index.ts +28 -22
  37. package/src/tools/nwt.ts +68 -0
  38. package/src/tui/app.tsx +1 -1
  39. package/src/tui/components/ChatList.tsx +1 -1
  40. package/src/tui/components/Header.tsx +1 -1
  41. package/src/tui/components/Thinking.tsx +7 -1
  42. package/src/tui/hooks/useChat.ts +85 -97
  43. package/dist/app/agent.d.ts +0 -31
  44. package/dist/app/agent.d.ts.map +0 -1
  45. package/dist/app/agent.js +0 -106
  46. package/dist/app/agent.js.map +0 -1
  47. package/dist/tui/input.d.ts +0 -13
  48. package/dist/tui/input.d.ts.map +0 -1
  49. package/dist/tui/input.js +0 -47
  50. package/dist/tui/input.js.map +0 -1
  51. package/dist/tui/output.d.ts +0 -44
  52. package/dist/tui/output.d.ts.map +0 -1
  53. package/dist/tui/output.js +0 -202
  54. package/dist/tui/output.js.map +0 -1
  55. package/dist/tui/repl.d.ts +0 -15
  56. package/dist/tui/repl.d.ts.map +0 -1
  57. package/dist/tui/repl.js +0 -162
  58. package/dist/tui/repl.js.map +0 -1
  59. package/install.bat +0 -63
  60. package/install.ps1 +0 -217
  61. package/install.sh +0 -113
  62. package/src/tui/input.ts +0 -53
  63. package/src/tui/output.ts +0 -235
  64. package/src/tui/repl.ts +0 -181
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Session Manager - Manages conversation history
3
- * Migrated from old src/core/session.ts
2
+ * Session Manager - Manages conversation history with auto-compaction
4
3
  */
5
4
 
6
5
  import type { ChatMessage } from '../types.js';
@@ -11,62 +10,69 @@ export class SessionManager {
11
10
  private sessionId: string;
12
11
  private createdAt: Date;
13
12
  private compactor: ContextCompactor;
13
+ private maxMessages: number;
14
14
 
15
15
  constructor(maxMessages = 50) {
16
+ this.maxMessages = maxMessages;
16
17
  this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
17
18
  this.createdAt = new Date();
18
19
  this.compactor = new ContextCompactor({ maxMessages });
19
20
  }
20
21
 
21
- /**
22
- * Add a message to the session
23
- */
24
22
  addMessage(role: ChatMessage['role'], content: string, extras?: Partial<ChatMessage>): void {
25
23
  this.messages.push({ role, content, ...extras });
24
+ this.autoCompact();
26
25
  }
27
26
 
28
- /**
29
- * Get all messages (copy)
30
- */
31
27
  getMessages(): ChatMessage[] {
32
28
  return [...this.messages];
33
29
  }
34
30
 
35
- /**
36
- * Get message count
37
- */
38
31
  getMessageCount(): number {
39
32
  return this.messages.length;
40
33
  }
41
34
 
42
- /**
43
- * Clear session history
44
- */
45
35
  clear(): void {
46
36
  this.messages = [];
47
37
  }
48
38
 
49
39
  /**
50
- * Truncate messages to fit context window
40
+ * Auto-compact when messages exceed max.
41
+ * Keeps system messages + recent half. One summary replaces the rest.
51
42
  */
43
+ private autoCompact(): void {
44
+ if (this.messages.length <= this.maxMessages) return;
45
+
46
+ const systemMsgs = this.messages.filter(m => m.role === 'system');
47
+ const others = this.messages.filter(m => m.role !== 'system');
48
+ const keepCount = Math.floor(this.maxMessages * 0.5);
49
+ const recent = others.slice(-keepCount);
50
+ const removed = others.length - keepCount;
51
+
52
+ if (removed <= 0) return;
53
+
54
+ // Remove old summaries before adding new one
55
+ const cleanSystem = systemMsgs.filter(m => !m.content.startsWith('[Earlier conversation'));
56
+ const summary: ChatMessage = {
57
+ role: 'system',
58
+ content: `[Earlier conversation: ${removed} messages compacted to save context]`,
59
+ };
60
+ this.messages = [...cleanSystem, summary, ...recent];
61
+ }
62
+
52
63
  truncate(maxMessages?: number): void {
53
64
  if (maxMessages) {
65
+ this.maxMessages = maxMessages;
54
66
  this.compactor = new ContextCompactor({ maxMessages });
55
67
  }
56
- const { compacted } = this.compactor.autoCompact(this.messages);
68
+ const { compacted } = this.compactor.compact(this.messages);
57
69
  this.messages = compacted;
58
70
  }
59
71
 
60
- /**
61
- * Get session ID
62
- */
63
72
  getId(): string {
64
73
  return this.sessionId;
65
74
  }
66
75
 
67
- /**
68
- * Get session info
69
- */
70
76
  getInfo(): { id: string; messageCount: number; createdAt: Date } {
71
77
  return {
72
78
  id: this.sessionId,
package/src/tools/nwt.ts CHANGED
@@ -107,6 +107,9 @@ export class NwtTool implements Tool {
107
107
  if (!existsSync(eventsDir)) mkdirSync(eventsDir, { recursive: true });
108
108
  if (!existsSync(archiveDir)) mkdirSync(archiveDir, { recursive: true });
109
109
 
110
+ // Auto-archive events older than 30 days on every init
111
+ this.autoArchiveIfNeeded(cwd);
112
+
110
113
  // Write metadata
111
114
  const meta = {
112
115
  version: '1.0.0',
@@ -340,6 +343,71 @@ export class NwtTool implements Tool {
340
343
  };
341
344
  }
342
345
 
346
+ // ── Auto Archive ──────────────────────────────────────
347
+
348
+ /**
349
+ * Auto-archive events older than 30 days.
350
+ * Runs silently on init - no output unless something was archived.
351
+ */
352
+ private autoArchiveIfNeeded(cwd: string): void {
353
+ try {
354
+ const nwtDir = join(cwd, NWT_DIR);
355
+ const eventsDir = join(nwtDir, EVENTS_DIR);
356
+ const archiveDir = join(nwtDir, ARCHIVE_DIR);
357
+
358
+ if (!existsSync(eventsDir)) return;
359
+
360
+ const files = readdirSync(eventsDir).filter(f => f.endsWith('.json'));
361
+ if (files.length === 0) return;
362
+
363
+ const cutoff = new Date();
364
+ cutoff.setDate(cutoff.getDate() - ARCHIVE_AFTER_DAYS);
365
+
366
+ const toArchive: string[] = [];
367
+ const toKeep: string[] = [];
368
+
369
+ for (const file of files) {
370
+ try {
371
+ const event = JSON.parse(readFileSync(join(eventsDir, file), 'utf-8'));
372
+ const eventDate = new Date(event.timestamp);
373
+ if (eventDate < cutoff) {
374
+ toArchive.push(file);
375
+ } else {
376
+ toKeep.push(file);
377
+ }
378
+ } catch {
379
+ toKeep.push(file);
380
+ }
381
+ }
382
+
383
+ if (toArchive.length === 0) return;
384
+
385
+ // Create monthly archive file
386
+ const archiveName = `archive-${new Date().toISOString().split('T')[0]}.json`;
387
+ const archiveEvents = toArchive.map(f => {
388
+ return JSON.parse(readFileSync(join(eventsDir, f), 'utf-8'));
389
+ });
390
+
391
+ if (!existsSync(archiveDir)) mkdirSync(archiveDir, { recursive: true });
392
+
393
+ // Append to existing archive or create new
394
+ const archivePath = join(archiveDir, archiveName);
395
+ let existing: any[] = [];
396
+ if (existsSync(archivePath)) {
397
+ try { existing = JSON.parse(readFileSync(archivePath, 'utf-8')); } catch {}
398
+ }
399
+ existing.push(...archiveEvents);
400
+ writeFileSync(archivePath, JSON.stringify(existing, null, 2));
401
+
402
+ // Remove archived files from events dir
403
+ for (const file of toArchive) {
404
+ try { renameSync(join(eventsDir, file), join(archiveDir, file)); } catch {}
405
+ }
406
+ } catch {
407
+ // Silent fail - don't break init
408
+ }
409
+ }
410
+
343
411
  // ── Helpers ───────────────────────────────────────────
344
412
 
345
413
  private loadEvents(cwd: string): TimelineEvent[] {
package/src/tui/app.tsx CHANGED
@@ -53,7 +53,7 @@ export function TuiApp({ app }: Props) {
53
53
  streamingToolCalls={streamingToolCalls}
54
54
  width={terminalWidth - 4}
55
55
  />
56
- {isThinking && <Thinking />}
56
+ <Thinking active={isThinking} />
57
57
  <UserInput onSubmit={onSubmit} disabled={isThinking} />
58
58
  <StatusBar messageCount={allMessages.length} skills={activeSkills} />
59
59
  </Box>
@@ -13,7 +13,7 @@ interface Props {
13
13
 
14
14
  export const ChatList = memo(function ChatList({ messages, streaming, streamingToolCalls, width }: Props) {
15
15
  return (
16
- <Box flexDirection="column" flexGrow={1}>
16
+ <Box flexDirection="column">
17
17
  {messages.map((msg, i) => (
18
18
  <ChatMessage key={i} message={msg} width={width} />
19
19
  ))}
@@ -14,7 +14,7 @@ export const Header = React.memo(function Header({ provider, model }: Props) {
14
14
  <Box>
15
15
  <Text color="#06B6D4" bold> ⚡ </Text>
16
16
  <Text color="#22D3EE" bold>THATGFSJ CODE</Text>
17
- <Text dimColor> v0.7.1</Text>
17
+ <Text dimColor> v0.7.3</Text>
18
18
  </Box>
19
19
  <Box>
20
20
  <Text color="#06B6D4" bold> {provider} </Text>
@@ -4,10 +4,16 @@ import { Box, Text } from 'ink';
4
4
  import Spinner from 'ink-spinner';
5
5
 
6
6
  interface Props {
7
+ active?: boolean;
7
8
  message?: string;
8
9
  }
9
10
 
10
- export function Thinking({ message = 'Thinking' }: Props) {
11
+ export function Thinking({ active = true, message = 'Thinking' }: Props) {
12
+ if (!active) {
13
+ // Keep layout stable - render empty space
14
+ return <Box paddingY={0}><Text> </Text></Box>;
15
+ }
16
+
11
17
  return (
12
18
  <Box paddingLeft={1}>
13
19
  <Text color="#06B6D4">
@@ -1,4 +1,4 @@
1
- import { useState, useCallback, useRef } from 'react';
1
+ import { useState, useCallback, useRef, useEffect } from 'react';
2
2
  import type { MessageData } from '../components/ChatMessage.js';
3
3
  import type { ToolCallData } from '../components/ToolCall.js';
4
4
  import type { App } from '../../app/index.js';
@@ -18,10 +18,12 @@ export function useChat(app: App) {
18
18
  streamingToolCalls: [],
19
19
  });
20
20
  const processingRef = useRef(false);
21
+ const abortRef = useRef(false);
21
22
 
22
- const sendMessage = useCallback(async (input: string) => {
23
+ const sendMessage = useCallback((input: string) => {
23
24
  if (processingRef.current) return;
24
25
  processingRef.current = true;
26
+ abortRef.current = false;
25
27
 
26
28
  // Add user message
27
29
  setState(prev => ({
@@ -34,117 +36,103 @@ export function useChat(app: App) {
34
36
 
35
37
  app.session.addMessage('user', input);
36
38
 
39
+ // Process stream in background (non-blocking)
40
+ const stream = app.streamResponse();
37
41
  let fullContent = '';
38
42
  let currentToolCalls: ToolCallData[] = [];
39
43
 
40
- try {
41
- const stream = app.streamResponse();
44
+ const processStream = async () => {
45
+ try {
46
+ for await (const chunk of stream) {
47
+ if (abortRef.current) break;
42
48
 
43
- for await (const chunk of stream) {
44
- // Check for tool messages
45
- if (chunk.includes('@@TOOL@@')) {
46
- const parts = chunk.split('\n');
47
- for (const part of parts) {
48
- if (part.startsWith('@@TOOL@@')) {
49
- try {
50
- const data = JSON.parse(part.slice(8));
51
- if (data.action === 'call') {
52
- // Tool call - show it immediately
53
- currentToolCalls.push({
54
- name: data.name,
55
- args: data.args || '',
56
- });
57
- setState(prev => ({
58
- ...prev,
59
- isThinking: false,
60
- streamingToolCalls: [...currentToolCalls],
61
- }));
62
- } else if (data.action === 'result') {
63
- // Tool result - update the last tool call
64
- const lastIdx = currentToolCalls.length - 1;
65
- if (lastIdx >= 0) {
66
- currentToolCalls[lastIdx] = {
67
- ...currentToolCalls[lastIdx],
68
- result: data.output || data.error || '',
69
- isError: !!data.error,
70
- };
49
+ if (chunk.includes('@@TOOL@@')) {
50
+ const parts = chunk.split('\n');
51
+ for (const part of parts) {
52
+ if (part.startsWith('@@TOOL@@')) {
53
+ try {
54
+ const data = JSON.parse(part.slice(8));
55
+ if (data.action === 'call') {
56
+ currentToolCalls.push({ name: data.name, args: data.args || '' });
57
+ setState(prev => ({
58
+ ...prev,
59
+ isThinking: false,
60
+ streamingToolCalls: [...currentToolCalls],
61
+ }));
62
+ } else if (data.action === 'result') {
63
+ const lastIdx = currentToolCalls.length - 1;
64
+ if (lastIdx >= 0) {
65
+ currentToolCalls[lastIdx] = {
66
+ ...currentToolCalls[lastIdx],
67
+ result: data.output || data.error || '',
68
+ isError: !!data.error,
69
+ };
70
+ }
71
+ setState(prev => ({
72
+ ...prev,
73
+ streamingToolCalls: [...currentToolCalls],
74
+ isThinking: true,
75
+ }));
71
76
  }
72
- setState(prev => ({
73
- ...prev,
74
- streamingToolCalls: [...currentToolCalls],
75
- isThinking: true, // Continue thinking after tool
76
- }));
77
+ } catch {
78
+ fullContent += part;
79
+ setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
77
80
  }
78
- } catch {
79
- // Not a tool message, treat as text
81
+ } else if (part) {
80
82
  fullContent += part;
81
- setState(prev => ({
82
- ...prev,
83
- isThinking: false,
84
- streaming: fullContent,
85
- }));
83
+ setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
86
84
  }
87
- } else if (part) {
88
- fullContent += part;
89
- setState(prev => ({
90
- ...prev,
91
- isThinking: false,
92
- streaming: fullContent,
93
- }));
94
85
  }
86
+ } else {
87
+ fullContent += chunk;
88
+ setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
95
89
  }
96
- } else {
97
- // Regular text chunk
98
- fullContent += chunk;
99
- setState(prev => ({
100
- ...prev,
101
- isThinking: false,
102
- streaming: fullContent,
103
- }));
104
90
  }
105
- }
106
91
 
107
- // Finalize: add the complete message
108
- if (fullContent.trim() || currentToolCalls.length > 0) {
109
- app.session.addMessage('assistant', fullContent);
110
- }
92
+ // Finalize
93
+ if (fullContent.trim() || currentToolCalls.length > 0) {
94
+ app.session.addMessage('assistant', fullContent);
95
+ }
111
96
 
112
- setState(prev => ({
113
- ...prev,
114
- messages: [
115
- ...prev.messages,
116
- ...(fullContent.trim() || currentToolCalls.length > 0
117
- ? [{
118
- role: 'assistant' as const,
119
- content: fullContent,
120
- toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,
121
- }]
122
- : []),
123
- ],
124
- streaming: '',
125
- streamingToolCalls: [],
126
- isThinking: false,
127
- }));
97
+ setState(prev => ({
98
+ ...prev,
99
+ messages: [
100
+ ...prev.messages,
101
+ ...(fullContent.trim() || currentToolCalls.length > 0
102
+ ? [{
103
+ role: 'assistant' as const,
104
+ content: fullContent,
105
+ toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,
106
+ }]
107
+ : []),
108
+ ],
109
+ streaming: '',
110
+ streamingToolCalls: [],
111
+ isThinking: false,
112
+ }));
128
113
 
129
- app.session.truncate();
114
+ app.session.truncate();
115
+ } catch (error: any) {
116
+ setState(prev => ({
117
+ ...prev,
118
+ messages: [
119
+ ...prev.messages,
120
+ ...(fullContent.trim()
121
+ ? [{ role: 'assistant' as const, content: fullContent }]
122
+ : []),
123
+ { role: 'assistant', content: `Error: ${error.message}` },
124
+ ],
125
+ streaming: '',
126
+ streamingToolCalls: [],
127
+ isThinking: false,
128
+ }));
129
+ }
130
130
 
131
- } catch (error: any) {
132
- setState(prev => ({
133
- ...prev,
134
- messages: [
135
- ...prev.messages,
136
- ...(fullContent.trim()
137
- ? [{ role: 'assistant' as const, content: fullContent }]
138
- : []),
139
- { role: 'assistant', content: `Error: ${error.message}` },
140
- ],
141
- streaming: '',
142
- streamingToolCalls: [],
143
- isThinking: false,
144
- }));
145
- }
131
+ processingRef.current = false;
132
+ };
146
133
 
147
- processingRef.current = false;
134
+ // Start processing without blocking
135
+ processStream();
148
136
  }, [app]);
149
137
 
150
138
  return {
@@ -1,31 +0,0 @@
1
- /**
2
- * Agent Loop - Core agent logic with streaming and tool execution
3
- * Extracted from old src/core/ai-engine.ts
4
- *
5
- * The agent loop: while(true) { stream response → check tool calls → execute → repeat }
6
- */
7
- import type { ChatMessage, ChatResponse } from '../types.js';
8
- import type { HookManager } from '../hooks/index.js';
9
- import { LLMService } from '../llm/index.js';
10
- import { ToolRegistry } from '../tools/index.js';
11
- export interface AgentConfig {
12
- maxIterations?: number;
13
- hooks?: HookManager;
14
- }
15
- export declare class Agent {
16
- private llm;
17
- private registry;
18
- private hooks?;
19
- private maxIterations;
20
- constructor(llm: LLMService, registry: ToolRegistry, config?: AgentConfig);
21
- /**
22
- * Run agent loop with streaming output
23
- * Returns the final response
24
- */
25
- run(messages: ChatMessage[]): AsyncGenerator<string, ChatResponse>;
26
- /**
27
- * Non-streaming chat (convenience method)
28
- */
29
- chat(messages: ChatMessage[]): Promise<ChatResponse>;
30
- }
31
- //# sourceMappingURL=agent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/app/agent.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,KAAK,CAAC,CAAc;IAC5B,OAAO,CAAC,aAAa,CAAS;gBAElB,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAE,WAAgB;IAU7E;;;OAGG;IACI,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC;IA0FzE;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAO3D"}
package/dist/app/agent.js DELETED
@@ -1,106 +0,0 @@
1
- /**
2
- * Agent Loop - Core agent logic with streaming and tool execution
3
- * Extracted from old src/core/ai-engine.ts
4
- *
5
- * The agent loop: while(true) { stream response → check tool calls → execute → repeat }
6
- */
7
- import chalk from 'chalk';
8
- export class Agent {
9
- llm;
10
- registry;
11
- hooks;
12
- maxIterations;
13
- constructor(llm, registry, config = {}) {
14
- this.llm = llm;
15
- this.registry = registry;
16
- this.hooks = config.hooks;
17
- this.maxIterations = config.maxIterations ?? 10;
18
- // Register tools with LLM service
19
- this.llm.registerTools(registry.list());
20
- }
21
- /**
22
- * Run agent loop with streaming output
23
- * Returns the final response
24
- */
25
- async *run(messages) {
26
- let currentMessages = [...messages];
27
- let iterations = 0;
28
- while (iterations < this.maxIterations) {
29
- iterations++;
30
- // Hook: beforeAgentLoop
31
- if (this.hooks) {
32
- await this.hooks.emit('beforeAgentLoop', { messages: currentMessages, iteration: iterations });
33
- }
34
- // Stream the response
35
- let fullContent = '';
36
- for await (const chunk of this.llm.chatStream(currentMessages, { maxIterations: 1 })) {
37
- fullContent += chunk;
38
- yield chunk;
39
- }
40
- // Get the full response to check for tool calls
41
- const response = {
42
- content: fullContent,
43
- role: 'assistant',
44
- };
45
- // Check if the response contains tool calls
46
- // For now, we rely on the LLM service to handle tool calls internally
47
- // If the LLM service returned tool_calls, we need to process them
48
- if (response.tool_calls && response.tool_calls.length > 0) {
49
- currentMessages.push({
50
- role: 'assistant',
51
- content: response.content,
52
- tool_calls: response.tool_calls,
53
- });
54
- for (const toolCall of response.tool_calls) {
55
- // Hook: beforeToolCall
56
- if (this.hooks) {
57
- await this.hooks.emit('beforeToolCall', {
58
- toolName: toolCall.function.name,
59
- toolParams: JSON.parse(toolCall.function.arguments || '{}'),
60
- toolCallId: toolCall.id,
61
- });
62
- }
63
- const result = await this.registry.execute(toolCall.function.name, JSON.parse(toolCall.function.arguments || '{}'));
64
- // Hook: afterToolCall
65
- if (this.hooks) {
66
- await this.hooks.emit('afterToolCall', {
67
- toolName: toolCall.function.name,
68
- toolParams: JSON.parse(toolCall.function.arguments || '{}'),
69
- toolResult: result,
70
- toolCallId: toolCall.id,
71
- });
72
- }
73
- currentMessages.push({
74
- role: 'tool',
75
- content: result.success ? (result.output || JSON.stringify(result.data)) : (result.error || 'Tool failed'),
76
- tool_call_id: toolCall.id,
77
- name: toolCall.function.name,
78
- });
79
- yield `\n${chalk.gray(`[tool: ${toolCall.function.name}]`)}`;
80
- }
81
- continue; // Next iteration
82
- }
83
- // No tool calls - done
84
- if (response.content) {
85
- currentMessages.push({ role: 'assistant', content: response.content });
86
- }
87
- // Hook: afterAgentLoop
88
- if (this.hooks) {
89
- await this.hooks.emit('afterAgentLoop', { messages: currentMessages, iteration: iterations });
90
- }
91
- return response;
92
- }
93
- return { content: '[Agent loop exceeded maximum iterations]', role: 'assistant' };
94
- }
95
- /**
96
- * Non-streaming chat (convenience method)
97
- */
98
- async chat(messages) {
99
- let fullContent = '';
100
- for await (const chunk of this.run(messages)) {
101
- fullContent += chunk;
102
- }
103
- return { content: fullContent, role: 'assistant' };
104
- }
105
- }
106
- //# sourceMappingURL=agent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/app/agent.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- /**
2
- * REPL Input Handler
3
- */
4
- export declare class REPLInput {
5
- private rl;
6
- private history;
7
- private historyIndex;
8
- constructor();
9
- prompt(prefix?: string): Promise<string>;
10
- close(): void;
11
- private completer;
12
- }
13
- //# sourceMappingURL=input.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/tui/input.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,qBAAa,SAAS;IACpB,OAAO,CAAC,EAAE,CAAqB;IAC/B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAc;;IAyB5B,MAAM,CAAC,MAAM,GAAE,MAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQhE,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,SAAS;CAKlB"}
package/dist/tui/input.js DELETED
@@ -1,47 +0,0 @@
1
- /**
2
- * REPL Input Handler
3
- */
4
- import readline from 'readline';
5
- import chalk from 'chalk';
6
- export class REPLInput {
7
- rl;
8
- history = [];
9
- historyIndex = -1;
10
- constructor() {
11
- this.rl = readline.createInterface({
12
- input: process.stdin,
13
- output: process.stdout,
14
- completer: this.completer.bind(this),
15
- historySize: 100,
16
- tabSize: 4,
17
- });
18
- this.rl.on('SIGINT', () => {
19
- process.stdout.write(chalk.gray('\n Goodbye! 👋\n'));
20
- process.exit(0);
21
- });
22
- this.rl.on('line', (line) => {
23
- if (line.trim()) {
24
- this.history.push(line);
25
- if (this.history.length > 100)
26
- this.history.shift();
27
- }
28
- this.historyIndex = this.history.length;
29
- });
30
- }
31
- async prompt(prefix = chalk.cyan('❯ ')) {
32
- return new Promise((resolve) => {
33
- this.rl.question(prefix, (answer) => {
34
- resolve(answer);
35
- });
36
- });
37
- }
38
- close() {
39
- this.rl.close();
40
- }
41
- completer(line) {
42
- const commands = ['exit', 'quit', 'clear', 'help', 'tools', 'model'];
43
- const hits = commands.filter(c => c.startsWith(line.toLowerCase()));
44
- return [hits.length ? hits : [], line];
45
- }
46
- }
47
- //# sourceMappingURL=input.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/tui/input.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,OAAO,SAAS;IACZ,EAAE,CAAqB;IACvB,OAAO,GAAa,EAAE,CAAC;IACvB,YAAY,GAAW,CAAC,CAAC,CAAC;IAElC;QACE,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YACjC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YACpC,WAAW,EAAE,GAAG;YAChB,OAAO,EAAE,CAAC;SACX,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBAChB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG;oBAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACtD,CAAC;YACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;gBAClC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAEO,SAAS,CAAC,IAAY;QAC5B,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACrE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;CACF"}