@steerable/agent-shell 0.6.66 → 0.6.68
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/host/runtime.js
CHANGED
|
@@ -24,6 +24,7 @@ import { WorktreeService } from '../local-backend/worktree-service.js';
|
|
|
24
24
|
import { TaskService } from '../local-backend/task-service.js';
|
|
25
25
|
import { LoopPtyMonitor } from '../local-backend/loop-pty-monitor.js';
|
|
26
26
|
import { LOCAL_SCOPE, closeStorage, getPackDbAccess, getScopedStore, initializeStorage, watchStorageChanges, } from '../storage/driver.js';
|
|
27
|
+
import { subscribeChatActivity } from '../storage/chat-activity.js';
|
|
27
28
|
import { getUserDataDir } from '../runtime.js';
|
|
28
29
|
import { acquireInstanceLease, bindStorageInstance, } from '../storage/process-locks.js';
|
|
29
30
|
import { createApprovalBridge } from '../sidecar/reverse-approval.js';
|
|
@@ -45,6 +46,10 @@ export async function createHostRuntime(options) {
|
|
|
45
46
|
const broadcastMain = options.broadcastMain ?? broadcast;
|
|
46
47
|
await initializeStorage();
|
|
47
48
|
watchStorageChanges(() => broadcast('store:changed', {}));
|
|
49
|
+
// 本连接写入会话不会推动 data_version。活动时间单独广播,侧边栏据此重排。
|
|
50
|
+
const unsubscribeChatActivity = subscribeChatActivity((activity) => {
|
|
51
|
+
broadcast('chat-activity', activity);
|
|
52
|
+
});
|
|
48
53
|
const scope = options.scope ?? LOCAL_SCOPE;
|
|
49
54
|
const defaultStore = getScopedStore(scope);
|
|
50
55
|
let localBackendRouter;
|
|
@@ -279,6 +284,7 @@ export async function createHostRuntime(options) {
|
|
|
279
284
|
}, 2_000);
|
|
280
285
|
},
|
|
281
286
|
async shutdown() {
|
|
287
|
+
unsubscribeChatActivity();
|
|
282
288
|
if (warmTimer) {
|
|
283
289
|
clearTimeout(warmTimer);
|
|
284
290
|
warmTimer = null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 会话最后活动时间变了之后通知宿主。
|
|
3
|
+
* SQLite 的 data_version 看不到本连接自己的提交,所以不能靠 store:changed
|
|
4
|
+
* 把这次更新送到侧边栏。
|
|
5
|
+
*/
|
|
6
|
+
export interface ChatActivity {
|
|
7
|
+
chatId: string;
|
|
8
|
+
updatedAt: string;
|
|
9
|
+
}
|
|
10
|
+
type ChatActivityListener = (activity: ChatActivity) => void;
|
|
11
|
+
/** 订阅会话活动。返回解除订阅。 */
|
|
12
|
+
export declare function subscribeChatActivity(listener: ChatActivityListener): () => void;
|
|
13
|
+
/** 通知所有订阅者。没有订阅者时不做任何事。 */
|
|
14
|
+
export declare function emitChatActivity(activity: ChatActivity): void;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 会话最后活动时间变了之后通知宿主。
|
|
3
|
+
* SQLite 的 data_version 看不到本连接自己的提交,所以不能靠 store:changed
|
|
4
|
+
* 把这次更新送到侧边栏。
|
|
5
|
+
*/
|
|
6
|
+
const listeners = new Set();
|
|
7
|
+
/** 订阅会话活动。返回解除订阅。 */
|
|
8
|
+
export function subscribeChatActivity(listener) {
|
|
9
|
+
listeners.add(listener);
|
|
10
|
+
return () => {
|
|
11
|
+
listeners.delete(listener);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** 通知所有订阅者。没有订阅者时不做任何事。 */
|
|
15
|
+
export function emitChatActivity(activity) {
|
|
16
|
+
for (const listener of listeners)
|
|
17
|
+
listener(activity);
|
|
18
|
+
}
|
package/dist/storage/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { ALL_ROUND_ASSISTANT_AGENT_ID, LOCAL_ASSISTANT_AGENT_ID, getBrand, } from '../brand.js';
|
|
4
4
|
import { isShellBuiltinAgentEnabled } from '../product-config.js';
|
|
5
5
|
import { DEFAULT_LLM_SETTINGS, llmSettingsCarryExpiredBakedKey, llmSettingsMatchOllamaDefaults, mergeLlmSettings, } from './llm-settings.js';
|
|
6
|
+
import { emitChatActivity } from './chat-activity.js';
|
|
6
7
|
import { MESSAGE_ORDER_DESC } from './message-order.js';
|
|
7
8
|
import { currentStorageInstanceId, instanceOwnerIsLive, } from './process-locks.js';
|
|
8
9
|
import { mergeTelemetrySettings, } from './telemetry-settings.js';
|
|
@@ -727,6 +728,7 @@ export class SqliteScopedStore {
|
|
|
727
728
|
SET title = ?, system_prompt = ?, pinned_refs = ?, is_pinned = ?, project_id = ?, updated_at = ?
|
|
728
729
|
WHERE tenant_id = ? AND user_id = ? AND id = ?
|
|
729
730
|
`).run(next.title, next.systemPrompt, JSON.stringify(next.pinnedRefs ?? null), next.isPinned ? 1 : 0, next.projectId ?? null, next.updatedAt, this.scope.tenantId, this.scope.userId, chatId);
|
|
731
|
+
emitChatActivity({ chatId, updatedAt: next.updatedAt });
|
|
730
732
|
return await this.getChat(chatId);
|
|
731
733
|
}
|
|
732
734
|
async deleteChat(chatId) {
|
|
@@ -867,8 +869,10 @@ export class SqliteScopedStore {
|
|
|
867
869
|
(tenant_id, user_id, id, chat_id, role, content, message_metadata, created_at)
|
|
868
870
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
869
871
|
`).run(this.scope.tenantId, this.scope.userId, id, chatId, role, content, messageMetadata, now);
|
|
870
|
-
this.db.prepare(`UPDATE chat_sessions SET updated_at = ?
|
|
872
|
+
const updated = this.db.prepare(`UPDATE chat_sessions SET updated_at = ?
|
|
871
873
|
WHERE tenant_id = ? AND user_id = ? AND id = ?`).run(now, this.scope.tenantId, this.scope.userId, chatId);
|
|
874
|
+
if (updated.changes > 0)
|
|
875
|
+
emitChatActivity({ chatId, updatedAt: now });
|
|
872
876
|
const row = this.db.prepare(`SELECT * FROM chat_messages WHERE tenant_id = ? AND user_id = ? AND id = ?`).get(this.scope.tenantId, this.scope.userId, id);
|
|
873
877
|
return this.mapChatMessage(row);
|
|
874
878
|
}
|
|
@@ -910,6 +914,7 @@ export class SqliteScopedStore {
|
|
|
910
914
|
*/
|
|
911
915
|
async replaceChatMessages(chatId, messages) {
|
|
912
916
|
const base = Date.now();
|
|
917
|
+
let activity = null;
|
|
913
918
|
const insert = this.db.prepare(`
|
|
914
919
|
INSERT INTO chat_messages
|
|
915
920
|
(tenant_id, user_id, id, chat_id, role, content, message_metadata, created_at)
|
|
@@ -920,11 +925,16 @@ export class SqliteScopedStore {
|
|
|
920
925
|
messages.forEach((m, i) => {
|
|
921
926
|
insert.run(this.scope.tenantId, this.scope.userId, randomUUID(), chatId, m.role, m.content, new Date(base + i).toISOString());
|
|
922
927
|
});
|
|
923
|
-
|
|
928
|
+
const updatedAt = new Date(base + messages.length).toISOString();
|
|
929
|
+
const updated = this.db
|
|
924
930
|
.prepare(`UPDATE chat_sessions SET updated_at = ?
|
|
925
931
|
WHERE tenant_id = ? AND user_id = ? AND id = ?`)
|
|
926
|
-
.run(
|
|
932
|
+
.run(updatedAt, this.scope.tenantId, this.scope.userId, chatId);
|
|
933
|
+
if (updated.changes > 0)
|
|
934
|
+
activity = { chatId, updatedAt };
|
|
927
935
|
})();
|
|
936
|
+
if (activity)
|
|
937
|
+
emitChatActivity(activity);
|
|
928
938
|
}
|
|
929
939
|
async listChatAgents(includeArchived = false) {
|
|
930
940
|
const rows = this.db.prepare(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steerable/agent-shell",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.68",
|
|
4
4
|
"description": "Steerable framework — product-neutral Node HostRuntime and headless HTTP server shared by Tauri desktop and browser deployments; scenario packs extend it through @steerable/pack-sdk.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://steerableframework.com/",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"jpeg-js": "^0.4.4",
|
|
54
54
|
"node-pty": "^1.1.0",
|
|
55
55
|
"pngjs": "^7.0.0",
|
|
56
|
-
"@steerable/agent-harness": "0.6.
|
|
57
|
-
"@steerable/agent-protocol": "0.6.
|
|
58
|
-
"@steerable/pack-sdk": "0.6.
|
|
56
|
+
"@steerable/agent-harness": "0.6.68",
|
|
57
|
+
"@steerable/agent-protocol": "0.6.68",
|
|
58
|
+
"@steerable/pack-sdk": "0.6.68"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/better-sqlite3": "^7.6.13",
|