@economic/agents 2.3.27 → 2.5.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/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as JwtAuthConfig, t as routeAgentRequest } from "./route-agent-request-D2ll--nF.mjs";
2
2
  import { Agent as Agent$1, Connection, ConnectionContext, SubAgentClass } from "agents";
3
3
  import { ChatResponseResult, PrepareStepContext, Session, Think, ToolCallContext, ToolCallDecision, TurnConfig, TurnContext, skills } from "@cloudflare/think";
4
- import { JSONValue, LanguageModel, Tool as Tool$1, UIMessage } from "ai";
4
+ import { JSONValue, LanguageModel, ModelMessage, Tool as Tool$1, UIMessage } from "ai";
5
5
  import { createCompactFunction } from "agents/experimental/memory/utils";
6
6
  import { SkillSource as SkillSource$1 } from "agents/skills";
7
7
 
@@ -34,6 +34,15 @@ type Tool<Context extends Record<string, unknown> = Record<string, unknown>, INP
34
34
  declare function tool<Context extends Record<string, unknown> = Record<string, unknown>, INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any>(tool: Tool<Context, INPUT, OUTPUT>): Tool$1<INPUT, OUTPUT>;
35
35
  //#endregion
36
36
  //#region src/server/agents/Agent.d.ts
37
+ /** What the model would see on its next step — returned by {@link Agent.inspectTurn}. */
38
+ interface TurnSnapshot {
39
+ system: string;
40
+ tools: ToolSet;
41
+ activeTools: string[];
42
+ /** Tools provided by the framework (session/skill meta-tools, MCP), not the agent. */
43
+ frameworkToolNames: string[];
44
+ messages: ModelMessage[];
45
+ }
37
46
  declare abstract class Agent<RequestContext extends Record<string, unknown> = Record<string, unknown>, UserContext extends Record<string, unknown> = Record<string, unknown>, State = unknown> extends Think<Cloudflare.Env & AgentEnv, State> {
38
47
  protected agentType: AgentConnectionType;
39
48
  protected clientIp?: string;
@@ -75,6 +84,19 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
75
84
  }>;
76
85
  beforeToolCall(ctx: ToolCallContext): Promise<ToolCallDecision | void>;
77
86
  getTools(): ToolSet;
87
+ /**
88
+ * Read-only: what the model would see on its next step for the given history
89
+ * — the assembled system prompt, the skill-gated toolset, and pruned
90
+ * messages. Runs no turn (nothing admitted, persisted, executed; no model
91
+ * call). Skill gating is derived from the history, so a history with an
92
+ * `activate_skill` call yields that skill's tools. For eval harnesses and
93
+ * prompt-preview tooling; call it inside the DO context.
94
+ */
95
+ inspectTurn(input?: {
96
+ messages?: ModelMessage[];
97
+ requestContext?: RequestContext;
98
+ userContext?: UserContext;
99
+ }): Promise<TurnSnapshot>;
78
100
  workspaceBash: boolean;
79
101
  getSkillScriptRunner(): skills.SkillScriptRunner | null;
80
102
  /**
@@ -82,6 +104,7 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
82
104
  * @returns The remote skills to be loaded from SKILLS_BUCKET.
83
105
  */
84
106
  protected getRemoteSkills(): string[];
107
+ private _pruneTurnMessages;
85
108
  private _getAuthorizedTools;
