@borgee/agents-host 0.2.97 → 0.2.101
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 +8 -0
- package/dist/agents-host.js +258 -64
- package/dist/chat/chat-control-plane.d.ts +13 -3
- package/dist/chat/sdk-chat-control-plane.d.ts +30 -5
- package/dist/chat/sdk-chat-control-plane.js +131 -3
- package/dist/context/skill-manual.js +1 -1
- package/dist/execution-telemetry.d.ts +96 -0
- package/dist/execution-telemetry.js +583 -0
- package/dist/gateway/channel-file-workspace.d.ts +15 -0
- package/dist/gateway/channel-file-workspace.js +130 -0
- package/dist/gateway/localhost-gateway.js +140 -0
- package/dist/plugin-sdk.js +72 -3
- package/dist/plugin-sdk.js.map +2 -2
- package/dist/policy/gateway-authorization.d.ts +1 -1
- package/dist/policy/gateway-authorization.js +22 -2
- package/dist/providers/claude/adapter.js +1 -0
- package/dist/providers/claude/cli-client.js +4 -0
- package/dist/providers/codex/adapter.js +1 -0
- package/dist/providers/codex/cli-client.js +5 -0
- package/dist/providers/copilot/adapter.js +4 -0
- package/dist/providers/copilot/cli-client.js +11 -1
- package/dist/providers/copilot/sdk-session.d.ts +12 -3
- package/dist/providers/copilot/sdk-session.js +222 -5
- package/dist/providers/create-provider.js +4 -0
- package/dist/providers/prompt-usage.d.ts +8 -0
- package/dist/providers/prompt-usage.js +52 -0
- package/dist/state-paths.d.ts +2 -0
- package/dist/state-paths.js +6 -0
- package/dist/types.d.ts +41 -0
- package/dist/typing-lease.d.ts +14 -0
- package/dist/typing-lease.js +31 -0
- package/package.json +2 -2
- package/skills/borgee-agent/SKILL.md +12 -4
- package/skills/borgee-agent/scripts/borgee-agent.mjs +89 -0
- package/skills/borgee-agent/scripts/borgee-agent.py +90 -0
package/dist/agents-host.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChatControlPlane } from './chat/chat-control-plane.js';
|
|
2
2
|
import { type AgentsHostRuntimeOptions } from './debug.js';
|
|
3
|
+
import { ExecutionDeliveryJournal } from './execution-telemetry.js';
|
|
3
4
|
import { type ProviderAdapter } from './providers/provider-adapter.js';
|
|
4
5
|
import type { AgentsHostConfig } from './types.js';
|
|
5
6
|
/**
|
|
@@ -13,6 +14,7 @@ export declare class AgentsHost {
|
|
|
13
14
|
private readonly borgee;
|
|
14
15
|
private readonly backgroundRuns;
|
|
15
16
|
private readonly logger;
|
|
17
|
+
private readonly executionDeliveryJournal;
|
|
16
18
|
private readonly contextInjectionEnabled;
|
|
17
19
|
private readonly collaborationEnabled;
|
|
18
20
|
private readonly collaborationOutcomeModelEnabled;
|
|
@@ -20,6 +22,8 @@ export declare class AgentsHost {
|
|
|
20
22
|
private readonly taskThreadCollaborationContractEnabled;
|
|
21
23
|
private readonly collaborationCapabilitiesDiagnosticsEnabled;
|
|
22
24
|
private readonly activeTurns;
|
|
25
|
+
private readonly executionTelemetryByExecutionId;
|
|
26
|
+
private readonly executionDispatches;
|
|
23
27
|
private readonly awaitingUserByChannel;
|
|
24
28
|
private readonly collaborationOutcomeByChannel;
|
|
25
29
|
/**
|
|
@@ -49,6 +53,7 @@ export declare class AgentsHost {
|
|
|
49
53
|
private controlPlaneClosed;
|
|
50
54
|
constructor(config: AgentsHostConfig, deps?: {
|
|
51
55
|
borgee?: ChatControlPlane;
|
|
56
|
+
executionDeliveryJournal?: ExecutionDeliveryJournal;
|
|
52
57
|
provider?: ProviderAdapter;
|
|
53
58
|
runtimeOptions?: AgentsHostRuntimeOptions;
|
|
54
59
|
});
|
|
@@ -56,6 +61,9 @@ export declare class AgentsHost {
|
|
|
56
61
|
stop(): Promise<void>;
|
|
57
62
|
private trackActiveTurn;
|
|
58
63
|
private dispatchMessage;
|
|
64
|
+
private runClaimedExecution;
|
|
65
|
+
private runMessageWithExecutionTelemetry;
|
|
66
|
+
private createExecutionTelemetryReporter;
|
|
59
67
|
private dispatchAutonomousReply;
|
|
60
68
|
private handleLegacyMessage;
|
|
61
69
|
private handleCollaborationMessage;
|
package/dist/agents-host.js
CHANGED
|
@@ -5,6 +5,8 @@ import { SdkChatControlPlane } from './chat/sdk-chat-control-plane.js';
|
|
|
5
5
|
import { HostLogger, summarizeError } from './debug.js';
|
|
6
6
|
import { toReportedActivity } from './progress-to-activity.js';
|
|
7
7
|
import { BackgroundRunTracker } from './background-runs.js';
|
|
8
|
+
import { ExecutionDeliveryJournal, ExecutionTelemetryReporter, } from './execution-telemetry.js';
|
|
9
|
+
import { startTypingLease } from './typing-lease.js';
|
|
8
10
|
import { ATTENTION_FOLLOW_SEMANTICS_COMPATIBILITY_GATE, COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE, COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE, COLLABORATION_SKILL_FIRST_COMPATIBILITY_GATE, CONTEXT_INJECTION_COMPATIBILITY_GATE, LOCALHOST_GATEWAY_COMPATIBILITY_GATE, POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE, resolveInternalPolicyMode, resolveInternalCompatibilityGates, SKILL_RUNTIME_COMPATIBILITY_GATE, TASK_THREAD_COLLABORATION_CONTRACT_COMPATIBILITY_GATE, TOKEN_BINDING_COMPATIBILITY_GATE, } from './compatibility-gates.js';
|
|
9
11
|
import { buildNormalizedAttentionSnapshot, parsePersistedAttentionSnapshot, } from './context/attention.js';
|
|
10
12
|
import { mergeCompactionSnapshot, parsePersistedCompactionSnapshot, } from './context/compaction.js';
|
|
@@ -14,7 +16,7 @@ import { extractTaskIdFromTaskAssignmentContent, resolveTaskAssignmentStatePath,
|
|
|
14
16
|
import { AuthorizationAuditSink, } from './policy/authorization-audit.js';
|
|
15
17
|
import { createProvider } from './providers/create-provider.js';
|
|
16
18
|
import { ProviderTurnCancelledError } from './providers/provider-adapter.js';
|
|
17
|
-
import { resolveAttentionStatePath, resolveCompactionStatePath, resolveSharedProtocolKickoffDecisionPath, resolveSharedProtocolStatusPath, } from './state-paths.js';
|
|
19
|
+
import { resolveAttentionStatePath, resolveCompactionStatePath, resolveExecutionDeliveryJournalPath, resolveExecutionTelemetryOutboxPath, resolveSharedProtocolKickoffDecisionPath, resolveSharedProtocolStatusPath, } from './state-paths.js';
|
|
18
20
|
import { appendVisibleMention as appendVisibleBodyMention, extractVisibleMentionIds as extractCanonicalMentionIds, } from './visible-mentions.js';
|
|
19
21
|
import { buildHostedIncomingContentText, buildHostedTurnContentParts, extractHostedMessageAttachments, normalizeHostedMessageAttachment, } from './hosted-turn-content.js';
|
|
20
22
|
import { waitForTaskForThread } from './task-thread-resolution.js';
|
|
@@ -110,6 +112,12 @@ class DefaultHostRuntime {
|
|
|
110
112
|
deps.borgee ??
|
|
111
113
|
new SdkChatControlPlane(config.borgeeBaseUrl, config.agent.agentApiKey, undefined, {
|
|
112
114
|
pluginId: `agents-host:${config.agent.provider}`,
|
|
115
|
+
executionTelemetryOutboxPath: resolveExecutionTelemetryOutboxPath(config.stateRootDir),
|
|
116
|
+
onExecutionTelemetryError: (error) => {
|
|
117
|
+
deps.logger.error('execution telemetry transport failed', {
|
|
118
|
+
error: summarizeError(error),
|
|
119
|
+
});
|
|
120
|
+
},
|
|
113
121
|
});
|
|
114
122
|
this.gateway = createLocalhostGatewayController({
|
|
115
123
|
gateEnabled: localhostGatewayGateEnabled,
|
|
@@ -291,6 +299,7 @@ export class AgentsHost {
|
|
|
291
299
|
borgee;
|
|
292
300
|
backgroundRuns;
|
|
293
301
|
logger;
|
|
302
|
+
executionDeliveryJournal;
|
|
294
303
|
contextInjectionEnabled;
|
|
295
304
|
collaborationEnabled;
|
|
296
305
|
collaborationOutcomeModelEnabled;
|
|
@@ -298,6 +307,8 @@ export class AgentsHost {
|
|
|
298
307
|
taskThreadCollaborationContractEnabled;
|
|
299
308
|
collaborationCapabilitiesDiagnosticsEnabled;
|
|
300
309
|
activeTurns = new Set();
|
|
310
|
+
executionTelemetryByExecutionId = new Map();
|
|
311
|
+
executionDispatches = new Map();
|
|
301
312
|
awaitingUserByChannel = new Map();
|
|
302
313
|
collaborationOutcomeByChannel = new Map();
|
|
303
314
|
/**
|
|
@@ -328,6 +339,9 @@ export class AgentsHost {
|
|
|
328
339
|
constructor(config, deps) {
|
|
329
340
|
this.config = config;
|
|
330
341
|
this.logger = new HostLogger(deps?.runtimeOptions);
|
|
342
|
+
this.executionDeliveryJournal =
|
|
343
|
+
deps?.executionDeliveryJournal ??
|
|
344
|
+
new ExecutionDeliveryJournal(resolveExecutionDeliveryJournalPath(config.stateRootDir));
|
|
331
345
|
const compatibilityGates = resolveInternalCompatibilityGates();
|
|
332
346
|
const contextInjectionGateEnabled = compatibilityGates.has(CONTEXT_INJECTION_COMPATIBILITY_GATE);
|
|
333
347
|
this.contextInjectionEnabled = contextInjectionGateEnabled;
|
|
@@ -392,6 +406,7 @@ export class AgentsHost {
|
|
|
392
406
|
const bufferedMessages = [];
|
|
393
407
|
let bufferingMessages = true;
|
|
394
408
|
try {
|
|
409
|
+
await this.executionDeliveryJournal.load();
|
|
395
410
|
this.provider.onAutonomousReply?.((reply) => this.dispatchAutonomousReply(reply));
|
|
396
411
|
await this.runtime.start((message) => {
|
|
397
412
|
if (!this.started) {
|
|
@@ -471,16 +486,145 @@ export class AgentsHost {
|
|
|
471
486
|
}
|
|
472
487
|
trackActiveTurn(task) {
|
|
473
488
|
this.activeTurns.add(task);
|
|
474
|
-
void task
|
|
489
|
+
void task
|
|
490
|
+
.catch((error) => {
|
|
491
|
+
this.logger.error('dispatched turn failed', {
|
|
492
|
+
error: summarizeError(error),
|
|
493
|
+
});
|
|
494
|
+
})
|
|
495
|
+
.finally(() => {
|
|
475
496
|
this.activeTurns.delete(task);
|
|
476
497
|
});
|
|
477
498
|
}
|
|
478
499
|
dispatchMessage(message) {
|
|
479
|
-
const
|
|
500
|
+
const executionId = message.execution_grant?.executionId;
|
|
501
|
+
const existing = executionId
|
|
502
|
+
? this.executionDispatches.get(executionId)
|
|
503
|
+
: undefined;
|
|
504
|
+
if (existing) {
|
|
505
|
+
this.trackActiveTurn(existing);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const run = () => this.collaborationEnabled
|
|
480
509
|
? this.handleCollaborationMessage(message)
|
|
481
510
|
: this.enqueueChannelTurn(message.channel_id, () => this.handleLegacyMessage(message));
|
|
511
|
+
const work = executionId
|
|
512
|
+
? this.runClaimedExecution(message, run)
|
|
513
|
+
: this.runMessageWithExecutionTelemetry(message, run).then((result) => {
|
|
514
|
+
if (result.error)
|
|
515
|
+
throw result.error;
|
|
516
|
+
});
|
|
517
|
+
const task = executionId
|
|
518
|
+
? work.finally(() => {
|
|
519
|
+
this.executionDispatches.delete(executionId);
|
|
520
|
+
})
|
|
521
|
+
: work;
|
|
522
|
+
if (executionId)
|
|
523
|
+
this.executionDispatches.set(executionId, task);
|
|
482
524
|
this.trackActiveTurn(task);
|
|
483
525
|
}
|
|
526
|
+
async runClaimedExecution(message, run) {
|
|
527
|
+
const grant = message.execution_grant;
|
|
528
|
+
const claim = await this.executionDeliveryJournal.claim(grant.executionId);
|
|
529
|
+
if (claim === 'completed')
|
|
530
|
+
return;
|
|
531
|
+
if (claim === 'recovering') {
|
|
532
|
+
if (this.borgee.reportExecutionTelemetry) {
|
|
533
|
+
let reporter = this.executionTelemetryByExecutionId.get(grant.executionId);
|
|
534
|
+
const restoredReporter = !reporter;
|
|
535
|
+
reporter ??= this.createExecutionTelemetryReporter(grant);
|
|
536
|
+
this.executionTelemetryByExecutionId.set(grant.executionId, reporter);
|
|
537
|
+
await reporter.start();
|
|
538
|
+
if (restoredReporter) {
|
|
539
|
+
const persistedUsage = await this.executionDeliveryJournal.readUsage(grant.executionId);
|
|
540
|
+
if (persistedUsage) {
|
|
541
|
+
const { provider, ...usage } = persistedUsage;
|
|
542
|
+
await reporter.usage(provider, usage);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
reporter.noteFailure();
|
|
546
|
+
let finishError;
|
|
547
|
+
try {
|
|
548
|
+
await reporter.finish(false);
|
|
549
|
+
}
|
|
550
|
+
catch (error) {
|
|
551
|
+
finishError = error;
|
|
552
|
+
}
|
|
553
|
+
if (reporter.allRequiredFramesDurable) {
|
|
554
|
+
await this.executionDeliveryJournal.complete(grant.executionId);
|
|
555
|
+
this.executionTelemetryByExecutionId.delete(grant.executionId);
|
|
556
|
+
}
|
|
557
|
+
if (finishError)
|
|
558
|
+
throw finishError;
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
throw new Error('Execution telemetry is unavailable for interrupted delivery recovery');
|
|
562
|
+
}
|
|
563
|
+
const result = await this.runMessageWithExecutionTelemetry(message, run);
|
|
564
|
+
if (result.allRequiredFramesDurable) {
|
|
565
|
+
await this.executionDeliveryJournal.complete(grant.executionId);
|
|
566
|
+
}
|
|
567
|
+
if (result.error)
|
|
568
|
+
throw result.error;
|
|
569
|
+
}
|
|
570
|
+
async runMessageWithExecutionTelemetry(message, run) {
|
|
571
|
+
const grant = message.execution_grant;
|
|
572
|
+
const reporter = grant && this.borgee.reportExecutionTelemetry
|
|
573
|
+
? this.executionTelemetryByExecutionId.get(grant.executionId) ??
|
|
574
|
+
this.createExecutionTelemetryReporter(grant)
|
|
575
|
+
: undefined;
|
|
576
|
+
if (grant && !reporter) {
|
|
577
|
+
return {
|
|
578
|
+
allRequiredFramesDurable: false,
|
|
579
|
+
error: new Error('Execution telemetry is unavailable for admitted delivery'),
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
if (grant && reporter) {
|
|
583
|
+
this.executionTelemetryByExecutionId.set(grant.executionId, reporter);
|
|
584
|
+
}
|
|
585
|
+
let runError;
|
|
586
|
+
try {
|
|
587
|
+
await run();
|
|
588
|
+
}
|
|
589
|
+
catch (error) {
|
|
590
|
+
reporter?.noteFailure();
|
|
591
|
+
runError = error;
|
|
592
|
+
}
|
|
593
|
+
let finishError;
|
|
594
|
+
if (reporter) {
|
|
595
|
+
try {
|
|
596
|
+
await reporter.finish();
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
finishError = error;
|
|
600
|
+
this.logger.error('execution telemetry finish failed', {
|
|
601
|
+
error: summarizeError(error),
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
finally {
|
|
605
|
+
if (reporter.allRequiredFramesDurable &&
|
|
606
|
+
grant &&
|
|
607
|
+
this.executionTelemetryByExecutionId.get(grant.executionId) === reporter) {
|
|
608
|
+
this.executionTelemetryByExecutionId.delete(grant.executionId);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const error = runError && finishError
|
|
613
|
+
? new AggregateError([runError, finishError], 'Execution and telemetry finalization both failed')
|
|
614
|
+
: runError ?? finishError;
|
|
615
|
+
return {
|
|
616
|
+
allRequiredFramesDurable: reporter?.allRequiredFramesDurable ?? grant === undefined,
|
|
617
|
+
...(error ? { error } : {}),
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
createExecutionTelemetryReporter(grant) {
|
|
621
|
+
return new ExecutionTelemetryReporter(grant, {
|
|
622
|
+
reportExecutionTelemetry: (frame) => this.borgee.reportExecutionTelemetry(frame),
|
|
623
|
+
}, Date.now, (provider, usage) => this.executionDeliveryJournal.recordUsage(grant.executionId, {
|
|
624
|
+
provider,
|
|
625
|
+
...usage,
|
|
626
|
+
}));
|
|
627
|
+
}
|
|
484
628
|
dispatchAutonomousReply(reply) {
|
|
485
629
|
if (!this.started
|
|
486
630
|
|| this.controlPlaneClosed
|
|
@@ -2322,17 +2466,6 @@ export class AgentsHost {
|
|
|
2322
2466
|
? 'silent-kickoff'
|
|
2323
2467
|
: undefined;
|
|
2324
2468
|
const turnExecutionId = activeTurn?.turnExecutionId ?? null;
|
|
2325
|
-
const stopTyping = silentTurn ? () => { } : this.borgee.startTyping(channelId);
|
|
2326
|
-
const collaborationGrounding = await this.buildCollaborationGrounding(authorId, options?.incomingAuthorKind, activeTurn, options?.kickoff);
|
|
2327
|
-
const publishesCollaborationDraft = !silentTurn &&
|
|
2328
|
-
!deferDelivery &&
|
|
2329
|
-
this.collaborationEnabled &&
|
|
2330
|
-
turnExecutionId != null &&
|
|
2331
|
-
activeTurn?.protocol === undefined;
|
|
2332
|
-
const supportsProviderProgress = this.provider.capabilities?.progressUpdates?.support === 'supported';
|
|
2333
|
-
const supportsBackgroundRunLifecycle = this.provider.capabilities?.backgroundRuns?.lifecycle === 'supported';
|
|
2334
|
-
const reportsProviderActivity = !silentTurn && supportsProviderProgress;
|
|
2335
|
-
const observeProviderProgress = supportsProviderProgress || supportsBackgroundRunLifecycle;
|
|
2336
2469
|
const turnContext = {
|
|
2337
2470
|
eventType: msg.type,
|
|
2338
2471
|
channelId,
|
|
@@ -2345,26 +2478,58 @@ export class AgentsHost {
|
|
|
2345
2478
|
};
|
|
2346
2479
|
const turnStartedAt = Date.now();
|
|
2347
2480
|
this.logger.debug('starting turn', turnContext);
|
|
2481
|
+
const executionTelemetry = msg.execution_grant
|
|
2482
|
+
? this.executionTelemetryByExecutionId.get(msg.execution_grant.executionId)
|
|
2483
|
+
: undefined;
|
|
2484
|
+
let executionSucceeded = false;
|
|
2485
|
+
let executionTelemetryStartFailed = false;
|
|
2348
2486
|
let reply;
|
|
2349
2487
|
let publicReplyText;
|
|
2350
2488
|
let visibleReplyBody;
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
? this.collaborationOutcomeByChannel.get(channelId)
|
|
2354
|
-
: undefined;
|
|
2355
|
-
const missedCollaborationDiagnostic = this.resolveMissedCollaborationDiagnosticForTurn(channelId);
|
|
2356
|
-
const collaborationCapabilities = this.resolveCollaborationCapabilityDeclarationForTurn(taskThreadContext);
|
|
2357
|
-
const incomingParts = options?.incomingParts
|
|
2358
|
-
?? buildHostedTurnContentParts({
|
|
2359
|
-
text: String(msg.content ?? msg.body ?? content),
|
|
2360
|
-
attachments: msg.attachments,
|
|
2361
|
-
});
|
|
2362
|
-
const activityReporter = silentTurn
|
|
2363
|
-
? undefined
|
|
2364
|
-
: this.beginTurnActivity(channelId, activeTurn?.generation);
|
|
2365
|
-
await this.ensureCompactionSnapshotLoaded(channelId);
|
|
2366
|
-
const compactionSnapshot = this.compactionSnapshotByChannel.get(channelId);
|
|
2489
|
+
let activityReporter;
|
|
2490
|
+
let typingLease;
|
|
2367
2491
|
try {
|
|
2492
|
+
if (!silentTurn) {
|
|
2493
|
+
typingLease = startTypingLease(() => this.borgee.reportTyping(channelId));
|
|
2494
|
+
}
|
|
2495
|
+
const collaborationGrounding = await this.buildCollaborationGrounding(authorId, options?.incomingAuthorKind, activeTurn, options?.kickoff);
|
|
2496
|
+
const publishesCollaborationDraft = !silentTurn &&
|
|
2497
|
+
!deferDelivery &&
|
|
2498
|
+
this.collaborationEnabled &&
|
|
2499
|
+
turnExecutionId != null &&
|
|
2500
|
+
activeTurn?.protocol === undefined;
|
|
2501
|
+
const supportsProviderProgress = this.provider.capabilities?.progressUpdates?.support === 'supported';
|
|
2502
|
+
const supportsBackgroundRunLifecycle = this.provider.capabilities?.backgroundRuns?.lifecycle === 'supported';
|
|
2503
|
+
const reportsProviderActivity = !silentTurn && supportsProviderProgress;
|
|
2504
|
+
const observeProviderProgress = supportsProviderProgress || supportsBackgroundRunLifecycle;
|
|
2505
|
+
const taskThreadCollaborationContract = this.resolveTaskThreadCollaborationContractForTurn(msg, taskThreadContext);
|
|
2506
|
+
const collaborationOutcome = this.collaborationOutcomeModelEnabled
|
|
2507
|
+
? this.collaborationOutcomeByChannel.get(channelId)
|
|
2508
|
+
: undefined;
|
|
2509
|
+
const missedCollaborationDiagnostic = this.resolveMissedCollaborationDiagnosticForTurn(channelId);
|
|
2510
|
+
const collaborationCapabilities = this.resolveCollaborationCapabilityDeclarationForTurn(taskThreadContext);
|
|
2511
|
+
const incomingParts = options?.incomingParts
|
|
2512
|
+
?? buildHostedTurnContentParts({
|
|
2513
|
+
text: String(msg.content ?? msg.body ?? content),
|
|
2514
|
+
attachments: msg.attachments,
|
|
2515
|
+
});
|
|
2516
|
+
activityReporter = silentTurn
|
|
2517
|
+
? undefined
|
|
2518
|
+
: this.beginTurnActivity(channelId, activeTurn?.generation);
|
|
2519
|
+
await this.ensureCompactionSnapshotLoaded(channelId);
|
|
2520
|
+
const compactionSnapshot = this.compactionSnapshotByChannel.get(channelId);
|
|
2521
|
+
if (executionTelemetry) {
|
|
2522
|
+
try {
|
|
2523
|
+
await executionTelemetry.start();
|
|
2524
|
+
}
|
|
2525
|
+
catch (error) {
|
|
2526
|
+
executionTelemetryStartFailed = true;
|
|
2527
|
+
this.logger.error('execution telemetry start failed', {
|
|
2528
|
+
error: summarizeError(error),
|
|
2529
|
+
});
|
|
2530
|
+
throw error;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2368
2533
|
reply = await this.provider.generateReply({
|
|
2369
2534
|
agentName: this.config.agent.agentName,
|
|
2370
2535
|
provider: this.config.agent.provider,
|
|
@@ -2405,42 +2570,61 @@ export class AgentsHost {
|
|
|
2405
2570
|
: { taskAssignmentContextOverridePersistence: 'ephemeral' }),
|
|
2406
2571
|
}
|
|
2407
2572
|
: {}),
|
|
2408
|
-
}, observeProviderProgress
|
|
2573
|
+
}, observeProviderProgress || executionTelemetry
|
|
2409
2574
|
? {
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
return;
|
|
2419
|
-
}
|
|
2420
|
-
}
|
|
2421
|
-
if (!this.canAcceptTurnOutput(channelId, activeTurn?.generation)) {
|
|
2422
|
-
return;
|
|
2423
|
-
}
|
|
2424
|
-
if (supportsProviderProgress && update.type === 'compaction') {
|
|
2425
|
-
this.noteCompactionProgress(channelId, update.compaction, {
|
|
2426
|
-
turnExecutionId: activeTurn?.turnExecutionId ?? undefined,
|
|
2427
|
-
});
|
|
2428
|
-
return;
|
|
2575
|
+
...(executionTelemetry
|
|
2576
|
+
? {
|
|
2577
|
+
onUsage: (usage) => {
|
|
2578
|
+
void executionTelemetry.usage(this.config.agent.provider, usage);
|
|
2579
|
+
},
|
|
2580
|
+
onExecutionContinuation: (completion) => {
|
|
2581
|
+
executionTelemetry.hold(completion);
|
|
2582
|
+
},
|
|
2429
2583
|
}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2584
|
+
: {}),
|
|
2585
|
+
...(observeProviderProgress
|
|
2586
|
+
? {
|
|
2587
|
+
onProgress: (update) => {
|
|
2588
|
+
if (supportsBackgroundRunLifecycle) {
|
|
2589
|
+
this.backgroundRuns.observe(channelId, update);
|
|
2590
|
+
if (update.type === 'activity' && update.activity.background === true) {
|
|
2591
|
+
this.borgee.reportActivity?.({
|
|
2592
|
+
channelId,
|
|
2593
|
+
activity: { shape: 'activity', ...update.activity },
|
|
2594
|
+
});
|
|
2595
|
+
return;
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
if (!this.canAcceptTurnOutput(channelId, activeTurn?.generation)) {
|
|
2599
|
+
return;
|
|
2600
|
+
}
|
|
2601
|
+
if (update.type === 'text'
|
|
2602
|
+
&& update.stream === 'answer'
|
|
2603
|
+
&& hasVisibleText(update.text)) {
|
|
2604
|
+
typingLease?.renew();
|
|
2605
|
+
}
|
|
2606
|
+
if (supportsProviderProgress && update.type === 'compaction') {
|
|
2607
|
+
this.noteCompactionProgress(channelId, update.compaction, {
|
|
2608
|
+
turnExecutionId: activeTurn?.turnExecutionId ?? undefined,
|
|
2609
|
+
});
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
const reportedActivity = toReportedActivity(update);
|
|
2613
|
+
if (reportsProviderActivity && reportedActivity) {
|
|
2614
|
+
activityReporter?.progress(reportedActivity);
|
|
2615
|
+
}
|
|
2616
|
+
if (!supportsProviderProgress ||
|
|
2617
|
+
update.type !== 'text' ||
|
|
2618
|
+
update.stream !== 'answer') {
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
if (!publishesCollaborationDraft) {
|
|
2622
|
+
return;
|
|
2623
|
+
}
|
|
2624
|
+
this.publishCollaborationDraft(channelId, activeTurn, update.text);
|
|
2625
|
+
},
|
|
2441
2626
|
}
|
|
2442
|
-
|
|
2443
|
-
},
|
|
2627
|
+
: {}),
|
|
2444
2628
|
}
|
|
2445
2629
|
: undefined);
|
|
2446
2630
|
publicReplyText = resolvePublicReplyText(reply);
|
|
@@ -2468,6 +2652,7 @@ export class AgentsHost {
|
|
|
2468
2652
|
return { reply, stale: true, completed: false };
|
|
2469
2653
|
}
|
|
2470
2654
|
if (silentTurn) {
|
|
2655
|
+
executionSucceeded = true;
|
|
2471
2656
|
this.logger.debug('completed turn', {
|
|
2472
2657
|
...turnContext,
|
|
2473
2658
|
durationMs: Date.now() - turnStartedAt,
|
|
@@ -2488,6 +2673,7 @@ export class AgentsHost {
|
|
|
2488
2673
|
};
|
|
2489
2674
|
}
|
|
2490
2675
|
if (deferDelivery) {
|
|
2676
|
+
executionSucceeded = true;
|
|
2491
2677
|
this.logger.debug('completed turn', {
|
|
2492
2678
|
...turnContext,
|
|
2493
2679
|
durationMs: Date.now() - turnStartedAt,
|
|
@@ -2524,6 +2710,7 @@ export class AgentsHost {
|
|
|
2524
2710
|
if (publishesCollaborationDraft) {
|
|
2525
2711
|
this.finalizeCollaborationDraft(channelId, activeTurn, posted.messageId, visibleReplyBody);
|
|
2526
2712
|
}
|
|
2713
|
+
executionSucceeded = true;
|
|
2527
2714
|
return {
|
|
2528
2715
|
reply,
|
|
2529
2716
|
deliveredMessageId: posted.messageId,
|
|
@@ -2547,6 +2734,7 @@ export class AgentsHost {
|
|
|
2547
2734
|
turnExecutionId: activeTurn.turnExecutionId,
|
|
2548
2735
|
});
|
|
2549
2736
|
}
|
|
2737
|
+
executionSucceeded = true;
|
|
2550
2738
|
return {
|
|
2551
2739
|
reply,
|
|
2552
2740
|
deliveredMessageId: null,
|
|
@@ -2565,6 +2753,9 @@ export class AgentsHost {
|
|
|
2565
2753
|
turnExecutionId: activeTurn.turnExecutionId,
|
|
2566
2754
|
});
|
|
2567
2755
|
}
|
|
2756
|
+
if (executionTelemetryStartFailed) {
|
|
2757
|
+
throw error;
|
|
2758
|
+
}
|
|
2568
2759
|
if (error instanceof ProviderTurnCancelledError) {
|
|
2569
2760
|
const cancelledReplyText = error.publicReplyText?.trim();
|
|
2570
2761
|
if (!silentTurn &&
|
|
@@ -2642,7 +2833,10 @@ export class AgentsHost {
|
|
|
2642
2833
|
};
|
|
2643
2834
|
}
|
|
2644
2835
|
finally {
|
|
2645
|
-
|
|
2836
|
+
if (executionTelemetry) {
|
|
2837
|
+
executionTelemetry.noteAttempt(executionSucceeded);
|
|
2838
|
+
}
|
|
2839
|
+
typingLease?.stop();
|
|
2646
2840
|
activityReporter?.end();
|
|
2647
2841
|
}
|
|
2648
2842
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AgentActivity, ReportTaskFinishedInput, ReportTurnActivityInput, StopBackgroundRunHandler, StopTurnHandler, TurnActivityReporter } from '../plugin-sdk.js';
|
|
2
|
-
import type { ChannelSummary, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
|
|
1
|
+
import type { AgentActivity, ExecutionTelemetryFrame, ReportTaskFinishedInput, ReportTurnActivityInput, StopBackgroundRunHandler, StopTurnHandler, TurnActivityReporter } from '../plugin-sdk.js';
|
|
2
|
+
import type { ChannelSummary, ChannelFileEntry, ChannelFileContent, PublishChannelFileInput, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
|
|
3
3
|
export interface ChatControlPlane {
|
|
4
4
|
onStopTurn?(handler: StopTurnHandler | undefined): void;
|
|
5
5
|
onStopBackgroundRun?(handler: StopBackgroundRunHandler | undefined): void;
|
|
@@ -9,9 +9,10 @@ export interface ChatControlPlane {
|
|
|
9
9
|
postMessage(input: PostMessageInput): Promise<PostedMessage>;
|
|
10
10
|
editMessage(messageId: string, content: string): Promise<void>;
|
|
11
11
|
deleteMessage(messageId: string): Promise<void>;
|
|
12
|
-
|
|
12
|
+
reportTyping(channelId: string): void;
|
|
13
13
|
/** Opens one turn's report on the activity rail. Fire-and-forget: nothing recovers what it sends. */
|
|
14
14
|
reportTurnActivity(input: ReportTurnActivityInput): TurnActivityReporter;
|
|
15
|
+
reportExecutionTelemetry?(frame: ExecutionTelemetryFrame): Promise<void>;
|
|
15
16
|
reportTaskFinished?(input: ReportTaskFinishedInput): void;
|
|
16
17
|
reportActivity?(input: {
|
|
17
18
|
channelId: string;
|
|
@@ -19,6 +20,15 @@ export interface ChatControlPlane {
|
|
|
19
20
|
}): void;
|
|
20
21
|
getMe(): Promise<MeResponseUser>;
|
|
21
22
|
listUsers(): Promise<DirectoryUser[]>;
|
|
23
|
+
listChannelFiles(input: {
|
|
24
|
+
channelId: string;
|
|
25
|
+
}): Promise<ChannelFileEntry[]>;
|
|
26
|
+
readChannelFile(input: {
|
|
27
|
+
channelId: string;
|
|
28
|
+
path: string;
|
|
29
|
+
textOnly: boolean;
|
|
30
|
+
}): Promise<ChannelFileContent>;
|
|
31
|
+
publishChannelFile(input: PublishChannelFileInput): Promise<ChannelFileEntry>;
|
|
22
32
|
listChannels(): Promise<ChannelSummary[]>;
|
|
23
33
|
readChannelHistory(input: ReadChannelHistoryInput): Promise<ChannelHistoryEntry[]>;
|
|
24
34
|
createTask(input: CreateTaskInput): Promise<Task>;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { type BorgeePluginClient, type BorgeePluginOptions, type InboundMessageEvent, type ReportTaskFinishedInput, type ReportTurnActivityInput, type StopTurnHandler, type StopBackgroundRunHandler, type TurnActivityReporter } from '../plugin-sdk.js';
|
|
2
|
-
import
|
|
1
|
+
import { type BorgeePluginClient, type BorgeePluginOptions, type ExecutionTelemetryFrame, type InboundMessageEvent, type ReportTaskFinishedInput, type ReportTurnActivityInput, type StopTurnHandler, type StopBackgroundRunHandler, type TurnActivityReporter } from '../plugin-sdk.js';
|
|
2
|
+
import { type ExecutionTelemetryOutboxPolicy } from '../execution-telemetry.js';
|
|
3
|
+
import type { ChannelSummary, ChannelFileEntry, ChannelFileContent, PublishChannelFileInput, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
|
|
3
4
|
import type { ChatControlPlane } from './chat-control-plane.js';
|
|
4
|
-
type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'createTask' | 'deleteMessage' | 'editMessage' | 'getMe' | 'getTask' | 'listChannels' | 'listTasks' | 'listUsers' | 'on' | 'onStopTurn' | 'onStopBackgroundRun' | 'reportActivity' | 'readHistory' | 'reportTurnActivity' | '
|
|
5
|
+
type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'createTask' | 'deleteMessage' | 'editMessage' | 'getMe' | 'getTask' | 'listChannelFiles' | 'readChannelFile' | 'publishChannelFile' | 'listChannels' | 'listTasks' | 'listUsers' | 'on' | 'onStopTurn' | 'onStopBackgroundRun' | 'reportActivity' | 'readHistory' | 'reportTurnActivity' | 'reportTyping' | 'sendMessage' | 'updateTask' | 'setTaskProperty' | 'deleteTaskProperty'> & Partial<Pick<BorgeePluginClient, 'connectionState' | 'reportExecutionTelemetry' | 'reportTaskFinished'>>;
|
|
5
6
|
type PluginClientFactory = (options: BorgeePluginOptions) => PluginClientLike;
|
|
6
|
-
type SdkChatControlPlaneOptions = Pick<BorgeePluginOptions, 'pluginId'
|
|
7
|
+
type SdkChatControlPlaneOptions = Pick<BorgeePluginOptions, 'pluginId'> & {
|
|
8
|
+
executionTelemetryCapacityWaitMs?: number;
|
|
9
|
+
executionTelemetryOutboxPath?: string;
|
|
10
|
+
executionTelemetryOutboxPolicy?: Partial<ExecutionTelemetryOutboxPolicy>;
|
|
11
|
+
onExecutionTelemetryError?: (error: unknown) => void;
|
|
12
|
+
};
|
|
7
13
|
/**
|
|
8
14
|
* Thin adapter over `@borgee/plugin-sdk` (the same BPP/`/ws/plugin` SDK used by
|
|
9
15
|
* the OpenClaw plugin) that implements the minimal `ChatControlPlane` surface
|
|
@@ -14,8 +20,14 @@ export declare class SdkChatControlPlane implements ChatControlPlane {
|
|
|
14
20
|
private pendingMessages;
|
|
15
21
|
private unsubscribe;
|
|
16
22
|
private stateUnsubscribe;
|
|
23
|
+
private telemetryAckUnsubscribe;
|
|
24
|
+
private executionTelemetryRetry?;
|
|
17
25
|
private activityTransportReady;
|
|
26
|
+
private readonly executionTelemetryOutbox;
|
|
27
|
+
private readonly onExecutionTelemetryError;
|
|
18
28
|
private connected;
|
|
29
|
+
private transportOnline;
|
|
30
|
+
private readonly executionTelemetryCapacityWaitMs;
|
|
19
31
|
private me;
|
|
20
32
|
constructor(baseUrl: string, apiKey: string, createClient?: PluginClientFactory, options?: SdkChatControlPlaneOptions);
|
|
21
33
|
onStopTurn(handler: StopTurnHandler | undefined): void;
|
|
@@ -28,10 +40,23 @@ export declare class SdkChatControlPlane implements ChatControlPlane {
|
|
|
28
40
|
reportTaskFinished(input: ReportTaskFinishedInput): void;
|
|
29
41
|
editMessage(messageId: string, content: string): Promise<void>;
|
|
30
42
|
deleteMessage(messageId: string): Promise<void>;
|
|
31
|
-
|
|
43
|
+
reportTyping(channelId: string): void;
|
|
32
44
|
reportTurnActivity(input: ReportTurnActivityInput): TurnActivityReporter;
|
|
45
|
+
reportExecutionTelemetry(frame: ExecutionTelemetryFrame): Promise<void>;
|
|
46
|
+
private flushExecutionTelemetry;
|
|
47
|
+
private scheduleExecutionTelemetryRetry;
|
|
48
|
+
private cancelExecutionTelemetryRetry;
|
|
33
49
|
getMe(): Promise<MeResponseUser>;
|
|
34
50
|
listUsers(): Promise<DirectoryUser[]>;
|
|
51
|
+
listChannelFiles(input: {
|
|
52
|
+
channelId: string;
|
|
53
|
+
}): Promise<ChannelFileEntry[]>;
|
|
54
|
+
readChannelFile(input: {
|
|
55
|
+
channelId: string;
|
|
56
|
+
path: string;
|
|
57
|
+
textOnly: boolean;
|
|
58
|
+
}): Promise<ChannelFileContent>;
|
|
59
|
+
publishChannelFile(input: PublishChannelFileInput): Promise<ChannelFileEntry>;
|
|
35
60
|
readChannelHistory(input: ReadChannelHistoryInput): Promise<ChannelHistoryEntry[]>;
|
|
36
61
|
listChannels(): Promise<ChannelSummary[]>;
|
|
37
62
|
createTask(input: CreateTaskInput): Promise<Task>;
|