@heysalad/cheri-cli 0.5.0 → 0.6.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/README.md +58 -30
- package/bin/cheri.js +3 -3
- package/package.json +7 -13
- package/src/commands/agent.js +165 -111
- package/src/commands/memory.js +4 -12
- package/src/commands/usage.js +64 -0
- package/src/lib/api-client.js +40 -0
- package/src/lib/config-store.js +0 -14
- package/src/lib/logger.js +1 -1
- package/src/repl.js +18 -22
- package/src/commands/chat.js +0 -15
- package/src/lib/branding.js +0 -37
- package/src/lib/providers/anthropic.js +0 -66
- package/src/lib/providers/base.js +0 -34
- package/src/lib/providers/bedrock.js +0 -7
- package/src/lib/providers/gemini.js +0 -89
- package/src/lib/providers/index.js +0 -53
- package/src/lib/providers/openai.js +0 -105
- package/src/lib/renderer.js +0 -44
- package/src/lib/repl.js +0 -225
- package/src/lib/tools/command-tools.js +0 -34
- package/src/lib/tools/file-tools.js +0 -73
- package/src/lib/tools/index.js +0 -32
- package/src/lib/tools/search-tools.js +0 -95
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# cheri-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CLI for [Cheri](https://cheri.heysalad.app) — the AI-powered cloud IDE that never forgets.
|
|
4
|
+
|
|
5
|
+
Manage workspaces, track API usage, and access your AI memory from the terminal.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
@@ -8,53 +10,79 @@ AI-powered cloud IDE by [HeySalad](https://heysalad.app). Like Claude Code, but
|
|
|
8
10
|
npm install -g @heysalad/cheri-cli
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Requires Node.js 18+.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
|
-
#
|
|
18
|
+
# Authenticate with your Cheri account
|
|
15
19
|
cheri login
|
|
16
20
|
|
|
21
|
+
# Launch a cloud workspace
|
|
22
|
+
cheri workspace launch owner/my-repo
|
|
23
|
+
|
|
17
24
|
# Check account status
|
|
18
25
|
cheri status
|
|
19
26
|
|
|
20
|
-
#
|
|
21
|
-
cheri
|
|
22
|
-
|
|
23
|
-
# List your workspaces
|
|
24
|
-
cheri workspace list
|
|
27
|
+
# View API usage and rate limits
|
|
28
|
+
cheri usage
|
|
29
|
+
```
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
| Command | Description |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `cheri login` | Authenticate with GitHub |
|
|
36
|
+
| `cheri status` | Show account and workspace status |
|
|
37
|
+
| `cheri usage` | Show API usage and rate limit status |
|
|
38
|
+
| `cheri workspace launch <repo>` | Launch a new cloud workspace |
|
|
39
|
+
| `cheri workspace list` | List all workspaces |
|
|
40
|
+
| `cheri workspace stop <id>` | Stop a running workspace |
|
|
41
|
+
| `cheri workspace status <id>` | Get workspace status |
|
|
42
|
+
| `cheri memory show` | Show current memory entries |
|
|
43
|
+
| `cheri memory add <text>` | Add a memory entry |
|
|
44
|
+
| `cheri memory clear` | Clear all memory |
|
|
45
|
+
| `cheri memory export` | Export memory to JSON |
|
|
46
|
+
| `cheri config list` | Show all configuration |
|
|
47
|
+
| `cheri config get <key>` | Get a config value |
|
|
48
|
+
| `cheri config set <key> <value>` | Set a config value |
|
|
49
|
+
| `cheri init` | Initialize a project |
|
|
50
|
+
|
|
51
|
+
## Interactive REPL
|
|
52
|
+
|
|
53
|
+
Run `cheri` with no arguments to enter the interactive REPL:
|
|
28
54
|
|
|
29
|
-
|
|
30
|
-
cheri
|
|
55
|
+
```
|
|
56
|
+
$ cheri
|
|
57
|
+
🍒 cheri > help
|
|
58
|
+
🍒 cheri > workspace list
|
|
59
|
+
🍒 cheri > usage
|
|
60
|
+
🍒 cheri > exit
|
|
61
|
+
```
|
|
31
62
|
|
|
32
|
-
|
|
33
|
-
cheri memory show
|
|
34
|
-
cheri memory add "Always use TypeScript strict mode"
|
|
35
|
-
cheri memory clear
|
|
63
|
+
## Rate Limits
|
|
36
64
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
65
|
+
| Plan | Limit |
|
|
66
|
+
|---|---|
|
|
67
|
+
| Free | 100 requests/hour |
|
|
68
|
+
| Pro | 1,000 requests/hour |
|
|
41
69
|
|
|
42
|
-
|
|
70
|
+
Use `cheri usage` to check your current rate limit status.
|
|
43
71
|
|
|
44
|
-
|
|
45
|
-
2. **`cheri workspace launch`** spins up a cloud workspace with code-server (VS Code in browser)
|
|
46
|
-
3. **`cheri memory`** stores persistent context that follows you across sessions
|
|
47
|
-
4. **`cheri init`** creates a local `.ai/` directory with project constitution files
|
|
72
|
+
## Configuration
|
|
48
73
|
|
|
49
|
-
|
|
74
|
+
Config is stored in `~/.cheri/`. Set the API URL if self-hosting:
|
|
50
75
|
|
|
51
|
-
|
|
76
|
+
```bash
|
|
77
|
+
cheri config set apiUrl https://your-instance.example.com
|
|
78
|
+
```
|
|
52
79
|
|
|
53
80
|
## Links
|
|
54
81
|
|
|
55
82
|
- [Cheri Cloud IDE](https://cheri.heysalad.app)
|
|
56
|
-
- [
|
|
83
|
+
- [Dashboard](https://cheri.heysalad.app/dashboard)
|
|
84
|
+
- [GitHub](https://github.com/chilu18/cloud-ide)
|
|
57
85
|
|
|
58
86
|
## License
|
|
59
87
|
|
|
60
|
-
MIT
|
|
88
|
+
MIT
|
package/bin/cheri.js
CHANGED
|
@@ -7,13 +7,13 @@ import { registerStatusCommand } from "../src/commands/status.js";
|
|
|
7
7
|
import { registerMemoryCommand } from "../src/commands/memory.js";
|
|
8
8
|
import { registerConfigCommand } from "../src/commands/config.js";
|
|
9
9
|
import { registerWorkspaceCommand } from "../src/commands/workspace.js";
|
|
10
|
-
import {
|
|
10
|
+
import { registerUsageCommand } from "../src/commands/usage.js";
|
|
11
11
|
import { registerAgentCommand } from "../src/commands/agent.js";
|
|
12
12
|
|
|
13
13
|
program
|
|
14
14
|
.name("cheri")
|
|
15
15
|
.description("Cheri CLI - AI-powered cloud IDE by HeySalad")
|
|
16
|
-
.version("0.
|
|
16
|
+
.version("0.1.0");
|
|
17
17
|
|
|
18
18
|
registerLoginCommand(program);
|
|
19
19
|
registerInitCommand(program);
|
|
@@ -21,7 +21,7 @@ registerStatusCommand(program);
|
|
|
21
21
|
registerMemoryCommand(program);
|
|
22
22
|
registerConfigCommand(program);
|
|
23
23
|
registerWorkspaceCommand(program);
|
|
24
|
-
|
|
24
|
+
registerUsageCommand(program);
|
|
25
25
|
registerAgentCommand(program);
|
|
26
26
|
|
|
27
27
|
// If no args, launch interactive command REPL
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heysalad/cheri-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Cheri CLI - AI-powered cloud IDE by HeySalad. Like Claude Code, but for cloud workspaces.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,15 +8,14 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
|
-
"src/"
|
|
12
|
-
"README.md"
|
|
11
|
+
"src/"
|
|
13
12
|
],
|
|
14
13
|
"scripts": {
|
|
15
14
|
"start": "node bin/cheri.js",
|
|
16
15
|
"dev": "node bin/cheri.js",
|
|
17
|
-
"release:patch": "npm version patch && npm publish
|
|
18
|
-
"release:minor": "npm version minor && npm publish
|
|
19
|
-
"release:major": "npm version major && npm publish
|
|
16
|
+
"release:patch": "npm version patch && npm publish && git push && git push --tags",
|
|
17
|
+
"release:minor": "npm version minor && npm publish && git push && git push --tags",
|
|
18
|
+
"release:major": "npm version major && npm publish && git push && git push --tags"
|
|
20
19
|
},
|
|
21
20
|
"keywords": [
|
|
22
21
|
"cloud-ide",
|
|
@@ -29,23 +28,18 @@
|
|
|
29
28
|
],
|
|
30
29
|
"repository": {
|
|
31
30
|
"type": "git",
|
|
32
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/chilu18/cloud-ide.git",
|
|
32
|
+
"directory": "cli"
|
|
33
33
|
},
|
|
34
|
-
"homepage": "https://cheri.heysalad.app",
|
|
35
34
|
"author": "HeySalad",
|
|
36
35
|
"license": "MIT",
|
|
37
36
|
"engines": {
|
|
38
37
|
"node": ">=18"
|
|
39
38
|
},
|
|
40
39
|
"dependencies": {
|
|
41
|
-
"@anthropic-ai/sdk": "^0.74.0",
|
|
42
|
-
"@google/generative-ai": "^0.24.1",
|
|
43
40
|
"chalk": "^5.3.0",
|
|
44
41
|
"commander": "^12.1.0",
|
|
45
42
|
"inquirer": "^9.2.23",
|
|
46
|
-
"marked": "^15.0.12",
|
|
47
|
-
"marked-terminal": "^7.3.0",
|
|
48
|
-
"openai": "^6.22.0",
|
|
49
43
|
"ora": "^8.0.1"
|
|
50
44
|
}
|
|
51
45
|
}
|
package/src/commands/agent.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { apiClient } from "../lib/api-client.js";
|
|
2
|
-
import { getConfigValue, setConfigValue } from "../lib/config-store.js";
|
|
3
|
-
import { createProvider } from "../lib/providers/index.js";
|
|
4
2
|
import { log } from "../lib/logger.js";
|
|
5
3
|
import chalk from "chalk";
|
|
6
4
|
|
|
@@ -8,96 +6,121 @@ const SYSTEM_PROMPT = `You are Cheri Agent, an AI assistant for the Cheri cloud
|
|
|
8
6
|
|
|
9
7
|
const TOOLS = [
|
|
10
8
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
type: "function",
|
|
10
|
+
function: {
|
|
11
|
+
name: "get_account_info",
|
|
12
|
+
description: "Get the current user's account information",
|
|
13
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
14
|
+
},
|
|
14
15
|
},
|
|
15
16
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
type: "function",
|
|
18
|
+
function: {
|
|
19
|
+
name: "list_workspaces",
|
|
20
|
+
description: "List all cloud workspaces for the current user",
|
|
21
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
22
|
+
},
|
|
19
23
|
},
|
|
20
24
|
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
type: "function",
|
|
26
|
+
function: {
|
|
27
|
+
name: "create_workspace",
|
|
28
|
+
description: "Launch a new cloud workspace for a GitHub repository",
|
|
29
|
+
parameters: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: { repo: { type: "string", description: "GitHub repo in owner/name format" } },
|
|
32
|
+
required: ["repo"],
|
|
27
33
|
},
|
|
28
|
-
required: ["repo"],
|
|
29
34
|
},
|
|
30
35
|
},
|
|
31
36
|
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
type: "function",
|
|
38
|
+
function: {
|
|
39
|
+
name: "stop_workspace",
|
|
40
|
+
description: "Stop and delete a running workspace",
|
|
41
|
+
parameters: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: { id: { type: "string", description: "Workspace ID to stop" } },
|
|
44
|
+
required: ["id"],
|
|
38
45
|
},
|
|
39
|
-
required: ["id"],
|
|
40
46
|
},
|
|
41
47
|
},
|
|
42
48
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
type: "function",
|
|
50
|
+
function: {
|
|
51
|
+
name: "get_workspace_status",
|
|
52
|
+
description: "Get the status of a specific workspace",
|
|
53
|
+
parameters: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: { id: { type: "string", description: "Workspace ID" } },
|
|
56
|
+
required: ["id"],
|
|
49
57
|
},
|
|
50
|
-
required: ["id"],
|
|
51
58
|
},
|
|
52
59
|
},
|
|
53
60
|
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
type: "function",
|
|
62
|
+
function: {
|
|
63
|
+
name: "get_memory",
|
|
64
|
+
description: "Retrieve all stored memory entries",
|
|
65
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
66
|
+
},
|
|
57
67
|
},
|
|
58
68
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
type: "function",
|
|
70
|
+
function: {
|
|
71
|
+
name: "add_memory",
|
|
72
|
+
description: "Add a new memory entry for the user",
|
|
73
|
+
parameters: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
content: { type: "string", description: "Memory content to store" },
|
|
77
|
+
category: { type: "string", description: "Optional category (defaults to 'general')" },
|
|
78
|
+
},
|
|
79
|
+
required: ["content"],
|
|
66
80
|
},
|
|
67
|
-
required: ["content"],
|
|
68
81
|
},
|
|
69
82
|
},
|
|
70
83
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
type: "function",
|
|
85
|
+
function: {
|
|
86
|
+
name: "clear_memory",
|
|
87
|
+
description: "Clear all stored memory entries",
|
|
88
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
89
|
+
},
|
|
74
90
|
},
|
|
75
91
|
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
type: "function",
|
|
93
|
+
function: {
|
|
94
|
+
name: "get_usage",
|
|
95
|
+
description: "Get the user's API usage and rate limit statistics",
|
|
96
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
97
|
+
},
|
|
79
98
|
},
|
|
80
99
|
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
100
|
+
type: "function",
|
|
101
|
+
function: {
|
|
102
|
+
name: "get_config",
|
|
103
|
+
description: "Get a configuration value by key (dot notation supported)",
|
|
104
|
+
parameters: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: { key: { type: "string", description: "Config key, e.g. 'ai.provider'" } },
|
|
107
|
+
required: ["key"],
|
|
87
108
|
},
|
|
88
|
-
required: ["key"],
|
|
89
109
|
},
|
|
90
110
|
},
|
|
91
111
|
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
type: "function",
|
|
113
|
+
function: {
|
|
114
|
+
name: "set_config",
|
|
115
|
+
description: "Set a configuration value",
|
|
116
|
+
parameters: {
|
|
117
|
+
type: "object",
|
|
118
|
+
properties: {
|
|
119
|
+
key: { type: "string", description: "Config key" },
|
|
120
|
+
value: { type: "string", description: "Value to set" },
|
|
121
|
+
},
|
|
122
|
+
required: ["key", "value"],
|
|
99
123
|
},
|
|
100
|
-
required: ["key", "value"],
|
|
101
124
|
},
|
|
102
125
|
},
|
|
103
126
|
];
|
|
@@ -123,11 +146,15 @@ async function executeTool(name, args) {
|
|
|
123
146
|
return await apiClient.clearMemory();
|
|
124
147
|
case "get_usage":
|
|
125
148
|
return await apiClient.getUsage();
|
|
126
|
-
case "get_config":
|
|
149
|
+
case "get_config": {
|
|
150
|
+
const { getConfigValue } = await import("../lib/config-store.js");
|
|
127
151
|
return { key: args.key, value: getConfigValue(args.key) };
|
|
128
|
-
|
|
152
|
+
}
|
|
153
|
+
case "set_config": {
|
|
154
|
+
const { setConfigValue } = await import("../lib/config-store.js");
|
|
129
155
|
setConfigValue(args.key, args.value);
|
|
130
156
|
return { key: args.key, value: args.value, status: "updated" };
|
|
157
|
+
}
|
|
131
158
|
default:
|
|
132
159
|
return { error: `Unknown tool: ${name}` };
|
|
133
160
|
}
|
|
@@ -136,72 +163,101 @@ async function executeTool(name, args) {
|
|
|
136
163
|
}
|
|
137
164
|
}
|
|
138
165
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
166
|
+
// Parse SSE stream from the cloud proxy
|
|
167
|
+
async function* parseSSEStream(response) {
|
|
168
|
+
const reader = response.body.getReader();
|
|
169
|
+
const decoder = new TextDecoder();
|
|
170
|
+
let buffer = "";
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
while (true) {
|
|
174
|
+
const { done, value } = await reader.read();
|
|
175
|
+
if (done) break;
|
|
176
|
+
|
|
177
|
+
buffer += decoder.decode(value, { stream: true });
|
|
178
|
+
const lines = buffer.split("\n");
|
|
179
|
+
buffer = lines.pop() || "";
|
|
142
180
|
|
|
143
|
-
|
|
181
|
+
for (const line of lines) {
|
|
182
|
+
if (line.startsWith("data: ")) {
|
|
183
|
+
const data = line.slice(6).trim();
|
|
184
|
+
if (data === "[DONE]") return;
|
|
185
|
+
try {
|
|
186
|
+
yield JSON.parse(data);
|
|
187
|
+
} catch {}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} finally {
|
|
192
|
+
reader.releaseLock();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
144
195
|
|
|
196
|
+
export async function runAgent(userRequest) {
|
|
145
197
|
const messages = [
|
|
198
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
146
199
|
{ role: "user", content: userRequest },
|
|
147
200
|
];
|
|
148
201
|
|
|
149
202
|
const MAX_ITERATIONS = 10;
|
|
150
203
|
|
|
151
204
|
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
205
|
+
const response = await apiClient.chatStream(messages, TOOLS);
|
|
206
|
+
|
|
152
207
|
let fullText = "";
|
|
153
|
-
const toolCalls =
|
|
154
|
-
|
|
155
|
-
for await (const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
toolCalls.push({ id: event.id, name: event.name, input: {} });
|
|
164
|
-
break;
|
|
165
|
-
|
|
166
|
-
case "tool_input_delta":
|
|
167
|
-
// accumulated by provider, final input comes in tool_use_end
|
|
168
|
-
break;
|
|
169
|
-
|
|
170
|
-
case "tool_use_end":
|
|
171
|
-
if (toolCalls.length > 0) {
|
|
172
|
-
toolCalls[toolCalls.length - 1].input = event.input;
|
|
173
|
-
}
|
|
174
|
-
break;
|
|
208
|
+
const toolCalls = {};
|
|
209
|
+
|
|
210
|
+
for await (const chunk of parseSSEStream(response)) {
|
|
211
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
212
|
+
const finishReason = chunk.choices?.[0]?.finish_reason;
|
|
213
|
+
|
|
214
|
+
if (delta?.content) {
|
|
215
|
+
process.stdout.write(delta.content);
|
|
216
|
+
fullText += delta.content;
|
|
217
|
+
}
|
|
175
218
|
|
|
176
|
-
|
|
177
|
-
|
|
219
|
+
if (delta?.tool_calls) {
|
|
220
|
+
for (const tc of delta.tool_calls) {
|
|
221
|
+
const idx = tc.index;
|
|
222
|
+
if (!toolCalls[idx]) {
|
|
223
|
+
toolCalls[idx] = { id: tc.id || "", name: "", arguments: "" };
|
|
224
|
+
}
|
|
225
|
+
if (tc.id) toolCalls[idx].id = tc.id;
|
|
226
|
+
if (tc.function?.name) toolCalls[idx].name = tc.function.name;
|
|
227
|
+
if (tc.function?.arguments) toolCalls[idx].arguments += tc.function.arguments;
|
|
228
|
+
}
|
|
178
229
|
}
|
|
230
|
+
|
|
231
|
+
if (finishReason) break;
|
|
179
232
|
}
|
|
180
233
|
|
|
234
|
+
const toolCallList = Object.values(toolCalls);
|
|
235
|
+
|
|
181
236
|
// No tool calls — final text response, done
|
|
182
|
-
if (
|
|
237
|
+
if (toolCallList.length === 0) {
|
|
183
238
|
if (fullText) process.stdout.write("\n");
|
|
184
239
|
return;
|
|
185
240
|
}
|
|
186
241
|
|
|
187
242
|
if (fullText) process.stdout.write("\n");
|
|
188
243
|
|
|
189
|
-
// Build assistant message
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
244
|
+
// Build assistant message with tool calls
|
|
245
|
+
const assistantMsg = { role: "assistant", content: fullText || null };
|
|
246
|
+
assistantMsg.tool_calls = toolCallList.map((tc) => ({
|
|
247
|
+
id: tc.id,
|
|
248
|
+
type: "function",
|
|
249
|
+
function: { name: tc.name, arguments: tc.arguments },
|
|
250
|
+
}));
|
|
251
|
+
messages.push(assistantMsg);
|
|
252
|
+
|
|
253
|
+
// Execute each tool and add results
|
|
254
|
+
for (const tc of toolCallList) {
|
|
255
|
+
let input = {};
|
|
256
|
+
try { input = JSON.parse(tc.arguments); } catch {}
|
|
198
257
|
|
|
199
|
-
|
|
200
|
-
const toolResults = [];
|
|
201
|
-
for (const tc of toolCalls) {
|
|
202
|
-
log.info(`Calling ${chalk.cyan(tc.name)}${Object.keys(tc.input).length ? chalk.dim(" " + JSON.stringify(tc.input)) : ""}`);
|
|
258
|
+
log.info(`Calling ${chalk.cyan(tc.name)}${Object.keys(input).length ? chalk.dim(" " + JSON.stringify(input)) : ""}`);
|
|
203
259
|
|
|
204
|
-
const result = await executeTool(tc.name,
|
|
260
|
+
const result = await executeTool(tc.name, input);
|
|
205
261
|
|
|
206
262
|
if (result.error) {
|
|
207
263
|
log.error(result.error);
|
|
@@ -209,14 +265,12 @@ export async function runAgent(userRequest) {
|
|
|
209
265
|
log.success(tc.name);
|
|
210
266
|
}
|
|
211
267
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
268
|
+
messages.push({
|
|
269
|
+
role: "tool",
|
|
270
|
+
tool_call_id: tc.id,
|
|
215
271
|
content: JSON.stringify(result),
|
|
216
272
|
});
|
|
217
273
|
}
|
|
218
|
-
|
|
219
|
-
messages.push({ role: "user", content: toolResults });
|
|
220
274
|
}
|
|
221
275
|
|
|
222
276
|
log.warn("Agent reached maximum iterations (10). Stopping.");
|
package/src/commands/memory.js
CHANGED
|
@@ -53,21 +53,13 @@ export async function showMemory(options = {}) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export async function addMemory(content, category = "general") {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
log.success(`Memory saved (${count} total). Category: ${chalk.cyan(entry.category)}`);
|
|
59
|
-
} catch (err) {
|
|
60
|
-
throw err;
|
|
61
|
-
}
|
|
56
|
+
const { entry, count } = await apiClient.addMemory(content, category);
|
|
57
|
+
log.success(`Memory saved (${count} total). Category: ${chalk.cyan(entry.category)}`);
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
export async function clearMemory() {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
log.success("All memories cleared.");
|
|
68
|
-
} catch (err) {
|
|
69
|
-
throw err;
|
|
70
|
-
}
|
|
61
|
+
await apiClient.clearMemory();
|
|
62
|
+
log.success("All memories cleared.");
|
|
71
63
|
}
|
|
72
64
|
|
|
73
65
|
export async function exportMemory(options = {}) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import { apiClient } from "../lib/api-client.js";
|
|
4
|
+
import { log } from "../lib/logger.js";
|
|
5
|
+
|
|
6
|
+
export async function showUsage() {
|
|
7
|
+
log.blank();
|
|
8
|
+
log.brand("Usage");
|
|
9
|
+
|
|
10
|
+
const spinner = ora("Fetching usage data...").start();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const data = await apiClient.getUsage();
|
|
14
|
+
spinner.stop();
|
|
15
|
+
|
|
16
|
+
// Rate limit
|
|
17
|
+
log.header("Rate Limit");
|
|
18
|
+
log.keyValue("Plan", data.plan === "pro" ? chalk.green("Pro") : "Free");
|
|
19
|
+
log.keyValue("Limit", `${data.rateLimit.limit} requests/hour`);
|
|
20
|
+
const remaining = data.rateLimit.remaining;
|
|
21
|
+
const limit = data.rateLimit.limit;
|
|
22
|
+
const remainColor = remaining > limit * 0.5 ? chalk.green : remaining > limit * 0.1 ? chalk.yellow : chalk.red;
|
|
23
|
+
log.keyValue("Remaining", remainColor(`${remaining}`));
|
|
24
|
+
log.keyValue("Resets at", data.rateLimit.resetsAt);
|
|
25
|
+
|
|
26
|
+
// Today's usage
|
|
27
|
+
log.header("Today");
|
|
28
|
+
log.keyValue("Requests", `${data.usage.today.requests}`);
|
|
29
|
+
const endpoints = data.usage.today.endpoints || {};
|
|
30
|
+
if (Object.keys(endpoints).length > 0) {
|
|
31
|
+
for (const [ep, count] of Object.entries(endpoints)) {
|
|
32
|
+
console.log(` ${chalk.dim(ep)} ${chalk.cyan(count)}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Summary
|
|
37
|
+
log.header("Summary");
|
|
38
|
+
log.keyValue("Last 7 days", `${data.usage.last7d.requests} requests`);
|
|
39
|
+
log.keyValue("Last 30 days", `${data.usage.last30d.requests} requests`);
|
|
40
|
+
log.keyValue("All time", `${data.summary.totalRequests} requests`);
|
|
41
|
+
if (data.summary.memberSince) {
|
|
42
|
+
log.keyValue("Member since", new Date(data.summary.memberSince).toLocaleDateString());
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
spinner.stop();
|
|
46
|
+
log.error(err.message);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
log.blank();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function registerUsageCommand(program) {
|
|
53
|
+
program
|
|
54
|
+
.command("usage")
|
|
55
|
+
.description("Show API usage and rate limit status")
|
|
56
|
+
.action(async () => {
|
|
57
|
+
try {
|
|
58
|
+
await showUsage();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
log.error(err.message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|