@borgee/agents-host 0.2.56 → 0.2.62
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 +11 -10
- package/dist/agents-host.d.ts +1 -0
- package/dist/agents-host.js +103 -9
- package/dist/compatibility-gates.js +2 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +21 -0
- package/dist/context/injection.d.ts +20 -2
- package/dist/context/injection.js +146 -103
- package/dist/context/prompt.js +11 -7
- package/dist/context/resolved-workspace.d.ts +1 -0
- package/dist/context/resolved-workspace.js +50 -8
- package/dist/context/turn-preparation.js +8 -0
- package/dist/gateway/localhost-gateway.js +2 -5
- package/dist/local-config.js +11 -1
- package/dist/managed-daemon.js +18 -13
- package/dist/plugin-sdk.js +0 -17
- package/dist/plugin-sdk.js.map +2 -2
- package/dist/policy/copilot-permission.d.ts +1 -0
- package/dist/policy/copilot-permission.js +18 -0
- package/dist/policy/gateway-authorization.js +2 -2
- package/dist/providers/claude/cli-client.d.ts +1 -1
- package/dist/providers/claude/cli-client.js +30 -3
- package/dist/providers/codex/cli-client.d.ts +2 -0
- package/dist/providers/codex/cli-client.js +25 -21
- package/dist/providers/copilot/cli-client.d.ts +1 -1
- package/dist/providers/copilot/cli-client.js +9 -3
- package/dist/providers/create-provider.d.ts +1 -1
- package/dist/providers/create-provider.js +2 -0
- package/dist/types.d.ts +16 -3
- package/package.json +2 -2
- package/skills/borgee-agent/SKILL.md +4 -4
- package/skills/borgee-agent/references/errors.md +2 -2
- package/skills/borgee-agent/references/task-properties.md +4 -3
package/README.md
CHANGED
|
@@ -479,7 +479,7 @@ successfully applied snapshot running.
|
|
|
479
479
|
Each Borgee channel is mapped 1:1 to a provider-native session while it stays
|
|
480
480
|
active:
|
|
481
481
|
|
|
482
|
-
- **Claude**: one persistent `@agentclientprotocol/claude-agent-acp` subprocess is shared by a single `AgentsHost`, with one ACP session per Borgee channel. Same-channel turns are serialized; different channels keep isolated ACP sessions. The real ACP session cwd now comes from the resolved channel workspace `~/.borgee/channels/<encoded-channel-id>/workspace`. Task threads
|
|
482
|
+
- **Claude**: one persistent `@agentclientprotocol/claude-agent-acp` subprocess is shared by a single `AgentsHost`, with one ACP session per Borgee channel. Same-channel turns are serialized; different channels keep isolated ACP sessions. The real ACP session cwd now comes from the resolved channel workspace `~/.borgee/channels/<encoded-channel-id>/workspace`. Task threads only switch execution onto an explicit existing `execution.local_directory`; otherwise they stay discussion-only on `~/.borgee/channels/<encoded-thread-id>/scratch/workspace`, and ACP permission requests are denied so filesystem and shell tools stay unavailable. The host persists the channel→ACP-session map in its state root, restores same-host continuity with ACP `session/resume` when available, retries stale restores with a fresh session immediately, and injects the per-channel local context paths through Claude ACP `_meta.systemPrompt.append`.
|
|
483
483
|
- **Codex**: one persistent `@agentclientprotocol/codex-acp` subprocess is
|
|
484
484
|
shared by a single `AgentsHost`, with one ACP session per Borgee channel. When
|
|
485
485
|
the current turn has a materialized channel context payload, Codex refreshes a
|
|
@@ -487,12 +487,11 @@ active:
|
|
|
487
487
|
per-channel projection directory and exposes that directory to Codex through
|
|
488
488
|
ACP `additionalDirectories`. The real ACP session cwd now comes from the
|
|
489
489
|
resolved channel workspace `~/.borgee/channels/<encoded-channel-id>/workspace`.
|
|
490
|
-
Task threads
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
repository is already checked out there. The host persists the
|
|
490
|
+
Task threads only switch execution onto an explicit existing
|
|
491
|
+
`execution.local_directory`; otherwise they stay discussion-only on
|
|
492
|
+
`~/.borgee/channels/<encoded-thread-id>/scratch/workspace`, and ACP
|
|
493
|
+
permission requests are denied so filesystem and shell tools stay
|
|
494
|
+
unavailable. The host persists the
|
|
496
495
|
channel→ACP-session map in its state root and attempts ACP `session/resume`
|
|
497
496
|
first when the adapter advertises it, otherwise `session/load`.
|
|
498
497
|
- **Copilot**: one persistent `copilot --acp` subprocess is shared by a single
|
|
@@ -500,9 +499,11 @@ active:
|
|
|
500
499
|
serialized; different channels keep isolated ACP sessions. The real ACP
|
|
501
500
|
session cwd now comes from the resolved channel workspace
|
|
502
501
|
`~/.borgee/channels/<encoded-channel-id>/workspace` by default. Task threads
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
502
|
+
only switch execution onto an explicit existing `execution.local_directory`;
|
|
503
|
+
otherwise they stay discussion-only on
|
|
504
|
+
`~/.borgee/channels/<encoded-thread-id>/scratch/workspace`, and ACP
|
|
505
|
+
permission requests are denied so filesystem and shell tools stay
|
|
506
|
+
unavailable. The
|
|
506
507
|
host persists the channel→ACP-session map in its state root and restores
|
|
507
508
|
same-host continuity with ACP `session/resume` when available, otherwise
|
|
508
509
|
`session/load` plus local replay cleanup on runtimes that advertise only
|
package/dist/agents-host.d.ts
CHANGED
|
@@ -125,6 +125,7 @@ export declare class AgentsHost {
|
|
|
125
125
|
private revalidateAttentionSnapshotForTurn;
|
|
126
126
|
private getAttentionSnapshotForTurn;
|
|
127
127
|
private isHumanWakeFiltered;
|
|
128
|
+
private isOrdinaryAgentWakeFiltered;
|
|
128
129
|
private applyAttentionUpdate;
|
|
129
130
|
private commitAttentionSnapshot;
|
|
130
131
|
private resolveTaskThreadCollaborationContractForTurn;
|
package/dist/agents-host.js
CHANGED
|
@@ -9,13 +9,13 @@ import { buildNormalizedAttentionSnapshot, parsePersistedAttentionSnapshot, } fr
|
|
|
9
9
|
import { mergeCompactionSnapshot, parsePersistedCompactionSnapshot, } from './context/compaction.js';
|
|
10
10
|
import { projectTaskThreadCollaborationContract } from './context/task-thread-collaboration.js';
|
|
11
11
|
import { createLocalhostGatewayController, LOCALHOST_GATEWAY_COLLABORATION_TARGET_COOLDOWN_MS, } from './gateway/localhost-gateway.js';
|
|
12
|
-
import { extractTaskIdFromTaskAssignmentContent,
|
|
12
|
+
import { extractTaskIdFromTaskAssignmentContent, resolveTaskAssignmentStatePath, } from './context/injection.js';
|
|
13
13
|
import { AuthorizationAuditSink, } from './policy/authorization-audit.js';
|
|
14
14
|
import { createProvider } from './providers/create-provider.js';
|
|
15
15
|
import { resolveAttentionStatePath, resolveCompactionStatePath, resolveSharedProtocolKickoffDecisionPath, resolveSharedProtocolStatusPath, } from './state-paths.js';
|
|
16
16
|
import { appendVisibleMention as appendVisibleBodyMention, extractVisibleMentionIds as extractCanonicalMentionIds, } from './visible-mentions.js';
|
|
17
|
-
import { waitForTaskForThread } from './task-thread-resolution.js';
|
|
18
17
|
import { buildHostedIncomingContentText, buildHostedTurnContentParts, extractHostedMessageAttachments, normalizeHostedMessageAttachment, } from './hosted-turn-content.js';
|
|
18
|
+
import { waitForTaskForThread } from './task-thread-resolution.js';
|
|
19
19
|
const PRIVATE_STATE_ROOT_MODE = 0o700;
|
|
20
20
|
const PROTOCOL_STATE_DIRNAME = 'protocol-state';
|
|
21
21
|
const PROTOCOL_PROVIDER_TURN_TIMEOUT_MS = 120_000;
|
|
@@ -136,6 +136,7 @@ class DefaultHostRuntime {
|
|
|
136
136
|
copilotArgs: config.copilotArgs,
|
|
137
137
|
copilotSessionTtlMinutes: config.copilotSessionTtlMinutes,
|
|
138
138
|
providerIdleShutdownMinutes: config.providerIdleShutdownMinutes,
|
|
139
|
+
allowCrossAgentIndependentWorkspaceHandoff: config.allowCrossAgentIndependentWorkspaceHandoff,
|
|
139
140
|
}, deps.logger, {
|
|
140
141
|
compatibilityGates,
|
|
141
142
|
authorizationAuditSink: this.authorizationAuditSink,
|
|
@@ -461,6 +462,9 @@ export class AgentsHost {
|
|
|
461
462
|
const authorKind = await this.classifyAuthor(normalized.authorId, false);
|
|
462
463
|
await this.ensureAttentionSnapshotLoaded(msg.channel_id, channelState);
|
|
463
464
|
attentionSnapshot = this.getAttentionSnapshotForTurn(msg.channel_id, taskThreadContext);
|
|
465
|
+
if (this.isOrdinaryAgentWakeFiltered(msg, authorKind)) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
464
468
|
if (this.isHumanWakeFiltered(msg, authorKind, attentionSnapshot)) {
|
|
465
469
|
return;
|
|
466
470
|
}
|
|
@@ -553,6 +557,9 @@ export class AgentsHost {
|
|
|
553
557
|
}
|
|
554
558
|
}
|
|
555
559
|
}
|
|
560
|
+
if (this.isOrdinaryAgentWakeFiltered(msg, authorKind)) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
556
563
|
if (this.isHumanWakeFiltered(msg, authorKind, attentionSnapshot)) {
|
|
557
564
|
return;
|
|
558
565
|
}
|
|
@@ -1824,19 +1831,74 @@ export class AgentsHost {
|
|
|
1824
1831
|
if (!this.contextInjectionEnabled) {
|
|
1825
1832
|
return { state: 'inactive' };
|
|
1826
1833
|
}
|
|
1834
|
+
const recoverFromControlPlane = async (preferredTaskId) => {
|
|
1835
|
+
try {
|
|
1836
|
+
if (preferredTaskId) {
|
|
1837
|
+
try {
|
|
1838
|
+
const preferredTask = await this.borgee.getTask({ taskId: preferredTaskId });
|
|
1839
|
+
if (preferredTask.threadId === channelId) {
|
|
1840
|
+
return preferredTask.id.trim().length > 0
|
|
1841
|
+
? { state: 'recovered', currentTaskId: preferredTask.id }
|
|
1842
|
+
: { state: 'recovered' };
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
catch {
|
|
1846
|
+
// Fall through to the visibility-based scan.
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
const channels = await this.borgee.listChannels();
|
|
1850
|
+
const currentChannel = channels.find((channel) => channel.id === channelId);
|
|
1851
|
+
if (currentChannel && currentChannel.kind !== 'thread') {
|
|
1852
|
+
return { state: 'inactive' };
|
|
1853
|
+
}
|
|
1854
|
+
let sawTaskListSuccess = false;
|
|
1855
|
+
let sawTaskListFailure = false;
|
|
1856
|
+
for (const channel of channels) {
|
|
1857
|
+
let tasks;
|
|
1858
|
+
try {
|
|
1859
|
+
tasks = await this.borgee.listTasks({ channelId: channel.id });
|
|
1860
|
+
sawTaskListSuccess = true;
|
|
1861
|
+
}
|
|
1862
|
+
catch {
|
|
1863
|
+
sawTaskListFailure = true;
|
|
1864
|
+
continue;
|
|
1865
|
+
}
|
|
1866
|
+
for (const task of tasks) {
|
|
1867
|
+
if (task.threadId === channelId) {
|
|
1868
|
+
return task.id.trim().length > 0 ? { state: 'recovered', currentTaskId: task.id } : { state: 'recovered' };
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
return sawTaskListSuccess && !sawTaskListFailure ? { state: 'inactive' } : { state: 'unavailable' };
|
|
1873
|
+
}
|
|
1874
|
+
catch {
|
|
1875
|
+
return { state: 'unavailable' };
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1827
1878
|
try {
|
|
1828
|
-
const content = await readFile(
|
|
1879
|
+
const content = await readFile(resolveTaskAssignmentStatePath(this.config.stateRootDir, channelId), 'utf8');
|
|
1829
1880
|
const payload = JSON.parse(content);
|
|
1830
1881
|
if (payload.taskAssignmentContext?.active !== true) {
|
|
1831
|
-
return
|
|
1882
|
+
return await recoverFromControlPlane();
|
|
1832
1883
|
}
|
|
1833
1884
|
const currentTaskId = typeof payload.taskAssignmentContext.currentTaskId === 'string'
|
|
1834
1885
|
? payload.taskAssignmentContext.currentTaskId.trim()
|
|
1835
1886
|
: '';
|
|
1836
|
-
|
|
1887
|
+
if (currentTaskId) {
|
|
1888
|
+
try {
|
|
1889
|
+
const task = await this.borgee.getTask({ taskId: currentTaskId });
|
|
1890
|
+
if (task.threadId === channelId) {
|
|
1891
|
+
return { state: 'active', currentTaskId: task.id };
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
catch {
|
|
1895
|
+
// Fall through to the recovery scan below.
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
return await recoverFromControlPlane(currentTaskId || undefined);
|
|
1837
1899
|
}
|
|
1838
1900
|
catch {
|
|
1839
|
-
return
|
|
1901
|
+
return await recoverFromControlPlane();
|
|
1840
1902
|
}
|
|
1841
1903
|
}
|
|
1842
1904
|
async ensureAttentionSnapshotLoaded(channelId, channelState) {
|
|
@@ -1936,11 +1998,28 @@ export class AgentsHost {
|
|
|
1936
1998
|
if (!ORDINARY_HUMAN_EVENT_KINDS.has(eventKind)) {
|
|
1937
1999
|
return false;
|
|
1938
2000
|
}
|
|
1939
|
-
if (
|
|
2001
|
+
if (msg.channel_type === 'dm'
|
|
2002
|
+
&& attentionSnapshot?.wakeMode !== 'mute-non-mention') {
|
|
1940
2003
|
return false;
|
|
1941
2004
|
}
|
|
1942
|
-
|
|
1943
|
-
|
|
2005
|
+
if (attentionSnapshot?.wakeMode === 'mute-non-mention') {
|
|
2006
|
+
this.noteWakeSuppressedAttentionPolicy(msg, authorKind);
|
|
2007
|
+
return true;
|
|
2008
|
+
}
|
|
2009
|
+
return false;
|
|
2010
|
+
}
|
|
2011
|
+
isOrdinaryAgentWakeFiltered(msg, authorKind) {
|
|
2012
|
+
if (authorKind !== 'agent') {
|
|
2013
|
+
return false;
|
|
2014
|
+
}
|
|
2015
|
+
if (msg.message_type === 'task_assignment') {
|
|
2016
|
+
return false;
|
|
2017
|
+
}
|
|
2018
|
+
if (msg.type?.trim() === 'mention') {
|
|
2019
|
+
return false;
|
|
2020
|
+
}
|
|
2021
|
+
const eventKind = msg.type?.trim() ?? '';
|
|
2022
|
+
return ORDINARY_HUMAN_EVENT_KINDS.has(eventKind);
|
|
1944
2023
|
}
|
|
1945
2024
|
applyAttentionUpdate(channelId, baseSnapshot, attentionUpdate, taskThreadContext, options) {
|
|
1946
2025
|
if (!this.attentionFollowSemanticsEnabled) {
|
|
@@ -2202,6 +2281,21 @@ export class AgentsHost {
|
|
|
2202
2281
|
...(taskThreadCollaborationContract ? { taskThreadCollaborationContract } : {}),
|
|
2203
2282
|
...(collaborationCapabilities ? { collaborationCapabilities } : {}),
|
|
2204
2283
|
...(missedCollaborationDiagnostic ? { missedCollaborationDiagnostic } : {}),
|
|
2284
|
+
...((taskThreadContext.state === 'active'
|
|
2285
|
+
|| taskThreadContext.state === 'recovered'
|
|
2286
|
+
|| taskThreadContext.state === 'unavailable')
|
|
2287
|
+
? {
|
|
2288
|
+
taskAssignmentContextOverride: {
|
|
2289
|
+
active: true,
|
|
2290
|
+
...(taskThreadContext.state === 'active' && taskThreadContext.currentTaskId
|
|
2291
|
+
? { currentTaskId: taskThreadContext.currentTaskId }
|
|
2292
|
+
: {}),
|
|
2293
|
+
},
|
|
2294
|
+
...(taskThreadContext.state === 'active'
|
|
2295
|
+
? { taskAssignmentContextOverridePersistence: 'persist' }
|
|
2296
|
+
: { taskAssignmentContextOverridePersistence: 'ephemeral' }),
|
|
2297
|
+
}
|
|
2298
|
+
: {}),
|
|
2205
2299
|
}, observeProviderProgress
|
|
2206
2300
|
? {
|
|
2207
2301
|
onProgress: (update) => {
|
|
@@ -24,8 +24,10 @@ export const INTERNAL_CLAUDE_PROMPT_STRATEGY_ENV = 'AGENTS_HOST_INTERNAL_CLAUDE_
|
|
|
24
24
|
export const MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION = 1;
|
|
25
25
|
const VALID_PROVIDER_IMPLEMENTATION_ENTRIES = '"claude:v1", "claude:v2", "copilot:v1", or "copilot:v2"';
|
|
26
26
|
export const DEFAULT_INTERNAL_COMPATIBILITY_GATES = Object.freeze([
|
|
27
|
+
ATTENTION_FOLLOW_SEMANTICS_COMPATIBILITY_GATE,
|
|
27
28
|
COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE,
|
|
28
29
|
COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE,
|
|
30
|
+
COLLABORATION_SKILL_FIRST_COMPATIBILITY_GATE,
|
|
29
31
|
CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE,
|
|
30
32
|
CONTEXT_INJECTION_COMPATIBILITY_GATE,
|
|
31
33
|
CODEX_PROVIDER_COMPATIBILITY_GATE,
|
package/dist/config.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare const MAX_TIMER_DELAY_MINUTES: number;
|
|
|
3
3
|
export declare const DEFAULT_COPILOT_SESSION_TTL_MINUTES: number;
|
|
4
4
|
export declare const PROVIDER_IDLE_SHUTDOWN_DISABLED_MINUTES = 0;
|
|
5
5
|
export declare const DEFAULT_PROVIDER_IDLE_SHUTDOWN_MINUTES = 10;
|
|
6
|
+
export declare const DEFAULT_ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF = true;
|
|
6
7
|
export declare const DEFAULT_CLAUDE_COMMAND = "claude-agent-acp";
|
|
7
8
|
export declare const LEGACY_CLAUDE_COMMAND = "claude";
|
|
8
9
|
export declare const LEGACY_CLAUDE_ONE_SHOT_ARGS: readonly ["--print", "--permission-mode", "bypassPermissions"];
|
|
@@ -13,6 +14,7 @@ export declare function parseArgs(value: string): string[];
|
|
|
13
14
|
export declare function optionalStringArray(value: unknown, fieldName: string, sourceLabel: string): string[] | undefined;
|
|
14
15
|
export declare function parseCopilotSessionTtlMinutesValue(value: unknown, sourceLabel: string): number;
|
|
15
16
|
export declare function parseProviderIdleShutdownMinutesValue(value: unknown, sourceLabel: string): number;
|
|
17
|
+
export declare function parseBooleanValue(value: unknown, envName: string, sourceLabel: string): boolean;
|
|
16
18
|
export declare function resolveProvider(rawValue: string, sourceLabel: string): ProviderKind;
|
|
17
19
|
export declare function assertProviderCompatibility(provider: ProviderKind, sourceLabel: string, env?: NodeJS.ProcessEnv): void;
|
|
18
20
|
export declare function isLegacyClaudeCompatibilityAlias(command: string, args: string[]): boolean;
|
package/dist/config.js
CHANGED
|
@@ -6,6 +6,7 @@ export const MAX_TIMER_DELAY_MINUTES = MAX_TIMER_DELAY_MS / 60_000;
|
|
|
6
6
|
export const DEFAULT_COPILOT_SESSION_TTL_MINUTES = 2 * 24 * 60;
|
|
7
7
|
export const PROVIDER_IDLE_SHUTDOWN_DISABLED_MINUTES = 0;
|
|
8
8
|
export const DEFAULT_PROVIDER_IDLE_SHUTDOWN_MINUTES = 10;
|
|
9
|
+
export const DEFAULT_ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF = true;
|
|
9
10
|
export const DEFAULT_CLAUDE_COMMAND = 'claude-agent-acp';
|
|
10
11
|
export const LEGACY_CLAUDE_COMMAND = 'claude';
|
|
11
12
|
export const LEGACY_CLAUDE_ONE_SHOT_ARGS = ['--print', '--permission-mode', 'bypassPermissions'];
|
|
@@ -18,6 +19,7 @@ export const DEFAULT_PROVIDER_COMMAND_CONFIG = {
|
|
|
18
19
|
copilotArgs: ['-s', '--no-color', '--allow-all-tools', '--output-format', 'text'],
|
|
19
20
|
copilotSessionTtlMinutes: DEFAULT_COPILOT_SESSION_TTL_MINUTES,
|
|
20
21
|
providerIdleShutdownMinutes: DEFAULT_PROVIDER_IDLE_SHUTDOWN_MINUTES,
|
|
22
|
+
allowCrossAgentIndependentWorkspaceHandoff: DEFAULT_ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF,
|
|
21
23
|
};
|
|
22
24
|
function requireEnv(name, env) {
|
|
23
25
|
return requireNonEmptyString(env[name], `Missing required environment variable: ${name}`);
|
|
@@ -75,6 +77,19 @@ export function parseProviderIdleShutdownMinutesValue(value, sourceLabel) {
|
|
|
75
77
|
}
|
|
76
78
|
return parsed;
|
|
77
79
|
}
|
|
80
|
+
export function parseBooleanValue(value, envName, sourceLabel) {
|
|
81
|
+
if (typeof value === 'boolean') {
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
const normalized = String(value).trim().toLowerCase();
|
|
85
|
+
if (normalized === 'true') {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
if (normalized === 'false') {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`Invalid ${envName} in ${sourceLabel}: expected true or false`);
|
|
92
|
+
}
|
|
78
93
|
export function resolveProvider(rawValue, sourceLabel) {
|
|
79
94
|
const raw = rawValue.trim().toLowerCase();
|
|
80
95
|
if (raw === 'claude' || raw === 'codex' || raw === 'copilot') {
|
|
@@ -134,6 +149,8 @@ export function resolveProviderCommandConfig(overrides = {}) {
|
|
|
134
149
|
copilotSessionTtlMinutes: overrides.copilotSessionTtlMinutes ?? DEFAULT_PROVIDER_COMMAND_CONFIG.copilotSessionTtlMinutes,
|
|
135
150
|
providerIdleShutdownMinutes: overrides.providerIdleShutdownMinutes
|
|
136
151
|
?? DEFAULT_PROVIDER_COMMAND_CONFIG.providerIdleShutdownMinutes,
|
|
152
|
+
allowCrossAgentIndependentWorkspaceHandoff: overrides.allowCrossAgentIndependentWorkspaceHandoff
|
|
153
|
+
?? DEFAULT_PROVIDER_COMMAND_CONFIG.allowCrossAgentIndependentWorkspaceHandoff,
|
|
137
154
|
};
|
|
138
155
|
}
|
|
139
156
|
export function loadConfigFromEnv(env = process.env) {
|
|
@@ -153,6 +170,10 @@ export function loadConfigFromEnv(env = process.env) {
|
|
|
153
170
|
providerIdleShutdownMinutes: env.PROVIDER_IDLE_SHUTDOWN_MINUTES && env.PROVIDER_IDLE_SHUTDOWN_MINUTES.trim().length > 0
|
|
154
171
|
? parseProviderIdleShutdownMinutesValue(env.PROVIDER_IDLE_SHUTDOWN_MINUTES, 'environment variable PROVIDER_IDLE_SHUTDOWN_MINUTES')
|
|
155
172
|
: DEFAULT_PROVIDER_COMMAND_CONFIG.providerIdleShutdownMinutes,
|
|
173
|
+
allowCrossAgentIndependentWorkspaceHandoff: env.ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF
|
|
174
|
+
&& env.ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF.trim().length > 0
|
|
175
|
+
? parseBooleanValue(env.ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF, 'ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF', 'environment variable ALLOW_CROSS_AGENT_INDEPENDENT_WORKSPACE_HANDOFF')
|
|
176
|
+
: DEFAULT_PROVIDER_COMMAND_CONFIG.allowCrossAgentIndependentWorkspaceHandoff,
|
|
156
177
|
});
|
|
157
178
|
assertProviderCommandCompatibility(provider, providerConfig, 'environment variables');
|
|
158
179
|
return {
|
|
@@ -49,6 +49,8 @@ export interface ChannelContextStore {
|
|
|
49
49
|
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
50
50
|
incomingMessageType?: string;
|
|
51
51
|
incomingContent?: string;
|
|
52
|
+
taskAssignmentContextOverride?: TaskAssignmentThreadContext;
|
|
53
|
+
taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
|
|
52
54
|
}): Promise<PreparedChannelContext>;
|
|
53
55
|
prepare(channelId: string, options?: {
|
|
54
56
|
provider?: ProviderKind;
|
|
@@ -62,6 +64,8 @@ export interface ChannelContextStore {
|
|
|
62
64
|
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
63
65
|
incomingMessageType?: string;
|
|
64
66
|
incomingContent?: string;
|
|
67
|
+
taskAssignmentContextOverride?: TaskAssignmentThreadContext;
|
|
68
|
+
taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
|
|
65
69
|
}): Promise<PreparedChannelContext>;
|
|
66
70
|
}
|
|
67
71
|
export interface SkillAssetResolver {
|
|
@@ -95,7 +99,10 @@ interface ContextFileSystem {
|
|
|
95
99
|
}): Promise<void>;
|
|
96
100
|
unlink(path: string): Promise<void>;
|
|
97
101
|
rename(oldPath: string, newPath: string): Promise<void>;
|
|
98
|
-
access(path: string): Promise<void>;
|
|
102
|
+
access(path: string, mode?: number): Promise<void>;
|
|
103
|
+
stat?(path: string): Promise<{
|
|
104
|
+
isDirectory(): boolean;
|
|
105
|
+
}>;
|
|
99
106
|
}
|
|
100
107
|
interface FileChannelContextStoreOptions {
|
|
101
108
|
fileSystem?: ContextFileSystem;
|
|
@@ -103,8 +110,10 @@ interface FileChannelContextStoreOptions {
|
|
|
103
110
|
skillAssetResolver?: SkillAssetResolver;
|
|
104
111
|
localhostGateway?: LocalhostGatewayContextPublisher;
|
|
105
112
|
workspaceCollectionRootDir?: string;
|
|
106
|
-
taskReader?: Pick<ChatControlPlane, 'getTask' | 'listChannels' | 'listTasks'>;
|
|
113
|
+
taskReader?: Pick<ChatControlPlane, 'getTask' | 'listChannels' | 'listTasks' | 'listUsers'>;
|
|
107
114
|
taskResolutionTimeoutMs?: number;
|
|
115
|
+
allowCrossAgentIndependentWorkspaceHandoff?: boolean;
|
|
116
|
+
resolveStableAgentId?: () => string | undefined;
|
|
108
117
|
env?: NodeJS.ProcessEnv;
|
|
109
118
|
resolvedHomeDir?: string;
|
|
110
119
|
}
|
|
@@ -117,12 +126,15 @@ export declare function extractTaskIdFromTaskAssignmentContent(incomingContent:
|
|
|
117
126
|
export declare function encodeChannelPathSegment(channelId: string): string;
|
|
118
127
|
export declare function resolveChannelContextDirectory(stateRootDir: string, channelId: string): string;
|
|
119
128
|
export declare function resolveChannelContextPayloadPath(stateRootDir: string, channelId: string): string;
|
|
129
|
+
export declare function resolveTaskAssignmentStateDirectory(stateRootDir: string, channelId: string): string;
|
|
130
|
+
export declare function resolveTaskAssignmentStatePath(stateRootDir: string, channelId: string): string;
|
|
120
131
|
export declare function resolveTaskWorkspaceRootDirectory(startupWorkspaceRootDir: string): string;
|
|
121
132
|
export declare function resolveManagedWorkspaceCollectionRoot(workspaceCollectionRootDir: string | undefined, env?: NodeJS.ProcessEnv, resolvedHomeDir?: string): string;
|
|
122
133
|
export declare function resolveChannelWorkspaceRootDirectory(workspaceCollectionRootDir: string, channelId: string): string;
|
|
123
134
|
export declare function resolveChannelWorkspaceDirectory(workspaceCollectionRootDir: string, channelId: string): string;
|
|
124
135
|
export declare function resolveTaskIsolatedWorkspaceDirectory(workspaceCollectionRootDir: string, channelId: string, taskId: string): string;
|
|
125
136
|
export declare const resolveTaskWorkspaceDirectory: typeof resolveTaskIsolatedWorkspaceDirectory;
|
|
137
|
+
export declare function resolveTaskThreadScratchWorkspaceDirectory(workspaceCollectionRootDir: string, channelId: string): string;
|
|
126
138
|
export declare function resolveChannelGatewayCredentialPath(stateRootDir: string, channelId: string): string;
|
|
127
139
|
export declare function resolveGatewayCredentialPathFromPayloadPath(payloadPath: string): string;
|
|
128
140
|
export declare function resolveClaudeProjectedBriefPathFromPayloadPath(payloadPath: string): string;
|
|
@@ -137,6 +149,8 @@ export declare class FileChannelContextStore implements ChannelContextStore {
|
|
|
137
149
|
private readonly workspaceCollectionRootDir;
|
|
138
150
|
private readonly taskReader?;
|
|
139
151
|
private readonly taskResolutionTimeoutMs;
|
|
152
|
+
private readonly allowCrossAgentIndependentWorkspaceHandoff;
|
|
153
|
+
private readonly resolveStableAgentId?;
|
|
140
154
|
constructor(stateRootDir: string, options?: FileChannelContextStoreOptions);
|
|
141
155
|
prepare(inputOrChannelId: {
|
|
142
156
|
channelId: string;
|
|
@@ -151,6 +165,8 @@ export declare class FileChannelContextStore implements ChannelContextStore {
|
|
|
151
165
|
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
152
166
|
incomingMessageType?: string;
|
|
153
167
|
incomingContent?: string;
|
|
168
|
+
taskAssignmentContextOverride?: TaskAssignmentThreadContext;
|
|
169
|
+
taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
|
|
154
170
|
} | string, options?: {
|
|
155
171
|
provider?: ProviderKind;
|
|
156
172
|
projectionStrategy?: ProjectionStrategy;
|
|
@@ -163,6 +179,8 @@ export declare class FileChannelContextStore implements ChannelContextStore {
|
|
|
163
179
|
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
164
180
|
incomingMessageType?: string;
|
|
165
181
|
incomingContent?: string;
|
|
182
|
+
taskAssignmentContextOverride?: TaskAssignmentThreadContext;
|
|
183
|
+
taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
|
|
166
184
|
}): Promise<PreparedChannelContext>;
|
|
167
185
|
private resolveSkillRuntimeBestEffort;
|
|
168
186
|
}
|