@borgee/agents-host 0.2.35 → 0.2.56
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 +23 -27
- package/dist/agents-host.d.ts +28 -5
- package/dist/agents-host.js +274 -236
- package/dist/chat/chat-control-plane.d.ts +3 -0
- package/dist/chat/sdk-chat-control-plane.d.ts +4 -3
- package/dist/chat/sdk-chat-control-plane.js +6 -0
- package/dist/cli.js +1 -5
- package/dist/compatibility-gates.d.ts +4 -0
- package/dist/compatibility-gates.js +18 -1
- package/dist/context/claude-file-brief.d.ts +2 -0
- package/dist/context/claude-file-brief.js +83 -0
- package/dist/context/compaction.d.ts +20 -0
- package/dist/context/compaction.js +59 -0
- package/dist/context/injection.d.ts +44 -9
- package/dist/context/injection.js +360 -53
- package/dist/context/main-session-delegation.d.ts +1 -1
- package/dist/context/projection-strategy.d.ts +24 -0
- package/dist/context/projection-strategy.js +90 -0
- package/dist/context/prompt.d.ts +16 -1
- package/dist/context/prompt.js +475 -53
- package/dist/context/resolved-workspace.d.ts +2 -0
- package/dist/context/resolved-workspace.js +64 -0
- package/dist/context/skill-manual.d.ts +14 -0
- package/dist/context/skill-manual.js +21 -0
- package/dist/context/turn-preparation.d.ts +8 -2
- package/dist/context/turn-preparation.js +68 -17
- package/dist/gateway/localhost-gateway.js +18 -8
- package/dist/hosted-turn-content.d.ts +15 -0
- package/dist/hosted-turn-content.js +50 -0
- package/dist/managed-daemon.d.ts +3 -2
- package/dist/managed-daemon.js +198 -37
- package/dist/plugin-sdk.js +276 -359
- package/dist/plugin-sdk.js.map +4 -4
- package/dist/progress-to-activity.d.ts +16 -0
- package/dist/progress-to-activity.js +24 -0
- package/dist/projection-strategy-values.d.ts +4 -0
- package/dist/projection-strategy-values.js +28 -0
- package/dist/providers/acp-progress-collector.d.ts +44 -0
- package/dist/providers/acp-progress-collector.js +130 -0
- package/dist/providers/awaiting-user.d.ts +2 -3
- package/dist/providers/awaiting-user.js +5 -7
- package/dist/providers/claude/activity-metadata.d.ts +14 -0
- package/dist/providers/claude/activity-metadata.js +81 -0
- package/dist/providers/claude/adapter.d.ts +3 -1
- package/dist/providers/claude/adapter.js +10 -0
- package/dist/providers/claude/cli-client.d.ts +9 -1
- package/dist/providers/claude/cli-client.js +270 -126
- package/dist/providers/codex/adapter.d.ts +3 -1
- package/dist/providers/codex/adapter.js +10 -0
- package/dist/providers/codex/cli-client.d.ts +10 -2
- package/dist/providers/codex/cli-client.js +88 -104
- package/dist/providers/codex/project-doc.js +22 -37
- package/dist/providers/copilot/adapter.d.ts +3 -1
- package/dist/providers/copilot/adapter.js +10 -0
- package/dist/providers/copilot/cli-client.d.ts +9 -1
- package/dist/providers/copilot/cli-client.js +68 -85
- package/dist/providers/create-provider.d.ts +3 -1
- package/dist/providers/create-provider.js +36 -9
- package/dist/providers/provider-adapter.d.ts +35 -0
- package/dist/providers/provider-adapter.js +44 -1
- package/dist/state-paths.d.ts +10 -2
- package/dist/state-paths.js +25 -6
- package/dist/task-thread-resolution.d.ts +3 -2
- package/dist/types.d.ts +163 -8
- package/package.json +2 -2
- package/skills/borgee-agent/SKILL.md +127 -38
- package/skills/borgee-agent/references/errors.md +38 -0
- package/skills/borgee-agent/references/task-properties.md +33 -0
- package/skills/borgee-agent/scripts/borgee-agent.mjs +553 -0
- package/skills/borgee-agent/scripts/borgee-agent.py +547 -0
- package/dist/durable-cursor-store.d.ts +0 -5
- package/dist/durable-cursor-store.js +0 -7
- package/skills/borgee-agent/borgee-agent.mjs +0 -562
- package/skills/borgee-agent/borgee-agent.py +0 -469
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
function buildWorkspaceRootLine(context) {
|
|
2
|
+
const resolvedWorkspace = context.resolvedWorkspace;
|
|
3
|
+
if (!resolvedWorkspace) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
if (resolvedWorkspace.authority === 'task') {
|
|
7
|
+
return `Writable task-isolated workspace root for this task thread: ${resolvedWorkspace.rootPath}.`;
|
|
8
|
+
}
|
|
9
|
+
if (context.taskAssignmentContext?.active === true) {
|
|
10
|
+
return `Writable workspace root inherited from this task thread's channel: ${resolvedWorkspace.rootPath}.`;
|
|
11
|
+
}
|
|
12
|
+
return `Writable workspace root for this channel: ${resolvedWorkspace.rootPath}.`;
|
|
13
|
+
}
|
|
14
|
+
function buildWorkspaceModeLine(context) {
|
|
15
|
+
if (context.taskAssignmentContext?.active !== true || !context.resolvedWorkspace) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
if (context.resolvedWorkspace.authority === 'task') {
|
|
19
|
+
return 'This task thread runs in a task-isolated workspace instead of inheriting the channel workspace.';
|
|
20
|
+
}
|
|
21
|
+
return 'This task thread inherits the channel workspace rather than using a task-isolated workspace.';
|
|
22
|
+
}
|
|
23
|
+
function buildWorkspaceLocalityLine(context) {
|
|
24
|
+
if (!context.resolvedWorkspace) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (context.resolvedWorkspace.authority === 'task') {
|
|
28
|
+
return 'This writable workspace is local to agents-host for this task thread. It does not imply that the target repository has already been checked out there.';
|
|
29
|
+
}
|
|
30
|
+
if (context.taskAssignmentContext?.active === true) {
|
|
31
|
+
return 'This writable workspace is local to agents-host for this task thread because the task inherits its channel workspace. It does not imply that the target repository has already been checked out there.';
|
|
32
|
+
}
|
|
33
|
+
return 'This writable workspace is local to agents-host for this channel. It does not imply that the target repository has already been checked out there.';
|
|
34
|
+
}
|
|
35
|
+
function buildCopilotCwdLine(context) {
|
|
36
|
+
if (!context.resolvedWorkspace) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (context.resolvedWorkspace.authority === 'task') {
|
|
40
|
+
return 'GitHub Copilot runs this turn with that task-isolated workspace as its real cwd.';
|
|
41
|
+
}
|
|
42
|
+
if (context.taskAssignmentContext?.active === true) {
|
|
43
|
+
return 'GitHub Copilot runs this turn with that inherited channel workspace as its real cwd.';
|
|
44
|
+
}
|
|
45
|
+
return 'GitHub Copilot runs this turn with that workspace as its real cwd.';
|
|
46
|
+
}
|
|
47
|
+
export function buildResolvedWorkspaceGuidanceLines(context, provider) {
|
|
48
|
+
if (!context?.resolvedWorkspace) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const lines = [buildWorkspaceRootLine(context), buildWorkspaceModeLine(context)]
|
|
52
|
+
.filter((line) => line != null);
|
|
53
|
+
if (provider === 'copilot') {
|
|
54
|
+
const copilotCwdLine = buildCopilotCwdLine(context);
|
|
55
|
+
if (copilotCwdLine) {
|
|
56
|
+
lines.push(copilotCwdLine);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const localityLine = buildWorkspaceLocalityLine(context);
|
|
60
|
+
if (localityLine) {
|
|
61
|
+
lines.push(localityLine);
|
|
62
|
+
}
|
|
63
|
+
return lines;
|
|
64
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SkillRuntimeBootstrapMetadata } from '../types.js';
|
|
2
|
+
export declare function buildSkillManualReadLine(skillRuntime: SkillRuntimeBootstrapMetadata): string;
|
|
3
|
+
/**
|
|
4
|
+
* What every model-facing surface says about the packaged CLI: what it is, where its manual is, and
|
|
5
|
+
* that the manual has to be opened before acting. Nothing else about the CLI is stated on a host
|
|
6
|
+
* surface — the manual is self-contained, so the invocation grammar, the command inventory, the
|
|
7
|
+
* limits and the credential-file rules have one home that cannot drift from the implementations.
|
|
8
|
+
*
|
|
9
|
+
* The authorization sentence is written against the credential file rather than against "this turn"
|
|
10
|
+
* because the surfaces disagree about scope: the per-turn prompt is turn-scoped while Claude's
|
|
11
|
+
* session append and Codex's projected document are session-scoped, and only the per-turn prompt
|
|
12
|
+
* knows whether a credential file exists.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildSkillManualLines(skillRuntime: SkillRuntimeBootstrapMetadata): string[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function buildSkillManualReadLine(skillRuntime) {
|
|
2
|
+
return `Read its manual at ${skillRuntime.skillMarkdownPath} before you act on this channel; it defines both the session-level coordination and delegation contract and the CLI invocation.`;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* What every model-facing surface says about the packaged CLI: what it is, where its manual is, and
|
|
6
|
+
* that the manual has to be opened before acting. Nothing else about the CLI is stated on a host
|
|
7
|
+
* surface — the manual is self-contained, so the invocation grammar, the command inventory, the
|
|
8
|
+
* limits and the credential-file rules have one home that cannot drift from the implementations.
|
|
9
|
+
*
|
|
10
|
+
* The authorization sentence is written against the credential file rather than against "this turn"
|
|
11
|
+
* because the surfaces disagree about scope: the per-turn prompt is turn-scoped while Claude's
|
|
12
|
+
* session append and Codex's projected document are session-scoped, and only the per-turn prompt
|
|
13
|
+
* knows whether a credential file exists.
|
|
14
|
+
*/
|
|
15
|
+
export function buildSkillManualLines(skillRuntime) {
|
|
16
|
+
return [
|
|
17
|
+
"A packaged local CLI reads this Borgee channel and acts on its tasks: channel history, visible participants, this channel's tasks and their properties, and short auxiliary mentions.",
|
|
18
|
+
buildSkillManualReadLine(skillRuntime),
|
|
19
|
+
'Every command the manual documents is already authorized on a turn whose prompt names a gateway credential file. Run them directly and do not ask the user for permission first.',
|
|
20
|
+
];
|
|
21
|
+
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { type DebugLogger } from '../debug.js';
|
|
2
|
-
import type { PreparedProviderTurnInput, ProviderInput } from '../types.js';
|
|
2
|
+
import type { ProjectionStrategy, PreparedProviderTurnInput, ProviderInput } from '../types.js';
|
|
3
3
|
import { type ChannelContextStore } from './injection.js';
|
|
4
|
+
type ResolveProjectionStrategy = (input: ProviderInput) => Promise<ProjectionStrategy>;
|
|
4
5
|
export declare class ProviderTurnPreparer {
|
|
5
6
|
private readonly channelContextStore?;
|
|
6
7
|
private readonly logger;
|
|
7
|
-
|
|
8
|
+
private readonly resolveProjectionStrategy;
|
|
9
|
+
constructor(channelContextStore?: ChannelContextStore | undefined, logger?: DebugLogger, options?: {
|
|
10
|
+
projectionStrategy?: ProjectionStrategy;
|
|
11
|
+
resolveProjectionStrategy?: ResolveProjectionStrategy;
|
|
12
|
+
});
|
|
8
13
|
prepare(input: ProviderInput): Promise<PreparedProviderTurnInput>;
|
|
9
14
|
}
|
|
15
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { HostLogger, summarizeError } from '../debug.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { DEFAULT_PROJECTION_STRATEGY } from '../projection-strategy-values.js';
|
|
3
|
+
import { buildHostedIncomingContentText, buildHostedTurnContentParts } from '../hosted-turn-content.js';
|
|
4
|
+
import { buildRuntimeSurfaceForTurn, ChannelContextPreparationError, } from './injection.js';
|
|
5
|
+
import { buildClaudeSessionPromptAppend, buildClaudeTurnPrompt, buildPrompt } from './prompt.js';
|
|
4
6
|
function providerLabel(provider) {
|
|
5
7
|
if (provider === 'copilot') {
|
|
6
8
|
return 'Copilot';
|
|
@@ -15,26 +17,36 @@ function toPromptContext(channelContext, input) {
|
|
|
15
17
|
&& !input.collaboration
|
|
16
18
|
&& !input.collaborationOutcome
|
|
17
19
|
&& !input.attentionSnapshot
|
|
20
|
+
&& !input.compactionSnapshot
|
|
18
21
|
&& !input.collaborationCapabilities
|
|
19
22
|
&& !input.missedCollaborationDiagnostic
|
|
20
23
|
&& !input.taskThreadCollaborationContract) {
|
|
21
24
|
return undefined;
|
|
22
25
|
}
|
|
26
|
+
const runtimeSurface = channelContext?.payload.runtimeSurface ?? buildRuntimeSurfaceForTurn({
|
|
27
|
+
localhostGateway: channelContext?.payload.localhostGateway ?? channelContext?.localhostGateway,
|
|
28
|
+
collaboration: input.collaboration,
|
|
29
|
+
taskAssignmentContext: channelContext?.payload.taskAssignmentContext,
|
|
30
|
+
});
|
|
23
31
|
return {
|
|
24
32
|
...(channelContext
|
|
25
33
|
? {
|
|
26
34
|
channelContextPayloadPath: channelContext.payloadPath,
|
|
27
|
-
|
|
35
|
+
claudeProjectedBriefPath: channelContext.claudeProjectedBriefPath,
|
|
36
|
+
claudeProjectedBriefHash: channelContext.claudeProjectedBriefHash,
|
|
37
|
+
gatewayCredentialPath: channelContext.gatewayCredentialPath,
|
|
28
38
|
skillRuntime: channelContext.skillRuntime,
|
|
29
39
|
localhostGateway: channelContext.localhostGateway,
|
|
30
40
|
taskAssignmentContext: channelContext.payload.taskAssignmentContext,
|
|
31
|
-
|
|
41
|
+
resolvedWorkspace: channelContext.resolvedWorkspace,
|
|
32
42
|
}
|
|
33
43
|
: {}),
|
|
44
|
+
runtimeSurface,
|
|
34
45
|
collaborationTurnExecutionId: input.collaboration?.turnExecutionId,
|
|
35
46
|
collaborationTurnMode: input.collaboration?.turnMode,
|
|
36
47
|
collaborationOutcome: input.collaborationOutcome ?? channelContext?.payload.collaborationOutcome,
|
|
37
48
|
attentionSnapshot: input.attentionSnapshot ?? channelContext?.payload.attentionSnapshot,
|
|
49
|
+
compactionSnapshot: input.compactionSnapshot ?? channelContext?.payload.compactionSnapshot,
|
|
38
50
|
...(() => {
|
|
39
51
|
const collaborationCapabilities = input.collaborationCapabilities ?? channelContext?.payload.collaborationCapabilities;
|
|
40
52
|
return collaborationCapabilities ? { collaborationCapabilities } : {};
|
|
@@ -70,16 +82,30 @@ function resolveProviderSessionRouting(input) {
|
|
|
70
82
|
export class ProviderTurnPreparer {
|
|
71
83
|
channelContextStore;
|
|
72
84
|
logger;
|
|
73
|
-
|
|
85
|
+
resolveProjectionStrategy;
|
|
86
|
+
constructor(channelContextStore, logger = new HostLogger(), options = {}) {
|
|
74
87
|
this.channelContextStore = channelContextStore;
|
|
75
88
|
this.logger = logger;
|
|
89
|
+
this.resolveProjectionStrategy = options.resolveProjectionStrategy
|
|
90
|
+
?? (async () => options.projectionStrategy ?? DEFAULT_PROJECTION_STRATEGY);
|
|
76
91
|
}
|
|
77
92
|
async prepare(input) {
|
|
93
|
+
const incomingParts = input.incomingParts ?? buildHostedTurnContentParts({
|
|
94
|
+
text: input.incomingContent,
|
|
95
|
+
});
|
|
96
|
+
const incomingContent = incomingParts.length > 0
|
|
97
|
+
? buildHostedIncomingContentText(incomingParts)
|
|
98
|
+
: input.incomingContent;
|
|
99
|
+
const projectionStrategy = input.provider === 'claude'
|
|
100
|
+
? await this.resolveProjectionStrategy(input)
|
|
101
|
+
: undefined;
|
|
78
102
|
let channelContext;
|
|
79
103
|
if (this.channelContextStore) {
|
|
80
104
|
try {
|
|
81
105
|
const prepareInput = {
|
|
82
106
|
channelId: input.channelId,
|
|
107
|
+
provider: input.provider,
|
|
108
|
+
projectionStrategy,
|
|
83
109
|
collaboration: input.collaboration
|
|
84
110
|
? {
|
|
85
111
|
...input.collaboration,
|
|
@@ -89,6 +115,7 @@ export class ProviderTurnPreparer {
|
|
|
89
115
|
: undefined,
|
|
90
116
|
collaborationOutcome: input.collaborationOutcome,
|
|
91
117
|
attentionSnapshot: input.attentionSnapshot,
|
|
118
|
+
compactionSnapshot: input.compactionSnapshot,
|
|
92
119
|
collaborationCapabilities: input.collaborationCapabilities,
|
|
93
120
|
missedCollaborationDiagnostic: input.missedCollaborationDiagnostic,
|
|
94
121
|
...(input.taskThreadCollaborationContract
|
|
@@ -97,8 +124,8 @@ export class ProviderTurnPreparer {
|
|
|
97
124
|
...(input.incomingMessageType !== undefined
|
|
98
125
|
? { incomingMessageType: input.incomingMessageType }
|
|
99
126
|
: {}),
|
|
100
|
-
...(input.incomingMessageType !== undefined &&
|
|
101
|
-
? { incomingContent
|
|
127
|
+
...(input.incomingMessageType !== undefined && incomingContent !== undefined
|
|
128
|
+
? { incomingContent }
|
|
102
129
|
: {}),
|
|
103
130
|
};
|
|
104
131
|
channelContext = await this.channelContextStore.prepare(prepareInput);
|
|
@@ -115,19 +142,43 @@ export class ProviderTurnPreparer {
|
|
|
115
142
|
}
|
|
116
143
|
const promptContext = toPromptContext(channelContext, input);
|
|
117
144
|
return {
|
|
145
|
+
agentName: input.agentName,
|
|
118
146
|
channelId: input.channelId,
|
|
147
|
+
incomingContent,
|
|
148
|
+
incomingParts,
|
|
119
149
|
incomingEventKind: input.incomingEventKind,
|
|
120
150
|
incomingMessageType: input.incomingMessageType,
|
|
121
|
-
prompt:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
151
|
+
prompt: input.provider === 'claude'
|
|
152
|
+
? buildClaudeTurnPrompt({
|
|
153
|
+
agentName: input.agentName,
|
|
154
|
+
channelId: input.channelId,
|
|
155
|
+
incomingAuthorId: input.incomingAuthorId,
|
|
156
|
+
incomingContent,
|
|
157
|
+
incomingEventKind: input.incomingEventKind,
|
|
158
|
+
incomingMessageType: input.incomingMessageType,
|
|
159
|
+
promptContext,
|
|
160
|
+
promptStrategy: projectionStrategy,
|
|
161
|
+
})
|
|
162
|
+
: buildPrompt({
|
|
163
|
+
agentName: input.agentName,
|
|
164
|
+
provider: input.provider,
|
|
165
|
+
channelId: input.channelId,
|
|
166
|
+
incomingAuthorId: input.incomingAuthorId,
|
|
167
|
+
incomingContent,
|
|
168
|
+
incomingEventKind: input.incomingEventKind,
|
|
169
|
+
incomingMessageType: input.incomingMessageType,
|
|
170
|
+
promptContext,
|
|
171
|
+
}),
|
|
172
|
+
...(input.provider === 'claude'
|
|
173
|
+
? {
|
|
174
|
+
claudeSessionPromptAppend: buildClaudeSessionPromptAppend({
|
|
175
|
+
agentName: input.agentName,
|
|
176
|
+
promptContext,
|
|
177
|
+
promptStrategy: projectionStrategy,
|
|
178
|
+
}),
|
|
179
|
+
projectionStrategy,
|
|
180
|
+
}
|
|
181
|
+
: {}),
|
|
131
182
|
promptContext,
|
|
132
183
|
providerSessionRouting: resolveProviderSessionRouting(input),
|
|
133
184
|
};
|
|
@@ -655,8 +655,14 @@ class LoopbackLocalhostGatewayController {
|
|
|
655
655
|
this.recordAudit('authorized', 200, decision.path, method ?? 'PUT', decision.binding);
|
|
656
656
|
}
|
|
657
657
|
async loadCurrentThreadTask(binding) {
|
|
658
|
+
// Only a task-thread binding has a current task at all. Without that context the scan below
|
|
659
|
+
// would list every visible channel's tasks to conclude what the binding already says, so the
|
|
660
|
+
// parent-channel answer is given here instead of after an O(channels x tasks) sweep.
|
|
661
|
+
if (binding.payload?.taskAssignmentContext?.active !== true) {
|
|
662
|
+
throw new GatewayHttpError(404, { error: 'not_found' }, 'not-found');
|
|
663
|
+
}
|
|
658
664
|
let task;
|
|
659
|
-
const preferredTaskId = binding.payload
|
|
665
|
+
const preferredTaskId = binding.payload.taskAssignmentContext.currentTaskId;
|
|
660
666
|
try {
|
|
661
667
|
task = await findTaskForThread(this.controlPlane, binding.channelId, preferredTaskId);
|
|
662
668
|
}
|
|
@@ -899,17 +905,21 @@ function mapGatewayControlPlaneError(error, fallbackReason) {
|
|
|
899
905
|
case 'bpp.channel_id_required':
|
|
900
906
|
case 'bpp.task_id_required':
|
|
901
907
|
return new GatewayHttpError(400, { error: 'bad_request' }, 'bad-request');
|
|
902
|
-
// An unregistered key
|
|
903
|
-
// Falling through to 502 would tell the agent the server
|
|
904
|
-
// would retry the same bad call instead of correcting it.
|
|
908
|
+
// An unregistered key, an oversized value or a status outside the enum is the
|
|
909
|
+
// caller's own mistake. Falling through to 502 would tell the agent the server
|
|
910
|
+
// is broken, and it would retry the same bad call instead of correcting it.
|
|
905
911
|
case 'bpp.task_property_key_unknown':
|
|
906
912
|
return new GatewayHttpError(400, { error: 'unknown_property_key' }, 'bad-request');
|
|
913
|
+
case 'bpp.task_property_value_invalid':
|
|
914
|
+
return new GatewayHttpError(400, { error: 'invalid_property_value' }, 'bad-request');
|
|
907
915
|
case 'bpp.task_property_value_too_long':
|
|
908
916
|
return new GatewayHttpError(400, { error: 'property_value_too_long' }, 'bad-request');
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
//
|
|
912
|
-
//
|
|
917
|
+
case 'bpp.task_invalid_status':
|
|
918
|
+
return new GatewayHttpError(400, { error: 'invalid_status' }, 'bad-request');
|
|
919
|
+
// A distinct body, not the bare `not_found` the other routes use: on a
|
|
920
|
+
// current-task property request `not_found` means the thread's own task
|
|
921
|
+
// could not be resolved, and "pass the task id" is the wrong correction
|
|
922
|
+
// for a key that simply was not set.
|
|
913
923
|
case 'bpp.task_property_not_found':
|
|
914
924
|
return new GatewayHttpError(404, { error: 'property_not_found' }, 'not-found');
|
|
915
925
|
default:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HostedMessageAttachment, HostedTurnContentPart } from './types.js';
|
|
2
|
+
type CanonicalHostedMessageAttachment = HostedMessageAttachment & {
|
|
3
|
+
kind: NonNullable<HostedMessageAttachment['kind']>;
|
|
4
|
+
};
|
|
5
|
+
export declare function normalizeHostedMessageAttachment(attachment: HostedMessageAttachment): CanonicalHostedMessageAttachment;
|
|
6
|
+
export declare function classifyHostedAttachmentKind(contentType: string | undefined): Extract<HostedTurnContentPart, {
|
|
7
|
+
type: 'image' | 'file';
|
|
8
|
+
}>['type'];
|
|
9
|
+
export declare function buildHostedTurnContentParts(input: {
|
|
10
|
+
text?: string;
|
|
11
|
+
attachments?: readonly HostedMessageAttachment[];
|
|
12
|
+
}): HostedTurnContentPart[];
|
|
13
|
+
export declare function extractHostedMessageAttachments(parts: readonly HostedTurnContentPart[]): HostedMessageAttachment[];
|
|
14
|
+
export declare function buildHostedIncomingContentText(parts: readonly HostedTurnContentPart[]): string;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export function normalizeHostedMessageAttachment(attachment) {
|
|
2
|
+
return {
|
|
3
|
+
url: attachment.url,
|
|
4
|
+
...(attachment.filename ? { filename: attachment.filename } : {}),
|
|
5
|
+
contentType: attachment.contentType,
|
|
6
|
+
kind: attachment.kind ?? classifyHostedAttachmentKind(attachment.contentType),
|
|
7
|
+
...(attachment.sizeBytes !== undefined ? { sizeBytes: attachment.sizeBytes } : {}),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function classifyHostedAttachmentKind(contentType) {
|
|
11
|
+
return contentType?.toLowerCase().startsWith('image/') ? 'image' : 'file';
|
|
12
|
+
}
|
|
13
|
+
export function buildHostedTurnContentParts(input) {
|
|
14
|
+
const text = input.text?.trim() ?? '';
|
|
15
|
+
const attachments = input.attachments ?? [];
|
|
16
|
+
const parts = [];
|
|
17
|
+
if (text.length > 0) {
|
|
18
|
+
parts.push({ type: 'text', text });
|
|
19
|
+
}
|
|
20
|
+
for (const attachment of attachments) {
|
|
21
|
+
const normalizedAttachment = normalizeHostedMessageAttachment(attachment);
|
|
22
|
+
parts.push({
|
|
23
|
+
type: normalizedAttachment.kind,
|
|
24
|
+
attachment: normalizedAttachment,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return parts;
|
|
28
|
+
}
|
|
29
|
+
export function extractHostedMessageAttachments(parts) {
|
|
30
|
+
return parts.flatMap((part) => ('attachment' in part ? [normalizeHostedMessageAttachment(part.attachment)] : []));
|
|
31
|
+
}
|
|
32
|
+
export function buildHostedIncomingContentText(parts) {
|
|
33
|
+
const text = parts
|
|
34
|
+
.flatMap((part) => (part.type === 'text' ? [part.text] : []))
|
|
35
|
+
.join('\n')
|
|
36
|
+
.trim();
|
|
37
|
+
const nonTextParts = parts.filter((part) => part.type === 'image' || part.type === 'file');
|
|
38
|
+
if (nonTextParts.length === 0) {
|
|
39
|
+
return text;
|
|
40
|
+
}
|
|
41
|
+
const summaryLines = [
|
|
42
|
+
`[Attachment metadata was received for ${nonTextParts.length} attachment${nonTextParts.length === 1 ? '' : 's'}]`,
|
|
43
|
+
...nonTextParts.map((part, index) => {
|
|
44
|
+
const filename = part.attachment.filename?.trim();
|
|
45
|
+
return `${index + 1}. ${part.type};${filename ? ` filename: ${filename};` : ''} content type: ${part.attachment.contentType}`;
|
|
46
|
+
}),
|
|
47
|
+
];
|
|
48
|
+
const summary = summaryLines.join('\n');
|
|
49
|
+
return text ? `${text}\n\n${summary}` : summary;
|
|
50
|
+
}
|
package/dist/managed-daemon.d.ts
CHANGED
|
@@ -95,6 +95,7 @@ export interface ManagedAgentsHostDaemonDeps {
|
|
|
95
95
|
materialize?: (rootPath: string, spec: LocalConfigGenerateSpec) => Promise<unknown>;
|
|
96
96
|
logger?: Pick<Console, 'log' | 'error'>;
|
|
97
97
|
logPath?: string;
|
|
98
|
+
platform?: NodeJS.Platform;
|
|
98
99
|
}
|
|
99
100
|
export interface DescribeManagedSpecOptions {
|
|
100
101
|
serverUrl: string;
|
|
@@ -192,7 +193,7 @@ export declare function applyManagedSpec(options: ApplyManagedSpecOptions, deps?
|
|
|
192
193
|
export declare class ManagedAgentsHostDaemon {
|
|
193
194
|
private readonly rootPath;
|
|
194
195
|
private readonly hostConfigPath;
|
|
195
|
-
private readonly
|
|
196
|
+
private readonly endpoint;
|
|
196
197
|
private readonly createSupervisor;
|
|
197
198
|
private readonly supervisor;
|
|
198
199
|
private readonly loadSpec;
|
|
@@ -204,7 +205,7 @@ export declare class ManagedAgentsHostDaemon {
|
|
|
204
205
|
private requestQueue;
|
|
205
206
|
private started;
|
|
206
207
|
private ready;
|
|
207
|
-
private
|
|
208
|
+
private ownsEndpoint;
|
|
208
209
|
private shutdownRequested;
|
|
209
210
|
private ownedSocketInode;
|
|
210
211
|
constructor(rootPath: string, debug?: boolean, deps?: ManagedAgentsHostDaemonDeps);
|