agents
Version:
A home for your AI agents
137 lines (136 loc) • 5.63 kB
JavaScript
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../classPrivateFieldGet2-DZBYAB34.js";
import { t as LifecycleCapability } from "../capability-B4WbF81e.js";
import { t as _classPrivateMethodInitSpec } from "../classPrivateMethodInitSpec-qMjJ6sHQ.js";
//#region src/state/index.ts
/**
* Namespaced KV key holding this capability's schema version. Kept separate
* from the host's global schema version so State owns its own migrations
* without gating the host's DDL.
*/
const STATE_SCHEMA_VERSION_KEY = "cf_agents:state_schema_version";
const CURRENT_STATE_SCHEMA_VERSION = 1;
/** Row id under which the single state value is stored in `cf_agents_state`. */
const STATE_ROW_ID = "cf_state_row_id";
/**
* Legacy row written by SDKs that predate the single-row state optimization.
* Never written now; the v1 migration deletes it.
*/
const LEGACY_WAS_CHANGED_ROW_ID = "cf_state_was_changed";
/**
* Sentinel distinguishing "state not yet loaded / never set" from a stored
* value. A distinct object reference means falsy states (null, 0, false, "")
* still read back as set.
*/
const DEFAULT_STATE = {};
var _state = /* @__PURE__ */ new WeakMap();
var _tableEnsured = /* @__PURE__ */ new WeakMap();
var _options = /* @__PURE__ */ new WeakMap();
var _State_brand = /* @__PURE__ */ new WeakSet();
/**
* Durable state storage for a Lifecycle Object.
*
* Owns the `cf_agents_state` state row, lazy load with an in-memory cache, and
* validated persistence. Install the instance with `Lifecycle.use()`. State
* validation and the post-change notification hook stay on the host, which
* injects both callbacks. This capability never touches connections.
*
* @experimental The API surface may change before stabilizing.
*/
var State = class extends LifecycleCapability {
/**
* Create a durable state capability.
*
* @param options - Optional initial state and a synchronous validation hook
* injected by the host.
*/
constructor(options = {}) {
super("state");
_classPrivateMethodInitSpec(this, _State_brand);
_classPrivateFieldInitSpec(this, _state, DEFAULT_STATE);
_classPrivateFieldInitSpec(this, _tableEnsured, false);
_classPrivateFieldInitSpec(this, _options, void 0);
_classPrivateFieldSet2(_options, this, options);
}
/** Initialize state storage during Lifecycle startup. */
async onStart() {
if ((await this.lifecycle.storage.get(STATE_SCHEMA_VERSION_KEY) ?? 0) >= CURRENT_STATE_SCHEMA_VERSION) {
_classPrivateFieldSet2(_tableEnsured, this, true);
return;
}
_assertClassBrand(_State_brand, this, _ensureTable).call(this);
this.lifecycle.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", LEGACY_WAS_CHANGED_ROW_ID);
await this.lifecycle.storage.put(STATE_SCHEMA_VERSION_KEY, CURRENT_STATE_SCHEMA_VERSION);
}
/**
* Current state.
*
* Loads lazily from storage on first access and caches in memory. Row
* existence in `cf_agents_state` is the signal that state was previously
* set, so falsy values persist correctly. On a corrupt row, falls back to
* the initial state (re-persisting it) or clears the row.
*/
get() {
if (_classPrivateFieldGet2(_state, this) !== DEFAULT_STATE) return _classPrivateFieldGet2(_state, this);
_assertClassBrand(_State_brand, this, _ensureTable).call(this);
const result = this.lifecycle.storage.sql.exec("SELECT state FROM cf_agents_state WHERE id = ?", STATE_ROW_ID).toArray();
if (result.length > 0) {
const state = result[0].state;
try {
_classPrivateFieldSet2(_state, this, JSON.parse(state));
} catch (e) {
console.error("Failed to parse stored state, falling back to initialState:", e);
const initial = _classPrivateFieldGet2(_options, this).initialState;
if (initial !== void 0) {
_classPrivateFieldSet2(_state, this, initial);
this.set(initial, "server");
} else {
this.lifecycle.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", STATE_ROW_ID);
return;
}
}
return _classPrivateFieldGet2(_state, this);
}
const initial = _classPrivateFieldGet2(_options, this).initialState;
if (initial === void 0) return;
this.set(initial, "server");
return initial;
}
/**
* Validate and persist a state change, then call the change hook.
*
* @param nextState - The new state to persist.
* @param source - `"server"` for host-originated changes, or the originating
* connection for client-originated changes.
* @throws Whatever the injected `validateStateChange` throws.
*/
set(nextState, source = "server") {
_classPrivateFieldGet2(_options, this).validateStateChange?.(nextState, source);
_assertClassBrand(_State_brand, this, _ensureTable).call(this);
const serialized = JSON.stringify(nextState);
this.lifecycle.storage.sql.exec("INSERT OR REPLACE INTO cf_agents_state (id, state) VALUES (?, ?)", STATE_ROW_ID, serialized);
_classPrivateFieldSet2(_state, this, nextState);
let pending;
try {
pending = _classPrivateFieldGet2(_options, this).onChanged?.(nextState, source);
} catch (error) {
console.error("State onChanged hook failed:", error);
return;
}
if (pending) Promise.resolve(pending).catch((error) => {
console.error("State onChanged hook failed:", error);
});
}
};
function _ensureTable() {
if (_classPrivateFieldGet2(_tableEnsured, this)) return;
this.lifecycle.storage.sql.exec(`
CREATE TABLE IF NOT EXISTS cf_agents_state (
id TEXT PRIMARY KEY NOT NULL,
state TEXT
)
`);
_classPrivateFieldSet2(_tableEnsured, this, true);
}
//#endregion
export { State };
//# sourceMappingURL=index.js.map