@animalabs/agent-framework 0.6.5 → 0.6.7
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 +78 -0
- package/dist/src/agent.d.ts +56 -2
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +372 -57
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server.js +0 -0
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +7 -2
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/canonical-json.d.ts +2 -0
- package/dist/src/canonical-json.d.ts.map +1 -0
- package/dist/src/canonical-json.js +23 -0
- package/dist/src/canonical-json.js.map +1 -0
- package/dist/src/framework.d.ts +160 -2
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +3098 -167
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +34 -4
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +36 -15
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +322 -76
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +1 -0
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +1 -0
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +39 -4
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +146 -28
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +43 -12
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js +1 -0
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +12 -1
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +661 -2
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +4 -0
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts +99 -0
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -0
- package/dist/src/recovery/discord-awareness-outbox.js +334 -0
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -0
- package/dist/src/recovery/offline-branch.d.ts +45 -0
- package/dist/src/recovery/offline-branch.d.ts.map +1 -0
- package/dist/src/recovery/offline-branch.js +362 -0
- package/dist/src/recovery/offline-branch.js.map +1 -0
- package/dist/src/recovery/recover-cli.d.ts +3 -0
- package/dist/src/recovery/recover-cli.d.ts.map +1 -0
- package/dist/src/recovery/recover-cli.js +129 -0
- package/dist/src/recovery/recover-cli.js.map +1 -0
- package/dist/src/types/agent.d.ts +37 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +1 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +14 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +31 -0
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +4 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/test/agent-runtime-settings.test.d.ts +2 -0
- package/dist/test/agent-runtime-settings.test.d.ts.map +1 -0
- package/dist/test/agent-runtime-settings.test.js +227 -0
- package/dist/test/agent-runtime-settings.test.js.map +1 -0
- package/dist/test/busy-agent-scheduler.test.d.ts +2 -0
- package/dist/test/busy-agent-scheduler.test.d.ts.map +1 -0
- package/dist/test/busy-agent-scheduler.test.js +62 -0
- package/dist/test/busy-agent-scheduler.test.js.map +1 -0
- package/dist/test/channel-lifecycle-provenance.test.d.ts +2 -0
- package/dist/test/channel-lifecycle-provenance.test.d.ts.map +1 -0
- package/dist/test/channel-lifecycle-provenance.test.js +47 -0
- package/dist/test/channel-lifecycle-provenance.test.js.map +1 -0
- package/dist/test/channel-registry-routing.test.js +5 -4
- package/dist/test/channel-registry-routing.test.js.map +1 -1
- package/dist/test/conversation-fork-injection-scoping.test.js +12 -1
- package/dist/test/conversation-fork-injection-scoping.test.js.map +1 -1
- package/dist/test/discord-awareness-outbox.test.d.ts +2 -0
- package/dist/test/discord-awareness-outbox.test.d.ts.map +1 -0
- package/dist/test/discord-awareness-outbox.test.js +248 -0
- package/dist/test/discord-awareness-outbox.test.js.map +1 -0
- package/dist/test/event-gate.test.js +21 -1
- package/dist/test/event-gate.test.js.map +1 -1
- package/dist/test/helpers/mock-membrane.d.ts +13 -1
- package/dist/test/helpers/mock-membrane.d.ts.map +1 -1
- package/dist/test/helpers/mock-membrane.js +9 -2
- package/dist/test/helpers/mock-membrane.js.map +1 -1
- package/dist/test/maintenance-timer.test.js +103 -1
- package/dist/test/maintenance-timer.test.js.map +1 -1
- package/dist/test/mcpl-awareness-barrier.test.d.ts +2 -0
- package/dist/test/mcpl-awareness-barrier.test.d.ts.map +1 -0
- package/dist/test/mcpl-awareness-barrier.test.js +845 -0
- package/dist/test/mcpl-awareness-barrier.test.js.map +1 -0
- package/dist/test/mcpl-gate-roundtrip.test.js +138 -6
- package/dist/test/mcpl-gate-roundtrip.test.js.map +1 -1
- package/dist/test/mcpl-reconnect-reregistration.test.js +22 -3
- package/dist/test/mcpl-reconnect-reregistration.test.js.map +1 -1
- package/dist/test/mcpl-request-timeout.test.js +15 -0
- package/dist/test/mcpl-request-timeout.test.js.map +1 -1
- package/dist/test/offline-recovery-branch.test.d.ts +2 -0
- package/dist/test/offline-recovery-branch.test.d.ts.map +1 -0
- package/dist/test/offline-recovery-branch.test.js +226 -0
- package/dist/test/offline-recovery-branch.test.js.map +1 -0
- package/dist/test/present-while-acting.test.d.ts +19 -0
- package/dist/test/present-while-acting.test.d.ts.map +1 -0
- package/dist/test/present-while-acting.test.js +295 -0
- package/dist/test/present-while-acting.test.js.map +1 -0
- package/dist/test/primary-summary-refusal-fallback-integration.test.d.ts +2 -0
- package/dist/test/primary-summary-refusal-fallback-integration.test.d.ts.map +1 -0
- package/dist/test/primary-summary-refusal-fallback-integration.test.js +1955 -0
- package/dist/test/primary-summary-refusal-fallback-integration.test.js.map +1 -0
- package/dist/test/primary-summary-refusal-fallback.test.d.ts +2 -0
- package/dist/test/primary-summary-refusal-fallback.test.d.ts.map +1 -0
- package/dist/test/primary-summary-refusal-fallback.test.js +753 -0
- package/dist/test/primary-summary-refusal-fallback.test.js.map +1 -0
- package/dist/test/same-round-think-policy.test.d.ts +2 -0
- package/dist/test/same-round-think-policy.test.d.ts.map +1 -0
- package/dist/test/same-round-think-policy.test.js +853 -0
- package/dist/test/same-round-think-policy.test.js.map +1 -0
- package/dist/test/trunk-channel-routing.test.js +38 -0
- package/dist/test/trunk-channel-routing.test.js.map +1 -1
- package/dist/test/workspace-read-image.test.d.ts +2 -0
- package/dist/test/workspace-read-image.test.d.ts.map +1 -0
- package/dist/test/workspace-read-image.test.js +518 -0
- package/dist/test/workspace-read-image.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -4
- package/src/agent.ts +485 -63
- package/src/api/server.ts +8 -2
- package/src/canonical-json.ts +22 -0
- package/src/framework.ts +4096 -304
- package/src/gate/event-gate.ts +50 -4
- package/src/index.ts +20 -0
- package/src/mcpl/channel-registry.ts +396 -85
- package/src/mcpl/push-handler.ts +2 -0
- package/src/mcpl/server-connection.ts +173 -28
- package/src/mcpl/types.ts +49 -12
- package/src/modules/workspace/index.ts +759 -2
- package/src/modules/workspace/types.ts +5 -0
- package/src/recovery/discord-awareness-outbox.ts +459 -0
- package/src/recovery/offline-branch.ts +510 -0
- package/src/recovery/recover-cli.ts +130 -0
- package/src/types/agent.ts +44 -0
- package/src/types/events.ts +1 -1
- package/src/types/framework.ts +17 -0
- package/src/types/module.ts +33 -0
- package/src/types/trace.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@animalabs/agent-framework",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.7",
|
|
4
4
|
"description": "Multi-agent framework with pluggable modules, persistent state, and concurrent tool execution",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,10 +21,12 @@
|
|
|
21
21
|
"src"
|
|
22
22
|
],
|
|
23
23
|
"bin": {
|
|
24
|
-
"agent-framework-mcp": "./dist/src/api/mcp-server.js"
|
|
24
|
+
"agent-framework-mcp": "./dist/src/api/mcp-server.js",
|
|
25
|
+
"agent-framework-recover": "./dist/src/recovery/recover-cli.js"
|
|
25
26
|
},
|
|
26
27
|
"scripts": {
|
|
27
28
|
"build": "tsc",
|
|
29
|
+
"postbuild": "node -e \"const fs=require('node:fs'); for (const p of ['dist/src/api/mcp-server.js','dist/src/recovery/recover-cli.js']) fs.chmodSync(p, 0o755)\"",
|
|
28
30
|
"dev": "tsc --watch",
|
|
29
31
|
"clean": "rm -rf dist",
|
|
30
32
|
"typecheck": "tsc --noEmit",
|
|
@@ -44,8 +46,8 @@
|
|
|
44
46
|
"license": "MIT",
|
|
45
47
|
"dependencies": {
|
|
46
48
|
"@animalabs/chronicle": "^0.2.2",
|
|
47
|
-
"@animalabs/context-manager": "^0.5.
|
|
48
|
-
"@animalabs/membrane": "^0.5.
|
|
49
|
+
"@animalabs/context-manager": "^0.5.12",
|
|
50
|
+
"@animalabs/membrane": "^0.5.73",
|
|
49
51
|
"chokidar": "^4.0.3",
|
|
50
52
|
"discord.js": "^14.25.1",
|
|
51
53
|
"ws": "^8.18.0"
|
package/src/agent.ts
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
import type { Membrane, NormalizedMessage, NormalizedRequest, ContentBlock, YieldingStream } from '@animalabs/membrane';
|
|
2
2
|
import { isAbortedResponse } from '@animalabs/membrane';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
3
4
|
import { toolResultDataToHistoryString } from './tool-result-history.js';
|
|
5
|
+
import { canonicalJsonStringify } from './canonical-json.js';
|
|
6
|
+
|
|
7
|
+
export interface ActivationCompileArtifacts {
|
|
8
|
+
compileResult: CompileResult;
|
|
9
|
+
contract: PrimarySummaryContract & {
|
|
10
|
+
systemHash: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
export interface StartStreamResult {
|
|
6
15
|
stream: YieldingStream;
|
|
7
16
|
request: NormalizedRequest;
|
|
17
|
+
artifacts: ActivationCompileArtifacts;
|
|
8
18
|
}
|
|
9
|
-
import type {
|
|
19
|
+
import type {
|
|
20
|
+
ContextManager,
|
|
21
|
+
TokenBudget,
|
|
22
|
+
ContextInjection,
|
|
23
|
+
CompileResult,
|
|
24
|
+
HotContextSettingsStatus,
|
|
25
|
+
HotContextSettingsUpdate,
|
|
26
|
+
PrimarySummaryContract,
|
|
27
|
+
PrimarySummaryIdentity,
|
|
28
|
+
PrimarySummaryProjection,
|
|
29
|
+
} from '@animalabs/context-manager';
|
|
10
30
|
import type {
|
|
11
31
|
AgentConfig,
|
|
12
32
|
AgentState,
|
|
33
|
+
SameRoundThinkTextPolicy,
|
|
34
|
+
SameRoundThinkTextPolicySource,
|
|
13
35
|
PendingToolCall,
|
|
14
36
|
CompletedToolCall,
|
|
15
37
|
ToolCallId,
|
|
@@ -19,8 +41,19 @@ import type {
|
|
|
19
41
|
AgentInfo,
|
|
20
42
|
InferenceResult,
|
|
21
43
|
InferenceOptions,
|
|
44
|
+
AgentRuntimeSettingsPatch,
|
|
45
|
+
AgentRuntimeSettingsSnapshot,
|
|
46
|
+
AgentRuntimeSettingsOverrides,
|
|
22
47
|
} from './types/index.js';
|
|
23
48
|
|
|
49
|
+
type PrimarySummaryContractWithSystemHash = PrimarySummaryContract & {
|
|
50
|
+
systemHash: string;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const DEFAULT_CONTEXT_BUDGET_TOKENS = 100_000;
|
|
54
|
+
const DEFAULT_TRANSITION_PACE_TOKENS = 16_000;
|
|
55
|
+
const DEFAULT_SAME_ROUND_THINK_TEXT_POLICY: SameRoundThinkTextPolicy = 'public';
|
|
56
|
+
|
|
24
57
|
/**
|
|
25
58
|
* An agent wraps a context manager and manages inference state.
|
|
26
59
|
*/
|
|
@@ -50,6 +83,7 @@ export class Agent {
|
|
|
50
83
|
readonly cacheTtl: NonNullable<AgentConfig['cacheTtl']>;
|
|
51
84
|
/** Provider-specific request parameters forwarded unchanged by Membrane. */
|
|
52
85
|
readonly providerParams?: Record<string, unknown>;
|
|
86
|
+
readonly sameRoundThinkTextPolicy: AgentConfig['sameRoundThinkTextPolicy'];
|
|
53
87
|
|
|
54
88
|
private _state: AgentState = { status: 'idle' };
|
|
55
89
|
private _inferenceStartedAt = 0;
|
|
@@ -60,6 +94,12 @@ export class Agent {
|
|
|
60
94
|
* ContextManager's built-in default applies. reserveForResponse uses
|
|
61
95
|
* this agent's maxTokens. */
|
|
62
96
|
contextBudgetTokens?: number;
|
|
97
|
+
private readonly configuredContextBudgetTokens?: number;
|
|
98
|
+
private readonly configuredTailTokens?: number;
|
|
99
|
+
private readonly configuredTransitionPaceTokens?: number;
|
|
100
|
+
private readonly configuredSameRoundThinkTextPolicy?: SameRoundThinkTextPolicy;
|
|
101
|
+
private contextBudgetTargetTokens?: number;
|
|
102
|
+
private runtimeSettingsOverrides: AgentRuntimeSettingsOverrides = {};
|
|
63
103
|
private contextManager: ContextManager;
|
|
64
104
|
private membrane: Membrane;
|
|
65
105
|
|
|
@@ -79,10 +119,16 @@ export class Agent {
|
|
|
79
119
|
this.refusalHandling = config.refusalHandling;
|
|
80
120
|
this.cacheTtl = config.cacheTtl ?? '1h';
|
|
81
121
|
this.providerParams = config.providerParams;
|
|
122
|
+
this.sameRoundThinkTextPolicy = config.sameRoundThinkTextPolicy;
|
|
82
123
|
this.maxStreamTokens = config.maxStreamTokens ?? 150_000;
|
|
83
124
|
this.contextBudgetTokens = config.contextBudgetTokens;
|
|
125
|
+
this.configuredContextBudgetTokens = config.contextBudgetTokens;
|
|
84
126
|
this.contextManager = contextManager;
|
|
85
127
|
this.membrane = membrane;
|
|
128
|
+
const hot = this.getHotContextSettings();
|
|
129
|
+
this.configuredTailTokens = hot?.tailTokens;
|
|
130
|
+
this.configuredTransitionPaceTokens = hot?.transitionPaceTokens;
|
|
131
|
+
this.configuredSameRoundThinkTextPolicy = config.sameRoundThinkTextPolicy;
|
|
86
132
|
}
|
|
87
133
|
|
|
88
134
|
/**
|
|
@@ -148,8 +194,414 @@ export class Agent {
|
|
|
148
194
|
return { maxTokens: this.contextBudgetTokens, reserveForResponse: this.maxTokens };
|
|
149
195
|
}
|
|
150
196
|
|
|
197
|
+
/** Structural compatibility keeps lightweight test/host ContextManager
|
|
198
|
+
* doubles working while making the new capability optional at runtime. */
|
|
199
|
+
private getHotContextSettings(): HotContextSettingsStatus | null {
|
|
200
|
+
const manager = this.contextManager as ContextManager & {
|
|
201
|
+
getHotContextSettings?: () => HotContextSettingsStatus | null;
|
|
202
|
+
};
|
|
203
|
+
return typeof manager.getHotContextSettings === 'function'
|
|
204
|
+
? manager.getHotContextSettings()
|
|
205
|
+
: null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private updateHotContextSettings(update: HotContextSettingsUpdate): HotContextSettingsStatus {
|
|
209
|
+
const manager = this.contextManager as ContextManager & {
|
|
210
|
+
updateHotContextSettings?: (value: HotContextSettingsUpdate) => HotContextSettingsStatus;
|
|
211
|
+
};
|
|
212
|
+
if (typeof manager.updateHotContextSettings !== 'function') {
|
|
213
|
+
throw new Error('The active context strategy does not support live context settings');
|
|
214
|
+
}
|
|
215
|
+
return manager.updateHotContextSettings(update);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private hashJson(value: unknown): string {
|
|
219
|
+
return createHash('sha256').update(canonicalJsonStringify(value), 'utf8').digest('hex');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private primarySummaryFallbackEnabled(): boolean {
|
|
223
|
+
return this.refusalHandling?.primarySummaryFallback?.enabled === true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private buildPrimarySummaryContractForRequest(request: NormalizedRequest): PrimarySummaryContractWithSystemHash {
|
|
227
|
+
return {
|
|
228
|
+
systemHash: this.hashJson(request.system ?? ''),
|
|
229
|
+
modelConfigHash: this.hashJson({
|
|
230
|
+
requestConfig: request.config,
|
|
231
|
+
providerParams: request.providerParams,
|
|
232
|
+
promptCaching: request.promptCaching,
|
|
233
|
+
cacheTtl: request.cacheTtl,
|
|
234
|
+
assistantParticipant: request.assistantParticipant,
|
|
235
|
+
}),
|
|
236
|
+
toolContractHash: this.hashJson(request.tools ?? []),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private setPrimaryLaneContract(contract: PrimarySummaryContract | undefined): void {
|
|
241
|
+
const manager = this.contextManager as ContextManager & {
|
|
242
|
+
setPrimaryLaneContract?: (value: PrimarySummaryContract | undefined) => void;
|
|
243
|
+
};
|
|
244
|
+
manager.setPrimaryLaneContract?.(contract);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private matchingPrimarySummaryQuarantine(
|
|
248
|
+
projection: PrimarySummaryProjection,
|
|
249
|
+
contract: PrimarySummaryContract,
|
|
250
|
+
): PrimarySummaryIdentity[] {
|
|
251
|
+
const manager = this.contextManager as ContextManager & {
|
|
252
|
+
matchingPrimarySummaryQuarantine?: (
|
|
253
|
+
projection: PrimarySummaryProjection,
|
|
254
|
+
contract?: PrimarySummaryContract,
|
|
255
|
+
) => PrimarySummaryIdentity[];
|
|
256
|
+
};
|
|
257
|
+
return manager.matchingPrimarySummaryQuarantine?.(projection, contract) ?? [];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private expandPrimarySummaryProjectionRaw(
|
|
261
|
+
compiled: CompileResult,
|
|
262
|
+
summaries: ReadonlyArray<PrimarySummaryIdentity>,
|
|
263
|
+
): CompileResult {
|
|
264
|
+
const manager = this.contextManager as ContextManager & {
|
|
265
|
+
expandPrimarySummaryProjectionRaw?: (
|
|
266
|
+
compiled: CompileResult,
|
|
267
|
+
summaries: ReadonlyArray<PrimarySummaryIdentity>,
|
|
268
|
+
) => CompileResult;
|
|
269
|
+
};
|
|
270
|
+
if (typeof manager.expandPrimarySummaryProjectionRaw !== 'function') return compiled;
|
|
271
|
+
return manager.expandPrimarySummaryProjectionRaw(compiled, summaries);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private primarySummaryIdentityKey(identity: PrimarySummaryIdentity): string {
|
|
275
|
+
return [
|
|
276
|
+
identity.id,
|
|
277
|
+
identity.contentHash,
|
|
278
|
+
identity.carrierHash,
|
|
279
|
+
identity.sourceLeafHash,
|
|
280
|
+
].join('\u0000');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private buildRequestFromCompileResult(
|
|
284
|
+
compileResult: CompileResult,
|
|
285
|
+
availableTools: ToolDefinition[],
|
|
286
|
+
): NormalizedRequest {
|
|
287
|
+
let { messages, systemInjections } = compileResult;
|
|
288
|
+
|
|
289
|
+
messages = messages
|
|
290
|
+
.map((m) => ({
|
|
291
|
+
...m,
|
|
292
|
+
content: m.content.filter(
|
|
293
|
+
(b: ContentBlock) => !(b.type === "text" && (typeof b.text !== "string" || b.text.trim() === "")),
|
|
294
|
+
),
|
|
295
|
+
}))
|
|
296
|
+
.filter((m) => m.content.length > 0);
|
|
297
|
+
|
|
298
|
+
if (messages.length > 0 && messages[messages.length - 1]!.participant === this.name) {
|
|
299
|
+
messages = [...messages, {
|
|
300
|
+
participant: 'user',
|
|
301
|
+
content: [{ type: 'text', text: '[Continue]' }],
|
|
302
|
+
}];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
messages,
|
|
307
|
+
system: this.buildSystemPrompt(systemInjections),
|
|
308
|
+
config: {
|
|
309
|
+
model: this.model,
|
|
310
|
+
maxTokens: this.maxTokens,
|
|
311
|
+
...(this.temperature !== undefined && { temperature: this.temperature }),
|
|
312
|
+
...(this.thinking !== undefined && { thinking: this.thinking }),
|
|
313
|
+
},
|
|
314
|
+
tools: availableTools.length > 0 ? availableTools : undefined,
|
|
315
|
+
promptCaching: true,
|
|
316
|
+
cacheTtl: this.cacheTtl,
|
|
317
|
+
...(this.providerParams && { providerParams: this.providerParams }),
|
|
318
|
+
assistantParticipant: this.name,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async prepareActivationRequest(
|
|
323
|
+
availableTools: ToolDefinition[],
|
|
324
|
+
injections?: ContextInjection[],
|
|
325
|
+
budget?: TokenBudget,
|
|
326
|
+
): Promise<{ request: NormalizedRequest; artifacts: ActivationCompileArtifacts }> {
|
|
327
|
+
(this.contextManager as unknown as { setToolDefinitions?: (t: ToolDefinition[]) => void })
|
|
328
|
+
.setToolDefinitions?.(availableTools);
|
|
329
|
+
|
|
330
|
+
let compileResult = await this.compileWithInjections(budget, injections);
|
|
331
|
+
let request = this.buildRequestFromCompileResult(compileResult, availableTools);
|
|
332
|
+
const contract = this.buildPrimarySummaryContractForRequest(request);
|
|
333
|
+
this.setPrimaryLaneContract(contract);
|
|
334
|
+
|
|
335
|
+
const projection = compileResult.primarySummaryProjection;
|
|
336
|
+
if (this.primarySummaryFallbackEnabled() && projection) {
|
|
337
|
+
const quarantined = this.matchingPrimarySummaryQuarantine(projection, contract);
|
|
338
|
+
if (quarantined.length > 0) {
|
|
339
|
+
compileResult = this.expandPrimarySummaryProjectionRaw(compileResult, quarantined);
|
|
340
|
+
request = this.buildRequestFromCompileResult(compileResult, availableTools);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
request,
|
|
346
|
+
artifacts: {
|
|
347
|
+
compileResult,
|
|
348
|
+
contract,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
getRuntimeSettings(): AgentRuntimeSettingsSnapshot {
|
|
354
|
+
const hot = this.getHotContextSettings();
|
|
355
|
+
return {
|
|
356
|
+
contextBudgetTokens:
|
|
357
|
+
this.contextBudgetTargetTokens ??
|
|
358
|
+
this.contextBudgetTokens ??
|
|
359
|
+
DEFAULT_CONTEXT_BUDGET_TOKENS,
|
|
360
|
+
...(hot ? { tailTokens: hot.tailTokens } : {}),
|
|
361
|
+
...(hot?.transitionPaceTokens !== undefined
|
|
362
|
+
? { transitionPaceTokens: hot.transitionPaceTokens }
|
|
363
|
+
: {}),
|
|
364
|
+
sameRoundThinkTextPolicy: this.getEffectiveSameRoundThinkTextPolicy(),
|
|
365
|
+
sameRoundThinkTextPolicySource: this.getSameRoundThinkTextPolicySource(),
|
|
366
|
+
transition: this.contextBudgetTargetTokens === undefined
|
|
367
|
+
? 'stable'
|
|
368
|
+
: hot?.blocked
|
|
369
|
+
? 'blocked'
|
|
370
|
+
: 'converging',
|
|
371
|
+
...(hot?.blocked === 'transition-pace-floor'
|
|
372
|
+
? { transitionReason: 'transition_pace_too_small' as const }
|
|
373
|
+
: hot?.blocked === 'prepared-window-floor'
|
|
374
|
+
? { transitionReason: 'protected_context_exceeds_target' as const }
|
|
375
|
+
: {}),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
getRuntimeSettingsOverrides(): AgentRuntimeSettingsOverrides {
|
|
380
|
+
return { ...this.runtimeSettingsOverrides };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
getEffectiveSameRoundThinkTextPolicy(): SameRoundThinkTextPolicy {
|
|
384
|
+
return this.runtimeSettingsOverrides.sameRoundThinkTextPolicy
|
|
385
|
+
?? this.configuredSameRoundThinkTextPolicy
|
|
386
|
+
?? DEFAULT_SAME_ROUND_THINK_TEXT_POLICY;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
getSameRoundThinkTextPolicySource(): SameRoundThinkTextPolicySource {
|
|
390
|
+
if (this.runtimeSettingsOverrides.sameRoundThinkTextPolicy !== undefined) {
|
|
391
|
+
return 'runtime_override';
|
|
392
|
+
}
|
|
393
|
+
if (this.configuredSameRoundThinkTextPolicy !== undefined) {
|
|
394
|
+
return 'recipe';
|
|
395
|
+
}
|
|
396
|
+
return 'compatibility_default';
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
getCurrentBranchGeneration():
|
|
400
|
+
| { id: string; name: string; head: number; generation: number; parentId?: string; branchPoint?: number; created: Date }
|
|
401
|
+
| null {
|
|
402
|
+
const manager = this.contextManager as ContextManager & {
|
|
403
|
+
currentBranchGeneration?: () => {
|
|
404
|
+
id: string;
|
|
405
|
+
name: string;
|
|
406
|
+
head: number;
|
|
407
|
+
generation: number;
|
|
408
|
+
parentId?: string;
|
|
409
|
+
branchPoint?: number;
|
|
410
|
+
created: Date;
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
return manager.currentBranchGeneration?.() ?? null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
buildPrimarySummaryRawExpansionRequest(
|
|
417
|
+
artifacts: ActivationCompileArtifacts,
|
|
418
|
+
summaries: ReadonlyArray<PrimarySummaryIdentity>,
|
|
419
|
+
availableTools: ToolDefinition[],
|
|
420
|
+
): { request: NormalizedRequest; artifacts: ActivationCompileArtifacts } {
|
|
421
|
+
this.setPrimaryLaneContract(artifacts.contract);
|
|
422
|
+
const alreadyExpanded = new Set(
|
|
423
|
+
artifacts.compileResult.primarySummaryProjection?.selectedSummaries
|
|
424
|
+
.filter((selection) => selection.renderedAs === 'raw_expansion')
|
|
425
|
+
.map((selection) => this.primarySummaryIdentityKey(selection.identity)) ?? [],
|
|
426
|
+
);
|
|
427
|
+
const expandable = summaries.filter((summary) =>
|
|
428
|
+
!alreadyExpanded.has(this.primarySummaryIdentityKey(summary)),
|
|
429
|
+
);
|
|
430
|
+
const compileResult = expandable.length > 0
|
|
431
|
+
? this.expandPrimarySummaryProjectionRaw(
|
|
432
|
+
artifacts.compileResult,
|
|
433
|
+
expandable,
|
|
434
|
+
)
|
|
435
|
+
: artifacts.compileResult;
|
|
436
|
+
return {
|
|
437
|
+
request: this.buildRequestFromCompileResult(compileResult, availableTools),
|
|
438
|
+
artifacts: {
|
|
439
|
+
compileResult,
|
|
440
|
+
contract: artifacts.contract,
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
updateRuntimeSettings(patch: AgentRuntimeSettingsPatch): AgentRuntimeSettingsSnapshot {
|
|
446
|
+
this.validateRuntimeSettingsPatch(patch);
|
|
447
|
+
let nextContextBudget = this.contextBudgetTokens;
|
|
448
|
+
let nextContextTarget = this.contextBudgetTargetTokens;
|
|
449
|
+
let appliedDefaultPace = false;
|
|
450
|
+
const hotPatch: {
|
|
451
|
+
tailTokens?: number;
|
|
452
|
+
transitionPaceTokens?: number | null;
|
|
453
|
+
preparedWindowTokens?: number | null;
|
|
454
|
+
} = {};
|
|
455
|
+
if (patch.tailTokens !== undefined) hotPatch.tailTokens = patch.tailTokens;
|
|
456
|
+
if (patch.transitionPaceTokens !== undefined) {
|
|
457
|
+
hotPatch.transitionPaceTokens = patch.transitionPaceTokens;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (patch.contextBudgetTokens !== undefined) {
|
|
461
|
+
const live = this.contextBudgetTokens ?? DEFAULT_CONTEXT_BUDGET_TOKENS;
|
|
462
|
+
if (patch.contextBudgetTokens >= live) {
|
|
463
|
+
nextContextBudget = patch.contextBudgetTokens;
|
|
464
|
+
nextContextTarget = undefined;
|
|
465
|
+
if (this.getHotContextSettings()) hotPatch.preparedWindowTokens = null;
|
|
466
|
+
} else {
|
|
467
|
+
const hot = this.getHotContextSettings();
|
|
468
|
+
if (!hot) {
|
|
469
|
+
throw new Error('The active context strategy cannot prepare a smaller window live');
|
|
470
|
+
}
|
|
471
|
+
if (patch.transitionPaceTokens === undefined && hot.transitionPaceTokens === undefined) {
|
|
472
|
+
hotPatch.transitionPaceTokens = DEFAULT_TRANSITION_PACE_TOKENS;
|
|
473
|
+
appliedDefaultPace = true;
|
|
474
|
+
}
|
|
475
|
+
hotPatch.preparedWindowTokens = patch.contextBudgetTokens - this.maxTokens;
|
|
476
|
+
nextContextTarget = patch.contextBudgetTokens;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (Object.keys(hotPatch).length > 0) {
|
|
481
|
+
this.updateHotContextSettings(hotPatch);
|
|
482
|
+
}
|
|
483
|
+
this.contextBudgetTokens = nextContextBudget;
|
|
484
|
+
this.contextBudgetTargetTokens = nextContextTarget;
|
|
485
|
+
if (appliedDefaultPace) {
|
|
486
|
+
this.runtimeSettingsOverrides.transitionPaceTokens = DEFAULT_TRANSITION_PACE_TOKENS;
|
|
487
|
+
}
|
|
488
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
489
|
+
if (key === 'sameRoundThinkTextPolicy') continue;
|
|
490
|
+
if (value !== undefined) (this.runtimeSettingsOverrides as Record<string, unknown>)[key] = value;
|
|
491
|
+
}
|
|
492
|
+
if (patch.sameRoundThinkTextPolicy !== undefined) {
|
|
493
|
+
this.runtimeSettingsOverrides.sameRoundThinkTextPolicy = patch.sameRoundThinkTextPolicy;
|
|
494
|
+
}
|
|
495
|
+
return this.getRuntimeSettings();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
resetRuntimeSettings(keys?: Array<keyof AgentRuntimeSettingsPatch>): AgentRuntimeSettingsSnapshot {
|
|
499
|
+
const reset = new Set(keys ?? ['contextBudgetTokens', 'tailTokens', 'transitionPaceTokens', 'sameRoundThinkTextPolicy']);
|
|
500
|
+
let nextContextBudget = this.contextBudgetTokens;
|
|
501
|
+
let nextContextTarget = this.contextBudgetTargetTokens;
|
|
502
|
+
const hotPatch: {
|
|
503
|
+
tailTokens?: number;
|
|
504
|
+
transitionPaceTokens?: number | null;
|
|
505
|
+
preparedWindowTokens?: number | null;
|
|
506
|
+
} = {};
|
|
507
|
+
|
|
508
|
+
if (reset.has('contextBudgetTokens')) {
|
|
509
|
+
const configured = this.configuredContextBudgetTokens ?? DEFAULT_CONTEXT_BUDGET_TOKENS;
|
|
510
|
+
const live = this.contextBudgetTokens ?? DEFAULT_CONTEXT_BUDGET_TOKENS;
|
|
511
|
+
if (configured < live) {
|
|
512
|
+
const hot = this.getHotContextSettings();
|
|
513
|
+
if (!hot) throw new Error('The active context strategy cannot prepare a smaller window live');
|
|
514
|
+
hotPatch.preparedWindowTokens = configured - this.maxTokens;
|
|
515
|
+
if (hot.transitionPaceTokens === undefined) {
|
|
516
|
+
hotPatch.transitionPaceTokens = DEFAULT_TRANSITION_PACE_TOKENS;
|
|
517
|
+
}
|
|
518
|
+
nextContextTarget = configured;
|
|
519
|
+
} else {
|
|
520
|
+
nextContextBudget = this.configuredContextBudgetTokens;
|
|
521
|
+
nextContextTarget = undefined;
|
|
522
|
+
if (this.getHotContextSettings()) hotPatch.preparedWindowTokens = null;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (reset.has('tailTokens')) {
|
|
526
|
+
if (this.configuredTailTokens !== undefined) hotPatch.tailTokens = this.configuredTailTokens;
|
|
527
|
+
}
|
|
528
|
+
if (reset.has('transitionPaceTokens') && this.getHotContextSettings()) {
|
|
529
|
+
hotPatch.transitionPaceTokens =
|
|
530
|
+
nextContextTarget !== undefined && this.configuredTransitionPaceTokens === undefined
|
|
531
|
+
? DEFAULT_TRANSITION_PACE_TOKENS
|
|
532
|
+
: this.configuredTransitionPaceTokens ?? null;
|
|
533
|
+
}
|
|
534
|
+
if (Object.keys(hotPatch).length > 0) this.updateHotContextSettings(hotPatch);
|
|
535
|
+
this.contextBudgetTokens = nextContextBudget;
|
|
536
|
+
this.contextBudgetTargetTokens = nextContextTarget;
|
|
537
|
+
if (reset.has('contextBudgetTokens')) delete this.runtimeSettingsOverrides.contextBudgetTokens;
|
|
538
|
+
if (reset.has('tailTokens')) delete this.runtimeSettingsOverrides.tailTokens;
|
|
539
|
+
if (reset.has('transitionPaceTokens')) {
|
|
540
|
+
delete this.runtimeSettingsOverrides.transitionPaceTokens;
|
|
541
|
+
}
|
|
542
|
+
if (reset.has('sameRoundThinkTextPolicy')) {
|
|
543
|
+
delete this.runtimeSettingsOverrides.sameRoundThinkTextPolicy;
|
|
544
|
+
}
|
|
545
|
+
return this.getRuntimeSettings();
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
cancelRuntimeSettingsTransition(): AgentRuntimeSettingsSnapshot {
|
|
549
|
+
if (this.contextBudgetTargetTokens !== undefined) {
|
|
550
|
+
this.updateHotContextSettings({ preparedWindowTokens: null });
|
|
551
|
+
this.contextBudgetTargetTokens = undefined;
|
|
552
|
+
const live = this.contextBudgetTokens ?? DEFAULT_CONTEXT_BUDGET_TOKENS;
|
|
553
|
+
if (live === (this.configuredContextBudgetTokens ?? DEFAULT_CONTEXT_BUDGET_TOKENS)) {
|
|
554
|
+
delete this.runtimeSettingsOverrides.contextBudgetTokens;
|
|
555
|
+
} else {
|
|
556
|
+
this.runtimeSettingsOverrides.contextBudgetTokens = live;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return this.getRuntimeSettings();
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
restoreRuntimeSettings(overrides: AgentRuntimeSettingsOverrides): AgentRuntimeSettingsSnapshot {
|
|
563
|
+
return this.updateRuntimeSettings(overrides);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
private validateRuntimeSettingsPatch(patch: AgentRuntimeSettingsPatch): void {
|
|
567
|
+
if (Object.keys(patch).length === 0) throw new Error('At least one setting is required');
|
|
568
|
+
if (patch.contextBudgetTokens !== undefined) {
|
|
569
|
+
if (!Number.isSafeInteger(patch.contextBudgetTokens) || patch.contextBudgetTokens <= this.maxTokens) {
|
|
570
|
+
throw new Error(`contextBudgetTokens must be a safe integer greater than max response tokens (${this.maxTokens})`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (patch.tailTokens !== undefined &&
|
|
574
|
+
(!Number.isSafeInteger(patch.tailTokens) || patch.tailTokens < 0)) {
|
|
575
|
+
throw new Error('tailTokens must be a non-negative safe integer');
|
|
576
|
+
}
|
|
577
|
+
if (patch.transitionPaceTokens !== undefined &&
|
|
578
|
+
(!Number.isSafeInteger(patch.transitionPaceTokens) || patch.transitionPaceTokens <= 0)) {
|
|
579
|
+
throw new Error('transitionPaceTokens must be a positive safe integer');
|
|
580
|
+
}
|
|
581
|
+
if (patch.sameRoundThinkTextPolicy !== undefined &&
|
|
582
|
+
patch.sameRoundThinkTextPolicy !== 'public' &&
|
|
583
|
+
patch.sameRoundThinkTextPolicy !== 'private') {
|
|
584
|
+
throw new Error("sameRoundThinkTextPolicy must be 'public' or 'private'");
|
|
585
|
+
}
|
|
586
|
+
if ((patch.tailTokens !== undefined || patch.transitionPaceTokens !== undefined) &&
|
|
587
|
+
!this.getHotContextSettings()) {
|
|
588
|
+
throw new Error('The active context strategy does not support live tail/transition settings');
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
private settleRuntimeSettingsTransition(): void {
|
|
593
|
+
if (this.contextBudgetTargetTokens === undefined) return;
|
|
594
|
+
const hot = this.getHotContextSettings();
|
|
595
|
+
if (!hot?.prepared) return;
|
|
596
|
+
this.contextBudgetTokens = this.contextBudgetTargetTokens;
|
|
597
|
+
this.contextBudgetTargetTokens = undefined;
|
|
598
|
+
this.updateHotContextSettings({ preparedWindowTokens: null });
|
|
599
|
+
}
|
|
600
|
+
|
|
151
601
|
async compileContext(budget?: TokenBudget): Promise<CompileResult> {
|
|
152
|
-
|
|
602
|
+
const result = await this.contextManager.compile(this.resolveBudget(budget));
|
|
603
|
+
if (!budget) this.settleRuntimeSettingsTransition();
|
|
604
|
+
return result;
|
|
153
605
|
}
|
|
154
606
|
|
|
155
607
|
/**
|
|
@@ -161,7 +613,9 @@ export class Agent {
|
|
|
161
613
|
budget?: TokenBudget,
|
|
162
614
|
injections?: ContextInjection[]
|
|
163
615
|
): Promise<CompileResult> {
|
|
164
|
-
|
|
616
|
+
const result = await this.contextManager.compile(this.resolveBudget(budget), injections);
|
|
617
|
+
if (!budget) this.settleRuntimeSettingsTransition();
|
|
618
|
+
return result;
|
|
165
619
|
}
|
|
166
620
|
|
|
167
621
|
// ==========================================================================
|
|
@@ -329,64 +783,8 @@ export class Agent {
|
|
|
329
783
|
injections?: ContextInjection[],
|
|
330
784
|
budget?: TokenBudget
|
|
331
785
|
): Promise<NormalizedRequest> {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
// summarizer/compression requests, or transcripts containing tool blocks
|
|
335
|
-
// are refused by Anthropic's reasoning_extraction classifier (labclaude
|
|
336
|
-
// incident, 2026-07-09). Optional chaining: older context-manager
|
|
337
|
-
// versions don't have the hook.
|
|
338
|
-
(this.contextManager as unknown as { setToolDefinitions?: (t: ToolDefinition[]) => void })
|
|
339
|
-
.setToolDefinitions?.(availableTools);
|
|
340
|
-
|
|
341
|
-
let { messages, systemInjections } = await this.compileWithInjections(budget, injections);
|
|
342
|
-
|
|
343
|
-
// Sanitize: strip empty/whitespace text blocks and drop messages left with
|
|
344
|
-
// no content. The Anthropic API rejects empty text blocks with 400
|
|
345
|
-
// "messages: text content blocks must be non-empty"; when such a block
|
|
346
|
-
// reaches a live activation request the agent cannot complete ANY turn
|
|
347
|
-
// ([inference-failed] on every attempt) until the offending message ages
|
|
348
|
-
// out of the window. Empty text blocks occur naturally: tool-only turns,
|
|
349
|
-
// delivery-failure placeholders, silent/skip turns. Non-text blocks pass
|
|
350
|
-
// through unchanged, so tool pairing is unaffected. (Field-observed
|
|
351
|
-
// 2026-07-10 on a resident agent: one empty block muted the agent's live
|
|
352
|
-
// path entirely; twin of context-manager's stripEmptyTextBlocks on the
|
|
353
|
-
// compression path.)
|
|
354
|
-
messages = messages
|
|
355
|
-
.map((m) => ({
|
|
356
|
-
...m,
|
|
357
|
-
content: m.content.filter(
|
|
358
|
-
// typeof guard is deliberate runtime defense: history loaded from
|
|
359
|
-
// disk can carry a non-string `text` despite what the types claim.
|
|
360
|
-
(b: ContentBlock) => !(b.type === "text" && (typeof b.text !== "string" || b.text.trim() === "")),
|
|
361
|
-
),
|
|
362
|
-
}))
|
|
363
|
-
.filter((m) => m.content.length > 0);
|
|
364
|
-
|
|
365
|
-
// Safety: ensure messages don't end with an assistant message.
|
|
366
|
-
// Some models reject trailing assistant messages ("prefill not supported"),
|
|
367
|
-
// and after context compression a stale assistant turn can end up last.
|
|
368
|
-
if (messages.length > 0 && messages[messages.length - 1]!.participant === this.name) {
|
|
369
|
-
messages = [...messages, {
|
|
370
|
-
participant: 'user',
|
|
371
|
-
content: [{ type: 'text', text: '[Continue]' }],
|
|
372
|
-
}];
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return {
|
|
376
|
-
messages,
|
|
377
|
-
system: this.buildSystemPrompt(systemInjections),
|
|
378
|
-
config: {
|
|
379
|
-
model: this.model,
|
|
380
|
-
maxTokens: this.maxTokens,
|
|
381
|
-
...(this.temperature !== undefined && { temperature: this.temperature }),
|
|
382
|
-
...(this.thinking !== undefined && { thinking: this.thinking }),
|
|
383
|
-
},
|
|
384
|
-
tools: availableTools.length > 0 ? availableTools : undefined,
|
|
385
|
-
promptCaching: true,
|
|
386
|
-
cacheTtl: this.cacheTtl,
|
|
387
|
-
...(this.providerParams && { providerParams: this.providerParams }),
|
|
388
|
-
assistantParticipant: this.name,
|
|
389
|
-
};
|
|
786
|
+
const { request } = await this.prepareActivationRequest(availableTools, injections, budget);
|
|
787
|
+
return request;
|
|
390
788
|
}
|
|
391
789
|
|
|
392
790
|
/**
|
|
@@ -406,7 +804,11 @@ export class Agent {
|
|
|
406
804
|
this._inferenceStartedAt = Date.now();
|
|
407
805
|
this.lastStreamInputTokens = 0;
|
|
408
806
|
|
|
409
|
-
const request = await this.
|
|
807
|
+
const { request, artifacts } = await this.prepareActivationRequest(
|
|
808
|
+
availableTools,
|
|
809
|
+
injections,
|
|
810
|
+
budget,
|
|
811
|
+
);
|
|
410
812
|
|
|
411
813
|
const stream = this.membrane.streamYielding(request, {
|
|
412
814
|
emitTokens: true,
|
|
@@ -415,7 +817,27 @@ export class Agent {
|
|
|
415
817
|
});
|
|
416
818
|
|
|
417
819
|
this._state = { status: 'streaming', stream };
|
|
418
|
-
return { stream, request };
|
|
820
|
+
return { stream, request, artifacts };
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
startStreamFromRequest(
|
|
824
|
+
request: NormalizedRequest,
|
|
825
|
+
artifacts: ActivationCompileArtifacts,
|
|
826
|
+
): StartStreamResult {
|
|
827
|
+
if (this._state.status !== 'streaming' && this._state.status !== 'idle') {
|
|
828
|
+
throw new Error(`Agent ${this.name} cannot replace stream in state ${this._state.status}`);
|
|
829
|
+
}
|
|
830
|
+
this._streamId++;
|
|
831
|
+
this._inferenceStartedAt = Date.now();
|
|
832
|
+
this.lastStreamInputTokens = 0;
|
|
833
|
+
this.setPrimaryLaneContract(artifacts.contract);
|
|
834
|
+
const stream = this.membrane.streamYielding(request, {
|
|
835
|
+
emitTokens: true,
|
|
836
|
+
emitBlocks: false,
|
|
837
|
+
emitUsage: true,
|
|
838
|
+
});
|
|
839
|
+
this._state = { status: 'streaming', stream };
|
|
840
|
+
return { stream, request, artifacts };
|
|
419
841
|
}
|
|
420
842
|
|
|
421
843
|
/**
|