@borgee/agents-host 0.2.2 → 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.
Files changed (84) hide show
  1. package/README.md +184 -21
  2. package/dist/agents-host-supervisor.d.ts +7 -5
  3. package/dist/agents-host-supervisor.js +24 -4
  4. package/dist/agents-host.d.ts +114 -15
  5. package/dist/agents-host.js +2712 -141
  6. package/dist/chat/chat-control-plane.d.ts +13 -2
  7. package/dist/chat/sdk-chat-control-plane.d.ts +14 -3
  8. package/dist/chat/sdk-chat-control-plane.js +54 -2
  9. package/dist/cli-args.d.ts +46 -5
  10. package/dist/cli-args.js +313 -32
  11. package/dist/cli.d.ts +9 -0
  12. package/dist/cli.js +112 -5
  13. package/dist/compatibility-gates.d.ts +39 -0
  14. package/dist/compatibility-gates.js +131 -0
  15. package/dist/config.d.ts +1 -0
  16. package/dist/config.js +23 -5
  17. package/dist/connections-state-store.d.ts +81 -0
  18. package/dist/connections-state-store.js +228 -0
  19. package/dist/context/attention.d.ts +12 -0
  20. package/dist/context/attention.js +137 -0
  21. package/dist/context/collaboration-capabilities-diagnostics.d.ts +3 -0
  22. package/dist/context/collaboration-capabilities-diagnostics.js +18 -0
  23. package/dist/context/collaboration-outcome.d.ts +2 -0
  24. package/dist/context/collaboration-outcome.js +26 -0
  25. package/dist/context/injection.d.ts +134 -0
  26. package/dist/context/injection.js +355 -0
  27. package/dist/context/prompt.d.ts +4 -1
  28. package/dist/context/prompt.js +231 -1
  29. package/dist/context/task-thread-collaboration.d.ts +6 -0
  30. package/dist/context/task-thread-collaboration.js +31 -0
  31. package/dist/context/turn-preparation.d.ts +9 -0
  32. package/dist/context/turn-preparation.js +135 -0
  33. package/dist/debug.d.ts +44 -0
  34. package/dist/debug.js +135 -0
  35. package/dist/gateway/localhost-gateway.d.ts +52 -0
  36. package/dist/gateway/localhost-gateway.js +857 -0
  37. package/dist/index.js +7 -5
  38. package/dist/local-config.d.ts +4 -1
  39. package/dist/local-config.js +24 -7
  40. package/dist/managed-daemon-log.d.ts +34 -0
  41. package/dist/managed-daemon-log.js +261 -0
  42. package/dist/managed-daemon.d.ts +220 -0
  43. package/dist/managed-daemon.js +1601 -0
  44. package/dist/policy/authorization-audit.d.ts +63 -0
  45. package/dist/policy/authorization-audit.js +94 -0
  46. package/dist/policy/copilot-permission.d.ts +15 -0
  47. package/dist/policy/copilot-permission.js +193 -0
  48. package/dist/policy/gateway-authorization.d.ts +42 -0
  49. package/dist/policy/gateway-authorization.js +162 -0
  50. package/dist/providers/awaiting-user.d.ts +12 -0
  51. package/dist/providers/awaiting-user.js +192 -0
  52. package/dist/providers/claude/adapter.d.ts +3 -1
  53. package/dist/providers/claude/adapter.js +8 -12
  54. package/dist/providers/claude/cli-client.d.ts +12 -5
  55. package/dist/providers/claude/cli-client.js +184 -37
  56. package/dist/providers/claude/session-store.d.ts +1 -0
  57. package/dist/providers/codex/adapter.d.ts +11 -0
  58. package/dist/providers/codex/adapter.js +19 -0
  59. package/dist/providers/codex/cli-client.d.ts +103 -0
  60. package/dist/providers/codex/cli-client.js +1133 -0
  61. package/dist/providers/codex/project-doc.d.ts +3 -0
  62. package/dist/providers/codex/project-doc.js +90 -0
  63. package/dist/providers/codex/session-store.d.ts +38 -0
  64. package/dist/providers/codex/session-store.js +150 -0
  65. package/dist/providers/copilot/adapter.d.ts +3 -1
  66. package/dist/providers/copilot/adapter.js +8 -12
  67. package/dist/providers/copilot/cli-client.d.ts +20 -2
  68. package/dist/providers/copilot/cli-client.js +251 -71
  69. package/dist/providers/copilot/session-store.d.ts +1 -0
  70. package/dist/providers/create-provider.d.ts +11 -2
  71. package/dist/providers/create-provider.js +131 -12
  72. package/dist/run.d.ts +1 -0
  73. package/dist/run.js +5 -2
  74. package/dist/state-paths.d.ts +14 -1
  75. package/dist/state-paths.js +87 -3
  76. package/dist/task-thread-resolution.d.ts +10 -0
  77. package/dist/task-thread-resolution.js +48 -0
  78. package/dist/types.d.ts +267 -1
  79. package/dist/visible-mentions.d.ts +3 -0
  80. package/dist/visible-mentions.js +15 -0
  81. package/package.json +19 -17
  82. package/skills/borgee-agent/SKILL.md +33 -0
  83. package/skills/borgee-agent/borgee-agent.mjs +473 -0
  84. package/skills/borgee-agent/borgee-agent.py +409 -0
