Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/skill-first-message-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

web: Fix the session title not being generated when the first message is a skill slash command.
17 changes: 17 additions & 0 deletions packages/kap-server/src/routes/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
* `skill_activation` origin. The returned `Turn` handle is
* discarded; clients follow progress via the `skill.activated`
* + `turn.*` events emitted by the service on the WS stream.
* The edge then applies the prompt-metadata update
* (`applyPromptMetadataUpdate`) so a first `/<skill>`
* message titles the session, matching the native RPC path.
*
* **Model projection**: `SkillDefinition` (v2) → protocol `SkillDescriptor`,
* byte-for-byte with v1's `toProtocolSkill`
Expand Down Expand Up @@ -72,9 +75,11 @@ import {
IAgentSkillService,
IBootstrapService,
IConfigService,
IEventService,
IPluginService,
ISessionIndex,
ISessionLifecycleService,
ISessionMetadata,
ISessionSkillCatalog,
ISkillCatalogRuntimeOptions,
ISkillDiscovery,
Expand All @@ -83,8 +88,10 @@ import {
isError2,
MERGE_ALL_AVAILABLE_SKILLS_SECTION,
SKILL_SOURCE_PRIORITY,
applyPromptMetadataUpdate,
configuredRoots,
projectRoots,
promptMetadataTextFromSkill,
userRoots,
type ISessionScopeHandle,
type Scope,
Expand Down Expand Up @@ -284,6 +291,16 @@ export function registerSkillsRoutes(app: SkillsRouteHost, core: Scope): void {
await agent.accessor
.get(IAgentSkillService)
.activate({ name: parsed.id, args: req.body.args });
// Keep the easy-title behavior of the native RPC / TUI path: a first
// `/<skill>` message titles the session (same as routes/prompts.ts).
await applyPromptMetadataUpdate(
{
metadata: resolved.handle.accessor.get(ISessionMetadata),
eventService: core.accessor.get(IEventService),
sessionId: session_id,
},
promptMetadataTextFromSkill({ name: parsed.id, args: req.body.args }),
);
requestLog(req)?.info({ session_id, skill_name: parsed.id }, 'skill activated');
reply.send(okEnvelope({ activated: true, skill_name: parsed.id }, req.id));
} catch (err) {
Expand Down
15 changes: 15 additions & 0 deletions packages/kap-server/test/skills.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,21 @@ describe('server-v2 /api/v1 skills', () => {
});
});

it('derives the session title from the first skill activation', async () => {
const id = await createSession();
await createMainAgent(id);

const activated = await postJson<{ activated: boolean; skill_name: string }>(
`/api/v1/sessions/${id}/skills/update-config:activate`,
{ args: '--help' },
);
expect(activated.body.code).toBe(0);

const got = await getJson<{ title: string }>(`/api/v1/sessions/${id}`);
expect(got.body.code).toBe(0);
expect(got.body.data.title).toBe('/update-config --help');
});

it('returns 40415 for an unknown skill', async () => {
const id = await createSession();
await createMainAgent(id);
Expand Down
Loading