惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
I
InfoQ
Engineering at Meta
Engineering at Meta
D
DataBreaches.Net
L
LangChain Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Recent Announcements
Recent Announcements
GbyAI
GbyAI
爱范儿
爱范儿
Microsoft Security Blog
Microsoft Security Blog
腾讯CDC
美团技术团队
罗磊的独立博客
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
T
The Blog of Author Tim Ferriss
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
M
MIT News - Artificial intelligence
D
Docker
MongoDB | Blog
MongoDB | Blog
F
Fortinet All Blogs
博客园 - 叶小钗

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
refactor: trim qqbot known user store · openclaw/openclaw...
steipete · 2026-05-02 · via Recent Commits to openclaw:main

@@ -13,7 +13,7 @@ import { debugLog, debugError } from "../utils/log.js";

1313

import { getQQBotDataDir, getQQBotDataPath } from "../utils/platform.js";

14141515

/** Persisted record for a user who has interacted with the bot. */

16-

export interface KnownUser {

16+

interface KnownUser {

1717

openid: string;

1818

type: ChatScope;

1919

nickname?: string;

@@ -135,120 +135,3 @@ export function recordKnownUser(user: {

135135

isDirty = true;

136136

saveUsersToFile();

137137

}

138-139-

/** Look up one known user. */

140-

export function getKnownUser(

141-

accountId: string,

142-

openid: string,

143-

type: ChatScope = "c2c",

144-

groupOpenid?: string,

145-

): KnownUser | undefined {

146-

return loadUsersFromFile().get(makeUserKey({ accountId, openid, type, groupOpenid }));

147-

}

148-149-

/** List known users with optional filtering and sorting. */

150-

export function listKnownUsers(options?: {

151-

accountId?: string;

152-

type?: ChatScope;

153-

activeWithin?: number;

154-

limit?: number;

155-

sortBy?: "lastSeenAt" | "firstSeenAt" | "interactionCount";

156-

sortOrder?: "asc" | "desc";

157-

}): KnownUser[] {

158-

let users = Array.from(loadUsersFromFile().values());

159-

if (options?.accountId) {

160-

users = users.filter((u) => u.accountId === options.accountId);

161-

}

162-

if (options?.type) {

163-

users = users.filter((u) => u.type === options.type);

164-

}

165-

if (options?.activeWithin) {

166-

const cutoff = Date.now() - options.activeWithin;

167-

users = users.filter((u) => u.lastSeenAt >= cutoff);

168-

}

169-

const sortBy = options?.sortBy ?? "lastSeenAt";

170-

const sortOrder = options?.sortOrder ?? "desc";

171-

users.sort((a, b) => {

172-

const aV = a[sortBy] ?? 0;

173-

const bV = b[sortBy] ?? 0;

174-

return sortOrder === "asc" ? aV - bV : bV - aV;

175-

});

176-

if (options?.limit && options.limit > 0) {

177-

users = users.slice(0, options.limit);

178-

}

179-

return users;

180-

}

181-182-

/** Return summary stats for known users. */

183-

export function getKnownUsersStats(accountId?: string): {

184-

totalUsers: number;

185-

c2cUsers: number;

186-

groupUsers: number;

187-

activeIn24h: number;

188-

activeIn7d: number;

189-

} {

190-

const users = listKnownUsers({ accountId });

191-

const now = Date.now();

192-

const day = 86400000;

193-

return {

194-

totalUsers: users.length,

195-

c2cUsers: users.filter((u) => u.type === "c2c").length,

196-

groupUsers: users.filter((u) => u.type === "group").length,

197-

activeIn24h: users.filter((u) => now - u.lastSeenAt < day).length,

198-

activeIn7d: users.filter((u) => now - u.lastSeenAt < 7 * day).length,

199-

};

200-

}

201-202-

/** Remove one user record. */

203-

export function removeKnownUser(

204-

accountId: string,

205-

openid: string,

206-

type: ChatScope = "c2c",

207-

groupOpenid?: string,

208-

): boolean {

209-

const cache = loadUsersFromFile();

210-

const key = makeUserKey({ accountId, openid, type, groupOpenid });

211-

if (cache.has(key)) {

212-

cache.delete(key);

213-

isDirty = true;

214-

saveUsersToFile();

215-

debugLog(`[known-users] Removed user ${openid}`);

216-

return true;

217-

}

218-

return false;

219-

}

220-221-

/** Clear all user records, optionally scoped to one account. */

222-

export function clearKnownUsers(accountId?: string): number {

223-

const cache = loadUsersFromFile();

224-

let count = 0;

225-

if (accountId) {

226-

for (const [key, user] of cache.entries()) {

227-

if (user.accountId === accountId) {

228-

cache.delete(key);

229-

count++;

230-

}

231-

}

232-

} else {

233-

count = cache.size;

234-

cache.clear();

235-

}

236-

if (count > 0) {

237-

isDirty = true;

238-

doSaveUsersToFile();

239-

debugLog(`[known-users] Cleared ${count} users`);

240-

}

241-

return count;

242-

}

243-244-

/** Return all groups in which a user has interacted. */

245-

export function getUserGroups(accountId: string, openid: string): string[] {

246-

return listKnownUsers({ accountId, type: "group" })

247-

.filter((u) => u.openid === openid && u.groupOpenid)

248-

.map((u) => u.groupOpenid!);

249-

}

250-251-

/** Return all recorded members for one group. */

252-

export function getGroupMembers(accountId: string, groupOpenid: string): KnownUser[] {

253-

return listKnownUsers({ accountId, type: "group" }).filter((u) => u.groupOpenid === groupOpenid);

254-

}