@memgrafter/flatagents 0.8.3 → 0.9.0

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/MACHINES.md CHANGED
@@ -22,7 +22,7 @@
22
22
  ```yaml
23
23
  # profiles.yml — agents reference by name
24
24
  spec: flatprofiles
25
- spec_version: "0.8.3"
25
+ spec_version: "0.9.0"
26
26
  data:
27
27
  model_profiles:
28
28
  fast: { provider: cerebras, name: zai-glm-4.6, temperature: 0.6 }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memgrafter/flatagents",
3
- "version": "0.8.3",
3
+ "version": "0.9.0",
4
4
  "description": "TypeScript SDK for FlatAgents - Declarative LLM orchestration with YAML",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -149,7 +149,7 @@
149
149
  * The profile field specifies which profile name to use as base.
150
150
  */
151
151
 
152
- export const SPEC_VERSION = "0.8.3";
152
+ export const SPEC_VERSION = "0.9.0";
153
153
 
154
154
  export interface AgentWrapper {
155
155
  spec: "flatagent";
@@ -1,4 +1,4 @@
1
- export const SPEC_VERSION = "0.8.3";
1
+ export const SPEC_VERSION = "0.9.0";
2
2
  export interface AgentWrapper {
3
3
  spec: "flatagent";
4
4
  spec_version: string;
@@ -13,6 +13,8 @@
13
13
  * - ResultBackend: InMemoryResultBackend (MUST)
14
14
  * - ExecutionType: Default, Retry, Parallel, MDAPVoting (MUST)
15
15
  * - MachineHooks: Base interface (MUST)
16
+ * - RegistrationBackend: SQLiteRegistrationBackend (MUST), MemoryRegistrationBackend (SHOULD)
17
+ * - WorkBackend: SQLiteWorkBackend (MUST), MemoryWorkBackend (SHOULD)
16
18
  *
17
19
  * OPTIONAL IMPLEMENTATIONS:
18
20
  * -------------------------
@@ -314,6 +316,158 @@ export interface LaunchIntent {
314
316
  launched: boolean;
315
317
  }
316
318
 
319
+ /**
320
+ * REGISTRATION BACKEND:
321
+ * ---------------------
322
+ * Worker lifecycle management for distributed execution.
323
+ *
324
+ * SDKs MUST provide:
325
+ * - SQLiteRegistrationBackend: For local deployments
326
+ *
327
+ * SDKs SHOULD provide:
328
+ * - MemoryRegistrationBackend: For testing
329
+ *
330
+ * Implementation notes:
331
+ * - Time units: Python reference SDK uses seconds for all interval values
332
+ * - Stale threshold: SDKs SHOULD default to 2× heartbeat_interval if not specified
333
+ */
334
+ export interface RegistrationBackend {
335
+ /**
336
+ * Register a new worker.
337
+ * Creates a new worker record with status "active".
338
+ */
339
+ register(worker: WorkerRegistration): Promise<WorkerRecord>;
340
+
341
+ /**
342
+ * Update worker's last_heartbeat timestamp.
343
+ * Can optionally update metadata.
344
+ */
345
+ heartbeat(worker_id: string, metadata?: Record<string, any>): Promise<void>;
346
+
347
+ /**
348
+ * Update worker status.
349
+ * Status values (string, not enum for extensibility):
350
+ * - "active": Worker is running and healthy
351
+ * - "terminating": Worker received shutdown signal
352
+ * - "terminated": Worker exited cleanly
353
+ * - "lost": Worker failed heartbeat, presumed dead
354
+ */
355
+ updateStatus(worker_id: string, status: string): Promise<void>;
356
+
357
+ /**
358
+ * Get a worker record by ID.
359
+ * @returns The worker record, or null if not found
360
+ */
361
+ get(worker_id: string): Promise<WorkerRecord | null>;
362
+
363
+ /**
364
+ * List workers matching filter criteria.
365
+ */
366
+ list(filter?: WorkerFilter): Promise<WorkerRecord[]>;
367
+ }
368
+
369
+ export interface WorkerRegistration {
370
+ worker_id: string;
371
+ host?: string;
372
+ pid?: number;
373
+ capabilities?: string[]; // e.g., ["gpu", "paper-analysis"]
374
+ pool_id?: string; // Worker pool grouping
375
+ started_at: string;
376
+ }
377
+
378
+ export interface WorkerRecord extends WorkerRegistration {
379
+ status: string; // See status values in RegistrationBackend.updateStatus
380
+ last_heartbeat: string;
381
+ current_task_id?: string;
382
+ }
383
+
384
+ export interface WorkerFilter {
385
+ status?: string | string[];
386
+ capability?: string;
387
+ pool_id?: string;
388
+ stale_threshold_seconds?: number; // Filter workers with old heartbeats
389
+ }
390
+
391
+ /**
392
+ * WORK BACKEND:
393
+ * -------------
394
+ * Work distribution via named pools with atomic claim.
395
+ *
396
+ * SDKs MUST provide:
397
+ * - SQLiteWorkBackend: For local deployments
398
+ *
399
+ * SDKs SHOULD provide:
400
+ * - MemoryWorkBackend: For testing
401
+ *
402
+ * Implementation notes:
403
+ * - Atomic claim: SDKs MUST ensure no two workers can claim the same job
404
+ * - Test requirements: Include concurrent claim race condition tests
405
+ */
406
+ export interface WorkBackend {
407
+ /**
408
+ * Get a named work pool.
409
+ * Creates the pool if it doesn't exist.
410
+ */
411
+ pool(name: string): WorkPool;
412
+ }
413
+
414
+ export interface WorkPool {
415
+ /**
416
+ * Add work item to the pool.
417
+ * @param item - The work data (will be JSON serialized)
418
+ * @param options.max_retries - Max retry attempts before poisoning (default: 3)
419
+ * @returns The item ID
420
+ */
421
+ push(item: any, options?: { max_retries?: number }): Promise<string>;
422
+
423
+ /**
424
+ * Atomically claim next available item.
425
+ * MUST be atomic - no two workers can claim the same job.
426
+ * @returns The claimed item, or null if pool is empty
427
+ */
428
+ claim(worker_id: string): Promise<WorkItem | null>;
429
+
430
+ /**
431
+ * Mark item as complete.
432
+ * Sets status to "done" and stores result.
433
+ */
434
+ complete(item_id: string, result?: any): Promise<void>;
435
+
436
+ /**
437
+ * Mark item as failed.
438
+ * Increments attempts. If attempts >= max_retries, marks as "poisoned".
439
+ * Otherwise returns to "pending" status for retry.
440
+ */
441
+ fail(item_id: string, error?: string): Promise<void>;
442
+
443
+ /**
444
+ * Get pool depth (unclaimed pending items).
445
+ */
446
+ size(): Promise<number>;
447
+
448
+ /**
449
+ * Release all jobs claimed by a worker.
450
+ * Used for stale worker cleanup.
451
+ * @returns Number of jobs released
452
+ */
453
+ releaseByWorker(worker_id: string): Promise<number>;
454
+ }
455
+
456
+ export interface WorkItem {
457
+ id: string;
458
+ data: any;
459
+ claimed_by?: string;
460
+ claimed_at?: string;
461
+ attempts: number;
462
+ max_retries: number; // default: 3
463
+ }
464
+
465
+ // Job status values (string):
466
+ // - "pending": Available for claim
467
+ // - "claimed": Currently being processed
468
+ // - "done": Successfully completed
469
+ // - "poisoned": Failed max_retries times, will not be retried
470
+
317
471
  export interface BackendConfig {
318
472
  /** Checkpoint storage. Default: memory */
319
473
  persistence?: "memory" | "local" | "redis" | "postgres" | "s3";
@@ -323,24 +477,36 @@ export interface BackendConfig {
323
477
 
324
478
  /** Inter-machine results. Default: memory */
325
479
  results?: "memory" | "redis";
480
+
481
+ /** Worker registration. Default: memory */
482
+ registration?: "memory" | "sqlite" | "redis";
483
+
484
+ /** Work pool. Default: memory */
485
+ work?: "memory" | "sqlite" | "redis";
486
+
487
+ /** Path for sqlite backends (registration and work share this) */
488
+ sqlite_path?: string;
326
489
  }
327
490
 
328
- export const SPEC_VERSION = "0.8.3";
491
+ export const SPEC_VERSION = "0.9.0";
329
492
 
330
493
  /**
331
494
  * Wrapper interface for JSON schema generation.
332
495
  * Groups all runtime interfaces that SDKs must implement.
333
496
  */
334
497
  export interface SDKRuntimeWrapper {
335
- spec: "flatagents-runtime";
336
- spec_version: typeof SPEC_VERSION;
337
- execution_lock?: ExecutionLock;
338
- persistence_backend?: PersistenceBackend;
339
- result_backend?: ResultBackend;
340
- execution_config?: ExecutionConfig;
341
- machine_hooks?: MachineHooks;
342
- llm_backend?: LLMBackend;
343
- machine_invoker?: MachineInvoker;
344
- backend_config?: BackendConfig;
345
- machine_snapshot?: MachineSnapshot;
498
+ spec: "flatagents-runtime";
499
+ spec_version: typeof SPEC_VERSION;
500
+ execution_lock?: ExecutionLock;
501
+ persistence_backend?: PersistenceBackend;
502
+ result_backend?: ResultBackend;
503
+ execution_config?: ExecutionConfig;
504
+ machine_hooks?: MachineHooks;
505
+ llm_backend?: LLMBackend;
506
+ machine_invoker?: MachineInvoker;
507
+ backend_config?: BackendConfig;
508
+ machine_snapshot?: MachineSnapshot;
509
+ registration_backend?: RegistrationBackend;
510
+ work_backend?: WorkBackend;
346
511
  }
512
+
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "spec_version": {
13
13
  "type": "string",
14
- "const": "0.8.3"
14
+ "const": "0.9.0"
15
15
  },
16
16
  "execution_lock": {
17
17
  "$ref": "#/definitions/ExecutionLock"
@@ -39,6 +39,12 @@
39
39
  },
40
40
  "machine_snapshot": {
41
41
  "$ref": "#/definitions/MachineSnapshot"
42
+ },
43
+ "registration_backend": {
44
+ "$ref": "#/definitions/RegistrationBackend"
45
+ },
46
+ "work_backend": {
47
+ "$ref": "#/definitions/WorkBackend"
42
48
  }
43
49
  },
44
50
  "required": [
@@ -51,7 +57,7 @@
51
57
  "ExecutionLock": {
52
58
  "type": "object",
53
59
  "additionalProperties": false,
54
- "description": "FlatAgents Runtime Interface Spec ==================================\n\nThis file defines the runtime interfaces that SDKs MUST implement to be considered compliant. These are NOT configuration schemas (see flatagent.d.ts and flatmachine.d.ts for those).\n\nREQUIRED IMPLEMENTATIONS:\n------------------------- - ExecutionLock: NoOpLock (MUST), LocalFileLock (SHOULD) - PersistenceBackend: MemoryBackend (MUST), LocalFileBackend (SHOULD) - ResultBackend: InMemoryResultBackend (MUST) - ExecutionType: Default, Retry, Parallel, MDAPVoting (MUST) - MachineHooks: Base interface (MUST)\n\nOPTIONAL IMPLEMENTATIONS:\n------------------------- - Distributed backends (Redis, Postgres, etc.) - LLMBackend (SDK may use native provider SDKs)\n\nEXECUTION LOCKING:\n------------------ Prevents concurrent execution of the same machine instance.\n\nSDKs MUST provide: - NoOpLock: For when locking is handled externally or disabled\n\nSDKs SHOULD provide: - LocalFileLock: For single-node deployments using fcntl/flock\n\nDistributed deployments should implement Redis/Consul/etcd locks.\n\nPERSISTENCE BACKEND:\n-------------------- Storage backend for machine checkpoints.\n\nSDKs MUST provide: - MemoryBackend: For testing and ephemeral runs\n\nSDKs SHOULD provide: - LocalFileBackend: For durable local storage with atomic writes\n\nRESULT BACKEND:\n--------------- Inter-machine communication via URI-addressed results.\n\nURI format: flatagents://{execution_id}/{path} - path is typically \"result\" or \"checkpoint\"\n\nSDKs MUST provide: - InMemoryResultBackend: For single-process execution\n\nEXECUTION TYPES:\n---------------- Execution strategy for agent calls.\n\nSDKs MUST implement all four types: - default: Single call, no retry - retry: Configurable backoffs with jitter - parallel: Run N samples, return all successes - mdap_voting: Multi-sample with consensus voting\n\nMACHINE HOOKS:\n-------------- Extension points for machine execution. All methods are optional and can be sync or async.\n\nSDKs SHOULD provide: - WebhookHooks: Send events to HTTP endpoint - CompositeHooks: Combine multiple hook implementations\n\nLLM BACKEND (OPTIONAL):\n----------------------- Abstraction over LLM providers.\n\nThis interface is OPTIONAL - SDKs may use provider SDKs directly. Useful for: - Unified retry/monitoring across providers - Provider-agnostic code - Testing with mock backends\n\nMACHINE INVOKER:\n---------------- Interface for invoking peer machines. Used internally by FlatMachine for `machine:` and `launch:` states.\n\nBACKEND CONFIGURATION:\n---------------------- Backend configuration for machine settings.\n\nExample in YAML: settings: backends: persistence: local locking: none results: memory"
60
+ "description": "FlatAgents Runtime Interface Spec ==================================\n\nThis file defines the runtime interfaces that SDKs MUST implement to be considered compliant. These are NOT configuration schemas (see flatagent.d.ts and flatmachine.d.ts for those).\n\nREQUIRED IMPLEMENTATIONS:\n------------------------- - ExecutionLock: NoOpLock (MUST), LocalFileLock (SHOULD) - PersistenceBackend: MemoryBackend (MUST), LocalFileBackend (SHOULD) - ResultBackend: InMemoryResultBackend (MUST) - ExecutionType: Default, Retry, Parallel, MDAPVoting (MUST) - MachineHooks: Base interface (MUST) - RegistrationBackend: SQLiteRegistrationBackend (MUST), MemoryRegistrationBackend (SHOULD) - WorkBackend: SQLiteWorkBackend (MUST), MemoryWorkBackend (SHOULD)\n\nOPTIONAL IMPLEMENTATIONS:\n------------------------- - Distributed backends (Redis, Postgres, etc.) - LLMBackend (SDK may use native provider SDKs)\n\nEXECUTION LOCKING:\n------------------ Prevents concurrent execution of the same machine instance.\n\nSDKs MUST provide: - NoOpLock: For when locking is handled externally or disabled\n\nSDKs SHOULD provide: - LocalFileLock: For single-node deployments using fcntl/flock\n\nDistributed deployments should implement Redis/Consul/etcd locks.\n\nPERSISTENCE BACKEND:\n-------------------- Storage backend for machine checkpoints.\n\nSDKs MUST provide: - MemoryBackend: For testing and ephemeral runs\n\nSDKs SHOULD provide: - LocalFileBackend: For durable local storage with atomic writes\n\nRESULT BACKEND:\n--------------- Inter-machine communication via URI-addressed results.\n\nURI format: flatagents://{execution_id}/{path} - path is typically \"result\" or \"checkpoint\"\n\nSDKs MUST provide: - InMemoryResultBackend: For single-process execution\n\nEXECUTION TYPES:\n---------------- Execution strategy for agent calls.\n\nSDKs MUST implement all four types: - default: Single call, no retry - retry: Configurable backoffs with jitter - parallel: Run N samples, return all successes - mdap_voting: Multi-sample with consensus voting\n\nMACHINE HOOKS:\n-------------- Extension points for machine execution. All methods are optional and can be sync or async.\n\nSDKs SHOULD provide: - WebhookHooks: Send events to HTTP endpoint - CompositeHooks: Combine multiple hook implementations\n\nLLM BACKEND (OPTIONAL):\n----------------------- Abstraction over LLM providers.\n\nThis interface is OPTIONAL - SDKs may use provider SDKs directly. Useful for: - Unified retry/monitoring across providers - Provider-agnostic code - Testing with mock backends\n\nMACHINE INVOKER:\n---------------- Interface for invoking peer machines. Used internally by FlatMachine for `machine:` and `launch:` states.\n\nBACKEND CONFIGURATION:\n---------------------- Backend configuration for machine settings.\n\nExample in YAML: settings: backends: persistence: local locking: none results: memory"
55
61
  },
56
62
  "PersistenceBackend": {
57
63
  "type": "object",
@@ -154,6 +160,28 @@
154
160
  "redis"
155
161
  ],
156
162
  "description": "Inter-machine results. Default: memory"
163
+ },
164
+ "registration": {
165
+ "type": "string",
166
+ "enum": [
167
+ "memory",
168
+ "sqlite",
169
+ "redis"
170
+ ],
171
+ "description": "Worker registration. Default: memory"
172
+ },
173
+ "work": {
174
+ "type": "string",
175
+ "enum": [
176
+ "memory",
177
+ "sqlite",
178
+ "redis"
179
+ ],
180
+ "description": "Work pool. Default: memory"
181
+ },
182
+ "sqlite_path": {
183
+ "type": "string",
184
+ "description": "Path for sqlite backends (registration and work share this)"
157
185
  }
158
186
  },
159
187
  "additionalProperties": false
@@ -238,6 +266,16 @@
238
266
  "launched"
239
267
  ],
240
268
  "additionalProperties": false
269
+ },
270
+ "RegistrationBackend": {
271
+ "type": "object",
272
+ "additionalProperties": false,
273
+ "description": "REGISTRATION BACKEND:\n--------------------- Worker lifecycle management for distributed execution.\n\nSDKs MUST provide: - SQLiteRegistrationBackend: For local deployments\n\nSDKs SHOULD provide: - MemoryRegistrationBackend: For testing\n\nImplementation notes: - Time units: Python reference SDK uses seconds for all interval values - Stale threshold: SDKs SHOULD default to 2× heartbeat_interval if not specified"
274
+ },
275
+ "WorkBackend": {
276
+ "type": "object",
277
+ "additionalProperties": false,
278
+ "description": "WORK BACKEND:\n------------- Work distribution via named pools with atomic claim.\n\nSDKs MUST provide: - SQLiteWorkBackend: For local deployments\n\nSDKs SHOULD provide: - MemoryWorkBackend: For testing\n\nImplementation notes: - Atomic claim: SDKs MUST ensure no two workers can claim the same job - Test requirements: Include concurrent claim race condition tests"
241
279
  }
242
280
  }
243
281
  }
@@ -102,12 +102,62 @@ export interface LaunchIntent {
102
102
  input: Record<string, any>;
103
103
  launched: boolean;
104
104
  }
105
+ export interface RegistrationBackend {
106
+ register(worker: WorkerRegistration): Promise<WorkerRecord>;
107
+ heartbeat(worker_id: string, metadata?: Record<string, any>): Promise<void>;
108
+ updateStatus(worker_id: string, status: string): Promise<void>;
109
+ get(worker_id: string): Promise<WorkerRecord | null>;
110
+ list(filter?: WorkerFilter): Promise<WorkerRecord[]>;
111
+ }
112
+ export interface WorkerRegistration {
113
+ worker_id: string;
114
+ host?: string;
115
+ pid?: number;
116
+ capabilities?: string[];
117
+ pool_id?: string;
118
+ started_at: string;
119
+ }
120
+ export interface WorkerRecord extends WorkerRegistration {
121
+ status: string;
122
+ last_heartbeat: string;
123
+ current_task_id?: string;
124
+ }
125
+ export interface WorkerFilter {
126
+ status?: string | string[];
127
+ capability?: string;
128
+ pool_id?: string;
129
+ stale_threshold_seconds?: number;
130
+ }
131
+ export interface WorkBackend {
132
+ pool(name: string): WorkPool;
133
+ }
134
+ export interface WorkPool {
135
+ push(item: any, options?: {
136
+ max_retries?: number;
137
+ }): Promise<string>;
138
+ claim(worker_id: string): Promise<WorkItem | null>;
139
+ complete(item_id: string, result?: any): Promise<void>;
140
+ fail(item_id: string, error?: string): Promise<void>;
141
+ size(): Promise<number>;
142
+ releaseByWorker(worker_id: string): Promise<number>;
143
+ }
144
+ export interface WorkItem {
145
+ id: string;
146
+ data: any;
147
+ claimed_by?: string;
148
+ claimed_at?: string;
149
+ attempts: number;
150
+ max_retries: number;
151
+ }
105
152
  export interface BackendConfig {
106
153
  persistence?: "memory" | "local" | "redis" | "postgres" | "s3";
107
154
  locking?: "none" | "local" | "redis" | "consul";
108
155
  results?: "memory" | "redis";
156
+ registration?: "memory" | "sqlite" | "redis";
157
+ work?: "memory" | "sqlite" | "redis";
158
+ sqlite_path?: string;
109
159
  }
110
- export const SPEC_VERSION = "0.8.3";
160
+ export const SPEC_VERSION = "0.9.0";
111
161
  export interface SDKRuntimeWrapper {
112
162
  spec: "flatagents-runtime";
113
163
  spec_version: typeof SPEC_VERSION;
@@ -120,4 +170,6 @@ export interface SDKRuntimeWrapper {
120
170
  machine_invoker?: MachineInvoker;
121
171
  backend_config?: BackendConfig;
122
172
  machine_snapshot?: MachineSnapshot;
173
+ registration_backend?: RegistrationBackend;
174
+ work_backend?: WorkBackend;
123
175
  }
@@ -256,7 +256,7 @@
256
256
  * pending_launches - Outbox pattern (v0.4.0)
257
257
  */
258
258
 
259
- export const SPEC_VERSION = "0.8.3";
259
+ export const SPEC_VERSION = "0.9.0";
260
260
 
261
261
  export interface MachineWrapper {
262
262
  spec: "flatmachine";
@@ -1,4 +1,4 @@
1
- export const SPEC_VERSION = "0.8.3";
1
+ export const SPEC_VERSION = "0.9.0";
2
2
  export interface MachineWrapper {
3
3
  spec: "flatmachine";
4
4
  spec_version: string;
@@ -107,7 +107,7 @@
107
107
  * base_url - Custom base URL for the API (e.g., for local models or proxies)
108
108
  */
109
109
 
110
- export const SPEC_VERSION = "0.8.3";
110
+ export const SPEC_VERSION = "0.9.0";
111
111
 
112
112
  export interface ProfilesWrapper {
113
113
  spec: "flatprofiles";
@@ -1,4 +1,4 @@
1
- export const SPEC_VERSION = "0.8.3";
1
+ export const SPEC_VERSION = "0.9.0";
2
2
  export interface ProfilesWrapper {
3
3
  spec: "flatprofiles";
4
4
  spec_version: string;