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 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 70-behavior native contract; 62 behaviors
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 || cause instanceof AgentRunCancelledError)
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 activeTurnInputs;
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 {};