casabot 1.0.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.
Files changed (61) hide show
  1. package/.github/workflows/publish.yml +28 -0
  2. package/LICENSE +190 -0
  3. package/README.md +112 -0
  4. package/dist/agent/base.d.ts +5 -0
  5. package/dist/agent/base.js +82 -0
  6. package/dist/agent/tools.d.ts +4 -0
  7. package/dist/agent/tools.js +36 -0
  8. package/dist/cli/index.d.ts +3 -0
  9. package/dist/cli/index.js +70 -0
  10. package/dist/cli/setup.d.ts +2 -0
  11. package/dist/cli/setup.js +356 -0
  12. package/dist/config/manager.d.ts +14 -0
  13. package/dist/config/manager.js +46 -0
  14. package/dist/config/types.d.ts +38 -0
  15. package/dist/config/types.js +2 -0
  16. package/dist/history/store.d.ts +7 -0
  17. package/dist/history/store.js +52 -0
  18. package/dist/index.d.ts +9 -0
  19. package/dist/index.js +7 -0
  20. package/dist/providers/anthropic.d.ts +10 -0
  21. package/dist/providers/anthropic.js +98 -0
  22. package/dist/providers/base.d.ts +11 -0
  23. package/dist/providers/base.js +2 -0
  24. package/dist/providers/custom.d.ts +4 -0
  25. package/dist/providers/custom.js +9 -0
  26. package/dist/providers/huggingface.d.ts +6 -0
  27. package/dist/providers/huggingface.js +8 -0
  28. package/dist/providers/index.d.ts +5 -0
  29. package/dist/providers/index.js +25 -0
  30. package/dist/providers/openai.d.ts +10 -0
  31. package/dist/providers/openai.js +76 -0
  32. package/dist/providers/openrouter.d.ts +6 -0
  33. package/dist/providers/openrouter.js +8 -0
  34. package/dist/skills/loader.d.ts +4 -0
  35. package/dist/skills/loader.js +48 -0
  36. package/dist/tui/app.d.ts +4 -0
  37. package/dist/tui/app.js +88 -0
  38. package/package.json +40 -0
  39. package/skills/agent/SKILL.md +180 -0
  40. package/skills/chat/SKILL.md +165 -0
  41. package/skills/config/SKILL.md +168 -0
  42. package/skills/memory/SKILL.md +245 -0
  43. package/skills/service/SKILL.md +224 -0
  44. package/src/agent/base.ts +98 -0
  45. package/src/agent/tools.ts +40 -0
  46. package/src/cli/index.ts +81 -0
  47. package/src/cli/setup.ts +378 -0
  48. package/src/config/manager.ts +53 -0
  49. package/src/config/types.ts +49 -0
  50. package/src/history/store.ts +59 -0
  51. package/src/index.ts +22 -0
  52. package/src/providers/anthropic.ts +115 -0
  53. package/src/providers/base.ts +12 -0
  54. package/src/providers/custom.ts +11 -0
  55. package/src/providers/huggingface.ts +10 -0
  56. package/src/providers/index.ts +29 -0
  57. package/src/providers/openai.ts +87 -0
  58. package/src/providers/openrouter.ts +10 -0
  59. package/src/skills/loader.ts +52 -0
  60. package/src/tui/app.tsx +158 -0
  61. package/tsconfig.json +20 -0