86
109
  /**
87
110
  * Wrap each tool's `execute` so it falls back to the current turn's tool
@@ -263,6 +286,7 @@ type Chat = {
263
286
  durable_object_name: string;
264
287
  title?: string;
265
288
  summary?: string;
289
+ title_set_by_user: number;
266
290
  created_at: number;
267
291
  updated_at: number;
268
292
  positive_feedback_count: number;
@@ -279,6 +303,7 @@ declare abstract class Assistant<State = unknown> extends Agent$1<Cloudflare.Env
279
303
  onConnect(connection: Connection, ctx: ConnectionContext): Promise<void>;
280
304
  createChat(): Promise<string>;
281
305
  deleteChat(id: string): Promise<void>;
306
+ renameChat(id: string, title: string): Promise<void>;
282
307
  getChats(): Promise<Chat[]>;
283
308
  getChatAgentClassName(): Promise<string>;
284
309
  recordChatTurn(durableObjectName: string, messages: UIMessage[]): Promise<void>;
@@ -340,4 +365,4 @@ declare function skill<Context extends Record<string, unknown> = Record<string,
340
365
  //#region src/server/index.d.ts
341
366
  declare function getCurrentToolContext(): any;
342
367
  //#endregion
343
- export { Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, Assistant, ChatAgent, type FacetStub, type LegacyChatStub, type LegacyMessageFeedback, type MigrationDeps, type Skill, type SkillSource, type Tool, type ToolContext, type ToolSet, getCurrentToolContext, migrateUserFromV1, routeAgentRequest, skill, tool };
368
+ export { Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, Assistant, ChatAgent, type FacetStub, type LegacyChatStub, type LegacyMessageFeedback, type MigrationDeps, type Skill, type SkillSource, type Tool, type ToolContext, type ToolSet, type TurnSnapshot, getCurrentToolContext, migrateUserFromV1, routeAgentRequest, skill, tool };
package/dist/index.mjs CHANGED
@@ -238,16 +238,7 @@ var Agent = class extends Think {
238
238
  return {
239
239
  system: await this.session.refreshSystemPrompt(),
240
240
  model: this.getModel(this._toolContextForCurrentTurn),
241
- messages: pruneMessages({
242
- messages: ctx.messages,
243
- toolCalls: [{
244
- type: "before-last-2-messages",
245
- tools: []
246
- }, {
247
- type: "before-last-5-messages",
248
- tools: ["activate_skill"]
249
- }]
250
- }),
241
+ messages: this._pruneTurnMessages(ctx.messages),
251
242
  tools: this._withTurnContextFallback(tools),
252
243
  activeTools,
253
244
  experimental_transform: buildSourcesTransform(),
@@ -301,6 +292,48 @@ var Agent = class extends Think {
301
292
  getTools() {
302
293
  return {};
303
294
  }
295
+ /**
296
+ * Read-only: what the model would see on its next step for the given history
297
+ * — the assembled system prompt, the skill-gated toolset, and pruned
298
+ * messages. Runs no turn (nothing admitted, persisted, executed; no model
299
+ * call). Skill gating is derived from the history, so a history with an
300
+ * `activate_skill` call yields that skill's tools. For eval harnesses and
301
+ * prompt-preview tooling; call it inside the DO context.
302
+ */
303
+ async inspectTurn(input = {}) {
304
+ const messages = input.messages ?? [];
305
+ await this.__unsafe_ensureInitialized();
306
+ const previousContext = this._toolContextForCurrentTurn;
307
+ this._toolContextForCurrentTurn = {
308
+ ...input.requestContext ?? {},
309
+ _userContext: input.userContext
310
+ };
311
+ const previousAuthorizedTools = this._authorizedToolsForCurrentTurn;
312
+ try {
313
+ const system = await this.session.refreshSystemPrompt();
314
+ const think = this;
315
+ const frameworkTools = {
316
+ ...await this.session.tools(),
317
+ ...think._skillRegistry?.tools(),
318
+ ...think.mcp?.getAITools?.()
319
+ };
320
+ const { tools, activeTools } = await this._getAuthorizedTools({
321
+ ...this.getTools(),
322
+ ...frameworkTools
323
+ }, this._getLastActivatedSkillName(messages));
324
+ const snapshotContext = this._toolContextForCurrentTurn;
325
+ return {
326
+ system,
327
+ tools: withFallbackToolContext(tools, () => snapshotContext),
328
+ activeTools,
329
+ frameworkToolNames: Object.keys(frameworkTools),
330
+ messages: this._pruneTurnMessages(messages)
331
+ };
332
+ } finally {
333
+ this._toolContextForCurrentTurn = previousContext;
334
+ this._authorizedToolsForCurrentTurn = previousAuthorizedTools;
335
+ }
336
+ }
304
337
  workspaceBash = false;