@@ -0,0 +1,192 @@
1
+ export const HOST_CONTROL_PREFIX = '[[BORGEE_CONTROL]] ';
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
+ }
15
+ function hasVisibleText(value) {
16
+ return value.trim().length > 0;
17
+ }
18
+ function stripTrailingCarriageReturn(value) {
19
+ return value.endsWith('\r') ? value.slice(0, -1) : value;
20
+ }
21
+ function matchControlLine(sourceText, trimTrailingWhitespace) {
22
+ const analyzedText = trimTrailingWhitespace
23
+ ? sourceText.replace(/[ \t\r\n]+$/u, '')
24
+ : sourceText;
25
+ const lastNewline = analyzedText.lastIndexOf('\n');
26
+ const lineStart = lastNewline === -1 ? 0 : lastNewline + 1;
27
+ const line = stripTrailingCarriageReturn(analyzedText.slice(lineStart));
28
+ const removalStart = lastNewline === -1 ? 0 : lastNewline;
29
+ if (line.startsWith(HOST_CONTROL_PREFIX)) {
30
+ return {
31
+ kind: 'footer',
32
+ analyzedText,
33
+ removalStart,
34
+ payload: line.slice(HOST_CONTROL_PREFIX.length),
35
+ };
36
+ }
37
+ if (line.length > 0 && HOST_CONTROL_PREFIX.startsWith(line)) {
38
+ return {
39
+ kind: 'plausible-prefix',
40
+ analyzedText,
41
+ removalStart,
42
+ };
43
+ }
44
+ return {
45
+ kind: 'none',
46
+ analyzedText,
47
+ removalStart,
48
+ };
49
+ }
50
+ function parseControlPayload(payload) {
51
+ let parsed;
52
+ try {
53
+ parsed = JSON.parse(payload);
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
59
+ return null;
60
+ }
61
+ const record = parsed;
62
+ if (typeof record.kind !== 'string') {
63
+ return null;
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
+ }
74
+ if (record.kind === 'continue-to-peer' || record.kind === 'conclude-locally') {
75
+ return Object.keys(record).every((key) => key === 'kind' || key === 'attentionUpdate')
76
+ ? {
77
+ kind: record.kind,
78
+ ...(attentionUpdate ? { attentionUpdate } : {}),
79
+ }
80
+ : null;
81
+ }
82
+ if (record.kind === 'start-protocol') {
83
+ return attentionUpdate === undefined
84
+ && Object.keys(record).length === 2
85
+ && typeof record.rounds === 'number'
86
+ && Number.isInteger(record.rounds)
87
+ && record.rounds > 0
88
+ ? {
89
+ kind: 'start-protocol',
90
+ rounds: record.rounds,
91
+ }
92
+ : null;
93
+ }
94
+ if (record.kind === 'awaiting-user') {
95
+ const keys = Object.keys(record);
96
+ if (keys.some((key) => key !== 'kind' && key !== 'question' && key !== 'reason' && key !== 'attentionUpdate')) {
97
+ return null;
98
+ }
99
+ if (typeof record.question !== 'string' || record.question.trim().length === 0) {
100
+ return null;
101
+ }
102
+ if (record.reason !== undefined
103
+ && (typeof record.reason !== 'string' || record.reason.trim().length === 0)) {
104
+ return null;
105
+ }
106
+ return {
107
+ kind: 'awaiting-user',
108
+ question: record.question.trim(),
109
+ ...(typeof record.reason === 'string' ? { reason: record.reason.trim() } : {}),
110
+ ...(attentionUpdate ? { attentionUpdate } : {}),
111
+ };
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
+ }
121
+ return null;
122
+ }
123
+ export function parseProviderReply(text) {
124
+ const match = matchControlLine(text, true);
125
+ if (match.kind !== 'footer' || match.payload === undefined) {
126
+ return { text };
127
+ }
128
+ const control = parseControlPayload(match.payload);
129
+ if (!control) {
130
+ return {
131
+ text: stripTrailingCarriageReturn(match.analyzedText.slice(0, match.removalStart)),
132
+ controlMalformed: true,
133
+ };
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
+ }
142
+ return {
143
+ text: textWithoutFooter,
144
+ control,
145
+ ...(control.kind === 'awaiting-user'
146
+ ? {
147
+ awaitingUser: {
148
+ question: control.question,
149
+ ...(control.reason ? { reason: control.reason } : {}),
150
+ },
151
+ }
152
+ : {}),
153
+ };
154
+ }
155
+ export function sanitizeAwaitingUserProgressText(text) {
156
+ const match = matchControlLine(text, true);
157
+ if (match.kind !== 'none') {
158
+ return stripTrailingCarriageReturn(match.analyzedText.slice(0, match.removalStart));
159
+ }
160
+ const rawMatch = matchControlLine(text, false);
161
+ if (rawMatch.kind === 'none') {
162
+ return text;
163
+ }
164
+ return stripTrailingCarriageReturn(rawMatch.analyzedText.slice(0, rawMatch.removalStart));
165
+ }
166
+ export class AwaitingUserProgressSanitizer {
167
+ onProgress;
168
+ lastPublished = null;
169
+ constructor(onProgress) {
170
+ this.onProgress = onProgress;
171
+ }
172
+ publish(text) {
173
+ if (!this.onProgress) {
174
+ return;
175
+ }
176
+ const sanitizedText = sanitizeAwaitingUserProgressText(text);
177
+ if (!hasVisibleText(sanitizedText) || sanitizedText === this.lastPublished) {
178
+ return;
179
+ }
180
+ this.lastPublished = sanitizedText;
181
+ this.onProgress({ text: sanitizedText });
182
+ }
183
+ }
184
+ export function createAwaitingUserProgressHandler(onProgress) {
185
+ if (!onProgress) {
186
+ return undefined;
187
+ }
188
+ const sanitizer = new AwaitingUserProgressSanitizer(onProgress);
189
+ return (update) => {
190
+ sanitizer.publish(update.text);
191
+ };
192
+ }
@@ -1,9 +1,11 @@
1
1
  import type { ProviderAdapter } from '../provider-adapter.js';
