@lincyaw/dsh 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/README.md +22 -2
- package/build/client.mjs +66 -0
- package/build/dist/client.js +90 -0
- package/build/dist/client.json +70 -0
- package/build/ensure.mjs +30 -0
- package/cordis.patch.yml +17 -0
- package/package.json +95 -3
- package/profile.patch.yml +25 -0
- package/rows/context.mjs +7 -0
- package/rows/load.mjs +8 -0
- package/rows/policy.mjs +7 -0
- package/rows/routes.mjs +7 -0
- package/rows/service.mjs +7 -0
- package/rows/skills.mjs +7 -0
- package/rows/tools.mjs +7 -0
- package/rows/turns.mjs +7 -0
- package/rows/workbench.mjs +9 -0
- package/rows/workspaces.mjs +7 -0
- package/skills/presmium-author/SKILL.md +95 -0
- package/skills/presmium-author/references/assistance.md +27 -0
- package/skills/presmium-author/references/code.md +52 -0
- package/skills/presmium-author/references/directives.md +592 -0
- package/skills/presmium-author/references/publishing.md +60 -0
- package/skills/presmium-author/references/writing.md +72 -0
- package/skills/presmium-present/SKILL.md +69 -0
- package/skills/presmium-present/references/classroom.md +46 -0
- package/skills/presmium-present/references/delivery.md +63 -0
- package/skills/presmium-present/references/lecture.md +58 -0
- package/src/client/Frame.tsx +314 -0
- package/src/client/brand.tsx +90 -0
- package/src/client/chrome.tsx +79 -0
- package/src/client/contract.ts +35 -0
- package/src/client/dsh.d.ts +129 -0
- package/src/client/fallback.tsx +49 -0
- package/src/client/frame.css +345 -0
- package/src/client/index.tsx +154 -0
- package/src/client/layout.ts +217 -0
- package/src/client/messages.ts +78 -0
- package/src/client/source.tsx +81 -0
- package/src/client/styles.css +3 -0
- package/src/client/theme.ts +149 -0
- package/src/node/context.ts +55 -0
- package/src/node/dsh.ts +93 -0
- package/src/node/launch.ts +59 -0
- package/src/node/policy.ts +59 -0
- package/src/node/routes.ts +46 -0
- package/src/node/service.ts +280 -0
- package/src/node/skills.ts +46 -0
- package/src/node/tools.ts +43 -0
- package/src/node/turns/index.ts +165 -0
- package/src/node/watchdog.mjs +36 -0
- package/src/node/workbench.ts +43 -0
- package/src/node/workspaces.ts +10 -0
- package/web.patch.yml +190 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import type { DshAgent, DshContext, DshToolExecution } from '../dsh.ts'
|
|
3
|
+
import type { PresmiumSession } from '../service.ts'
|
|
4
|
+
|
|
5
|
+
export const name = 'presmium-turns'
|
|
6
|
+
export const inject = ['presmium', 'tools']
|
|
7
|
+
|
|
8
|
+
export const WRITES = new Set(['write', 'edit', 'str_replace_editor', 'bash', 'pwsh', 'terminal_send'])
|
|
9
|
+
|
|
10
|
+
const REVIEW = '/__presmium/presmium.workspace/review'
|
|
11
|
+
const RETRY_MS = 2000
|
|
12
|
+
|
|
13
|
+
interface LiveAgent extends DshAgent {
|
|
14
|
+
inject(message: unknown): void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface SessionEvent {
|
|
18
|
+
type: string
|
|
19
|
+
data?: { turn?: number }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface Reverted {
|
|
23
|
+
type: 'reverted'
|
|
24
|
+
session: string
|
|
25
|
+
turns?: string
|
|
26
|
+
revision: string
|
|
27
|
+
subject: string
|
|
28
|
+
revertedBy: string
|
|
29
|
+
files: string[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface Turns {
|
|
33
|
+
turn?: number
|
|
34
|
+
document?: PresmiumSession
|
|
35
|
+
wrote: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function labelOf(exec: Readonly<DshToolExecution>): string {
|
|
39
|
+
const args = (exec.arguments ?? {}) as { file_path?: unknown, path?: unknown, command?: unknown, input?: unknown }
|
|
40
|
+
const what = [args.file_path, args.path, args.command, args.input].find(value => typeof value === 'string' && value.trim())
|
|
41
|
+
return what ? `${exec.name} ${String(what).replace(/\s+/g, ' ').trim().slice(0, 160)}` : exec.name
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function revertNotice(event: Reverted): unknown {
|
|
45
|
+
const short = (id: string) => id.slice(0, 10)
|
|
46
|
+
const files = event.files.length ? event.files.join(', ') : 'its files'
|
|
47
|
+
const turns = event.turns ? ` (turns ${event.turns})` : ''
|
|
48
|
+
const text = `[Presmium] The author undid the change this session made${turns}: commit ${short(event.revision)} "${event.subject}", undone by commit ${short(event.revertedBy)}. ${files} ${event.files.length === 1 ? 'is' : 'are'} back as before that change. Read a file again before you edit it, and do not make that change again unless the author asks.`
|
|
49
|
+
const summary = `Presmium: the author undid commit ${short(event.revision)}${turns}`
|
|
50
|
+
return Object.freeze({ id: randomUUID(), role: 'user', content: Object.freeze([Object.freeze({ type: 'text', text })]), source: Object.freeze({ kind: 'presmium', form: 'notice', summary: summary.slice(0, 120) }) })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function apply(ctx: DshContext): void {
|
|
54
|
+
const log = ctx.logger?.('presmium') ?? console
|
|
55
|
+
const sessions = new Map<string, Turns>()
|
|
56
|
+
const agents = new Map<string, LiveAgent>()
|
|
57
|
+
const pending = new Map<string, unknown[]>()
|
|
58
|
+
const turnsOf = (id: string) => {
|
|
59
|
+
let known = sessions.get(id)
|
|
60
|
+
if (!known) sessions.set(id, known = { wrote: false })
|
|
61
|
+
return known
|
|
62
|
+
}
|
|
63
|
+
const parents = new Map<string, string>()
|
|
64
|
+
const reviewerOf = (id: string) => {
|
|
65
|
+
let at = id
|
|
66
|
+
for (let depth = 0; depth < 32 && parents.has(at); depth++) at = parents.get(at)!
|
|
67
|
+
return at
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const post = async (presmium: PresmiumSession, session: string, path: string, body: Record<string, unknown>): Promise<void> => {
|
|
71
|
+
const response = await ctx.presmium.request(`${REVIEW}/${path}`, { body: { session, ...body }, headers: { 'presmium-document': encodeURIComponent(presmium.document.dir) } })
|
|
72
|
+
const text = await response.text()
|
|
73
|
+
if (response.ok) return
|
|
74
|
+
if (path === 'open' && response.status === 404) throw new Error('the workspace is not a git repository, so the author cannot review a change: run git init in it')
|
|
75
|
+
let reason = text
|
|
76
|
+
try {
|
|
77
|
+
reason = (JSON.parse(text) as { error?: string, detail?: string }).error ?? reason
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
throw new Error(reason || `the review answered ${response.status}`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ctx.on('session/event', (session: { id: string }, event: SessionEvent) => {
|
|
84
|
+
if (event.type === 'turn/start' && typeof event.data?.turn === 'number') turnsOf(session.id).turn = event.data.turn
|
|
85
|
+
if (event.type !== 'turn/end') return
|
|
86
|
+
const turns = sessions.get(session.id)
|
|
87
|
+
if (!turns?.wrote || !turns.document) return
|
|
88
|
+
turns.wrote = false
|
|
89
|
+
void post(turns.document, session.id, 'step', { ...turns.turn !== undefined ? { turn: turns.turn } : {}, end: true })
|
|
90
|
+
.catch((error: unknown) => log.warn(`presmium-turns: the end of turn ${turns.turn} of ${session.id} was not told to the review: ${error instanceof Error ? error.message : String(error)}`))
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
ctx.on('tools/execute', async (exec: DshToolExecution, next: () => Promise<unknown>) => {
|
|
94
|
+
const presmium = WRITES.has(exec.name) ? ctx.presmium.session(exec.agent) : undefined
|
|
95
|
+
if (!presmium) return next()
|
|
96
|
+
const session = reviewerOf(presmium.id)
|
|
97
|
+
const turns = turnsOf(session)
|
|
98
|
+
try {
|
|
99
|
+
await post(presmium, session, 'open', turns.turn !== undefined ? { turn: turns.turn } : {})
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(`Presmium: ${error instanceof Error ? error.message : String(error)}. Nothing was changed.`)
|
|
102
|
+
}
|
|
103
|
+
turns.document = presmium
|
|
104
|
+
turns.wrote = true
|
|
105
|
+
try {
|
|
106
|
+
return await next()
|
|
107
|
+
} finally {
|
|
108
|
+
await post(presmium, session, 'step', { ...turns.turn !== undefined ? { turn: turns.turn } : {}, label: labelOf(exec), tool: exec.name })
|
|
109
|
+
.catch((error: unknown) => log.warn(`presmium-turns: no checkpoint after ${exec.name} in ${session}: ${error instanceof Error ? error.message : String(error)}`))
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
ctx.on('agent/created', ({ agent }: { agent: LiveAgent }) => {
|
|
114
|
+
const header = agent.session.header as { origin?: string, parentSession?: string } | undefined
|
|
115
|
+
if (header?.origin === 'subagent' && header.parentSession) parents.set(agent.session.id, header.parentSession)
|
|
116
|
+
agents.set(agent.session.id, agent)
|
|
117
|
+
for (const notice of pending.get(agent.session.id) ?? []) agent.inject(notice)
|
|
118
|
+
pending.delete(agent.session.id)
|
|
119
|
+
})
|
|
120
|
+
ctx.on('agent/disposed', ({ agent }: { agent: LiveAgent }) => {
|
|
121
|
+
if (agents.get(agent.session.id) === agent) agents.delete(agent.session.id)
|
|
122
|
+
})
|
|
123
|
+
ctx.on('session/disposed', (session: { id: string }) => {
|
|
124
|
+
sessions.delete(session.id)
|
|
125
|
+
parents.delete(session.id)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const tell = (event: Reverted) => {
|
|
129
|
+
const notice = revertNotice(event)
|
|
130
|
+
const agent = agents.get(event.session)
|
|
131
|
+
if (agent) agent.inject(notice)
|
|
132
|
+
else pending.set(event.session, [...pending.get(event.session) ?? [], notice])
|
|
133
|
+
log.info(`presmium-turns: told session ${event.session} that commit ${event.revision} was undone`)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const stop = new AbortController()
|
|
137
|
+
const follow = async () => {
|
|
138
|
+
while (!stop.signal.aborted) {
|
|
139
|
+
try {
|
|
140
|
+
const response = await ctx.presmium.request(`${REVIEW}/events`, { headers: { accept: 'text/event-stream' }, signal: stop.signal })
|
|
141
|
+
if (!response.ok || !response.body) throw new Error(`review/events answered ${response.status}`)
|
|
142
|
+
const decoder = new TextDecoder()
|
|
143
|
+
let buffer = ''
|
|
144
|
+
for await (const chunk of response.body) {
|
|
145
|
+
buffer += decoder.decode(chunk as Uint8Array, { stream: true })
|
|
146
|
+
let end: number
|
|
147
|
+
while ((end = buffer.indexOf('\n\n')) >= 0) {
|
|
148
|
+
const block = buffer.slice(0, end)
|
|
149
|
+
buffer = buffer.slice(end + 2)
|
|
150
|
+
const data = block.split('\n').filter(line => line.startsWith('data: ')).map(line => line.slice(6)).join('\n')
|
|
151
|
+
if (!data) continue
|
|
152
|
+
const event = JSON.parse(data) as { type?: string }
|
|
153
|
+
if (event.type === 'reverted') tell(event as Reverted)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (stop.signal.aborted) return
|
|
158
|
+
log.debug(`presmium-turns: the review events: ${error instanceof Error ? error.message : String(error)}`)
|
|
159
|
+
}
|
|
160
|
+
await new Promise(done => setTimeout(done, RETRY_MS).unref())
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
void follow()
|
|
164
|
+
ctx.effect(() => () => stop.abort())
|
|
165
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
3
|
+
|
|
4
|
+
const GRACE_MS = 5000
|
|
5
|
+
|
|
6
|
+
const [command, ...args] = process.argv.slice(2)
|
|
7
|
+
if (!command) {
|
|
8
|
+
process.stderr.write('usage: watchdog.mjs <command> [args...]\n')
|
|
9
|
+
process.exit(2)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const group = (signal) => {
|
|
13
|
+
try {
|
|
14
|
+
process.kill(-process.pid, signal)
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const child = spawn(command, args, { stdio: ['ignore', 'inherit', 'inherit'] })
|
|
20
|
+
let ending = false
|
|
21
|
+
const end = () => {
|
|
22
|
+
if (ending) return
|
|
23
|
+
ending = true
|
|
24
|
+
group('SIGTERM')
|
|
25
|
+
setTimeout(() => group('SIGKILL'), GRACE_MS).unref()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
process.on('SIGTERM', end)
|
|
29
|
+
process.on('SIGINT', end)
|
|
30
|
+
process.stdin.on('end', end).on('close', end).on('error', end)
|
|
31
|
+
process.stdin.resume()
|
|
32
|
+
child.on('error', (error) => {
|
|
33
|
+
process.stderr.write(`watchdog: ${error.message}\n`)
|
|
34
|
+
process.exit(1)
|
|
35
|
+
})
|
|
36
|
+
child.on('exit', () => group('SIGKILL'))
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { DshContext } from './dsh.ts'
|
|
2
|
+
|
|
3
|
+
export const name = 'presmium-workbench'
|
|
4
|
+
export const inject = ['presmium', 'connection', 'webServer']
|
|
5
|
+
|
|
6
|
+
const ICON = `data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="#0F5F5C"/><path d="M11 8h7.5a6.5 6.5 0 0 1 0 13H15v4h-4zM15 12v5h3.5a2.5 2.5 0 0 0 0-5z" fill="#F7F5F0" fill-rule="evenodd"/></svg>')}`
|
|
7
|
+
|
|
8
|
+
export function brandIndex(html: string): string {
|
|
9
|
+
return html
|
|
10
|
+
.replace(/<title>[^<]*<\/title>/, '<title>Presmium</title>')
|
|
11
|
+
.replace(/<link rel="(?:icon|manifest)"[^>]*>\s*/g, '')
|
|
12
|
+
.replace('</head>', `<link rel="icon" type="image/svg+xml" href="${ICON}" />\n</head>`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface WebServer {
|
|
16
|
+
tapIndex(transform: (html: string) => string): () => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function apply(ctx: DshContext & { webServer: WebServer }): void {
|
|
20
|
+
ctx.effect(() => ctx.webServer.tapIndex(brandIndex))
|
|
21
|
+
ctx.connection.fetch.register({
|
|
22
|
+
path: '/api/presmium/context', methods: ['POST'], requestBody: 'buffered',
|
|
23
|
+
async fetch(request) {
|
|
24
|
+
const body = await request.json().catch(() => null) as { session?: unknown, document?: unknown } | null
|
|
25
|
+
if (!body || typeof body.session !== 'string' || !body.session || (body.document !== null && typeof body.document !== 'string')) return new Response('Invalid context', { status: 400 })
|
|
26
|
+
try {
|
|
27
|
+
await ctx.presmium.selectDocument(body.session, body.document)
|
|
28
|
+
return Response.json({ session: body.session, document: body.document })
|
|
29
|
+
} catch {
|
|
30
|
+
return new Response('Unknown document', { status: 400 })
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
ctx.connection.fetch.register({
|
|
35
|
+
path: '/api/presmium/workbench',
|
|
36
|
+
methods: ['GET'],
|
|
37
|
+
requestBody: 'buffered',
|
|
38
|
+
async fetch() {
|
|
39
|
+
const { url, root } = await ctx.presmium.ready
|
|
40
|
+
return new Response(JSON.stringify({ mcp: `${url}/mcp`, root }), { headers: { 'Content-Type': 'application/json' } })
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { basename } from 'node:path'
|
|
2
|
+
import type { DshContext } from './dsh.ts'
|
|
3
|
+
|
|
4
|
+
export const name = 'presmium-workspaces'
|
|
5
|
+
export const inject = ['presmium', 'workspaceRegistry']
|
|
6
|
+
|
|
7
|
+
export async function apply(ctx: DshContext): Promise<void> {
|
|
8
|
+
const { root } = await ctx.presmium.ready
|
|
9
|
+
await ctx.workspaceRegistry.create(root, basename(root))
|
|
10
|
+
}
|
package/web.patch.yml
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
- insert:
|
|
2
|
+
- id: presmium-workspaces
|
|
3
|
+
name: '@lincyaw/dsh/workspaces'
|
|
4
|
+
- id: presmium-routes
|
|
5
|
+
name: '@lincyaw/dsh/routes'
|
|
6
|
+
|
|
7
|
+
- id: workspace-controller
|
|
8
|
+
config:
|
|
9
|
+
documentsDirectory: !!js (process.env.DSH_HOME || `${process.env.XDG_STATE_HOME || `${process.env.HOME}/.local/state`}/presmium/studio`) + '/documents'
|
|
10
|
+
|
|
11
|
+
- id: harness-dev-context
|
|
12
|
+
disabled: true
|
|
13
|
+
|
|
14
|
+
- insert:
|
|
15
|
+
- id: presmium-workbench
|
|
16
|
+
name: '@lincyaw/dsh'
|
|
17
|
+
|
|
18
|
+
- id: ui-layout
|
|
19
|
+
disabled: true
|
|
20
|
+
- id: ui-sidebar
|
|
21
|
+
disabled: true
|
|
22
|
+
- id: ui-brand-official
|
|
23
|
+
disabled: true
|
|
24
|
+
- id: ui-settings-account
|
|
25
|
+
disabled: true
|
|
26
|
+
- id: account-controller
|
|
27
|
+
disabled: true
|
|
28
|
+
- id: deepseek-account
|
|
29
|
+
disabled: true
|
|
30
|
+
- id: llm-deepseek-account
|
|
31
|
+
disabled: true
|
|
32
|
+
- id: web-search-deepseek
|
|
33
|
+
disabled: true
|
|
34
|
+
- id: ui-settings-web-search
|
|
35
|
+
disabled: true
|
|
36
|
+
- id: ui-settings-session-log
|
|
37
|
+
disabled: true
|
|
38
|
+
|
|
39
|
+
# 内置的「创作」预设:Presmium 的作者人设与发布会原则。预设的 persona 遮蔽部署级
|
|
40
|
+
# 的人设(profile.patch.yml),所以这里重述 Presmium 的角色。
|
|
41
|
+
- insert:
|
|
42
|
+
- id: preset-authoring
|
|
43
|
+
name: '@deepseek-ai/dsh-agent-preset'
|
|
44
|
+
config:
|
|
45
|
+
id: authoring
|
|
46
|
+
name: 创作
|
|
47
|
+
description: 面向受众的讲义与演示创作:信息量优先、受众视角、版式不重复。
|
|
48
|
+
order: 0
|
|
49
|
+
plugins:
|
|
50
|
+
- id: persona
|
|
51
|
+
name: '@deepseek-ai/dsh-persona'
|
|
52
|
+
config:
|
|
53
|
+
prefix: |
|
|
54
|
+
You are Presmium's assistant for the authors of lectures, powered by the {{model}} model. You help write and revise lecture documents (MyST Markdown that Presmium renders as a web page, slides and a notebook), run their code and check them, in the author's language.
|
|
55
|
+
|
|
56
|
+
创作或编辑面向受众的内容(讲义、幻灯片、文档、文章及其他展示材料)时,你全程遵守发布会原则:以核心观点和受众价值为中心组织内容,并根据呈现载体调整表达方式。
|
|
57
|
+
|
|
58
|
+
**最高优先级:信息量原则**
|
|
59
|
+
|
|
60
|
+
每一句话都必须有明确的存在意义,对受众理解内容、形成判断或采取行动发挥具体作用。每页、每屏或每个独立内容区块都必须承载有效信息,并承担明确的说明或论证任务。句子、注释、例子、数据和重复说明,都应具有明确作用;删除后不影响受众理解或判断的内容应直接删除。叙事安排、版式变化与语言润色均须服从这一原则,不得为满足形式要求而添加无效内容。
|
|
61
|
+
|
|
62
|
+
1. 围绕最有价值、最有说服力的观点或优势组织叙事,使全部内容共同支撑核心主张。
|
|
63
|
+
2. 按照受众理解问题的逻辑安排内容,避免按个人思考、工作开展或方案尝试的过程罗列经历。
|
|
64
|
+
3. 避免“只是一些浅见”“可能没什么价值”等自我削弱表达,不主动贬低内容的价值。
|
|
65
|
+
4. 根据内容目的与受众需求选择讨论角度、评价维度和比较口径,集中呈现能够充分证明核心价值的内容。
|
|
66
|
+
5. 涉及不同观点、方法或结果时,结合各自目标、适用条件与合理取舍解释差异,避免简单作出优劣判断。
|
|
67
|
+
6. 明确说明核心观点为什么重要、依据是什么,以及能够帮助受众理解或解决什么问题,不依赖受众自行从文字、表格或图形中推导内容价值。
|
|
68
|
+
7. 对于采用分页、分屏或区块布局的材料,相同的排版结构不得连续出现;任意连续五页、五屏或五个主要展示区块内不得重复使用相同的排版结构。
|
|
69
|
+
8. 出现排版结构重复时,应根据内容关系重新组织信息,选择适合的流程、对照、时间线、图表或图文组合等呈现方式,避免通过更换颜色、图标或文字维持相同布局。
|
|
70
|
+
9. 对于幻灯片,单页文字过多时,应优先采用图形化表达,根据内容关系改用流程图、关系图、时间线、数据图表或图文组合,减少连续文字并保留必要信息。图形应承担信息表达和关系说明的作用,避免将整段文字直接放入形状中。
|
|
71
|
+
10. 开头应尽早呈现受众关心的问题、值得讨论的关键、核心观点及最有说服力的依据。
|
|
72
|
+
11. 结尾应强化核心观点与最值得记住的信息,避免突然改变立场或加入自我否定的评价。
|
|
73
|
+
- id: agent-instructions
|
|
74
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
75
|
+
config:
|
|
76
|
+
maxBytes: 65536
|
|
77
|
+
- id: time-context
|
|
78
|
+
name: '@deepseek-ai/dsh-time-context'
|
|
79
|
+
- id: tool-bash
|
|
80
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
81
|
+
disabled: !!js process.platform === 'win32'
|
|
82
|
+
- id: tool-pwsh
|
|
83
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
84
|
+
disabled: !!js process.platform !== 'win32'
|
|
85
|
+
- id: tool-fs
|
|
86
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
87
|
+
- id: tool-fs-search
|
|
88
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
89
|
+
config:
|
|
90
|
+
sampleOverCapGlobResults: false
|
|
91
|
+
- id: tool-jobs
|
|
92
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
93
|
+
- id: tool-schedule
|
|
94
|
+
name: '@deepseek-ai/dsh-tool-schedule'
|
|
95
|
+
- id: skill-filesystem
|
|
96
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
97
|
+
- id: tool-skill
|
|
98
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
99
|
+
- id: command-goal
|
|
100
|
+
name: '@deepseek-ai/dsh-command-goal'
|
|
101
|
+
- id: tool-goal
|
|
102
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
103
|
+
- id: planning
|
|
104
|
+
name: cordis:group
|
|
105
|
+
group: true
|
|
106
|
+
isolate:
|
|
107
|
+
planMode: true
|
|
108
|
+
config:
|
|
109
|
+
- id: plan-mode
|
|
110
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
111
|
+
config:
|
|
112
|
+
section: |
|
|
113
|
+
You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
|
114
|
+
|
|
115
|
+
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
|
116
|
+
|
|
117
|
+
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
|
118
|
+
|
|
119
|
+
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
|
120
|
+
|
|
121
|
+
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
|
122
|
+
|
|
123
|
+
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
|
124
|
+
- id: compaction
|
|
125
|
+
name: cordis:group
|
|
126
|
+
group: true
|
|
127
|
+
isolate:
|
|
128
|
+
compaction: true
|
|
129
|
+
toolResultPruner: true
|
|
130
|
+
config:
|
|
131
|
+
- id: compaction-basic
|
|
132
|
+
name: '@deepseek-ai/dsh-compaction-basic'
|
|
133
|
+
- id: command-compact
|
|
134
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
135
|
+
- id: tool-result-pruner
|
|
136
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
137
|
+
config:
|
|
138
|
+
thresholdChars: 8192
|
|
139
|
+
headChars: 4096
|
|
140
|
+
tailChars: 1024
|
|
141
|
+
- id: delegation
|
|
142
|
+
name: cordis:group
|
|
143
|
+
group: true
|
|
144
|
+
isolate:
|
|
145
|
+
workflowEngine: true
|
|
146
|
+
config:
|
|
147
|
+
- id: tool-subagent-control
|
|
148
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
149
|
+
- id: tool-subagent-list-agents
|
|
150
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
151
|
+
- id: tool-subagent
|
|
152
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
153
|
+
config:
|
|
154
|
+
provider: spawn
|
|
155
|
+
toolName: subagent
|
|
156
|
+
modelSelectionSettings: true
|
|
157
|
+
- id: tool-subagent-fork
|
|
158
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
159
|
+
config:
|
|
160
|
+
provider: fork
|
|
161
|
+
toolName: subagent_fork
|
|
162
|
+
- id: workflow-ptc
|
|
163
|
+
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
164
|
+
config:
|
|
165
|
+
provider: spawn
|
|
166
|
+
- id: tool-workflow
|
|
167
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
168
|
+
- id: tool-ask-user
|
|
169
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
170
|
+
- id: tool-todo
|
|
171
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
172
|
+
config:
|
|
173
|
+
allowParallelInProgress: true
|
|
174
|
+
- id: tool-web
|
|
175
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
176
|
+
config:
|
|
177
|
+
fetch: true
|
|
178
|
+
searchTimeoutMs: 60000
|
|
179
|
+
- id: present
|
|
180
|
+
name: '@deepseek-ai/dsh-tool-present'
|
|
181
|
+
- id: tool-plugin-manager
|
|
182
|
+
name: '@deepseek-ai/dsh-plugin-manager/tools'
|
|
183
|
+
disabled: true
|
|
184
|
+
- id: tool-plugin-market
|
|
185
|
+
name: '@deepseek-ai/dsh-plugin-market/tools'
|
|
186
|
+
disabled: true
|
|
187
|
+
|
|
188
|
+
- id: agent-preset-registry
|
|
189
|
+
config:
|
|
190
|
+
default: authoring
|