305
338
  getSkillScriptRunner() {
306
339
  if (!("LOADER" in this.env)) return null;
@@ -313,6 +346,18 @@ var Agent = class extends Think {
313
346
  getRemoteSkills() {
314
347
  return [];
315
348
  }
349
+ _pruneTurnMessages(messages) {
350
+ return pruneMessages({
351
+ messages,
352
+ toolCalls: [{
353
+ type: "before-last-2-messages",
354
+ tools: []
355
+ }, {
356
+ type: "before-last-5-messages",
357
+ tools: ["activate_skill"]
358
+ }]
359
+ });
360
+ }
316
361
  async _getAuthorizedTools(availableTools, activeSkillName) {
317
362
  const tools = { ...availableTools };
318
363
  const activeTools = Object.keys(tools);
@@ -459,6 +504,7 @@ function ensureChatsTableExists(sql) {
459
504
  durable_object_name TEXT NOT NULL,
460
505
  title TEXT,
461
506
  summary TEXT,
507
+ title_set_by_user INTEGER NOT NULL DEFAULT 0,
462
508
  created_at INTEGER NOT NULL,
463
509
  updated_at INTEGER NOT NULL,
464
510
  positive_feedback_count INTEGER NOT NULL DEFAULT 0,
@@ -466,6 +512,7 @@ function ensureChatsTableExists(sql) {
466
512
  PRIMARY KEY (durable_object_name)
467
513
  )`;
468
514
  ensureChatsFeedbackColumnsExist(sql);
515
+ ensureChatsTitleSetByUserColumnExists(sql);
469
516
  ensureChatMessageFeedbackTableExists(sql);
470
517
  } catch (error) {
471
518
  console.error("[Agent] Failed to create chats table", error);
@@ -479,6 +526,11 @@ function ensureChatsFeedbackColumnsExist(sql) {
479
526
  sql`ALTER TABLE chats ADD COLUMN negative_feedback_count INTEGER NOT NULL DEFAULT 0`;
480
527
  } catch {}
481
528
  }
529
+ function ensureChatsTitleSetByUserColumnExists(sql) {
530
+ try {
531
+ sql`ALTER TABLE chats ADD COLUMN title_set_by_user INTEGER NOT NULL DEFAULT 0`;
532
+ } catch {}
533
+ }
482
534
  function ensureChatMessageFeedbackTableExists(sql) {
483
535
  sql`CREATE TABLE IF NOT EXISTS chat_message_feedback (
484
536
  chat_id TEXT NOT NULL,
@@ -507,6 +559,19 @@ function registerChatWithMetadata(sql, durableObjectName, metadata) {
507
559
  VALUES (${durableObjectName}, ${title ?? null}, ${summary ?? null}, ${createdAt}, ${updatedAt})
508
560
  ON CONFLICT (durable_object_name) DO NOTHING`;
509
561
  }
562
+ /**
563
+ * Sets a chat's title on the user's behalf. Marks the title as user-set so
564
+ * the AI summariser stops overwriting it (it keeps updating the summary).
565
+ */
566
+ function renameChat(sql, durableObjectName, title, dateTime = Date.now()) {
567
+ const trimmed = title.trim();
568
+ if (!trimmed) throw new Error("Chat title cannot be empty");
569
+ sql`UPDATE chats
570
+ SET title = ${trimmed},
571
+ title_set_by_user = 1,
572
+ updated_at = ${dateTime}
573
+ WHERE durable_object_name = ${durableObjectName}`;
574
+ }
510
575
  function deleteChat(sql, durableObjectName) {
511
576
  sql`DELETE FROM chats WHERE durable_object_name = ${durableObjectName}`;
512
577
  sql`DELETE FROM chat_message_feedback WHERE chat_id = ${durableObjectName}`;
@@ -578,7 +643,7 @@ async function summariseChatWithAI(sql, durableObjectName, messages, model) {
578
643
  return;
579
644
  }
580
645
  sql`UPDATE chats
581
- SET title = ${title},
646
+ SET title = CASE WHEN title_set_by_user = 1 THEN title ELSE ${title} END,
582
647
  summary = ${summary},
583
648
  updated_at = ${Date.now()}
584
649
  WHERE durable_object_name = ${durableObjectName}`;
@@ -825,6 +890,11 @@ var Assistant = class extends Agent$1 {
825
890
  2,
826
891
  "deleteChat"
827
892
  ],
893
+ [
894
+ callable(),
895
+ 2,
896
+ "renameChat"
897
+ ],
828
898
  [
829
899
  callable(),
830
900
  2,
@@ -888,6 +958,9 @@ var Assistant = class extends Agent$1 {
888
958
  await this.deleteSubAgent(this.agent, id);
889
959
  deleteChat(this.sql.bind(this), id);
890
960
  }
961
+ async renameChat(id, title) {
962
+ renameChat(this.sql.bind(this), id, title);
963
+ }
891
964
  async getChats() {
892
965
  return getChats(this.sql.bind(this));
893
966
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@economic/agents",
3
- "version": "2.3.27",
3
+ "version": "2.5.0",
4
4
  "description": "A starter for creating a TypeScript package.",
5
5
  "license": "MIT",
6
6
  "files": [