diff --git a/.smallclaw/users/cherry/sessions/chat_34b3twqadtf.json b/.smallclaw/users/cherry/sessions/chat_34b3twqadtf.json new file mode 100644 index 0000000..e08fc0d --- /dev/null +++ b/.smallclaw/users/cherry/sessions/chat_34b3twqadtf.json @@ -0,0 +1,11 @@ +{ + "id": "chat_34b3twqadtf", + "username": "cherry", + "history": [], + "workspace": "/home/kim/homeclaw/.smallclaw/users/cherry/workspace", + "createdAt": 1777557605647, + "lastActiveAt": 1777557605647, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 0 +} \ No newline at end of file diff --git a/.smallclaw/users/cherry/sessions/chat_kxljz0acngo.json b/.smallclaw/users/cherry/sessions/chat_kxljz0acngo.json new file mode 100644 index 0000000..9fd369a --- /dev/null +++ b/.smallclaw/users/cherry/sessions/chat_kxljz0acngo.json @@ -0,0 +1,11 @@ +{ + "id": "chat_kxljz0acngo", + "username": "cherry", + "history": [], + "workspace": "/home/kim/homeclaw/.smallclaw/users/cherry/workspace", + "createdAt": 1777558178534, + "lastActiveAt": 1777558178534, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 0 +} \ No newline at end of file diff --git a/.smallclaw/users/cherry/sessions/ebe74a5d-31cd-420b-8441-456bd2aba571.json b/.smallclaw/users/cherry/sessions/ebe74a5d-31cd-420b-8441-456bd2aba571.json new file mode 100644 index 0000000..1ff3c91 --- /dev/null +++ b/.smallclaw/users/cherry/sessions/ebe74a5d-31cd-420b-8441-456bd2aba571.json @@ -0,0 +1,32 @@ +{ + "id": "ebe74a5d-31cd-420b-8441-456bd2aba571", + "username": "cherry", + "history": [ + { + "role": "user", + "content": "[1777536817652-_______________.pdf]([REDACTED-HE].pdf)\n\n**[PDF 내용 — 1페이지]**\n\n제 2 4 기 2 0 2 4 년 1 2 월 3 1 일 현 재 제 2 3 기 2 0 2 3 년 1 2 월 3 1 일 현 재 재 무 상 태 표 회 사 명 : 김 상 규 연 합 치 과 의 원 ( 단 위 : 원 ) 과 목 제 2 4 ( 당 ) 기 제 2 3 ( 전 ) 기 금 액 금 액 자 산 Ⅰ . 유 동 자 산 9 , 7 0 4 , 8 6 7 9 , 7 6 1 , 1 0 5 ( 1 ) 당 좌 자 산 9 , 7 0 4 , 8 6 7 9 , 7 6 1 , 1 0 5 현 금 1 , 3 4 4 , 4 3 7 1 , 4 7 0 , 2 1 5 미 수 금 8 , 3 6 0 , 4 3 0 8 , 2 9 0 , 8 9 0 ( 2 ) 재 고 자 산 0 0 Ⅱ . 비 유 동 자 산 1 1 7 , 0 7 5 , 1 7 7 1 2 2 , 4 9 4 , 8 8 2 ( 1 ) 투 자 자 산 0 0 ( 2 ) 유 형 자 산 1 7 , 0 7 5 , 1 7 7 2 2 , 4 9 4 , 8 8 2 의 료 기 기 3 0 8 , 0 2 6 , 5 0 0 3 0 0 , 9 2 6 , 5 0 0 감 가 상 각 누 계 액 2 9 1 , 5 8 7 , 1 5 4 1 6 , 4 3 9 , 3 4 6 2 7 9 , 5 6 2 , 6 7 0 2 1 , 3 6 3 , 8 3 0 차 량 운 반 구 2 7 , 0 0 0 , 0 0 0 2 7 , 0 0 0 , 0 0 0 감 가 상 각 누 계 액 2 6 , 9 9 9 , 0 0 0 1 , 0 0 0 2 6 , 9 9 9 , 0 0 0 1 , 0 0 0 비 품 3 6 , 5 4 2 , 0 0 0 3 6 , 5 4 2 , 0 0 0 감 가 상 각 누 계 액 3 5 , 9 1 6 , 1 6 9 6 2 5 , 8 3 1 3 5 , 4 2 0 , 9 4 8 1 , 1 2 1 , 0 5 2 시 설 장 치 1 3 8 , 3 0 0 , 4 0 0 1 3 8 , 3 0 0 , 4 0 0 감 가 상 각 누 계 액 1 3 8 , 2 9 1 , 4 0 0 9 , 0 0 0 1 3 8 , 2 9 1 , 4 0 0 9 , 0 0 0 ( 3 ) 무 형 자 산 0 0 ( 4 ) 기 타 비 유 동 자 산 1 0 0 , 0 0 0 , 0 0 0 1 0 0 , 0 0 0 , 0 0 0 임 차 보 증 금 1 0 0 , 0 0 0 , 0 0 0 1 0 0 , 0 0 0 , 0 0 0 자 산 총 계 1 2 6 , 7 8 0 , 0 4 4 1 3 2 , 2 5 5 , 9 8 7 부 채 Ⅰ . 유 동 부 채 0 1 , 9 0 7 , 0 7 9 단 기 차 입 금 0 1 , 9 0 7 , 0 7 9 Ⅱ . 비 유 동 부 채 0 0 부 채 총 계 1 , 9 0 7 , 0 7 9 자 본 Ⅰ . 자 본 금 1 2 6 , 7 8 0 , 0 4 4 1 3 0 , 3 4 8 , 9 0 8 자 본 금 1 2 6 , 7 8 0 , 0 4 4 1 3 0 , 3 4 8 , 9 0 8 ( 당 기 순 이 익 ) 당 기 : 9 9 , 4 3 1 , 1 3 6 원 전 기 : 1 0 4 , 8 6 6 , 8 0 6 원 자 본 총 계 1 2 6 , 7 8 0 , 0 4 4 1 3 0 , 3 4 8 , 9 0 8 부 채 및 자 본 총 계 1 2 6 , 7 8 0 , 0 4 4 1 3 2 , 2 5 5 , 9 8 7", + "timestamp": 1777558457685 + }, + { + "role": "assistant", + "content": "제24기(2024년)와 제23기(2023년) 재무상태표를 바탕으로 주요 지표를 요약해 드립니다.\n\n### **[김상규연합치과의원 재무 요약]**\n*단위: 원*\n\n| 항목 | 제24기 (2024년) | 제23기 (2023년) | 증감액 |\n| :--- | :---: | :---: | :---: |\n| **자산총계** | **126,780,044** | **132,255,987** | **-5,475,943** |\n| - 유동자산 | 9,704,867 | 9,761,105 | -56,238 |\n| - 비유동자산 | 117,075,177 | 122,494,882 | -5,419,705 |\n| **부채총계** | **0** | **1,907,079** | **-1,907,079** |\n| **자본총계** | **126,780,044** | **130,348,908** | **-3,568,864** |\n| **당기순이익** | **99,431,136** | **104,866,806** | **-5,435,670** |\n\n**주요 특징:**\n1. **부채 상환:** 전기에 있던 단기차입금(1,907,079원)을 모두 상환하여 부채가 0원이 되었습니다.\n2. **자산 감소:** 의료기기 등 유형자산의 감가상각으로 인해 비유동자산이 약 542만 원 감소하며 전체 자산 규모가 소폭 줄었습니다.\n3. **수익성:** 당기순이익은 약 9,943만 원으로 전년 대비 약 5.2% 감소했으나 여전히 안정적인 수익을 유지하고 있습니다.", + "timestamp": 1777558461694 + }, + { + "role": "user", + "content": "오늘 구미 날씨 어때?", + "timestamp": 1777559534761 + }, + { + "role": "assistant", + "content": "오늘(4월 30일) 구미는 낮 동안 최고 23도까지 올라가며 완연한 봄 날씨를 보이겠으나, 밤부터는 차차 흐려질 전망입니다. 최저 기온은 10도 안팎으로 일교차가 크니 옷차림에 유의하시기 바랍니다.", + "timestamp": 1777559546551 + } + ], + "workspace": "/home/kim/homeclaw/workspace", + "createdAt": 1777558344866, + "lastActiveAt": 1777559546551, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 903 +} \ No newline at end of file diff --git a/.smallclaw/users/papa/sessions/01e87a84-03ff-4a6a-9290-4689d99aaf5e.json b/.smallclaw/users/papa/sessions/01e87a84-03ff-4a6a-9290-4689d99aaf5e.json new file mode 100644 index 0000000..be5ddab --- /dev/null +++ b/.smallclaw/users/papa/sessions/01e87a84-03ff-4a6a-9290-4689d99aaf5e.json @@ -0,0 +1,22 @@ +{ + "id": "01e87a84-03ff-4a6a-9290-4689d99aaf5e", + "username": "papa", + "history": [ + { + "role": "user", + "content": "Hi", + "timestamp": 1777562658152 + }, + { + "role": "assistant", + "content": "Hello! How can I help you today?", + "timestamp": 1777562659780 + } + ], + "workspace": "/home/kim/homeclaw/workspace", + "createdAt": 1777562644087, + "lastActiveAt": 1777562659780, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 23 +} \ No newline at end of file diff --git a/.smallclaw/users/papa/sessions/7fef44b0-82d9-4fe7-89b3-368ffe081f05.json b/.smallclaw/users/papa/sessions/7fef44b0-82d9-4fe7-89b3-368ffe081f05.json new file mode 100644 index 0000000..b560eb1 --- /dev/null +++ b/.smallclaw/users/papa/sessions/7fef44b0-82d9-4fe7-89b3-368ffe081f05.json @@ -0,0 +1,82 @@ +{ + "id": "7fef44b0-82d9-4fe7-89b3-368ffe081f05", + "username": "papa", + "history": [ + { + "role": "user", + "content": "hi", + "timestamp": 1777554672211 + }, + { + "role": "assistant", + "content": "Hello! How can I help you today?", + "timestamp": 1777554673776 + }, + { + "role": "user", + "content": "who are you?", + "timestamp": 1777554687545 + }, + { + "role": "assistant", + "content": "I'm SmallClaw, your local AI assistant. I'm here to help you with research, coding, and automating tasks across your system.", + "timestamp": 1777554690225 + }, + { + "role": "user", + "content": "슬라이드 만들 수 있니?", + "timestamp": 1777554830403 + }, + { + "role": "assistant", + "content": "네, 가능합니다. 어떤 주제로 슬라이드를 만들고 싶으신가요? 주제와 포함하고 싶은 내용을 말씀해 주시면 바로 제작해 드릴게요.", + "timestamp": 1777554832303 + }, + { + "role": "user", + "content": "강아지 슬라이드 만들어 줘", + "timestamp": 1777554847595 + }, + { + "role": "assistant", + "content": "죄송합니다. 현재 시스템에 슬라이드 제작에 필요한 라이브러리(`python-pptx`)가 설치되어 있지 않아 제작에 어려움이 있습니다.\n\n직접 설치를 시도했으나 권한 및 환경 문제로 실패했습니다. 혹시 터미널에서 아래 명령어를 실행해 주실 수 있나요?\n\n```bash\nsudo apt update && sudo apt install python3-pptx\n```\n\n설치가 완료되면 다시 말씀해 주세요. 바로 멋진 강아지 슬라이드를 만들어 드리겠습니다!", + "timestamp": 1777554930211 + }, + { + "role": "user", + "content": "다시 시도해봐", + "timestamp": 1777555215443 + }, + { + "role": "assistant", + "content": "강아지 소개 슬라이드 제작을 완료했습니다. `강아지_소개_presentation` 폴더에서 확인하실 수 있습니다.", + "timestamp": 1777555220771 + }, + { + "role": "user", + "content": "고양이 사진 몇 장만 찾아 줘.", + "timestamp": 1777555566883 + }, + { + "role": "assistant", + "content": "귀여운 고양이 사진 몇 장을 찾아보았습니다:\n\n1. ![고양이 1](https://images.pexels.[REDACTED-HE].jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)\n2. ![고양이 2](https://images.pexels.com/photos/1170986/pexels-photo-1170986.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)\n3. ![고양이 3](https://images.pexels.[REDACTED-HE].jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)\n\n더 많은 사진이 필요하시면 말씀해 주세요!", + "timestamp": 1777555584729 + }, + { + "role": "user", + "content": "강아지 사진 몇 장 찾아줘.", + "timestamp": 1777555923232 + }, + { + "role": "assistant", + "content": "귀여운 강아지 사진 몇 장을 찾아보았습니다:\n\n1. ![강아지 1](https://images.pexels.com/photos/1108099/pexels-photo-1108099.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)\n2. ![강아지 2](https://images.pexels.com/photos/333083/pexels-photo-333083.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)\n3. ![강아지 3](https://images.pexels.com/photos/1254140/pexels-photo-1254140.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500)\n\n더 필요한 사진이 있으면 말씀해 주세요!", + "timestamp": 1777555982734 + } + ], + "workspace": "/home/kim/homeclaw/workspace", + "createdAt": 1777554638015, + "lastActiveAt": 1777555982734, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 500 +} \ No newline at end of file diff --git a/.smallclaw/users/papa/sessions/a4323d11-3330-498e-8542-69aceeba339d.json b/.smallclaw/users/papa/sessions/a4323d11-3330-498e-8542-69aceeba339d.json new file mode 100644 index 0000000..c1daac7 --- /dev/null +++ b/.smallclaw/users/papa/sessions/a4323d11-3330-498e-8542-69aceeba339d.json @@ -0,0 +1,52 @@ +{ + "id": "a4323d11-3330-498e-8542-69aceeba339d", + "username": "papa", + "history": [ + { + "role": "user", + "content": "Hi", + "timestamp": 1777561257199 + }, + { + "role": "assistant", + "content": "Hello! How can I help you today?", + "timestamp": 1777561258835 + }, + { + "role": "user", + "content": "![1775525820641.jpg]([REDACTED-HE].jpg)", + "timestamp": 1777561413133 + }, + { + "role": "assistant", + "content": "I see you've shared two identical images. How can I help you with them?", + "timestamp": 1777561414833 + }, + { + "role": "user", + "content": "Make brighter.", + "timestamp": 1777561467662 + }, + { + "role": "assistant", + "content": "I've brightened the image for you. You can find the new version at `[REDACTED-HE].jpg`.", + "timestamp": 1777561521584 + }, + { + "role": "user", + "content": "Make a download link.", + "timestamp": 1777561545763 + }, + { + "role": "assistant", + "content": "You can download the brightened image here: [brightened_1775525820641.jpg]([REDACTED-HE].jpg)", + "timestamp": 1777561562028 + } + ], + "workspace": "/home/kim/homeclaw/workspace", + "createdAt": 1777561222758, + "lastActiveAt": 1777561562029, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 178 +} \ No newline at end of file diff --git a/.smallclaw/users/papa/sessions/ade74005-d817-4ada-ad04-5715584a71c6.json b/.smallclaw/users/papa/sessions/ade74005-d817-4ada-ad04-5715584a71c6.json new file mode 100644 index 0000000..47c5246 --- /dev/null +++ b/.smallclaw/users/papa/sessions/ade74005-d817-4ada-ad04-5715584a71c6.json @@ -0,0 +1,22 @@ +{ + "id": "ade74005-d817-4ada-ad04-5715584a71c6", + "username": "papa", + "history": [ + { + "role": "user", + "content": "오늘 bbc 뉴스 정리", + "timestamp": 1777562199057 + }, + { + "role": "assistant", + "content": "2026년 5월 1일 주요 BBC 뉴스입니다.\n\n* **중동 긴장 고조:** 트럼프 대통령이 이란에 대한 '짧고 강력한' 타격 계획을 보고받을 예정이라는 소식에 국제 유가가 2022년 이후 최고치를 기록했습니다.\n* **가자 구호선 나포:** 이스라엘군이 크레타섬 인근에서 가자로 향하던 구호선 22척을 나포하고 활동가 175명을 구금했습니다.\n* **영국 왕실 동정:** 찰스 3세 국왕 부부가 미국 독립 250주년 축하 행사를 끝으로 4일간의 방미 일정을 마쳤으며, 트럼프 대통령이 작별 인사를 전했습니다.\n* **기타:** 런던에 새로 등장한 조각상이 본인의 작품임을 뱅크시가 확인했으며, 호주 아웃백에서는 실종된 5세 아동이 살해된 것으로 추정되는 시신으로 발견되었습니다.", + "timestamp": 1777562223847 + } + ], + "workspace": "/home/kim/homeclaw/workspace", + "createdAt": 1777560002619, + "lastActiveAt": 1777562223847, + "pendingMemoryFlush": false, + "pendingCompaction": false, + "contextTokenEstimate": 127 +} \ No newline at end of file diff --git a/.smallclaw/users/papa/workspace/uploads/1777558453079-1777536817652-_______________.pdf b/.smallclaw/users/papa/workspace/uploads/1777558453079-1777536817652-_______________.pdf new file mode 100644 index 0000000..96847af Binary files /dev/null and b/.smallclaw/users/papa/workspace/uploads/1777558453079-1777536817652-_______________.pdf differ diff --git a/.smallclaw/users/papa/workspace/uploads/1777558453462-1777536817652-_______________.txt b/.smallclaw/users/papa/workspace/uploads/1777558453462-1777536817652-_______________.txt new file mode 100644 index 0000000..44658c8 --- /dev/null +++ b/.smallclaw/users/papa/workspace/uploads/1777558453462-1777536817652-_______________.txt @@ -0,0 +1 @@ +제 2 4 기 2 0 2 4 년 1 2 월 3 1 일 현 재 제 2 3 기 2 0 2 3 년 1 2 월 3 1 일 현 재 재 무 상 태 표 회 사 명 : 김 상 규 연 합 치 과 의 원 ( 단 위 : 원 ) 과 목 제 2 4 ( 당 ) 기 제 2 3 ( 전 ) 기 금 액 금 액 자 산 Ⅰ . 유 동 자 산 9 , 7 0 4 , 8 6 7 9 , 7 6 1 , 1 0 5 ( 1 ) 당 좌 자 산 9 , 7 0 4 , 8 6 7 9 , 7 6 1 , 1 0 5 현 금 1 , 3 4 4 , 4 3 7 1 , 4 7 0 , 2 1 5 미 수 금 8 , 3 6 0 , 4 3 0 8 , 2 9 0 , 8 9 0 ( 2 ) 재 고 자 산 0 0 Ⅱ . 비 유 동 자 산 1 1 7 , 0 7 5 , 1 7 7 1 2 2 , 4 9 4 , 8 8 2 ( 1 ) 투 자 자 산 0 0 ( 2 ) 유 형 자 산 1 7 , 0 7 5 , 1 7 7 2 2 , 4 9 4 , 8 8 2 의 료 기 기 3 0 8 , 0 2 6 , 5 0 0 3 0 0 , 9 2 6 , 5 0 0 감 가 상 각 누 계 액 2 9 1 , 5 8 7 , 1 5 4 1 6 , 4 3 9 , 3 4 6 2 7 9 , 5 6 2 , 6 7 0 2 1 , 3 6 3 , 8 3 0 차 량 운 반 구 2 7 , 0 0 0 , 0 0 0 2 7 , 0 0 0 , 0 0 0 감 가 상 각 누 계 액 2 6 , 9 9 9 , 0 0 0 1 , 0 0 0 2 6 , 9 9 9 , 0 0 0 1 , 0 0 0 비 품 3 6 , 5 4 2 , 0 0 0 3 6 , 5 4 2 , 0 0 0 감 가 상 각 누 계 액 3 5 , 9 1 6 , 1 6 9 6 2 5 , 8 3 1 3 5 , 4 2 0 , 9 4 8 1 , 1 2 1 , 0 5 2 시 설 장 치 1 3 8 , 3 0 0 , 4 0 0 1 3 8 , 3 0 0 , 4 0 0 감 가 상 각 누 계 액 1 3 8 , 2 9 1 , 4 0 0 9 , 0 0 0 1 3 8 , 2 9 1 , 4 0 0 9 , 0 0 0 ( 3 ) 무 형 자 산 0 0 ( 4 ) 기 타 비 유 동 자 산 1 0 0 , 0 0 0 , 0 0 0 1 0 0 , 0 0 0 , 0 0 0 임 차 보 증 금 1 0 0 , 0 0 0 , 0 0 0 1 0 0 , 0 0 0 , 0 0 0 자 산 총 계 1 2 6 , 7 8 0 , 0 4 4 1 3 2 , 2 5 5 , 9 8 7 부 채 Ⅰ . 유 동 부 채 0 1 , 9 0 7 , 0 7 9 단 기 차 입 금 0 1 , 9 0 7 , 0 7 9 Ⅱ . 비 유 동 부 채 0 0 부 채 총 계 1 , 9 0 7 , 0 7 9 자 본 Ⅰ . 자 본 금 1 2 6 , 7 8 0 , 0 4 4 1 3 0 , 3 4 8 , 9 0 8 자 본 금 1 2 6 , 7 8 0 , 0 4 4 1 3 0 , 3 4 8 , 9 0 8 ( 당 기 순 이 익 ) 당 기 : 9 9 , 4 3 1 , 1 3 6 원 전 기 : 1 0 4 , 8 6 6 , 8 0 6 원 자 본 총 계 1 2 6 , 7 8 0 , 0 4 4 1 3 0 , 3 4 8 , 9 0 8 부 채 및 자 본 총 계 1 2 6 , 7 8 0 , 0 4 4 1 3 2 , 2 5 5 , 9 8 7 \ No newline at end of file diff --git a/.smallclaw/users/papa/workspace/uploads/1777561410773-1775525820641.jpg b/.smallclaw/users/papa/workspace/uploads/1777561410773-1775525820641.jpg new file mode 100644 index 0000000..2293b52 Binary files /dev/null and b/.smallclaw/users/papa/workspace/uploads/1777561410773-1775525820641.jpg differ diff --git a/.smallclaw/users/papa/workspace/uploads/brightened_1775525820641.jpg b/.smallclaw/users/papa/workspace/uploads/brightened_1775525820641.jpg new file mode 100644 index 0000000..2751337 Binary files /dev/null and b/.smallclaw/users/papa/workspace/uploads/brightened_1775525820641.jpg differ diff --git a/package-lock.json b/package-lock.json index 8cf6669..17fd45d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1724,7 +1724,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pptxgenjs/-/pptxgenjs-4.0.1.tgz", "integrity": "sha512-TeJISr8wouAuXw4C1F/mC33xbZs/FuEG6nH9FG1Zj+nuPcGMP5YRHl6X+j3HSUnS1f3at6k75ZZXPMZlA5Lj9A==", - "license": "MIT", "dependencies": { "@types/node": "^22.8.1", "https": "^1.0.0", diff --git a/src/gateway/agent-builder-integration.ts b/src/gateway/agent-builder-integration.ts index fcc5585..19b90c8 100644 --- a/src/gateway/agent-builder-integration.ts +++ b/src/gateway/agent-builder-integration.ts @@ -928,9 +928,10 @@ export function registerAgentBuilderTools(toolsArray: any[]): any[] { * const systemPrompt = BASE_SYSTEM_PROMPT + '\n\n' + getWorkflowContextBlock(); */ export function getWorkflowContextBlock(): string { - const summary = workflowStore.toLLMSummary(); const stats = workflowStore.getStats(); + if (stats.total_workflows === 0) return ''; + const summary = workflowStore.toLLMSummary(); return [ '---', '## Your Workflow Memory', diff --git a/src/gateway/server-v2.ts b/src/gateway/server-v2.ts index 7dcd8a1..efe7a49 100644 --- a/src/gateway/server-v2.ts +++ b/src/gateway/server-v2.ts @@ -895,15 +895,21 @@ function detectToolCategories(text: string): Set { const lower = String(text || '').toLowerCase(); const cats = new Set(); const WEB = ['search', 'find', 'look up', 'google', 'what is', 'who is', 'news', 'latest', 'research', 'look into', 'check online', 'summarize', 'article', 'read about']; - const BROWSER = ['open', 'login', 'log in', 'website', 'click', 'fill', 'form', 'navigate', 'go to', 'browse', 'sign in', 'download']; - const DESKTOP = ['desktop', 'screenshot', 'window', 'focus window', 'app', 'screen', 'type into', 'drag', 'clipboard']; + // 'open'/'browse'/'download' removed — too broad; 'download' belongs to SHELL + const BROWSER = ['website', 'click', 'fill', 'form', 'navigate', 'go to', 'sign in', 'login', 'log in', 'open website', 'open browser', 'open url', 'open tab', 'web browser', 'browser_']; + // 'window'/'app'/'screen' removed — too broad + const DESKTOP = ['desktop', 'screenshot', 'focus window', 'type into', 'drag', 'clipboard', 'desktop_', 'take screenshot']; const FILES = ['read file', 'write file', 'edit file', 'create file', 'modify', 'replace', 'open file', 'delete file', 'rename', 'copy file', 'make a file', 'update the file', 'change the file', 'save to']; - const TASK = ['task', 'background', 'run this', 'start a', 'status', 'paused', 'resume', 'in progress', 'what tasks', 'running tasks']; - const SCHEDULE = ['schedule', 'every day', 'every week', 'at ', 'recurring', 'cron', 'automate', 'remind me', 'daily', 'weekly']; + // 'task'/'background'/'run this'/'start a'/'status'/'paused'/'resume' removed — too broad + const TASK = ['background task', 'task status', 'what tasks', 'running tasks', 'in progress', 'paused task', 'resume task', 'task list', 'start a task', 'task_control', 'start_task']; + // 'at ' removed — matches virtually any sentence + const SCHEDULE = ['schedule', 'every day', 'every week', 'recurring', 'cron', 'automate', 'remind me', 'daily', 'weekly']; const SHELL = ['run command', 'execute', 'terminal', 'powershell', 'script', 'command line', 'cmd', 'bash', 'python', 'pip', 'npm', 'node', 'run script', 'shell', 'download', 'curl', 'save image', 'save file', 'install']; const MEMORY = ['remember', 'note that', 'save that', 'write that down', 'dont forget', "don't forget", 'keep in mind', 'update my', 'add to my', 'i prefer', 'i like', 'i hate', 'i use', 'my name', 'call me', 'i work', 'my project', 'my stack']; const PPTX = ['pptx', 'powerpoint', 'presentation', '슬라이드', '발표 자료', '프레젠테이션']; - const DEBUG = ['why', 'error', 'failed', 'how does', 'architecture', 'debug', 'caused', 'broke', 'not working', 'explain how', 'whats wrong', "what's wrong"]; + // 'why' removed — matches casual questions; keep specific error/debug terms + const DEBUG = ['error', 'failed', 'how does', 'architecture', 'debug', 'caused', 'broke', 'not working', 'explain how', 'whats wrong', "what's wrong"]; + const WORKFLOW = ['workflow', 'agent builder', 'architect_workflow', 'deploy workflow', 'workflow template', 'build workflow']; if (WEB.some(k => lower.includes(k))) cats.add('web'); if (BROWSER.some(k => lower.includes(k))) cats.add('browser'); if (DESKTOP.some(k => lower.includes(k))) cats.add('desktop'); @@ -914,6 +920,7 @@ function detectToolCategories(text: string): Set { if (MEMORY.some(k => lower.includes(k))) cats.add('memory'); if (PPTX.some(k => lower.includes(k))) cats.add('pptx'); if (DEBUG.some(k => lower.includes(k))) cats.add('debug'); + if (WORKFLOW.some(k => lower.includes(k))) cats.add('workflow'); return cats; } @@ -938,6 +945,8 @@ const TOOL_BLOCKS: Record = { debug: `DEBUG: If asked about errors or architecture, use read_source(file) to inspect SmallClaw source. SELF.md has architecture overview. Workspace files: IDENTITY.md, SOUL.md, USER.md, TOOLS.md, SELF.md. Read the relevant one before diagnosing.`, pptx: `PPTX WORKFLOW — MANDATORY: When the user asks for ANY PPTX / PowerPoint / presentation / slide deck, you MUST use the create_presentation tool. NO EXCEPTIONS. (1) Call create_presentation ONCE with ALL slides in a single spec. The tool auto-creates the project folder from the title. (2) Slide type field is called type — valid values: "title", "content", "section", "image", "blank". Do NOT use layout. (3) For slide images, put image_url directly in the slide spec — the Python engine downloads it automatically into the project folder. Do NOT write Python scripts to download images. Do NOT call shell("curl ...") to download images — before OR after create_presentation. create_presentation handles ALL image downloading internally. (4) If image_url fails or you have a local file, use image_path relative to the project folder (e.g. "uploads/photo.jpg"). image_url takes priority if both are set. (5) Missing images become red "[Image not found]" placeholders — this is expected, not an error. NEVER retry a failed image download, NEVER recreate the presentation, and NEVER call create_presentation again for the same topic. (6) PREFERRED IMAGE SOURCES: Use Unsplash, Pexels, or Pixabay direct image URLs. AVOID Wikipedia / Wikimedia Commons image URLs — they often return 403/400. (7) The .pptx file is saved inside the project folder. IMPORTANT: Always combine ALL slides into a SINGLE create_presentation call. NEVER create multiple presentations for the same topic. After create_presentation returns successfully, the task is DONE. Do not make any follow-up tool calls. (8) To ADD slides to an existing presentation, use edit_presentation(path, spec) — do NOT write Python scripts to edit PPTX files.`, + + workflow: `WORKFLOW TOOLS: ALWAYS call search_workflow_templates(intent) FIRST before creating anything — reuse existing workflows. If no match: (1) architect_workflow(desc) → (2) verify_workflow_credentials(wf_id) if creds needed → wait for user → (3) test_workflow(wf_id) → (4) deploy_workflow(wf_id, name, ...). Never call architect_workflow if search returns a match. Always relay tool user_message fields verbatim to the user.`, }; // Read memory categories for a specific file (for category-aware injection) @@ -951,13 +960,18 @@ function readMemoryCategories(workspacePath: string, file: 'user' | 'soul'): str } // Read memory snippets matching detected categories (for category-aware injection) -function readMemorySnippets(workspacePath: string, categories: string[]): string { +function readMemorySnippets(workspacePath: string, categories: string[], fileCache?: Map): string { if (categories.length === 0) return ''; const snippets: string[] = []; for (const file of ['USER.md', 'SOUL.md']) { - const filePath = path.join(workspacePath, file); - if (!fs.existsSync(filePath)) continue; - const content = fs.readFileSync(filePath, 'utf-8'); + let content: string; + if (fileCache?.has(file)) { + content = fileCache.get(file)!; + } else { + const filePath = path.join(workspacePath, file); + if (!fs.existsSync(filePath)) continue; + content = fs.readFileSync(filePath, 'utf-8'); + } const lines = content.split('\n'); let inSection = false; let currentSection = ''; @@ -1001,34 +1015,39 @@ async function buildPersonalityContext( historyLength: number, ): Promise { + // Per-request file cache — prevents reading USER.md/SOUL.md twice + // (once for context blocks, once for readMemorySnippets) + const fileCache = new Map(); + const loadFile = (filename: string, maxChars: number): string => { + if (!fileCache.has(filename)) { + fileCache.set(filename, loadWorkspaceFile(workspacePath, filename, 99999)); + } + const raw = fileCache.get(filename) ?? ''; + if (!raw) return ''; + return raw.length <= maxChars ? raw : raw.slice(0, maxChars) + '\n...(truncated)'; + }; + + // Intraday notes: only read if file exists (avoid stat overhead on every request) + const today = new Date().toISOString().split('T')[0]; + const intradayPath = path.join(workspacePath, 'memory', `${today}-intraday-notes.md`); + const intradayNotes = fs.existsSync(intradayPath) ? fs.readFileSync(intradayPath, 'utf-8').trim().slice(-600) : ''; + const isAutonomous = executionMode === 'background_task' || executionMode === 'cron' || executionMode === 'heartbeat'; if (isAutonomous) { - const identity = loadWorkspaceFile(workspacePath, 'IDENTITY.md', 400); - const soul = loadWorkspaceFile(workspacePath, 'SOUL.md', 800); - const user = loadWorkspaceFile(workspacePath, 'USER.md', 600); - const today = new Date().toISOString().split('T')[0]; - const intradayPath = path.join(workspacePath, 'memory', `${today}-intraday-notes.md`); - const intradayNotes = fs.existsSync(intradayPath) ? fs.readFileSync(intradayPath, 'utf-8').trim().slice(-600) : ''; const parts = [ - identity ? `[IDENTITY]\n${identity}` : '', - soul ? `[SOUL]\n${soul}` : '', - user ? `[USER]\n${user}` : '', + loadFile('IDENTITY.md', 400) ? `[IDENTITY]\n${loadFile('IDENTITY.md', 400)}` : '', + loadFile('SOUL.md', 800) ? `[SOUL]\n${loadFile('SOUL.md', 800)}` : '', + loadFile('USER.md', 600) ? `[USER]\n${loadFile('USER.md', 600)}` : '', intradayNotes ? `[TODAY_NOTES]\n${intradayNotes}` : '', ].filter(Boolean); await hookBus.fire({ type: 'agent:bootstrap', sessionId, workspacePath, bootstrapFiles: [], timestamp: Date.now() }); return parts.length > 0 ? '\n\n' + parts.join('\n\n') : ''; } - const identity = loadWorkspaceFile(workspacePath, 'IDENTITY.md', 400); - const user = loadWorkspaceFile(workspacePath, 'USER.md', 500); - const today = new Date().toISOString().split('T')[0]; - const intradayPath = path.join(workspacePath, 'memory', `${today}-intraday-notes.md`); - const intradayNotes = fs.existsSync(intradayPath) ? fs.readFileSync(intradayPath, 'utf-8').trim().slice(-600) : ''; - if (historyLength === 0) { const parts = [ - identity ? `[IDENTITY]\n${identity}` : '', - user ? `[USER]\n${user}` : '', + loadFile('IDENTITY.md', 400) ? `[IDENTITY]\n${loadFile('IDENTITY.md', 400)}` : '', + loadFile('USER.md', 500) ? `[USER]\n${loadFile('USER.md', 500)}` : '', intradayNotes ? `[TODAY_NOTES]\n${intradayNotes}` : '', ].filter(Boolean); await hookBus.fire({ type: 'agent:bootstrap', sessionId, workspacePath, bootstrapFiles: [], timestamp: Date.now() }); @@ -1036,7 +1055,6 @@ async function buildPersonalityContext( } const cats = detectToolCategories(messageText); - const soul = loadWorkspaceFile(workspacePath, 'SOUL.md', 600); // Build tool blocks for detected categories const toolBlockParts: string[] = []; @@ -1044,27 +1062,27 @@ async function buildPersonalityContext( if (TOOL_BLOCKS[cat]) toolBlockParts.push(TOOL_BLOCKS[cat]); } - // Build memory snippets for categories related to detected tool groups + // Build memory snippets — pass fileCache so USER.md/SOUL.md are not re-read const memoryCategoryKeywords: string[] = []; for (const cat of cats) { const memCats = TOOL_TO_MEMORY_CATS[cat] || []; memoryCategoryKeywords.push(...memCats); } const memorySnippets = memoryCategoryKeywords.length > 0 - ? readMemorySnippets(workspacePath, memoryCategoryKeywords) + ? readMemorySnippets(workspacePath, memoryCategoryKeywords, fileCache) : ''; // Tier 3: complex/multi-domain — add tools.md hint const isComplex = cats.size >= 3 || /\b(how do i|help me|can you|i need to|i want to)\b/i.test(messageText); const toolsHint = isComplex ? `\nFor full tool reference: read_file TOOLS.md` : ''; - // Self.md for debug - const self = cats.has('debug') ? loadWorkspaceFile(workspacePath, 'SELF.md', 600) : ''; + // Self.md for debug (cached with fileCache) + const self = cats.has('debug') ? loadFile('SELF.md', 600) : ''; const parts = [ - identity ? `[IDENTITY]\n${identity}` : '', - user ? `[USER]\n${user}` : '', - soul ? `[SOUL]\n${soul}` : '', + loadFile('IDENTITY.md', 400) ? `[IDENTITY]\n${loadFile('IDENTITY.md', 400)}` : '', + loadFile('USER.md', 500) ? `[USER]\n${loadFile('USER.md', 500)}` : '', + loadFile('SOUL.md', 600) ? `[SOUL]\n${loadFile('SOUL.md', 600)}` : '', intradayNotes ? `[TODAY_NOTES]\n${intradayNotes}` : '', toolBlockParts.length > 0 ? `[TOOLS]\n${toolBlockParts.join('\n\n')}${toolsHint}` : (toolsHint ? `[TOOLS]${toolsHint}` : ''), memorySnippets ? `[RELEVANT_MEMORY]\n${memorySnippets}` : '', @@ -3764,10 +3782,11 @@ async function handleChat( return ''; })(); + const workflowCtx = getWorkflowContextBlock(); // empty string when 0 workflows const messages: any[] = [ { role: 'system', - content: `${executionModeSystemBlock ? `${executionModeSystemBlock}\n\n` : ''}You are SmallClaw 🦞, a local AI assistant.\nCurrent date: ${dateStr}, ${timeStr}.\nNever search for or link SmallClaw repos unless the user is asking about SmallClaw itself.\nThis app runs on the user's own machine — browser/desktop automation requests are pre-authorized.\nKeep responses SHORT (1-2 sentences). Don't think out loud. Act and report. Greet naturally without tools.${callerContext ? '\n\n' + callerContext : ''}${browserStateCtx}${personalityCtx}${skillsManager.buildPromptContext(500)}\n\n${getWorkflowContextBlock()}`, + content: `${executionModeSystemBlock ? `${executionModeSystemBlock}\n\n` : ''}You are SmallClaw 🦞, a local AI assistant.\nCurrent date: ${dateStr}, ${timeStr}.\nNever search for or link SmallClaw repos unless the user is asking about SmallClaw itself.\nThis app runs on the user's own machine — browser/desktop automation requests are pre-authorized.\nKeep responses SHORT (1-2 sentences). Don't think out loud. Act and report. Greet naturally without tools.${callerContext ? '\n\n' + callerContext : ''}${browserStateCtx}${personalityCtx}${skillsManager.buildPromptContext(500)}${workflowCtx ? '\n\n' + workflowCtx : ''}`, }, ]; diff --git a/web-ui/index.html b/web-ui/index.html index cfd037d..32c93f8 100644 --- a/web-ui/index.html +++ b/web-ui/index.html @@ -2666,6 +2666,10 @@ Menu + @@ -5569,6 +5573,8 @@ async function checkAuth() { const nameEl = document.getElementById('user-info-name'); if (pill) pill.style.display = 'flex'; if (nameEl) nameEl.textContent = data.username; + const mobileLogout = document.getElementById('mob-tab-logout'); + if (mobileLogout) mobileLogout.style.display = 'flex'; } } catch (e) { console.error('Auth check failed:', e); diff --git a/workspace/installation_test/download.html b/workspace/installation_test/download.html new file mode 100644 index 0000000..b7f3276 --- /dev/null +++ b/workspace/installation_test/download.html @@ -0,0 +1,24 @@ + + + + + Installation Test - 다운로드 + + + +
+