@@ -0,0 +1,356 @@
1
+ import { createInterface } from "readline";
2
+ import { ensureDirectories, saveConfig, loadConfig, PATHS } from "../config/manager.js";
3
+ import { writeFile, access } from "fs/promises";
4
+ import { join } from "path";
5
+ function askQuestion(rl, question) {
6
+ return new Promise((resolve) => {
7
+ rl.question(question, (answer) => {
8
+ resolve(answer.trim());
9
+ });
10
+ });
11
+ }
12
+ const PROVIDER_OPTIONS = [
13
+ { label: "OpenAI", type: "openai", defaultModel: "gpt-4o" },
14
+ { label: "Anthropic", type: "anthropic", defaultModel: "claude-sonnet-4-20250514" },
15
+ { label: "Hugging Face", type: "huggingface", defaultModel: "meta-llama/Meta-Llama-3-8B-Instruct" },
16
+ { label: "OpenRouter", type: "openrouter", defaultModel: "openai/gpt-4o" },
17
+ { label: "Custom (OpenAI 호환)", type: "custom-openai", defaultModel: "" },
18
+ { label: "Custom (Anthropic 호환)", type: "custom-anthropic", defaultModel: "" },
19
+ ];
20
+ async function installDefaultSkills() {
21
+ const defaultSkills = {
22
+ agent: {
23
+ name: "에이전트 생성 및 관리",
24
+ description: "base가 서브에이전트를 만들고 관리하기 위한 매뉴얼",
25
+ content: `# 에이전트 생성 및 관리
26
+
27
+ ## podman 설치
28
+ \`\`\`bash
29
+ # 설치 확인
30
+ which podman || sudo apt install -y podman
31
+ \`\`\`
32
+
33
+ ## podman 저장공간 설정
34
+ \`\`\`bash
35
+ # 저장 경로 확인
36
+ podman info --format '{{.Store.GraphRoot}}'
37
+ \`\`\`
38
+
39
+ ## 서브에이전트 컨테이너 생성
40
+ \`\`\`bash
41
+ # 새 에이전트 컨테이너 생성
42
+ podman run -d --name <agent-name> \\
43
+ -v ~/casabot/workspaces/<agent-name>:/workspace \\
44
+ -v ~/casabot/skills:/skills:ro \\
45
+ node:20-slim sleep infinity
46
+
47
+ # 에이전트 스크립트 복사 및 실행
48
+ podman cp <script-path> <agent-name>:/workspace/agent.js
49
+ podman exec <agent-name> node /workspace/agent.js
50
+ \`\`\`
51
+
52
+ ## 공급자 설정 전달
53
+ \`\`\`bash
54
+ # 환경변수로 API 키 전달
55
+ podman exec -e API_KEY=<key> -e MODEL=<model> <agent-name> node /workspace/agent.js
56
+ \`\`\`
57
+
58
+ ## 스킬 전달
59
+ 컨테이너 생성 시 \`-v ~/casabot/skills:/skills:ro\`로 마운트하면 에이전트가 스킬을 읽을 수 있습니다.
60
+
61
+ ## 에이전트 목록 조회
62
+ \`\`\`bash
63
+ podman ps --filter "label=casabot" --format "{{.Names}}\\t{{.Status}}"
64
+ \`\`\`
65
+
66
+ ## 에이전트 파괴 및 정리
67
+ \`\`\`bash
68
+ podman stop <agent-name> && podman rm <agent-name>
69
+ # 워크스페이스도 정리할 경우:
70
+ rm -rf ~/casabot/workspaces/<agent-name>
71
+ \`\`\`
72
+
73
+ ## 작업 위임
74
+ \`\`\`bash
75
+ # 에이전트에 작업 전달 (stdin으로)
76
+ echo "<task-description>" | podman exec -i <agent-name> node /workspace/agent.js
77
+ \`\`\`
78
+
79
+ ## 결과 수집
80
+ \`\`\`bash
81
+ # 에이전트 출력 확인
82
+ podman logs <agent-name>
83
+ # 워크스페이스 결과 파일 확인
84
+ ls ~/casabot/workspaces/<agent-name>/output/
85
+ \`\`\``,
86
+ },
87
+ config: {
88
+ name: "CasAbot 설정",
89
+ description: "CasAbot 자체의 구조와 설정을 이해하기 위한 매뉴얼",
90
+ content: `# CasAbot 설정
91
+
92
+ ## 디렉토리 구조
93
+ \`\`\`
94
+ ~/casabot/
95
+ ├── casabot.json # 모든 설정
96
+ ├── skills/ # 스킬 디렉토리 (SKILL.md 포함)
97
+ │ ├── agent/
98
+ │ ├── config/
99
+ │ ├── chat/
100
+ │ ├── service/
101
+ │ └── memory/
102
+ ├── workspaces/ # 에이전트별 워크스페이스
103
+ ├── history/ # 대화 전체 기록 (원본 로그)
104
+ └── memory/ # 에이전트가 직접 작성한 메모 (.md)
105
+ \`\`\`
106
+
107
+ ## casabot.json 스키마
108
+ \`\`\`json
109
+ {
110
+ "providers": [
111
+ {
112
+ "name": "공급자 이름",
113
+ "type": "openai | anthropic | huggingface | openrouter | custom-openai | custom-anthropic",
114
+ "apiKey": "API 키",
115
+ "endpoint": "커스텀 엔드포인트 (선택)",
116
+ "model": "모델 이름",
117
+ "isDefault": true
118
+ }
119
+ ],
120
+ "activeProvider": "활성 공급자 이름",
121
+ "baseModel": "기본 모델 이름"
122
+ }
123
+ \`\`\`
124
+
125
+ ## 공급자 추가 방법
126
+ casabot.json의 providers 배열에 새 항목을 추가합니다:
127
+ \`\`\`bash
128
+ # casabot.json 편집
129
+ cat ~/casabot/casabot.json | jq '.providers += [{"name":"new","type":"openai","apiKey":"sk-...","model":"gpt-4o","isDefault":false}]' > /tmp/casabot.json && mv /tmp/casabot.json ~/casabot/casabot.json
130
+ \`\`\`
131
+
132
+ ## 공급자 변경 방법
133
+ activeProvider 값을 변경합니다:
134
+ \`\`\`bash
135
+ cat ~/casabot/casabot.json | jq '.activeProvider = "new-provider-name"' > /tmp/casabot.json && mv /tmp/casabot.json ~/casabot/casabot.json
136
+ \`\`\``,
137
+ },
138
+ chat: {
139
+ name: "대화 관리",
140
+ description: "대화 세션을 관리하고 외부 서비스와 연동하기 위한 매뉴얼",
141
+ content: `# 대화 관리
142
+
143
+ ## 대화 세션 관리
144
+ 대화 기록은 ~/casabot/history/ 에 JSON 파일로 저장됩니다.
145
+
146
+ ## 대화 불러오기
147
+ \`\`\`bash
148
+ # 최근 대화 목록
149
+ ls -lt ~/casabot/history/ | head -20
150
+
151
+ # 특정 대화 내용 보기
152
+ cat ~/casabot/history/<conversation-id>.json | jq '.messages[] | {role, content: .content[:100]}'
153
+ \`\`\`
154
+
155
+ ## 이전 대화 검색
156
+ \`\`\`bash
157
+ # 키워드로 대화 검색
158
+ grep -rl "검색어" ~/casabot/history/
159
+
160
+ # 특정 날짜 이후 대화
161
+ find ~/casabot/history/ -newer <date-reference-file> -name "*.json"
162
+ \`\`\`
163
+
164
+ ## 외부 서비스 연동
165
+ 외부 서비스(WhatsApp, Discord 등)와의 연동은 서브에이전트를 통해 처리합니다:
166
+ 1. 연동 서브에이전트를 생성합니다 (agent 스킬 참조)
167
+ 2. 해당 서비스의 API/봇을 설정합니다
168
+ 3. 메시지를 수신하면 base에게 전달하고, 응답을 서비스로 보냅니다`,
169
+ },
170
+ service: {
171
+ name: "시스템 서비스 등록",
172
+ description: "자동 시작 및 서비스 연동을 설정하기 위한 매뉴얼",
173
+ content: `# 시스템 서비스 등록
174
+
175
+ ## base 자동 시작 (systemd)
176
+ \`\`\`bash
177
+ # systemd 서비스 파일 생성
178
+ cat > ~/.config/systemd/user/casabot.service << 'EOF'
179
+ [Unit]
180
+ Description=CasAbot Base Agent
181
+ After=network.target
182
+
183
+ [Service]
184
+ Type=simple
185
+ ExecStart=/usr/bin/env casabot
186
+ Restart=on-failure
187
+ RestartSec=10
188
+ WorkingDirectory=%h/casabot
189
+
190
+ [Install]
191
+ WantedBy=default.target
192
+ EOF
193
+
194
+ # 서비스 활성화 및 시작
195
+ systemctl --user daemon-reload
196
+ systemctl --user enable casabot
197
+ systemctl --user start casabot
198
+ \`\`\`
199
+
200
+ ## 서비스 상태 확인
201
+ \`\`\`bash
202
+ systemctl --user status casabot
203
+ journalctl --user -u casabot -f
204
+ \`\`\`
205
+
206
+ ## 특정 에이전트 자동 시작
207
+ 에이전트 컨테이너에 \`--restart=always\` 옵션을 추가합니다:
208
+ \`\`\`bash
209
+ podman run -d --restart=always --name <agent-name> ...
210
+ \`\`\`
211
+
212
+ ## 외부 서비스 연동 자동화
213
+ cron 또는 systemd timer를 사용하여 주기적 작업을 설정합니다:
214
+ \`\`\`bash
215
+ # crontab 편집
216
+ crontab -e
217
+ # 매 5분마다 모니터링 에이전트 실행
218
+ */5 * * * * podman exec monitor node /workspace/check.js
219
+ \`\`\``,
220
+ },
221
+ memory: {
222
+ name: "기록",
223
+ description: "base와 서브에이전트가 기록(memory)을 작성하고 조회하기 위한 매뉴얼",
224
+ content: `# 기록 (Memory)
225
+
226
+ ## 기억(History)과 기록(Memory)의 차이
227
+ - **기억 (History)**: ~/casabot/history/ — 대화 전체의 원본 로그 (자동 저장, 수정 불가)
228
+ - **기록 (Memory)**: ~/casabot/memory/ — 에이전트가 직접 작성한 메모 (.md 파일)
229
+
230
+ ## 기록 파일 위치
231
+ ~/casabot/memory/
232
+
233
+ ## 기록 작성 규칙
234
+ - 파일 형식: 마크다운 (.md)
235
+ - 파일명: \`YYYY-MM-DD-주제.md\` 또는 \`주제.md\`
236
+ - 내용: 자유 형식이나 다음을 포함하면 좋음:
237
+ - 날짜/시간
238
+ - 작성자 (어떤 에이전트가 작성했는지)
239
+ - 요약
240
+ - 상세 내용
241
+
242
+ ### 기록 작성 예시
243
+ \`\`\`bash
244
+ cat > ~/casabot/memory/2024-01-15-프로젝트-분석.md << 'EOF'
245
+ # 프로젝트 분석 결과
246
+ - 작성자: code-reviewer
247
+ - 날짜: 2024-01-15
248
+
249
+ ## 요약
250
+ 사용자의 프로젝트 코드를 분석한 결과...
251
+
252
+ ## 상세
253
+ ...
254
+ EOF
255
+ \`\`\`
256
+
257
+ ## 기록 조회 및 검색
258
+ \`\`\`bash
259
+ # 전체 기록 목록
260
+ ls -lt ~/casabot/memory/
261
+
262
+ # 키워드 검색
263
+ grep -rl "검색어" ~/casabot/memory/
264
+
265
+ # 특정 기록 읽기
266
+ cat ~/casabot/memory/<filename>.md
267
+ \`\`\``,
268
+ },
269
+ };
270
+ for (const [dir, skill] of Object.entries(defaultSkills)) {
271
+ const skillPath = join(PATHS.skills, dir, "SKILL.md");
272
+ const exists = await access(skillPath).then(() => true).catch(() => false);
273
+ if (exists)
274
+ continue;
275
+ const content = `---
276
+ name: ${skill.name}
277
+ description: ${skill.description}
278
+ metadata:
279
+ casabot:
280
+ requires:
281
+ bins: []
282
+ ---
283
+
284
+ ${skill.content}
285
+ `;
286
+ await writeFile(skillPath, content, "utf-8");
287
+ }
288
+ }
289
+ export async function setupWizard() {
290
+ const rl = createInterface({
291
+ input: process.stdin,
292
+ output: process.stdout,
293
+ });
294
+ try {
295
+ console.log("\n🌟 CasAbot 설정을 시작합니다.\n");
296
+ console.log("공급자를 선택하세요:");
297
+ PROVIDER_OPTIONS.forEach((opt, i) => {
298
+ console.log(` ${i + 1}. ${opt.label}`);
299
+ });
300
+ const choiceStr = await askQuestion(rl, `\n선택 (1-${PROVIDER_OPTIONS.length}): `);
301
+ const choice = parseInt(choiceStr, 10) - 1;
302
+ if (choice < 0 || choice >= PROVIDER_OPTIONS.length) {
303
+ console.error("❌ 잘못된 선택입니다.");
304
+ return;
305
+ }
306
+ const selected = PROVIDER_OPTIONS[choice];
307
+ const apiKey = await askQuestion(rl, "API Key: ");
308
+ if (!apiKey) {
309
+ console.error("❌ API Key는 필수입니다.");
310
+ return;
311
+ }
312
+ let endpoint;
313
+ if (selected.type === "custom-openai" || selected.type === "custom-anthropic") {
314
+ endpoint = await askQuestion(rl, "엔드포인트 URL: ");
315
+ if (!endpoint) {
316
+ console.error("❌ 커스텀 공급자는 엔드포인트가 필수입니다.");
317
+ return;
318
+ }
319
+ }
320
+ const defaultModelHint = selected.defaultModel ? ` (기본: ${selected.defaultModel})` : "";
321
+ const modelInput = await askQuestion(rl, `모델${defaultModelHint}: `);
322
+ const model = modelInput || selected.defaultModel;
323
+ if (!model) {
324
+ console.error("❌ 모델 이름은 필수입니다.");
325
+ return;
326
+ }
327
+ const nameInput = await askQuestion(rl, `공급자 이름 (기본: ${selected.type}): `);
328
+ const providerName = nameInput || selected.type;
329
+ const providerConfig = {
330
+ name: providerName,
331
+ type: selected.type,
332
+ apiKey,
333
+ model,
334
+ isDefault: true,
335
+ ...(endpoint ? { endpoint } : {}),
336
+ };
337
+ await ensureDirectories();
338
+ const config = await loadConfig();
339
+ config.providers = config.providers.filter((p) => p.name !== providerName);
340
+ config.providers.push(providerConfig);
341
+ config.activeProvider = providerName;
342
+ config.baseModel = model;
343
+ await saveConfig(config);
344
+ console.log("\n📦 기본 스킬을 설치합니다...");
345
+ await installDefaultSkills();
346
+ console.log("\n✅ 설정이 완료되었습니다!");
347
+ console.log(` 공급자: ${providerName} (${selected.label})`);
348
+ console.log(` 모델: ${model}`);
349
+ console.log(` 설정 파일: ~/casabot/casabot.json`);
350
+ console.log("\n'casabot' 명령어로 시작하세요.\n");
351
+ }
352
+ finally {
353
+ rl.close();
354
+ }
355
+ }
356
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,14 @@
1
+ import type { CasabotConfig } from "./types.js";
2
+ export declare const CASABOT_HOME: string;
3
+ export declare const PATHS: {
4
+ readonly config: string;
5
+ readonly skills: string;
6
+ readonly workspaces: string;
7
+ readonly history: string;
8
+ readonly memory: string;
9
+ };
10
+ export declare function getDefaultConfig(): CasabotConfig;
11
+ export declare function ensureDirectories(): Promise<void>;
12
+ export declare function loadConfig(): Promise<CasabotConfig>;
13
+ export declare function saveConfig(config: CasabotConfig): Promise<void>;
14
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1,46 @@
1
+ import { readFile, writeFile, mkdir } from "fs/promises";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ export const CASABOT_HOME = join(homedir(), "casabot");
5
+ export const PATHS = {
6
+ config: join(CASABOT_HOME, "casabot.json"),
7
+ skills: join(CASABOT_HOME, "skills"),
8
+ workspaces: join(CASABOT_HOME, "workspaces"),
9
+ history: join(CASABOT_HOME, "history"),
10
+ memory: join(CASABOT_HOME, "memory"),
11
+ };
12
+ const SKILL_DIRS = ["agent", "config", "chat", "service", "memory"];
13
+ export function getDefaultConfig() {
14
+ return {
15
+ providers: [],
16
+ activeProvider: "",
17
+ baseModel: "",
18
+ };
19
+ }
20
+ export async function ensureDirectories() {
21
+ const dirs = [
22
+ CASABOT_HOME,
23
+ PATHS.skills,
24
+ PATHS.workspaces,
25
+ PATHS.history,
26
+ PATHS.memory,
27
+ ...SKILL_DIRS.map((d) => join(PATHS.skills, d)),
28
+ ];
29
+ for (const dir of dirs) {
30
+ await mkdir(dir, { recursive: true });
31
+ }
32
+ }
33
+ export async function loadConfig() {
34
+ try {
35
+ const raw = await readFile(PATHS.config, "utf-8");
36
+ return JSON.parse(raw);
37
+ }
38
+ catch {
39
+ return getDefaultConfig();
40
+ }
41
+ }
42
+ export async function saveConfig(config) {
43
+ await ensureDirectories();
44
+ await writeFile(PATHS.config, JSON.stringify(config, null, 2), "utf-8");
45
+ }
46
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1,38 @@
1
+ export type ProviderType = "openai" | "anthropic" | "huggingface" | "openrouter" | "custom-openai" | "custom-anthropic";
2
+ export interface ProviderConfig {
3
+ name: string;
4
+ type: ProviderType;
5
+ apiKey: string;
6
+ endpoint?: string;
7
+ model: string;
8
+ isDefault: boolean;
9
+ }
10
+ export interface CasabotConfig {
11
+ providers: ProviderConfig[];
12
+ activeProvider: string;
13
+ baseModel: string;
14
+ }
15
+ export interface Skill {
16
+ name: string;
17
+ description: string;
18
+ metadata: Record<string, unknown>;
19
+ instructions: string;
20
+ path: string;
21
+ }
22
+ export interface ToolCall {
23
+ id: string;
24
+ name: string;
25
+ arguments: string;
26
+ }
27
+ export interface Message {
28
+ role: "user" | "assistant" | "system" | "tool";
29
+ content: string;
30
+ toolCalls?: ToolCall[];
31
+ toolCallId?: string;
32
+ }
33
+ export interface ConversationHistory {
34
+ id: string;
35
+ startedAt: string;
36
+ messages: Message[];
37
+ }
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ import type { ConversationHistory, Message } from "../config/types.js";
2
+ export declare function createConversation(): ConversationHistory;
3
+ export declare function saveConversation(conversation: ConversationHistory): Promise<void>;
4
+ export declare function loadConversation(id: string): Promise<ConversationHistory | null>;
5
+ export declare function listConversations(): Promise<ConversationHistory[]>;
6
+ export declare function appendMessage(conversation: ConversationHistory, message: Message): Promise<void>;
7
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { readFile, writeFile, readdir } from "fs/promises";
2
+ import { join } from "path";
3
+ import { randomUUID } from "crypto";
4
+ import { PATHS } from "../config/manager.js";
5
+ export function createConversation() {
6
+ return {
7
+ id: randomUUID(),
8
+ startedAt: new Date().toISOString(),
9
+ messages: [],
10
+ };
11
+ }
12
+ function historyPath(id) {
13
+ return join(PATHS.history, `${id}.json`);
14
+ }
15
+ export async function saveConversation(conversation) {
16
+ const filePath = historyPath(conversation.id);
17
+ await writeFile(filePath, JSON.stringify(conversation, null, 2), "utf-8");
18
+ }
19
+ export async function loadConversation(id) {
20
+ try {
21
+ const raw = await readFile(historyPath(id), "utf-8");
22
+ return JSON.parse(raw);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ export async function listConversations() {
29
+ let files;
30
+ try {
31
+ files = await readdir(PATHS.history);
32
+ }
33
+ catch {
34
+ return [];
35
+ }
36
+ const conversations = [];
37
+ for (const file of files) {
38
+ if (!file.endsWith(".json"))
39
+ continue;
40
+ const raw = await readFile(join(PATHS.history, file), "utf-8").catch(() => null);
41
+ if (!raw)
42
+ continue;
43
+ conversations.push(JSON.parse(raw));
44
+ }
45
+ conversations.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
46
+ return conversations;
47
+ }
48
+ export async function appendMessage(conversation, message) {
49
+ conversation.messages.push(message);
50
+ await saveConversation(conversation);
51
+ }
52
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1,9 @@
1
+ export type { ProviderType, ProviderConfig, CasabotConfig, Skill, Message, ToolCall, ConversationHistory, } from "./config/types.js";
2
+ export { loadConfig, saveConfig, ensureDirectories, CASABOT_HOME, PATHS } from "./config/manager.js";
3
+ export { createProvider } from "./providers/index.js";
4
+ export type { ChatProvider, ToolDefinition } from "./providers/base.js";
5
+ export { loadSkills, formatSkillsForPrompt } from "./skills/loader.js";
6
+ export { createConversation, saveConversation, loadConversation, listConversations, } from "./history/store.js";
7
+ export { runAgent, buildSystemPrompt } from "./agent/base.js";
8
+ export { startTUI } from "./tui/app.js";
9
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { loadConfig, saveConfig, ensureDirectories, CASABOT_HOME, PATHS } from "./config/manager.js";
2
+ export { createProvider } from "./providers/index.js";
3
+ export { loadSkills, formatSkillsForPrompt } from "./skills/loader.js";
4
+ export { createConversation, saveConversation, loadConversation, listConversations, } from "./history/store.js";
5
+ export { runAgent, buildSystemPrompt } from "./agent/base.js";
6
+ export { startTUI } from "./tui/app.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ import type { Message, ProviderConfig } from "../config/types.js";
2
+ import type { ChatProvider, ToolDefinition } from "./base.js";
3
+ export declare class AnthropicProvider implements ChatProvider {
4
+ readonly name: string;
5
+ private client;
6
+ private model;
7
+ constructor(config: ProviderConfig);
8
+ chat(messages: Message[], tools: ToolDefinition[]): Promise<Message>;
9
+ }
10
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1,98 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ function toAnthropicMessages(messages) {
3
+ let system = "";
4
+ const msgs = [];
5
+ for (const msg of messages) {
6
+ if (msg.role === "system") {
7
+ system += (system ? "\n\n" : "") + msg.content;
8
+ continue;
9
+ }
10
+ if (msg.role === "assistant" && msg.toolCalls?.length) {
11
+ const content = [];
12
+ if (msg.content) {
13
+ content.push({ type: "text", text: msg.content });
14
+ }
15
+ for (const tc of msg.toolCalls) {
16
+ content.push({
17
+ type: "tool_use",
18
+ id: tc.id,
19
+ name: tc.name,
20
+ input: JSON.parse(tc.arguments),
21
+ });
22
+ }
23
+ msgs.push({ role: "assistant", content });
24
+ continue;
25
+ }
26
+ if (msg.role === "tool") {
27
+ msgs.push({
28
+ role: "user",
29
+ content: [
30
+ {
31
+ type: "tool_result",
32
+ tool_use_id: msg.toolCallId,
33
+ content: msg.content,
34
+ },
35
+ ],
36
+ });
37
+ continue;
38
+ }
39
+ msgs.push({
40
+ role: msg.role,
41
+ content: msg.content,
42
+ });
43
+ }
44
+ return { system, msgs };
45
+ }
46
+ function toAnthropicTools(tools) {
47
+ return tools.map((t) => ({
48
+ name: t.name,
49
+ description: t.description,
50
+ input_schema: t.parameters,
51
+ }));
52
+ }
53
+ export class AnthropicProvider {
54
+ name;
55
+ client;
56
+ model;
57
+ constructor(config) {
58
+ this.name = config.name;
59
+ this.model = config.model;
60
+ this.client = new Anthropic({
61
+ apiKey: config.apiKey,
62
+ ...(config.endpoint ? { baseURL: config.endpoint } : {}),
63
+ });
64
+ }
65
+ async chat(messages, tools) {
66
+ const { system, msgs } = toAnthropicMessages(messages);
67
+ const response = await this.client.messages.create({
68
+ model: this.model,
69
+ max_tokens: 4096,
70
+ ...(system ? { system } : {}),
71
+ messages: msgs,
72
+ ...(tools.length > 0 ? { tools: toAnthropicTools(tools) } : {}),
73
+ });
74
+ let textContent = "";
75
+ const toolCalls = [];
76
+ for (const block of response.content) {
77
+ if (block.type === "text") {
78
+ textContent += block.text;
79
+ }
80
+ else if (block.type === "tool_use") {
81
+ toolCalls.push({
82
+ id: block.id,
83
+ name: block.name,
84
+ arguments: JSON.stringify(block.input),
85
+ });
86
+ }
87
+ }
88
+ const result = {
89
+ role: "assistant",
90
+ content: textContent,
91
+ };
92
+ if (toolCalls.length > 0) {
93
+ result.toolCalls = toolCalls;
94
+ }
95
+ return result;
96
+ }
97
+ }
98
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1,11 @@
1
+ import type { Message } from "../config/types.js";
2
+ export interface ToolDefinition {
3
+ name: string;
4
+ description: string;
5
+ parameters: Record<string, unknown>;
6
+ }
7
+ export interface ChatProvider {
8
+ readonly name: string;
9
+ chat(messages: Message[], tools: ToolDefinition[]): Promise<Message>;
10
+ }
11
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1,4 @@
1
+ import type { ProviderConfig } from "../config/types.js";
2
+ import type { ChatProvider } from "./base.js";
3
+ export declare function createCustomProvider(config: ProviderConfig): ChatProvider;
4
+ //# sourceMappingURL=custom.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { OpenAIProvider } from "./openai.js";
2
+ import { AnthropicProvider } from "./anthropic.js";
3
+ export function createCustomProvider(config) {
4
+ if (config.type === "custom-anthropic") {
5
+ return new AnthropicProvider(config);
6
+ }
7
+ return new OpenAIProvider(config);
8
+ }
9
+ //# sourceMappingURL=custom.js.map