praxis-agent 0.55.1 → 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.
@@ -243,11 +243,9 @@ export declare function parseCliInvocation(argv: readonly string[]): CliInvocati
243
243
  export declare function readStreamJsonMessages(input: AsyncIterable<string | Uint8Array>): AsyncGenerator<StreamJsonMessage>;
244
244
  export declare function readStreamUserMessages(input: AsyncIterable<string | Uint8Array>): AsyncGenerator<StreamUserMessage>;
245
245
  export declare class StreamJsonOutput {
246
- private readonly write;
246
+ private readonly emitRaw;
247
247
  private readonly info;
248
248
  private readonly sessionId;
249
- private readonly includePartialMessages;
250
- private readonly includeHookEvents;
251
249
  private turnId;
252
250
  private turnText;
253
251
  private turnThinking;
@@ -263,7 +261,17 @@ export declare class StreamJsonOutput {
263
261
  private modelTurns;
264
262
  private compacting;
265
263
  private sessionState;
266
- constructor(write: (value: unknown) => void, info: CliRuntimeInfo, sessionId: string, includePartialMessages: boolean, includeHookEvents?: boolean);
264
+ private readonly emitSessionStateEvents;
265
+ private partialEvents;
266
+ private pendingPartialStop;
267
+ constructor(emitRaw: (value: unknown) => void, info: CliRuntimeInfo, sessionId: string, options: {
268
+ includePartialMessages: boolean;
269
+ includeHookEvents?: boolean;
270
+ emitSessionStateEvents?: boolean;
271
+ });
272
+ private readonly includePartialMessages;
273
+ private readonly includeHookEvents;
274
+ private write;
267
275
  init(): void;
268
276
  replayUser(message: StreamUserMessage['message']): void;
269
277
  /**
@@ -282,11 +290,15 @@ export declare class StreamJsonOutput {
282
290
  error(message: string, startedAt: number): void;
283
291
  private onEvent;
284
292
  private writeSessionState;
293
+ private writeTerminalIdle;
285
294
  private ensureTurn;
286
295
  private discardTurn;
287
296
  private startTurn;
297
+ private writePartialMessageStart;
288
298
  private partialText;
299
+ private beginPartialBlock;
289
300
  private finishPartial;
301
+ private finishPartialTail;
290
302
  private flushAssistant;
291
303
  private finishTurn;
292
304
  }
@@ -1694,11 +1694,9 @@ export async function* readStreamUserMessages(input) {
1694
1694
  }
1695
1695
  const emptyUsage = () => ({ inputTokens: 0, outputTokens: 0 });
1696
1696
  export class StreamJsonOutput {
1697
- write;
1697
+ emitRaw;
1698
1698
  info;
1699
1699
  sessionId;
1700
- includePartialMessages;
1701
- includeHookEvents;
1702
1700
  turnId = randomUUID();
1703
1701
  turnText = '';
1704
1702
  turnThinking = [];
@@ -1714,14 +1712,28 @@ export class StreamJsonOutput {
1714
1712
  modelTurns = 0;
1715
1713
  compacting = false;
1716
1714
  sessionState;
1717
- constructor(write, info, sessionId, includePartialMessages, includeHookEvents = false) {
1718
- this.write = write;
1715
+ emitSessionStateEvents;
1716
+ partialEvents = [];
1717
+ pendingPartialStop;
1718
+ constructor(emitRaw, info, sessionId, options) {
1719
+ this.emitRaw = emitRaw;
1719
1720
  this.info = info;
1720
1721
  this.sessionId = sessionId;
1721
- this.includePartialMessages = includePartialMessages;
1722
- this.includeHookEvents = includeHookEvents;
1722
+ this.includePartialMessages = options.includePartialMessages;
1723
+ this.includeHookEvents = options.includeHookEvents ?? false;
1724
+ this.emitSessionStateEvents = options.emitSessionStateEvents ?? false;
1725
+ }
1726
+ includePartialMessages;
1727
+ includeHookEvents;
1728
+ write(value) {
1729
+ this.emitRaw({
1730
+ ...value,
1731
+ uuid: value.uuid ?? randomUUID(),
1732
+ session_id: value.session_id ?? this.sessionId,
1733
+ });
1723
1734
  }
1724
1735
  init() {
1736
+ this.writeSessionState('running');
1725
1737
  this.write({
1726
1738
  type: 'system',
1727
1739
  subtype: 'init',
@@ -1740,7 +1752,6 @@ export class StreamJsonOutput {
1740
1752
  output_style: 'default',
1741
1753
  plugins: this.info.plugins ?? [],
1742
1754
  fast_mode_state: 'off',
1743
- uuid: randomUUID(),
1744
1755
  });
1745
1756
  }
1746
1757
  replayUser(message) {
@@ -1775,6 +1786,7 @@ export class StreamJsonOutput {
1775
1786
  result(result, startedAt) {
1776
1787
  this.finishTurn();
1777
1788
  this.write(createSuccessResult(result, this.info, startedAt, this.modelTurns));
1789
+ this.writeTerminalIdle();
1778
1790
  this.modelTurns = 0;
1779
1791
  }
1780
1792
  promptSuggestion(suggestion) {
@@ -1788,6 +1800,7 @@ export class StreamJsonOutput {
1788
1800
  error(message, startedAt) {
1789
1801
  this.finishTurn();
1790
1802
  this.write(createErrorResult(message, this.sessionId, startedAt, this.modelTurns));
1803
+ this.writeTerminalIdle();
1791
1804
  this.modelTurns = 0;
1792
1805
  }
1793
1806
  onEvent(event) {
@@ -1831,11 +1844,6 @@ export class StreamJsonOutput {
1831
1844
  this.flushAssistant();
1832
1845
  if (event.state === 'awaiting-permission')
1833
1846
  this.writeSessionState('requires_action');
1834
- else if (event.state === 'completed' ||
1835
- event.state === 'cancelled' ||
1836
- event.state === 'failed') {
1837
- this.writeSessionState('idle');
1838
- }
1839
1847
  }
1840
1848
  return;
1841
1849
  }
@@ -1853,7 +1861,7 @@ export class StreamJsonOutput {
1853
1861
  }
1854
1862
  this.activeThinkingIndex = this.nextContentIndex;
1855
1863
  this.nextContentIndex += 1;
1856
- this.write({
1864
+ this.beginPartialBlock({
1857
1865
  type: 'stream_event',
1858
1866
  event: {
1859
1867
  type: 'content_block_start',
@@ -1862,6 +1870,14 @@ export class StreamJsonOutput {
1862
1870
  },
1863
1871
  parent_tool_use_id: null,
1864
1872
  session_id: this.sessionId,
1873
+ }, {
1874
+ type: 'stream_event',
1875
+ event: {
1876
+ type: 'content_block_stop',
1877
+ index: this.activeThinkingIndex,
1878
+ },
1879
+ parent_tool_use_id: null,
1880
+ session_id: this.sessionId,
1865
1881
  });
1866
1882
  }
1867
1883
  return;
@@ -1873,7 +1889,7 @@ export class StreamJsonOutput {
1873
1889
  if (this.activeThinkingIndex === undefined) {
1874
1890
  throw new Error('Thinking delta arrived without an active block');
1875
1891
  }
1876
- this.write({
1892
+ this.partialEvents.push({
1877
1893
  type: 'stream_event',
1878
1894
  event: {
1879
1895
  type: 'content_block_delta',
@@ -1895,22 +1911,13 @@ export class StreamJsonOutput {
1895
1911
  if (this.activeThinkingIndex === undefined) {
1896
1912
  throw new Error('Thinking block stopped without an active block');
1897
1913
  }
1898
- this.write({
1899
- type: 'stream_event',
1900
- event: {
1901
- type: 'content_block_stop',
1902
- index: this.activeThinkingIndex,
1903
- },
1904
- parent_tool_use_id: null,
1905
- session_id: this.sessionId,
1906
- });
1907
1914
  this.activeThinkingIndex = undefined;
1908
1915
  }
1909
1916
  return;
1910
1917
  }
1911
1918
  if (event.type === 'user-message') {
1912
1919
  this.write({
1913
- type: 'user_message',
1920
+ type: 'user',
1914
1921
  message: event.message,
1915
1922
  status: event.status,
1916
1923
  ...(event.attachments?.length
@@ -1924,6 +1931,42 @@ export class StreamJsonOutput {
1924
1931
  if (event.type === 'tool-call') {
1925
1932
  this.ensureTurn();
1926
1933
  this.turnCalls.push(event.call);
1934
+ if (this.includePartialMessages) {
1935
+ const index = this.nextContentIndex++;
1936
+ this.beginPartialBlock({
1937
+ type: 'stream_event',
1938
+ event: {
1939
+ type: 'content_block_start',
1940
+ index,
1941
+ content_block: {
1942
+ type: 'tool_use',
1943
+ id: event.call.id,
1944
+ name: event.call.name,
1945
+ input: {},
1946
+ },
1947
+ },
1948
+ parent_tool_use_id: null,
1949
+ session_id: this.sessionId,
1950
+ }, {
1951
+ type: 'stream_event',
1952
+ event: { type: 'content_block_stop', index },
1953
+ parent_tool_use_id: null,
1954
+ session_id: this.sessionId,
1955
+ });
1956
+ this.partialEvents.push({
1957
+ type: 'stream_event',
1958
+ event: {
1959
+ type: 'content_block_delta',
1960
+ index,
1961
+ delta: {
1962
+ type: 'input_json_delta',
1963
+ partial_json: JSON.stringify(event.call.input),
1964
+ },
1965
+ },
1966
+ parent_tool_use_id: null,
1967
+ session_id: this.sessionId,
1968
+ });
1969
+ }
1927
1970
  return;
1928
1971
  }
1929
1972
  if (event.type === 'usage') {
@@ -2062,13 +2105,7 @@ export class StreamJsonOutput {
2062
2105
  return;
2063
2106
  }
2064
2107
  if (event.type === 'session-state-changed') {
2065
- this.write({
2066
- type: 'system',
2067
- subtype: 'session_state_changed',
2068
- state: event.state,
2069
- uuid: randomUUID(),
2070
- session_id: this.sessionId,
2071
- });
2108
+ this.writeSessionState(event.state);
2072
2109
  return;
2073
2110
  }
2074
2111
  if (event.type === 'api-retry') {
@@ -2135,12 +2172,15 @@ export class StreamJsonOutput {
2135
2172
  this.partialText(event.message);
2136
2173
  }
2137
2174
  this.flushAssistant();
2138
- this.writeSessionState('idle');
2139
2175
  }
2140
2176
  }
2141
2177
  writeSessionState(state) {
2178
+ if (!this.emitSessionStateEvents)
2179
+ return;
2142
2180
  if (this.sessionState === state)
2143
2181
  return;
2182
+ if (state === 'idle')
2183
+ return;
2144
2184
  this.sessionState = state;
2145
2185
  this.write({
2146
2186
  type: 'system',
@@ -2150,6 +2190,16 @@ export class StreamJsonOutput {
2150
2190
  session_id: this.sessionId,
2151
2191
  });
2152
2192
  }
2193
+ writeTerminalIdle() {
2194
+ if (!this.emitSessionStateEvents || this.sessionState === 'idle')
2195
+ return;
2196
+ this.sessionState = 'idle';
2197
+ this.write({
2198
+ type: 'system',
2199
+ subtype: 'session_state_changed',
2200
+ state: 'idle',
2201
+ });
2202
+ }
2153
2203
  ensureTurn() {
2154
2204
  if (!this.turnActive)
2155
2205
  this.startTurn();
@@ -2173,6 +2223,8 @@ export class StreamJsonOutput {
2173
2223
  this.textContentIndex = undefined;
2174
2224
  this.activeThinkingIndex = undefined;
2175
2225
  this.nextContentIndex = 0;
2226
+ this.partialEvents = [];
2227
+ this.pendingPartialStop = undefined;
2176
2228
  }
2177
2229
  startTurn() {
2178
2230
  if (this.turnActive)
@@ -2189,28 +2241,37 @@ export class StreamJsonOutput {
2189
2241
  this.textContentIndex = undefined;
2190
2242
  this.activeThinkingIndex = undefined;
2191
2243
  this.nextContentIndex = 0;
2244
+ this.partialEvents = [];
2245
+ this.pendingPartialStop = undefined;
2192
2246
  this.modelTurns += 1;
2193
2247
  if (this.includePartialMessages) {
2194
2248
  this.write({
2195
- type: 'stream_event',
2196
- event: {
2197
- type: 'message_start',
2198
- message: {
2199
- id: this.turnId,
2200
- type: 'message',
2201
- role: 'assistant',
2202
- model: this.info.model,
2203
- content: [],
2204
- stop_reason: null,
2205
- stop_sequence: null,
2206
- usage: { input_tokens: 0, output_tokens: 0 },
2207
- },
2208
- },
2209
- parent_tool_use_id: null,
2210
- session_id: this.sessionId,
2249
+ type: 'system',
2250
+ subtype: 'status',
2251
+ status: 'requesting',
2211
2252
  });
2212
2253
  }
2213
2254
  }
2255
+ writePartialMessageStart() {
2256
+ this.write({
2257
+ type: 'stream_event',
2258
+ event: {
2259
+ type: 'message_start',
2260
+ message: {
2261
+ id: this.turnId,
2262
+ type: 'message',
2263
+ role: 'assistant',
2264
+ model: this.info.model,
2265
+ content: [],
2266
+ stop_reason: null,
2267
+ stop_sequence: null,
2268
+ usage: { input_tokens: this.turnUsage.inputTokens, output_tokens: 0 },
2269
+ },
2270
+ },
2271
+ parent_tool_use_id: null,
2272
+ session_id: this.sessionId,
2273
+ });
2274
+ }
2214
2275
  partialText(delta) {
2215
2276
  if (!this.includePartialMessages)
2216
2277
  return;
@@ -2218,7 +2279,7 @@ export class StreamJsonOutput {
2218
2279
  this.contentStarted = true;
2219
2280
  this.textContentIndex = this.nextContentIndex;
2220
2281
  this.nextContentIndex += 1;
2221
- this.write({
2282
+ this.beginPartialBlock({
2222
2283
  type: 'stream_event',
2223
2284
  event: {
2224
2285
  type: 'content_block_start',
@@ -2227,9 +2288,14 @@ export class StreamJsonOutput {
2227
2288
  },
2228
2289
  parent_tool_use_id: null,
2229
2290
  session_id: this.sessionId,
2291
+ }, {
2292
+ type: 'stream_event',
2293
+ event: { type: 'content_block_stop', index: this.textContentIndex },
2294
+ parent_tool_use_id: null,
2295
+ session_id: this.sessionId,
2230
2296
  });
2231
2297
  }
2232
- this.write({
2298
+ this.partialEvents.push({
2233
2299
  type: 'stream_event',
2234
2300
  event: {
2235
2301
  type: 'content_block_delta',
@@ -2240,57 +2306,26 @@ export class StreamJsonOutput {
2240
2306
  session_id: this.sessionId,
2241
2307
  });
2242
2308
  }
2309
+ beginPartialBlock(start, stop) {
2310
+ if (this.pendingPartialStop)
2311
+ this.partialEvents.push(this.pendingPartialStop);
2312
+ this.pendingPartialStop = stop;
2313
+ this.partialEvents.push(start);
2314
+ }
2243
2315
  finishPartial() {
2244
2316
  if (!this.includePartialMessages)
2245
2317
  return;
2246
- if (this.contentStarted) {
2247
- this.write({
2248
- type: 'stream_event',
2249
- event: {
2250
- type: 'content_block_stop',
2251
- index: this.textContentIndex,
2252
- },
2253
- parent_tool_use_id: null,
2254
- session_id: this.sessionId,
2255
- });
2256
- }
2257
- for (const [toolIndex, call] of this.turnCalls.entries()) {
2258
- const index = this.nextContentIndex + toolIndex;
2259
- this.write({
2260
- type: 'stream_event',
2261
- event: {
2262
- type: 'content_block_start',
2263
- index,
2264
- content_block: {
2265
- type: 'tool_use',
2266
- id: call.id,
2267
- name: call.name,
2268
- input: {},
2269
- },
2270
- },
2271
- parent_tool_use_id: null,
2272
- session_id: this.sessionId,
2273
- });
2274
- this.write({
2275
- type: 'stream_event',
2276
- event: {
2277
- type: 'content_block_delta',
2278
- index,
2279
- delta: {
2280
- type: 'input_json_delta',
2281
- partial_json: JSON.stringify(call.input),
2282
- },
2283
- },
2284
- parent_tool_use_id: null,
2285
- session_id: this.sessionId,
2286
- });
2287
- this.write({
2288
- type: 'stream_event',
2289
- event: { type: 'content_block_stop', index },
2290
- parent_tool_use_id: null,
2291
- session_id: this.sessionId,
2292
- });
2293
- }
2318
+ this.writePartialMessageStart();
2319
+ for (const event of this.partialEvents)
2320
+ this.write(event);
2321
+ this.partialEvents = [];
2322
+ }
2323
+ finishPartialTail() {
2324
+ if (!this.includePartialMessages)
2325
+ return;
2326
+ if (this.pendingPartialStop)
2327
+ this.write(this.pendingPartialStop);
2328
+ this.pendingPartialStop = undefined;
2294
2329
  this.write({
2295
2330
  type: 'stream_event',
2296
2331
  event: {
@@ -2341,12 +2376,13 @@ export class StreamJsonOutput {
2341
2376
  stop_sequence: null,
2342
2377
  usage: {
2343
2378
  input_tokens: this.turnUsage.inputTokens,
2344
- output_tokens: this.turnUsage.outputTokens,
2379
+ output_tokens: 0,
2345
2380
  },
2346
2381
  },
2347
2382
  parent_tool_use_id: null,
2348
2383
  session_id: this.sessionId,
2349
2384
  });
2385
+ this.finishPartialTail();
2350
2386
  }
2351
2387
  finishTurn() {
2352
2388
  this.flushAssistant();
@@ -5607,7 +5607,11 @@ async function execute(argv, io, dependencies, signal) {
5607
5607
  claudeCodeVersion: '2.1.208',
5608
5608
  };
5609
5609
  if (outputFormat === 'stream-json') {
5610
- const output = new StreamJsonOutput((value) => writeJson(io, value), info, sessionId, includePartialMessages, invocation.includeHookEvents);
5610
+ const output = new StreamJsonOutput((value) => writeJson(io, value), info, sessionId, {
5611
+ includePartialMessages,
5612
+ includeHookEvents: invocation.includeHookEvents,
5613
+ emitSessionStateEvents: process.env.CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS === '1',
5614
+ });
5611
5615
  output.init();
5612
5616
  output.sink({ type: 'text-delta', delta: text });
5613
5617
  output.sink({ type: 'usage', usage: result.usage });
@@ -5787,7 +5791,11 @@ async function execute(argv, io, dependencies, signal) {
5787
5791
  }
5788
5792
  let activeSessionId = existingSessionId ?? invocation.sessionId ?? randomUUID();
5789
5793
  if (outputFormat === 'stream-json' && !invocation.legacyJson) {
5790
- streamOutput = new StreamJsonOutput((value) => writeJson(io, value), runtimeInfo, activeSessionId, includePartialMessages, invocation.includeHookEvents);
5794
+ streamOutput = new StreamJsonOutput((value) => writeJson(io, value), runtimeInfo, activeSessionId, {
5795
+ includePartialMessages,
5796
+ includeHookEvents: invocation.includeHookEvents,
5797
+ emitSessionStateEvents: process.env.CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS === '1',
5798
+ });
5791
5799
  }
5792
5800
  if (streamInputExhausted)
5793
5801
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "praxis-agent",
3
- "version": "0.55.1",
3
+ "version": "0.55.2",
4
4
  "description": "Local-first, single-user general agent for the command line.",
5
5
  "license": "MIT",
6
6
  "author": "wuqisen",