@economic/agents 0.0.1-alpha.17 → 0.0.1-alpha.18
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 +9 -20
- package/dist/index.mjs +56 -51
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -113,28 +113,17 @@ declare abstract class AIChatAgent<Env extends Cloudflare.Env = Cloudflare.Env>
|
|
|
113
113
|
*/
|
|
114
114
|
protected log(message: string, payload?: Record<string, unknown>): Promise<void>;
|
|
115
115
|
/**
|
|
116
|
-
* Records this conversation in the `conversations` D1 table and
|
|
117
|
-
*
|
|
118
|
-
* after every turn.
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* (
|
|
124
|
-
*
|
|
116
|
+
* Records this conversation in the `conversations` D1 table and triggers
|
|
117
|
+
* LLM-based title/summary generation when appropriate. Called automatically
|
|
118
|
+
* from `persistMessages` after every turn.
|
|
119
|
+
*
|
|
120
|
+
* On the first turn (no existing row), awaits `generateTitleAndSummary` and
|
|
121
|
+
* inserts the row with title and summary already populated. On subsequent
|
|
122
|
+
* turns, upserts the timestamp and fire-and-forgets a summary refresh every
|
|
123
|
+
* `SUMMARY_CONTEXT_MESSAGES` messages (when the context window fully turns
|
|
124
|
+
* over). Neither path blocks the response to the client.
|
|
125
125
|
*/
|
|
126
126
|
private recordConversation;
|
|
127
|
-
/**
|
|
128
|
-
* Generates a title and summary for the conversation after 30 minutes of
|
|
129
|
-
* inactivity. Invoked automatically by the Cloudflare Agents SDK scheduler
|
|
130
|
-
* — do not call this directly.
|
|
131
|
-
*
|
|
132
|
-
* Delegates to `generateConversationSummary` in `features/conversations`,
|
|
133
|
-
* which fetches the previous summary, slices to the last
|
|
134
|
-
* `SUMMARY_CONTEXT_MESSAGES` messages, calls `fastModel` with a structured
|
|
135
|
-
* output schema, and writes the result back to D1.
|
|
136
|
-
*/
|
|
137
|
-
generateSummary(): Promise<void>;
|
|
138
127
|
/**
|
|
139
128
|
* Builds the parameter object for a `streamText` or `generateText` call,
|
|
140
129
|
* pre-filling `messages`, `activeSkills`, and `fastModel` from this agent instance.
|
package/dist/index.mjs
CHANGED
|
@@ -3724,21 +3724,19 @@ function superRefine(fn) {
|
|
|
3724
3724
|
* Records a conversation row in the `conversations` D1 table.
|
|
3725
3725
|
*
|
|
3726
3726
|
* Called by `AIChatAgent` after every turn. On first call for a given
|
|
3727
|
-
* `durableObjectId` the row is inserted with `created_at` set to now
|
|
3727
|
+
* `durableObjectId` the row is inserted with `created_at` set to now,
|
|
3728
|
+
* and with the provided `title` and `summary` if supplied.
|
|
3728
3729
|
* On subsequent calls only `user_id` and `updated_at` are refreshed —
|
|
3729
|
-
* `created_at`, `title`, and `summary` are never overwritten
|
|
3730
|
-
*
|
|
3731
|
-
* After upserting, `AIChatAgent` cancels any pending `generateSummary`
|
|
3732
|
-
* schedule and resets it to fire 30 minutes from now, debouncing the
|
|
3733
|
-
* idle timer on every turn.
|
|
3730
|
+
* `created_at`, `title`, and `summary` are never overwritten, preserving
|
|
3731
|
+
* any user edits.
|
|
3734
3732
|
*/
|
|
3735
|
-
async function recordConversation(db, durableObjectId, userId) {
|
|
3733
|
+
async function recordConversation(db, durableObjectId, userId, title, summary) {
|
|
3736
3734
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3737
3735
|
await db.prepare(`INSERT INTO conversations (durable_object_id, user_id, title, summary, created_at, updated_at)
|
|
3738
|
-
VALUES (?, ?,
|
|
3736
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
3739
3737
|
ON CONFLICT(durable_object_id) DO UPDATE SET
|
|
3740
3738
|
user_id = excluded.user_id,
|
|
3741
|
-
updated_at = excluded.updated_at`).bind(durableObjectId, userId, now, now).run();
|
|
3739
|
+
updated_at = excluded.updated_at`).bind(durableObjectId, userId, title ?? null, summary ?? null, now, now).run();
|
|
3742
3740
|
}
|
|
3743
3741
|
/**
|
|
3744
3742
|
* Returns the current `title` and `summary` for a conversation row,
|
|
@@ -3754,19 +3752,19 @@ async function updateConversationSummary(db, durableObjectId, title, summary) {
|
|
|
3754
3752
|
await db.prepare(`UPDATE conversations SET title = ?, summary = ? WHERE durable_object_id = ?`).bind(title, summary, durableObjectId).run();
|
|
3755
3753
|
}
|
|
3756
3754
|
/**
|
|
3757
|
-
* Generates a title and summary for a conversation using the provided model
|
|
3758
|
-
*
|
|
3755
|
+
* Generates a title and summary for a conversation using the provided model.
|
|
3756
|
+
* Returns the result without writing to D1.
|
|
3759
3757
|
*
|
|
3760
|
-
*
|
|
3761
|
-
*
|
|
3762
|
-
*
|
|
3758
|
+
* Pass `existingSummary` so the model can detect direction changes when
|
|
3759
|
+
* updating an existing summary. Omit it (or pass undefined) for the initial
|
|
3760
|
+
* generation.
|
|
3763
3761
|
*
|
|
3764
|
-
*
|
|
3762
|
+
* Only the last `SUMMARY_CONTEXT_MESSAGES` messages are used to keep the
|
|
3763
|
+
* prompt bounded regardless of total conversation length.
|
|
3765
3764
|
*/
|
|
3766
|
-
async function
|
|
3767
|
-
const existing = await getConversationSummary(db, durableObjectId);
|
|
3765
|
+
async function generateTitleAndSummary(messages, model, existingSummary) {
|
|
3768
3766
|
const recentMessages = await convertToModelMessages(messages.slice(-30));
|
|
3769
|
-
const previousContext =
|
|
3767
|
+
const previousContext = existingSummary ? `Previous summary: ${existingSummary}\n\nMost recent messages:` : "Conversation:";
|
|
3770
3768
|
const { output } = await generateText({
|
|
3771
3769
|
model,
|
|
3772
3770
|
output: Output.object({ schema: object({
|
|
@@ -3775,7 +3773,22 @@ async function generateConversationSummary(db, durableObjectId, messages, model)
|
|
|
3775
3773
|
}) }),
|
|
3776
3774
|
prompt: `${previousContext}\n\n${formatMessagesForSummary(recentMessages)}`
|
|
3777
3775
|
});
|
|
3778
|
-
|
|
3776
|
+
return output;
|
|
3777
|
+
}
|
|
3778
|
+
/**
|
|
3779
|
+
* Generates a title and summary for a conversation using the provided model
|
|
3780
|
+
* and writes the result back to D1.
|
|
3781
|
+
*
|
|
3782
|
+
* Fetches any existing summary first so the model can detect direction changes.
|
|
3783
|
+
* Only the last `SUMMARY_CONTEXT_MESSAGES` messages are passed to keep the
|
|
3784
|
+
* prompt bounded regardless of total conversation length.
|
|
3785
|
+
*
|
|
3786
|
+
* Called by `AIChatAgent` every `SUMMARY_CONTEXT_MESSAGES` messages after
|
|
3787
|
+
* the first turn.
|
|
3788
|
+
*/
|
|
3789
|
+
async function generateConversationSummary(db, durableObjectId, messages, model) {
|
|
3790
|
+
const { title, summary } = await generateTitleAndSummary(messages, model, (await getConversationSummary(db, durableObjectId))?.summary ?? void 0);
|
|
3791
|
+
await updateConversationSummary(db, durableObjectId, title, summary);
|
|
3779
3792
|
}
|
|
3780
3793
|
//#endregion
|
|
3781
3794
|
//#region src/agents/AIChatAgent.ts
|
|
@@ -3828,39 +3841,31 @@ var AIChatAgent = class extends AIChatAgent$1 {
|
|
|
3828
3841
|
await insertAuditEvent(context.db, this.ctx.id.toString(), context.userId, message, payload);
|
|
3829
3842
|
}
|
|
3830
3843
|
/**
|
|
3831
|
-
* Records this conversation in the `conversations` D1 table and
|
|
3832
|
-
*
|
|
3833
|
-
* after every turn.
|
|
3844
|
+
* Records this conversation in the `conversations` D1 table and triggers
|
|
3845
|
+
* LLM-based title/summary generation when appropriate. Called automatically
|
|
3846
|
+
* from `persistMessages` after every turn.
|
|
3834
3847
|
*
|
|
3835
|
-
*
|
|
3836
|
-
*
|
|
3837
|
-
*
|
|
3838
|
-
* (
|
|
3839
|
-
*
|
|
3848
|
+
* On the first turn (no existing row), awaits `generateTitleAndSummary` and
|
|
3849
|
+
* inserts the row with title and summary already populated. On subsequent
|
|
3850
|
+
* turns, upserts the timestamp and fire-and-forgets a summary refresh every
|
|
3851
|
+
* `SUMMARY_CONTEXT_MESSAGES` messages (when the context window fully turns
|
|
3852
|
+
* over). Neither path blocks the response to the client.
|
|
3840
3853
|
*/
|
|
3841
|
-
async recordConversation() {
|
|
3854
|
+
async recordConversation(messageCount) {
|
|
3842
3855
|
const context = this.resolveD1Context();
|
|
3843
3856
|
if (!context) return;
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
* `SUMMARY_CONTEXT_MESSAGES` messages, calls `fastModel` with a structured
|
|
3857
|
-
* output schema, and writes the result back to D1.
|
|
3858
|
-
*/
|
|
3859
|
-
async generateSummary() {
|
|
3860
|
-
const context = this.resolveD1Context();
|
|
3861
|
-
if (!context) return;
|
|
3862
|
-
await generateConversationSummary(context.db, this.ctx.id.toString(), this.messages, this.fastModel);
|
|
3863
|
-
this.log("conversation summary generated");
|
|
3857
|
+
const durableObjectId = this.ctx.id.toString();
|
|
3858
|
+
if (!await getConversationSummary(context.db, durableObjectId)) {
|
|
3859
|
+
const { title, summary } = await generateTitleAndSummary(this.messages, this.fastModel);
|
|
3860
|
+
await recordConversation(context.db, durableObjectId, context.userId, title, summary);
|
|
3861
|
+
this.log("conversation summary generated");
|
|
3862
|
+
} else {
|
|
3863
|
+
await recordConversation(context.db, durableObjectId, context.userId);
|
|
3864
|
+
if (messageCount % 30 === 0) {
|
|
3865
|
+
generateConversationSummary(context.db, durableObjectId, this.messages, this.fastModel);
|
|
3866
|
+
this.log("conversation summary updated");
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3864
3869
|
}
|
|
3865
3870
|
/**
|
|
3866
3871
|
* Builds the parameter object for a `streamText` or `generateText` call,
|
|
@@ -3913,7 +3918,7 @@ var AIChatAgent = class extends AIChatAgent$1 {
|
|
|
3913
3918
|
* Returns an empty array if no skills have been loaded yet.
|
|
3914
3919
|
*/
|
|
3915
3920
|
async getLoadedSkills() {
|
|
3916
|
-
return getStoredSkills(this.sql);
|
|
3921
|
+
return getStoredSkills(this.sql.bind(this));
|
|
3917
3922
|
}
|
|
3918
3923
|
/**
|
|
3919
3924
|
* Extracts skill state from activate_skill results, persists to DO SQLite,
|
|
@@ -3944,9 +3949,9 @@ var AIChatAgent = class extends AIChatAgent$1 {
|
|
|
3944
3949
|
} catch {}
|
|
3945
3950
|
}
|
|
3946
3951
|
}
|
|
3947
|
-
if (latestSkillState !== void 0) saveStoredSkills(this.sql, latestSkillState);
|
|
3952
|
+
if (latestSkillState !== void 0) saveStoredSkills(this.sql.bind(this), latestSkillState);
|
|
3948
3953
|
this.log("turn completed", buildTurnSummary(messages, latestSkillState ?? []));
|
|
3949
|
-
this.recordConversation();
|
|
3954
|
+
this.recordConversation(messages.length);
|
|
3950
3955
|
const filtered = filterEphemeralMessages(messages);
|
|
3951
3956
|
return super.persistMessages(filtered, excludeBroadcastIds, options);
|
|
3952
3957
|
}
|