@ours.network/fleet 1.1.0-nightly.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +231 -46
- package/dist/application/capabilities.js +18 -6
- package/dist/application/fleet-query-service.js +7 -4
- package/dist/application/role-command-service.js +9 -0
- package/dist/application/role-creation-service.d.ts +4 -4
- package/dist/application/role-creation-service.js +8 -1
- package/dist/application/role-repository.d.ts +4 -2
- package/dist/application/role-repository.js +6 -3
- package/dist/application/session-control.d.ts +3 -1
- package/dist/application/session-control.js +4 -2
- package/dist/application/task-room-service.d.ts +92 -39
- package/dist/application/task-room-service.js +562 -289
- package/dist/briefing.js +79 -22
- package/dist/build-info.json +5 -5
- package/dist/canonical-json.d.ts +2 -0
- package/dist/canonical-json.js +10 -0
- package/dist/cli.js +129 -47
- package/dist/config.d.ts +38 -3
- package/dist/config.js +193 -28
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +7 -4
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +181 -41
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +40 -4
- package/dist/fleet-command-audit.d.ts +22 -1
- package/dist/fleet-command-audit.js +355 -50
- package/dist/fleet-proxy.d.ts +5 -2
- package/dist/harness/claude-code-session.js +2 -1
- package/dist/harness/codex-app-server-proxy.d.ts +40 -0
- package/dist/harness/codex-app-server-proxy.js +348 -14
- package/dist/harness/codex-session.d.ts +9 -2
- package/dist/harness/codex-session.js +18 -2
- package/dist/harness/codex.d.ts +5 -1
- package/dist/harness/codex.js +104 -10
- package/dist/harness/types.d.ts +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/init-guidance.d.ts +1 -1
- package/dist/init-guidance.js +1 -1
- package/dist/init-wizard.d.ts +98 -0
- package/dist/init-wizard.js +631 -0
- package/dist/lifecycle-summary.d.ts +134 -0
- package/dist/lifecycle-summary.js +179 -0
- package/dist/loops/config.d.ts +10 -1
- package/dist/loops/config.js +38 -5
- package/dist/model-recovery.d.ts +1 -1
- package/dist/ops.js +2 -17
- package/dist/owner-channel/channel.d.ts +19 -3
- package/dist/owner-channel/channel.js +301 -120
- package/dist/owner-channel/commands.d.ts +28 -6
- package/dist/owner-channel/commands.js +109 -27
- package/dist/owner-channel/lifecycle-outbox.d.ts +24 -0
- package/dist/owner-channel/lifecycle-outbox.js +87 -0
- package/dist/owner-channel/ours-client.d.ts +19 -0
- package/dist/owner-channel/ours-client.js +3 -0
- package/dist/permissions.js +1 -1
- package/dist/preset-migration.d.ts +42 -0
- package/dist/preset-migration.js +450 -0
- package/dist/reports/artifact.d.ts +10 -0
- package/dist/reports/artifact.js +32 -0
- package/dist/reports/index.d.ts +5 -0
- package/dist/reports/index.js +5 -0
- package/dist/reports/render.d.ts +6 -0
- package/dist/reports/render.js +240 -0
- package/dist/reports/service.d.ts +42 -0
- package/dist/reports/service.js +57 -0
- package/dist/reports/tasks.d.ts +52 -0
- package/dist/reports/tasks.js +177 -0
- package/dist/reports/types.d.ts +315 -0
- package/dist/reports/types.js +6 -0
- package/dist/resolved-plan.js +13 -1
- package/dist/rooms-tasks/cli.d.ts +2 -0
- package/dist/rooms-tasks/cli.js +361 -285
- package/dist/rooms-tasks/close.d.ts +9 -1
- package/dist/rooms-tasks/close.js +23 -7
- package/dist/rooms-tasks/config.js +16 -25
- package/dist/rooms-tasks/cowork-adapter.d.ts +5 -0
- package/dist/rooms-tasks/cowork-adapter.js +13 -0
- package/dist/rooms-tasks/deletion.d.ts +51 -0
- package/dist/rooms-tasks/deletion.js +217 -0
- package/dist/rooms-tasks/external-worker.d.ts +8 -0
- package/dist/rooms-tasks/external-worker.js +38 -0
- package/dist/rooms-tasks/launch-snapshot.d.ts +19 -0
- package/dist/rooms-tasks/launch-snapshot.js +181 -0
- package/dist/rooms-tasks/member-overrides.d.ts +30 -0
- package/dist/rooms-tasks/member-overrides.js +204 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +9 -2
- package/dist/rooms-tasks/provision.js +146 -83
- package/dist/rooms-tasks/room-state.d.ts +1 -0
- package/dist/rooms-tasks/room-state.js +12 -1
- package/dist/rooms-tasks/task-room-name.d.ts +12 -0
- package/dist/rooms-tasks/task-room-name.js +61 -0
- package/dist/rooms-tasks/task-state.d.ts +115 -3
- package/dist/rooms-tasks/task-state.js +361 -11
- package/dist/rooms-tasks/templates.d.ts +4 -1
- package/dist/rooms-tasks/templates.js +34 -3
- package/dist/rooms-tasks/terminal.d.ts +3 -0
- package/dist/rooms-tasks/terminal.js +10 -4
- package/dist/rooms-tasks/types.d.ts +92 -7
- package/dist/rooms-tasks/types.js +14 -1
- package/dist/runner.d.ts +3 -0
- package/dist/runner.js +91 -44
- package/dist/session/acp.d.ts +4 -1
- package/dist/session/acp.js +29 -13
- package/dist/session/arbiter.d.ts +2 -1
- package/dist/session/arbiter.js +2 -0
- package/dist/session/codex-app-server-transport.d.ts +53 -0
- package/dist/session/codex-app-server-transport.js +184 -0
- package/dist/session/codex-app-server.d.ts +122 -0
- package/dist/session/codex-app-server.js +1031 -0
- package/dist/session/control.d.ts +1 -1
- package/dist/session/control.js +17 -1
- package/dist/session/conversation-types.d.ts +4 -4
- package/dist/session/types.d.ts +24 -6
- package/dist/session/types.js +28 -0
- package/dist/spawn.d.ts +9 -0
- package/dist/spawn.js +77 -9
- package/dist/web/fleet-config-service.d.ts +1 -0
- package/dist/web/fleet-config-service.js +25 -7
- package/dist/web/runtime.js +11 -6
- package/dist/web/server.js +28 -1
- package/dist/web-app/assets/{index-BbTc5KtZ.js → index-C0h3ALvs.js} +8 -8
- package/dist/web-app/index.html +1 -1
- package/package.json +4 -4
- package/presets/brain-catalog.json +17 -0
- package/presets/fleet/{agents → agent_templates}/Critic.yaml +2 -0
- package/presets/fleet/{agents/Agent.yaml → agent_templates/Developer.yaml} +3 -1
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +50 -0
- package/presets/fleet/agents/{Developer.yaml → FleetCoordinator.yaml} +1 -1
- package/presets/fleet/brains/claude-fable-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +37 -0
- package/presets/fleet/roles/Critic.yaml +23 -1
- package/presets/fleet/roles/Developer.yaml +27 -5
- package/presets/fleet/roles/LocalCoordinator.yaml +35 -0
- package/presets/fleet/room_templates/pair.yaml +9 -7
- package/presets/fleet/room_templates/single.yaml +5 -4
- package/presets/fleet/room_templates/team.yaml +12 -8
- package/presets/manifest.json +2 -1
- package/presets/fleet/agents/Architect.yaml +0 -3
- package/presets/fleet/agents/Secretary.yaml +0 -3
- package/presets/fleet/agents/Tester.yaml +0 -3
- package/presets/fleet/roles/Agent.yaml +0 -6
- package/presets/fleet/roles/Architect.yaml +0 -6
- package/presets/fleet/roles/Secretary.yaml +0 -6
- package/presets/fleet/roles/Tester.yaml +0 -6
|
@@ -1,14 +1,45 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { canonicalJson } from '../canonical-json.js';
|
|
3
|
+
import { redactLaunchDefinition, sealLaunchSnapshot } from './launch-snapshot.js';
|
|
2
4
|
export function hashTemplate(t) {
|
|
3
|
-
const canonical =
|
|
5
|
+
const canonical = canonicalJson({
|
|
4
6
|
name: t.name, version: t.version, description: t.description,
|
|
5
7
|
room: t.room, contract: t.contract, members: t.members,
|
|
6
8
|
});
|
|
7
9
|
return createHash('sha256').update(canonical).digest('hex');
|
|
8
10
|
}
|
|
9
|
-
export function snapshotTemplate(t) {
|
|
11
|
+
export function snapshotTemplate(t, agentTemplates) {
|
|
10
12
|
const { sourceFile: _, ...semantic } = t;
|
|
11
|
-
return { ...semantic,
|
|
13
|
+
return { ...semantic, members: semantic.members.map(member => {
|
|
14
|
+
const definition = agentTemplates?.[member.agent_template];
|
|
15
|
+
return {
|
|
16
|
+
...member,
|
|
17
|
+
...(definition ? {
|
|
18
|
+
agent_projection: redactLaunchDefinition(definition),
|
|
19
|
+
agent_template_hash: createHash('sha256').update(canonicalJson(definition)).digest('hex'),
|
|
20
|
+
} : {}),
|
|
21
|
+
};
|
|
22
|
+
}), content_hash: agentTemplates ? createHash('sha256').update(canonicalJson({
|
|
23
|
+
template: hashTemplate(t),
|
|
24
|
+
members: semantic.members.map(member => ({
|
|
25
|
+
agent_template: member.agent_template,
|
|
26
|
+
agent_template_hash: agentTemplates?.[member.agent_template]
|
|
27
|
+
? createHash('sha256').update(canonicalJson(agentTemplates[member.agent_template])).digest('hex')
|
|
28
|
+
: null,
|
|
29
|
+
})),
|
|
30
|
+
})).digest('hex') : hashTemplate(t) };
|
|
31
|
+
}
|
|
32
|
+
/** Explicit mutation boundary immediately before Task/Room plan persistence. */
|
|
33
|
+
export function sealTemplateSnapshot(snapshot, agentTemplates, launchDefinitions) {
|
|
34
|
+
const referenced = Object.fromEntries([...new Set(snapshot.members.map(member => member.launch_definition_id ?? member.agent_template))]
|
|
35
|
+
.sort().map(id => {
|
|
36
|
+
const member = snapshot.members.find(candidate => (candidate.launch_definition_id ?? candidate.agent_template) === id);
|
|
37
|
+
const definition = launchDefinitions?.[id] ?? agentTemplates[member.agent_template];
|
|
38
|
+
if (!definition)
|
|
39
|
+
throw new Error(`Agent Template '${id}' not found`);
|
|
40
|
+
return [id, definition];
|
|
41
|
+
}));
|
|
42
|
+
return { ...snapshot, launch_snapshot_hash: sealLaunchSnapshot(referenced) };
|
|
12
43
|
}
|
|
13
44
|
export function resolveTemplate(name, customTemplates) {
|
|
14
45
|
const atIdx = name.lastIndexOf('@');
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type RoomCloseDeps } from './close.js';
|
|
2
2
|
import type { CoworkAdapter } from './cowork-adapter.js';
|
|
3
3
|
import type { TaskOutcome, TaskRecord, TaskTerminalIntent } from './types.js';
|
|
4
|
+
export declare const TASK_OPERATION_LOCK_STALE_MS: number;
|
|
5
|
+
/** Common per-task operation lock serializing terminal, deletion, and recovery acceptance. */
|
|
6
|
+
export declare function taskOperationLockPath(taskId: string): string;
|
|
4
7
|
export interface TaskTerminalInput {
|
|
5
8
|
taskId: string;
|
|
6
9
|
kind: TaskTerminalIntent['kind'];
|
|
@@ -2,10 +2,11 @@ import { join } from 'node:path';
|
|
|
2
2
|
import { withFileLock } from '../atomic-file.js';
|
|
3
3
|
import { stateRoot } from '../paths.js';
|
|
4
4
|
import { deleteManagedRoom } from './close.js';
|
|
5
|
-
import { beginTaskTerminalIntent, finishTaskTerminalIntent, getTask, setTaskTerminalIntentError, } from './task-state.js';
|
|
5
|
+
import { assertNoPendingDeletion, beginTaskTerminalIntent, finishTaskTerminalIntent, getTask, setTaskTerminalIntentError, } from './task-state.js';
|
|
6
6
|
import { getRoomRecord } from './room-state.js';
|
|
7
|
-
const TASK_OPERATION_LOCK_STALE_MS = 10 * 60_000;
|
|
8
|
-
|
|
7
|
+
export const TASK_OPERATION_LOCK_STALE_MS = 10 * 60_000;
|
|
8
|
+
/** Common per-task operation lock serializing terminal, deletion, and recovery acceptance. */
|
|
9
|
+
export function taskOperationLockPath(taskId) {
|
|
9
10
|
return join(stateRoot(), 'locks', 'task-terminal', encodeURIComponent(taskId));
|
|
10
11
|
}
|
|
11
12
|
function errorText(error) {
|
|
@@ -24,6 +25,9 @@ export function acceptTaskTerminalIntent(input) {
|
|
|
24
25
|
export function settleTaskTerminalIntent(input) {
|
|
25
26
|
return withFileLock(taskOperationLockPath(input.taskId), async () => {
|
|
26
27
|
const current = getTask(input.taskId);
|
|
28
|
+
// Deletion supersedes a pending terminal intent: fail boundedly before any
|
|
29
|
+
// room side effect so the deletion worker owns all remaining cleanup.
|
|
30
|
+
assertNoPendingDeletion(current);
|
|
27
31
|
const intent = current.terminal_intent;
|
|
28
32
|
if (!intent)
|
|
29
33
|
throw new Error(`task ${input.taskId} has no accepted terminal intent`);
|
|
@@ -45,7 +49,9 @@ export function settleTaskTerminalIntent(input) {
|
|
|
45
49
|
return finishTaskTerminalIntent(input.taskId);
|
|
46
50
|
}
|
|
47
51
|
catch (error) {
|
|
48
|
-
setTaskTerminalIntentError(input.taskId, errorText(error),
|
|
52
|
+
setTaskTerminalIntentError(input.taskId, errorText(error), intent.kind === 'cancelled'
|
|
53
|
+
? `Retry 'ours-fleet task cancel ${input.taskId} ${input.taskId}'.`
|
|
54
|
+
: `Retry 'ours-fleet task done ${input.taskId}'.`);
|
|
49
55
|
throw error;
|
|
50
56
|
}
|
|
51
57
|
}, {}, TASK_OPERATION_LOCK_STALE_MS);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* membership, and archive. Messenger Server owns owner presentation.
|
|
6
6
|
* Fleet stores only IDs, CIDs, orchestration state, and saga cursors.
|
|
7
7
|
*/
|
|
8
|
+
import type { AgentLaunchConfiguration } from '../lifecycle-summary.js';
|
|
8
9
|
export type TaskState = 'backlog' | 'provisioning' | 'active' | 'review' | 'done' | 'cancelled' | 'failed';
|
|
9
10
|
export declare const TASK_TERMINAL_STATES: readonly TaskState[];
|
|
10
11
|
export declare const TASK_CANCELLABLE_STATES: readonly TaskState[];
|
|
@@ -44,6 +45,47 @@ export interface TaskTerminalIntent {
|
|
|
44
45
|
first_failure?: string;
|
|
45
46
|
first_recovery_hint?: string;
|
|
46
47
|
}
|
|
48
|
+
/** Origin evidence for an accepted deletion; retained until the record is unlinked. */
|
|
49
|
+
export type TaskDeletionActor = {
|
|
50
|
+
kind: 'local_control';
|
|
51
|
+
surface: 'cli' | 'web';
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'authenticated_owner';
|
|
54
|
+
surface: 'messenger';
|
|
55
|
+
cid: string;
|
|
56
|
+
};
|
|
57
|
+
export type TaskDeletionMemberPhase = 'pending' | 'stop_requested' | 'liveness_absent' | 'archive_secured' | 'identity_absent';
|
|
58
|
+
/**
|
|
59
|
+
* Durable retirement cursor for a managed member when no room orchestration
|
|
60
|
+
* record exists to carry the equivalent seat cursor.
|
|
61
|
+
*/
|
|
62
|
+
export interface TaskDeletionMemberCursor {
|
|
63
|
+
name: string;
|
|
64
|
+
identity_cid: string;
|
|
65
|
+
phase: TaskDeletionMemberPhase;
|
|
66
|
+
launch_id?: string;
|
|
67
|
+
archive_path?: string;
|
|
68
|
+
updated_at: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* First-wins durable deletion intent. There is no settled status: settlement
|
|
72
|
+
* ends by unlinking the task record, so physical absence is the completion
|
|
73
|
+
* evidence. While pending, the task is hidden from normal operation and every
|
|
74
|
+
* lifecycle mutation or room publication is rejected.
|
|
75
|
+
*/
|
|
76
|
+
export interface TaskDeletionIntent {
|
|
77
|
+
status: 'pending';
|
|
78
|
+
accepted_at: string;
|
|
79
|
+
actor: TaskDeletionActor;
|
|
80
|
+
room_id?: string;
|
|
81
|
+
/** Snapshot of managed members at acceptance; the missing-room retirement evidence. */
|
|
82
|
+
members: TaskDeletionMemberCursor[];
|
|
83
|
+
error?: string;
|
|
84
|
+
error_at?: string;
|
|
85
|
+
recovery_hint?: string;
|
|
86
|
+
first_failure?: string;
|
|
87
|
+
first_recovery_hint?: string;
|
|
88
|
+
}
|
|
47
89
|
export interface TaskRecord {
|
|
48
90
|
task_id: string;
|
|
49
91
|
/** Stable organizational list identifier. Missing legacy values mean `default`. */
|
|
@@ -56,6 +98,14 @@ export interface TaskRecord {
|
|
|
56
98
|
state: TaskState;
|
|
57
99
|
blocked?: TaskBlocked;
|
|
58
100
|
template?: TaskTemplateRef;
|
|
101
|
+
execution_plan?: {
|
|
102
|
+
schema_version: 1;
|
|
103
|
+
snapshot: TemplateSnapshot;
|
|
104
|
+
room_policy?: RoomLaunchPolicy;
|
|
105
|
+
overrides: Record<string, unknown>;
|
|
106
|
+
overrides_hash: string;
|
|
107
|
+
plan_hash: string;
|
|
108
|
+
};
|
|
59
109
|
no_room?: boolean;
|
|
60
110
|
room_id?: string;
|
|
61
111
|
room_identity_cid?: string;
|
|
@@ -67,6 +117,7 @@ export interface TaskRecord {
|
|
|
67
117
|
ended_at?: string;
|
|
68
118
|
outcome?: TaskOutcome;
|
|
69
119
|
terminal_intent?: TaskTerminalIntent;
|
|
120
|
+
deletion?: TaskDeletionIntent;
|
|
70
121
|
}
|
|
71
122
|
export interface TaskListRecord {
|
|
72
123
|
list_id: string;
|
|
@@ -82,7 +133,7 @@ export interface SagaCursor {
|
|
|
82
133
|
error?: string;
|
|
83
134
|
recovery_hint?: string;
|
|
84
135
|
}
|
|
85
|
-
export type ProvisioningDetail = 'waiting_cowork' | 'waiting_owner_invite' | 'owner_cid_mismatch' | 'member_failed' | 'waiting_seats' | 'uncertain';
|
|
136
|
+
export type ProvisioningDetail = 'waiting_cowork' | 'waiting_owner_authorization' | 'waiting_owner_invite' | 'owner_cid_mismatch' | 'member_failed' | 'waiting_seats' | 'uncertain';
|
|
86
137
|
export interface RoomRoleBriefingDefinition {
|
|
87
138
|
role: string;
|
|
88
139
|
text: string;
|
|
@@ -103,6 +154,13 @@ export interface RoomMemberLaunchState {
|
|
|
103
154
|
/** Redacted, deterministic effective Agent launch definition retained for retry inspection. */
|
|
104
155
|
agent_definition?: Record<string, unknown>;
|
|
105
156
|
agent_fingerprint?: string;
|
|
157
|
+
agent_template?: string;
|
|
158
|
+
agent_template_hash?: string;
|
|
159
|
+
/**
|
|
160
|
+
* Operator-facing launch configuration captured from the exact resolved
|
|
161
|
+
* launch state; the single source for later Task/Room lifecycle reports.
|
|
162
|
+
*/
|
|
163
|
+
presentation?: AgentLaunchConfiguration;
|
|
106
164
|
launch_id?: string;
|
|
107
165
|
updated_at: string;
|
|
108
166
|
error?: string;
|
|
@@ -175,6 +233,8 @@ export interface RoomOrchestrationRecord {
|
|
|
175
233
|
goal?: string;
|
|
176
234
|
task_id?: string;
|
|
177
235
|
template_snapshot?: TemplateSnapshot;
|
|
236
|
+
/** Resolved once at launch; legacy absence means non-anonymous. */
|
|
237
|
+
room_policy?: RoomLaunchPolicy;
|
|
178
238
|
saga: SagaCursor;
|
|
179
239
|
provisioning_detail?: ProvisioningDetail;
|
|
180
240
|
owner_seat_cid?: string;
|
|
@@ -192,15 +252,19 @@ export interface TemplateMemberSlot {
|
|
|
192
252
|
slot: string;
|
|
193
253
|
role: string;
|
|
194
254
|
count: number;
|
|
195
|
-
/**
|
|
196
|
-
|
|
197
|
-
ref: string;
|
|
198
|
-
};
|
|
255
|
+
/** Stable reference to an inert Agent Template, never a persistent Agent. */
|
|
256
|
+
agent_template: string;
|
|
199
257
|
}
|
|
200
258
|
export interface TemplateRoomConfig {
|
|
201
259
|
quiet_membership?: boolean;
|
|
202
260
|
anonymous?: boolean;
|
|
203
261
|
}
|
|
262
|
+
export interface RoomLaunchPolicy {
|
|
263
|
+
anonymous: boolean;
|
|
264
|
+
}
|
|
265
|
+
export declare const LEGACY_ROOM_LAUNCH_POLICY: Readonly<RoomLaunchPolicy>;
|
|
266
|
+
/** Validate durable policy before it can influence room creation or recovery. */
|
|
267
|
+
export declare function storedRoomLaunchPolicy(value: RoomLaunchPolicy | undefined): RoomLaunchPolicy;
|
|
204
268
|
export interface TemplateDefinition {
|
|
205
269
|
name: string;
|
|
206
270
|
version: number;
|
|
@@ -211,8 +275,27 @@ export interface TemplateDefinition {
|
|
|
211
275
|
contract?: string;
|
|
212
276
|
members: TemplateMemberSlot[];
|
|
213
277
|
}
|
|
214
|
-
export interface
|
|
278
|
+
export interface TemplateSnapshotMember extends TemplateMemberSlot {
|
|
279
|
+
/** Source of the effective temporary-loop policy, independent of its sealed value. */
|
|
280
|
+
loop_source?: 'agent-template' | 'cli' | 'omitted';
|
|
281
|
+
/** Secret-safe public projection; launch material lives in the sealed snapshot. */
|
|
282
|
+
agent_projection?: Record<string, unknown>;
|
|
283
|
+
agent_template_hash?: string;
|
|
284
|
+
/** Private sealed-snapshot lookup key; harmless provenance, not an identity. */
|
|
285
|
+
launch_definition_id?: string;
|
|
286
|
+
role_preset?: {
|
|
287
|
+
id: string;
|
|
288
|
+
hash: string;
|
|
289
|
+
};
|
|
290
|
+
brain_preset?: {
|
|
291
|
+
id: string;
|
|
292
|
+
hash: string;
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
export interface TemplateSnapshot extends Omit<TemplateDefinition, 'members'> {
|
|
296
|
+
members: TemplateSnapshotMember[];
|
|
215
297
|
content_hash: string;
|
|
298
|
+
launch_snapshot_hash?: string;
|
|
216
299
|
}
|
|
217
300
|
export interface RoomsOwnerConfig {
|
|
218
301
|
provider: string;
|
|
@@ -247,4 +330,6 @@ export declare const ROOMS_COWORK_KEYS: readonly ["config"];
|
|
|
247
330
|
export declare const ROOMS_DEFAULTS_KEYS: readonly ["template", "attach_owner", "close_when_task_done"];
|
|
248
331
|
export declare const TASKS_KEYS: readonly ["default_room_template", "create_mode", "close_room_on_done", "retain_completed_for"];
|
|
249
332
|
export declare const TEMPLATE_KEYS: readonly ["version", "description", "room", "contract", "members", "override_builtin"];
|
|
250
|
-
export declare const
|
|
333
|
+
export declare const TEMPLATE_ROOM_KEYS: readonly ["quiet_membership", "anonymous"];
|
|
334
|
+
/** `agent` is accepted only so validation can emit its actionable migration error. */
|
|
335
|
+
export declare const TEMPLATE_MEMBER_KEYS: readonly ["slot", "role", "count", "agent_template", "agent"];
|
|
@@ -7,6 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export const TASK_TERMINAL_STATES = ['done', 'cancelled', 'failed'];
|
|
9
9
|
export const TASK_CANCELLABLE_STATES = ['backlog', 'provisioning', 'active', 'review'];
|
|
10
|
+
export const LEGACY_ROOM_LAUNCH_POLICY = Object.freeze({
|
|
11
|
+
anonymous: false,
|
|
12
|
+
});
|
|
13
|
+
/** Validate durable policy before it can influence room creation or recovery. */
|
|
14
|
+
export function storedRoomLaunchPolicy(value) {
|
|
15
|
+
if (value === undefined)
|
|
16
|
+
return { ...LEGACY_ROOM_LAUNCH_POLICY };
|
|
17
|
+
if (typeof value.anonymous !== 'boolean')
|
|
18
|
+
throw new Error('invalid durable Room launch policy; anonymous must be a boolean');
|
|
19
|
+
return { ...value };
|
|
20
|
+
}
|
|
10
21
|
// ── Validation keys ─────────────────────────────────────────────────────
|
|
11
22
|
export const ROOMS_KEYS = ['cowork', 'owner', 'defaults'];
|
|
12
23
|
export const ROOMS_OWNER_KEYS = ['provider', 'public_invite', 'public_invite_file', 'expected_cid', 'role'];
|
|
@@ -14,4 +25,6 @@ export const ROOMS_COWORK_KEYS = ['config'];
|
|
|
14
25
|
export const ROOMS_DEFAULTS_KEYS = ['template', 'attach_owner', 'close_when_task_done'];
|
|
15
26
|
export const TASKS_KEYS = ['default_room_template', 'create_mode', 'close_room_on_done', 'retain_completed_for'];
|
|
16
27
|
export const TEMPLATE_KEYS = ['version', 'description', 'room', 'contract', 'members', 'override_builtin'];
|
|
17
|
-
export const
|
|
28
|
+
export const TEMPLATE_ROOM_KEYS = ['quiet_membership', 'anonymous'];
|
|
29
|
+
/** `agent` is accepted only so validation can emit its actionable migration error. */
|
|
30
|
+
export const TEMPLATE_MEMBER_KEYS = ['slot', 'role', 'count', 'agent_template', 'agent'];
|
package/dist/runner.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { AgentSession, ExitRecord, TurnResult } from './session/types.js';
|
|
|
7
7
|
import type { AgentSessionAdapter, AgentSessionStartOptions } from './harness/agent-session.js';
|
|
8
8
|
import { type OwnerChannelHandle, type OwnerChannelOptions } from './owner-channel/channel.js';
|
|
9
9
|
import { type OwnerBinderLease } from './owner-channel/binder.js';
|
|
10
|
+
import { ScheduledLoopManager, type ScheduledLoopManagerHandle } from './loops/manager.js';
|
|
10
11
|
export interface RunnerDeps {
|
|
11
12
|
exec: Exec;
|
|
12
13
|
cpuDelegated(): boolean;
|
|
@@ -26,6 +27,8 @@ export interface RunnerDeps {
|
|
|
26
27
|
startAgentSession(adapter: AgentSessionAdapter, options: AgentSessionStartOptions): Promise<AgentSession>;
|
|
27
28
|
/** Construct the authenticated role control route (injectable where sockets are unavailable). */
|
|
28
29
|
createControlServer(stateDir: string, session: AgentSession, log: (line: string) => void): Pick<RoleControlServer, 'start' | 'close' | 'setFleetSpawner' | 'setFleetAuditor' | 'setOwnerChannel' | 'setConfigReloader' | 'setLoopManager'>;
|
|
30
|
+
/** Construct scheduled-loop execution (injectable for fail-closed startup tests). */
|
|
31
|
+
createLoopManager(...args: ConstructorParameters<typeof ScheduledLoopManager>): ScheduledLoopManagerHandle;
|
|
29
32
|
/** Acquire the cross-process owner-channel binder lease before replacing the control socket. */
|
|
30
33
|
acquireOwnerBinder(stateDir: string, role: string, identity: string): Promise<OwnerBinderLease>;
|
|
31
34
|
/** Ask the still-authenticated predecessor to emit the fixed recovery notice. */
|
package/dist/runner.js
CHANGED
|
@@ -14,7 +14,7 @@ import { selectIsolationBackend } from './isolation/registry.js';
|
|
|
14
14
|
import { resourceArgs, cpuControllerDelegated } from './isolation/resources.js';
|
|
15
15
|
import { resolveLaunchRuntime } from './isolation/runtime.js';
|
|
16
16
|
import { controlRequest, RoleControlServer } from './session/control.js';
|
|
17
|
-
import { ACP_CANCEL_DEADLINE_EXCEEDED, classifyShellStatus } from './session/types.js';
|
|
17
|
+
import { ACP_CANCEL_DEADLINE_EXCEEDED, CODEX_APP_SERVER_CANCEL_DEADLINE_EXCEEDED, classifyShellStatus, } from './session/types.js';
|
|
18
18
|
import { effectiveModelForRole, modelRecoveryHeld, reconcileModelRecovery, recordModelFailure, classifyFailureText, } from './model-recovery.js';
|
|
19
19
|
import { rotateWorklog } from './worklog.js';
|
|
20
20
|
import { reconcilePermanentRoleIdentities } from './creation.js';
|
|
@@ -26,6 +26,7 @@ import { FLEET_PROXY_CALLER_ENV, FLEET_PROXY_STATE_DIR_ENV, } from './fleet-prox
|
|
|
26
26
|
import { effectivePermissionMode } from './permissions.js';
|
|
27
27
|
import { assertModelPinReachesChild, effectiveRoleModel, repinModelEnv } from './model-env.js';
|
|
28
28
|
import { archiveTempState, markTempSupervisorActive, requestedTempStopReason, } from './temp-lifecycle.js';
|
|
29
|
+
import { FleetCommandAuditStore } from './fleet-command-audit.js';
|
|
29
30
|
export const SUPERVISOR_RECYCLE_REQUIRED = 'OWNER_CHANNEL_SUPERVISOR_RECYCLE_REQUIRED';
|
|
30
31
|
export class SupervisorRecycleRequiredError extends Error {
|
|
31
32
|
code = SUPERVISOR_RECYCLE_REQUIRED;
|
|
@@ -53,6 +54,7 @@ const defaultDeps = () => ({
|
|
|
53
54
|
createOwnerChannel: opts => new OwnerChannel(opts),
|
|
54
55
|
startAgentSession: (adapter, options) => adapter.start(options),
|
|
55
56
|
createControlServer: (stateDir, session, log) => new RoleControlServer(stateDir, session, log),
|
|
57
|
+
createLoopManager: (...args) => new ScheduledLoopManager(...args),
|
|
56
58
|
acquireOwnerBinder: (stateDir, role, identity) => acquireOwnerBinderLease(stateDir, role, identity),
|
|
57
59
|
reportOwnerStartupFailure: async (stateDir) => {
|
|
58
60
|
const response = await controlRequest(stateDir, {
|
|
@@ -69,6 +71,32 @@ const defaultDeps = () => ({
|
|
|
69
71
|
});
|
|
70
72
|
const MONITOR_OWNER_FILE = '.monitor-owner';
|
|
71
73
|
const OBSOLETE_OURS_AUTOSTART_ENV = 'OURS_AUTOSTART';
|
|
74
|
+
function localFleetAuditor(stateDir, caller, log) {
|
|
75
|
+
const store = new FleetCommandAuditStore(join(stateDir, '.fleet-command-audit.json'));
|
|
76
|
+
return {
|
|
77
|
+
async begin(requestId, argv) {
|
|
78
|
+
let attempt = store.begin(requestId, caller, argv);
|
|
79
|
+
if (attempt.invocation === 'sending') {
|
|
80
|
+
log(`[${caller}] fleet proxy command ${attempt.correlationId} `
|
|
81
|
+
+ `route=${attempt.classification.route} decision=${attempt.classification.decision}`);
|
|
82
|
+
attempt = store.invocation(attempt.correlationId, caller, 'delivered');
|
|
83
|
+
}
|
|
84
|
+
return attempt;
|
|
85
|
+
},
|
|
86
|
+
async finish(input) {
|
|
87
|
+
let attempt = store.finish(input.correlationId, caller, {
|
|
88
|
+
class: input.class, effect: input.effect,
|
|
89
|
+
...(input.exitCode === undefined ? {} : { exitCode: input.exitCode }),
|
|
90
|
+
...(input.resourceIds ? { resourceIds: input.resourceIds } : {}),
|
|
91
|
+
...(input.presentations ? { presentations: input.presentations } : {}),
|
|
92
|
+
});
|
|
93
|
+
if (attempt.outcome?.delivery === 'sending')
|
|
94
|
+
attempt = store.outcome(attempt.correlationId, caller, 'delivered');
|
|
95
|
+
return attempt;
|
|
96
|
+
},
|
|
97
|
+
async present() { },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
72
100
|
/** Environment injected only into the managed harness process. */
|
|
73
101
|
export function managedFleetProxyEnv(role, stateDir) {
|
|
74
102
|
const roleEnv = { ...(role.env ?? {}) };
|
|
@@ -464,6 +492,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
464
492
|
const runCwd = role.cwd && existsSync(role.cwd) ? role.cwd : dir;
|
|
465
493
|
const prep = await adapter.prepareSession(role, { stateDir: dir, runCwd });
|
|
466
494
|
const sessionBackend = role.session ?? 'acp';
|
|
495
|
+
const sessionLabel = sessionBackend === 'acp' ? 'ACP' : 'Codex app-server';
|
|
467
496
|
let launch = adapter.agentSession.prepareLaunch(role, prep);
|
|
468
497
|
// Isolation is additive: only roles that declare `isolation:` are wrapped.
|
|
469
498
|
let wrappedArgv = launch.argv;
|
|
@@ -554,7 +583,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
554
583
|
let control;
|
|
555
584
|
let unsubscribeRecovery;
|
|
556
585
|
let monitorLoop;
|
|
557
|
-
let
|
|
586
|
+
let sessionStartupComplete = false;
|
|
558
587
|
let sessionClosed = false;
|
|
559
588
|
let ownerChannel;
|
|
560
589
|
let ownerBinder;
|
|
@@ -585,7 +614,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
585
614
|
unsubscribeRecovery = agentSession.subscribe(event => {
|
|
586
615
|
if (event.kind !== 'error' || !event.text)
|
|
587
616
|
return;
|
|
588
|
-
const evidence = classifyFailureText(event.text,
|
|
617
|
+
const evidence = classifyFailureText(event.text, sessionBackend, new Date(deps.now()).toISOString());
|
|
589
618
|
if (evidence)
|
|
590
619
|
resolvedMonitorDeps.onFailureEvidence?.(evidence);
|
|
591
620
|
});
|
|
@@ -610,31 +639,50 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
610
639
|
+ `${error?.message ?? String(error)}`);
|
|
611
640
|
}
|
|
612
641
|
}
|
|
613
|
-
control = deps.createControlServer(dir, arbiter, deps.log);
|
|
614
642
|
try {
|
|
643
|
+
if (role.owner_channel)
|
|
644
|
+
ownerChannel = deps.createOwnerChannel({
|
|
645
|
+
role: name,
|
|
646
|
+
harness: role.harness,
|
|
647
|
+
config: role.owner_channel,
|
|
648
|
+
session: arbiter,
|
|
649
|
+
stateDir: dir,
|
|
650
|
+
env: role.env,
|
|
651
|
+
log: deps.log,
|
|
652
|
+
...(ownerBinder ? { binderLease: ownerBinder } : {}),
|
|
653
|
+
...(configPath ? { configPath } : {}),
|
|
654
|
+
});
|
|
655
|
+
control = deps.createControlServer(dir, arbiter, deps.log);
|
|
656
|
+
control.setFleetAuditor(ownerChannel ? {
|
|
657
|
+
begin: (requestId, argv) => ownerChannel.beginFleetCommandAudit(requestId, argv),
|
|
658
|
+
finish: input => ownerChannel.finishFleetCommandAudit(input),
|
|
659
|
+
present: presentations => ownerChannel.notifyFleetLifecycle(presentations),
|
|
660
|
+
} : localFleetAuditor(dir, name, deps.log));
|
|
615
661
|
await control.start();
|
|
616
662
|
}
|
|
617
663
|
catch (error) {
|
|
664
|
+
await ownerChannel?.close().catch(() => undefined);
|
|
618
665
|
ownerBinder?.release();
|
|
619
666
|
await agentSession.close();
|
|
620
667
|
unsubscribeRecovery?.();
|
|
621
668
|
throw error;
|
|
622
669
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
670
|
+
if (!role.roomMemberStartup)
|
|
671
|
+
control.setFleetSpawner(async (requested) => {
|
|
672
|
+
const event = await executeManagedSpawn(role, configPath, requested, deps.log);
|
|
673
|
+
// Room-member launches are collected with their Task/Room transaction so
|
|
674
|
+
// causal delivery is Task → Room → Agents → Room active → Task active.
|
|
675
|
+
if (!requested.roomMemberStartup && role.owner_channel && ownerChannel?.notifyFleetSpawn) {
|
|
676
|
+
try {
|
|
677
|
+
await ownerChannel.notifyFleetSpawn(event);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
deps.log(`[${name}] Agent lifecycle notice delivery failed: `
|
|
681
|
+
+ `${error?.message ?? String(error)}`);
|
|
682
|
+
}
|
|
634
683
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
});
|
|
684
|
+
return event;
|
|
685
|
+
});
|
|
638
686
|
resolvedMonitorDeps.delivery = {
|
|
639
687
|
// A wake is only delivered when its turn TERMINATES successfully. A
|
|
640
688
|
// refusal or a cancellation reached the agent and was not acted on, so
|
|
@@ -645,7 +693,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
645
693
|
// steer into the live turn instead; after it completes, honor the
|
|
646
694
|
// configured interrupt policy normally.
|
|
647
695
|
const policy = options?.interrupt;
|
|
648
|
-
const interrupt = policy === true &&
|
|
696
|
+
const interrupt = policy === true && sessionStartupComplete;
|
|
649
697
|
const promptOptions = {
|
|
650
698
|
interrupt, steer: true,
|
|
651
699
|
...(interrupt ? { interruptSource: 'fleet-monitor' } : {}),
|
|
@@ -653,7 +701,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
653
701
|
};
|
|
654
702
|
// Startup is already a protected boundary: as with immediate mode,
|
|
655
703
|
// steer rather than waiting on/cancelling the runner-owned first turn.
|
|
656
|
-
const result = policy === 'after_tool' &&
|
|
704
|
+
const result = policy === 'after_tool' && sessionStartupComplete
|
|
657
705
|
? await arbiter.submitPromptAfterTool(text, promptOptions)
|
|
658
706
|
: await arbiter.submitPrompt(text, promptOptions);
|
|
659
707
|
const steered = result.accepted
|
|
@@ -714,32 +762,21 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
714
762
|
exit: {
|
|
715
763
|
version: 1,
|
|
716
764
|
class: 'program-exit',
|
|
717
|
-
detail:
|
|
765
|
+
detail: `${sessionLabel} startup triggered model recovery (${modelRecovery})`,
|
|
718
766
|
},
|
|
719
767
|
rotated: false,
|
|
720
768
|
mode,
|
|
721
769
|
modelRecovery,
|
|
722
770
|
};
|
|
723
771
|
}
|
|
724
|
-
throw new Error(`[${name}]
|
|
772
|
+
throw new Error(`[${name}] ${sessionLabel} startup prompt ${started.outcome}` +
|
|
725
773
|
`${started.detail ? `: ${started.detail}` : ''}`);
|
|
726
774
|
}
|
|
727
775
|
if (interruptedForWake)
|
|
728
|
-
deps.log(`[${name}]
|
|
776
|
+
deps.log(`[${name}] ${sessionLabel} startup prompt cancelled by ${started.cancellationSource}; `
|
|
729
777
|
+ 'keeping temporary supervisor alive');
|
|
730
|
-
|
|
731
|
-
if (
|
|
732
|
-
ownerChannel = deps.createOwnerChannel({
|
|
733
|
-
role: name,
|
|
734
|
-
harness: role.harness,
|
|
735
|
-
config: role.owner_channel,
|
|
736
|
-
session: arbiter,
|
|
737
|
-
stateDir: dir,
|
|
738
|
-
env: role.env,
|
|
739
|
-
log: deps.log,
|
|
740
|
-
...(ownerBinder ? { binderLease: ownerBinder } : {}),
|
|
741
|
-
...(configPath ? { configPath } : {}),
|
|
742
|
-
});
|
|
778
|
+
sessionStartupComplete = true;
|
|
779
|
+
if (ownerChannel) {
|
|
743
780
|
try {
|
|
744
781
|
await ownerChannel.start();
|
|
745
782
|
}
|
|
@@ -758,10 +795,6 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
758
795
|
}
|
|
759
796
|
if (ownerChannel) {
|
|
760
797
|
control.setOwnerChannel(ownerChannel);
|
|
761
|
-
control.setFleetAuditor({
|
|
762
|
-
begin: (requestId, argv) => ownerChannel.beginFleetCommandAudit(requestId, argv),
|
|
763
|
-
finish: input => ownerChannel.finishFleetCommandAudit(input),
|
|
764
|
-
});
|
|
765
798
|
}
|
|
766
799
|
reloadLoopConfig = async () => {
|
|
767
800
|
const nextRole = findRole(loadConfig(configPath), name);
|
|
@@ -772,7 +805,7 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
772
805
|
if (generation === loopGeneration && (loopManager || !definitions.length))
|
|
773
806
|
return { changed: false, loops: definitions.length };
|
|
774
807
|
if (!loopManager && definitions.length) {
|
|
775
|
-
loopManager =
|
|
808
|
+
loopManager = deps.createLoopManager(name, definitions, dir, arbiter, {
|
|
776
809
|
now: deps.now,
|
|
777
810
|
setTimer: (callback, ms) => setTimeout(callback, ms),
|
|
778
811
|
clearTimer: timer => clearTimeout(timer),
|
|
@@ -788,10 +821,12 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
788
821
|
deps.log(`[${name}] scheduled loops reloaded (${definitions.length} definitions)`);
|
|
789
822
|
return { changed: true, loops: definitions.length };
|
|
790
823
|
};
|
|
791
|
-
|
|
824
|
+
// Temporary agents are immutable launch snapshots: never re-resolve mutable Fleet YAML.
|
|
825
|
+
if (!temp)
|
|
826
|
+
control.setConfigReloader(reloadLoopConfig);
|
|
792
827
|
if (role.loops?.length) {
|
|
793
828
|
try {
|
|
794
|
-
loopManager =
|
|
829
|
+
loopManager = deps.createLoopManager(name, role.loops, dir, arbiter, {
|
|
795
830
|
now: deps.now,
|
|
796
831
|
setTimer: (callback, ms) => setTimeout(callback, ms),
|
|
797
832
|
clearTimer: timer => clearTimeout(timer),
|
|
@@ -801,6 +836,17 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
801
836
|
loopManager.start();
|
|
802
837
|
}
|
|
803
838
|
catch (error) {
|
|
839
|
+
if (temp) {
|
|
840
|
+
monitor?.stop();
|
|
841
|
+
if (monitorLoop)
|
|
842
|
+
await monitorLoop;
|
|
843
|
+
await control.close();
|
|
844
|
+
ownerBinder?.release();
|
|
845
|
+
await agentSession.close();
|
|
846
|
+
unsubscribeRecovery?.();
|
|
847
|
+
throw new Error(`[${name}] configured temporary loop manager failed to start: `
|
|
848
|
+
+ `${error?.message ?? String(error)}`);
|
|
849
|
+
}
|
|
804
850
|
deps.log(`[${name}] scheduled loop manager unavailable: ${error?.name ?? 'Error'}`);
|
|
805
851
|
}
|
|
806
852
|
}
|
|
@@ -946,7 +992,8 @@ export async function runOnce(name, opts = {}, partialDeps = {}) {
|
|
|
946
992
|
rotated = true;
|
|
947
993
|
deps.log(`[${name}] ${why} -> rotated session-id; next start is FRESH`);
|
|
948
994
|
};
|
|
949
|
-
if (exitRecord.detail.includes(ACP_CANCEL_DEADLINE_EXCEEDED)
|
|
995
|
+
if (exitRecord.detail.includes(ACP_CANCEL_DEADLINE_EXCEEDED)
|
|
996
|
+
|| exitRecord.detail.includes(CODEX_APP_SERVER_CANCEL_DEADLINE_EXCEEDED))
|
|
950
997
|
// This is a deliberate adapter reclamation, not evidence that resume state
|
|
951
998
|
// is poisoned. Preserve the context even when the resumed generation hits
|
|
952
999
|
// the same bound immediately; runSupervised still counts the fast exit and
|
package/dist/session/acp.d.ts
CHANGED
|
@@ -28,6 +28,8 @@ export declare function promptContentBlocks(text: string, origin?: PromptOrigin)
|
|
|
28
28
|
export declare function runtimeSelector(options: acp.SessionConfigOption[] | null | undefined, category: string): RuntimeSelectorMetadata | undefined;
|
|
29
29
|
export interface AcpSessionOptions {
|
|
30
30
|
name: string;
|
|
31
|
+
/** Harness identity used only for honest optional capability reporting. */
|
|
32
|
+
harness?: string;
|
|
31
33
|
argv: string[];
|
|
32
34
|
cwd: string;
|
|
33
35
|
env: Record<string, string>;
|
|
@@ -89,6 +91,7 @@ export declare function classifyStopReason(stopReason: string | undefined): Turn
|
|
|
89
91
|
export declare class AcpSession implements AgentSession {
|
|
90
92
|
private readonly options;
|
|
91
93
|
readonly backend: "acp";
|
|
94
|
+
readonly capabilities: import("./types.js").AgentSessionCapabilities;
|
|
92
95
|
readonly pid: number;
|
|
93
96
|
private readonly child;
|
|
94
97
|
private readonly events;
|
|
@@ -115,7 +118,7 @@ export declare class AcpSession implements AgentSession {
|
|
|
115
118
|
private queueDepth;
|
|
116
119
|
private exit;
|
|
117
120
|
private steeringSupported;
|
|
118
|
-
private
|
|
121
|
+
private agentCapabilities?;
|
|
119
122
|
private runtimeModel?;
|
|
120
123
|
private reasoningEffort?;
|
|
121
124
|
private controllerCount;
|