dsh-lark-agent 0.3.3 → 0.5.0
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/README.md +10 -5
- package/dist/bot-service.js +4 -2
- package/dist/bridge.d.ts +27 -1
- package/dist/bridge.js +333 -66
- package/dist/card-actions.js +3 -1
- package/dist/client/AgentSettings.d.ts +12 -0
- package/dist/client/ConnectionCard.d.ts +5 -1
- package/dist/client/ManagerPanel.d.ts +3 -0
- package/dist/client/api.d.ts +14 -2
- package/dist/client/index.d.ts +1 -1
- package/dist/client/manager-styles.d.ts +2 -0
- package/dist/client/use-connection.d.ts +2 -2
- package/dist/client.cjs +727 -258
- package/dist/config.d.ts +4 -0
- package/dist/config.js +8 -0
- package/dist/dsh-runtime.d.ts +3 -0
- package/dist/dsh-runtime.js +46 -4
- package/dist/lark-cli.d.ts +20 -1
- package/dist/lark-cli.js +168 -2
- package/dist/media-input.d.ts +28 -0
- package/dist/media-input.js +127 -0
- package/dist/media-scopes.d.ts +5 -0
- package/dist/media-scopes.js +6 -0
- package/dist/message.d.ts +7 -0
- package/dist/message.js +27 -3
- package/dist/onboarding/agents.d.ts +9 -0
- package/dist/onboarding/agents.js +100 -0
- package/dist/onboarding/controller.d.ts +15 -2
- package/dist/onboarding/controller.js +155 -14
- package/dist/onboarding/host.d.ts +14 -2
- package/dist/onboarding/host.js +49 -32
- package/dist/onboarding/lark-platform.d.ts +6 -0
- package/dist/onboarding/lark-platform.js +15 -4
- package/dist/onboarding/manager.d.ts +32 -0
- package/dist/onboarding/manager.js +129 -0
- package/dist/onboarding/model-check.d.ts +5 -0
- package/dist/onboarding/model-check.js +51 -0
- package/dist/onboarding/protocol.d.ts +51 -1
- package/dist/onboarding/settings-store.d.ts +11 -0
- package/dist/onboarding/settings-store.js +67 -0
- package/dist/replies.d.ts +16 -0
- package/dist/replies.js +37 -11
- package/dist/session-controls.d.ts +34 -0
- package/dist/session-controls.js +66 -0
- package/dist/session-store.d.ts +7 -1
- package/dist/session-store.js +44 -11
- package/dist/topic-cards.d.ts +3 -0
- package/dist/topic-cards.js +8 -0
- package/dist/topic-store.d.ts +40 -0
- package/dist/topic-store.js +192 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ In the sidebar, open **插件 → 添加插件** (Plugins → Add plugin), enter
|
|
|
35
35
|
[`dsh plugin`](https://www.npmjs.com/package/@deepseek-ai/dsh) runs pnpm, so pnpm must be on your PATH:
|
|
36
36
|
|
|
37
37
|
```sh
|
|
38
|
-
dsh plugin --profile web add dsh-lark-agent --allow-build=protobufjs
|
|
38
|
+
dsh plugin --profile web add dsh-lark-agent@0.5.0 --allow-build=protobufjs
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Then restart `dsh web`.
|
|
@@ -51,7 +51,7 @@ Then restart `dsh web`.
|
|
|
51
51
|
|
|
52
52
|
### Update
|
|
53
53
|
|
|
54
|
-
When a new version has been out for a day, the Feishu settings page shows a notice with these steps (in the desktop app it also opens the plugin list for you). Until then
|
|
54
|
+
When a new version has been out for a day, the Feishu settings page shows a notice with these steps (in the desktop app it also opens the plugin list for you). Until then, installs without an exact version, including `@latest`, still select the previous version because pnpm 11 skips releases less than 24 hours old. Use the exact version in the installation example above to install this release immediately after publication. If an install picks an older version that your DeepSeek Harness rejects as incompatible, see [Troubleshooting](https://github.com/Nirvana-Jie/dsh-lark-agent/blob/main/DEVELOPMENT.md#排障).
|
|
55
55
|
|
|
56
56
|
1. On the Feishu settings page, click **暂停连接** (pause) and back up as described in [Upgrade](https://github.com/Nirvana-Jie/dsh-lark-agent/blob/main/DEVELOPMENT.md#升级).
|
|
57
57
|
2. Desktop app: the Add plugin dialog says third-party plugins must be uninstalled before a new version is installed, so uninstall `dsh-lark-agent` on the Plugins page and add it again (this in-app upgrade hasn't been tested end to end yet; an earlier source build is listed as `dsh-larkbot`). CLI: run `dsh plugin --profile web update dsh-lark-agent@latest`, then restart `dsh web`.
|
|
@@ -61,24 +61,27 @@ When a new version has been out for a day, the Feishu settings page shows a noti
|
|
|
61
61
|
|
|
62
62
|
Button labels are quoted in Chinese, as they appear, with an English gloss.
|
|
63
63
|
|
|
64
|
-
1. Open
|
|
64
|
+
1. Open **设置 → 飞书 agent** (Settings → Feishu agent) in the desktop app, or **设置 → 插件 → 飞书 agent** on the web. Choose a robot and click **扫码创建并连接** (scan to create and connect). Use **添加机器人** (add robot) for another Agent; each robot has its own preset and workspace settings.
|
|
65
65
|
2. Scan the QR code with your own Feishu account and approve. If your organization requires admin approval, click **重新检查** (check again) once it is approved.
|
|
66
66
|
3. Click **打开飞书私聊** (open private chat) and, from the account that scanned, send the pairing word (`DSH-…`, valid for 10 minutes) as a plain-text message on its own, exactly as shown. If asked, confirm with **这是我,完成连接** (this is me).
|
|
67
67
|
4. When the page shows **已连接** (connected), send the bot a message.
|
|
68
68
|
|
|
69
|
-
The Feishu entry works only while the host is online: not when the app is closed, the web host is stopped, or the computer sleeps.
|
|
69
|
+
The connection's model check does not create a “飞书连接测试” conversation in Harness. The Feishu entry works only while the host is online: not when the app is closed, the web host is stopped, or the computer sleeps.
|
|
70
70
|
|
|
71
71
|
## What it can do
|
|
72
72
|
|
|
73
73
|
| In Feishu, you… | The assistant… |
|
|
74
74
|
| --- | --- |
|
|
75
75
|
| Send a request | Works on it with Harness's own tools (web search, reading pages, workspace files and more), streaming the reply live into one card; its thinking and tool steps are folded inside, step by step as in the app, and the card ends with the model, thinking depth and permission mode it used |
|
|
76
|
+
| Use several assistants | Manages up to 10 Feishu robots from one page, each with its own Agent preset, workspace, connection and history; pause a robot to edit its settings. Preset selection is available when the host provides it |
|
|
77
|
+
| Send images in your private Harness chat | Reads PNG, JPEG, WebP or GIF through the host's durable attachments, when the selected model supports images; up to 4 images, 10 MB each |
|
|
78
|
+
| Send a voice message | Use **开通语音权限** (authorize voice) for that robot, then pause, enable and save voice input. Transcribes up to 60 seconds of Chinese / English speech and replies in text; requires FFmpeg and a tenant plan that supports ASR |
|
|
76
79
|
| Ask for something that needs your OK | Sends a confirmation card: tap **允许一次** (allow once) or **拒绝** (deny); no answer within 5 minutes means it won't run |
|
|
77
80
|
| Get asked to choose by Harness | Sends a choice card: tap an option, or fill it in and submit |
|
|
78
81
|
| Use `/permission`, or **设置 → 权限模式** (Settings → Permission mode) in the bottom menu | Switches between read-only, workspace edits and full access, like the app's permission selector; full access stops asking. The card you tap updates in place and turns green when done |
|
|
79
82
|
| Ask for the result file | Sends files from its workspace straight to the chat |
|
|
80
83
|
| Say "lead with the conclusion from now on" | Remembers the preference |
|
|
81
|
-
|
|
|
84
|
+
| Continue inside a topic, or use `/sessions`, `/new` | Keeps each conversation in its own native Feishu topic; reply beneath a new topic's entry card, or use the searchable, paged dropdown to reopen an earlier topic |
|
|
82
85
|
| Ask for a bar chart of some numbers | Replies with a native Feishu chart card |
|
|
83
86
|
| Ask it to let you pick between options first | Sends a form card and continues once you submit |
|
|
84
87
|
| Ask for an architecture diagram or a report | Creates a Feishu doc (with a whiteboard for diagrams) shared read-only with you alone; in App `0.2.1-rc.2` / `rc.3`, opening that Feishu session in the app also shows a local preview |
|
|
@@ -86,6 +89,8 @@ The Feishu entry works only while the host is online: not when the app is closed
|
|
|
86
89
|
|
|
87
90
|
By default it answers only your own private chat. In that chat the assistant is your Harness itself: the tools it can use and the actions that need your confirmation follow the permission settings on your computer. Sessions and memory stay on the computer running Harness; messages pass through Feishu and your model provider.
|
|
88
91
|
|
|
92
|
+
A new request in the main chat opens a topic; continue inside that topic to keep its context. Authorized group chats work the same way and still require an @mention on each message. `/new` opens another topic and keeps the earlier ones available.
|
|
93
|
+
|
|
89
94
|
## Good to know
|
|
90
95
|
|
|
91
96
|
- **More docs**: commands, privacy, upgrades, the chat bottom menu, team deployment and troubleshooting are in [DEVELOPMENT.md](https://github.com/Nirvana-Jie/dsh-lark-agent/blob/main/DEVELOPMENT.md) (Chinese).
|
package/dist/bot-service.js
CHANGED
|
@@ -14,6 +14,7 @@ import { ModelPreferencesStore } from './model-preferences.js';
|
|
|
14
14
|
import { ArtifactStore } from './artifacts.js';
|
|
15
15
|
import { LarkArtifactPublisher } from './artifact-publisher.js';
|
|
16
16
|
import { PermissionPreferencesStore } from './permission-preferences.js';
|
|
17
|
+
import { TopicStore } from './topic-store.js';
|
|
17
18
|
/** A failed close is still an owned service, never a disposable startup error. */
|
|
18
19
|
export class BotServiceStartError extends Error {
|
|
19
20
|
service;
|
|
@@ -38,6 +39,7 @@ export async function createBotService(ctx, config, onHealth = () => undefined,
|
|
|
38
39
|
config.cardInteractions ? CardActions.open(config.stateDir, JSON.stringify([config.profile, config.botOpenId])) : undefined,
|
|
39
40
|
DirectChatsStore.open(config.stateDir), ModelPreferencesStore.open(config.stateDir), ArtifactStore.open(config.stateDir),
|
|
40
41
|
PermissionPreferencesStore.open(config.stateDir),
|
|
42
|
+
TopicStore.open(config.stateDir),
|
|
41
43
|
];
|
|
42
44
|
// An opener may create signing state: finish all openers before releasing
|
|
43
45
|
// ownership after a sibling fails, so no old writer outlives the lock.
|
|
@@ -45,7 +47,7 @@ export async function createBotService(ctx, config, onHealth = () => undefined,
|
|
|
45
47
|
const failed = openedStores.find(result => result.status === 'rejected');
|
|
46
48
|
if (failed?.status === 'rejected')
|
|
47
49
|
throw failed.reason;
|
|
48
|
-
const [sessions, memories, actions, directChats, modelPreferences, artifacts, permissionPreferences] = await Promise.all(openingStores);
|
|
50
|
+
const [sessions, memories, actions, directChats, modelPreferences, artifacts, permissionPreferences, topics] = await Promise.all(openingStores);
|
|
49
51
|
if (startup?.directChat) {
|
|
50
52
|
const { openId, chatId } = startup.directChat;
|
|
51
53
|
if (!config.users.some(user => user.openId === openId && user.direct))
|
|
@@ -61,7 +63,7 @@ export async function createBotService(ctx, config, onHealth = () => undefined,
|
|
|
61
63
|
? new LarkCli({ profile: config.profile, executable: config.executable, eventKey: 'application.bot.menu_v6' }) : undefined;
|
|
62
64
|
const progressTransport = config.loadingReaction
|
|
63
65
|
? new LarkCli({ profile: config.profile, executable: config.executable, commandTimeoutMs: 5_000 }) : undefined;
|
|
64
|
-
const bridge = new BotBridge(config, new DshRuntime(ctx), transport, ledger, { sessions, memories, actions, directChats, modelPreferences, artifacts, permissionPreferences }, event => console.info(`[im-larkbot] ${JSON.stringify(event)}`), progressTransport, new LarkArtifactPublisher(config.profile, config.botOpenId, { executable: config.executable }));
|
|
66
|
+
const bridge = new BotBridge(config, new DshRuntime(ctx), transport, ledger, { sessions, memories, actions, directChats, modelPreferences, artifacts, permissionPreferences, topics }, event => console.info(`[im-larkbot] ${JSON.stringify(event)}`), progressTransport, new LarkArtifactPublisher(config.profile, config.botOpenId, { executable: config.executable }));
|
|
65
67
|
let stopped = false, started = false, healthy = false;
|
|
66
68
|
const readiness = { messages: false, cards: !callbacks, menu: !menu };
|
|
67
69
|
let stopping;
|
package/dist/bridge.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { type ModelPreferencesStore } from './model-preferences.js';
|
|
|
10
10
|
import type { PermissionPreferencesStore } from './permission-preferences.js';
|
|
11
11
|
import type { ArtifactStore } from './artifacts.js';
|
|
12
12
|
import type { ArtifactPublisher } from './artifact-publisher.js';
|
|
13
|
+
import { type TopicStore, type TopicReceipt } from './topic-store.js';
|
|
14
|
+
import { type MediaTransport } from './media-input.js';
|
|
13
15
|
export interface Runtime {
|
|
14
16
|
create(policy: AgentPolicy): Promise<RuntimeSession>;
|
|
15
17
|
resume(policy: AgentPolicy, id: string): Promise<RuntimeSession>;
|
|
@@ -32,8 +34,9 @@ export interface BotState {
|
|
|
32
34
|
};
|
|
33
35
|
artifacts?: Pick<ArtifactStore, 'add' | 'get' | 'list' | 'claimPublish' | 'publication' | 'submit'>;
|
|
34
36
|
permissionPreferences?: Pick<PermissionPreferencesStore, 'get' | 'set'>;
|
|
37
|
+
topics?: Pick<TopicStore, 'get' | 'list' | 'record' | 'occupied'>;
|
|
35
38
|
}
|
|
36
|
-
export interface Transport {
|
|
39
|
+
export interface Transport extends MediaTransport {
|
|
37
40
|
reply(messageId: string, text: string, options: {
|
|
38
41
|
idempotencyKey: string;
|
|
39
42
|
inThread: boolean;
|
|
@@ -69,6 +72,15 @@ export interface Transport {
|
|
|
69
72
|
inThread: boolean;
|
|
70
73
|
image: boolean;
|
|
71
74
|
}): Promise<void>;
|
|
75
|
+
openTopic?(target: {
|
|
76
|
+
chatId: string;
|
|
77
|
+
messageId?: string;
|
|
78
|
+
}, title: string, options: {
|
|
79
|
+
idempotencyKey: string;
|
|
80
|
+
chatType?: 'p2p' | 'group';
|
|
81
|
+
textOnly?: boolean;
|
|
82
|
+
}): Promise<TopicReceipt>;
|
|
83
|
+
topicLink?(messageId: string): Promise<string | undefined>;
|
|
72
84
|
}
|
|
73
85
|
export type Audit = (event: {
|
|
74
86
|
stage: string;
|
|
@@ -97,6 +109,8 @@ export declare class BotBridge {
|
|
|
97
109
|
private readonly progress;
|
|
98
110
|
private readonly interactions;
|
|
99
111
|
private liveUnavailableUntil;
|
|
112
|
+
private readonly topicCreations;
|
|
113
|
+
private readonly topicResumes;
|
|
100
114
|
constructor(config: BotConfig, runtime: Runtime, transport: Transport, ledger: MessageLedger, state: BotState, audit?: Audit, progressTransport?: ProgressTransport, artifactPublisher?: ArtifactPublisher | undefined);
|
|
101
115
|
setCardActionsReady(ready: boolean): void;
|
|
102
116
|
private parseIncoming;
|
|
@@ -131,8 +145,19 @@ export declare class BotBridge {
|
|
|
131
145
|
/** Redraw a stale card with the current state, without running its command. */
|
|
132
146
|
private refreshPanel;
|
|
133
147
|
private commandFeedback;
|
|
148
|
+
private topicsEnabled;
|
|
149
|
+
private topicScope;
|
|
150
|
+
private newTopicKey;
|
|
151
|
+
private entryKey;
|
|
152
|
+
private reserveTopic;
|
|
153
|
+
private createTopic;
|
|
134
154
|
private context;
|
|
135
155
|
private sessionContext;
|
|
156
|
+
private catalogContext;
|
|
157
|
+
/** Only this user's chat and current disclosure epoch participate in the picker. */
|
|
158
|
+
private topicSessions;
|
|
159
|
+
private continueTopic;
|
|
160
|
+
private topicNavigation;
|
|
136
161
|
private policy;
|
|
137
162
|
private ensureSession;
|
|
138
163
|
private bindRestoredSession;
|
|
@@ -154,6 +179,7 @@ export declare class BotBridge {
|
|
|
154
179
|
private permissionCommand;
|
|
155
180
|
/** Bring a newly opened harness session to the chat's choice, or a new one without a choice to the App's default. */
|
|
156
181
|
private applyPermission;
|
|
182
|
+
private permissionContext;
|
|
157
183
|
/** A preset changed in the App on this chat's live session becomes the chat's choice, so new sessions keep it. */
|
|
158
184
|
private adoptPermission;
|
|
159
185
|
private modelState;
|