companionbot 0.16.0 → 0.16.2
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.
|
@@ -3,7 +3,7 @@ import { recordActivity, recordError } from "../../health/index.js";
|
|
|
3
3
|
import { getHistory, getModel, getThinkingLevel, runWithChatId, trimHistoryByTokens, smartTrimHistory, detectImportantContext, pinContext, addMessage, } from "../../session/state.js";
|
|
4
4
|
import * as persistence from "../../session/persistence.js";
|
|
5
5
|
import { updateLastMessageTime } from "../../heartbeat/index.js";
|
|
6
|
-
import { extractUrls, fetchWebContent, formatUrlContent, buildSystemPrompt, } from "../utils/index.js";
|
|
6
|
+
import { extractUrls, fetchWebContent, formatUrlContent, buildSystemPrompt, formatMessageTimestamp, } from "../utils/index.js";
|
|
7
7
|
import { estimateMessagesTokens } from "../../utils/tokens.js";
|
|
8
8
|
import { TOKENS, TELEGRAM } from "../../config/constants.js";
|
|
9
9
|
import { toUserFriendlyError } from "../../utils/retry.js";
|
|
@@ -155,8 +155,9 @@ export function registerMessageHandlers(bot) {
|
|
|
155
155
|
const response = await fetch(fileUrl);
|
|
156
156
|
const buffer = await response.arrayBuffer();
|
|
157
157
|
const base64 = Buffer.from(buffer).toString("base64");
|
|
158
|
-
// 캡션이 있으면 사용, 없으면 기본 질문
|
|
159
|
-
const
|
|
158
|
+
// 캡션이 있으면 사용, 없으면 기본 질문 (타임스탬프 포함)
|
|
159
|
+
const rawCaption = ctx.message.caption || "이 사진에 뭐가 있어?";
|
|
160
|
+
const caption = `${formatMessageTimestamp()} ${rawCaption}`;
|
|
160
161
|
// 이미지와 텍스트를 함께 전송
|
|
161
162
|
const imageContent = [
|
|
162
163
|
{
|
|
@@ -174,7 +175,7 @@ export function registerMessageHandlers(bot) {
|
|
|
174
175
|
];
|
|
175
176
|
// API용 메모리 히스토리에는 이미지 데이터 포함
|
|
176
177
|
history.push({ role: "user", content: imageContent });
|
|
177
|
-
// JSONL에는 캡션만 저장 (이미지 base64는 너무 큼)
|
|
178
|
+
// JSONL에는 캡션만 저장 (이미지 base64는 너무 큼) - caption에 이미 타임스탬프 포함
|
|
178
179
|
persistence.appendMessage(chatId, "user", `[이미지] ${caption}`);
|
|
179
180
|
try {
|
|
180
181
|
const systemPrompt = await buildSystemPrompt(modelId, history);
|
|
@@ -267,8 +268,9 @@ export function registerMessageHandlers(bot) {
|
|
|
267
268
|
messageForHistory = userMessage + "\n\n" + urlRefs.join("\n");
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
|
-
// 히스토리에는 간략 버전 저장 + JSONL에 영구 저장
|
|
271
|
-
|
|
271
|
+
// 히스토리에는 간략 버전 저장 + JSONL에 영구 저장 (타임스탬프 포함)
|
|
272
|
+
const timestampedMessage = formatMessageTimestamp() + " " + messageForHistory;
|
|
273
|
+
addMessage(chatId, "user", timestampedMessage);
|
|
272
274
|
// Typing indicator 시작 (긴 작업 동안 유지)
|
|
273
275
|
const typingIndicator = new TypingIndicator(ctx);
|
|
274
276
|
typingIndicator.start();
|
|
@@ -4,3 +4,5 @@ export { extractUrls, fetchWebContent, isSafeUrl, formatUrlContent, clearUrlCach
|
|
|
4
4
|
export { buildSystemPrompt, extractName } from "./prompt.js";
|
|
5
5
|
// Cache utilities
|
|
6
6
|
export { getWorkspace, invalidateWorkspaceCache, preloadWorkspace, isWorkspaceCached } from "./cache.js";
|
|
7
|
+
// Timestamp utilities
|
|
8
|
+
export { formatMessageTimestamp, addTimestampToMessage } from "./timestamp.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 메시지에 타임스탬프를 추가하는 유틸리티
|
|
3
|
+
* LLM이 시간 순서와 오늘/어제를 구분할 수 있도록 함
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 현재 시간을 간결한 형식으로 반환
|
|
7
|
+
* 예: "[10:35]" 또는 "[어제 23:15]"
|
|
8
|
+
*/
|
|
9
|
+
export function formatMessageTimestamp(date = new Date()) {
|
|
10
|
+
const now = new Date();
|
|
11
|
+
const isToday = date.toDateString() === now.toDateString();
|
|
12
|
+
const yesterday = new Date(now);
|
|
13
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
14
|
+
const isYesterday = date.toDateString() === yesterday.toDateString();
|
|
15
|
+
const time = date.toLocaleTimeString("ko-KR", {
|
|
16
|
+
hour: "2-digit",
|
|
17
|
+
minute: "2-digit",
|
|
18
|
+
hour12: false,
|
|
19
|
+
timeZone: "Asia/Seoul",
|
|
20
|
+
});
|
|
21
|
+
if (isToday) {
|
|
22
|
+
return `[${time}]`;
|
|
23
|
+
}
|
|
24
|
+
else if (isYesterday) {
|
|
25
|
+
return `[어제 ${time}]`;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// 더 오래된 경우 날짜도 포함
|
|
29
|
+
const dateStr = date.toLocaleDateString("ko-KR", {
|
|
30
|
+
month: "short",
|
|
31
|
+
day: "numeric",
|
|
32
|
+
timeZone: "Asia/Seoul",
|
|
33
|
+
});
|
|
34
|
+
return `[${dateStr} ${time}]`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 메시지 내용에 타임스탬프 prefix 추가
|
|
39
|
+
*/
|
|
40
|
+
export function addTimestampToMessage(content, date = new Date()) {
|
|
41
|
+
const timestamp = formatMessageTimestamp(date);
|
|
42
|
+
return `${timestamp} ${content}`;
|
|
43
|
+
}
|
|
@@ -100,11 +100,11 @@ export const compactTools = [
|
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
name: "save_memory",
|
|
103
|
-
description: "
|
|
103
|
+
description: "중요한 정보 저장. 사용자 정보, 선호도, 약속, 결정 등 나중에 기억해야 할 것들",
|
|
104
104
|
input_schema: {
|
|
105
105
|
type: "object",
|
|
106
106
|
properties: {
|
|
107
|
-
content: { type: "string", description: "
|
|
107
|
+
content: { type: "string", description: "기억할 내용" },
|
|
108
108
|
category: { type: "string", enum: ["user_info", "preference", "event", "project", "decision", "emotion", "other"] },
|
|
109
109
|
},
|
|
110
110
|
required: ["content"],
|
|
@@ -112,11 +112,11 @@ export const compactTools = [
|
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
114
|
name: "memory_search",
|
|
115
|
-
description: "
|
|
115
|
+
description: "과거 기억 검색. 이전에 나눈 대화, 저장한 정보, 사용자 선호도 등을 찾을 때 사용",
|
|
116
116
|
input_schema: {
|
|
117
117
|
type: "object",
|
|
118
118
|
properties: {
|
|
119
|
-
query: { type: "string" },
|
|
119
|
+
query: { type: "string", description: "검색할 내용" },
|
|
120
120
|
limit: { type: "number", description: "Max results (default: 5)" },
|
|
121
121
|
minScore: { type: "number", description: "Min similarity 0-1 (default: 0.3)" },
|
|
122
122
|
},
|
|
@@ -131,11 +131,11 @@ export const compactTools = [
|
|
|
131
131
|
// === 날씨/웹 ===
|
|
132
132
|
{
|
|
133
133
|
name: "get_weather",
|
|
134
|
-
description: "
|
|
134
|
+
description: "현재 날씨 조회. 외출, 옷차림, 우산 필요 여부 등 물어볼 때 사용",
|
|
135
135
|
input_schema: {
|
|
136
136
|
type: "object",
|
|
137
137
|
properties: {
|
|
138
|
-
city: { type: "string" },
|
|
138
|
+
city: { type: "string", description: "도시명 (예: Seoul, Tokyo)" },
|
|
139
139
|
country: { type: "string", description: "Country code (optional)" },
|
|
140
140
|
},
|
|
141
141
|
required: ["city"],
|
|
@@ -143,11 +143,11 @@ export const compactTools = [
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
name: "web_search",
|
|
146
|
-
description: "
|
|
146
|
+
description: "웹 검색 (Brave API). 최신 정보, 뉴스, 사실 확인이 필요할 때 사용. 검색어로 관련 결과 반환",
|
|
147
147
|
input_schema: {
|
|
148
148
|
type: "object",
|
|
149
149
|
properties: {
|
|
150
|
-
query: { type: "string" },
|
|
150
|
+
query: { type: "string", description: "검색어" },
|
|
151
151
|
count: { type: "number", description: "Results count (default: 5, max: 20)" },
|
|
152
152
|
},
|
|
153
153
|
required: ["query"],
|
|
@@ -155,11 +155,11 @@ export const compactTools = [
|
|
|
155
155
|
},
|
|
156
156
|
{
|
|
157
157
|
name: "web_fetch",
|
|
158
|
-
description: "
|
|
158
|
+
description: "URL에서 웹페이지 본문 추출. 링크 내용 확인, 기사 읽기, 문서 요약 등에 사용. HTML → 텍스트 변환",
|
|
159
159
|
input_schema: {
|
|
160
160
|
type: "object",
|
|
161
161
|
properties: {
|
|
162
|
-
url: { type: "string" },
|
|
162
|
+
url: { type: "string", description: "가져올 웹페이지 URL" },
|
|
163
163
|
maxChars: { type: "number", description: "Max chars (default: 5000)" },
|
|
164
164
|
},
|
|
165
165
|
required: ["url"],
|