feat(cowork-service): add runtime todo projection
This commit is contained in:
parent
fdf9286e34
commit
97b731e14f
@ -153,6 +153,33 @@ describe('agent runtime routes', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('projects IPC tasks into shared AgentTodo objects', async () => {
|
||||
call.mockResolvedValue({
|
||||
result: {
|
||||
tasks: [
|
||||
{
|
||||
id: 'task-1',
|
||||
goal: 'Review the repository and summarize changes',
|
||||
status: 'running',
|
||||
createdAt: '2026-04-04T08:00:00.000Z',
|
||||
updatedAt: '2026-04-04T08:10:00.000Z',
|
||||
sessionId: 'sess-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const res = await app.inject({ method: 'GET', url: '/api/agent-runtime/todos' });
|
||||
expect(res.statusCode).toBe(200);
|
||||
const body = JSON.parse(res.payload);
|
||||
expect(body.todos[0]).toMatchObject({
|
||||
todoId: 'todo_task-1',
|
||||
sessionId: 'sess-1',
|
||||
status: 'in-progress',
|
||||
text: 'Review the repository and summarize changes',
|
||||
});
|
||||
});
|
||||
|
||||
it('projects approval audit records into AgentApprovalCheckpoint objects', async () => {
|
||||
mockFetch
|
||||
.mockResolvedValueOnce({
|
||||
|
||||
@ -6,11 +6,13 @@ import {
|
||||
AgentRunSchema,
|
||||
AgentSessionSchema,
|
||||
AgentTaskSchema,
|
||||
AgentTodoSchema,
|
||||
type AgentActionLog,
|
||||
type AgentApprovalCheckpoint,
|
||||
type AgentRun,
|
||||
type AgentSession,
|
||||
type AgentTask,
|
||||
type AgentTodo,
|
||||
} from '@bytelyst/events';
|
||||
import { BadRequestError } from '@bytelyst/errors';
|
||||
import { config } from '../../lib/config.js';
|
||||
@ -146,6 +148,41 @@ function toAgentTask(task: Record<string, unknown>, fallbackNow: string): AgentT
|
||||
});
|
||||
}
|
||||
|
||||
function mapTodoStatus(status: unknown): AgentTodo['status'] {
|
||||
switch (status) {
|
||||
case 'running':
|
||||
return 'in-progress';
|
||||
case 'completed':
|
||||
return 'done';
|
||||
case 'cancelled':
|
||||
return 'dropped';
|
||||
case 'failed':
|
||||
return 'open';
|
||||
case 'pending':
|
||||
default:
|
||||
return 'open';
|
||||
}
|
||||
}
|
||||
|
||||
function toAgentTodo(task: Record<string, unknown>, fallbackNow: string): AgentTodo {
|
||||
const todoId =
|
||||
typeof task.id === 'string' && task.id.length > 0 ? `todo_${task.id}` : `todo_${fallbackNow}`;
|
||||
const createdAt = asIsoString(task.createdAt ?? task.startedAt, fallbackNow);
|
||||
const updatedAt = asIsoString(task.updatedAt ?? task.completedAt ?? createdAt, createdAt);
|
||||
const text =
|
||||
typeof task.goal === 'string' && task.goal.trim().length > 0 ? task.goal.trim() : 'Cowork task';
|
||||
|
||||
return AgentTodoSchema.parse({
|
||||
todoId,
|
||||
sessionId:
|
||||
typeof task.sessionId === 'string' && task.sessionId.length > 0 ? task.sessionId : todoId,
|
||||
text,
|
||||
status: mapTodoStatus(task.status),
|
||||
createdAt,
|
||||
updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
function mapApprovalStatus(action: unknown): AgentApprovalCheckpoint['status'] {
|
||||
switch (action) {
|
||||
case 'approval_granted':
|
||||
@ -381,6 +418,24 @@ export async function agentRuntimeRoutes(app: FastifyInstance) {
|
||||
};
|
||||
});
|
||||
|
||||
app.get('/api/agent-runtime/todos', async req => {
|
||||
if (!bridge.isRunning) {
|
||||
return { todos: [], count: 0 };
|
||||
}
|
||||
|
||||
const resp = await bridge.call('list_tasks', { auth: buildAuth(req) });
|
||||
if (resp.error) throw new BadRequestError(resp.error.message);
|
||||
|
||||
const raw = (resp.result as { tasks?: Record<string, unknown>[] } | undefined)?.tasks ?? [];
|
||||
const now = new Date().toISOString();
|
||||
const todos = raw.map(task => toAgentTodo(task, now));
|
||||
|
||||
return {
|
||||
todos,
|
||||
count: todos.length,
|
||||
};
|
||||
});
|
||||
|
||||
app.get('/api/agent-runtime/approvals', async req => {
|
||||
const records = await fetchApprovalRecords(req);
|
||||
const now = new Date().toISOString();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user