@economic/agents 2.3.19 → 2.3.20

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/dist/index.d.mts CHANGED
@@ -114,6 +114,21 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
114
114
  * cold start, so registration is not allowed to block the connection.
115
115
  */
116
116
  protected registerInstance(): Promise<void>;
117
+ /**
118
+ * The `(agent_name, durable_object_name)` key of the registered row for this
119
+ * DO. For a parented (facet) agent this resolves to the top-level parent's
120
+ * row, since facets are not registered themselves.
121
+ */
122
+ protected getRegisteredInstanceKey(): {
123
+ agentName: string;
124
+ durableObjectName: string;
125
+ };
126
+ /**
127
+ * Records activity against this DO's registered row by advancing its
128
+ * `updated_at`, so instances can be ordered by recency of activity.
129
+ * Best-effort and non-blocking — never allowed to interfere with a turn.
130
+ */
131
+ protected touchInstance(): Promise<void>;
117
132
  /**
118
133
  * Resolves the analytics/telemetry agent name to the entry-point agent: the
119
134
  * top-level DO registered in the `agent` catalog table.
@@ -249,6 +264,13 @@ declare abstract class Assistant<State = unknown> extends Agent$1<Cloudflare.Env
249
264
  * Best-effort and idempotent: no-ops on conflict, retried on the next start.
250
265
  */
251
266
  private registerInstance;
267
+ /**
268
+ * Records activity against this Assistant's registry row by advancing its
269
+ * `updated_at`, so instances can be ordered by recency of activity. An
270
+ * Assistant is a top-level DO, so its row is keyed by its own class + name.
271
+ * Best-effort and non-blocking.
272
+ */
273
+ private touchInstance;
252
274
  /**
253
275
  * Binding of the legacy v1 chat Durable Object class, used to migrate a
254
276
  * user's v1 chats into facets the first time they connect. Set this on the
package/dist/index.mjs CHANGED
@@ -28,12 +28,31 @@ const TURN_PROTOCOL_RULES_PROMPT = `These rules are specific for responding to u
28
28
  * Registers a top-level DO in the global registry.
29
29
  *
30
30
  * Idempotent: keyed on `(agent_name, durable_object_name)`, so repeated calls
31
- * across cold starts no-op and `created_at` reflects the first registration.
31
+ * across cold starts no-op and timestamps reflect the first registration.
32
+ * `updated_at` is seeded to `created_at`; ongoing activity is recorded
33
+ * separately via {@link touchAgentInstance} so cold-start re-registration
34
+ * never inflates the activity timestamp.
32
35
  */
33
36
  async function registerAgentInstance(db, input) {
34
- await db.prepare(`INSERT INTO agent_registry (agent_name, durable_object_name, actor_id, created_at)
35
- VALUES (?, ?, ?, ?)
36
- ON CONFLICT (agent_name, durable_object_name) DO NOTHING`).bind(input.agentName, input.durableObjectName, input.actorId, input.createdAt).run();
37
+ await db.prepare(`INSERT INTO agent_registry (agent_name, durable_object_name, actor_id, created_at, updated_at)
38
+ VALUES (?, ?, ?, ?, ?)
39
+ ON CONFLICT (agent_name, durable_object_name) DO NOTHING`).bind(input.agentName, input.durableObjectName, input.actorId, input.createdAt, input.createdAt).run();
40
+ }
41
+ /**
42
+ * Records activity on a registered top-level DO by advancing its `updated_at`.
43
+ *
44
+ * Used to order instances by recency of activity. Keyed on
45
+ * `(agent_name, durable_object_name)` to target the exact registered row —
46
+ * for a parented (facet) agent this is the top-level parent's row, since
47
+ * facets are not registered themselves.
48
+ *
49
+ * Best-effort: a no-op if the row does not yet exist (registration is
50
+ * retried on the next cold start).
51
+ */
52
+ async function touchAgentInstance(db, input) {
53
+ await db.prepare(`UPDATE agent_registry
54
+ SET updated_at = ?
55
+ WHERE agent_name = ? AND durable_object_name = ?`).bind(input.updatedAt, input.agentName, input.durableObjectName).run();
37
56
  }
38
57
  //#endregion
39
58
  //#region src/server/util/agent.ts