Installation Test

+

슬라이드 1장이 준비되었습니다.

+ 프레젠테이션 다운로드 +
/home/kim/homeclaw/workspace/installation_test/installation_test.pptx
+
+ + diff --git a/workspace/installation_test/installation_test.pptx b/workspace/installation_test/installation_test.pptx new file mode 100644 index 0000000..e67e43a Binary files /dev/null and b/workspace/installation_test/installation_test.pptx differ diff --git a/workspace/test/download.html b/workspace/test/download.html new file mode 100644 index 0000000..ba0c917 --- /dev/null +++ b/workspace/test/download.html @@ -0,0 +1,24 @@ + + + + + Test - 다운로드 + + + +
+

Test

+

슬라이드 1장이 준비되었습니다.

+ 프레젠테이션 다운로드 +
/home/kim/homeclaw/workspace/test/test.pptx
+
+ + diff --git a/workspace/test/test.pptx b/workspace/test/test.pptx new file mode 100644 index 0000000..b6b4301 Binary files /dev/null and b/workspace/test/test.pptx differ diff --git a/workspace/verification_test/download.html b/workspace/verification_test/download.html new file mode 100644 index 0000000..16c825b --- /dev/null +++ b/workspace/verification_test/download.html @@ -0,0 +1,24 @@ + + + + + Verification Test - 다운로드 + + + +
+

