@borgee/agents-host 0.2.33 → 0.2.44
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 +28 -7
- package/dist/agents-host.d.ts +19 -0
- package/dist/agents-host.js +163 -44
- package/dist/chat/chat-control-plane.d.ts +9 -0
- package/dist/chat/sdk-chat-control-plane.d.ts +10 -1
- package/dist/chat/sdk-chat-control-plane.js +9 -0
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.js +5 -0
- package/dist/compatibility-gates.d.ts +1 -0
- package/dist/compatibility-gates.js +2 -0
- package/dist/config.d.ts +4 -1
- package/dist/config.js +21 -3
- package/dist/context/injection.d.ts +5 -3
- package/dist/context/injection.js +45 -29
- package/dist/context/main-session-delegation.d.ts +1 -0
- package/dist/context/main-session-delegation.js +6 -0
- package/dist/context/prompt.js +25 -35
- package/dist/context/skill-manual.d.ts +13 -0
- package/dist/context/skill-manual.js +18 -0
- package/dist/context/turn-preparation.js +13 -4
- package/dist/gateway/localhost-gateway.js +75 -1
- package/dist/hosted-turn-content.d.ts +15 -0
- package/dist/hosted-turn-content.js +50 -0
- package/dist/local-config.js +10 -1
- package/dist/managed-daemon.d.ts +3 -2
- package/dist/managed-daemon.js +82 -29
- package/dist/plugin-sdk.js +58 -1
- package/dist/plugin-sdk.js.map +2 -2
- package/dist/policy/gateway-authorization.d.ts +18 -3
- package/dist/policy/gateway-authorization.js +33 -1
- package/dist/providers/claude/adapter.d.ts +3 -1
- package/dist/providers/claude/adapter.js +13 -1
- package/dist/providers/claude/cli-client.d.ts +36 -3
- package/dist/providers/claude/cli-client.js +225 -37
- package/dist/providers/codex/adapter.d.ts +3 -1
- package/dist/providers/codex/adapter.js +13 -1
- package/dist/providers/codex/cli-client.d.ts +35 -3
- package/dist/providers/codex/cli-client.js +212 -31
- package/dist/providers/codex/project-doc.js +16 -29
- package/dist/providers/copilot/adapter.d.ts +3 -1
- package/dist/providers/copilot/adapter.js +13 -1
- package/dist/providers/copilot/cli-client.d.ts +34 -2
- package/dist/providers/copilot/cli-client.js +196 -18
- package/dist/providers/create-provider.d.ts +1 -1
- package/dist/providers/create-provider.js +30 -14
- package/dist/providers/idle-backend-shutdown.d.ts +16 -0
- package/dist/providers/idle-backend-shutdown.js +53 -0
- package/dist/providers/provider-adapter.d.ts +35 -0
- package/dist/providers/provider-adapter.js +44 -1
- package/dist/state-paths.d.ts +9 -1
- package/dist/state-paths.js +22 -3
- package/dist/types.d.ts +40 -2
- package/package.json +2 -2
- package/skills/borgee-agent/SKILL.md +133 -35
- package/skills/borgee-agent/references/errors.md +38 -0
- package/skills/borgee-agent/references/task-properties.md +30 -0
- package/skills/borgee-agent/scripts/borgee-agent.mjs +553 -0
- package/skills/borgee-agent/scripts/borgee-agent.py +547 -0
- package/skills/borgee-agent/borgee-agent.mjs +0 -507
- package/skills/borgee-agent/borgee-agent.py +0 -438
|
@@ -8,6 +8,21 @@ export interface GatewayTaskRoute {
|
|
|
8
8
|
taskId: string;
|
|
9
9
|
resource: 'task' | 'task-history';
|
|
10
10
|
}
|
|
11
|
+
/** One task property, addressed by key. PUT writes it, DELETE removes it. */
|
|
12
|
+
export interface GatewayTaskPropertyRoute {
|
|
13
|
+
taskId: string;
|
|
14
|
+
key: string;
|
|
15
|
+
resource: 'task-property';
|
|
16
|
+
}
|
|
17
|
+
/** The same, on the thread's own task, so an agent need not resolve a task id. */
|
|
18
|
+
export interface GatewayCurrentTaskPropertyRoute {
|
|
19
|
+
channelId: string;
|
|
20
|
+
key: string;
|
|
21
|
+
resource: 'current-task-property';
|
|
22
|
+
}
|
|
23
|
+
export type GatewayRoute = GatewayChannelRoute | GatewayTaskRoute | GatewayTaskPropertyRoute | GatewayCurrentTaskPropertyRoute | {
|
|
24
|
+
resource: 'health';
|
|
25
|
+
};
|
|
11
26
|
export interface GatewayAuthorizationBinding {
|
|
12
27
|
channelId: string;
|
|
13
28
|
agentId?: string;
|
|
@@ -23,9 +38,7 @@ export interface GatewayAuthorizationDecision {
|
|
|
23
38
|
};
|
|
24
39
|
allowHeader?: string;
|
|
25
40
|
binding?: GatewayAuthorizationBinding;
|
|
26
|
-
route?:
|
|
27
|
-
resource: 'health';
|
|
28
|
-
};
|
|
41
|
+
route?: GatewayRoute;
|
|
29
42
|
path: string;
|
|
30
43
|
token?: string;
|
|
31
44
|
}
|
|
@@ -39,4 +52,6 @@ export declare function hasVisibleHeader(value: string | string[] | undefined):
|
|
|
39
52
|
export declare function parseBearerToken(value: string | string[] | undefined): string | null;
|
|
40
53
|
export declare function matchChannelRoute(pathname: string, allowCollaborationRoutes?: boolean): GatewayChannelRoute | null;
|
|
41
54
|
export declare function matchTaskRoute(pathname: string): GatewayTaskRoute | null;
|
|
55
|
+
export declare function matchTaskPropertyRoute(pathname: string): GatewayTaskPropertyRoute | null;
|
|
56
|
+
export declare function matchCurrentTaskPropertyRoute(pathname: string): GatewayCurrentTaskPropertyRoute | null;
|
|
42
57
|
export declare function evaluateGatewayAuthorization(input: GatewayAuthorizationInput): GatewayAuthorizationDecision;
|
|
@@ -61,6 +61,30 @@ export function matchTaskRoute(pathname) {
|
|
|
61
61
|
resource: match[2] ? 'task-history' : 'task',
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
export function matchTaskPropertyRoute(pathname) {
|
|
65
|
+
const match = /^\/v1\/tasks\/([^/]+)\/properties\/([^/]+)$/.exec(pathname);
|
|
66
|
+
if (!match) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const taskId = decodePathSegment(match[1]);
|
|
70
|
+
const key = decodePathSegment(match[2]);
|
|
71
|
+
if (taskId == null || key == null) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return { taskId, key, resource: 'task-property' };
|
|
75
|
+
}
|
|
76
|
+
export function matchCurrentTaskPropertyRoute(pathname) {
|
|
77
|
+
const match = /^\/v1\/channels\/([^/]+)\/current-task\/properties\/([^/]+)$/.exec(pathname);
|
|
78
|
+
if (!match) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const channelId = decodePathSegment(match[1]);
|
|
82
|
+
const key = decodePathSegment(match[2]);
|
|
83
|
+
if (channelId == null || key == null) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return { channelId, key, resource: 'current-task-property' };
|
|
87
|
+
}
|
|
64
88
|
function allowedMethodsForRoute(route, collaborationRoutesEnabled) {
|
|
65
89
|
switch (route.resource) {
|
|
66
90
|
case 'health':
|
|
@@ -78,6 +102,11 @@ function allowedMethodsForRoute(route, collaborationRoutesEnabled) {
|
|
|
78
102
|
case 'current-task':
|
|
79
103
|
case 'task':
|
|
80
104
|
return ['GET', 'PATCH'];
|
|
105
|
+
// No GET: a property is read back with the task it belongs to, so a
|
|
106
|
+
// per-key read would be a second way to learn the same thing.
|
|
107
|
+
case 'current-task-property':
|
|
108
|
+
case 'task-property':
|
|
109
|
+
return ['PUT', 'DELETE'];
|
|
81
110
|
}
|
|
82
111
|
}
|
|
83
112
|
export function evaluateGatewayAuthorization(input) {
|
|
@@ -96,7 +125,10 @@ export function evaluateGatewayAuthorization(input) {
|
|
|
96
125
|
const collaborationRoutesEnabled = input.allowCollaborationRoutes ?? false;
|
|
97
126
|
const route = url.pathname === '/health'
|
|
98
127
|
? { resource: 'health' }
|
|
99
|
-
: matchChannelRoute(url.pathname, collaborationRoutesEnabled)
|
|
128
|
+
: matchChannelRoute(url.pathname, collaborationRoutesEnabled)
|
|
129
|
+
?? matchCurrentTaskPropertyRoute(url.pathname)
|
|
130
|
+
?? matchTaskPropertyRoute(url.pathname)
|
|
131
|
+
?? matchTaskRoute(url.pathname);
|
|
100
132
|
if (hiddenCollaborationRoute) {
|
|
101
133
|
return {
|
|
102
134
|
reason: 'not-found',
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ProviderAdapter } from '../provider-adapter.js';
|
|
2
2
|
import type { ProviderGenerateOptions, ProviderInput, ProviderReply } from '../../types.js';
|
|
3
3
|
import { ProviderTurnPreparer } from '../../context/turn-preparation.js';
|
|
4
4
|
import { ClaudeCliClient } from './cli-client.js';
|
|
5
|
+
export declare const CLAUDE_HOSTED_PROVIDER_CAPABILITIES: import("../provider-adapter.js").ProviderCapabilities;
|
|
5
6
|
export declare class ClaudeProviderAdapter implements ProviderAdapter {
|
|
6
7
|
private readonly cli;
|
|
7
8
|
private readonly turnPreparer;
|
|
9
|
+
readonly capabilities: import("../provider-adapter.js").ProviderCapabilities;
|
|
8
10
|
constructor(cli: ClaudeCliClient, turnPreparer: ProviderTurnPreparer);
|
|
9
11
|
generateReply(input: ProviderInput, options?: ProviderGenerateOptions): Promise<ProviderReply>;
|
|
10
12
|
dispose(): Promise<void>;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
import { createHostedProviderCapabilities } from '../provider-adapter.js';
|
|
1
2
|
import { createAwaitingUserProgressHandler, parseProviderReply } from '../awaiting-user.js';
|
|
3
|
+
export const CLAUDE_HOSTED_PROVIDER_CAPABILITIES = createHostedProviderCapabilities({
|
|
4
|
+
imageInputTransport: {
|
|
5
|
+
source: 'transport-derived',
|
|
6
|
+
support: 'supported',
|
|
7
|
+
reason: 'real-media-delivered',
|
|
8
|
+
delivery: ['blob'],
|
|
9
|
+
},
|
|
10
|
+
});
|
|
2
11
|
export class ClaudeProviderAdapter {
|
|
3
12
|
cli;
|
|
4
13
|
turnPreparer;
|
|
14
|
+
capabilities = CLAUDE_HOSTED_PROVIDER_CAPABILITIES;
|
|
5
15
|
constructor(cli, turnPreparer) {
|
|
6
16
|
this.cli = cli;
|
|
7
17
|
this.turnPreparer = turnPreparer;
|
|
@@ -11,7 +21,9 @@ export class ClaudeProviderAdapter {
|
|
|
11
21
|
const text = await this.cli.generateReply(preparedTurn, {
|
|
12
22
|
onProgress: createAwaitingUserProgressHandler(options?.onProgress),
|
|
13
23
|
});
|
|
14
|
-
|
|
24
|
+
// Read the session AFTER the turn: a first turn on a channel opens the
|
|
25
|
+
// session as it runs, so before this point there is nothing to report.
|
|
26
|
+
return { ...parseProviderReply(text), sessionId: this.cli.sessionIdForChannel(input.channelId) };
|
|
15
27
|
}
|
|
16
28
|
async dispose() {
|
|
17
29
|
await this.cli.dispose();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import spawn from 'cross-spawn';
|
|
2
2
|
import { PROTOCOL_VERSION, client, methods, ndJsonStream } from '@agentclientprotocol/sdk';
|
|
3
3
|
import { type DebugLogger } from '../../debug.js';
|
|
4
|
-
import type { PreparedProviderTurnInput, ProviderGenerateOptions } from '../../types.js';
|
|
4
|
+
import type { PreparedPromptContext, PreparedProviderTurnInput, ProviderGenerateOptions } from '../../types.js';
|
|
5
5
|
import type { ClaudeChannelSessionStore } from './session-store.js';
|
|
6
6
|
interface ClaudeAcpRuntime {
|
|
7
7
|
spawn: typeof spawn;
|
|
@@ -9,10 +9,18 @@ interface ClaudeAcpRuntime {
|
|
|
9
9
|
ndJsonStream: typeof ndJsonStream;
|
|
10
10
|
methods: typeof methods;
|
|
11
11
|
protocolVersion: typeof PROTOCOL_VERSION;
|
|
12
|
+
fetch: typeof fetch;
|
|
12
13
|
cwd: string;
|
|
14
|
+
idleBackendShutdownMs: number;
|
|
15
|
+
idleShutdownGracePeriodMs: number;
|
|
13
16
|
shutdownGracePeriodMs: number;
|
|
14
17
|
shutdownForceKillWaitMs: number;
|
|
15
18
|
}
|
|
19
|
+
interface ClaudeHostedImageInputConfig {
|
|
20
|
+
borgeeBaseUrl?: string;
|
|
21
|
+
agentApiKey?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function buildClaudeSessionSystemPrompt(promptContext?: PreparedPromptContext): string | undefined;
|
|
16
24
|
/**
|
|
17
25
|
* Persistent ACP-backed client for the Claude ACP adapter.
|
|
18
26
|
*
|
|
@@ -27,8 +35,15 @@ export declare class ClaudeCliClient {
|
|
|
27
35
|
private readonly sessionStore?;
|
|
28
36
|
private readonly resolveSessionStoreAgentId;
|
|
29
37
|
private readonly logger;
|
|
38
|
+
private readonly imageInputConfig;
|
|
30
39
|
private readonly runtime;
|
|
31
40
|
private readonly channels;
|
|
41
|
+
/**
|
|
42
|
+
* The provider session currently bound to channelId, or undefined before a
|
|
43
|
+
* turn has opened one. Surfaced so agents-host can record which session
|
|
44
|
+
* worked a task without the agent being asked to report its own id.
|
|
45
|
+
*/
|
|
46
|
+
sessionIdForChannel(channelId: string): string | undefined;
|
|
32
47
|
private readonly persistedSessions;
|
|
33
48
|
private readonly closingSessions;
|
|
34
49
|
private readonly pendingSessionStarts;
|
|
@@ -41,7 +56,13 @@ export declare class ClaudeCliClient {
|
|
|
41
56
|
private startPromise?;
|
|
42
57
|
private shutdownPromise?;
|
|
43
58
|
private childExitPromise?;
|
|
44
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Bumped on every spawn so the `exit` / `connection.closed` handlers of a
|
|
61
|
+
* backend we deliberately recycled stay silent instead of latching a fatal
|
|
62
|
+
* error onto the client that already owns its successor.
|
|
63
|
+
*/
|
|
64
|
+
private backendGeneration;
|
|
65
|
+
private idleShutdownPromise?;
|
|
45
66
|
private fatalError;
|
|
46
67
|
private disposing;
|
|
47
68
|
private backendClosed;
|
|
@@ -49,8 +70,9 @@ export declare class ClaudeCliClient {
|
|
|
49
70
|
private sessionStoreLoadPromise;
|
|
50
71
|
private sessionStoreWriteQueue;
|
|
51
72
|
private sessionCapabilities;
|
|
73
|
+
private readonly idleBackendShutdown;
|
|
52
74
|
private childStderr;
|
|
53
|
-
constructor(command: string, args?: string[], runtimeOverrides?: Partial<ClaudeAcpRuntime>, sessionStore?: ClaudeChannelSessionStore | undefined, resolveSessionStoreAgentId?: () => string | undefined, logger?: DebugLogger);
|
|
75
|
+
constructor(command: string, args?: string[], runtimeOverrides?: Partial<ClaudeAcpRuntime>, sessionStore?: ClaudeChannelSessionStore | undefined, resolveSessionStoreAgentId?: () => string | undefined, logger?: DebugLogger, imageInputConfig?: ClaudeHostedImageInputConfig);
|
|
54
76
|
generateReply(turn: PreparedProviderTurnInput, options?: ProviderGenerateOptions): Promise<string>;
|
|
55
77
|
generateReply(channelId: string, prompt: string, options?: ProviderGenerateOptions): Promise<string>;
|
|
56
78
|
dispose(): Promise<void>;
|
|
@@ -83,8 +105,19 @@ export declare class ClaudeCliClient {
|
|
|
83
105
|
private enqueueSessionStoreWrite;
|
|
84
106
|
private trackSessionStoreOperation;
|
|
85
107
|
private shutdownBackend;
|
|
108
|
+
/**
|
|
109
|
+
* Backend teardown without the fatal latch: the client stays usable and
|
|
110
|
+
* `ensureStarted()` spawns a replacement process on the next turn. Only safe
|
|
111
|
+
* while `isBackendIdle()` holds, because every channel's live ACP session is
|
|
112
|
+
* dropped here and no turn is ever replayed onto its successor.
|
|
113
|
+
*/
|
|
114
|
+
private shutdownIdleBackend;
|
|
115
|
+
private isBackendIdle;
|
|
116
|
+
private closeBackendProcess;
|
|
86
117
|
private waitForPendingSessionStarts;
|
|
87
118
|
private waitForPendingSessionCloses;
|
|
88
119
|
private waitForChildExit;
|
|
120
|
+
private buildPromptInput;
|
|
121
|
+
private fetchImageBlock;
|
|
89
122
|
}
|
|
90
123
|
export {};
|