instar 0.9.0 → 0.9.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.
- package/dist/cli.js +0 -0
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +202 -71
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +38 -4
- package/dist/commands/setup.js.map +1 -1
- package/dist/core/AgentConnector.d.ts +76 -0
- package/dist/core/AgentConnector.d.ts.map +1 -0
- package/dist/core/AgentConnector.js +323 -0
- package/dist/core/AgentConnector.js.map +1 -0
- package/dist/core/AutoUpdater.d.ts +7 -0
- package/dist/core/AutoUpdater.d.ts.map +1 -1
- package/dist/core/AutoUpdater.js +31 -3
- package/dist/core/AutoUpdater.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +86 -5
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/StateWriteAuthority.d.ts +101 -0
- package/dist/core/StateWriteAuthority.d.ts.map +1 -0
- package/dist/core/StateWriteAuthority.js +167 -0
- package/dist/core/StateWriteAuthority.js.map +1 -0
- package/dist/core/types.d.ts +104 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/TopicMemory.d.ts +167 -0
- package/dist/memory/TopicMemory.d.ts.map +1 -0
- package/dist/memory/TopicMemory.js +494 -0
- package/dist/memory/TopicMemory.js.map +1 -0
- package/dist/memory/TopicSummarizer.d.ts +58 -0
- package/dist/memory/TopicSummarizer.d.ts.map +1 -0
- package/dist/memory/TopicSummarizer.js +140 -0
- package/dist/memory/TopicSummarizer.js.map +1 -0
- package/dist/messaging/TelegramAdapter.d.ts +35 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +136 -2
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +2 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +340 -1
- package/dist/server/routes.js.map +1 -1
- package/dist/users/UserManager.d.ts +21 -0
- package/dist/users/UserManager.d.ts.map +1 -1
- package/dist/users/UserManager.js +32 -0
- package/dist/users/UserManager.js.map +1 -1
- package/dist/users/UserOnboarding.d.ts +116 -0
- package/dist/users/UserOnboarding.d.ts.map +1 -0
- package/dist/users/UserOnboarding.js +365 -0
- package/dist/users/UserOnboarding.js.map +1 -0
- package/package.json +2 -1
- package/upgrades/0.8.23.md +106 -0
- package/upgrades/0.9.1.md +91 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TopicSummarizer — LLM-powered rolling summary generation for topic conversations.
|
|
3
|
+
*
|
|
4
|
+
* Generates and maintains rolling summaries for each Telegram topic thread.
|
|
5
|
+
* Summaries compress the full conversation history into a concise context
|
|
6
|
+
* that new sessions can load instantly — no need to replay hundreds of messages.
|
|
7
|
+
*
|
|
8
|
+
* Summary strategy:
|
|
9
|
+
* - First summary: Generated from all messages when topic exceeds threshold
|
|
10
|
+
* - Incremental updates: Previous summary + new messages → updated summary
|
|
11
|
+
* - Triggered: On session end (if threshold exceeded) or on-demand via API
|
|
12
|
+
*
|
|
13
|
+
* Uses IntelligenceProvider (Claude CLI by default) for LLM calls.
|
|
14
|
+
* Haiku tier for cost efficiency — summaries don't need deep reasoning.
|
|
15
|
+
*/
|
|
16
|
+
import type { IntelligenceProvider } from '../core/types.js';
|
|
17
|
+
import type { TopicMemory, TopicMessage } from './TopicMemory.js';
|
|
18
|
+
export interface TopicSummarizerConfig {
|
|
19
|
+
/** Minimum new messages before triggering a summary update */
|
|
20
|
+
messageThreshold: number;
|
|
21
|
+
/** Maximum messages to include in a single summarization prompt */
|
|
22
|
+
maxMessagesPerPrompt: number;
|
|
23
|
+
/** Maximum tokens for the summary response */
|
|
24
|
+
maxSummaryTokens: number;
|
|
25
|
+
}
|
|
26
|
+
export interface SummarizeResult {
|
|
27
|
+
topicId: number;
|
|
28
|
+
summary: string;
|
|
29
|
+
messagesProcessed: number;
|
|
30
|
+
isUpdate: boolean;
|
|
31
|
+
durationMs: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build the prompt for generating a topic summary.
|
|
35
|
+
*/
|
|
36
|
+
declare function buildSummaryPrompt(messages: TopicMessage[], existingSummary: string | null, topicName: string | null): string;
|
|
37
|
+
export declare class TopicSummarizer {
|
|
38
|
+
private intelligence;
|
|
39
|
+
private topicMemory;
|
|
40
|
+
private config;
|
|
41
|
+
constructor(intelligence: IntelligenceProvider, topicMemory: TopicMemory, config?: Partial<TopicSummarizerConfig>);
|
|
42
|
+
/**
|
|
43
|
+
* Generate or update the summary for a topic.
|
|
44
|
+
* Returns null if the topic doesn't need a summary update.
|
|
45
|
+
*/
|
|
46
|
+
summarize(topicId: number, force?: boolean): Promise<SummarizeResult | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Check all topics and summarize those that need it.
|
|
49
|
+
* Returns results for topics that were summarized.
|
|
50
|
+
*/
|
|
51
|
+
summarizeAll(): Promise<SummarizeResult[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Check if a specific topic needs a summary update.
|
|
54
|
+
*/
|
|
55
|
+
needsUpdate(topicId: number): boolean;
|
|
56
|
+
}
|
|
57
|
+
export { buildSummaryPrompt };
|
|
58
|
+
//# sourceMappingURL=TopicSummarizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TopicSummarizer.d.ts","sourceRoot":"","sources":["../../src/memory/TopicSummarizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,8CAA8C;IAC9C,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD;;GAEG;AACH,iBAAS,kBAAkB,CACzB,QAAQ,EAAE,YAAY,EAAE,EACxB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,MAAM,CA8CR;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,MAAM,CAAwB;gBAGpC,YAAY,EAAE,oBAAoB,EAClC,WAAW,EAAE,WAAW,EACxB,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAOzC;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAqDlF;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAgBhD;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAGtC;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TopicSummarizer — LLM-powered rolling summary generation for topic conversations.
|
|
3
|
+
*
|
|
4
|
+
* Generates and maintains rolling summaries for each Telegram topic thread.
|
|
5
|
+
* Summaries compress the full conversation history into a concise context
|
|
6
|
+
* that new sessions can load instantly — no need to replay hundreds of messages.
|
|
7
|
+
*
|
|
8
|
+
* Summary strategy:
|
|
9
|
+
* - First summary: Generated from all messages when topic exceeds threshold
|
|
10
|
+
* - Incremental updates: Previous summary + new messages → updated summary
|
|
11
|
+
* - Triggered: On session end (if threshold exceeded) or on-demand via API
|
|
12
|
+
*
|
|
13
|
+
* Uses IntelligenceProvider (Claude CLI by default) for LLM calls.
|
|
14
|
+
* Haiku tier for cost efficiency — summaries don't need deep reasoning.
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_CONFIG = {
|
|
17
|
+
messageThreshold: 20,
|
|
18
|
+
maxMessagesPerPrompt: 200,
|
|
19
|
+
maxSummaryTokens: 1024,
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Build the prompt for generating a topic summary.
|
|
23
|
+
*/
|
|
24
|
+
function buildSummaryPrompt(messages, existingSummary, topicName) {
|
|
25
|
+
const lines = [];
|
|
26
|
+
lines.push('You are summarizing a conversation between a user and their AI agent.');
|
|
27
|
+
lines.push('Your summary will be loaded as context for future sessions so the agent can continue the conversation seamlessly.');
|
|
28
|
+
lines.push('');
|
|
29
|
+
if (topicName) {
|
|
30
|
+
lines.push(`Topic: ${topicName}`);
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
lines.push('RULES:');
|
|
34
|
+
lines.push('- Capture what was discussed, decisions made, current state, and any pending items');
|
|
35
|
+
lines.push('- Preserve specific details: names, file paths, version numbers, URLs, technical decisions');
|
|
36
|
+
lines.push('- Note the emotional tone and relationship dynamics if relevant');
|
|
37
|
+
lines.push('- Keep it under 500 words — concise but complete');
|
|
38
|
+
lines.push('- Write in present tense for current state, past tense for completed work');
|
|
39
|
+
lines.push('- DO NOT include meta-commentary about the summarization itself');
|
|
40
|
+
lines.push('');
|
|
41
|
+
if (existingSummary) {
|
|
42
|
+
lines.push('EXISTING SUMMARY (update this with the new messages below):');
|
|
43
|
+
lines.push('---');
|
|
44
|
+
lines.push(existingSummary);
|
|
45
|
+
lines.push('---');
|
|
46
|
+
lines.push('');
|
|
47
|
+
lines.push('NEW MESSAGES SINCE LAST SUMMARY:');
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
lines.push('CONVERSATION TO SUMMARIZE:');
|
|
51
|
+
}
|
|
52
|
+
lines.push('');
|
|
53
|
+
for (const m of messages) {
|
|
54
|
+
const sender = m.fromUser ? 'User' : 'Agent';
|
|
55
|
+
const ts = m.timestamp ? new Date(m.timestamp).toISOString().slice(0, 16).replace('T', ' ') : '';
|
|
56
|
+
// Truncate very long messages to keep prompt manageable
|
|
57
|
+
const text = m.text.length > 1000 ? m.text.slice(0, 1000) + '...' : m.text;
|
|
58
|
+
lines.push(`[${ts}] ${sender}: ${text}`);
|
|
59
|
+
}
|
|
60
|
+
lines.push('');
|
|
61
|
+
lines.push('Write the updated conversation summary:');
|
|
62
|
+
return lines.join('\n');
|
|
63
|
+
}
|
|
64
|
+
export class TopicSummarizer {
|
|
65
|
+
intelligence;
|
|
66
|
+
topicMemory;
|
|
67
|
+
config;
|
|
68
|
+
constructor(intelligence, topicMemory, config) {
|
|
69
|
+
this.intelligence = intelligence;
|
|
70
|
+
this.topicMemory = topicMemory;
|
|
71
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate or update the summary for a topic.
|
|
75
|
+
* Returns null if the topic doesn't need a summary update.
|
|
76
|
+
*/
|
|
77
|
+
async summarize(topicId, force) {
|
|
78
|
+
const needsUpdate = force || this.topicMemory.needsSummaryUpdate(topicId, this.config.messageThreshold);
|
|
79
|
+
if (!needsUpdate)
|
|
80
|
+
return null;
|
|
81
|
+
const startTime = Date.now();
|
|
82
|
+
// Get existing summary and new messages
|
|
83
|
+
const existingSummary = this.topicMemory.getTopicSummary(topicId);
|
|
84
|
+
const newMessages = this.topicMemory.getMessagesSinceSummary(topicId);
|
|
85
|
+
if (newMessages.length === 0 && !force)
|
|
86
|
+
return null;
|
|
87
|
+
// Limit messages to prevent prompt explosion
|
|
88
|
+
const messagesToProcess = newMessages.slice(-this.config.maxMessagesPerPrompt);
|
|
89
|
+
const meta = this.topicMemory.getTopicMeta(topicId);
|
|
90
|
+
const prompt = buildSummaryPrompt(messagesToProcess, existingSummary?.summary ?? null, meta?.topicName ?? null);
|
|
91
|
+
// Generate summary via LLM (Haiku for cost efficiency)
|
|
92
|
+
const summary = await this.intelligence.evaluate(prompt, {
|
|
93
|
+
model: 'fast',
|
|
94
|
+
maxTokens: this.config.maxSummaryTokens,
|
|
95
|
+
});
|
|
96
|
+
if (!summary || summary.trim().length < 10) {
|
|
97
|
+
throw new Error(`Summary generation returned empty/invalid result for topic ${topicId}`);
|
|
98
|
+
}
|
|
99
|
+
// Get the last message ID for tracking what's been summarized
|
|
100
|
+
const lastMessage = newMessages[newMessages.length - 1];
|
|
101
|
+
const totalMessages = this.topicMemory.getMessageCount(topicId);
|
|
102
|
+
// Save the summary
|
|
103
|
+
this.topicMemory.saveTopicSummary(topicId, summary.trim(), totalMessages, lastMessage?.messageId ?? existingSummary?.lastMessageId ?? 0);
|
|
104
|
+
return {
|
|
105
|
+
topicId,
|
|
106
|
+
summary: summary.trim(),
|
|
107
|
+
messagesProcessed: messagesToProcess.length,
|
|
108
|
+
isUpdate: !!existingSummary,
|
|
109
|
+
durationMs: Date.now() - startTime,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check all topics and summarize those that need it.
|
|
114
|
+
* Returns results for topics that were summarized.
|
|
115
|
+
*/
|
|
116
|
+
async summarizeAll() {
|
|
117
|
+
const topics = this.topicMemory.listTopics();
|
|
118
|
+
const results = [];
|
|
119
|
+
for (const topic of topics) {
|
|
120
|
+
try {
|
|
121
|
+
const result = await this.summarize(topic.topicId);
|
|
122
|
+
if (result)
|
|
123
|
+
results.push(result);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
console.error(`[TopicSummarizer] Failed to summarize topic ${topic.topicId}: ${err}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if a specific topic needs a summary update.
|
|
133
|
+
*/
|
|
134
|
+
needsUpdate(topicId) {
|
|
135
|
+
return this.topicMemory.needsSummaryUpdate(topicId, this.config.messageThreshold);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Export the prompt builder for testing
|
|
139
|
+
export { buildSummaryPrompt };
|
|
140
|
+
//# sourceMappingURL=TopicSummarizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TopicSummarizer.js","sourceRoot":"","sources":["../../src/memory/TopicSummarizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -85,6 +85,14 @@ export declare class TelegramAdapter implements MessagingAdapter {
|
|
|
85
85
|
}>) | null;
|
|
86
86
|
onIsSessionAlive: ((tmuxSession: string) => boolean) | null;
|
|
87
87
|
onIsSessionActive: ((tmuxSession: string) => Promise<boolean>) | null;
|
|
88
|
+
onMessageLogged: ((entry: {
|
|
89
|
+
messageId: number;
|
|
90
|
+
topicId: number | null;
|
|
91
|
+
text: string;
|
|
92
|
+
fromUser: boolean;
|
|
93
|
+
timestamp: string;
|
|
94
|
+
sessionName: string | null;
|
|
95
|
+
}) => void) | null;
|
|
88
96
|
onAttentionStatusChange: ((itemId: string, status: string) => Promise<void>) | null;
|
|
89
97
|
onSwitchAccountRequest: ((target: string, replyTopicId: number) => Promise<void>) | null;
|
|
90
98
|
onQuotaStatusRequest: ((replyTopicId: number) => Promise<void>) | null;
|
|
@@ -93,6 +101,23 @@ export declare class TelegramAdapter implements MessagingAdapter {
|
|
|
93
101
|
cause: string;
|
|
94
102
|
detail: string;
|
|
95
103
|
} | null>) | null;
|
|
104
|
+
onGetRegistrationPolicy: (() => {
|
|
105
|
+
policy: string;
|
|
106
|
+
contactHint?: string;
|
|
107
|
+
agentName?: string;
|
|
108
|
+
}) | null;
|
|
109
|
+
onNotifyAdminJoinRequest: ((request: {
|
|
110
|
+
name: string;
|
|
111
|
+
username?: string;
|
|
112
|
+
telegramUserId: number;
|
|
113
|
+
}) => Promise<void>) | null;
|
|
114
|
+
onValidateInviteCode: ((code: string, telegramUserId: number) => Promise<{
|
|
115
|
+
valid: boolean;
|
|
116
|
+
error?: string;
|
|
117
|
+
}>) | null;
|
|
118
|
+
onStartMiniOnboarding: ((telegramUserId: number, firstName: string, username?: string) => Promise<void>) | null;
|
|
119
|
+
private unknownUserRateLimit;
|
|
120
|
+
private static readonly UNKNOWN_USER_COOLDOWN_MS;
|
|
96
121
|
constructor(config: TelegramConfig, stateDir: string);
|
|
97
122
|
start(): Promise<void>;
|
|
98
123
|
stop(): Promise<void>;
|
|
@@ -133,6 +158,16 @@ export declare class TelegramAdapter implements MessagingAdapter {
|
|
|
133
158
|
* If no authorizedUserIds configured, all messages are accepted.
|
|
134
159
|
*/
|
|
135
160
|
private isAuthorized;
|
|
161
|
+
/**
|
|
162
|
+
* Handle a message from an unknown/unauthorized Telegram user.
|
|
163
|
+
* Checks the registration policy and responds appropriately:
|
|
164
|
+
* - admin-only: Gated message + notify admin
|
|
165
|
+
* - invite-only: Ask for invite code
|
|
166
|
+
* - open: Start mini-onboarding (rate limited)
|
|
167
|
+
*
|
|
168
|
+
* Rate-limited to prevent spam from the same unknown user.
|
|
169
|
+
*/
|
|
170
|
+
private handleUnknownUser;
|
|
136
171
|
registerTopicSession(topicId: number, sessionName: string): void;
|
|
137
172
|
unregisterTopic(topicId: number): void;
|
|
138
173
|
getSessionForTopic(topicId: number): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelegramAdapter.d.ts","sourceRoot":"","sources":["../../src/messaging/TelegramAdapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"TelegramAdapter.d.ts","sourceRoot":"","sources":["../../src/messaging/TelegramAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -68,6 +68,9 @@ export class TelegramAdapter {
|
|
|
68
68
|
onListSessions = null;
|
|
69
69
|
onIsSessionAlive = null;
|
|
70
70
|
onIsSessionActive = null;
|
|
71
|
+
// Message log callback — fires on every message logged (inbound and outbound).
|
|
72
|
+
// Used by TopicMemory to dual-write to SQLite for search and summarization.
|
|
73
|
+
onMessageLogged = null;
|
|
71
74
|
// Attention queue callbacks
|
|
72
75
|
onAttentionStatusChange = null;
|
|
73
76
|
// Quota management callbacks
|
|
@@ -75,6 +78,18 @@ export class TelegramAdapter {
|
|
|
75
78
|
onQuotaStatusRequest = null;
|
|
76
79
|
onLoginRequest = null;
|
|
77
80
|
onClassifySessionDeath = null;
|
|
81
|
+
// Unknown user handling callbacks (Multi-User Setup Wizard Phase 4.5)
|
|
82
|
+
// Returns the registration policy and optional contact hint for the gated message
|
|
83
|
+
onGetRegistrationPolicy = null;
|
|
84
|
+
// Called when an admin-only join request is created (notify admin via lifeline/admin topic)
|
|
85
|
+
onNotifyAdminJoinRequest = null;
|
|
86
|
+
// Called to validate an invite code for invite-only policy
|
|
87
|
+
onValidateInviteCode = null;
|
|
88
|
+
// Called to start mini-onboarding for open policy
|
|
89
|
+
onStartMiniOnboarding = null;
|
|
90
|
+
// Rate limiting for unknown user responses (prevent spam)
|
|
91
|
+
unknownUserRateLimit = new Map(); // telegramUserId -> last response timestamp
|
|
92
|
+
static UNKNOWN_USER_COOLDOWN_MS = 60_000; // 1 minute between responses to same unknown user
|
|
78
93
|
constructor(config, stateDir) {
|
|
79
94
|
this.config = config;
|
|
80
95
|
this.stateDir = stateDir;
|
|
@@ -310,6 +325,118 @@ export class TelegramAdapter {
|
|
|
310
325
|
return true;
|
|
311
326
|
return authorized.includes(userId);
|
|
312
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Handle a message from an unknown/unauthorized Telegram user.
|
|
330
|
+
* Checks the registration policy and responds appropriately:
|
|
331
|
+
* - admin-only: Gated message + notify admin
|
|
332
|
+
* - invite-only: Ask for invite code
|
|
333
|
+
* - open: Start mini-onboarding (rate limited)
|
|
334
|
+
*
|
|
335
|
+
* Rate-limited to prevent spam from the same unknown user.
|
|
336
|
+
*/
|
|
337
|
+
async handleUnknownUser(telegramUserId, firstName, username, messageText) {
|
|
338
|
+
// Rate limit: don't spam responses to the same unknown user
|
|
339
|
+
const lastResponse = this.unknownUserRateLimit.get(telegramUserId);
|
|
340
|
+
if (lastResponse && (Date.now() - lastResponse) < TelegramAdapter.UNKNOWN_USER_COOLDOWN_MS) {
|
|
341
|
+
console.log(`[telegram] Rate-limited response to unknown user ${telegramUserId} (${username ?? firstName})`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
// Get registration policy from callback
|
|
345
|
+
const policyInfo = this.onGetRegistrationPolicy?.();
|
|
346
|
+
if (!policyInfo) {
|
|
347
|
+
// No policy callback wired — fall back to silent ignore (legacy behavior)
|
|
348
|
+
console.log(`[telegram] Ignoring message from unauthorized user ${telegramUserId} (${username ?? firstName}) — no registration policy configured`);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const { policy, contactHint, agentName } = policyInfo;
|
|
352
|
+
const displayName = agentName || 'This agent';
|
|
353
|
+
// Mark that we responded to this user
|
|
354
|
+
this.unknownUserRateLimit.set(telegramUserId, Date.now());
|
|
355
|
+
// Clean up old rate limit entries periodically (keep map from growing unbounded)
|
|
356
|
+
if (this.unknownUserRateLimit.size > 100) {
|
|
357
|
+
const cutoff = Date.now() - TelegramAdapter.UNKNOWN_USER_COOLDOWN_MS * 10;
|
|
358
|
+
for (const [uid, ts] of this.unknownUserRateLimit) {
|
|
359
|
+
if (ts < cutoff)
|
|
360
|
+
this.unknownUserRateLimit.delete(uid);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
console.log(`[telegram] Unknown user ${telegramUserId} (${username ?? firstName}) — policy: ${policy}`);
|
|
364
|
+
try {
|
|
365
|
+
switch (policy) {
|
|
366
|
+
case 'admin-only': {
|
|
367
|
+
// Send gated message to the user
|
|
368
|
+
let gatedMessage = `Hi ${firstName}! ${displayName} is not open for public registration. Access is managed by an administrator.`;
|
|
369
|
+
if (contactHint) {
|
|
370
|
+
gatedMessage += `\n\n${contactHint}`;
|
|
371
|
+
}
|
|
372
|
+
gatedMessage += `\n\nYour request has been noted and forwarded to the admin.`;
|
|
373
|
+
// Reply in the group's General topic (since unknown users don't have their own topic)
|
|
374
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, gatedMessage).catch(() => { });
|
|
375
|
+
// Notify admin via callback
|
|
376
|
+
if (this.onNotifyAdminJoinRequest) {
|
|
377
|
+
await this.onNotifyAdminJoinRequest({
|
|
378
|
+
name: firstName,
|
|
379
|
+
username,
|
|
380
|
+
telegramUserId,
|
|
381
|
+
}).catch(err => {
|
|
382
|
+
console.error(`[telegram] Failed to notify admin of join request: ${err}`);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
case 'invite-only': {
|
|
388
|
+
// Check if the message contains an invite code
|
|
389
|
+
const trimmedText = messageText?.trim();
|
|
390
|
+
if (trimmedText && this.onValidateInviteCode) {
|
|
391
|
+
const result = await this.onValidateInviteCode(trimmedText, telegramUserId);
|
|
392
|
+
if (result.valid) {
|
|
393
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, `Welcome, ${firstName}! Your invite code has been accepted. Setting up your account...`).catch(() => { });
|
|
394
|
+
// Trigger mini-onboarding after successful invite validation
|
|
395
|
+
if (this.onStartMiniOnboarding) {
|
|
396
|
+
await this.onStartMiniOnboarding(telegramUserId, firstName, username).catch(err => {
|
|
397
|
+
console.error(`[telegram] Failed to start onboarding after invite: ${err}`);
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
else if (result.error) {
|
|
403
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, result.error).catch(() => { });
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Default invite-only prompt
|
|
408
|
+
let inviteMessage = `Hi ${firstName}! ${displayName} requires an invite code to join. Please reply with your invite code.`;
|
|
409
|
+
if (contactHint) {
|
|
410
|
+
inviteMessage += `\n\n${contactHint}`;
|
|
411
|
+
}
|
|
412
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, inviteMessage).catch(() => { });
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
case 'open': {
|
|
416
|
+
// Start mini-onboarding via callback
|
|
417
|
+
if (this.onStartMiniOnboarding) {
|
|
418
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, `Hi ${firstName}! Welcome! Setting up your account...`).catch(() => { });
|
|
419
|
+
await this.onStartMiniOnboarding(telegramUserId, firstName, username).catch(err => {
|
|
420
|
+
console.error(`[telegram] Failed to start mini-onboarding: ${err}`);
|
|
421
|
+
this.sendToTopic(GENERAL_TOPIC_ID, `Sorry ${firstName}, there was an issue setting up your account. Please try again later.`).catch(() => { });
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, `Hi ${firstName}! Registration is currently being set up. Please try again later.`).catch(() => { });
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
default: {
|
|
430
|
+
// Unknown policy — fall back to gated message
|
|
431
|
+
console.warn(`[telegram] Unknown registration policy: ${policy}`);
|
|
432
|
+
await this.sendToTopic(GENERAL_TOPIC_ID, `Hi ${firstName}! ${displayName} is not currently accepting new users.`).catch(() => { });
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch (err) {
|
|
437
|
+
console.error(`[telegram] Error handling unknown user ${telegramUserId}: ${err}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
313
440
|
// ── Topic-Session Registry ─────────────────────────────────
|
|
314
441
|
registerTopicSession(topicId, sessionName) {
|
|
315
442
|
this.topicToSession.set(topicId, sessionName);
|
|
@@ -829,6 +956,13 @@ export class TelegramAdapter {
|
|
|
829
956
|
catch (err) {
|
|
830
957
|
console.error(`[telegram] Failed to append to message log: ${err}`);
|
|
831
958
|
}
|
|
959
|
+
// Notify subscribers (TopicMemory for SQLite dual-write)
|
|
960
|
+
if (this.onMessageLogged) {
|
|
961
|
+
try {
|
|
962
|
+
this.onMessageLogged(entry);
|
|
963
|
+
}
|
|
964
|
+
catch { /* non-critical — don't break logging pipeline */ }
|
|
965
|
+
}
|
|
832
966
|
}
|
|
833
967
|
/** Keep only the last 75,000 lines when log exceeds 100,000 lines.
|
|
834
968
|
* High limits because message history is core agent memory.
|
|
@@ -1157,9 +1291,9 @@ export class TelegramAdapter {
|
|
|
1157
1291
|
const msg = update.message;
|
|
1158
1292
|
if (!msg)
|
|
1159
1293
|
return;
|
|
1160
|
-
// Auth gating —
|
|
1294
|
+
// Auth gating — handle messages from unauthorized/unknown users
|
|
1161
1295
|
if (!this.isAuthorized(msg.from.id)) {
|
|
1162
|
-
|
|
1296
|
+
await this.handleUnknownUser(msg.from.id, msg.from.first_name, msg.from.username, msg.text);
|
|
1163
1297
|
return;
|
|
1164
1298
|
}
|
|
1165
1299
|
const numericTopicId = msg.message_thread_id ?? GENERAL_TOPIC_ID;
|