praxis-agent 0.55.0 → 0.55.2
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 +1 -1
- package/dist/application/context-engine.js +4 -1
- package/dist/application/context-preparation.d.ts +60 -0
- package/dist/application/context-preparation.js +139 -0
- package/dist/application/session-service.d.ts +1 -8
- package/dist/application/session-service.js +362 -844
- package/dist/application/turn-accounting.d.ts +74 -0
- package/dist/application/turn-accounting.js +444 -0
- package/dist/application/turn-lifecycle.d.ts +21 -9
- package/dist/application/turn-lifecycle.js +141 -27
- package/dist/application/turn-persistence.d.ts +62 -0
- package/dist/application/turn-persistence.js +114 -0
- package/dist/cli/protocol.d.ts +16 -4
- package/dist/cli/protocol.js +136 -100
- package/dist/cli-runtime.js +10 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -347,7 +347,7 @@ normal/low-capability full-frame p95 budgets of `<16.7/<33 ms`.
|
|
|
347
347
|
`npm run test:coverage` measures all production code under `src/**` with V8 and
|
|
348
348
|
enforces global floors of 79% statements, 70% branches, 85% functions, and 81% lines,
|
|
349
349
|
and rejects any production runtime module with zero covered statements (while allowing
|
|
350
|
-
type-only modules). `npm run test:fixtures` executes the
|
|
350
|
+
type-only modules). `npm run test:fixtures` executes the 71-behavior native contract; 63 behaviors
|
|
351
351
|
are qualified and 8 are explicitly excluded. `npm run verify:fixture-contracts`
|
|
352
352
|
performs the structural check and is part of `npm run check`.
|
|
353
353
|
`npm run test:core-completion` is retained as a compatibility alias for
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AgentRunCancelledError, } from '../core/runtime.js';
|
|
2
2
|
import { contextRecoveryMadeProgress, isPromptTooLongError, } from '../core/context-budget.js';
|
|
3
|
+
import { StaleContextGenerationError } from './context-preparation.js';
|
|
3
4
|
function assertSignal(signal) {
|
|
4
5
|
if (signal?.aborted)
|
|
5
6
|
throw new AgentRunCancelledError();
|
|
@@ -95,7 +96,9 @@ export class ContextEngine {
|
|
|
95
96
|
return { kind: 'retry', envelope: proposal.envelope };
|
|
96
97
|
}
|
|
97
98
|
catch (cause) {
|
|
98
|
-
if (signal?.aborted ||
|
|
99
|
+
if (signal?.aborted ||
|
|
100
|
+
cause instanceof AgentRunCancelledError ||
|
|
101
|
+
cause instanceof StaleContextGenerationError)
|
|
99
102
|
throw cause;
|
|
100
103
|
return { kind: 'exhausted', error };
|
|
101
104
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type ContextAssembler, type ContextAssemblyOptions } from '../core/context.js';
|
|
2
|
+
import type { ModelMessage, ModelToolDefinition } from '../core/runtime.js';
|
|
3
|
+
import type { ContextEnvelope } from './context-engine.js';
|
|
4
|
+
export interface ContextPreparationProjection {
|
|
5
|
+
readonly generation: number;
|
|
6
|
+
readonly envelope: ContextEnvelope;
|
|
7
|
+
readonly stableSystemMessageCount: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ContextPreparationSources {
|
|
10
|
+
readonly history: () => readonly ModelMessage[];
|
|
11
|
+
readonly memory: () => readonly ModelMessage[];
|
|
12
|
+
readonly activeTools: () => readonly ModelToolDefinition[];
|
|
13
|
+
}
|
|
14
|
+
export interface ContextPreparationProjectOptions {
|
|
15
|
+
readonly includeHistory?: boolean;
|
|
16
|
+
readonly includeMemory?: boolean;
|
|
17
|
+
readonly pendingMessages?: readonly ModelMessage[];
|
|
18
|
+
}
|
|
19
|
+
export interface ContextHistoryReplacement {
|
|
20
|
+
readonly generation: number;
|
|
21
|
+
readonly envelope: ContextEnvelope;
|
|
22
|
+
readonly stableSystemMessageCount: number;
|
|
23
|
+
commit<T>(replace: () => Promise<T>): Promise<{
|
|
24
|
+
generation: number;
|
|
25
|
+
value: T;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export declare class StaleContextGenerationError extends Error {
|
|
29
|
+
readonly expectedGeneration: number;
|
|
30
|
+
readonly actualGeneration: number;
|
|
31
|
+
constructor(expectedGeneration: number, actualGeneration: number);
|
|
32
|
+
}
|
|
33
|
+
export interface ContextPreparationOptions {
|
|
34
|
+
readonly assembler?: ContextAssembler;
|
|
35
|
+
readonly sources: ContextPreparationSources;
|
|
36
|
+
readonly agentMentions?: () => {
|
|
37
|
+
readonly prompt: string;
|
|
38
|
+
readonly messages: readonly string[];
|
|
39
|
+
};
|
|
40
|
+
readonly initialGeneration?: number;
|
|
41
|
+
}
|
|
42
|
+
/** Owns provider-visible context projection and guarded history replacement. */
|
|
43
|
+
export declare class ContextPreparation {
|
|
44
|
+
private readonly assembler;
|
|
45
|
+
private readonly sources;
|
|
46
|
+
private readonly agentMentions;
|
|
47
|
+
private generation;
|
|
48
|
+
private prepared;
|
|
49
|
+
private replacementQueue;
|
|
50
|
+
constructor(options: ContextPreparationOptions);
|
|
51
|
+
refresh(options?: ContextAssemblyOptions): Promise<void>;
|
|
52
|
+
project(options?: ContextPreparationProjectOptions): ContextPreparationProjection;
|
|
53
|
+
proposeHistoryReplacement(input: {
|
|
54
|
+
readonly historyMessages: readonly ModelMessage[];
|
|
55
|
+
readonly pendingMessages?: readonly ModelMessage[];
|
|
56
|
+
}): ContextHistoryReplacement;
|
|
57
|
+
private projectWithMessages;
|
|
58
|
+
private decorate;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=context-preparation.d.ts.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { injectFirstUserMessageContext, projectContextSnapshot, } from '../core/context.js';
|
|
2
|
+
import { assembleContextSnapshot } from '../core/prompt-composer.js';
|
|
3
|
+
export class StaleContextGenerationError extends Error {
|
|
4
|
+
expectedGeneration;
|
|
5
|
+
actualGeneration;
|
|
6
|
+
constructor(expectedGeneration, actualGeneration) {
|
|
7
|
+
super(`Stale context generation: expected ${expectedGeneration}, actual ${actualGeneration}; prepare a new history replacement`);
|
|
8
|
+
this.name = 'StaleContextGenerationError';
|
|
9
|
+
this.expectedGeneration = expectedGeneration;
|
|
10
|
+
this.actualGeneration = actualGeneration;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function validateGeneration(generation) {
|
|
14
|
+
if (!Number.isSafeInteger(generation) || generation < 1) {
|
|
15
|
+
throw new TypeError('Context generation must be a positive safe integer');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function cloneTools(tools) {
|
|
19
|
+
return tools.map((tool) => ({ ...tool }));
|
|
20
|
+
}
|
|
21
|
+
/** Owns provider-visible context projection and guarded history replacement. */
|
|
22
|
+
export class ContextPreparation {
|
|
23
|
+
assembler;
|
|
24
|
+
sources;
|
|
25
|
+
agentMentions;
|
|
26
|
+
generation;
|
|
27
|
+
prepared;
|
|
28
|
+
replacementQueue = Promise.resolve();
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.assembler = options.assembler;
|
|
31
|
+
this.sources = options.sources;
|
|
32
|
+
this.agentMentions = options.agentMentions;
|
|
33
|
+
this.generation = options.initialGeneration ?? 1;
|
|
34
|
+
validateGeneration(this.generation);
|
|
35
|
+
}
|
|
36
|
+
async refresh(options = {}) {
|
|
37
|
+
const snapshot = await assembleContextSnapshot(this.assembler, options);
|
|
38
|
+
const projection = projectContextSnapshot(snapshot);
|
|
39
|
+
const stableCount = projection.stableSystemSectionCount;
|
|
40
|
+
const prepared = {
|
|
41
|
+
stableSystemMessages: projection.systemMessages.slice(0, stableCount),
|
|
42
|
+
volatileSystemMessages: projection.systemMessages.slice(stableCount),
|
|
43
|
+
...(projection.firstUserMessageContext === undefined
|
|
44
|
+
? {}
|
|
45
|
+
: { firstUserMessageContext: projection.firstUserMessageContext }),
|
|
46
|
+
stableSystemMessageCount: stableCount,
|
|
47
|
+
};
|
|
48
|
+
this.prepared = prepared;
|
|
49
|
+
}
|
|
50
|
+
project(options = {}) {
|
|
51
|
+
return this.projectWithMessages((options.includeHistory ?? true) ? this.sources.history() : [], (options.includeMemory ?? true) ? this.sources.memory() : [], options.pendingMessages ?? []);
|
|
52
|
+
}
|
|
53
|
+
proposeHistoryReplacement(input) {
|
|
54
|
+
const baseGeneration = this.generation;
|
|
55
|
+
if (baseGeneration === Number.MAX_SAFE_INTEGER) {
|
|
56
|
+
throw new RangeError('Context generation cannot exceed Number.MAX_SAFE_INTEGER');
|
|
57
|
+
}
|
|
58
|
+
const generation = baseGeneration + 1;
|
|
59
|
+
const projection = this.projectWithMessages(input.historyMessages, [], input.pendingMessages ?? []);
|
|
60
|
+
let committed = false;
|
|
61
|
+
return {
|
|
62
|
+
generation,
|
|
63
|
+
envelope: projection.envelope,
|
|
64
|
+
stableSystemMessageCount: projection.stableSystemMessageCount,
|
|
65
|
+
commit: async (replace) => {
|
|
66
|
+
const operation = this.replacementQueue.then(async () => {
|
|
67
|
+
if (this.generation !== baseGeneration) {
|
|
68
|
+
throw new StaleContextGenerationError(baseGeneration, this.generation);
|
|
69
|
+
}
|
|
70
|
+
if (committed) {
|
|
71
|
+
throw new StaleContextGenerationError(baseGeneration, this.generation);
|
|
72
|
+
}
|
|
73
|
+
const value = await replace();
|
|
74
|
+
this.generation = generation;
|
|
75
|
+
committed = true;
|
|
76
|
+
return { generation, value };
|
|
77
|
+
});
|
|
78
|
+
this.replacementQueue = operation.then(() => undefined, () => undefined);
|
|
79
|
+
return operation;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
projectWithMessages(historyMessages, memoryMessages, pendingMessages) {
|
|
84
|
+
const prepared = this.prepared;
|
|
85
|
+
if (!prepared) {
|
|
86
|
+
throw new Error('ContextPreparation must be refreshed before projecting');
|
|
87
|
+
}
|
|
88
|
+
const history = [...historyMessages];
|
|
89
|
+
const memory = [...memoryMessages];
|
|
90
|
+
const pending = [...pendingMessages];
|
|
91
|
+
const decoratedHistory = this.decorate([...history, ...memory, ...pending]);
|
|
92
|
+
const messages = [
|
|
93
|
+
...prepared.stableSystemMessages,
|
|
94
|
+
...prepared.volatileSystemMessages,
|
|
95
|
+
...decoratedHistory,
|
|
96
|
+
];
|
|
97
|
+
return {
|
|
98
|
+
generation: this.generation,
|
|
99
|
+
envelope: {
|
|
100
|
+
messages,
|
|
101
|
+
tools: cloneTools(this.sources.activeTools()),
|
|
102
|
+
},
|
|
103
|
+
stableSystemMessageCount: prepared.stableSystemMessageCount,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
decorate(messages) {
|
|
107
|
+
const prepared = this.prepared;
|
|
108
|
+
if (!prepared) {
|
|
109
|
+
throw new Error('ContextPreparation must be refreshed before projecting');
|
|
110
|
+
}
|
|
111
|
+
const withFirstUserContext = injectFirstUserMessageContext(messages, prepared.firstUserMessageContext);
|
|
112
|
+
const mentionInput = this.agentMentions?.();
|
|
113
|
+
if (!mentionInput || mentionInput.messages.length === 0)
|
|
114
|
+
return withFirstUserContext;
|
|
115
|
+
let insertionIndex = withFirstUserContext.length;
|
|
116
|
+
let foundPrompt = false;
|
|
117
|
+
for (let index = withFirstUserContext.length - 1; index >= 0; index -= 1) {
|
|
118
|
+
const message = withFirstUserContext[index];
|
|
119
|
+
if (message?.role === 'user' &&
|
|
120
|
+
typeof message.content === 'string' &&
|
|
121
|
+
message.content.endsWith(mentionInput.prompt)) {
|
|
122
|
+
insertionIndex = index;
|
|
123
|
+
foundPrompt = true;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!foundPrompt)
|
|
128
|
+
return withFirstUserContext;
|
|
129
|
+
return [
|
|
130
|
+
...withFirstUserContext.slice(0, insertionIndex),
|
|
131
|
+
...mentionInput.messages.map((content) => ({
|
|
132
|
+
role: 'user',
|
|
133
|
+
content,
|
|
134
|
+
})),
|
|
135
|
+
...withFirstUserContext.slice(insertionIndex),
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=context-preparation.js.map
|
|
@@ -236,7 +236,7 @@ export declare class ClaudeSessionService {
|
|
|
236
236
|
private readonly hookLifecycle;
|
|
237
237
|
private readonly leadOperations;
|
|
238
238
|
private readonly fileChangeWatcher;
|
|
239
|
-
private readonly
|
|
239
|
+
private readonly turnCoordinator;
|
|
240
240
|
private runtimeCwd;
|
|
241
241
|
constructor(options: ClaudeSessionServiceOptions);
|
|
242
242
|
nextScheduledPrompt(signal?: AbortSignal): Promise<ScheduledPrompt | null>;
|
|
@@ -374,13 +374,6 @@ export declare class ClaudeSessionService {
|
|
|
374
374
|
private toolCapabilities;
|
|
375
375
|
private capabilityToolNames;
|
|
376
376
|
private teamRegistry;
|
|
377
|
-
private append;
|
|
378
|
-
/**
|
|
379
|
-
* Update the in-memory compatibility projection used by the turn pipeline.
|
|
380
|
-
* Authoritative native persistence is performed by NativeSessionTranscript;
|
|
381
|
-
* these entries are never written to the native event store.
|
|
382
|
-
*/
|
|
383
|
-
private appendProjectionMany;
|
|
384
377
|
private logicalTailUuid;
|
|
385
378
|
}
|
|
386
379
|
export {};
|