mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 09:37:28 +00:00
✨ feat(types): foundation types for CC Task block (LOBE-7392)
Sets up the data shape for rendering CC subagent spawns as inline `task` blocks inside the parent assistantGroup, replacing the role:'task' message intermediary that was previously proposed in PR #13928. Pure data layer — no DB schema migration, no new columns. - TaskBlock + AssistantContentBlock.tasks?: derived view that the MessageTransformer will populate by joining Threads onto the parent message's tool_use entries (follow-up commit). Carries threadId, subagentType, description, status — enough for the folded inline header without re-fetching the thread on every render pass. - ThreadMetadata gains sourceToolCallId, subagentType, description. sourceToolCallId disambiguates parallel subagents that share a sourceMessageId (one assistant turn can spawn multiple Task tool_uses in one batch). - CreateThreadParams.id + zod schema field + thread router passthrough lets clients allocate the threadId synchronously before the create mutation resolves. The CC adapter emits Task tool_use synchronously while the create call is async, so having the id up-front lets us persist subagent inner messages with the right threadId without a queue or blocking the stream. - ClaudeCodeApiName.Task + TaskArgs match the CC tool_use shape (description, prompt, subagent_type) so executor / renderer can type the input safely. Refs LOBE-7392 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8ef2620644
commit
16d73261f9
4 changed files with 92 additions and 0 deletions
|
|
@ -17,6 +17,16 @@ export enum ClaudeCodeApiName {
|
|||
Grep = 'Grep',
|
||||
Read = 'Read',
|
||||
Skill = 'Skill',
|
||||
/**
|
||||
* Spawns a subagent. CC emits this as a regular `tool_use`; downstream
|
||||
* events for the subagent's internal turns are tagged with
|
||||
* `parent_tool_use_id` pointing back at this tool_use's id, and the
|
||||
* subagent's final answer arrives as the `tool_result` for this id.
|
||||
* The executor turns this into a Thread (linked via
|
||||
* `metadata.sourceToolCallId = tool_use.id`) instead of a separate
|
||||
* `role: 'task'` message.
|
||||
*/
|
||||
Task = 'Task',
|
||||
TodoWrite = 'TodoWrite',
|
||||
ToolSearch = 'ToolSearch',
|
||||
Write = 'Write',
|
||||
|
|
@ -60,3 +70,15 @@ export interface ToolSearchArgs {
|
|||
max_results?: number;
|
||||
query?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for CC's built-in `Task` tool. The model fills these in when it
|
||||
* decides to delegate work to a subagent: the description shows up in the
|
||||
* folded header, the prompt becomes the subagent's initial user message, and
|
||||
* `subagent_type` selects which subagent template handles it.
|
||||
*/
|
||||
export interface TaskArgs {
|
||||
description?: string;
|
||||
prompt?: string;
|
||||
subagent_type?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,43 @@ export interface ChatFileItem {
|
|||
url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A subagent execution embedded inline in the parent assistant block.
|
||||
*
|
||||
* Used for Claude Code's `Task` tool (and equivalent subagent-spawning tools):
|
||||
* the LLM emits a Task tool_use, the executor creates a Thread to run the
|
||||
* subagent, and the rendered block shows a folded header + (on expand) the
|
||||
* Thread's child messages — instead of producing a separate `role: 'task'`
|
||||
* ChatItem bubble.
|
||||
*
|
||||
* Derived view, not persisted: the MessageTransformer reconstructs
|
||||
* `block.tasks[]` by joining Threads (`threads.sourceMessageId = msg.id`,
|
||||
* matched by `metadata.sourceToolCallId === tool_use.id`) onto the parent
|
||||
* message's tool_use entries.
|
||||
*/
|
||||
export interface TaskBlock {
|
||||
/** Description from the spawning tool_use input (e.g. CC Task `description`) */
|
||||
description?: string;
|
||||
/** Execution duration in milliseconds (Thread.metadata.duration) */
|
||||
duration?: number;
|
||||
/** Error details when subagent failed */
|
||||
error?: any;
|
||||
/** Equals the parent tool_use id that spawned this subagent */
|
||||
id: string;
|
||||
/** Subagent type, e.g. CC's `subagent_type` input (Explore, Plan, ...) */
|
||||
subagentType?: string;
|
||||
/** Status of the underlying Thread */
|
||||
threadId: string;
|
||||
/** Title pulled from the thread (defaults to description) */
|
||||
title?: string;
|
||||
/** Total cost in dollars */
|
||||
totalCost?: number;
|
||||
/** Total tokens consumed */
|
||||
totalTokens?: number;
|
||||
/** Total tool calls made by the subagent */
|
||||
totalToolCalls?: number;
|
||||
}
|
||||
|
||||
export interface AssistantContentBlock {
|
||||
content: string;
|
||||
error?: ChatMessageError | null;
|
||||
|
|
@ -50,6 +87,13 @@ export interface AssistantContentBlock {
|
|||
metadata?: Record<string, any>;
|
||||
performance?: ModelPerformance;
|
||||
reasoning?: ModelReasoning;
|
||||
/**
|
||||
* Subagent executions embedded inline. Disambiguated from regular tools
|
||||
* because each task carries a Thread reference and renders as a folded
|
||||
* panel (showing the Thread's child messages on expand) instead of a
|
||||
* standalone tool result.
|
||||
*/
|
||||
tasks?: TaskBlock[];
|
||||
tools?: ChatToolPayloadWithResult[];
|
||||
usage?: ModelUsage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,26 @@ export interface ThreadMetadata {
|
|||
clientMode?: boolean;
|
||||
/** Task completion time */
|
||||
completedAt?: string;
|
||||
/** Description of the task (e.g. CC Task tool's `description` input) */
|
||||
description?: string;
|
||||
/** Execution duration in milliseconds */
|
||||
duration?: number;
|
||||
/** Error details when task failed */
|
||||
error?: any;
|
||||
/** Operation ID for tracking */
|
||||
operationId?: string;
|
||||
/**
|
||||
* The specific tool_use id within `sourceMessageId` that spawned this thread.
|
||||
* Used to position the thread inline as a `task` block within the parent
|
||||
* message's content stream — e.g. CC's `Task` tool_use spawning a subagent.
|
||||
* Multiple threads can share the same `sourceMessageId` (parallel subagents),
|
||||
* disambiguated by this field.
|
||||
*/
|
||||
sourceToolCallId?: string;
|
||||
/** Task start time, used to calculate duration */
|
||||
startedAt?: string;
|
||||
/** Subagent type identifier, e.g. CC's `subagent_type` input (Explore, Plan, ...) */
|
||||
subagentType?: string;
|
||||
/** Total cost in dollars */
|
||||
totalCost?: number;
|
||||
/** Total messages created during execution */
|
||||
|
|
@ -77,6 +89,14 @@ export interface CreateThreadParams {
|
|||
agentId?: string;
|
||||
/** Group ID for group chat context */
|
||||
groupId?: string;
|
||||
/**
|
||||
* Optional client-provided id. Lets the caller derive the thread id
|
||||
* synchronously (e.g. when wiring CC subagent threads from the stream
|
||||
* adapter, where the id needs to be known before the create call returns
|
||||
* so subagent inner messages can be persisted with the right `threadId`).
|
||||
* Falls back to the schema's `idGenerator` when omitted.
|
||||
*/
|
||||
id?: string;
|
||||
/** Initial metadata for the thread */
|
||||
metadata?: ThreadMetadata;
|
||||
parentThreadId?: string;
|
||||
|
|
@ -91,10 +111,13 @@ export interface CreateThreadParams {
|
|||
export const threadMetadataSchema = z.object({
|
||||
clientMode: z.boolean().optional(),
|
||||
completedAt: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
duration: z.number().optional(),
|
||||
error: z.any().optional(),
|
||||
operationId: z.string().optional(),
|
||||
sourceToolCallId: z.string().optional(),
|
||||
startedAt: z.string().optional(),
|
||||
subagentType: z.string().optional(),
|
||||
totalCost: z.number().optional(),
|
||||
totalMessages: z.number().optional(),
|
||||
totalTokens: z.number().optional(),
|
||||
|
|
@ -104,6 +127,7 @@ export const threadMetadataSchema = z.object({
|
|||
export const createThreadSchema = z.object({
|
||||
agentId: z.string().optional(),
|
||||
groupId: z.string().optional(),
|
||||
id: z.string().optional(),
|
||||
metadata: threadMetadataSchema.optional(),
|
||||
parentThreadId: z.string().optional(),
|
||||
sourceMessageId: z.string().optional(),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const threadProcedure = authedProcedure.use(serverDatabase).use(async (opts) =>
|
|||
export const threadRouter = router({
|
||||
createThread: threadProcedure.input(createThreadSchema).mutation(async ({ input, ctx }) => {
|
||||
const thread = await ctx.threadModel.create({
|
||||
id: input.id,
|
||||
metadata: input.metadata,
|
||||
parentThreadId: input.parentThreadId,
|
||||
sourceMessageId: input.sourceMessageId,
|
||||
|
|
@ -40,6 +41,7 @@ export const threadRouter = router({
|
|||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const thread = await ctx.threadModel.create({
|
||||
id: input.id,
|
||||
metadata: input.metadata,
|
||||
parentThreadId: input.parentThreadId,
|
||||
sourceMessageId: input.sourceMessageId,
|
||||
|
|
|
|||
Loading…
Reference in a new issue