Merge latest master into skill invocation controls

# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	examples/acp-agent/tests/snapshots/skill-load/session.jsonl
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.md
#	packages/host/apiproxy/README.zh.md
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/skill/tool-skill/src/index.ts
#	packages/ui/tui/README.i18n.yaml
This commit is contained in:
Tianyi Cui
2026-07-29 01:29:39 +08:00
665 changed files with 15945 additions and 6555 deletions

View File

@@ -8,7 +8,8 @@ import type { Context } from 'cordis'
import z from 'schemastery'
import type { Agent } from '@deepseek-ai/dsh-agent'
import { defineTool } from '@deepseek-ai/dsh-tools'
import { assertNever, type Message } from '@deepseek-ai/dsh-llm'
import { assertNever, createUserMessage } from '@deepseek-ai/dsh-llm'
import type { UserMessage } from '@deepseek-ai/dsh-session'
import {
isModelInvocable,
isSkillName,
@@ -132,7 +133,7 @@ export function apply(ctx: Context, config: Config = {}): void {
.filter(isModelInvocable)
if (skills.length > 0) {
const catalog = renderCatalogMessage(skills, catalogDescriptionMaxLength)
agent.inject({ content: catalog.content, source: { kind: 'plugin', plugin: 'dsh-tool-skill' } })
agent.inject(catalog)
}
catalogLoaded.add(agent.session)
})
@@ -184,10 +185,9 @@ function renderResourceHint(skill: Pick<SkillDefinition, 'provider' | 'resourceB
}
}
function renderCatalogMessage(skills: SkillSummary[], descriptionMaxLength: number): Message {
function renderCatalogMessage(skills: SkillSummary[], descriptionMaxLength: number): UserMessage {
const entries = skills.map(skill => `- \`${skill.name}\`: ${catalogDescription(skill.description, descriptionMaxLength)}`)
return {
role: 'user',
return createUserMessage({
content: [{
type: 'text',
text: [
@@ -202,7 +202,8 @@ function renderCatalogMessage(skills: SkillSummary[], descriptionMaxLength: numb
'</system-reminder>',
].join('\n'),
}],
}
source: { kind: 'plugin', plugin: 'dsh-tool-skill' },
})
}
function catalogDescription(value: string, maxLength: number): string {

View File

@@ -3,8 +3,8 @@ import { mkdir, writeFile } from 'node:fs/promises'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import { Context } from 'cordis'
import { CallId, type Message } from '@deepseek-ai/dsh-llm'
import { AgentMessageId } from '@deepseek-ai/dsh-agent'
import { createUserMessage, CallId, type Message } from '@deepseek-ai/dsh-llm'
import {} from '@deepseek-ai/dsh-agent'
import { Session, SessionId } from '@deepseek-ai/dsh-session'
import { createScope, type Scope } from '@deepseek-ai/dsh-scope'
import SystemPrompt, { renderPrompt } from '@deepseek-ai/dsh-system-prompt'
@@ -46,12 +46,11 @@ function agentForCwd(cwd: string): Agent {
session,
status: 'idle',
acceptsNextStep: false,
send: () => AgentMessageId('stub'),
followup: () => AgentMessageId('stub'),
steer: () => AgentMessageId('stub'),
send: () => {},
followup: () => {},
steer: () => {},
inject(input) {
session.append('user/message', input, { surfaceOp: 'append' })
return AgentMessageId('stub')
},
cancel() {},
whenIdle: () => Promise.resolve(),
@@ -158,14 +157,16 @@ describe('dsh-tool-skill', () => {
content: 'User-only body.',
})
ctx.on('agent/step', (agent) => {
agent.inject({ content: [{ type: 'text', text: 'later contribution' }], source: { kind: 'plugin', plugin: 'later-contribution' } })
agent.inject(createUserMessage({ content: [{ type: 'text', text: 'later contribution' }], source: { kind: 'plugin', plugin: 'later-contribution' } }))
})
const prefix = await composePrefix(ctx, '/workspace')
expect(prefix).toEqual([
{
id: expect.any(String) as unknown,
role: 'user',
source: { kind: 'plugin', plugin: 'dsh-tool-skill' },
content: [{
type: 'text',
text: [
@@ -183,7 +184,12 @@ describe('dsh-tool-skill', () => {
].join('\n'),
}],
},
{ role: 'user', content: [{ type: 'text', text: 'later contribution' }] },
{
id: expect.any(String) as unknown,
role: 'user',
content: [{ type: 'text', text: 'later contribution' }],
source: { kind: 'plugin', plugin: 'later-contribution' },
},
])
const rendered = JSON.stringify(prefix[0])
expect(rendered).not.toContain('whenToUse')