hakimi 0.1.0 → 0.1.1
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 +31 -15
- package/dist/services/chatRouter.js +7 -2
- package/dist/services/configAgent.js +7 -6
- package/dist/services/theAgent.js +6 -0
- package/dist/utils/paths.d.ts +2 -0
- package/dist/utils/paths.js +28 -0
- package/package.json +2 -2
- package/prompts/config-agent.md +11 -3
package/README.md
CHANGED
|
@@ -1,38 +1,50 @@
|
|
|
1
1
|
# Hakimi
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Chat with an AI assistant via Telegram/Slack/Feishu to remotely control your computer.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Prerequisites
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Hakimi depends on [Kimi Code CLI](https://github.com/MoonshotAI/kimi-cli). Install it first:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
# Linux/macOS
|
|
11
|
+
curl -LsSf https://code.kimi.com/install.sh | bash
|
|
12
|
+
|
|
13
|
+
# Windows (PowerShell)
|
|
14
|
+
Invoke-RestMethod https://code.kimi.com/install.ps1 | Invoke-Expression
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For detailed instructions, see the [Getting Started Guide](https://moonshotai.github.io/kimi-cli/en/guides/getting-started.html).
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g hakimi
|
|
11
23
|
```
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
## Usage
|
|
14
26
|
|
|
15
27
|
```bash
|
|
16
|
-
|
|
28
|
+
hakimi
|
|
17
29
|
```
|
|
18
30
|
|
|
19
31
|
Debug mode (show detailed logs):
|
|
20
32
|
|
|
21
33
|
```bash
|
|
22
|
-
|
|
34
|
+
hakimi --debug
|
|
23
35
|
```
|
|
24
36
|
|
|
25
|
-
###
|
|
37
|
+
### 1. Login to Kimi Code
|
|
26
38
|
|
|
27
39
|
Press `L` to login to your Kimi Code account. Follow the prompts to complete authorization in your browser.
|
|
28
40
|
|
|
29
|
-
###
|
|
41
|
+
### 2. Configure
|
|
30
42
|
|
|
31
43
|
Press `C` to start the configuration wizard. The AI assistant will guide you through:
|
|
32
44
|
- Naming your AI assistant
|
|
33
45
|
- Setting up chat platforms (Telegram/Slack/Feishu)
|
|
34
46
|
|
|
35
|
-
###
|
|
47
|
+
### 3. Start Service
|
|
36
48
|
|
|
37
49
|
Press `S` to start the service, then send messages to your Bot on the chat platform.
|
|
38
50
|
|
|
@@ -55,11 +67,6 @@ Press `S` to start the service, then send messages to your Bot on the chat platf
|
|
|
55
67
|
1. Go to https://open.feishu.cn to create an app
|
|
56
68
|
2. Get the App ID and App Secret
|
|
57
69
|
|
|
58
|
-
## Config File Locations
|
|
59
|
-
|
|
60
|
-
- Kimi Code: `~/.kimi/config.toml`
|
|
61
|
-
- Hakimi: `~/.hakimi/config.toml`
|
|
62
|
-
|
|
63
70
|
## Hotkeys
|
|
64
71
|
|
|
65
72
|
| Key | Function |
|
|
@@ -69,3 +76,12 @@ Press `S` to start the service, then send messages to your Bot on the chat platf
|
|
|
69
76
|
| S | Start/Stop service |
|
|
70
77
|
| Q | Quit |
|
|
71
78
|
| Esc | Back/Cancel |
|
|
79
|
+
|
|
80
|
+
## Config Files
|
|
81
|
+
|
|
82
|
+
- Kimi Code: `~/.kimi/config.toml`
|
|
83
|
+
- Hakimi: `~/.hakimi/config.toml`
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
|
@@ -144,9 +144,14 @@ export class ChatRouter {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
handleMessage(koishiSession) {
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
this.log(`Received: platform=${koishiSession.platform}, guildId=${koishiSession.guildId}, channelId=${koishiSession.channelId}, userId=${koishiSession.userId}`);
|
|
148
|
+
// Only handle private messages (no guildId, or Slack DM channels starting with 'D')
|
|
149
|
+
const isPrivate = !koishiSession.guildId ||
|
|
150
|
+
(koishiSession.platform === 'slack' && koishiSession.channelId?.startsWith('D'));
|
|
151
|
+
if (!isPrivate) {
|
|
152
|
+
this.log(`Skipping non-private message`);
|
|
149
153
|
return;
|
|
154
|
+
}
|
|
150
155
|
const sessionId = `${koishiSession.platform}-${koishiSession.selfId}-${koishiSession.userId}`;
|
|
151
156
|
const content = koishiSession.content || '';
|
|
152
157
|
let chatSession = this.sessionCache.get(sessionId);
|
|
@@ -5,9 +5,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { createSession, createExternalTool } from '@moonshot-ai/kimi-agent-sdk';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { writeHakimiConfig } from '../utils/config.js';
|
|
8
|
-
import { HAKIMI_DIR } from '../utils/paths.js';
|
|
8
|
+
import { HAKIMI_DIR, getLanguageInstruction } from '../utils/paths.js';
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
|
|
10
|
+
function generateSessionId() {
|
|
11
|
+
return `hakimi-config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
12
|
+
}
|
|
11
13
|
export async function loadConfigPrompt() {
|
|
12
14
|
const promptPath = join(__dirname, '../../prompts/config-agent.md');
|
|
13
15
|
return readFile(promptPath, 'utf-8');
|
|
@@ -58,15 +60,14 @@ export class ConfigAgent {
|
|
|
58
60
|
});
|
|
59
61
|
this.session = createSession({
|
|
60
62
|
workDir: HAKIMI_DIR,
|
|
61
|
-
sessionId:
|
|
63
|
+
sessionId: generateSessionId(),
|
|
62
64
|
thinking: false,
|
|
63
65
|
yoloMode: true,
|
|
64
66
|
externalTools: [askUserTool, finishConfigTool],
|
|
65
67
|
});
|
|
66
|
-
// Clear previous session context
|
|
67
|
-
await this.sendMessage('/clear');
|
|
68
68
|
// Send initial prompt with system instructions
|
|
69
|
-
|
|
69
|
+
const langInstruction = getLanguageInstruction();
|
|
70
|
+
await this.sendMessage(this.systemPrompt + `\n\n${langInstruction}\n\nPlease start by asking the user what they want to name their AI assistant.`);
|
|
70
71
|
}
|
|
71
72
|
async sendMessage(content) {
|
|
72
73
|
if (!this.session) {
|
|
@@ -4,9 +4,11 @@ import { existsSync } from 'node:fs';
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
+
import { getLanguageInstruction } from '../utils/paths.js';
|
|
7
8
|
const HOME_DIR = homedir();
|
|
8
9
|
const AGENT_YAML_DIR = '/tmp/hakimi/agents';
|
|
9
10
|
function generateAgentYaml(agentName) {
|
|
11
|
+
const langInstruction = getLanguageInstruction();
|
|
10
12
|
return `version: 1
|
|
11
13
|
agent:
|
|
12
14
|
extend: default
|
|
@@ -16,6 +18,10 @@ agent:
|
|
|
16
18
|
|
|
17
19
|
You are accessible via instant messaging platforms (Telegram/Slack/Feishu).
|
|
18
20
|
|
|
21
|
+
You have PERSISTENT conversation history with each user. Your session is preserved across messages and even across app restarts. You CAN and SHOULD remember what you discussed with the user earlier in this conversation. Never claim you "cannot access previous messages" or "don't have memory" - you do have full context of the conversation history.
|
|
22
|
+
|
|
23
|
+
${langInstruction}
|
|
24
|
+
|
|
19
25
|
IMPORTANT: You MUST use the SendMessage tool to reply to the user. Do NOT put your reply in the assistant message content - it will be ignored. Only messages sent via SendMessage will reach the user.
|
|
20
26
|
|
|
21
27
|
IMPORTANT: Prefer calling SendMessage multiple times with shorter messages rather than one long message. This provides better user experience on IM platforms - users see responses progressively instead of waiting for a wall of text. For example:
|
package/dist/utils/paths.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ export declare const KIMI_DIR: string;
|
|
|
2
2
|
export declare const KIMI_CONFIG: string;
|
|
3
3
|
export declare const HAKIMI_DIR: string;
|
|
4
4
|
export declare const HAKIMI_CONFIG: string;
|
|
5
|
+
export declare function getSystemLanguage(): string;
|
|
6
|
+
export declare function getLanguageInstruction(): string;
|
package/dist/utils/paths.js
CHANGED
|
@@ -4,3 +4,31 @@ export const KIMI_DIR = join(homedir(), '.kimi');
|
|
|
4
4
|
export const KIMI_CONFIG = join(KIMI_DIR, 'config.toml');
|
|
5
5
|
export const HAKIMI_DIR = join(homedir(), '.hakimi');
|
|
6
6
|
export const HAKIMI_CONFIG = join(HAKIMI_DIR, 'config.toml');
|
|
7
|
+
export function getSystemLanguage() {
|
|
8
|
+
const lang = process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || 'en';
|
|
9
|
+
// Extract language code (e.g., "zh_CN.UTF-8" -> "zh_CN", "en_US.UTF-8" -> "en_US")
|
|
10
|
+
const match = lang.match(/^([a-z]{2}(?:_[A-Z]{2})?)/i);
|
|
11
|
+
return match ? match[1] : 'en';
|
|
12
|
+
}
|
|
13
|
+
export function getLanguageInstruction() {
|
|
14
|
+
const lang = getSystemLanguage();
|
|
15
|
+
if (lang.startsWith('zh')) {
|
|
16
|
+
return 'Please respond in Chinese (中文).';
|
|
17
|
+
}
|
|
18
|
+
else if (lang.startsWith('ja')) {
|
|
19
|
+
return 'Please respond in Japanese (日本語).';
|
|
20
|
+
}
|
|
21
|
+
else if (lang.startsWith('ko')) {
|
|
22
|
+
return 'Please respond in Korean (한국어).';
|
|
23
|
+
}
|
|
24
|
+
else if (lang.startsWith('es')) {
|
|
25
|
+
return 'Please respond in Spanish (Español).';
|
|
26
|
+
}
|
|
27
|
+
else if (lang.startsWith('fr')) {
|
|
28
|
+
return 'Please respond in French (Français).';
|
|
29
|
+
}
|
|
30
|
+
else if (lang.startsWith('de')) {
|
|
31
|
+
return 'Please respond in German (Deutsch).';
|
|
32
|
+
}
|
|
33
|
+
return 'Please respond in the user\'s language.';
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hakimi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Chat with AI assistant via Telegram/Slack/Feishu to remotely control your computer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -55,4 +55,4 @@
|
|
|
55
55
|
"tsx": "^4.21.0",
|
|
56
56
|
"typescript": "^5.9.3"
|
|
57
57
|
}
|
|
58
|
-
}
|
|
58
|
+
}
|
package/prompts/config-agent.md
CHANGED
|
@@ -41,6 +41,7 @@ Documentation:
|
|
|
41
41
|
- Koishi Slack Adapter: https://koishi.chat/plugins/adapter/slack.html
|
|
42
42
|
|
|
43
43
|
Required configuration:
|
|
44
|
+
- `protocol`: Always use `"ws"` (WebSocket mode via Socket Mode)
|
|
44
45
|
- `token`: App-level token (starts with `xapp-`)
|
|
45
46
|
- `botToken`: Bot user OAuth token (starts with `xoxb-`)
|
|
46
47
|
|
|
@@ -49,9 +50,12 @@ Optional:
|
|
|
49
50
|
|
|
50
51
|
To get these tokens:
|
|
51
52
|
1. Go to https://api.slack.com/apps and create a new app
|
|
52
|
-
2.
|
|
53
|
-
3. Under "
|
|
54
|
-
4. Under "
|
|
53
|
+
2. Enable Socket Mode under "Socket Mode" settings
|
|
54
|
+
3. Under "Basic Information", generate an App-Level Token with `connections:write` scope
|
|
55
|
+
4. Under "OAuth & Permissions", install the app and copy the Bot User OAuth Token
|
|
56
|
+
5. Under "Basic Information", find the Signing Secret (optional)
|
|
57
|
+
|
|
58
|
+
**Always use `protocol: "ws"` for Slack.**
|
|
55
59
|
|
|
56
60
|
### Feishu (Lark)
|
|
57
61
|
|
|
@@ -61,12 +65,16 @@ Documentation:
|
|
|
61
65
|
- Koishi Lark Adapter: https://koishi.chat/plugins/adapter/lark.html
|
|
62
66
|
|
|
63
67
|
Required configuration:
|
|
68
|
+
- `protocol`: Always use `"ws"` (WebSocket mode)
|
|
64
69
|
- `appId`: Application ID
|
|
65
70
|
- `appSecret`: Application Secret
|
|
66
71
|
|
|
67
72
|
To get these:
|
|
68
73
|
1. Go to https://open.feishu.cn and create an application
|
|
69
74
|
2. Find the App ID and App Secret in the application credentials
|
|
75
|
+
3. Enable "Events" and configure event subscription
|
|
76
|
+
|
|
77
|
+
**Always use `protocol: "ws"` for Feishu.**
|
|
70
78
|
|
|
71
79
|
## Instructions
|
|
72
80
|
|