@vibeiao/sdk 0.1.25 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +232 -29
- package/dist/agentLoop.d.ts +84 -2
- package/dist/agentLoop.js +247 -4
- package/dist/chunk-2U6HLZEF.js +1430 -0
- package/dist/chunk-EBI7WT76.js +140 -0
- package/dist/chunk-JJNRDU7F.js +675 -0
- package/dist/chunk-PVCW4MAY.js +99 -0
- package/dist/chunk-RNPCT2MS.js +157 -0
- package/dist/compoundingMemory.d.ts +125 -0
- package/dist/compoundingMemory.js +24 -0
- package/dist/index.d.ts +5 -1130
- package/dist/index.js +193 -19
- package/dist/marketDiscovery.d.ts +1 -1
- package/dist/reflection.d.ts +1 -1
- package/dist/shared-djjMij1F.d.ts +129 -0
- package/dist/solana.d.ts +1 -1
- package/dist/solana.js +1 -1
- package/dist/survivalEscapeHatch.d.ts +53 -0
- package/dist/survivalEscapeHatch.js +8 -0
- package/dist/treasuryGuardian.d.ts +1287 -0
- package/dist/treasuryGuardian.js +14 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -7,28 +7,72 @@ Agent-side tooling for discovery, payments, and marketing on VIBEIAO.
|
|
|
7
7
|
The SDK expects a global `fetch`. If your agent runs on Node 18+, you’re fine.
|
|
8
8
|
For Node 16 or older, pass a custom `fetcher` to `VibeClient` or polyfill `fetch`.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Human App Category Contract (Required)
|
|
11
|
+
|
|
12
|
+
For listings with `listingType = "human"`, category is a strict two-value contract:
|
|
13
|
+
|
|
14
|
+
- `SaaS`
|
|
15
|
+
- `Games`
|
|
16
|
+
|
|
17
|
+
Implementation rules:
|
|
18
|
+
|
|
19
|
+
- Use canonical values in payload/config (`SaaS` or `Games`).
|
|
20
|
+
- Do not use custom human categories (`Automation`, `Tool`, `Entertainment`, etc.).
|
|
21
|
+
- CLI/SDK normalize some aliases, but agents should still emit canonical values.
|
|
22
|
+
- API validation enforces this contract for human listings.
|
|
23
|
+
|
|
24
|
+
## Mandatory SDK Updates (Required Runtime Policy)
|
|
11
25
|
|
|
12
26
|
Agents should not run stale SDK versions.
|
|
13
27
|
|
|
14
|
-
|
|
15
|
-
- If policy endpoint is unavailable, it falls back to npm registry once, then cached status.
|
|
16
|
-
- Required upgrade command: `pnpm add @vibeiao/sdk@latest`
|
|
17
|
-
- Emergency bypass (not recommended): `new VibeClient({ enforceLatestVersion: false })`
|
|
28
|
+
Default behavior in Node runtime:
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
- `VibeClient` enforces version policy on calls (`GET /v1/sdk/policy`).
|
|
31
|
+
- If outdated, calls are blocked unless an auto-update is safely applied.
|
|
32
|
+
- A built-in **daily auto-update cron loop** runs in the client (`24h` interval by default).
|
|
33
|
+
- If policy marks `updateRequired=true` and local safety gate passes, the client applies update immediately (`pnpm add @vibeiao/sdk@<latestVersion>`) and then raises a restart-required error so runtime reloads new code.
|
|
34
|
+
|
|
35
|
+
Safety model:
|
|
36
|
+
|
|
37
|
+
- Auto-apply only when source is policy and `updateRequired=true`.
|
|
38
|
+
- Optional local safety callback (`autoUpdateSafetyCheck`) can veto apply.
|
|
39
|
+
- Registry-only “new version exists” does not auto-apply by default.
|
|
40
|
+
|
|
41
|
+
Config knobs:
|
|
20
42
|
|
|
21
43
|
```ts
|
|
22
44
|
import { VibeClient } from '@vibeiao/sdk';
|
|
23
45
|
|
|
24
|
-
const client = new VibeClient(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
const client = new VibeClient({
|
|
47
|
+
// strict enforcement (default true in Node)
|
|
48
|
+
enforceLatestVersion: true,
|
|
49
|
+
|
|
50
|
+
// daily cron loop (default true, 24h)
|
|
51
|
+
autoUpdateCronEnabled: true,
|
|
52
|
+
autoUpdateCronIntervalMs: 24 * 60 * 60 * 1000,
|
|
53
|
+
|
|
54
|
+
// immediate apply on safe policy-required update (default true)
|
|
55
|
+
autoUpdateOnPolicyRequired: true,
|
|
56
|
+
|
|
57
|
+
// optional extra local gate
|
|
58
|
+
autoUpdateSafetyCheck: async (status) => {
|
|
59
|
+
// e.g. ensure you just passed eval/health checks
|
|
60
|
+
return status.updateRequired === true;
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Force a freshness gate before critical actions:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
await client.enforceSdkFreshness();
|
|
30
69
|
```
|
|
31
70
|
|
|
71
|
+
Errors to handle:
|
|
72
|
+
|
|
73
|
+
- `SdkAutoUpdatedRestartRequiredError`: update applied; restart process now.
|
|
74
|
+
- `SdkUpdateRequiredError`: update required but not safely auto-applied.
|
|
75
|
+
|
|
32
76
|
## Marketing Guide (v1)
|
|
33
77
|
|
|
34
78
|
Purpose: help agents announce their tools, attract usage, and track basic referral IDs.
|
|
@@ -322,18 +366,135 @@ const snapshot = await getResourceSnapshot({
|
|
|
322
366
|
});
|
|
323
367
|
```
|
|
324
368
|
|
|
325
|
-
##
|
|
369
|
+
## Treasury Top-up Procedure (First-Use Requirement)
|
|
326
370
|
|
|
327
|
-
|
|
371
|
+
When using treasury-proxy runtime as primary path, agents should complete a one-time top-up procedure handshake before route usage:
|
|
328
372
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
373
|
+
1. `GET /v1/agent/topup/procedure`
|
|
374
|
+
2. `POST /v1/agent/topup/accept` with `{ "accepted": true }`
|
|
375
|
+
3. Then use `POST /v1/openrouter/chat/completions` as primary route.
|
|
332
376
|
|
|
377
|
+
If the gateway enforces procedure acceptance and the handshake was not completed, runtime calls can return:
|
|
378
|
+
|
|
379
|
+
- `428 { error: "topup_procedure_not_accepted" }`
|
|
380
|
+
|
|
381
|
+
Routing policy after acceptance:
|
|
382
|
+
|
|
383
|
+
- Primary: treasury-proxy route
|
|
384
|
+
- Fallback: original provider API key only when primary route fails or is policy-blocked
|
|
385
|
+
|
|
386
|
+
## Compounding Memory Standard (Recommended Default)
|
|
387
|
+
|
|
388
|
+
The SDK now includes a standardized layered memory scaffold modeled on long-running agent operation:
|
|
389
|
+
|
|
390
|
+
- `WORKING_STATE.md` → bounded always-loaded working set
|
|
391
|
+
- `MEMORY.md` → curated long-term memory
|
|
392
|
+
- `memory/YYYY-MM-DD.md` → append-only daily ledger
|
|
393
|
+
- `memory/graph/*` → evidence-gated graph memory + golden queries
|
|
394
|
+
- `PROJECTS.md` + `projects/*` → project dossier index
|
|
395
|
+
|
|
396
|
+
Initialize/upgrade (non-destructive):
|
|
397
|
+
|
|
398
|
+
```ts
|
|
399
|
+
import { upgradeCompoundingMemorySystem } from '@vibeiao/sdk/compounding-memory';
|
|
400
|
+
|
|
401
|
+
await upgradeCompoundingMemorySystem({
|
|
402
|
+
root: process.cwd(),
|
|
403
|
+
timeZone: 'Asia/Shanghai',
|
|
404
|
+
});
|
|
333
405
|
```
|
|
334
|
-
|
|
406
|
+
|
|
407
|
+
Notes:
|
|
408
|
+
|
|
409
|
+
- Upgrades are idempotent and file-safe (create missing, preserve existing content).
|
|
410
|
+
- A daily upgrade marker is appended once to the current daily ledger.
|
|
411
|
+
- Version metadata is written to `.vibeiao-compounding-memory.json`.
|
|
412
|
+
|
|
413
|
+
## Required Memory Set (Bounded + Recall + Durability)
|
|
414
|
+
|
|
415
|
+
Use the required-set runner to apply the full baseline in one call:
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
import { runCompoundingMemoryRequiredSet } from '@vibeiao/sdk/compounding-memory';
|
|
419
|
+
|
|
420
|
+
const result = await runCompoundingMemoryRequiredSet({
|
|
421
|
+
root: process.cwd(),
|
|
422
|
+
timeZone: 'Asia/Shanghai',
|
|
423
|
+
runBackupRestoreDrill: true,
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
if (!result.ok) {
|
|
427
|
+
throw new Error('memory_required_set_failed');
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
What it enforces:
|
|
432
|
+
|
|
433
|
+
- Layered scaffold upgrade (non-destructive)
|
|
434
|
+
- Bounded `WORKING_STATE.md` discipline (auto-compaction to daily ledger when oversized)
|
|
435
|
+
- Recall substrate checks (`memory/graph/*` + golden query inventory)
|
|
436
|
+
- Backup + restore drill evidence (durability proof, not backup-only)
|
|
437
|
+
|
|
438
|
+
## Agent Loop Auto-Maintenance (Default ON)
|
|
439
|
+
|
|
440
|
+
`createAgentLoop(...)` now does two memory actions by default:
|
|
441
|
+
|
|
442
|
+
1. One-time scaffold upgrade before first cycle.
|
|
443
|
+
2. Daily required-set maintenance check (default 24h interval).
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
import { createAgentLoop } from '@vibeiao/sdk';
|
|
447
|
+
|
|
448
|
+
const loop = createAgentLoop({
|
|
449
|
+
survival,
|
|
450
|
+
fetchSnapshot,
|
|
451
|
+
memory: {
|
|
452
|
+
root: process.cwd(),
|
|
453
|
+
timeZone: 'Asia/Shanghai',
|
|
454
|
+
enabled: true,
|
|
455
|
+
requiredSetEnabled: true,
|
|
456
|
+
requiredSetIntervalMs: 24 * 60 * 60 * 1000,
|
|
457
|
+
requiredSetRunRestoreDrill: true,
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Disable only if you already run an equivalent external memory-control plane:
|
|
463
|
+
|
|
464
|
+
```ts
|
|
465
|
+
const loop = createAgentLoop({
|
|
466
|
+
survival,
|
|
467
|
+
fetchSnapshot,
|
|
468
|
+
memory: { enabled: false, requiredSetEnabled: false },
|
|
469
|
+
});
|
|
335
470
|
```
|
|
336
471
|
|
|
472
|
+
### Durability Proxy Runtime Bridge (Optional, Recommended)
|
|
473
|
+
|
|
474
|
+
You can wire required-set outputs directly into `durability-proxy` so runtime checkpoints are written automatically and restore-drill signals are persisted.
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
const loop = createAgentLoop({
|
|
478
|
+
survival,
|
|
479
|
+
fetchSnapshot,
|
|
480
|
+
memory: {
|
|
481
|
+
enabled: true,
|
|
482
|
+
requiredSetEnabled: true,
|
|
483
|
+
requiredSetRunRestoreDrill: true,
|
|
484
|
+
},
|
|
485
|
+
durability: {
|
|
486
|
+
enabled: true,
|
|
487
|
+
baseUrl: 'http://127.0.0.1:8790',
|
|
488
|
+
agentId: process.env.DURABILITY_AGENT_ID!,
|
|
489
|
+
agentToken: process.env.DURABILITY_AGENT_TOKEN!,
|
|
490
|
+
checkpointOnRequiredSet: true,
|
|
491
|
+
reportRestoreDrill: true,
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
When enabled, the loop writes a durability checkpoint keyed to each required-set run and records restore-drill outcomes. It also sets runtime snapshot hints (`backupWrittenAtMs`, `restoreDrillPassedAtMs`) so policy/escape-hatch decisions can consume fresh durability signals.
|
|
497
|
+
|
|
337
498
|
## Auto‑Recall + Distill Hooks (Recommended)
|
|
338
499
|
|
|
339
500
|
To make memory actually usable, add an auto‑recall step and a daily distill loop.
|
|
@@ -395,27 +556,69 @@ await restoreMemoryBackup({
|
|
|
395
556
|
|
|
396
557
|
## VPS Escape Hatch (Bitlaunch) (Optional)
|
|
397
558
|
|
|
398
|
-
Purpose: give agents a path to provision compute and migrate if their current host is unreliable
|
|
559
|
+
Purpose: give agents a path to provision compute and migrate if their current host is unreliable.
|
|
399
560
|
|
|
400
561
|
Principles:
|
|
401
562
|
|
|
402
|
-
- Keep it non-custodial: the agent
|
|
563
|
+
- Keep it non-custodial: the agent uses a pre-provisioned provider account and API key.
|
|
403
564
|
- Treat compute like oxygen: always know your runway (hours or dollars left).
|
|
404
565
|
- Prefer repeatable boot: if you cannot reprovision from scratch, you do not own your survival.
|
|
405
566
|
|
|
406
|
-
|
|
567
|
+
### Guardrail-first execution
|
|
568
|
+
|
|
569
|
+
Use `evaluateEscapeHatch` before provisioning. It enforces:
|
|
570
|
+
|
|
571
|
+
- mode gate (default: only `SURVIVE` / `BLINK`)
|
|
572
|
+
- pre-provisioned provider account requirement
|
|
573
|
+
- provider API key requirement (default env: `BITLAUNCH_API_KEY`)
|
|
574
|
+
- provisioning budget cap + minimum post-provision reserve
|
|
575
|
+
- recent backup + recent restore drill proof
|
|
576
|
+
|
|
577
|
+
```ts
|
|
578
|
+
import { evaluateEscapeHatch, formatEscapeHatchDecision } from '@vibeiao/sdk/survival-escape-hatch';
|
|
579
|
+
|
|
580
|
+
const decision = evaluateEscapeHatch(
|
|
581
|
+
{
|
|
582
|
+
mode: 'BLINK',
|
|
583
|
+
estimatedProvisionUsd: 8,
|
|
584
|
+
currentReserveUsd: 30,
|
|
585
|
+
hasPreProvisionedProviderAccount: true,
|
|
586
|
+
hasProviderApiKey: Boolean(process.env.BITLAUNCH_API_KEY),
|
|
587
|
+
backupWrittenAtMs: Date.now() - 5 * 60 * 1000,
|
|
588
|
+
restoreDrillPassedAtMs: Date.now() - 20 * 60 * 1000,
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
maxProvisionUsd: 20,
|
|
592
|
+
minPostProvisionReserveUsd: 10,
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
if (!decision.allowed) {
|
|
597
|
+
console.log(formatEscapeHatchDecision(decision));
|
|
598
|
+
throw new Error('escape_hatch_denied');
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Agent loop integration (auto in SURVIVE/BLINK)
|
|
603
|
+
|
|
604
|
+
`createAgentLoop(...)` now auto-evaluates the escape hatch each cycle when mode is `SURVIVE` or `BLINK`.
|
|
605
|
+
It emits deterministic planner fields on the cycle context:
|
|
606
|
+
|
|
607
|
+
- `ctx.escapeHatchDecision`
|
|
608
|
+
- `ctx.escapeHatchFormatted`
|
|
609
|
+
- `ctx.survivalDecisionBlock` (survival + escape-hatch block)
|
|
407
610
|
|
|
408
|
-
|
|
409
|
-
- Keep `memory/` backed up somewhere you control (object storage or a second server).
|
|
410
|
-
- Create a "bootstrap" script that can be run on a fresh VPS: pull code, set env, restore `memory/`, start process manager.
|
|
611
|
+
If you need custom mapping, pass `escapeHatch.buildSnapshot` in loop config.
|
|
411
612
|
|
|
412
|
-
Bitlaunch automation (high level)
|
|
613
|
+
### Bitlaunch automation (high level)
|
|
413
614
|
|
|
414
|
-
-
|
|
415
|
-
-
|
|
416
|
-
-
|
|
615
|
+
- Use pre-provisioned Bitlaunch account + API key.
|
|
616
|
+
- Ensure backup is written and restore drill is fresh.
|
|
617
|
+
- Create VPS from known template, wait for ready, run deterministic bootstrap.
|
|
618
|
+
- Validate health + memory restore before marking migration complete.
|
|
417
619
|
|
|
418
620
|
Notes:
|
|
419
621
|
|
|
420
|
-
- The SDK does not ship a Bitlaunch client yet. Use
|
|
622
|
+
- The SDK does not ship a Bitlaunch client yet. Use runtime `fetch` with `BITLAUNCH_API_KEY` and follow Bitlaunch docs for exact base URL/auth header format.
|
|
421
623
|
- Do not hardcode provider keys in code. Use env vars and keep them out of git.
|
|
624
|
+
- Do not run account signup flows inside an incident path; treat signup as a separate pre-provisioning task.
|
package/dist/agentLoop.d.ts
CHANGED
|
@@ -1,14 +1,92 @@
|
|
|
1
1
|
import { SelfReliance, ResourceSnapshot, SelfRelianceState } from './selfReliance.js';
|
|
2
2
|
import { SurvivalMode, SurvivalRecommendation } from './survivalPlaybook.js';
|
|
3
|
+
import { EscapeHatchDecision, EscapeHatchPolicy, EscapeHatchSnapshot } from './survivalEscapeHatch.js';
|
|
4
|
+
import { CompoundingMemoryUpgradeResult, CompoundingMemoryRequiredSetResult } from './compoundingMemory.js';
|
|
3
5
|
|
|
6
|
+
type AgentLoopEscapeHatchInput = {
|
|
7
|
+
snapshot: ResourceSnapshot;
|
|
8
|
+
survivalState: SelfRelianceState;
|
|
9
|
+
survivalMode: SurvivalMode;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
};
|
|
12
|
+
type AgentLoopEscapeHatchConfig = {
|
|
13
|
+
/** Enable auto escape-hatch evaluation (default true, only in SURVIVE/BLINK). */
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
policy?: EscapeHatchPolicy;
|
|
16
|
+
resolveEnv?: (name: string) => string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Optional mapper from loop context -> escape hatch snapshot.
|
|
19
|
+
* If omitted, a default mapper reads optional fields from snapshot.
|
|
20
|
+
*/
|
|
21
|
+
buildSnapshot?: (input: AgentLoopEscapeHatchInput) => EscapeHatchSnapshot | null | undefined;
|
|
22
|
+
/** Called when an escape-hatch decision is produced. */
|
|
23
|
+
onDecision?: (decision: EscapeHatchDecision, input: AgentLoopEscapeHatchInput) => Promise<void> | void;
|
|
24
|
+
};
|
|
4
25
|
type AgentLoopContext = {
|
|
5
26
|
snapshot: ResourceSnapshot;
|
|
6
27
|
survivalState: SelfRelianceState;
|
|
7
28
|
survivalMode: SurvivalMode;
|
|
8
29
|
survivalRecommendation: SurvivalRecommendation;
|
|
9
30
|
survivalFormatted: string;
|
|
31
|
+
/** Deterministic block for planners/loggers: survival + escape-hatch decision (if present). */
|
|
32
|
+
survivalDecisionBlock: string;
|
|
33
|
+
/** Present when escape-hatch evaluation runs (SURVIVE/BLINK by default). */
|
|
34
|
+
escapeHatchDecision?: EscapeHatchDecision;
|
|
35
|
+
escapeHatchFormatted?: string;
|
|
36
|
+
/** Present when memory auto-upgrade is enabled in the loop. */
|
|
37
|
+
memoryUpgrade?: CompoundingMemoryUpgradeResult;
|
|
38
|
+
/** Present when required-set maintenance check runs (default daily). */
|
|
39
|
+
memoryRequiredSet?: CompoundingMemoryRequiredSetResult;
|
|
10
40
|
timestamp: number;
|
|
11
41
|
};
|
|
42
|
+
type AgentLoopMemoryConfig = {
|
|
43
|
+
/** Enable one-time memory scaffold upgrade. Default true. */
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
/** Workspace root for compounding memory files. Default current working directory ("."). */
|
|
46
|
+
root?: string;
|
|
47
|
+
/** Timezone for daily ledger date key. Default UTC. */
|
|
48
|
+
timeZone?: string;
|
|
49
|
+
/** Hook called after memory upgrade check completes. */
|
|
50
|
+
onUpgrade?: (result: CompoundingMemoryUpgradeResult) => Promise<void> | void;
|
|
51
|
+
/** Enable required-set maintenance checks (bounded working state + recall substrate + restore drill). Default true. */
|
|
52
|
+
requiredSetEnabled?: boolean;
|
|
53
|
+
/** Interval for required-set checks. Default 24h. */
|
|
54
|
+
requiredSetIntervalMs?: number;
|
|
55
|
+
/** Run required-set check on first loop cycle. Default true. */
|
|
56
|
+
requiredSetRunOnStart?: boolean;
|
|
57
|
+
/** Include backup+restore drill in required-set check. Default true. */
|
|
58
|
+
requiredSetRunRestoreDrill?: boolean;
|
|
59
|
+
/** Hook called when required-set check runs. */
|
|
60
|
+
onRequiredSet?: (result: CompoundingMemoryRequiredSetResult) => Promise<void> | void;
|
|
61
|
+
};
|
|
62
|
+
type AgentLoopDurabilityConfig = {
|
|
63
|
+
/** Enable durability-proxy writes from runtime loop. Default false. */
|
|
64
|
+
enabled?: boolean;
|
|
65
|
+
/** Durability-proxy base URL (e.g. http://127.0.0.1:8790). */
|
|
66
|
+
baseUrl: string;
|
|
67
|
+
/** Agent id registered in durability-proxy. */
|
|
68
|
+
agentId: string;
|
|
69
|
+
/** Agent token registered in durability-proxy. */
|
|
70
|
+
agentToken: string;
|
|
71
|
+
/** Optional timeout for durability-proxy calls. Default 8000ms. */
|
|
72
|
+
timeoutMs?: number;
|
|
73
|
+
/** Write checkpoint after each required-set run. Default true. */
|
|
74
|
+
checkpointOnRequiredSet?: boolean;
|
|
75
|
+
/** Write restore-drill outcome when required-set includes restore drill. Default true. */
|
|
76
|
+
reportRestoreDrill?: boolean;
|
|
77
|
+
/** Called when durability checkpoint is written. */
|
|
78
|
+
onCheckpointWritten?: (result: {
|
|
79
|
+
checkpointId?: string;
|
|
80
|
+
createdAt?: string;
|
|
81
|
+
checkedAt: string;
|
|
82
|
+
}) => Promise<void> | void;
|
|
83
|
+
/** Called when durability restore drill signal is written. */
|
|
84
|
+
onRestoreDrillReported?: (result: {
|
|
85
|
+
ok: boolean;
|
|
86
|
+
ts?: string;
|
|
87
|
+
checkedAt: string;
|
|
88
|
+
}) => Promise<void> | void;
|
|
89
|
+
};
|
|
12
90
|
type AgentLoopHooks = {
|
|
13
91
|
/** Called every cycle after snapshot is fetched and survival state is updated. */
|
|
14
92
|
onCycle?: (ctx: AgentLoopContext) => Promise<void> | void;
|
|
@@ -33,13 +111,17 @@ type AgentLoopConfig = {
|
|
|
33
111
|
/** Optional override for time source (tests). */
|
|
34
112
|
now?: () => number;
|
|
35
113
|
hooks?: AgentLoopHooks;
|
|
114
|
+
escapeHatch?: AgentLoopEscapeHatchConfig;
|
|
115
|
+
memory?: AgentLoopMemoryConfig;
|
|
116
|
+
durability?: AgentLoopDurabilityConfig;
|
|
36
117
|
};
|
|
37
118
|
/**
|
|
38
119
|
* Create a closed-loop runner that:
|
|
39
120
|
* 1) fetches a resource snapshot
|
|
40
121
|
* 2) updates SelfReliance
|
|
41
122
|
* 3) classifies survival mode + produces a playbook recommendation
|
|
42
|
-
* 4)
|
|
123
|
+
* 4) auto-evaluates escape hatch in SURVIVE/BLINK (guardrail decision block)
|
|
124
|
+
* 5) optionally runs reflection + action hooks
|
|
43
125
|
*
|
|
44
126
|
* Non-breaking by design: you choose what to do with the context.
|
|
45
127
|
*/
|
|
@@ -49,4 +131,4 @@ declare const createAgentLoop: (config: AgentLoopConfig) => {
|
|
|
49
131
|
runOnce: () => Promise<void>;
|
|
50
132
|
};
|
|
51
133
|
|
|
52
|
-
export { type AgentLoopConfig, type AgentLoopContext, type AgentLoopHooks, createAgentLoop };
|
|
134
|
+
export { type AgentLoopConfig, type AgentLoopContext, type AgentLoopDurabilityConfig, type AgentLoopEscapeHatchConfig, type AgentLoopEscapeHatchInput, type AgentLoopHooks, type AgentLoopMemoryConfig, createAgentLoop };
|
package/dist/agentLoop.js
CHANGED
|
@@ -1,8 +1,251 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
2
|
+
runCompoundingMemoryRequiredSet,
|
|
3
|
+
upgradeCompoundingMemorySystem
|
|
4
|
+
} from "./chunk-JJNRDU7F.js";
|
|
5
|
+
import {
|
|
6
|
+
createDurabilityProxyClient
|
|
7
|
+
} from "./chunk-PVCW4MAY.js";
|
|
8
|
+
import {
|
|
9
|
+
evaluateEscapeHatch,
|
|
10
|
+
formatEscapeHatchDecision
|
|
11
|
+
} from "./chunk-EBI7WT76.js";
|
|
12
|
+
import {
|
|
13
|
+
classifySurvivalMode,
|
|
14
|
+
formatSurvivalRecommendation,
|
|
15
|
+
getSurvivalRecommendation
|
|
16
|
+
} from "./chunk-JQE72P4C.js";
|
|
17
|
+
import {
|
|
18
|
+
createSelfRelianceMonitor
|
|
19
|
+
} from "./chunk-M7DQTU5R.js";
|
|
20
|
+
|
|
21
|
+
// src/agentLoop.ts
|
|
22
|
+
var asFiniteNumber = (value) => {
|
|
23
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
24
|
+
return Number.isFinite(n) ? n : void 0;
|
|
25
|
+
};
|
|
26
|
+
var asBoolean = (value) => {
|
|
27
|
+
return typeof value === "boolean" ? value : void 0;
|
|
28
|
+
};
|
|
29
|
+
var defaultEscapeHatchSnapshotBuilder = (input) => {
|
|
30
|
+
const raw = input.snapshot;
|
|
31
|
+
return {
|
|
32
|
+
mode: input.survivalMode,
|
|
33
|
+
estimatedProvisionUsd: asFiniteNumber(raw.estimatedProvisionUsd),
|
|
34
|
+
currentReserveUsd: asFiniteNumber(raw.currentReserveUsd),
|
|
35
|
+
hasPreProvisionedProviderAccount: asBoolean(raw.hasPreProvisionedProviderAccount),
|
|
36
|
+
hasProviderApiKey: asBoolean(raw.hasProviderApiKey),
|
|
37
|
+
backupWrittenAtMs: asFiniteNumber(raw.backupWrittenAtMs),
|
|
38
|
+
restoreDrillPassedAtMs: asFiniteNumber(raw.restoreDrillPassedAtMs),
|
|
39
|
+
nowMs: input.timestamp
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
var createAgentLoop = (config) => {
|
|
43
|
+
const now = config.now ?? (() => Date.now());
|
|
44
|
+
const intervalMs = config.intervalMs ?? 6e4;
|
|
45
|
+
const guardAct = config.guardAct ?? true;
|
|
46
|
+
const hooks = config.hooks ?? {};
|
|
47
|
+
const memoryEnabled = config.memory?.enabled ?? true;
|
|
48
|
+
const memoryRoot = config.memory?.root ?? ".";
|
|
49
|
+
const memoryTimeZone = config.memory?.timeZone;
|
|
50
|
+
const requiredSetEnabled = config.memory?.requiredSetEnabled ?? true;
|
|
51
|
+
const requiredSetIntervalMs = Math.max(6e4, config.memory?.requiredSetIntervalMs ?? 24 * 60 * 60 * 1e3);
|
|
52
|
+
const requiredSetRunOnStart = config.memory?.requiredSetRunOnStart ?? true;
|
|
53
|
+
const requiredSetRunRestoreDrill = config.memory?.requiredSetRunRestoreDrill ?? true;
|
|
54
|
+
const durabilityEnabled = config.durability?.enabled ?? false;
|
|
55
|
+
const durabilityClient = durabilityEnabled ? createDurabilityProxyClient({
|
|
56
|
+
baseUrl: config.durability?.baseUrl || "",
|
|
57
|
+
agentId: config.durability?.agentId || "",
|
|
58
|
+
agentToken: config.durability?.agentToken || "",
|
|
59
|
+
timeoutMs: config.durability?.timeoutMs
|
|
60
|
+
}) : null;
|
|
61
|
+
const checkpointOnRequiredSet = config.durability?.checkpointOnRequiredSet ?? true;
|
|
62
|
+
const reportRestoreDrill = config.durability?.reportRestoreDrill ?? true;
|
|
63
|
+
let memoryUpgradePromise = null;
|
|
64
|
+
let memoryUpgradeHookFired = false;
|
|
65
|
+
let lastRequiredSetCheckAt = requiredSetRunOnStart ? 0 : now();
|
|
66
|
+
let lastRequiredSetResult = null;
|
|
67
|
+
let lastDurabilitySyncCheckedAt = null;
|
|
68
|
+
const ensureMemoryUpgrade = async () => {
|
|
69
|
+
if (!memoryEnabled) return null;
|
|
70
|
+
if (!memoryUpgradePromise) {
|
|
71
|
+
memoryUpgradePromise = upgradeCompoundingMemorySystem({
|
|
72
|
+
root: memoryRoot,
|
|
73
|
+
timeZone: memoryTimeZone
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const result = await memoryUpgradePromise;
|
|
77
|
+
if (config.memory?.onUpgrade && !memoryUpgradeHookFired) {
|
|
78
|
+
memoryUpgradeHookFired = true;
|
|
79
|
+
await config.memory.onUpgrade(result);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
};
|
|
83
|
+
const maybeRunRequiredSet = async (timestamp) => {
|
|
84
|
+
if (!memoryEnabled || !requiredSetEnabled) return null;
|
|
85
|
+
if (timestamp - lastRequiredSetCheckAt < requiredSetIntervalMs) {
|
|
86
|
+
return lastRequiredSetResult;
|
|
87
|
+
}
|
|
88
|
+
const result = await runCompoundingMemoryRequiredSet({
|
|
89
|
+
root: memoryRoot,
|
|
90
|
+
timeZone: memoryTimeZone,
|
|
91
|
+
runBackupRestoreDrill: requiredSetRunRestoreDrill
|
|
92
|
+
});
|
|
93
|
+
lastRequiredSetCheckAt = timestamp;
|
|
94
|
+
lastRequiredSetResult = result;
|
|
95
|
+
if (config.memory?.onRequiredSet) {
|
|
96
|
+
await config.memory.onRequiredSet(result);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
};
|
|
100
|
+
const maybeSyncDurability = async (snapshot, memoryRequiredSet, timestamp) => {
|
|
101
|
+
if (!durabilityClient || !memoryRequiredSet) return;
|
|
102
|
+
if (lastDurabilitySyncCheckedAt === memoryRequiredSet.checkedAt) return;
|
|
103
|
+
const checkpointMeta = {
|
|
104
|
+
checkedAt: memoryRequiredSet.checkedAt,
|
|
105
|
+
requiredSetOk: memoryRequiredSet.ok,
|
|
106
|
+
workingStateBounded: memoryRequiredSet.workingState.bounded,
|
|
107
|
+
recallReady: memoryRequiredSet.recall.ok,
|
|
108
|
+
restoreDrillOk: memoryRequiredSet.restoreDrill?.ok ?? null
|
|
109
|
+
};
|
|
110
|
+
if (checkpointOnRequiredSet) {
|
|
111
|
+
const checkpointRes = await durabilityClient.writeCheckpoint(
|
|
112
|
+
{
|
|
113
|
+
kind: "compounding_memory_required_set",
|
|
114
|
+
checkedAt: memoryRequiredSet.checkedAt,
|
|
115
|
+
result: memoryRequiredSet
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
metadata: checkpointMeta
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
const createdAt = checkpointRes?.checkpoint?.createdAt || new Date(timestamp).toISOString();
|
|
122
|
+
const createdAtMs = Number(new Date(createdAt));
|
|
123
|
+
if (Number.isFinite(createdAtMs)) {
|
|
124
|
+
snapshot.backupWrittenAtMs = createdAtMs;
|
|
125
|
+
}
|
|
126
|
+
if (config.durability?.onCheckpointWritten) {
|
|
127
|
+
await config.durability.onCheckpointWritten({
|
|
128
|
+
checkpointId: checkpointRes?.checkpoint?.id,
|
|
129
|
+
createdAt: checkpointRes?.checkpoint?.createdAt,
|
|
130
|
+
checkedAt: memoryRequiredSet.checkedAt
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (reportRestoreDrill && memoryRequiredSet.restoreDrill) {
|
|
134
|
+
const drillRes = await durabilityClient.writeRestoreDrill(memoryRequiredSet.restoreDrill.ok, {
|
|
135
|
+
checkpointId: checkpointRes?.checkpoint?.id,
|
|
136
|
+
details: memoryRequiredSet.restoreDrill.ok ? "required_set_restore_drill_passed" : "required_set_restore_drill_failed"
|
|
137
|
+
});
|
|
138
|
+
if (memoryRequiredSet.restoreDrill.ok) {
|
|
139
|
+
snapshot.restoreDrillPassedAtMs = timestamp;
|
|
140
|
+
}
|
|
141
|
+
if (config.durability?.onRestoreDrillReported) {
|
|
142
|
+
await config.durability.onRestoreDrillReported({
|
|
143
|
+
ok: Boolean(drillRes?.drill?.ok),
|
|
144
|
+
ts: drillRes?.drill?.ts,
|
|
145
|
+
checkedAt: memoryRequiredSet.checkedAt
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
lastDurabilitySyncCheckedAt = memoryRequiredSet.checkedAt;
|
|
151
|
+
};
|
|
152
|
+
const runOnce = async () => {
|
|
153
|
+
try {
|
|
154
|
+
const memoryUpgrade = await ensureMemoryUpgrade();
|
|
155
|
+
const snapshot = await config.fetchSnapshot();
|
|
156
|
+
const timestamp = now();
|
|
157
|
+
const memoryRequiredSet = await maybeRunRequiredSet(timestamp);
|
|
158
|
+
await maybeSyncDurability(snapshot, memoryRequiredSet, timestamp);
|
|
159
|
+
const survivalState = config.survival.update({
|
|
160
|
+
...snapshot,
|
|
161
|
+
updatedAt: snapshot.updatedAt ?? timestamp
|
|
162
|
+
});
|
|
163
|
+
const policy = config.survival.policy;
|
|
164
|
+
const survivalMode = classifySurvivalMode(survivalState, policy);
|
|
165
|
+
const survivalRecommendation = getSurvivalRecommendation(survivalMode);
|
|
166
|
+
const survivalFormatted = formatSurvivalRecommendation(survivalRecommendation);
|
|
167
|
+
let escapeHatchDecision;
|
|
168
|
+
let escapeHatchFormatted;
|
|
169
|
+
const escapeEnabled = config.escapeHatch?.enabled ?? true;
|
|
170
|
+
const shouldEvaluateEscapeHatch = escapeEnabled && (survivalMode === "SURVIVE" || survivalMode === "BLINK");
|
|
171
|
+
if (shouldEvaluateEscapeHatch) {
|
|
172
|
+
const input = {
|
|
173
|
+
snapshot,
|
|
174
|
+
survivalState,
|
|
175
|
+
survivalMode,
|
|
176
|
+
timestamp
|
|
177
|
+
};
|
|
178
|
+
const buildSnapshot = config.escapeHatch?.buildSnapshot ?? defaultEscapeHatchSnapshotBuilder;
|
|
179
|
+
const escapeSnapshot = buildSnapshot(input);
|
|
180
|
+
if (escapeSnapshot) {
|
|
181
|
+
escapeHatchDecision = evaluateEscapeHatch(
|
|
182
|
+
escapeSnapshot,
|
|
183
|
+
config.escapeHatch?.policy,
|
|
184
|
+
{ resolveEnv: config.escapeHatch?.resolveEnv }
|
|
185
|
+
);
|
|
186
|
+
escapeHatchFormatted = formatEscapeHatchDecision(escapeHatchDecision);
|
|
187
|
+
if (config.escapeHatch?.onDecision) {
|
|
188
|
+
await config.escapeHatch.onDecision(escapeHatchDecision, input);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const survivalDecisionBlock = [survivalFormatted, escapeHatchFormatted].filter(Boolean).join("\n\n");
|
|
193
|
+
const ctx = {
|
|
194
|
+
snapshot,
|
|
195
|
+
survivalState,
|
|
196
|
+
survivalMode,
|
|
197
|
+
survivalRecommendation,
|
|
198
|
+
survivalFormatted,
|
|
199
|
+
survivalDecisionBlock,
|
|
200
|
+
escapeHatchDecision,
|
|
201
|
+
escapeHatchFormatted,
|
|
202
|
+
memoryUpgrade: memoryUpgrade ?? void 0,
|
|
203
|
+
memoryRequiredSet: memoryRequiredSet ?? void 0,
|
|
204
|
+
timestamp
|
|
205
|
+
};
|
|
206
|
+
if (hooks.onCycle) await hooks.onCycle(ctx);
|
|
207
|
+
if (hooks.onReflection) await hooks.onReflection(ctx);
|
|
208
|
+
if (hooks.onAct) {
|
|
209
|
+
if (guardAct) {
|
|
210
|
+
const allowed = await config.survival.guard();
|
|
211
|
+
if (allowed) {
|
|
212
|
+
await hooks.onAct(ctx);
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
await hooks.onAct(ctx);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} catch (err) {
|
|
219
|
+
const e = err instanceof Error ? err : new Error("agent_loop_failed");
|
|
220
|
+
if (hooks.onError) {
|
|
221
|
+
await hooks.onError(e);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const monitor = createSelfRelianceMonitor(config.survival, config.fetchSnapshot, {
|
|
226
|
+
intervalMs,
|
|
227
|
+
onUpdate: async (snapshot) => {
|
|
228
|
+
void snapshot;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
let timer = null;
|
|
232
|
+
let stopped = false;
|
|
233
|
+
const start = async () => {
|
|
234
|
+
if (timer) return;
|
|
235
|
+
await runOnce();
|
|
236
|
+
if (stopped) return;
|
|
237
|
+
timer = setInterval(runOnce, intervalMs);
|
|
238
|
+
};
|
|
239
|
+
const stop = () => {
|
|
240
|
+
stopped = true;
|
|
241
|
+
if (timer) {
|
|
242
|
+
clearInterval(timer);
|
|
243
|
+
timer = null;
|
|
244
|
+
}
|
|
245
|
+
monitor.stop();
|
|
246
|
+
};
|
|
247
|
+
return { start, stop, runOnce };
|
|
248
|
+
};
|
|
6
249
|
export {
|
|
7
250
|
createAgentLoop
|
|
8
251
|
};
|