@borgee/agents-host 0.2.26 → 0.2.28
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/dist/agents-host.d.ts +25 -0
- package/dist/agents-host.js +627 -14
- package/dist/compatibility-gates.d.ts +4 -0
- package/dist/compatibility-gates.js +4 -0
- package/dist/context/attention.d.ts +12 -0
- package/dist/context/attention.js +137 -0
- package/dist/context/collaboration-capabilities-diagnostics.d.ts +3 -0
- package/dist/context/collaboration-capabilities-diagnostics.js +18 -0
- package/dist/context/collaboration-outcome.d.ts +2 -0
- package/dist/context/collaboration-outcome.js +26 -0
- package/dist/context/injection.d.ts +26 -1
- package/dist/context/injection.js +7 -2
- package/dist/context/prompt.js +61 -0
- package/dist/context/task-thread-collaboration.d.ts +6 -0
- package/dist/context/task-thread-collaboration.js +31 -0
- package/dist/context/turn-preparation.js +30 -1
- package/dist/providers/awaiting-user.js +46 -5
- package/dist/providers/codex/project-doc.js +24 -0
- package/dist/state-paths.d.ts +1 -0
- package/dist/state-paths.js +3 -0
- package/dist/types.d.ts +97 -4
- package/package.json +1 -1
|
@@ -6,6 +6,10 @@ export declare const CONTEXT_INJECTION_COMPATIBILITY_GATE = "context-injection";
|
|
|
6
6
|
export declare const SKILL_RUNTIME_COMPATIBILITY_GATE = "skill-runtime";
|
|
7
7
|
export declare const LOCALHOST_GATEWAY_COMPATIBILITY_GATE = "localhost-gateway";
|
|
8
8
|
export declare const COLLABORATION_SKILL_FIRST_COMPATIBILITY_GATE = "collaboration-skill-first";
|
|
9
|
+
export declare const COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE = "collaboration-outcome-model";
|
|
10
|
+
export declare const ATTENTION_FOLLOW_SEMANTICS_COMPATIBILITY_GATE = "attention-follow-semantics";
|
|
11
|
+
export declare const TASK_THREAD_COLLABORATION_CONTRACT_COMPATIBILITY_GATE = "task-thread-collaboration-contract";
|
|
12
|
+
export declare const COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE = "collaboration-capabilities-diagnostics";
|
|
9
13
|
export declare const TOKEN_BINDING_COMPATIBILITY_GATE = "token-binding";
|
|
10
14
|
export declare const POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE = "policy-audit-enforcement";
|
|
11
15
|
export declare const MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE = "managed-runtime-convergence";
|
|
@@ -7,6 +7,10 @@ export const CONTEXT_INJECTION_COMPATIBILITY_GATE = 'context-injection';
|
|
|
7
7
|
export const SKILL_RUNTIME_COMPATIBILITY_GATE = 'skill-runtime';
|
|
8
8
|
export const LOCALHOST_GATEWAY_COMPATIBILITY_GATE = 'localhost-gateway';
|
|
9
9
|
export const COLLABORATION_SKILL_FIRST_COMPATIBILITY_GATE = 'collaboration-skill-first';
|
|
10
|
+
export const COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE = 'collaboration-outcome-model';
|
|
11
|
+
export const ATTENTION_FOLLOW_SEMANTICS_COMPATIBILITY_GATE = 'attention-follow-semantics';
|
|
12
|
+
export const TASK_THREAD_COLLABORATION_CONTRACT_COMPATIBILITY_GATE = 'task-thread-collaboration-contract';
|
|
13
|
+
export const COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE = 'collaboration-capabilities-diagnostics';
|
|
10
14
|
export const TOKEN_BINDING_COMPATIBILITY_GATE = 'token-binding';
|
|
11
15
|
export const POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE = 'policy-audit-enforcement';
|
|
12
16
|
export const MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE = 'managed-runtime-convergence';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AttentionClaimActivation, AttentionClaimContext, AttentionClaimState, AttentionDeliveryMode, AttentionSnapshot, AttentionWakeMode } from '../types.js';
|
|
2
|
+
export declare function deriveAttentionWakeMode(snapshot: Pick<AttentionSnapshot, 'deliveryMode' | 'claimState' | 'claimActivation'>): AttentionWakeMode;
|
|
3
|
+
export declare function buildNormalizedAttentionSnapshot(params?: {
|
|
4
|
+
deliveryMode?: AttentionDeliveryMode;
|
|
5
|
+
claimState?: AttentionClaimState;
|
|
6
|
+
claimActivation?: AttentionClaimActivation;
|
|
7
|
+
observedAt?: number;
|
|
8
|
+
turnExecutionId?: string;
|
|
9
|
+
claimContext?: AttentionClaimContext;
|
|
10
|
+
}): AttentionSnapshot;
|
|
11
|
+
export declare function parsePersistedAttentionSnapshot(raw: unknown): AttentionSnapshot;
|
|
12
|
+
export declare function buildAttentionSummaryLines(snapshot: AttentionSnapshot | undefined): string[];
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
function isRecord(value) {
|
|
2
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
function isDeliveryMode(value) {
|
|
5
|
+
return value === 'default' || value === 'follow' || value === 'muted';
|
|
6
|
+
}
|
|
7
|
+
function isClaimState(value) {
|
|
8
|
+
return value === 'unclaimed' || value === 'claimed';
|
|
9
|
+
}
|
|
10
|
+
function isClaimActivation(value) {
|
|
11
|
+
return value === 'inactive' || value === 'active' || value === 'dormant';
|
|
12
|
+
}
|
|
13
|
+
function isUsableTaskId(value) {
|
|
14
|
+
return value.length > 0 && !/[\u0000-\u001f\u007f\s]/u.test(value);
|
|
15
|
+
}
|
|
16
|
+
function normalizeClaimContext(value) {
|
|
17
|
+
if (!isRecord(value) || typeof value.scope !== 'string' || typeof value.taskId !== 'string') {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
const taskId = value.taskId.trim();
|
|
21
|
+
if (value.scope === 'task-thread') {
|
|
22
|
+
return isUsableTaskId(taskId) ? { scope: 'task-thread', taskId } : undefined;
|
|
23
|
+
}
|
|
24
|
+
if (value.scope === 'channel') {
|
|
25
|
+
return isUsableTaskId(taskId) ? { scope: 'channel', taskId } : undefined;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
export function deriveAttentionWakeMode(snapshot) {
|
|
30
|
+
if (snapshot.deliveryMode === 'muted') {
|
|
31
|
+
return 'mute-non-mention';
|
|
32
|
+
}
|
|
33
|
+
if (snapshot.deliveryMode === 'follow') {
|
|
34
|
+
return 'follow-visible-human';
|
|
35
|
+
}
|
|
36
|
+
if (snapshot.claimState === 'claimed' && snapshot.claimActivation === 'active') {
|
|
37
|
+
return 'follow-visible-human';
|
|
38
|
+
}
|
|
39
|
+
return 'current-policy';
|
|
40
|
+
}
|
|
41
|
+
export function buildNormalizedAttentionSnapshot(params) {
|
|
42
|
+
let deliveryMode = params?.deliveryMode ?? 'default';
|
|
43
|
+
let claimState = params?.claimState ?? 'unclaimed';
|
|
44
|
+
let claimActivation = params?.claimActivation ?? 'inactive';
|
|
45
|
+
let claimContext = params?.claimContext;
|
|
46
|
+
if (claimState === 'unclaimed') {
|
|
47
|
+
claimActivation = 'inactive';
|
|
48
|
+
claimContext = undefined;
|
|
49
|
+
}
|
|
50
|
+
else if (claimActivation === 'inactive') {
|
|
51
|
+
claimState = 'unclaimed';
|
|
52
|
+
claimContext = undefined;
|
|
53
|
+
}
|
|
54
|
+
if (claimActivation === 'dormant') {
|
|
55
|
+
deliveryMode = 'default';
|
|
56
|
+
}
|
|
57
|
+
if (claimContext?.scope === 'task-thread' && !isUsableTaskId(claimContext.taskId)) {
|
|
58
|
+
claimState = 'unclaimed';
|
|
59
|
+
claimActivation = 'inactive';
|
|
60
|
+
claimContext = undefined;
|
|
61
|
+
deliveryMode = 'default';
|
|
62
|
+
}
|
|
63
|
+
const snapshot = {
|
|
64
|
+
source: 'host-observed',
|
|
65
|
+
deliveryMode,
|
|
66
|
+
claimState,
|
|
67
|
+
claimActivation,
|
|
68
|
+
wakeMode: deriveAttentionWakeMode({
|
|
69
|
+
deliveryMode,
|
|
70
|
+
claimState,
|
|
71
|
+
claimActivation,
|
|
72
|
+
}),
|
|
73
|
+
observedAt: params?.observedAt ?? Date.now(),
|
|
74
|
+
...(params?.turnExecutionId ? { turnExecutionId: params.turnExecutionId } : {}),
|
|
75
|
+
...(claimContext ? { claimContext } : {}),
|
|
76
|
+
};
|
|
77
|
+
return snapshot;
|
|
78
|
+
}
|
|
79
|
+
export function parsePersistedAttentionSnapshot(raw) {
|
|
80
|
+
if (!isRecord(raw)) {
|
|
81
|
+
return buildNormalizedAttentionSnapshot();
|
|
82
|
+
}
|
|
83
|
+
const deliveryMode = isDeliveryMode(raw.deliveryMode) ? raw.deliveryMode : 'default';
|
|
84
|
+
const claimState = isClaimState(raw.claimState) ? raw.claimState : 'unclaimed';
|
|
85
|
+
const claimActivation = isClaimActivation(raw.claimActivation) ? raw.claimActivation : 'inactive';
|
|
86
|
+
const observedAt = typeof raw.observedAt === 'number' && Number.isFinite(raw.observedAt)
|
|
87
|
+
? raw.observedAt
|
|
88
|
+
: Date.now();
|
|
89
|
+
const turnExecutionId = typeof raw.turnExecutionId === 'string' && raw.turnExecutionId.trim().length > 0
|
|
90
|
+
? raw.turnExecutionId
|
|
91
|
+
: undefined;
|
|
92
|
+
const claimContext = normalizeClaimContext(raw.claimContext);
|
|
93
|
+
const normalized = buildNormalizedAttentionSnapshot({
|
|
94
|
+
deliveryMode,
|
|
95
|
+
claimState,
|
|
96
|
+
claimActivation,
|
|
97
|
+
observedAt,
|
|
98
|
+
turnExecutionId,
|
|
99
|
+
claimContext,
|
|
100
|
+
});
|
|
101
|
+
if (normalized.claimContext?.scope === 'task-thread') {
|
|
102
|
+
return buildNormalizedAttentionSnapshot({
|
|
103
|
+
deliveryMode: 'default',
|
|
104
|
+
claimState: normalized.claimState,
|
|
105
|
+
claimActivation: 'dormant',
|
|
106
|
+
observedAt: normalized.observedAt,
|
|
107
|
+
turnExecutionId: normalized.turnExecutionId,
|
|
108
|
+
claimContext: normalized.claimContext,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return normalized;
|
|
112
|
+
}
|
|
113
|
+
function formatObservedAt(observedAt) {
|
|
114
|
+
return new Date(observedAt).toISOString();
|
|
115
|
+
}
|
|
116
|
+
export function buildAttentionSummaryLines(snapshot) {
|
|
117
|
+
if (!snapshot) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
return [
|
|
121
|
+
'Host-observed attention snapshot for this channel (projection only; not server-authoritative truth).',
|
|
122
|
+
`Delivery mode: ${snapshot.deliveryMode}`,
|
|
123
|
+
`Claim state: ${snapshot.claimState}`,
|
|
124
|
+
`Claim activation: ${snapshot.claimActivation}`,
|
|
125
|
+
`Wake mode: ${snapshot.wakeMode}`,
|
|
126
|
+
...(snapshot.claimContext
|
|
127
|
+
? [
|
|
128
|
+
`Claim scope: ${snapshot.claimContext.scope}`,
|
|
129
|
+
`Claim task id: ${snapshot.claimContext.taskId}`,
|
|
130
|
+
]
|
|
131
|
+
: []),
|
|
132
|
+
`Observed at: ${formatObservedAt(snapshot.observedAt)}`,
|
|
133
|
+
...(snapshot.turnExecutionId
|
|
134
|
+
? [`Observed turn execution id: ${snapshot.turnExecutionId}`]
|
|
135
|
+
: []),
|
|
136
|
+
];
|
|
137
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CollaborationCapabilityDeclaration, MissedCollaborationDiagnostic } from '../types.js';
|
|
2
|
+
export declare function buildCollaborationCapabilityDeclarationSummaryLines(declaration: CollaborationCapabilityDeclaration | undefined): string[];
|
|
3
|
+
export declare function buildMissedCollaborationDiagnosticSummaryLines(diagnostic: MissedCollaborationDiagnostic | undefined): string[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function buildCollaborationCapabilityDeclarationSummaryLines(declaration) {
|
|
2
|
+
if (!declaration) {
|
|
3
|
+
return [];
|
|
4
|
+
}
|
|
5
|
+
return [
|
|
6
|
+
'Shared hosted collaboration capability declaration (projection only; hosted-path vocabulary only, not authorization, action availability, thread-binding authority, or standalone-runtime parity).',
|
|
7
|
+
`Capability declaration: ${JSON.stringify(declaration)}`,
|
|
8
|
+
];
|
|
9
|
+
}
|
|
10
|
+
export function buildMissedCollaborationDiagnosticSummaryLines(diagnostic) {
|
|
11
|
+
if (!diagnostic) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
return [
|
|
15
|
+
'Latest hosted missed-collaboration diagnostic (projection only; delivery, wake, or response explanation only).',
|
|
16
|
+
`Missed-collaboration diagnostic: ${JSON.stringify(diagnostic)}`,
|
|
17
|
+
];
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function formatObservedAt(observedAt) {
|
|
2
|
+
return new Date(observedAt).toISOString();
|
|
3
|
+
}
|
|
4
|
+
export function buildCollaborationOutcomeSummaryLines(snapshot) {
|
|
5
|
+
if (!snapshot) {
|
|
6
|
+
return [];
|
|
7
|
+
}
|
|
8
|
+
return [
|
|
9
|
+
'Host-observed collaboration outcome snapshot for this channel (projection only; not provider-authoritative truth).',
|
|
10
|
+
`Response state: ${snapshot.responseState}`,
|
|
11
|
+
`Delivery state: ${snapshot.deliveryState}`,
|
|
12
|
+
...(snapshot.wakeState ? [`Wake state: ${snapshot.wakeState}`] : []),
|
|
13
|
+
...(snapshot.blockedDetails
|
|
14
|
+
? [
|
|
15
|
+
`Blocked question: ${snapshot.blockedDetails.question}`,
|
|
16
|
+
...(snapshot.blockedDetails.reason
|
|
17
|
+
? [`Blocked reason: ${snapshot.blockedDetails.reason}`]
|
|
18
|
+
: []),
|
|
19
|
+
]
|
|
20
|
+
: []),
|
|
21
|
+
`Observed at: ${formatObservedAt(snapshot.observedAt)}`,
|
|
22
|
+
...(snapshot.turnExecutionId
|
|
23
|
+
? [`Observed turn execution id: ${snapshot.turnExecutionId}`]
|
|
24
|
+
: []),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LocalhostGatewayBootstrapMetadata, ProviderCollaborationContext, SkillRuntimeBootstrapMetadata, TaskAssignmentThreadContext, TaskWorkspaceContext } from '../types.js';
|
|
1
|
+
import type { AttentionSnapshot, CollaborationCapabilityDeclaration, CollaborationOutcomeSnapshot, LocalhostGatewayBootstrapMetadata, MissedCollaborationDiagnostic, ProviderCollaborationContext, SkillRuntimeBootstrapMetadata, TaskThreadCollaborationContract, TaskAssignmentThreadContext, TaskWorkspaceContext } from '../types.js';
|
|
2
2
|
export interface SkillRuntimeBootstrapPayload {
|
|
3
3
|
skillDirectoryPath: string;
|
|
4
4
|
nodeCliPath: string;
|
|
@@ -7,6 +7,11 @@ export interface SkillRuntimeBootstrapPayload {
|
|
|
7
7
|
export interface ChannelContextPayload {
|
|
8
8
|
schemaVersion: 1;
|
|
9
9
|
channelId: string;
|
|
10
|
+
collaborationOutcome?: CollaborationOutcomeSnapshot;
|
|
11
|
+
attentionSnapshot?: AttentionSnapshot;
|
|
12
|
+
taskThreadCollaborationContract?: TaskThreadCollaborationContract;
|
|
13
|
+
collaborationCapabilities?: CollaborationCapabilityDeclaration;
|
|
14
|
+
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
10
15
|
skillRuntime?: SkillRuntimeBootstrapPayload;
|
|
11
16
|
localhostGateway?: LocalhostGatewayBootstrapMetadata;
|
|
12
17
|
taskAssignmentContext?: TaskAssignmentThreadContext;
|
|
@@ -29,11 +34,21 @@ export interface ChannelContextStore {
|
|
|
29
34
|
prepare(input: {
|
|
30
35
|
channelId: string;
|
|
31
36
|
collaboration?: ProviderCollaborationContext;
|
|
37
|
+
collaborationOutcome?: CollaborationOutcomeSnapshot;
|
|
38
|
+
attentionSnapshot?: AttentionSnapshot;
|
|
39
|
+
taskThreadCollaborationContract?: TaskThreadCollaborationContract;
|
|
40
|
+
collaborationCapabilities?: CollaborationCapabilityDeclaration;
|
|
41
|
+
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
32
42
|
incomingMessageType?: string;
|
|
33
43
|
incomingContent?: string;
|
|
34
44
|
}): Promise<PreparedChannelContext>;
|
|
35
45
|
prepare(channelId: string, options?: {
|
|
36
46
|
collaboration?: ProviderCollaborationContext;
|
|
47
|
+
collaborationOutcome?: CollaborationOutcomeSnapshot;
|
|
48
|
+
attentionSnapshot?: AttentionSnapshot;
|
|
49
|
+
taskThreadCollaborationContract?: TaskThreadCollaborationContract;
|
|
50
|
+
collaborationCapabilities?: CollaborationCapabilityDeclaration;
|
|
51
|
+
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
37
52
|
incomingMessageType?: string;
|
|
38
53
|
incomingContent?: string;
|
|
39
54
|
}): Promise<PreparedChannelContext>;
|
|
@@ -97,10 +112,20 @@ export declare class FileChannelContextStore implements ChannelContextStore {
|
|
|
97
112
|
prepare(inputOrChannelId: {
|
|
98
113
|
channelId: string;
|
|
99
114
|
collaboration?: ProviderCollaborationContext;
|
|
115
|
+
collaborationOutcome?: CollaborationOutcomeSnapshot;
|
|
116
|
+
attentionSnapshot?: AttentionSnapshot;
|
|
117
|
+
taskThreadCollaborationContract?: TaskThreadCollaborationContract;
|
|
118
|
+
collaborationCapabilities?: CollaborationCapabilityDeclaration;
|
|
119
|
+
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
100
120
|
incomingMessageType?: string;
|
|
101
121
|
incomingContent?: string;
|
|
102
122
|
} | string, options?: {
|
|
103
123
|
collaboration?: ProviderCollaborationContext;
|
|
124
|
+
collaborationOutcome?: CollaborationOutcomeSnapshot;
|
|
125
|
+
attentionSnapshot?: AttentionSnapshot;
|
|
126
|
+
taskThreadCollaborationContract?: TaskThreadCollaborationContract;
|
|
127
|
+
collaborationCapabilities?: CollaborationCapabilityDeclaration;
|
|
128
|
+
missedCollaborationDiagnostic?: MissedCollaborationDiagnostic;
|
|
104
129
|
incomingMessageType?: string;
|
|
105
130
|
incomingContent?: string;
|
|
106
131
|
}): Promise<PreparedChannelContext>;
|
|
@@ -57,10 +57,15 @@ function buildLocalhostGatewayAuthPayload(channelId, localhostGateway) {
|
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
function buildChannelContextPayload(channelId, skillRuntime, localhostGateway, options) {
|
|
60
|
+
function buildChannelContextPayload(channelId, collaborationOutcome, attentionSnapshot, taskThreadCollaborationContract, collaborationCapabilities, missedCollaborationDiagnostic, skillRuntime, localhostGateway, options) {
|
|
61
61
|
return {
|
|
62
62
|
schemaVersion: 1,
|
|
63
63
|
channelId,
|
|
64
|
+
...(collaborationOutcome ? { collaborationOutcome } : {}),
|
|
65
|
+
...(attentionSnapshot ? { attentionSnapshot } : {}),
|
|
66
|
+
...(taskThreadCollaborationContract ? { taskThreadCollaborationContract } : {}),
|
|
67
|
+
...(collaborationCapabilities ? { collaborationCapabilities } : {}),
|
|
68
|
+
...(missedCollaborationDiagnostic ? { missedCollaborationDiagnostic } : {}),
|
|
64
69
|
...(skillRuntime ? { skillRuntime: toSkillRuntimePayload(skillRuntime) } : {}),
|
|
65
70
|
...(localhostGateway ? { localhostGateway } : {}),
|
|
66
71
|
...(options?.taskAssignmentContext ? { taskAssignmentContext: options.taskAssignmentContext } : {}),
|
|
@@ -281,7 +286,7 @@ export class FileChannelContextStore {
|
|
|
281
286
|
rootPath: resolveTaskWorkspaceDirectory(this.startupWorkspaceRootDir, input.channelId, taskAssignmentContext.currentTaskId),
|
|
282
287
|
}
|
|
283
288
|
: undefined;
|
|
284
|
-
const payload = buildChannelContextPayload(input.channelId, skillRuntime, localhostGateway, taskAssignmentContext || taskWorkspace
|
|
289
|
+
const payload = buildChannelContextPayload(input.channelId, input.collaborationOutcome, input.attentionSnapshot, input.taskThreadCollaborationContract, input.collaborationCapabilities, input.missedCollaborationDiagnostic, skillRuntime, localhostGateway, taskAssignmentContext || taskWorkspace
|
|
285
290
|
? {
|
|
286
291
|
...(taskAssignmentContext ? { taskAssignmentContext } : {}),
|
|
287
292
|
...(taskWorkspace ? { taskWorkspace } : {}),
|
package/dist/context/prompt.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { AWAITING_USER_CONTROL_PREFIX } from '../providers/awaiting-user.js';
|
|
2
|
+
import { buildAttentionSummaryLines } from './attention.js';
|
|
3
|
+
import { buildCollaborationCapabilityDeclarationSummaryLines, buildMissedCollaborationDiagnosticSummaryLines, } from './collaboration-capabilities-diagnostics.js';
|
|
4
|
+
import { buildCollaborationOutcomeSummaryLines } from './collaboration-outcome.js';
|
|
5
|
+
import { buildTaskThreadCollaborationSummaryLines } from './task-thread-collaboration.js';
|
|
2
6
|
function providerLabel(provider) {
|
|
3
7
|
if (provider === 'copilot') {
|
|
4
8
|
return 'GitHub Copilot';
|
|
@@ -89,6 +93,10 @@ function buildInboundMetadataLines(params) {
|
|
|
89
93
|
return [
|
|
90
94
|
`Incoming transport event kind: ${params.incomingEventKind?.trim() || 'message'}`,
|
|
91
95
|
`Incoming semantic message type: ${params.incomingMessageType?.trim() || 'default'}`,
|
|
96
|
+
...(() => {
|
|
97
|
+
const lines = buildTaskThreadCollaborationSummaryLines(params.promptContext?.taskThreadCollaborationContract);
|
|
98
|
+
return lines.length > 0 ? ['', ...lines] : [];
|
|
99
|
+
})(),
|
|
92
100
|
...buildTaskAssignmentPromptLines(params),
|
|
93
101
|
];
|
|
94
102
|
}
|
|
@@ -101,10 +109,37 @@ function describeIdentity(identity) {
|
|
|
101
109
|
return `${label}, kind=${identity.kind}`;
|
|
102
110
|
}
|
|
103
111
|
function buildTurnControlPromptLines(context) {
|
|
112
|
+
const taskThreadAttentionAvailable = context?.taskAssignmentContext?.active === true
|
|
113
|
+
&& typeof context.taskAssignmentContext.currentTaskId === 'string'
|
|
114
|
+
&& context.taskAssignmentContext.currentTaskId.trim().length > 0;
|
|
115
|
+
const attentionLines = context?.attentionSnapshot
|
|
116
|
+
? [
|
|
117
|
+
'Attention controls are projection-only host hints. They do not bypass server-side mention policy or widen message delivery.',
|
|
118
|
+
`To follow ordinary delivered human messages in this channel, add "attentionUpdate":"follow-channel".`,
|
|
119
|
+
`To stop follow-based human wake for this channel, add "attentionUpdate":"unfollow-channel".`,
|
|
120
|
+
`To mute ordinary delivered human wake while keeping explicit mentions and task assignments untouched, add "attentionUpdate":"mute-channel".`,
|
|
121
|
+
`To set a durable channel-level attention hint, add "attentionUpdate":"claim-channel".`,
|
|
122
|
+
...(taskThreadAttentionAvailable
|
|
123
|
+
? [
|
|
124
|
+
`To set a durable task-thread attention hint, add "attentionUpdate":"claim-task-thread" only when this turn has active injected task-thread context with a usable currentTaskId.`,
|
|
125
|
+
`To clear a local claim without changing deliveryMode, add "attentionUpdate":"unclaim-channel" or "attentionUpdate":"unclaim-task-thread".`,
|
|
126
|
+
]
|
|
127
|
+
: [
|
|
128
|
+
`To clear a local channel claim without changing deliveryMode, add "attentionUpdate":"unclaim-channel".`,
|
|
129
|
+
]),
|
|
130
|
+
]
|
|
131
|
+
: [];
|
|
132
|
+
const attentionOnlyLine = context?.attentionSnapshot
|
|
133
|
+
? [
|
|
134
|
+
`For an attention-only reply, keep a non-empty visible body and append: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"attention-only","attentionUpdate":"follow-channel"}`,
|
|
135
|
+
]
|
|
136
|
+
: [];
|
|
104
137
|
if (!context) {
|
|
105
138
|
return [
|
|
106
139
|
`Only when you need host-local turn control, append exactly one final non-empty line starting with ${AWAITING_USER_CONTROL_PREFIX}.`,
|
|
107
140
|
`For ordinary blocked-on-human turns, use: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"awaiting-user","question":"<short question>","reason":"<short reason>"}`,
|
|
141
|
+
...attentionLines,
|
|
142
|
+
...attentionOnlyLine,
|
|
108
143
|
'Do not emit multiple control lines, and do not use a control footer for ordinary answers.',
|
|
109
144
|
];
|
|
110
145
|
}
|
|
@@ -123,6 +158,10 @@ function buildTurnControlPromptLines(context) {
|
|
|
123
158
|
`When handing off to the named peer, use: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"continue-to-peer"}`,
|
|
124
159
|
`When finishing locally, use: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"conclude-locally"}`,
|
|
125
160
|
`If you are blocked on the human instead, use: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"awaiting-user","question":"<short question>","reason":"<short reason>"}`,
|
|
161
|
+
...(context.attentionSnapshot
|
|
162
|
+
? ['You may add one attentionUpdate field to continue-to-peer, conclude-locally, or awaiting-user when you also need an attention change for this channel.']
|
|
163
|
+
: []),
|
|
164
|
+
...attentionLines,
|
|
126
165
|
'Do not emit multiple control lines, and do not use start-protocol while host-managed collaboration is already active.',
|
|
127
166
|
];
|
|
128
167
|
}
|
|
@@ -151,6 +190,7 @@ function buildTurnControlPromptLines(context) {
|
|
|
151
190
|
...(participantSummary ? [`Visible kickoff participants: ${participantSummary}.`] : []),
|
|
152
191
|
'This evaluation is read-only and silent: do not use auxiliary collaboration send commands, and do not draft a user-visible reply body for this turn.',
|
|
153
192
|
`If the anchor message is genuinely requesting host-managed collaboration between the named agents, use: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"start-protocol","rounds":<positive integer>}`,
|
|
193
|
+
'Do not combine start-protocol with any attentionUpdate field.',
|
|
154
194
|
'If collaboration should not start, omit the control footer entirely.',
|
|
155
195
|
'Do not emit multiple control lines.',
|
|
156
196
|
];
|
|
@@ -158,6 +198,11 @@ function buildTurnControlPromptLines(context) {
|
|
|
158
198
|
return [
|
|
159
199
|
`Only when you need host-local turn control, append exactly one final non-empty line starting with ${AWAITING_USER_CONTROL_PREFIX}.`,
|
|
160
200
|
`For ordinary blocked-on-human turns, use: ${AWAITING_USER_CONTROL_PREFIX}{"kind":"awaiting-user","question":"<short question>","reason":"<short reason>"}`,
|
|
201
|
+
...(context?.attentionSnapshot
|
|
202
|
+
? ['You may add one attentionUpdate field to awaiting-user when you also need an attention change for this channel.']
|
|
203
|
+
: []),
|
|
204
|
+
...attentionLines,
|
|
205
|
+
...attentionOnlyLine,
|
|
161
206
|
'Do not emit multiple control lines, and do not use a control footer for ordinary answers.',
|
|
162
207
|
];
|
|
163
208
|
}
|
|
@@ -184,6 +229,22 @@ export function buildPrompt(params) {
|
|
|
184
229
|
incomingMessageType: params.incomingMessageType,
|
|
185
230
|
promptContext: params.promptContext,
|
|
186
231
|
}),
|
|
232
|
+
...(() => {
|
|
233
|
+
const lines = buildCollaborationOutcomeSummaryLines(params.promptContext?.collaborationOutcome);
|
|
234
|
+
return lines.length > 0 ? ['', ...lines] : [];
|
|
235
|
+
})(),
|
|
236
|
+
...(() => {
|
|
237
|
+
const lines = buildAttentionSummaryLines(params.promptContext?.attentionSnapshot);
|
|
238
|
+
return lines.length > 0 ? ['', ...lines] : [];
|
|
239
|
+
})(),
|
|
240
|
+
...(() => {
|
|
241
|
+
const lines = buildCollaborationCapabilityDeclarationSummaryLines(params.promptContext?.collaborationCapabilities);
|
|
242
|
+
return lines.length > 0 ? ['', ...lines] : [];
|
|
243
|
+
})(),
|
|
244
|
+
...(() => {
|
|
245
|
+
const lines = buildMissedCollaborationDiagnosticSummaryLines(params.promptContext?.missedCollaborationDiagnostic);
|
|
246
|
+
return lines.length > 0 ? ['', ...lines] : [];
|
|
247
|
+
})(),
|
|
187
248
|
...buildSkillRuntimePromptLines(params.promptContext),
|
|
188
249
|
...buildLocalhostGatewayPromptLines(params.promptContext),
|
|
189
250
|
'',
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TaskThreadCollaborationContract } from '../types.js';
|
|
2
|
+
export declare function projectTaskThreadCollaborationContract(params: {
|
|
3
|
+
incomingMessageType?: string;
|
|
4
|
+
taskThreadContextActive: boolean;
|
|
5
|
+
}): TaskThreadCollaborationContract | undefined;
|
|
6
|
+
export declare function buildTaskThreadCollaborationSummaryLines(contract: TaskThreadCollaborationContract | undefined): string[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function projectTaskThreadCollaborationContract(params) {
|
|
2
|
+
if (!params.taskThreadContextActive) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
const turnRole = params.incomingMessageType?.trim() === 'task_assignment'
|
|
6
|
+
? 'assignment'
|
|
7
|
+
: 'continuation';
|
|
8
|
+
return {
|
|
9
|
+
source: 'host-projected',
|
|
10
|
+
turnRole,
|
|
11
|
+
taskThreadContextActive: true,
|
|
12
|
+
mainResult: 'ordinary-final-reply-in-thread',
|
|
13
|
+
auxiliaryRoute: 'optional-auxiliary-send-or-escalation-only',
|
|
14
|
+
checkIn: 'status-update-intent-only',
|
|
15
|
+
blockedWork: 'in-thread-disclosure-only',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function buildTaskThreadCollaborationSummaryLines(contract) {
|
|
19
|
+
if (!contract) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return [
|
|
23
|
+
'Shared task-thread collaboration contract for this turn (projection only; not runtime-authoritative truth).',
|
|
24
|
+
`Thread role: ${contract.turnRole}`,
|
|
25
|
+
`Active task-thread context: ${contract.taskThreadContextActive ? 'yes' : 'no'}`,
|
|
26
|
+
'Main task result: return the ordinary final reply in this task thread.',
|
|
27
|
+
'Auxiliary send or escalation: optional auxiliary route only, never the main completion path.',
|
|
28
|
+
'Check-in: status-update intent only; no timer, heartbeat, send-route, scheduler, receipt, or recovery authority is implied here.',
|
|
29
|
+
'Blocked work: disclose the blocker in-thread through the existing in-thread reply path, if one exists; no blocked-state authority or extra control kind is implied here.',
|
|
30
|
+
];
|
|
31
|
+
}
|
|
@@ -11,7 +11,13 @@ function providerLabel(provider) {
|
|
|
11
11
|
return 'Claude';
|
|
12
12
|
}
|
|
13
13
|
function toPromptContext(channelContext, input) {
|
|
14
|
-
if (!channelContext
|
|
14
|
+
if (!channelContext
|
|
15
|
+
&& !input.collaboration
|
|
16
|
+
&& !input.collaborationOutcome
|
|
17
|
+
&& !input.attentionSnapshot
|
|
18
|
+
&& !input.collaborationCapabilities
|
|
19
|
+
&& !input.missedCollaborationDiagnostic
|
|
20
|
+
&& !input.taskThreadCollaborationContract) {
|
|
15
21
|
return undefined;
|
|
16
22
|
}
|
|
17
23
|
return {
|
|
@@ -27,6 +33,22 @@ function toPromptContext(channelContext, input) {
|
|
|
27
33
|
: {}),
|
|
28
34
|
collaborationTurnExecutionId: input.collaboration?.turnExecutionId,
|
|
29
35
|
collaborationTurnMode: input.collaboration?.turnMode,
|
|
36
|
+
collaborationOutcome: input.collaborationOutcome ?? channelContext?.payload.collaborationOutcome,
|
|
37
|
+
attentionSnapshot: input.attentionSnapshot ?? channelContext?.payload.attentionSnapshot,
|
|
38
|
+
...(() => {
|
|
39
|
+
const collaborationCapabilities = input.collaborationCapabilities ?? channelContext?.payload.collaborationCapabilities;
|
|
40
|
+
return collaborationCapabilities ? { collaborationCapabilities } : {};
|
|
41
|
+
})(),
|
|
42
|
+
...(() => {
|
|
43
|
+
const missedCollaborationDiagnostic = input.missedCollaborationDiagnostic ?? channelContext?.payload.missedCollaborationDiagnostic;
|
|
44
|
+
return missedCollaborationDiagnostic ? { missedCollaborationDiagnostic } : {};
|
|
45
|
+
})(),
|
|
46
|
+
...(input.taskThreadCollaborationContract || channelContext?.payload.taskThreadCollaborationContract
|
|
47
|
+
? {
|
|
48
|
+
taskThreadCollaborationContract: input.taskThreadCollaborationContract
|
|
49
|
+
?? channelContext?.payload.taskThreadCollaborationContract,
|
|
50
|
+
}
|
|
51
|
+
: {}),
|
|
30
52
|
kickoff: input.collaboration?.kickoff,
|
|
31
53
|
protocol: input.collaboration?.protocol,
|
|
32
54
|
grounding: input.collaboration?.grounding,
|
|
@@ -65,6 +87,13 @@ export class ProviderTurnPreparer {
|
|
|
65
87
|
&& input.collaboration.turnMode !== 'silent-kickoff',
|
|
66
88
|
}
|
|
67
89
|
: undefined,
|
|
90
|
+
collaborationOutcome: input.collaborationOutcome,
|
|
91
|
+
attentionSnapshot: input.attentionSnapshot,
|
|
92
|
+
collaborationCapabilities: input.collaborationCapabilities,
|
|
93
|
+
missedCollaborationDiagnostic: input.missedCollaborationDiagnostic,
|
|
94
|
+
...(input.taskThreadCollaborationContract
|
|
95
|
+
? { taskThreadCollaborationContract: input.taskThreadCollaborationContract }
|
|
96
|
+
: {}),
|
|
68
97
|
...(input.incomingMessageType !== undefined
|
|
69
98
|
? { incomingMessageType: input.incomingMessageType }
|
|
70
99
|
: {}),
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
export const HOST_CONTROL_PREFIX = '[[BORGEE_CONTROL]] ';
|
|
2
2
|
export const AWAITING_USER_CONTROL_PREFIX = HOST_CONTROL_PREFIX;
|
|
3
|
+
const VALID_ATTENTION_UPDATES = new Set([
|
|
4
|
+
'follow-channel',
|
|
5
|
+
'unfollow-channel',
|
|
6
|
+
'mute-channel',
|
|
7
|
+
'claim-channel',
|
|
8
|
+
'claim-task-thread',
|
|
9
|
+
'unclaim-channel',
|
|
10
|
+
'unclaim-task-thread',
|
|
11
|
+
]);
|
|
12
|
+
function isProviderAttentionUpdate(value) {
|
|
13
|
+
return typeof value === 'string' && VALID_ATTENTION_UPDATES.has(value);
|
|
14
|
+
}
|
|
3
15
|
function hasVisibleText(value) {
|
|
4
16
|
return value.trim().length > 0;
|
|
5
17
|
}
|
|
@@ -50,13 +62,26 @@ function parseControlPayload(payload) {
|
|
|
50
62
|
if (typeof record.kind !== 'string') {
|
|
51
63
|
return null;
|
|
52
64
|
}
|
|
65
|
+
const attentionUpdate = (() => {
|
|
66
|
+
if (record.attentionUpdate === undefined) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
return isProviderAttentionUpdate(record.attentionUpdate) ? record.attentionUpdate : null;
|
|
70
|
+
})();
|
|
71
|
+
if (attentionUpdate === null) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
53
74
|
if (record.kind === 'continue-to-peer' || record.kind === 'conclude-locally') {
|
|
54
|
-
return Object.keys(record).
|
|
55
|
-
? {
|
|
75
|
+
return Object.keys(record).every((key) => key === 'kind' || key === 'attentionUpdate')
|
|
76
|
+
? {
|
|
77
|
+
kind: record.kind,
|
|
78
|
+
...(attentionUpdate ? { attentionUpdate } : {}),
|
|
79
|
+
}
|
|
56
80
|
: null;
|
|
57
81
|
}
|
|
58
82
|
if (record.kind === 'start-protocol') {
|
|
59
|
-
return
|
|
83
|
+
return attentionUpdate === undefined
|
|
84
|
+
&& Object.keys(record).length === 2
|
|
60
85
|
&& typeof record.rounds === 'number'
|
|
61
86
|
&& Number.isInteger(record.rounds)
|
|
62
87
|
&& record.rounds > 0
|
|
@@ -68,7 +93,7 @@ function parseControlPayload(payload) {
|
|
|
68
93
|
}
|
|
69
94
|
if (record.kind === 'awaiting-user') {
|
|
70
95
|
const keys = Object.keys(record);
|
|
71
|
-
if (keys.some((key) => key !== 'kind' && key !== 'question' && key !== 'reason')) {
|
|
96
|
+
if (keys.some((key) => key !== 'kind' && key !== 'question' && key !== 'reason' && key !== 'attentionUpdate')) {
|
|
72
97
|
return null;
|
|
73
98
|
}
|
|
74
99
|
if (typeof record.question !== 'string' || record.question.trim().length === 0) {
|
|
@@ -82,8 +107,17 @@ function parseControlPayload(payload) {
|
|
|
82
107
|
kind: 'awaiting-user',
|
|
83
108
|
question: record.question.trim(),
|
|
84
109
|
...(typeof record.reason === 'string' ? { reason: record.reason.trim() } : {}),
|
|
110
|
+
...(attentionUpdate ? { attentionUpdate } : {}),
|
|
85
111
|
};
|
|
86
112
|
}
|
|
113
|
+
if (record.kind === 'attention-only') {
|
|
114
|
+
return Object.keys(record).length === 2 && attentionUpdate
|
|
115
|
+
? {
|
|
116
|
+
kind: 'attention-only',
|
|
117
|
+
attentionUpdate,
|
|
118
|
+
}
|
|
119
|
+
: null;
|
|
120
|
+
}
|
|
87
121
|
return null;
|
|
88
122
|
}
|
|
89
123
|
export function parseProviderReply(text) {
|
|
@@ -98,8 +132,15 @@ export function parseProviderReply(text) {
|
|
|
98
132
|
controlMalformed: true,
|
|
99
133
|
};
|
|
100
134
|
}
|
|
135
|
+
const textWithoutFooter = stripTrailingCarriageReturn(match.analyzedText.slice(0, match.removalStart));
|
|
136
|
+
if (control.kind === 'attention-only' && !hasVisibleText(textWithoutFooter)) {
|
|
137
|
+
return {
|
|
138
|
+
text: textWithoutFooter,
|
|
139
|
+
controlMalformed: true,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
101
142
|
return {
|
|
102
|
-
text:
|
|
143
|
+
text: textWithoutFooter,
|
|
103
144
|
control,
|
|
104
145
|
...(control.kind === 'awaiting-user'
|
|
105
146
|
? {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
|
+
import { buildAttentionSummaryLines } from '../../context/attention.js';
|
|
3
|
+
import { buildCollaborationCapabilityDeclarationSummaryLines, buildMissedCollaborationDiagnosticSummaryLines, } from '../../context/collaboration-capabilities-diagnostics.js';
|
|
4
|
+
import { buildCollaborationOutcomeSummaryLines } from '../../context/collaboration-outcome.js';
|
|
5
|
+
import { buildTaskThreadCollaborationSummaryLines } from '../../context/task-thread-collaboration.js';
|
|
2
6
|
const PROJECT_DOC_MAX_BYTES = 32 * 1024;
|
|
3
7
|
function buildSkillRuntimeLines(context) {
|
|
4
8
|
if (!context?.skillRuntime || !context.channelContextPayloadPath) {
|
|
@@ -47,6 +51,26 @@ export function buildCodexProjectDocument(context) {
|
|
|
47
51
|
'That writable task workspace is local to agents-host for the current task thread and does not imply that the target repository has already been checked out there.',
|
|
48
52
|
]
|
|
49
53
|
: []),
|
|
54
|
+
...(() => {
|
|
55
|
+
const collaborationOutcomeLines = buildCollaborationOutcomeSummaryLines(context?.collaborationOutcome);
|
|
56
|
+
return collaborationOutcomeLines.length > 0 ? ['', ...collaborationOutcomeLines] : [];
|
|
57
|
+
})(),
|
|
58
|
+
...(() => {
|
|
59
|
+
const attentionLines = buildAttentionSummaryLines(context?.attentionSnapshot);
|
|
60
|
+
return attentionLines.length > 0 ? ['', ...attentionLines] : [];
|
|
61
|
+
})(),
|
|
62
|
+
...(() => {
|
|
63
|
+
const capabilityLines = buildCollaborationCapabilityDeclarationSummaryLines(context?.collaborationCapabilities);
|
|
64
|
+
return capabilityLines.length > 0 ? ['', ...capabilityLines] : [];
|
|
65
|
+
})(),
|
|
66
|
+
...(() => {
|
|
67
|
+
const diagnosticLines = buildMissedCollaborationDiagnosticSummaryLines(context?.missedCollaborationDiagnostic);
|
|
68
|
+
return diagnosticLines.length > 0 ? ['', ...diagnosticLines] : [];
|
|
69
|
+
})(),
|
|
70
|
+
...(() => {
|
|
71
|
+
const taskThreadLines = buildTaskThreadCollaborationSummaryLines(context?.taskThreadCollaborationContract);
|
|
72
|
+
return taskThreadLines.length > 0 ? ['', ...taskThreadLines] : [];
|
|
73
|
+
})(),
|
|
50
74
|
...(() => {
|
|
51
75
|
const skillRuntimeLines = buildSkillRuntimeLines(context);
|
|
52
76
|
return skillRuntimeLines.length > 0 ? ['', ...skillRuntimeLines] : [];
|