-
Notifications
You must be signed in to change notification settings - Fork 0
fix(task-board): set task context on spawned sessions #429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -839,6 +839,49 @@ describe('TaskOrchestrator', () => { | |
| expect(deps.setTaskContext).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('does not call setTaskContext (pinned) for spawned sessions', async () => { | ||
| const spawnSession = vi.fn().mockResolvedValue('spawned-client-1'); | ||
| const deps = createTestDeps(store); | ||
| deps.spawnSession = spawnSession; | ||
| const orch = new TaskOrchestrator(deps); | ||
|
|
||
| const goal = store.create({ title: 'Goal' }); | ||
| store.create({ | ||
| title: 'Spawn task', | ||
| parentId: goal.id, | ||
| sessionPolicy: 'spawn', | ||
| }); | ||
|
|
||
| orch.start(goal.id); | ||
|
|
||
| await vi.waitFor(() => { | ||
| expect(spawnSession).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| // Spawned sessions get taskContext via startChat options, not setTaskContext | ||
| expect(deps.setTaskContext).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 missing_tests: The new test 'falls back to setTaskContext (pinned) when spawn returns null' duplicates the existing test at line 656 ('falls back to pinned session when spawnSession returns null'), which also mocks |
||
| it('falls back to setTaskContext (pinned) when spawn returns null', async () => { | ||
| const spawnSession = vi.fn().mockResolvedValue(null); | ||
| const deps = createTestDeps(store); | ||
| deps.spawnSession = spawnSession; | ||
| const orch = new TaskOrchestrator(deps); | ||
|
|
||
| const goal = store.create({ title: 'Goal' }); | ||
| const task = store.create({ | ||
| title: 'Spawn task', | ||
| parentId: goal.id, | ||
| sessionPolicy: 'spawn', | ||
| }); | ||
|
|
||
| orch.start(goal.id); | ||
|
|
||
| await vi.waitFor(() => { | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 missing_tests: The fallback test asserts |
||
| expect(deps.setTaskContext).toHaveBeenCalledWith(task.id, goal.id); | ||
| }); | ||
| }); | ||
|
|
||
| it('reuse policy tasks use pinned session as before', () => { | ||
| const spawnSession = vi.fn().mockResolvedValue('spawned-client-1'); | ||
| const deps = createTestDeps(store); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -745,6 +745,7 @@ export async function startChat( | |
| onSessionResolved?: (sessionId: string) => void; | ||
| telosTaskId?: string; | ||
| agentName?: string; | ||
| taskContext?: { currentTaskId: string; goalId: string }; | ||
| }, | ||
| ) { | ||
| return withSpanAsync( | ||
|
|
@@ -775,6 +776,7 @@ async function _startChatInner( | |
| onSessionResolved?: (sessionId: string) => void; | ||
| telosTaskId?: string; | ||
| agentName?: string; | ||
| taskContext?: { currentTaskId: string; goalId: string }; | ||
| }, | ||
| ) { | ||
| const abortController = new AbortController(); | ||
|
|
@@ -862,6 +864,9 @@ async function _startChatInner( | |
| const session = registry.get(clientId)!; | ||
| session.model = options.model ?? session.model; | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 style: The placement between |
||
| session.inputQueue = inputQueue as { push: (msg: unknown) => void; close: () => void }; | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 missing_tests: The core fix — |
||
| if (options.taskContext) { | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 regressions: The |
||
| session.taskContext = options.taskContext; | ||
| } | ||
| _onSessionChange?.(clientId, 'start'); | ||
|
|
||
| // Session state machine: mark CREATED (Phase 1 — write only, no behavior change) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -255,6 +255,7 @@ const orchestrator = new TaskOrchestrator({ | |
| mode: 'agent', | ||
| isolation: true, | ||
| telosTaskId: goalId, | ||
| taskContext: { currentTaskId: taskId, goalId }, | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 style: Redundant double-set:
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 style: Both |
||
| onSessionResolved: (sessionId) => { | ||
| log.info('spawned headless session resolved', { taskId, sessionId, clientId }); | ||
| sseRegistry.broadcast('sessions_changed', {}); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 missing_tests: The new test 'does not call setTaskContext (pinned) for spawned sessions' duplicates existing coverage: the test at line 824 ('auto policy spawns instead of reusing') already asserts
expect(deps.setTaskContext).not.toHaveBeenCalled()with an identical mock setup (spawnSession returns a clientId). The only difference is explicitsessionPolicy: 'spawn'vs. the default 'auto', but both resolve to the same code path (line 346:const policy = next.sessionPolicy === 'reuse' ? 'reuse' : 'spawn').[fixable]