plexspaces 0.1.1__py3-none-any.whl

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.
Files changed (87) hide show
  1. plexspaces/__init__.py +80 -0
  2. plexspaces/actor_id.py +114 -0
  3. plexspaces/decorators.py +691 -0
  4. plexspaces/generated/__init__.py +0 -0
  5. plexspaces/generated/buf/__init__.py +0 -0
  6. plexspaces/generated/buf/validate/__init__.py +3799 -0
  7. plexspaces/generated/google/__init__.py +0 -0
  8. plexspaces/generated/google/api/__init__.py +379 -0
  9. plexspaces/generated/grpc/__init__.py +0 -0
  10. plexspaces/generated/grpc/gateway/__init__.py +0 -0
  11. plexspaces/generated/grpc/gateway/protoc_gen_openapiv2/__init__.py +0 -0
  12. plexspaces/generated/grpc/gateway/protoc_gen_openapiv2/options/__init__.py +1022 -0
  13. plexspaces/generated/plexspaces/__init__.py +0 -0
  14. plexspaces/generated/plexspaces/actor/__init__.py +0 -0
  15. plexspaces/generated/plexspaces/actor/v1/__init__.py +3538 -0
  16. plexspaces/generated/plexspaces/application/__init__.py +0 -0
  17. plexspaces/generated/plexspaces/application/v1/__init__.py +827 -0
  18. plexspaces/generated/plexspaces/behaviors/__init__.py +0 -0
  19. plexspaces/generated/plexspaces/behaviors/v1/__init__.py +63 -0
  20. plexspaces/generated/plexspaces/channel/__init__.py +0 -0
  21. plexspaces/generated/plexspaces/channel/v1/__init__.py +915 -0
  22. plexspaces/generated/plexspaces/circuitbreaker/__init__.py +0 -0
  23. plexspaces/generated/plexspaces/circuitbreaker/prv/__init__.py +398 -0
  24. plexspaces/generated/plexspaces/common/__init__.py +0 -0
  25. plexspaces/generated/plexspaces/common/v1/__init__.py +691 -0
  26. plexspaces/generated/plexspaces/config/__init__.py +0 -0
  27. plexspaces/generated/plexspaces/config/v1/__init__.py +109 -0
  28. plexspaces/generated/plexspaces/dashboard/__init__.py +0 -0
  29. plexspaces/generated/plexspaces/dashboard/v1/__init__.py +647 -0
  30. plexspaces/generated/plexspaces/facets/__init__.py +0 -0
  31. plexspaces/generated/plexspaces/facets/v1/__init__.py +333 -0
  32. plexspaces/generated/plexspaces/firecracker/__init__.py +0 -0
  33. plexspaces/generated/plexspaces/firecracker/v1/__init__.py +890 -0
  34. plexspaces/generated/plexspaces/grpc/__init__.py +0 -0
  35. plexspaces/generated/plexspaces/grpc/v1/__init__.py +679 -0
  36. plexspaces/generated/plexspaces/journaling/__init__.py +0 -0
  37. plexspaces/generated/plexspaces/journaling/v1/__init__.py +1006 -0
  38. plexspaces/generated/plexspaces/keyvalue/__init__.py +0 -0
  39. plexspaces/generated/plexspaces/keyvalue/v1/__init__.py +1007 -0
  40. plexspaces/generated/plexspaces/locks/__init__.py +0 -0
  41. plexspaces/generated/plexspaces/locks/prv/__init__.py +122 -0
  42. plexspaces/generated/plexspaces/mailbox/__init__.py +0 -0
  43. plexspaces/generated/plexspaces/mailbox/v1/__init__.py +246 -0
  44. plexspaces/generated/plexspaces/metrics/__init__.py +0 -0
  45. plexspaces/generated/plexspaces/metrics/v1/__init__.py +878 -0
  46. plexspaces/generated/plexspaces/node/__init__.py +0 -0
  47. plexspaces/generated/plexspaces/node/v1/__init__.py +2564 -0
  48. plexspaces/generated/plexspaces/object_registry/__init__.py +0 -0
  49. plexspaces/generated/plexspaces/object_registry/v1/__init__.py +759 -0
  50. plexspaces/generated/plexspaces/persistence/__init__.py +0 -0
  51. plexspaces/generated/plexspaces/persistence/prv/__init__.py +539 -0
  52. plexspaces/generated/plexspaces/pool/__init__.py +0 -0
  53. plexspaces/generated/plexspaces/pool/v1/__init__.py +791 -0
  54. plexspaces/generated/plexspaces/processgroups/__init__.py +0 -0
  55. plexspaces/generated/plexspaces/processgroups/v1/__init__.py +622 -0
  56. plexspaces/generated/plexspaces/scheduling/__init__.py +0 -0
  57. plexspaces/generated/plexspaces/scheduling/v1/__init__.py +364 -0
  58. plexspaces/generated/plexspaces/security/__init__.py +0 -0
  59. plexspaces/generated/plexspaces/security/v1/__init__.py +254 -0
  60. plexspaces/generated/plexspaces/services/__init__.py +0 -0
  61. plexspaces/generated/plexspaces/services/prv/__init__.py +112 -0
  62. plexspaces/generated/plexspaces/storage/__init__.py +0 -0
  63. plexspaces/generated/plexspaces/storage/v1/__init__.py +747 -0
  64. plexspaces/generated/plexspaces/supervision/__init__.py +0 -0
  65. plexspaces/generated/plexspaces/supervision/v1/__init__.py +536 -0
  66. plexspaces/generated/plexspaces/system/__init__.py +0 -0
  67. plexspaces/generated/plexspaces/system/v1/__init__.py +1602 -0
  68. plexspaces/generated/plexspaces/timer/__init__.py +0 -0
  69. plexspaces/generated/plexspaces/timer/v1/__init__.py +402 -0
  70. plexspaces/generated/plexspaces/tuplespace/__init__.py +0 -0
  71. plexspaces/generated/plexspaces/tuplespace/v1/__init__.py +869 -0
  72. plexspaces/generated/plexspaces/wasm/__init__.py +0 -0
  73. plexspaces/generated/plexspaces/wasm/v1/__init__.py +920 -0
  74. plexspaces/generated/plexspaces/workflow/__init__.py +0 -0
  75. plexspaces/generated/plexspaces/workflow/v1/__init__.py +870 -0
  76. plexspaces/host.py +2093 -0
  77. plexspaces/leader_worker.py +148 -0
  78. plexspaces/proto_wire.py +1357 -0
  79. plexspaces/runtime.py +284 -0
  80. plexspaces/workflow.py +105 -0
  81. plexspaces-0.1.1.dist-info/METADATA +505 -0
  82. plexspaces-0.1.1.dist-info/RECORD +87 -0
  83. plexspaces-0.1.1.dist-info/WHEEL +5 -0
  84. plexspaces-0.1.1.dist-info/entry_points.txt +2 -0
  85. plexspaces-0.1.1.dist-info/top_level.txt +2 -0
  86. plexspaces_cli/__init__.py +8 -0
  87. plexspaces_cli/build.py +374 -0