Verification Test

+

슬라이드 1장이 준비되었습니다.

+ 프레젠테이션 다운로드 +
/home/kim/homeclaw/workspace/verification_test/verification_test.pptx
+
+ + diff --git a/workspace/verification_test/verification_test.pptx b/workspace/verification_test/verification_test.pptx new file mode 100644 index 0000000..14197bf Binary files /dev/null and b/workspace/verification_test/verification_test.pptx differ diff --git a/workspace/강아지_소개_presentation/download.html b/workspace/강아지_소개_presentation/download.html new file mode 100644 index 0000000..b4dd303 --- /dev/null +++ b/workspace/강아지_소개_presentation/download.html @@ -0,0 +1,24 @@ + + + + + 강아지 소개 Presentation - 다운로드 + + + +
+

강아지 소개 Presentation

+

슬라이드 4장이 준비되었습니다.

+ 프레젠테이션 다운로드 +
/home/kim/homeclaw/workspace/강아지_소개_presentation/강아지_소개_presentation.pptx
+
+ + diff --git a/workspace/강아지_소개_presentation/preview/slide_1.png b/workspace/강아지_소개_presentation/preview/slide_1.png new file mode 100644 index 0000000..d32fa4e Binary files /dev/null and b/workspace/강아지_소개_presentation/preview/slide_1.png differ diff --git a/workspace/강아지_소개_presentation/preview/slide_2.png b/workspace/강아지_소개_presentation/preview/slide_2.png new file mode 100644 index 0000000..2b8237f Binary files /dev/null and b/workspace/강아지_소개_presentation/preview/slide_2.png differ diff --git a/workspace/강아지_소개_presentation/preview/slide_3.png b/workspace/강아지_소개_presentation/preview/slide_3.png new file mode 100644 index 0000000..7046645 Binary files /dev/null and b/workspace/강아지_소개_presentation/preview/slide_3.png differ diff --git a/workspace/강아지_소개_presentation/preview/slide_4.png b/workspace/강아지_소개_presentation/preview/slide_4.png new file mode 100644 index 0000000..49ea564 Binary files /dev/null and b/workspace/강아지_소개_presentation/preview/slide_4.png differ diff --git a/workspace/강아지_소개_presentation/강아지_소개_presentation.pptx b/workspace/강아지_소개_presentation/강아지_소개_presentation.pptx new file mode 100644 index 0000000..a963c32 Binary files /dev/null and b/workspace/강아지_소개_presentation/강아지_소개_presentation.pptx differ