@tyvm/knowhow 0.0.54 → 0.0.56
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/docs/input-queue-manager.md +142 -0
- package/docs/multi-worker-management.md +142 -0
- package/package.json +1 -1
- package/scripts/README.md +119 -0
- package/scripts/restore_keys.sh +59 -0
- package/scripts/unset_keys.sh +60 -0
- package/src/agents/base/base.ts +2 -2
- package/src/agents/tools/askHuman.ts +2 -0
- package/src/agents/tools/startAgentTask.ts +2 -2
- package/src/ai.ts +3 -1
- package/src/chat/CliChatService.ts +2 -2
- package/src/chat/modules/AgentModule.ts +25 -2
- package/src/chat-old.ts +2 -2
- package/src/cli.ts +56 -3
- package/src/clients/anthropic.ts +7 -5
- package/src/clients/knowhow.ts +2 -2
- package/src/clients/openai.ts +5 -0
- package/src/index.ts +6 -6
- package/src/microphone.ts +12 -4
- package/src/services/DockerService.ts +473 -0
- package/src/services/KnowhowClient.ts +4 -1
- package/src/services/index.ts +5 -1
- package/src/types.ts +7 -0
- package/src/utils/InputQueueManager.ts +324 -0
- package/src/utils/index.ts +5 -152
- package/src/worker.ts +158 -9
- package/src/workerRegistry.ts +152 -0
- package/tests/clients/AIClient.test.ts +177 -92
- package/tests/manual/test-concurrent-ask.ts +43 -0
- package/tests/services/DockerService.test.ts +24 -0
- package/tests/unit/input-queue.test.ts +80 -0
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.js +2 -2
- package/ts_build/src/agents/tools/askHuman.d.ts +1 -1
- package/ts_build/src/agents/tools/askHuman.js.map +1 -1
- package/ts_build/src/agents/tools/startAgentTask.js +2 -1
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/ai.js +3 -1
- package/ts_build/src/ai.js.map +1 -1
- package/ts_build/src/chat/CliChatService.js +1 -1
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.js +11 -1
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat-old.js +1 -1
- package/ts_build/src/chat-old.js.map +1 -1
- package/ts_build/src/cli.js +46 -3
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.js +7 -5
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/knowhow.js +1 -1
- package/ts_build/src/clients/knowhow.js.map +1 -1
- package/ts_build/src/clients/openai.js +5 -0
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/dockerWorker.d.ts +22 -0
- package/ts_build/src/dockerWorker.js +210 -0
- package/ts_build/src/dockerWorker.js.map +1 -0
- package/ts_build/src/index.js +4 -4
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/microphone.js +8 -3
- package/ts_build/src/microphone.js.map +1 -1
- package/ts_build/src/services/DockerService.d.ts +26 -0
- package/ts_build/src/services/DockerService.js +363 -0
- package/ts_build/src/services/DockerService.js.map +1 -0
- package/ts_build/src/services/KnowhowClient.d.ts +1 -1
- package/ts_build/src/services/KnowhowClient.js +1 -1
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/index.d.ts +3 -0
- package/ts_build/src/services/index.js +4 -1
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/types.d.ts +5 -0
- package/ts_build/src/types.js +4 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/utils/InputQueueManager.d.ts +19 -0
- package/ts_build/src/utils/InputQueueManager.js +234 -0
- package/ts_build/src/utils/InputQueueManager.js.map +1 -0
- package/ts_build/src/utils/index.d.ts +1 -3
- package/ts_build/src/utils/index.js +4 -114
- package/ts_build/src/utils/index.js.map +1 -1
- package/ts_build/src/worker-entrypoint.d.ts +2 -0
- package/ts_build/src/worker-entrypoint.js +39 -0
- package/ts_build/src/worker-entrypoint.js.map +1 -0
- package/ts_build/src/worker.d.ts +7 -1
- package/ts_build/src/worker.js +117 -9
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/src/workerRegistry.d.ts +11 -0
- package/ts_build/src/workerRegistry.js +143 -0
- package/ts_build/src/workerRegistry.js.map +1 -0
- package/ts_build/tests/clients/AIClient.test.js +88 -42
- package/ts_build/tests/clients/AIClient.test.js.map +1 -1
- package/ts_build/tests/manual/test-concurrent-ask.d.ts +1 -0
- package/ts_build/tests/manual/test-concurrent-ask.js +22 -0
- package/ts_build/tests/manual/test-concurrent-ask.js.map +1 -0
- package/ts_build/tests/services/DockerService.test.d.ts +1 -0
- package/ts_build/tests/services/DockerService.test.js +22 -0
- package/ts_build/tests/services/DockerService.test.js.map +1 -0
- package/ts_build/tests/unit/input-queue.test.d.ts +1 -0
- package/ts_build/tests/unit/input-queue.test.js +32 -0
- package/ts_build/tests/unit/input-queue.test.js.map +1 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Input Queue Manager
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
When multiple `ask()` calls (used by `askHuman` tool and `ChatService.getInput`) are made concurrently before any resolve, each call would create its own readline interface listening to `process.stdin`. This caused input duplication - each character typed would be processed by multiple listeners, appearing doubled or tripled in the terminal.
|
|
6
|
+
|
|
7
|
+
### Example Scenario
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// Agent asks a question
|
|
11
|
+
const answer1 = ask("What is your name?");
|
|
12
|
+
|
|
13
|
+
// Before user responds, agent asks another question
|
|
14
|
+
const answer2 = ask("What is your age?");
|
|
15
|
+
|
|
16
|
+
// Problem: User sees both questions and typed characters appear multiple times
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Solution
|
|
20
|
+
|
|
21
|
+
Implemented a singleton `InputQueueManager` class that:
|
|
22
|
+
|
|
23
|
+
1. **Queues all concurrent asks**: When multiple `ask()` calls happen, they're added to a queue
|
|
24
|
+
2. **Maintains a single input stream**: Only one readline interface is active at a time
|
|
25
|
+
3. **Updates the display**: When a new question is asked while waiting, the display updates to show the most recent question
|
|
26
|
+
4. **Resolves all pending promises**: When the user presses Enter, all queued promises resolve with the same answer
|
|
27
|
+
|
|
28
|
+
### Key Features
|
|
29
|
+
|
|
30
|
+
- **Single input stream**: Only one `process.stdin` listener is active at any time
|
|
31
|
+
- **Dynamic question updates**: The displayed question updates to the most recent one
|
|
32
|
+
- **Preserved user input**: When the question changes, the user's typed text is preserved
|
|
33
|
+
- **Cursor position maintained**: Cursor position is maintained relative to the typed text
|
|
34
|
+
- **Autocomplete support**: Tab completion uses options from the most recent question
|
|
35
|
+
- **History support**: Arrow key navigation uses history from the most recent question
|
|
36
|
+
|
|
37
|
+
## Implementation Details
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
class InputQueueManager {
|
|
41
|
+
private queue: Array<{
|
|
42
|
+
question: string;
|
|
43
|
+
options: string[];
|
|
44
|
+
history: string[];
|
|
45
|
+
resolve: (value: string) => void;
|
|
46
|
+
}> = [];
|
|
47
|
+
private currentReadline: any = null;
|
|
48
|
+
private isProcessing = false;
|
|
49
|
+
private currentLine = "";
|
|
50
|
+
private cursorPos = 0;
|
|
51
|
+
|
|
52
|
+
async ask(question, options, history): Promise<string> {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
this.queue.push({ question, options, history, resolve });
|
|
55
|
+
|
|
56
|
+
if (!this.isProcessing) {
|
|
57
|
+
this.processNext();
|
|
58
|
+
} else {
|
|
59
|
+
this.updateDisplay(); // Update to show new question
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private updateDisplay(): void {
|
|
65
|
+
// Clear line and show most recent question
|
|
66
|
+
const current = this.queue[this.queue.length - 1];
|
|
67
|
+
process.stdout.write('\r\x1b[K');
|
|
68
|
+
process.stdout.write(current.question + this.currentLine);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private async processNext(): Promise<void> {
|
|
72
|
+
// Process most recent question
|
|
73
|
+
const current = this.queue[this.queue.length - 1];
|
|
74
|
+
|
|
75
|
+
// Set up single readline interface
|
|
76
|
+
this.currentReadline = readline.createInterface({...});
|
|
77
|
+
|
|
78
|
+
// Handle input
|
|
79
|
+
process.stdin.on("data", dataHandler);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// On Enter press
|
|
83
|
+
private handleSubmit(answer: string): void {
|
|
84
|
+
// Resolve ALL pending promises with the same answer
|
|
85
|
+
while (this.queue.length > 0) {
|
|
86
|
+
const item = this.queue.shift();
|
|
87
|
+
item.resolve(answer);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Clean up and process next if any
|
|
91
|
+
cleanup();
|
|
92
|
+
this.processNext();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Usage
|
|
98
|
+
|
|
99
|
+
The `ask()` function now automatically uses the singleton queue:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { ask } from "./utils";
|
|
103
|
+
|
|
104
|
+
// Multiple concurrent calls are now safe
|
|
105
|
+
const promise1 = ask("Question 1?");
|
|
106
|
+
const promise2 = ask("Question 2?"); // Display updates to this
|
|
107
|
+
const promise3 = ask("Question 3?"); // Display updates to this
|
|
108
|
+
|
|
109
|
+
// User types "answer" and presses Enter
|
|
110
|
+
// All three promises resolve with "answer"
|
|
111
|
+
const [a1, a2, a3] = await Promise.all([promise1, promise2, promise3]);
|
|
112
|
+
console.log(a1, a2, a3); // "answer", "answer", "answer"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Testing
|
|
116
|
+
|
|
117
|
+
Run the manual test to verify the behavior:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx ts-node tests/manual/test-concurrent-ask.ts
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Expected behavior:
|
|
124
|
+
- You should see only the most recent question
|
|
125
|
+
- Typing should not duplicate characters
|
|
126
|
+
- Both promises resolve with the same answer
|
|
127
|
+
|
|
128
|
+
## Benefits
|
|
129
|
+
|
|
130
|
+
1. **No input duplication**: Characters appear once, as expected
|
|
131
|
+
2. **Clean user experience**: User always sees the most relevant question
|
|
132
|
+
3. **Backward compatible**: Existing code using `ask()` works without changes
|
|
133
|
+
4. **Handles edge cases**: Properly cleans up resources and handles Ctrl+C
|
|
134
|
+
5. **Maintains features**: Autocomplete, history, and cursor control all work correctly
|
|
135
|
+
|
|
136
|
+
## Related Files
|
|
137
|
+
|
|
138
|
+
- `src/utils/index.ts` - Implementation of InputQueueManager
|
|
139
|
+
- `src/agents/tools/askHuman.ts` - Uses `ask()` via the queue
|
|
140
|
+
- `src/chat/CliChatService.ts` - Uses `ask()` via the queue
|
|
141
|
+
- `tests/unit/input-queue.test.ts` - Unit tests documenting behavior
|
|
142
|
+
- `tests/manual/test-concurrent-ask.ts` - Manual test to verify fix
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Multi-Worker Management
|
|
2
|
+
|
|
3
|
+
This feature allows you to manage and start multiple knowhow workers from different directories using a centralized registry.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The multi-worker management system provides:
|
|
8
|
+
- Registration of worker directories in a global config (`~/.knowhow/workers.json`)
|
|
9
|
+
- A single command to start all registered workers simultaneously
|
|
10
|
+
- Management commands to list, register, and unregister workers
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Register a Worker
|
|
15
|
+
|
|
16
|
+
Navigate to a project directory and register it as a worker:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cd /path/to/project1
|
|
20
|
+
knowhow worker --register
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This will:
|
|
24
|
+
1. Register the current directory in `~/.knowhow/workers.json`
|
|
25
|
+
2. Ensure the worker configuration is set up in the local `.knowhow/knowhow.json`
|
|
26
|
+
|
|
27
|
+
### Start All Workers
|
|
28
|
+
|
|
29
|
+
Start all registered workers at once:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
knowhow workers
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This command will:
|
|
36
|
+
- Read all registered worker paths from the global config
|
|
37
|
+
- Start each worker by executing `knowhow worker` in its directory
|
|
38
|
+
- Keep all workers running until you press Ctrl+C
|
|
39
|
+
- Gracefully shut down all workers on exit
|
|
40
|
+
|
|
41
|
+
### List Registered Workers
|
|
42
|
+
|
|
43
|
+
View all registered worker paths:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
knowhow workers --list
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Output example:
|
|
50
|
+
```
|
|
51
|
+
Registered workers (3):
|
|
52
|
+
1. /Users/username/project1
|
|
53
|
+
2. /Users/username/project2
|
|
54
|
+
3. /Users/username/project3
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Unregister a Worker
|
|
58
|
+
|
|
59
|
+
Remove a worker from the registry:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
knowhow workers --unregister /path/to/project
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Clear All Workers
|
|
66
|
+
|
|
67
|
+
Remove all registered workers:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
knowhow workers --clear
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
The worker registry is stored in:
|
|
76
|
+
```
|
|
77
|
+
~/.knowhow/workers.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Example format:
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"workers": [
|
|
84
|
+
"/Users/username/project1",
|
|
85
|
+
"/Users/username/project2",
|
|
86
|
+
"/Users/username/project3"
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Typical Workflow
|
|
92
|
+
|
|
93
|
+
1. **Set up multiple projects as workers:**
|
|
94
|
+
```bash
|
|
95
|
+
cd ~/project1
|
|
96
|
+
knowhow worker --register
|
|
97
|
+
|
|
98
|
+
cd ~/project2
|
|
99
|
+
knowhow worker --register
|
|
100
|
+
|
|
101
|
+
cd ~/project3
|
|
102
|
+
knowhow worker --register
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
2. **Start all workers:**
|
|
106
|
+
```bash
|
|
107
|
+
knowhow workers
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
3. **Check worker status:**
|
|
111
|
+
```bash
|
|
112
|
+
knowhow workers --list
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
4. **Stop all workers:**
|
|
116
|
+
Press `Ctrl+C` in the terminal where workers are running
|
|
117
|
+
|
|
118
|
+
## Benefits
|
|
119
|
+
|
|
120
|
+
- **Centralized Management**: Manage multiple workers from a single command
|
|
121
|
+
- **Simplified Deployment**: No need to manually start workers in each directory
|
|
122
|
+
- **Persistent Configuration**: Worker registrations persist across sessions
|
|
123
|
+
- **Graceful Shutdown**: All workers shut down cleanly when stopped
|
|
124
|
+
|
|
125
|
+
## Implementation Details
|
|
126
|
+
|
|
127
|
+
### Files Created
|
|
128
|
+
|
|
129
|
+
- `src/workerRegistry.ts` - Core registry management functions
|
|
130
|
+
- `~/.knowhow/workers.json` - Global worker registry storage
|
|
131
|
+
|
|
132
|
+
### CLI Commands Modified
|
|
133
|
+
|
|
134
|
+
- `knowhow worker` - Added `--register` flag to register current directory
|
|
135
|
+
- `knowhow workers` - New command with subcommands for management and starting workers
|
|
136
|
+
|
|
137
|
+
### Process Management
|
|
138
|
+
|
|
139
|
+
- Each worker runs as a child process
|
|
140
|
+
- Workers inherit stdio from the parent process (you see all logs)
|
|
141
|
+
- SIGINT/SIGTERM signals are properly handled for graceful shutdown
|
|
142
|
+
- Workers are not detached, so they stop when the parent process stops
|
package/package.json
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# AI Keys Management Scripts
|
|
2
|
+
|
|
3
|
+
These bash scripts help you temporarily unset and restore AI API keys in your terminal session. This is useful for testing CLI behavior without authentication or when you want to work in a clean environment.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add these functions to your `~/.bashrc` or `~/.zshrc`:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# AI Keys Management
|
|
11
|
+
unset_keys() {
|
|
12
|
+
source /path/to/knowhow/scripts/unset_keys.sh
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
restore_keys() {
|
|
16
|
+
source /path/to/knowhow/scripts/restore_keys.sh
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Replace `/path/to/knowhow` with the actual path to your knowhow repository.
|
|
21
|
+
|
|
22
|
+
Then reload your shell:
|
|
23
|
+
```bash
|
|
24
|
+
source ~/.bashrc # or source ~/.zshrc
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Unset Keys
|
|
30
|
+
|
|
31
|
+
Temporarily remove AI API keys from your current shell session:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
unset_keys
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This will:
|
|
38
|
+
- Backup all your API keys to `BACKUP_*` environment variables
|
|
39
|
+
- Unset the following environment variables:
|
|
40
|
+
- `OPENAI_KEY`
|
|
41
|
+
- `OPENAI_API_KEY`
|
|
42
|
+
- `ANTHROPIC_API_KEY`
|
|
43
|
+
- `ANTHROPIC_KEY`
|
|
44
|
+
- `GEMINI_API_KEY`
|
|
45
|
+
- `GOOGLE_API_KEY`
|
|
46
|
+
- `XAI_API_KEY`
|
|
47
|
+
|
|
48
|
+
### Restore Keys
|
|
49
|
+
|
|
50
|
+
Restore your API keys from the backup:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
restore_keys
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This will:
|
|
57
|
+
- Read the backup from `BACKUP_*` environment variables
|
|
58
|
+
- Restore all previously unset environment variables
|
|
59
|
+
- Clear the `BACKUP_*` environment variables
|
|
60
|
+
|
|
61
|
+
## Example Workflow
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Check that you have keys set
|
|
65
|
+
echo $OPENAI_KEY
|
|
66
|
+
# Output: sk-proj-...
|
|
67
|
+
|
|
68
|
+
# Unset the keys for testing
|
|
69
|
+
unset_keys
|
|
70
|
+
# Output: ✓ Successfully backed up and unset 5 API key(s)
|
|
71
|
+
|
|
72
|
+
# Verify keys are unset
|
|
73
|
+
echo $OPENAI_KEY
|
|
74
|
+
# Output: (empty)
|
|
75
|
+
|
|
76
|
+
# Test your CLI without keys
|
|
77
|
+
knowhow --help
|
|
78
|
+
|
|
79
|
+
# Restore your keys when done
|
|
80
|
+
restore_keys
|
|
81
|
+
# Output: ✓ Successfully restored 5 API key(s)
|
|
82
|
+
|
|
83
|
+
# Verify keys are restored
|
|
84
|
+
echo $OPENAI_KEY
|
|
85
|
+
# Output: sk-proj-...
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Notes
|
|
89
|
+
|
|
90
|
+
- These commands only affect the **current terminal session**
|
|
91
|
+
- The backup variables (`BACKUP_*`) are stored in the current shell session only
|
|
92
|
+
- If you close your terminal before running `restore_keys`, the backups are **lost** and you'll need to restart your terminal or re-source your shell configuration to get your keys back from your original bashrc/zshrc
|
|
93
|
+
- The scripts must be **sourced** (not executed) to affect your current shell environment
|
|
94
|
+
|
|
95
|
+
## Troubleshooting
|
|
96
|
+
|
|
97
|
+
### Keys lost after closing terminal
|
|
98
|
+
|
|
99
|
+
If you close your terminal after running `unset_keys`, the backup environment variables are lost. To restore your keys, simply open a new terminal (which will reload your bashrc/zshrc with the original key values) or run:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
source ~/.bashrc # or source ~/.zshrc
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Permission denied
|
|
106
|
+
|
|
107
|
+
Make sure the scripts are executable:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
chmod +x scripts/unset_keys.sh scripts/restore_keys.sh
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Commands not found
|
|
114
|
+
|
|
115
|
+
Make sure you've added the functions to your shell configuration and reloaded it:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
source ~/.bashrc # or source ~/.zshrc
|
|
119
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# restore_keys - Restore AI API keys that were backed up by unset_keys
|
|
4
|
+
# Usage: source restore_keys.sh OR restore_keys (if added to bashrc)
|
|
5
|
+
#
|
|
6
|
+
# This script restores environment variables from BACKUP_* environment variables
|
|
7
|
+
# created by unset_keys
|
|
8
|
+
|
|
9
|
+
# Colors for output
|
|
10
|
+
RED='\033[0;31m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
BLUE='\033[0;34m'
|
|
14
|
+
NC='\033[0m' # No Color
|
|
15
|
+
|
|
16
|
+
restore_keys() {
|
|
17
|
+
echo -e "${BLUE}Restoring AI API keys...${NC}"
|
|
18
|
+
|
|
19
|
+
# List of environment variables to restore
|
|
20
|
+
local keys=(
|
|
21
|
+
"OPENAI_KEY"
|
|
22
|
+
"OPENAI_API_KEY"
|
|
23
|
+
"ANTHROPIC_API_KEY"
|
|
24
|
+
"ANTHROPIC_KEY"
|
|
25
|
+
"GEMINI_API_KEY"
|
|
26
|
+
"GOOGLE_API_KEY"
|
|
27
|
+
"XAI_API_KEY"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
local restored=0
|
|
31
|
+
|
|
32
|
+
# Restore each key from its BACKUP_* variable
|
|
33
|
+
for key in "${keys[@]}"; do
|
|
34
|
+
local backup_var="BACKUP_${key}"
|
|
35
|
+
if [ -n "${!backup_var}" ]; then
|
|
36
|
+
export "${key}=${!backup_var}"
|
|
37
|
+
unset "$backup_var"
|
|
38
|
+
restored=$((restored + 1))
|
|
39
|
+
fi
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
if [ $restored -eq 0 ]; then
|
|
43
|
+
echo -e "${YELLOW}No backed up keys found to restore${NC}"
|
|
44
|
+
echo -e "${YELLOW}Run 'unset_keys' first to create backups${NC}"
|
|
45
|
+
else
|
|
46
|
+
echo -e "${GREEN}✓ Successfully restored ${restored} API key(s)${NC}"
|
|
47
|
+
echo -e "${BLUE}BACKUP_* variables cleared${NC}"
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# If script is sourced, run the function
|
|
52
|
+
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
|
53
|
+
restore_keys
|
|
54
|
+
else
|
|
55
|
+
echo -e "${RED}ERROR: This script must be sourced, not executed${NC}"
|
|
56
|
+
echo "Usage: source ${BASH_SOURCE[0]}"
|
|
57
|
+
echo "Or add to bashrc and run: restore_keys"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# unset_keys - Temporarily unset AI API keys in current shell session
|
|
4
|
+
# Usage: source unset_keys.sh OR unset_keys (if added to bashrc)
|
|
5
|
+
#
|
|
6
|
+
# This script backs up your current AI API keys to BACKUP_* environment variables
|
|
7
|
+
# and then unsets the original keys, allowing you to test
|
|
8
|
+
# CLI behavior without authentication.
|
|
9
|
+
|
|
10
|
+
# Colors for output
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
BLUE='\033[0;34m'
|
|
15
|
+
NC='\033[0m' # No Color
|
|
16
|
+
|
|
17
|
+
unset_keys() {
|
|
18
|
+
echo -e "${BLUE}Backing up AI API keys to BACKUP_* variables and unsetting originals...${NC}"
|
|
19
|
+
|
|
20
|
+
# List of environment variables to backup and unset
|
|
21
|
+
local keys=(
|
|
22
|
+
"OPENAI_KEY"
|
|
23
|
+
"OPENAI_API_KEY"
|
|
24
|
+
"ANTHROPIC_API_KEY"
|
|
25
|
+
"ANTHROPIC_KEY"
|
|
26
|
+
"GEMINI_API_KEY"
|
|
27
|
+
"GOOGLE_API_KEY"
|
|
28
|
+
"XAI_API_KEY"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
local backed_up=0
|
|
32
|
+
|
|
33
|
+
# Backup and unset each key
|
|
34
|
+
for key in "${keys[@]}"; do
|
|
35
|
+
if [ -n "${!key}" ]; then
|
|
36
|
+
# Save the key value to BACKUP_* environment variable
|
|
37
|
+
export "BACKUP_${key}=${!key}"
|
|
38
|
+
unset "$key"
|
|
39
|
+
backed_up=$((backed_up + 1))
|
|
40
|
+
fi
|
|
41
|
+
done
|
|
42
|
+
|
|
43
|
+
if [ $backed_up -eq 0 ]; then
|
|
44
|
+
echo -e "${YELLOW}No AI keys found to unset${NC}"
|
|
45
|
+
else
|
|
46
|
+
echo -e "${GREEN}✓ Successfully backed up and unset ${backed_up} API key(s)${NC}"
|
|
47
|
+
echo -e "${BLUE}Keys backed up to BACKUP_* environment variables${NC}"
|
|
48
|
+
echo -e "${YELLOW}Run 'restore_keys' to restore them${NC}"
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# If script is sourced, run the function
|
|
53
|
+
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
|
54
|
+
unset_keys
|
|
55
|
+
else
|
|
56
|
+
echo -e "${RED}ERROR: This script must be sourced, not executed${NC}"
|
|
57
|
+
echo "Usage: source ${BASH_SOURCE[0]}"
|
|
58
|
+
echo "Or add to bashrc and run: unset_keys"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
package/src/agents/base/base.ts
CHANGED
|
@@ -512,7 +512,7 @@ export abstract class BaseAgent implements IAgent {
|
|
|
512
512
|
messages,
|
|
513
513
|
"pre_call"
|
|
514
514
|
);
|
|
515
|
-
const compressThreshold =
|
|
515
|
+
const compressThreshold = 30000;
|
|
516
516
|
|
|
517
517
|
const response = await this.getClient().createChatCompletion({
|
|
518
518
|
model,
|
|
@@ -639,7 +639,7 @@ export abstract class BaseAgent implements IAgent {
|
|
|
639
639
|
|
|
640
640
|
if (
|
|
641
641
|
this.getMessagesLength(messages) > compressThreshold &&
|
|
642
|
-
messages.length >
|
|
642
|
+
messages.length > 30
|
|
643
643
|
) {
|
|
644
644
|
const taskBreakdown = await this.getTaskBreakdown(messages);
|
|
645
645
|
console.log(
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Marked from "marked";
|
|
2
2
|
import { ask } from "../../utils";
|
|
3
3
|
|
|
4
|
+
// Simple, CLI-agnostic implementation
|
|
5
|
+
// CLI-specific behavior is handled via ToolsService override in AgentModule
|
|
4
6
|
export async function askHuman(question: string) {
|
|
5
7
|
console.log("AI has asked: ");
|
|
6
8
|
console.log(Marked.parse(question), "\n");
|
|
@@ -59,7 +59,8 @@ export async function startAgentTask(params: StartAgentTaskParams) {
|
|
|
59
59
|
command += ` --max-spend-limit ${maxSpendLimit}`;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const timeout = maxTimeLimit || 60000;
|
|
63
|
+
return execCommand(command, timeout, true);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
export const startAgentTaskDefinition: Tool = {
|
|
@@ -106,4 +107,3 @@ export const startAgentTaskDefinition: Tool = {
|
|
|
106
107
|
},
|
|
107
108
|
},
|
|
108
109
|
};
|
|
109
|
-
|
package/src/ai.ts
CHANGED
|
@@ -73,7 +73,9 @@ export async function summarizeTexts(
|
|
|
73
73
|
|
|
74
74
|
console.log(content);
|
|
75
75
|
|
|
76
|
-
const summary = await singlePrompt(content, model, agent)
|
|
76
|
+
const summary = await singlePrompt(content, model, agent).catch((err) => {
|
|
77
|
+
return `Text of length ${text.length} could not be summarized due to error: ${err.message}`;
|
|
78
|
+
});
|
|
77
79
|
summaries.push(summary);
|
|
78
80
|
}
|
|
79
81
|
|
|
@@ -206,8 +206,8 @@ export class CliChatService implements ChatService {
|
|
|
206
206
|
value = await editor({ message: prompt });
|
|
207
207
|
this.context.multilineMode = false; // Disable after use like original
|
|
208
208
|
} else {
|
|
209
|
-
// Use saved input history for scrollback
|
|
210
|
-
const history = this.inputHistory.slice()
|
|
209
|
+
// Use saved input history for scrollback (InputQueueManager handles reverse access)
|
|
210
|
+
const history = this.inputHistory.slice();
|
|
211
211
|
value = await ask(prompt, options, history);
|
|
212
212
|
}
|
|
213
213
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Chat Module - Handles agent interactions
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
KnowhowSimpleClient,
|
|
6
|
+
KNOWHOW_API_URL,
|
|
7
|
+
} from "../../services/KnowhowClient";
|
|
5
8
|
import * as fs from "fs";
|
|
6
9
|
import * as path from "path";
|
|
7
10
|
|
|
@@ -641,7 +644,7 @@ ${reason}
|
|
|
641
644
|
this.saveSession(taskId, taskInfo, []);
|
|
642
645
|
|
|
643
646
|
// Create Knowhow chat task if messageId provided
|
|
644
|
-
const baseUrl =
|
|
647
|
+
const baseUrl = KNOWHOW_API_URL;
|
|
645
648
|
console.log(
|
|
646
649
|
`Base URL for Knowhow API: ${baseUrl}, Message ID: ${options.messageId}`
|
|
647
650
|
);
|
|
@@ -706,6 +709,26 @@ ${reason}
|
|
|
706
709
|
|
|
707
710
|
// Set up message processors like in original startAgent
|
|
708
711
|
|
|
712
|
+
// Register an override for askHuman to use CLI input method
|
|
713
|
+
// This keeps the askHuman tool CLI-agnostic while enabling CLI-specific behavior
|
|
714
|
+
// through the override system, achieving better separation of concerns
|
|
715
|
+
agent.tools.registerOverride(
|
|
716
|
+
"askHuman",
|
|
717
|
+
async (originalArgs: any[], originalTool: any) => {
|
|
718
|
+
const question = originalArgs[0];
|
|
719
|
+
|
|
720
|
+
// Use CLI-specific input method from CliChatService
|
|
721
|
+
const chatService = this.chatService;
|
|
722
|
+
if (!chatService) {
|
|
723
|
+
throw new Error("ChatService not available in tools context");
|
|
724
|
+
}
|
|
725
|
+
console.log("AI has asked: ");
|
|
726
|
+
console.log(Marked.parse(question), "\n");
|
|
727
|
+
return await chatService.getInput("response: ");
|
|
728
|
+
},
|
|
729
|
+
10 // Priority level
|
|
730
|
+
);
|
|
731
|
+
|
|
709
732
|
agent.messageProcessor.setProcessors("pre_call", [
|
|
710
733
|
new ToolResponseCache(agent.tools).createProcessor(),
|
|
711
734
|
new TokenCompressor(agent.tools).createProcessor((msg) =>
|
package/src/chat-old.ts
CHANGED
|
@@ -152,7 +152,7 @@ export async function getInput(
|
|
|
152
152
|
value = await editor({ message: question });
|
|
153
153
|
Flags.disable(ChatFlags.multi);
|
|
154
154
|
} else {
|
|
155
|
-
const history = chatHistory.map((c) => c.input)
|
|
155
|
+
const history = chatHistory.map((c) => c.input);
|
|
156
156
|
value = await ask(question, options, history);
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -248,7 +248,7 @@ export async function chatLoop<E extends GptQuestionEmbedding>(
|
|
|
248
248
|
provider = await ask(
|
|
249
249
|
`\n\nCurrent Provider: ${provider}\nCurrent Model: ${model}\n\nWhich provider would you like to use: `,
|
|
250
250
|
providers
|
|
251
|
-
);
|
|
251
|
+
) as keyof typeof Clients.clients;
|
|
252
252
|
model =
|
|
253
253
|
ChatModelDefaults[provider] ||
|
|
254
254
|
(await Clients.getRegisteredModels(provider))[0];
|