MCPcopy Create free account
hub / github.com/TraderAlice/OpenAlice / dispatchHeadlessTaskMethod

Function dispatchHeadlessTaskMethod

src/workspaces/service.ts:543–639  ·  view source on GitHub ↗
(
    ws: WorkspaceMeta,
    adapter: CliAdapter,
    prompt: string,
    timeoutMs: number,
    // The firing issue's id, when this dispatch came from the ScheduleScanner.
    // Manual/external runs (the workspace "run task" route) leave it undefined.
    issueId?: string,
  )

Source from the content-addressed store, hash-verified

541 * Throws `HeadlessCapacityError` when too many tasks are already in flight.
542 */
543 const dispatchHeadlessTaskMethod = async (
544 ws: WorkspaceMeta,
545 adapter: CliAdapter,
546 prompt: string,
547 timeoutMs: number,
548 // The firing issue's id, when this dispatch came from the ScheduleScanner.
549 // Manual/external runs (the workspace "run task" route) leave it undefined.
550 issueId?: string,
551 ): Promise<{ taskId: string }> => {
552 if (!adapter.capabilities.headless || !adapter.composeHeadlessCommand) {
553 throw new Error(`adapter "${adapter.id}" has no headless mode`);
554 }
555 await ensureAgentCredentialReady({
556 meta: ws,
557 agentId: adapter.id,
558 adapter,
559 logger: launcherLogger,
560 });
561 if (headlessTasks.runningCount() >= MAX_CONCURRENT_HEADLESS) {
562 throw new HeadlessCapacityError(MAX_CONCURRENT_HEADLESS);
563 }
564 const rec = await headlessTasks.create({
565 wsId: ws.id,
566 agent: adapter.id,
567 prompt,
568 startedAt: Date.now(),
569 ...(issueId ? { issueId } : {}),
570 });
571 // Fire-and-forget: run to natural exit, then fill the record. NOTE: status
572 // is judged by exit code — pi can exit 0 on an in-band model error, so
573 // "done" means "process exited cleanly", not "the agent succeeded"; the
574 // operator confirms via the Inbox / the task's tail.
575 void runHeadlessTaskMethod(ws, adapter, prompt, timeoutMs, {
576 taskId: rec.taskId,
577 onSessionId: (id) =>
578 void headlessTasks
579 .setAgentSessionId(rec.taskId, id)
580 .catch((err) =>
581 launcherLogger.warn('headless.session_id_record_failed', { taskId: rec.taskId, err }),
582 ),
583 })
584 .then(async (r) => {
585 const status = r.killed ? 'failed' : r.exitCode === 0 ? 'done' : 'failed';
586 await headlessTasks.complete(rec.taskId, {
587 status,
588 finishedAt: Date.now(),
589 durationMs: r.durationMs,
590 exitCode: r.exitCode,
591 signal: r.signal,
592 killed: r.killed,
593 });
594 // Scheduled one-shot issues are the only board items whose lifecycle can
595 // be closed mechanically from a run exit. Repeating schedules keep their
596 // issue open; failed one-shots stay open so the operator can inspect and
597 // decide whether to rerun.
598 try {
599 const issueCompletion = await completeOneShotIssueAfterRun({
600 wsDir: ws.dir,

Callers

nothing calls this directly

Calls 9

runHeadlessTaskMethodFunction · 0.85
runningCountMethod · 0.80
warnMethod · 0.80
infoMethod · 0.80
createMethod · 0.65
completeMethod · 0.65
setAgentSessionIdMethod · 0.45

Tested by

no test coverage detected