feat: /last and bind button for previous Q/A context (v0.3.4)
After attaching a session, show a button and /last command that load the latest human/assistant turn via session.history so phone users can continue with context. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+34
-2
@@ -3,8 +3,9 @@ import { SessionId } from '@deepseek-ai/dsh-session/types';
|
||||
import { isAuthorized } from './auth.js';
|
||||
import { catalogFromLiveAgents, loadCatalog, truncateButton, visibleSessionsForWorkspace, workspacesWithVisibleSessions, } from './catalog.js';
|
||||
import { TelegramClient, } from './client.js';
|
||||
import { MSG, parseCommand } from './commands.js';
|
||||
import { MSG, LAST_CB, parseCommand } from './commands.js';
|
||||
import { markdownToHtml, splitMessage } from './format.js';
|
||||
import { formatLastTurn, loadLastTurn } from './history.js';
|
||||
import { describeAgent, displayLabel } from './label.js';
|
||||
import { formatModel, loadSessionModels, selectSessionModel, } from './models.js';
|
||||
const WS_CB = 'ws:';
|
||||
@@ -14,6 +15,11 @@ const MODEL_CB = 'mdl:';
|
||||
const EFFORT_CB = 'me:';
|
||||
const BACK_MODEL_CB = 'mb';
|
||||
const MAX_BUTTONS = 40;
|
||||
function lastContextKeyboard() {
|
||||
return {
|
||||
inline_keyboard: [[{ text: '查看上次对话', callback_data: LAST_CB }]],
|
||||
};
|
||||
}
|
||||
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
function contentToText(content) {
|
||||
return content
|
||||
@@ -57,6 +63,7 @@ export class TelegramBridge {
|
||||
void this.client.setMyCommands([
|
||||
{ command: 'start', description: '欢迎与用法' },
|
||||
{ command: 'sessions', description: '按工作区列出并附着会话' },
|
||||
{ command: 'last', description: '查看上次问答(续接上下文)' },
|
||||
{ command: 'model', description: '切换当前绑定会话的模型' },
|
||||
{ command: 'status', description: '查看当前绑定' },
|
||||
{ command: 'unbind', description: '断开手机绑定(不关闭本机会话)' },
|
||||
@@ -112,6 +119,9 @@ export class TelegramBridge {
|
||||
case 'sessions':
|
||||
await this.sendWorkspacePicker(chatId);
|
||||
return;
|
||||
case 'last':
|
||||
await this.sendLastTurn(chatId);
|
||||
return;
|
||||
case 'model':
|
||||
await this.sendModelPicker(chatId);
|
||||
return;
|
||||
@@ -146,6 +156,11 @@ export class TelegramBridge {
|
||||
}
|
||||
const data = cq.data ?? '';
|
||||
const picker = this.pickers.get(String(chatId));
|
||||
if (data === LAST_CB) {
|
||||
await this.client.answerCallbackQuery(cq.id);
|
||||
await this.sendLastTurn(chatId);
|
||||
return;
|
||||
}
|
||||
if (data === BACK_WS_CB) {
|
||||
await this.client.answerCallbackQuery(cq.id);
|
||||
await this.sendWorkspacePicker(chatId, picker?.catalog);
|
||||
@@ -317,7 +332,24 @@ export class TelegramBridge {
|
||||
: displayLabel(parts);
|
||||
this.bindings.set(String(chatId), { chatId, sessionId: String(agent.id), label });
|
||||
await this.client.answerCallbackQuery(callbackId, '已附着');
|
||||
await this.client.sendMessage(chatId, MSG.BOUND(label));
|
||||
await this.client.sendMessage(chatId, MSG.BOUND(label), undefined, lastContextKeyboard());
|
||||
}
|
||||
async sendLastTurn(chatId) {
|
||||
const binding = this.bindings.get(String(chatId));
|
||||
if (!binding) {
|
||||
await this.client.sendMessage(chatId, MSG.NEED_BIND);
|
||||
return;
|
||||
}
|
||||
const agent = await this.ensureLiveAgent(binding.sessionId);
|
||||
try {
|
||||
const turn = await loadLastTurn(this.ctx, binding.sessionId, agent);
|
||||
const text = formatLastTurn(turn);
|
||||
await this.deliver(chatId, text);
|
||||
}
|
||||
catch (err) {
|
||||
this.ctx.logger.warn(`dsh-telegram-channel: /last failed: ${this.redact(err)}`);
|
||||
await this.client.sendMessage(chatId, MSG.LAST_FAILED);
|
||||
}
|
||||
}
|
||||
async sendModelPicker(chatId) {
|
||||
const binding = this.bindings.get(String(chatId));
|
||||
|
||||
Reference in New Issue
Block a user