@bastani/atomic 0.9.44-alpha.3 → 0.9.44-alpha.4

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.44-alpha.4] - 2026-10-25
6
+
7
+ Workflow journals stay small even when many stages write to the same run at once.
8
+
9
+ - **No more full-list rewrites under contention:** a pending-message write that loses a race with another writer rebuilds its change and retries instead of storing the whole pending list. Those rewrites drove journal growth and workflow host load under heavy fan-out ([#3929](https://github.com/bastani-inc/atomic/issues/3929), [#3937](https://github.com/bastani-inc/atomic/pull/3937))
10
+
5
11
  ## [0.9.44-alpha.3] - 2026-10-25
6
12
 
7
13
  Chatty workflow swarms stay fast and their journals stay small, and Atomic picks up a round of dependency security fixes.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic's pi-compatible MCP integration for server connections, OAuth, tools, resources, and terminal management.",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.44-alpha.4] - 2026-10-25
10
+
11
+ ### Fixed
12
+
13
+ - A pending-message write that loses a race with another writer to the same run (for example a stage's delivery receipt) no longer stores the run's whole list of pending stage messages in the journal. It is rebuilt as a change on top of the other writer's entry and retried, and only falls back to the full list after repeated conflicts. In a 160-worker fan-out, 2% of queued events had fallen back and written 93% of their bytes, up to 1.5 MB each and growing with the list ([#3929](https://github.com/bastani-inc/atomic/issues/3929))
14
+
9
15
  ## [0.9.44-alpha.3] - 2026-10-25
10
16
 
11
17
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -7097,16 +7097,20 @@ class JournalDurableBackend {
7097
7097
  }
7098
7098
  *append(runId, event, options) {
7099
7099
  const lease = yield* this.ownership(runId);
7100
- const base = this.sequences.get(runId);
7101
7100
  const pinned = options?.expectSeq;
7102
- const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
7103
- if (encoded !== undefined) {
7101
+ for (let attempt = 0;attempt < CHANGE_APPEND_ATTEMPTS; attempt++) {
7102
+ const base = this.sequences.get(runId);
7103
+ const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
7104
+ if (encoded === undefined)
7105
+ break;
7104
7106
  try {
7105
7107
  return yield* this.write(runId, lease, encoded, { ...options, expectSeq: base });
7106
7108
  } catch (error) {
7107
7109
  if (!(error instanceof JournalCasConflictError) || pinned !== undefined)
7108
7110
  throw error;
7109
7111
  }
7112
+ for (const entry of yield* this.entries(runId, (this.sequences.get(runId) ?? 0) + 1))
7113
+ this.fold(entry);
7110
7114
  }
7111
7115
  yield* this.write(runId, lease, event, options);
7112
7116
  }
@@ -7787,7 +7791,7 @@ function decodePendingStageDeliveries(previous, messages) {
7787
7791
  function hasPendingStageDeliveryDelta(messages) {
7788
7792
  return messages?.some(isDeltaEncoded) === true;
7789
7793
  }
7790
- var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
7794
+ var PROCESS_HOLDER_ID, CHANGE_APPEND_ATTEMPTS = 4, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
7791
7795
  var init_journal_backend = __esm(() => {
7792
7796
  init_workflow_instance_ownership_error();
7793
7797
  init_backend();
@@ -1908,16 +1908,20 @@ class JournalDurableBackend {
1908
1908
  }
1909
1909
  *append(runId, event, options) {
1910
1910
  const lease = yield* this.ownership(runId);
1911
- const base = this.sequences.get(runId);
1912
1911
  const pinned = options?.expectSeq;
1913
- const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
1914
- if (encoded !== undefined) {
1912
+ for (let attempt = 0;attempt < CHANGE_APPEND_ATTEMPTS; attempt++) {
1913
+ const base = this.sequences.get(runId);
1914
+ const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
1915
+ if (encoded === undefined)
1916
+ break;
1915
1917
  try {
1916
1918
  return yield* this.write(runId, lease, encoded, { ...options, expectSeq: base });
1917
1919
  } catch (error) {
1918
1920
  if (!(error instanceof JournalCasConflictError) || pinned !== undefined)
1919
1921
  throw error;
1920
1922
  }
1923
+ for (const entry of yield* this.entries(runId, (this.sequences.get(runId) ?? 0) + 1))
1924
+ this.fold(entry);
1921
1925
  }
1922
1926
  yield* this.write(runId, lease, event, options);
1923
1927
  }
@@ -2598,7 +2602,7 @@ function decodePendingStageDeliveries(previous, messages) {
2598
2602
  function hasPendingStageDeliveryDelta(messages) {
2599
2603
  return messages?.some(isDeltaEncoded) === true;
2600
2604
  }
2601
- var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
2605
+ var PROCESS_HOLDER_ID, CHANGE_APPEND_ATTEMPTS = 4, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
2602
2606
  var init_journal_backend = __esm(() => {
2603
2607
  init_workflow_instance_ownership_error();
2604
2608
  init_backend();
@@ -10117,16 +10117,20 @@ class JournalDurableBackend {
10117
10117
  }
10118
10118
  *append(runId, event, options) {
10119
10119
  const lease = yield* this.ownership(runId);
10120
- const base = this.sequences.get(runId);
10121
10120
  const pinned = options?.expectSeq;
10122
- const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
10123
- if (encoded !== undefined) {
10121
+ for (let attempt = 0;attempt < CHANGE_APPEND_ATTEMPTS; attempt++) {
10122
+ const base = this.sequences.get(runId);
10123
+ const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
10124
+ if (encoded === undefined)
10125
+ break;
10124
10126
  try {
10125
10127
  return yield* this.write(runId, lease, encoded, { ...options, expectSeq: base });
10126
10128
  } catch (error) {
10127
10129
  if (!(error instanceof JournalCasConflictError) || pinned !== undefined)
10128
10130
  throw error;
10129
10131
  }
10132
+ for (const entry of yield* this.entries(runId, (this.sequences.get(runId) ?? 0) + 1))
10133
+ this.fold(entry);
10130
10134
  }
10131
10135
  yield* this.write(runId, lease, event, options);
10132
10136
  }
@@ -10807,7 +10811,7 @@ function decodePendingStageDeliveries(previous, messages) {
10807
10811
  function hasPendingStageDeliveryDelta(messages) {
10808
10812
  return messages?.some(isDeltaEncoded) === true;
10809
10813
  }
10810
- var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
10814
+ var PROCESS_HOLDER_ID, CHANGE_APPEND_ATTEMPTS = 4, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
10811
10815
  var init_journal_backend = __esm(() => {
10812
10816
  init_workflow_instance_ownership_error();
10813
10817
  init_backend();
@@ -1908,16 +1908,20 @@ class JournalDurableBackend {
1908
1908
  }
1909
1909
  *append(runId, event, options) {
1910
1910
  const lease = yield* this.ownership(runId);
1911
- const base = this.sequences.get(runId);
1912
1911
  const pinned = options?.expectSeq;
1913
- const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
1914
- if (encoded !== undefined) {
1912
+ for (let attempt = 0;attempt < CHANGE_APPEND_ATTEMPTS; attempt++) {
1913
+ const base = this.sequences.get(runId);
1914
+ const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
1915
+ if (encoded === undefined)
1916
+ break;
1915
1917
  try {
1916
1918
  return yield* this.write(runId, lease, encoded, { ...options, expectSeq: base });
1917
1919
  } catch (error) {
1918
1920
  if (!(error instanceof JournalCasConflictError) || pinned !== undefined)
1919
1921
  throw error;
1920
1922
  }
1923
+ for (const entry of yield* this.entries(runId, (this.sequences.get(runId) ?? 0) + 1))
1924
+ this.fold(entry);
1921
1925
  }
1922
1926
  yield* this.write(runId, lease, event, options);
1923
1927
  }
@@ -2598,7 +2602,7 @@ function decodePendingStageDeliveries(previous, messages) {
2598
2602
  function hasPendingStageDeliveryDelta(messages) {
2599
2603
  return messages?.some(isDeltaEncoded) === true;
2600
2604
  }
2601
- var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
2605
+ var PROCESS_HOLDER_ID, CHANGE_APPEND_ATTEMPTS = 4, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
2602
2606
  var init_journal_backend = __esm(() => {
2603
2607
  init_workflow_instance_ownership_error();
2604
2608
  init_backend();
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bastani/atomic",
9
- "version": "0.9.44-alpha.3",
9
+ "version": "0.9.44-alpha.4",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@bastani/atomic-natives": "0.9.44-alpha.3",
13
- "@bastani/pi-ai": "0.9.44-alpha.3",
12
+ "@bastani/atomic-natives": "0.9.44-alpha.4",
13
+ "@bastani/pi-ai": "0.9.44-alpha.4",
14
14
  "@earendil-works/pi-agent-core": "1.4.0",
15
15
  "@earendil-works/pi-codemode": "1.4.0",
16
16
  "@earendil-works/pi-tui": "1.4.0",
@@ -427,18 +427,18 @@
427
427
  }
428
428
  },
429
429
  "node_modules/@bastani/atomic-natives": {
430
- "version": "0.9.44-alpha.3",
431
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.44-alpha.3.tgz",
430
+ "version": "0.9.44-alpha.4",
431
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.44-alpha.4.tgz",
432
432
  "license": "MIT",
433
433
  "optionalDependencies": {
434
- "@bastani/atomic-natives-darwin-arm64": "0.9.44-alpha.3",
435
- "@bastani/atomic-natives-darwin-x64": "0.9.44-alpha.3",
436
- "@bastani/atomic-natives-linux-arm64-gnu": "0.9.44-alpha.3",
437
- "@bastani/atomic-natives-linux-arm64-musl": "0.9.44-alpha.3",
438
- "@bastani/atomic-natives-linux-x64-gnu": "0.9.44-alpha.3",
439
- "@bastani/atomic-natives-linux-x64-musl": "0.9.44-alpha.3",
440
- "@bastani/atomic-natives-win32-arm64-msvc": "0.9.44-alpha.3",
441
- "@bastani/atomic-natives-win32-x64-msvc": "0.9.44-alpha.3"
434
+ "@bastani/atomic-natives-darwin-arm64": "0.9.44-alpha.4",
435
+ "@bastani/atomic-natives-darwin-x64": "0.9.44-alpha.4",
436
+ "@bastani/atomic-natives-linux-arm64-gnu": "0.9.44-alpha.4",
437
+ "@bastani/atomic-natives-linux-arm64-musl": "0.9.44-alpha.4",
438
+ "@bastani/atomic-natives-linux-x64-gnu": "0.9.44-alpha.4",
439
+ "@bastani/atomic-natives-linux-x64-musl": "0.9.44-alpha.4",
440
+ "@bastani/atomic-natives-win32-arm64-msvc": "0.9.44-alpha.4",
441
+ "@bastani/atomic-natives-win32-x64-msvc": "0.9.44-alpha.4"
442
442
  },
443
443
  "engines": {
444
444
  "bun": ">=1.4.2",
@@ -446,8 +446,8 @@
446
446
  }
447
447
  },
448
448
  "node_modules/@bastani/atomic-natives-darwin-arm64": {
449
- "version": "0.9.44-alpha.3",
450
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.44-alpha.3.tgz",
449
+ "version": "0.9.44-alpha.4",
450
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.44-alpha.4.tgz",
451
451
  "license": "MIT",
452
452
  "os": [
453
453
  "darwin"
@@ -458,8 +458,8 @@
458
458
  "optional": true
459
459
  },
460
460
  "node_modules/@bastani/atomic-natives-darwin-x64": {
461
- "version": "0.9.44-alpha.3",
462
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.44-alpha.3.tgz",
461
+ "version": "0.9.44-alpha.4",
462
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.44-alpha.4.tgz",
463
463
  "license": "MIT",
464
464
  "os": [
465
465
  "darwin"
@@ -470,8 +470,8 @@
470
470
  "optional": true
471
471
  },
472
472
  "node_modules/@bastani/atomic-natives-linux-arm64-gnu": {
473
- "version": "0.9.44-alpha.3",
474
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.44-alpha.3.tgz",
473
+ "version": "0.9.44-alpha.4",
474
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.44-alpha.4.tgz",
475
475
  "license": "MIT",
476
476
  "os": [
477
477
  "linux"
@@ -485,8 +485,8 @@
485
485
  "optional": true
486
486
  },
487
487
  "node_modules/@bastani/atomic-natives-linux-arm64-musl": {
488
- "version": "0.9.44-alpha.3",
489
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.44-alpha.3.tgz",
488
+ "version": "0.9.44-alpha.4",
489
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.44-alpha.4.tgz",
490
490
  "license": "MIT",
491
491
  "os": [
492
492
  "linux"
@@ -500,8 +500,8 @@
500
500
  "optional": true
501
501
  },
502
502
  "node_modules/@bastani/atomic-natives-linux-x64-gnu": {
503
- "version": "0.9.44-alpha.3",
504
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.44-alpha.3.tgz",
503
+ "version": "0.9.44-alpha.4",
504
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.44-alpha.4.tgz",
505
505
  "license": "MIT",
506
506
  "os": [
507
507
  "linux"
@@ -515,8 +515,8 @@
515
515
  "optional": true
516
516
  },
517
517
  "node_modules/@bastani/atomic-natives-linux-x64-musl": {
518
- "version": "0.9.44-alpha.3",
519
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.44-alpha.3.tgz",
518
+ "version": "0.9.44-alpha.4",
519
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.44-alpha.4.tgz",
520
520
  "license": "MIT",
521
521
  "os": [
522
522
  "linux"
@@ -530,8 +530,8 @@
530
530
  "optional": true
531
531
  },
532
532
  "node_modules/@bastani/atomic-natives-win32-arm64-msvc": {
533
- "version": "0.9.44-alpha.3",
534
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.44-alpha.3.tgz",
533
+ "version": "0.9.44-alpha.4",
534
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.44-alpha.4.tgz",
535
535
  "license": "MIT",
536
536
  "os": [
537
537
  "win32"
@@ -542,8 +542,8 @@
542
542
  "optional": true
543
543
  },
544
544
  "node_modules/@bastani/atomic-natives-win32-x64-msvc": {
545
- "version": "0.9.44-alpha.3",
546
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.44-alpha.3.tgz",
545
+ "version": "0.9.44-alpha.4",
546
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.44-alpha.4.tgz",
547
547
  "license": "MIT",
548
548
  "os": [
549
549
  "win32"
@@ -554,8 +554,8 @@
554
554
  "optional": true
555
555
  },
556
556
  "node_modules/@bastani/pi-ai": {
557
- "version": "0.9.44-alpha.3",
558
- "resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.44-alpha.3.tgz",
557
+ "version": "0.9.44-alpha.4",
558
+ "resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.44-alpha.4.tgz",
559
559
  "license": "MIT",
560
560
  "dependencies": {
561
561
  "@anthropic-ai/sdk": "0.129.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.44-alpha.3",
3
+ "version": "0.9.44-alpha.4",
4
4
  "description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "atomicConfig": {
@@ -89,8 +89,8 @@
89
89
  "prepublishOnly": "bun run clean && bun run build && bun run shrinkwrap"
90
90
  },
91
91
  "dependencies": {
92
- "@bastani/atomic-natives": "0.9.44-alpha.3",
93
- "@bastani/pi-ai": "0.9.44-alpha.3",
92
+ "@bastani/atomic-natives": "0.9.44-alpha.4",
93
+ "@bastani/pi-ai": "0.9.44-alpha.4",
94
94
  "@earendil-works/pi-agent-core": "1.4.0",
95
95
  "@earendil-works/pi-codemode": "1.4.0",
96
96
  "@earendil-works/pi-tui": "1.4.0",