@@ -172,6 +191,7 @@ var Agent = class extends Think {
172
191
  * `returned.tools` into your own `TurnConfig.tools` if you return tools.
173
192
  */
174
193
  async beforeTurn(ctx) {
194
+ this.touchInstance();
175
195
  this._toolContextForCurrentTurn = this.getToolContextForCurrentTurn(ctx.body);
176
196
  this._toolsForCurrentTurn = ctx.tools;
177
197
  const activeSkillName = this._getLastActivatedSkillName(ctx.messages);
@@ -313,6 +333,32 @@ var Agent = class extends Think {
313
333
  }
314
334
  }
315
335
  /**
336
+ * The `(agent_name, durable_object_name)` key of the registered row for this
337
+ * DO. For a parented (facet) agent this resolves to the top-level parent's
338
+ * row, since facets are not registered themselves.
339
+ */
340
+ getRegisteredInstanceKey() {
341
+ return {
342
+ agentName: this.parentPath[0]?.className ?? this.constructor.name,
343
+ durableObjectName: this.parentPath[0]?.name ?? this.name
344
+ };
345
+ }
346
+ /**
347
+ * Records activity against this DO's registered row by advancing its
348
+ * `updated_at`, so instances can be ordered by recency of activity.
349
+ * Best-effort and non-blocking — never allowed to interfere with a turn.
350
+ */
351
+ async touchInstance() {
352
+ try {
353
+ await touchAgentInstance(this.env.AGENTS_DB, {
354
+ ...this.getRegisteredInstanceKey(),
355
+ updatedAt: Date.now()
356
+ });
357
+ } catch (error) {
358
+ console.error("[Agent] Failed to update agent_registry activity", error);
359
+ }
360
+ }
361
+ /**
316
362
  * Resolves the analytics/telemetry agent name to the entry-point agent: the
317
363
  * top-level DO registered in the `agent` catalog table.
318
364
  *
@@ -718,6 +764,7 @@ var Assistant = class extends Agent$1 {
718
764
  const now = Date.now();
719
765
  await this.subAgent(this.agent, id);
720
766
  registerChat(this.sql.bind(this), id, now);
767
+ this.touchInstance(now);
721
768
  return id;
722
769
  }
723
770
  async deleteChat(id) {
@@ -762,6 +809,23 @@ var Assistant = class extends Agent$1 {
762
809
  }
763
810
  }
764
811
  /**
812
+ * Records activity against this Assistant's registry row by advancing its
813
+ * `updated_at`, so instances can be ordered by recency of activity. An
814
+ * Assistant is a top-level DO, so its row is keyed by its own class + name.
815
+ * Best-effort and non-blocking.
816
+ */
817
+ async touchInstance(updatedAt) {
818
+ try {
819
+ await touchAgentInstance(this.env.AGENTS_DB, {
820
+ agentName: this.constructor.name,
821
+ durableObjectName: this.name,
822
+ updatedAt
823
+ });
824
+ } catch (error) {
825
+ console.error("[Assistant] Failed to update agent_registry activity", error);
826
+ }
827
+ }
828
+ /**
765
829
  * Binding of the legacy v1 chat Durable Object class, used to migrate a
766
830
  * user's v1 chats into facets the first time they connect. Set this on the
767
831
  * concrete subclass to enable lazy v1 -> v2 migration; leave undefined to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@economic/agents",
3
- "version": "2.3.19",
3
+ "version": "2.3.20",
4
4
  "description": "A starter for creating a TypeScript package.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -0,0 +1,13 @@
1
+ -- ─── agent_registry.updated_at ────────────────────────────────────────────────────
2
+ -- Adds an activity timestamp to the registry so top-level DOs (one row per
3
+ -- Assistant, i.e. per user) can be ordered by recency of activity. Bumped by
4
+ -- the owning DO whenever a chat is created or has a turn.
5
+ --
6
+ -- Existing rows are backfilled to created_at so ordering remains sensible
7
+ -- before any new activity updates the column.
8
+
9
+ ALTER TABLE agent_registry ADD COLUMN updated_at INTEGER;
10
+
11
+ UPDATE agent_registry SET updated_at = created_at WHERE updated_at IS NULL;
12
+
13
+ CREATE INDEX IF NOT EXISTS agent_registry_updated ON agent_registry(updated_at);