2
2
  import type { ProviderGenerateOptions, ProviderInput, ProviderReply } from '../../types.js';
3
+ import { ProviderTurnPreparer } from '../../context/turn-preparation.js';
3
4
  import { ClaudeCliClient } from './cli-client.js';
4
5
  export declare class ClaudeProviderAdapter implements ProviderAdapter {
5
6
  private readonly cli;
6
- constructor(cli: ClaudeCliClient);
7
+ private readonly turnPreparer;
8
+ constructor(cli: ClaudeCliClient, turnPreparer: ProviderTurnPreparer);
7
9
  generateReply(input: ProviderInput, options?: ProviderGenerateOptions): Promise<ProviderReply>;
8
10
  dispose(): Promise<void>;
9
11
  }
@@ -1,21 +1,17 @@
1
- import { buildPrompt } from '../../context/prompt.js';
1
+ import { createAwaitingUserProgressHandler, parseProviderReply } from '../awaiting-user.js';
2
2
  export class ClaudeProviderAdapter {
3
3
  cli;
4
- constructor(cli) {
4
+ turnPreparer;
5
+ constructor(cli, turnPreparer) {
5
6
  this.cli = cli;
7
+ this.turnPreparer = turnPreparer;
6
8
  }
7
9
  async generateReply(input, options) {
8
- const prompt = buildPrompt({
9
- agentName: input.agentName,
10
- provider: input.provider,
11
- channelId: input.channelId,
12
- incomingAuthorId: input.incomingAuthorId,
13
- incomingContent: input.incomingContent,
10
+ const preparedTurn = await this.turnPreparer.prepare(input);
11
+ const text = await this.cli.generateReply(preparedTurn, {
12
+ onProgress: createAwaitingUserProgressHandler(options?.onProgress),
14
13
  });
15
- const text = await this.cli.generateReply(input.channelId, prompt, {
16
- onProgress: options?.onProgress,
17
- });
18
- return { text };
14
+ return parseProviderReply(text);
19
15
  }
20
16
  async dispose() {
21
17
  await this.cli.dispose();
@@ -1,22 +1,26 @@
1
1
  import spawn from 'cross-spawn';
2
- import type { ProviderGenerateOptions } from '../../types.js';
2
+ import { type DebugLogger } from '../../debug.js';
3
+ import type { PreparedProviderTurnInput, ProviderGenerateOptions } from '../../types.js';
3
4
  import type { ClaudeChannelSessionStore } from './session-store.js';
4
5
  interface ClaudeCliRuntime {
5
6
  spawn: typeof spawn;
7
+ cwd: string;
6
8
  }
7
9
  /**
8
10
  * CLI client for the Claude Code CLI (`claude`) non-interactive mode, with
9
- * native per-channel session continuity.
11
+ * native provider-session continuity.
10
12
  *
11
13
  * Claude session memory remains entirely inside the Claude CLI. This client
12
- * only pins one native session id per Borgee channel and serializes turns per
13
- * channel so `--resume` is never called concurrently for the same session.
14
+ * only pins one native session id per routed provider session and serializes
15
+ * turns per route so `--resume` is never called concurrently for the same
16
+ * native session.
14
17
  */
15
18
  export declare class ClaudeCliClient {
16
19
  private readonly command;
17
20
  private readonly args;
18
21
  private readonly sessionStore?;
19
22
  private readonly resolveSessionStoreAgentId;
23
+ private readonly logger;
20
24
  private readonly runtime;
21
25
  private readonly channels;
22
26
  private readonly persistedSessions;
@@ -24,7 +28,8 @@ export declare class ClaudeCliClient {
24
28
  private stopped;
25
29
  private sessionStoreLoadPromise;
26
30
  private sessionStoreWriteQueue;
27
- constructor(command: string, args: string[], runtimeOverrides?: Partial<ClaudeCliRuntime>, sessionStore?: ClaudeChannelSessionStore | undefined, resolveSessionStoreAgentId?: () => string | undefined);
31
+ constructor(command: string, args: string[], runtimeOverrides?: Partial<ClaudeCliRuntime>, sessionStore?: ClaudeChannelSessionStore | undefined, resolveSessionStoreAgentId?: () => string | undefined, logger?: DebugLogger);
32
+ generateReply(turn: PreparedProviderTurnInput, options?: ProviderGenerateOptions): Promise<string>;
28
33
  generateReply(channelId: string, prompt: string, options?: ProviderGenerateOptions): Promise<string>;
29
34
  dispose(): Promise<void>;
30
35
  private getOrCreateChannelState;
@@ -37,6 +42,8 @@ export declare class ClaudeCliClient {
37
42
  private persistSession;
38
43
  private persistSessionBestEffort;
39
44
  private resetPersistedSession;
45
+ private resolveTurnCwd;
46
+ private resetSessionIfCwdChanged;
40
47
  private resetPersistedSessionBestEffort;
41
48
  private enqueueSessionStoreWrite;
42
49
  private run;