@@ -0,0 +1,920 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # sources: plexspaces/v1/wasm/wasm.proto
3
+ # plugin: python-betterproto
4
+ # This file has been @generated
5
+
6
+ from dataclasses import dataclass
7
+ from datetime import (
8
+ datetime,
9
+ timedelta,
10
+ )
11
+ from typing import (
12
+ TYPE_CHECKING,
13
+ Dict,
14
+ List,
15
+ Optional,
16
+ )
17
+
18
+ import betterproto
19
+ import grpclib
20
+ from betterproto.grpc.grpclib_server import ServiceBase
21
+
22
+ from ...common import v1 as __common_v1__
23
+
24
+ if TYPE_CHECKING:
25
+ import grpclib.server
26
+ from betterproto.grpc.grpclib_client import MetadataLike
27
+ from grpclib.metadata import Deadline
28
+
29
+
30
+ class WasmErrorCode(betterproto.Enum):
31
+ """
32
+ WASM runtime error codes
33
+
34
+ ## Purpose
35
+ Defines error categories for WASM operations. Used for gRPC status codes
36
+ and error reporting across language boundaries.
37
+
38
+ ## Why This Exists
39
+ - **Proto-First**: Errors are part of the API contract (not Rust-only)
40
+ - **Multi-Language**: Error types available in all supported languages (TypeScript, Python SDKs)
41
+ - **gRPC Compatibility**: Maps to gRPC status codes for proper error handling
42
+ - **Structured Errors**: Clients can handle specific error types programmatically
43
+
44
+ ## Design Notes
45
+ - Error codes are stable (don't reorder or change values)
46
+ - New error codes can be added at the end
47
+ - OK = 0 for consistency with gRPC conventions
48
+ """
49
+
50
+ OK = 0
51
+ """Success (not an error)"""
52
+
53
+ COMPILATION_FAILED = 1
54
+ """
55
+ Module compilation failed
56
+
57
+ Causes: Invalid WASM bytecode, unsupported features, syntax errors
58
+ Recovery: Fix WASM module, use compatible toolchain
59
+ """
60
+
61
+ INSTANTIATION_FAILED = 2
62
+ """
63
+ Module instantiation failed
64
+
65
+ Causes: Import resolution errors, initialization errors, memory allocation failure
66
+ Recovery: Check module dependencies, ensure host functions available
67
+ """
68
+
69
+ RESOURCE_LIMIT_EXCEEDED = 3
70
+ """
71
+ Resource limit exceeded (memory, fuel, CPU time)
72
+
73
+ Causes: Actor exceeded memory/fuel/time quota
74
+ Recovery: Increase limits or optimize actor code
75
+ """
76
+
77
+ CAPABILITY_DENIED = 4
78
+ """
79
+ Capability denied (missing permission)
80
+
81
+ Causes: Actor attempted unauthorized operation (filesystem, network, spawn)
82
+ Recovery: Grant capability or remove unauthorized code
83
+ """
84
+
85
+ HOST_FUNCTION_ERROR = 5
86
+ """
87
+ Host function call failed
88
+
89
+ Causes: Host function error (send_message failed, tuplespace_write failed)
90
+ Recovery: Check host function arguments, retry
91
+ """
92
+
93
+ ACTOR_FUNCTION_ERROR = 6
94
+ """
95
+ Actor function call failed
96
+
97
+ Causes: Actor's exported function (init, handle_message) threw error or trapped
98
+ Recovery: Fix actor code, check logs
99
+ """
100
+
101
+ CACHE_ERROR = 7
102
+ """
103
+ Module cache error
104
+
105
+ Causes: Cache lookup failed, eviction error, storage backend error
106
+ Recovery: Retry, check cache backend health
107
+ """
108
+
109
+ HASH_MISMATCH = 8
110
+ """
111
+ Module hash mismatch (integrity check failed)
112
+
113
+ Causes: Module bytes corrupted during transfer, malicious modification
114
+ Recovery: Re-deploy module, check network integrity
115
+ """
116
+
117
+ MODULE_NOT_FOUND = 9
118
+ """
119
+ Module not found
120
+
121
+ Causes: Module not deployed, evicted from cache, wrong name/version
122
+ Recovery: Deploy module first, check name/version
123
+ """
124
+
125
+ SERIALIZATION_ERROR = 10
126
+ """
127
+ Serialization/deserialization error
128
+
129
+ Causes: Invalid protobuf, incompatible schema version
130
+ Recovery: Check message format, ensure compatible versions
131
+ """
132
+
133
+ WASMTIME_ERROR = 11
134
+ """
135
+ Internal wasmtime runtime error
136
+
137
+ Causes: wasmtime internal error, runtime bug
138
+ Recovery: Check logs, report bug, try different wasmtime version
139
+ """
140
+
141
+
142
+ class DeployWasmModuleRequestPreWarmStrategy(betterproto.Enum):
143
+ """Pre-warm strategy"""
144
+
145
+ NONE = 0
146
+ """No pre-warming - nodes fetch on-demand (lazy)"""
147
+
148
+ ANNOUNCE = 1
149
+ """Announce to all nodes - they decide whether to pre-fetch"""
150
+
151
+ PUSH_ALL = 2
152
+ """Push to all nodes immediately (eager)"""
153
+
154
+ PUSH_TAGGED = 3
155
+ """Push to subset of nodes (e.g., based on tags)"""
156
+
157
+
158
+ @dataclass(eq=False, repr=False)
159
+ class HttpFetchRequest(betterproto.Message):
160
+ """
161
+ Outbound HTTP request sent by actor-world host.http-fetch.
162
+
163
+ The WIT operation keeps link/method/path as typed arguments and exchanges
164
+ request metadata/body as protobuf bytes so polyglot SDKs can share one model.
165
+ """
166
+
167
+ headers: Dict[str, str] = betterproto.map_field(
168
+ 1, betterproto.TYPE_STRING, betterproto.TYPE_STRING
169
+ )
170
+ """
171
+ Request headers to merge with service-link defaults and auth headers.
172
+ """
173
+
174
+ body: bytes = betterproto.bytes_field(2)
175
+ """Raw request body bytes."""
176
+
177
+
178
+ @dataclass(eq=False, repr=False)
179
+ class HttpFetchResponse(betterproto.Message):
180
+ """Outbound HTTP response returned by actor-world host.http-fetch."""
181
+
182
+ status: int = betterproto.uint32_field(1)
183
+ """HTTP status code."""
184
+
185
+ headers: Dict[str, str] = betterproto.map_field(
186
+ 2, betterproto.TYPE_STRING, betterproto.TYPE_STRING
187
+ )
188
+ """Response headers."""
189
+
190
+ body: bytes = betterproto.bytes_field(3)
191
+ """Raw response body bytes."""
192
+
193
+
194
+ @dataclass(eq=False, repr=False)
195
+ class WasmModule(betterproto.Message):
196
+ """
197
+ WebAssembly module definition
198
+
199
+ ## Purpose
200
+ Represents a compiled WebAssembly module that can be deployed to nodes
201
+ and instantiated as actors. Modules are immutable and content-addressed
202
+ for caching and deduplication.
203
+
204
+ ## Why This Exists
205
+ - Enables dynamic code deployment (like Java classloader)
206
+ - Content-addressed hash allows efficient caching across nodes
207
+ - Metadata enables version management and dependency tracking
208
+ - Separation of code (module) and state (actor instance) enables fast migration
209
+
210
+ ## Design Notes
211
+ - `module_bytes` is the compiled WASM binary (Component Model format)
212
+ - `module_hash` is SHA-256 for cache lookup and verification
213
+ - `wit_interface` is optional WIT definition for tooling/debugging
214
+ - Modules are immutable - updates create new versions with different hashes
215
+ """
216
+
217
+ name: str = betterproto.string_field(1)
218
+ """
219
+ Module name (e.g., "counter-actor", "chat-room-actor")
220
+
221
+ Used for human-readable identification and registry lookups.
222
+ """
223
+
224
+ version: str = betterproto.string_field(2)
225
+ """
226
+ Module version (semantic versioning: "1.2.3")
227
+
228
+ Enables gradual rollout and rollback of actor code.
229
+ """
230
+
231
+ module_bytes: bytes = betterproto.bytes_field(3)
232
+ """
233
+ Compiled WebAssembly Component Model bytes
234
+
235
+ This is the actual WASM binary that will be loaded and instantiated.
236
+ Must be a valid WASM Component Model module (not legacy WASM).
237
+ """
238
+
239
+ module_hash: str = betterproto.string_field(4)
240
+ """
241
+ SHA-256 hash of module_bytes (for content-addressable caching)
242
+
243
+ Format: hex-encoded 64-character string
244
+ Example: "a1b2c3d4e5f6..."
245
+
246
+ Why content-addressed:
247
+ - Deduplication: Same module hash = same module, cache once
248
+ - Verification: Ensure module integrity during distribution
249
+ - Efficient lookup: Nodes can check cache before downloading
250
+ """
251
+
252
+ wit_interface: str = betterproto.string_field(5)
253
+ """
254
+ WIT (WebAssembly Interface Types) interface definition (optional)
255
+
256
+ Human-readable interface for tooling, debugging, and documentation.
257
+ Not required for runtime (Component Model is self-describing).
258
+ """
259
+
260
+ source_languages: List[str] = betterproto.string_field(6)
261
+ """
262
+ Supported languages (e.g., "rust", "javascript", "go")
263
+
264
+ Indicates source language for debugging and tooling.
265
+ """
266
+
267
+ metadata: "__common_v1__.Metadata" = betterproto.message_field(7)
268
+ """
269
+ Module metadata (tags, labels, annotations)
270
+
271
+ Examples:
272
+ - tags: ["production", "stateless", "compute-intensive"]
273
+ - labels: {"team": "backend", "service": "payment"}
274
+ """
275
+
276
+ created_at: datetime = betterproto.message_field(8)
277
+ """Upload timestamp (when module was first deployed to registry)"""
278
+
279
+ size_bytes: int = betterproto.uint64_field(9)
280
+ """
281
+ Module size in bytes (uncompressed)
282
+
283
+ Used for bandwidth estimation and pre-warming decisions.
284
+ """
285
+
286
+ version_number: int = betterproto.uint32_field(10)
287
+ """Schema version for forward/backward compatibility"""
288
+
289
+
290
+ @dataclass(eq=False, repr=False)
291
+ class ResourceLimits(betterproto.Message):
292
+ """
293
+ Resource limits for WASM actor instances
294
+
295
+ ## Purpose
296
+ Defines resource constraints for WASM actors to prevent resource exhaustion
297
+ and ensure fair scheduling. Enforced by wasmtime runtime.
298
+
299
+ ## Why This Exists
300
+ - Memory limits prevent OOM crashes (multi-tenant safety)
301
+ - Fuel metering prevents infinite loops (gas-style execution limits)
302
+ - Time limits prevent hung actors
303
+ - Stack limits prevent stack overflow
304
+
305
+ ## Design Notes
306
+ - Limits are per-instance (each actor has own quota)
307
+ - Fuel is like Ethereum gas - metered during execution
308
+ - Defaults chosen for balanced workloads (can override per-actor)
309
+ """
310
+
311
+ max_memory_bytes: int = betterproto.uint64_field(1)
312
+ """
313
+ Maximum linear memory size in bytes (default: 16MB)
314
+
315
+ WASM linear memory is contiguous, growable.
316
+ 16MB default balances:
317
+ - Enough for most actors (2MB-8MB typical)
318
+ - 64 actors per GB of RAM
319
+ - 32x more efficient than JavaNow (64MB per actor)
320
+ """
321
+
322
+ max_stack_bytes: int = betterproto.uint64_field(2)
323
+ """
324
+ Maximum stack size in bytes (default: 512KB)
325
+
326
+ Stack overflow protection. Most actors use < 100KB.
327
+ """
328
+
329
+ max_fuel: int = betterproto.uint64_field(3)
330
+ """
331
+ Maximum fuel units (gas-style execution limit)
332
+
333
+ Fuel is consumed during execution (ops, memory access, calls).
334
+ Default: 10 billion units = ~1 second CPU time
335
+ Zero = unlimited (not recommended for untrusted code)
336
+ """
337
+
338
+ max_execution_time: timedelta = betterproto.message_field(4)
339
+ """
340
+ Maximum execution time per message (optional)
341
+
342
+ If set, actor handler must complete within this duration.
343
+ Default: None (rely on fuel metering instead)
344
+ """
345
+
346
+ max_table_elements: int = betterproto.uint32_field(5)
347
+ """
348
+ Maximum table elements (for indirect calls)
349
+
350
+ Default: 10,000 (enough for most actors)
351
+ """
352
+
353
+ max_pooled_instances: int = betterproto.uint32_field(6)
354
+ """
355
+ Maximum number of instances in instance pool
356
+
357
+ For warm start optimization. Default: 10 per actor type.
358
+ """
359
+
360
+
361
+ @dataclass(eq=False, repr=False)
362
+ class WasmCapabilities(betterproto.Message):
363
+ """
364
+ WASI capabilities for WASM actors
365
+
366
+ ## Purpose
367
+ Defines what host resources a WASM actor can access. Based on WASI Preview 2
368
+ capability-based security model.
369
+
370
+ ## Why This Exists
371
+ - **Principle of Least Privilege**: Actors only get capabilities they need
372
+ - **Facets Pattern Revival**: JavaNow-inspired capability composition
373
+ - **Security**: Sandboxed actors cannot access unauthorized resources
374
+ - **Auditing**: Capabilities are explicit and logged
375
+
376
+ ## Design Notes
377
+ - Capabilities are granted at instantiation time (immutable per instance)
378
+ - WASI capabilities (filesystem, network, clocks) use WASI standard
379
+ - PlexSpaces capabilities (tuplespace, actors) are custom host functions
380
+ - Denied by default (opt-in model)
381
+ """
382
+
383
+ allow_filesystem: bool = betterproto.bool_field(1)
384
+ """
385
+ Allow filesystem access (WASI filesystem interface)
386
+
387
+ If true, actor can use WASI file operations (open, read, write).
388
+ Paths are virtualized (actor cannot access arbitrary host paths).
389
+ """
390
+
391
+ filesystem_root: str = betterproto.string_field(2)
392
+ """
393
+ Filesystem root path (if filesystem access allowed)
394
+
395
+ Actor's root is mapped to this host path (chroot-style).
396
+ Example: "/actors/{actor_id}/data"
397
+ """
398
+
399
+ allow_network: bool = betterproto.bool_field(3)
400
+ """
401
+ Allow network access (WASI sockets interface)
402
+
403
+ If true, actor can make outbound network connections.
404
+ Inbound connections not supported (actors receive messages via mailbox).
405
+ """
406
+
407
+ allow_env: bool = betterproto.bool_field(4)
408
+ """
409
+ Allow environment variables (WASI environment interface)
410
+
411
+ If true, actor can read environment variables.
412
+ Useful for configuration (but TupleSpace config preferred).
413
+ """
414
+
415
+ allow_random: bool = betterproto.bool_field(5)
416
+ """
417
+ Allow random number generation (WASI random interface)
418
+
419
+ If true, actor can use cryptographically secure random.
420
+ Generally safe to allow.
421
+ """
422
+
423
+ allow_clocks: bool = betterproto.bool_field(6)
424
+ """
425
+ Allow clock access (WASI clocks interface)
426
+
427
+ If true, actor can read monotonic and wall-clock time.
428
+ Required for timeouts, timestamps.
429
+ """
430
+
431
+ allow_tuplespace: bool = betterproto.bool_field(7)
432
+ """
433
+ Allow TupleSpace operations (PlexSpaces-specific)
434
+
435
+ If true, actor can call host functions: tuplespace_write, tuplespace_read, etc.
436
+ Most actors need this for coordination.
437
+ """
438
+
439
+ allow_spawn_actors: bool = betterproto.bool_field(8)
440
+ """
441
+ Allow actor spawning (PlexSpaces-specific)
442
+
443
+ If true, actor can spawn new actors via spawn_actor host function.
444
+ Useful for supervisor actors, not needed for leaf actors.
445
+ """
446
+
447
+ allow_send_messages: bool = betterproto.bool_field(9)
448
+ """
449
+ Allow message sending (PlexSpaces-specific)
450
+
451
+ If true, actor can send messages to other actors via send_message host function.
452
+ Almost all actors need this (inter-actor communication).
453
+ """
454
+
455
+ allow_logging: bool = betterproto.bool_field(10)
456
+ """
457
+ Allow logging (PlexSpaces-specific)
458
+
459
+ If true, actor can emit logs via log host function.
460
+ Useful for debugging, not required for production actors.
461
+ """
462
+
463
+
464
+ @dataclass(eq=False, repr=False)
465
+ class WasmConfig(betterproto.Message):
466
+ """
467
+ WASM actor configuration
468
+
469
+ ## Purpose
470
+ Combines resource limits and capabilities into a complete configuration
471
+ for instantiating a WASM actor. Can be templated per actor type.
472
+
473
+ ## Why This Exists
474
+ - **Reusable Profiles**: Define once, apply to many actors
475
+ - **Security Policies**: Enforce organizational security requirements
476
+ - **Resource Management**: Prevent resource exhaustion
477
+
478
+ ## Design Notes
479
+ - Can create profiles: "untrusted" (minimal caps), "trusted" (full caps)
480
+ - Immutable after instantiation (cannot escalate privileges)
481
+ """
482
+
483
+ limits: "ResourceLimits" = betterproto.message_field(1)
484
+ """Resource limits for this actor"""
485
+
486
+ capabilities: "WasmCapabilities" = betterproto.message_field(2)
487
+ """Capabilities granted to this actor"""
488
+
489
+ profile_name: str = betterproto.string_field(3)
490
+ """
491
+ Configuration name (e.g., "default", "untrusted", "compute-intensive")
492
+
493
+ Allows reusing configurations across actors.
494
+ """
495
+
496
+ enable_pooling: bool = betterproto.bool_field(4)
497
+ """
498
+ Enable instance pooling for warm starts
499
+
500
+ If true, pre-instantiate instances for faster spawning.
501
+ Trade-off: Memory usage vs latency.
502
+ """
503
+
504
+ enable_aot: bool = betterproto.bool_field(5)
505
+ """
506
+ Enable ahead-of-time (AOT) compilation
507
+
508
+ If true, compile module to native code on deployment.
509
+ Trade-off: Deployment time vs execution speed.
510
+ """
511
+
512
+ durability_enabled: bool = betterproto.bool_field(6)
513
+ """
514
+ Enable checkpoint/restore durability (load on init, save on terminate).
515
+
516
+ Off by default for performance. When true, actor state is loaded from
517
+ journal on init and saved on terminate (Cloudflare Durable Objects pattern).
518
+ """
519
+
520
+ use_instance_pool: bool = betterproto.bool_field(7)
521
+ """
522
+ Use pre-instantiated instance pool (InstancePool) when spawning actors.
523
+
524
+ On by default. When true, runtime may checkout from a per-module pool instead
525
+ of instantiating each time (faster spawn when pool has capacity). Requires
526
+ deploy-path integration; until then, only engine-level pooling (enable_pooling)
527
+ is active for HTTP/deploy.
528
+ """
529
+
530
+ max_concurrent_instantiations: int = betterproto.uint32_field(8)
531
+ """
532
+ Maximum concurrent instantiations (initial + re-instantiation) when pooling is enabled.
533
+
534
+ Limits total concurrent Wasmtime instantiations to avoid hitting Wasmtime's memory-stripe
535
+ limit (default 10). Per-actor re-instantiation lock serializes per actor; this global cap
536
+ prevents N actors from re-instantiating at once. Default: 8 (stays under Wasmtime's limit
537
+ with headroom). Only used when enable_pooling is true.
538
+
539
+ When 0 or not set, uses code default of 8.
540
+ """
541
+
542
+
543
+ @dataclass(eq=False, repr=False)
544
+ class DeployWasmModuleRequest(betterproto.Message):
545
+ """
546
+ Deploy WASM module request
547
+
548
+ ## Purpose
549
+ Uploads a WASM module to the cluster registry and optionally pre-warms
550
+ nodes by pushing the module to their caches.
551
+
552
+ ## Why This Exists
553
+ - **Hybrid Distribution**: Push announces availability, nodes can pull
554
+ - **Pre-warming**: Reduce cold start latency by pre-fetching modules
555
+ - **Version Management**: Deploy new versions without disrupting running actors
556
+
557
+ ## Design Notes
558
+ - Module stored in cluster registry (e.g., S3, Redis, etcd)
559
+ - Nodes notified of new module (can pre-fetch if heuristics match)
560
+ - Idempotent: Re-deploying same module (same hash) is no-op
561
+ """
562
+
563
+ module: "WasmModule" = betterproto.message_field(1)
564
+ """WASM module to deploy"""
565
+
566
+ pre_warm: "DeployWasmModuleRequestPreWarmStrategy" = betterproto.enum_field(2)
567
+ """How to distribute module to nodes"""
568
+
569
+ target_node_tags: List[str] = betterproto.string_field(3)
570
+ """
571
+ Node tags for PUSH_TAGGED strategy (e.g., ["us-east-1", "production"])
572
+ """
573
+
574
+
575
+ @dataclass(eq=False, repr=False)
576
+ class DeployWasmModuleResponse(betterproto.Message):
577
+ """Deploy WASM module response"""
578
+
579
+ success: bool = betterproto.bool_field(1)
580
+ """Was deployment successful?"""
581
+
582
+ module_hash: str = betterproto.string_field(2)
583
+ """Module hash (for cache lookup)"""
584
+
585
+ nodes_pre_warmed: int = betterproto.uint32_field(3)
586
+ """Number of nodes that received the module (for pre-warming)"""
587
+
588
+ error: "WasmError" = betterproto.message_field(4)
589
+ """
590
+ Error details if deployment failed (replaces error_message)
591
+
592
+ If deployment succeeded, this field is not set (code = OK).
593
+ If deployment failed, code indicates failure reason.
594
+ """
595
+
596
+
597
+ @dataclass(eq=False, repr=False)
598
+ class InstantiateActorRequest(betterproto.Message):
599
+ """
600
+ Instantiate WASM actor request
601
+
602
+ ## Purpose
603
+ Creates a new actor instance from a deployed WASM module. The instance
604
+ is initialized with provided state and configuration.
605
+
606
+ ## Why This Exists
607
+ - **Dynamic Actor Creation**: Spawn actors at runtime (like erlang:spawn)
608
+ - **State Initialization**: Restore actor from snapshot or start fresh
609
+ - **Configuration Flexibility**: Each actor can have custom config
610
+
611
+ ## Design Notes
612
+ - Module must be deployed first (or node will fetch on-demand)
613
+ - Initial state is opaque bytes (actor interprets based on module logic)
614
+ - Config can override module defaults (e.g., more memory for specific actor)
615
+ """
616
+
617
+ module_ref: str = betterproto.string_field(1)
618
+ """
619
+ Module name or hash to instantiate
620
+
621
+ Supports both:
622
+ - Name: "counter-actor@1.2.3" (fetches from registry)
623
+ - Hash: "a1b2c3d4..." (direct cache lookup)
624
+ """
625
+
626
+ actor_id: str = betterproto.string_field(2)
627
+ """
628
+ Actor ID to assign to this instance
629
+
630
+ Format: ULID for sortability (see CLAUDE.md Core Principle 0)
631
+ """
632
+
633
+ initial_state: bytes = betterproto.bytes_field(3)
634
+ """
635
+ Initial state bytes (opaque to runtime)
636
+
637
+ Passed to WASM module's init() function.
638
+ Can be:
639
+ - Empty (new actor with default state)
640
+ - Snapshot (restoring actor from checkpoint)
641
+ - Migration state (actor moving to new node)
642
+ """
643
+
644
+ config: "WasmConfig" = betterproto.message_field(4)
645
+ """
646
+ Configuration overrides (optional)
647
+
648
+ If not provided, uses module's default config or system defaults.
649
+ """
650
+
651
+ target_node_id: str = betterproto.string_field(5)
652
+ """
653
+ Node ID to instantiate on (optional)
654
+
655
+ If not provided, scheduler chooses node based on load balancing.
656
+ """
657
+
658
+
659
+ @dataclass(eq=False, repr=False)
660
+ class InstantiateActorResponse(betterproto.Message):
661
+ """Instantiate WASM actor response"""
662
+
663
+ success: bool = betterproto.bool_field(1)
664
+ """Was instantiation successful?"""
665
+
666
+ actor_id: str = betterproto.string_field(2)
667
+ """Actor ID of instantiated actor"""
668
+
669
+ node_id: str = betterproto.string_field(3)
670
+ """Node ID where actor is running"""
671
+
672
+ created_at: datetime = betterproto.message_field(4)
673
+ """Instance creation time"""
674
+
675
+ error: "WasmError" = betterproto.message_field(5)
676
+ """
677
+ Error details if instantiation failed (replaces error_message)
678
+
679
+ If instantiation succeeded, this field is not set (code = OK).
680
+ If instantiation failed, code indicates failure reason.
681
+ """
682
+
683
+
684
+ @dataclass(eq=False, repr=False)
685
+ class MigrateActorRequest(betterproto.Message):
686
+ """
687
+ Migrate WASM actor request
688
+
689
+ ## Purpose
690
+ Moves a running actor from one node to another. Only state migrates,
691
+ code (WASM module) is already cached on destination node.
692
+
693
+ ## Why This Exists
694
+ - **Load Balancing**: Move actors to less loaded nodes
695
+ - **Node Shutdown**: Drain actors before maintenance
696
+ - **Locality Optimization**: Move actor closer to data
697
+
698
+ ## Design Notes
699
+ - Explicit migration (user-initiated) - simplest approach (User Decision A8)
700
+ - Code cached everywhere - only state migrates (10ms vs 500ms)
701
+ - Atomic migration: Source actor paused until destination ready
702
+ """
703
+
704
+ actor_id: str = betterproto.string_field(1)
705
+ """Actor ID to migrate"""
706
+
707
+ source_node_id: str = betterproto.string_field(2)
708
+ """Source node ID (current location)"""
709
+
710
+ target_node_id: str = betterproto.string_field(3)
711
+ """Destination node ID (target location)"""
712
+
713
+ include_journal: bool = betterproto.bool_field(4)
714
+ """
715
+ Include journal entries (for durable actors)
716
+
717
+ If true, migrate journal for replay on destination.
718
+ """
719
+
720
+
721
+ @dataclass(eq=False, repr=False)
722
+ class MigrateActorResponse(betterproto.Message):
723
+ """Migrate WASM actor response"""
724
+
725
+ success: bool = betterproto.bool_field(1)
726
+ """Was migration successful?"""
727
+
728
+ migration_time: timedelta = betterproto.message_field(2)
729
+ """Migration duration (should be < 10ms for state-only)"""
730
+
731
+ state_size_bytes: int = betterproto.uint64_field(3)
732
+ """Size of state transferred (bytes)"""
733
+
734
+ error: "WasmError" = betterproto.message_field(4)
735
+ """Error details if migration failed"""
736
+
737
+
738
+ @dataclass(eq=False, repr=False)
739
+ class WasmError(betterproto.Message):
740
+ """
741
+ WASM error details
742
+
743
+ ## Purpose
744
+ Provides structured error information for debugging and error handling.
745
+ Replaces simple string error messages with typed, actionable error data.
746
+
747
+ ## Why This Exists
748
+ - **Debugging**: Details map provides context (module name, actor ID, stack trace)
749
+ - **Client Handling**: Clients can programmatically handle specific error codes
750
+ - **Observability**: Error metrics can be tracked by code
751
+ - **Hash Mismatch**: Special fields for integrity check failures
752
+
753
+ ## Design Notes
754
+ - Compatible with gRPC Status (code + message + details)
755
+ - Details map is extensible (add any key-value metadata)
756
+ - expected_hash/actual_hash only populated for HASH_MISMATCH errors
757
+
758
+ ## Examples
759
+ ```
760
+ WasmError {
761
+ code: RESOURCE_LIMIT_EXCEEDED,
762
+ message: "Memory limit exceeded: 18MB > 16MB",
763
+ details: {
764
+ "actor_id": "calc-001@node2",
765
+ "limit": "16777216",
766
+ "actual": "18874368",
767
+ "resource": "memory"
768
+ }
769
+ }
770
+ ```
771
+ """
772
+
773
+ code: "WasmErrorCode" = betterproto.enum_field(1)
774
+ """Error code category"""
775
+
776
+ message: str = betterproto.string_field(2)
777
+ """
778
+ Human-readable error message
779
+
780
+ Format: Brief description suitable for logging and user display
781
+ Example: "Module compilation failed: invalid opcode at offset 0x1234"
782
+ """
783
+
784
+ details: Dict[str, str] = betterproto.map_field(
785
+ 3, betterproto.TYPE_STRING, betterproto.TYPE_STRING
786
+ )
787
+ """
788
+ Additional context for debugging
789
+
790
+ Common keys:
791
+ - "actor_id": Actor that failed
792
+ - "module_name": Module that failed
793
+ - "module_hash": Module hash for integrity errors
794
+ - "stack_trace": Stack trace if available
795
+ - "resource": Resource type (memory, fuel, cpu_time)
796
+ - "limit": Resource limit value
797
+ - "actual": Actual resource usage
798
+ """
799
+
800
+ expected_hash: str = betterproto.string_field(4)
801
+ """For HASH_MISMATCH: expected hash (SHA-256 hex)"""
802
+
803
+ actual_hash: str = betterproto.string_field(5)
804
+ """For HASH_MISMATCH: actual hash (SHA-256 hex)"""
805
+
806
+
807
+ class WasmRuntimeServiceStub(betterproto.ServiceStub):
808
+ async def deploy_module(
809
+ self,
810
+ deploy_wasm_module_request: "DeployWasmModuleRequest",
811
+ *,
812
+ timeout: Optional[float] = None,
813
+ deadline: Optional["Deadline"] = None,
814
+ metadata: Optional["MetadataLike"] = None
815
+ ) -> "DeployWasmModuleResponse":
816
+ return await self._unary_unary(
817
+ "/plexspaces.wasm.v1.WasmRuntimeService/DeployModule",
818
+ deploy_wasm_module_request,
819
+ DeployWasmModuleResponse,
820
+ timeout=timeout,
821
+ deadline=deadline,
822
+ metadata=metadata,
823
+ )
824
+
825
+ async def instantiate_actor(
826
+ self,
827
+ instantiate_actor_request: "InstantiateActorRequest",
828
+ *,
829
+ timeout: Optional[float] = None,
830
+ deadline: Optional["Deadline"] = None,
831
+ metadata: Optional["MetadataLike"] = None
832
+ ) -> "InstantiateActorResponse":
833
+ return await self._unary_unary(
834
+ "/plexspaces.wasm.v1.WasmRuntimeService/InstantiateActor",
835
+ instantiate_actor_request,
836
+ InstantiateActorResponse,
837
+ timeout=timeout,
838
+ deadline=deadline,
839
+ metadata=metadata,
840
+ )
841
+
842
+ async def migrate_actor(
843
+ self,
844
+ migrate_actor_request: "MigrateActorRequest",
845
+ *,
846
+ timeout: Optional[float] = None,
847
+ deadline: Optional["Deadline"] = None,
848
+ metadata: Optional["MetadataLike"] = None
849
+ ) -> "MigrateActorResponse":
850
+ return await self._unary_unary(
851
+ "/plexspaces.wasm.v1.WasmRuntimeService/MigrateActor",
852
+ migrate_actor_request,
853
+ MigrateActorResponse,
854
+ timeout=timeout,
855
+ deadline=deadline,
856
+ metadata=metadata,
857
+ )
858
+
859
+
860
+ class WasmRuntimeServiceBase(ServiceBase):
861
+
862
+ async def deploy_module(
863
+ self, deploy_wasm_module_request: "DeployWasmModuleRequest"
864
+ ) -> "DeployWasmModuleResponse":
865
+ raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
866
+
867
+ async def instantiate_actor(
868
+ self, instantiate_actor_request: "InstantiateActorRequest"
869
+ ) -> "InstantiateActorResponse":
870
+ raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
871
+
872
+ async def migrate_actor(
873
+ self, migrate_actor_request: "MigrateActorRequest"
874
+ ) -> "MigrateActorResponse":
875
+ raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
876
+
877
+ async def __rpc_deploy_module(
878
+ self,
879
+ stream: "grpclib.server.Stream[DeployWasmModuleRequest, DeployWasmModuleResponse]",
880
+ ) -> None:
881
+ request = await stream.recv_message()
882
+ response = await self.deploy_module(request)
883
+ await stream.send_message(response)
884
+
885
+ async def __rpc_instantiate_actor(
886
+ self,
887
+ stream: "grpclib.server.Stream[InstantiateActorRequest, InstantiateActorResponse]",
888
+ ) -> None:
889
+ request = await stream.recv_message()
890
+ response = await self.instantiate_actor(request)
891
+ await stream.send_message(response)
892
+
893
+ async def __rpc_migrate_actor(
894
+ self, stream: "grpclib.server.Stream[MigrateActorRequest, MigrateActorResponse]"
895
+ ) -> None:
896
+ request = await stream.recv_message()
897
+ response = await self.migrate_actor(request)
898
+ await stream.send_message(response)
899
+
900
+ def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
901
+ return {
902
+ "/plexspaces.wasm.v1.WasmRuntimeService/DeployModule": grpclib.const.Handler(
903
+ self.__rpc_deploy_module,
904
+ grpclib.const.Cardinality.UNARY_UNARY,
905
+ DeployWasmModuleRequest,
906
+ DeployWasmModuleResponse,
907
+ ),
908
+ "/plexspaces.wasm.v1.WasmRuntimeService/InstantiateActor": grpclib.const.Handler(
909
+ self.__rpc_instantiate_actor,
910
+ grpclib.const.Cardinality.UNARY_UNARY,
911
+ InstantiateActorRequest,
912
+ InstantiateActorResponse,
913
+ ),
914
+ "/plexspaces.wasm.v1.WasmRuntimeService/MigrateActor": grpclib.const.Handler(
915
+ self.__rpc_migrate_actor,
916
+ grpclib.const.Cardinality.UNARY_UNARY,
917
+ MigrateActorRequest,
918
+ MigrateActorResponse,
919
+ ),
920
+ }