@economic/agents 2.11.3 → 2.13.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/README.md CHANGED
@@ -443,7 +443,7 @@ Use this skill whenever the user asks about current conditions or a forecast.
443
443
  });
444
444
  ```
445
445
 
446
- Return skills from `getSkills()`. Add `authorize(ctx)` to gate a skill (and its tools). `skill()` throws if `description` or `instructions` is missing.
446
+ Return skills from `getSkills()`. Add `authorize(ctx)` to gate a skill (and its tools). Denied skills are hidden from the catalog and `activate_skill` by default. Set `onUnauthorized` to a reason string, or a function that returns one, to expose a denied skill with user-facing guidance. A function can return `undefined` to keep it hidden. `skill()` throws if `description` or `instructions` is missing.
447
447
 
448
448
  ### Native Agent Skills
449
449
 
@@ -640,7 +640,30 @@ When configured:
640
640
  AI telemetry is emitted per turn from the `ai` SDK's OpenTelemetry spans:
641
641
 
642
642
  - **Audit logs** → one JSON object per turn in `AGENTS_AUDIT_LOGS` (model, actor, IP, prompt, response, tool calls).
643
- - **Analytics** → per-turn and per-tool data points in `AGENTS_ANALYTICS`.
643
+ - **Analytics** → typed per-turn and per-tool events. By default these are written to
644
+ `AGENTS_ANALYTICS` using the existing Analytics Engine schema.
645
+
646
+ Additional analytics destinations can receive the same events by overriding
647
+ `getAnalyticsHandlers()`. Analytics Engine remains enabled whenever `AGENTS_ANALYTICS` is bound:
648
+
649
+ ```typescript
650
+ import type { AnalyticsHandler } from "@economic/agents";
651
+
652
+ const warehouse: AnalyticsHandler = {
653
+ name: "warehouse",
654
+ async handle(event) {
655
+ await sendToWarehouse(event);
656
+ },
657
+ };
658
+
659
+ getAnalyticsHandlers() {
660
+ return [warehouse];
661
+ }
662
+ ```
663
+
664
+ Handler failures are isolated and recorded as operational errors. Delivery runs through the
665
+ agent's lifetime management without blocking the response. `prompt.received` includes the raw
666
+ prompt for destinations such as conversation classification; handlers must treat it as sensitive.
644
667
 
645
668
  Separately, the SDK writes structured operational logs for completed/failed LLM and tool calls, turn duration, framework failures, and selected recovery warnings. Prompt, response, tool argument, and tool result content is excluded. These records use the stable fields `source`, `event`, `level`, `timestamp`, `agentName`, `agentClass`, `durableObjectName`, and `attributes`, while preserving Cloudflare's diagnostic events.
646
669
 
@@ -660,29 +683,34 @@ Imported from `@economic/agents` unless noted.
660
683
 
661
684
  ### Helpers and types
662
685
 
663
- | Export | Description |
664
- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
665
- | `tool(def)` / `Tool` / `ToolSet` | Define a tool with optional `approval`, `authorize`, and `onUnauthorized`. |
666
- | `action(def)` / `Action` / `RegisteredAction` / `ActionContext` | Define a ledger-backed action with approval and idempotency support. |
667
- | `skill(def)` / `Skill` | Define a skill with optional `tools`, `actions`, and authorization. |
668
- | `ToolContext` | `RequestContext & { _userContext?: UserContext }`. |
669
- | `AgentEnv` | The bindings the runtime expects. |
670
- | `AgentConnectionState` / `AgentConnectionStatus` / `AgentConnectionType` | Connection state shared with the client. |
686
+ | Export | Description |
687
+ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
688
+ | `tool(def)` / `Tool` / `ToolSet` | Define a tool with optional `approval`, `authorize`, and `onUnauthorized`. |
689
+ | `action(def)` / `Action` / `RegisteredAction` / `ActionContext` | Define a ledger-backed action with approval and idempotency support. |
690
+ | `skill(def)` / `Skill` | Define a skill with optional `tools`, `actions`, `authorize`, and `onUnauthorized`. |
691
+ | `UnauthorizedPolicy` | Shared reason or context-dependent reason for denied tools, actions, and skills. |
692
+ | `ToolContext` | `RequestContext & { _userContext?: UserContext }`. |
693
+ | `AgentEnv` | The bindings the runtime expects. |
694
+ | `AgentConnectionState` / `AgentConnectionStatus` / `AgentConnectionType` | Connection state shared with the client. |
695
+ | `AnalyticsHandler` / `AnalyticsEvent` | Typed, consumer-configured product-analytics destinations. |
696
+ | `createAnalyticsEngineHandler(dataset)` | Analytics Engine destination using the existing v2 positional schema. |
671
697
 
672
698
  ### Members
673
699
 
674
- | Member | On | Description |
675
- | ---------------------------------------------- | ----------- | -------------------------------------------- |
676
- | `getModel(ctx?)` | `Agent` | Required. Model for inference. |
677
- | `getSystemPrompt(ctx?)` | `Agent` | Required. System prompt. |
678
- | `getTools()` | `Agent` | Always-on tools (default `{}`). |
679
- | `getSkills()` | `Agent` | Local skills (default `[]`). |
680
- | `static getJwtAuthConfig(env)` | `Agent` | Optional JWT verification and actor binding. |
681
- | `getUserContext(jwtToken)` | `Agent` | Optional per-user context after auth. |
682
- | `submitMessageFeedback` / `getMessageFeedback` | `ChatAgent` | Callable message feedback. |
683
- | `agent` | `Assistant` | Required. Your `ChatAgent` subclass. |
684
- | `fastModel` | `Assistant` | Required. Cheap model for titles/summaries. |
685
- | `createChat` / `getChats` / `deleteChat` | `Assistant` | Callable chat management. |
700
+ | Member | On | Description |
701
+ | ---------------------------------------------- | ----------- | ---------------------------------------------------------------------- |
702
+ | `getModel(ctx?)` | `Agent` | Required. Model for inference. |
703
+ | `getSystemPrompt(ctx?)` | `Agent` | Required. System prompt. |
704
+ | `getTools()` | `Agent` | Always-on tools (default `{}`). |
705
+ | `getSkills()` | `Agent` | Local skills (default `[]`). |
706
+ | `getAnalyticsHandlers()` | `Agent` | Additional analytics destinations; Analytics Engine remains automatic. |
707
+ | `getAnalyticsAttributes()` | `Agent` | Additional dimensions included on every analytics event. |
708
+ | `static getJwtAuthConfig(env)` | `Agent` | Optional JWT verification and actor binding. |
709
+ | `getUserContext(jwtToken)` | `Agent` | Optional per-user context after auth. |
710
+ | `submitMessageFeedback` / `getMessageFeedback` | `ChatAgent` | Callable message feedback. |
711
+ | `agent` | `Assistant` | Required. Your `ChatAgent` subclass. |
712
+ | `fastModel` | `Assistant` | Required. Cheap model for titles/summaries. |
713
+ | `createChat` / `getChats` / `deleteChat` | `Assistant` | Callable chat management. |
686
714
 
687
715
  ### Package root (`@economic/agents`)
688
716
 
package/dist/index.d.mts CHANGED
@@ -24,6 +24,11 @@ interface AgentEnv {
24
24
  }
25
25
  type AgentConnectionStatus = "connecting" | "reconnecting" | "connected" | "disconnected" | "unauthorized" | "error";
26
26
  type AgentConnectionType = "agent" | "chat" | "assistant";
27
+ /**
28
+ * Guidance for an unauthorized capability. A string exposes the capability
29
+ * with that guidance; `undefined` from a function keeps it hidden.
30
+ */
31
+ type UnauthorizedPolicy<Context extends Record<string, unknown> = Record<string, unknown>> = string | ((ctx?: Context) => string | undefined);
27
32
  //#endregion
28
33
  //#region src/server/features/auth/index.d.ts
29
34
  interface JwtAuthConfig<TClaims extends Record<string, unknown> = Record<string, unknown>> {
@@ -100,22 +105,111 @@ declare function exchangeToken(subjectToken: string, config: TokenExchangeConfig
100
105
  //#endregion
101
106
  //#region src/server/util/tools.d.ts
102
107
  type ToolSet = Record<string, Tool>;
103
- interface UnauthorizedToolPolicy<Context extends Record<string, unknown> = Record<string, unknown>> {
104
- /**
105
- * Keep the tool visible to the model when {@link Tool.authorize} returns
106
- * `false`. A function can decide from the same context passed to `authorize`.
107
- */
108
- expose: boolean | ((ctx?: Context) => boolean);
109
- /** Explanation shown to the model for this unavailable tool. */
110
- reason: string | ((ctx?: Context) => string);
111
- }
108
+ /** @deprecated Use {@link UnauthorizedPolicy}. */
109
+ type UnauthorizedToolPolicy<Context extends Record<string, unknown> = Record<string, unknown>> = UnauthorizedPolicy<Context>;
112
110
  type Tool<Context extends Record<string, unknown> = Record<string, unknown>, INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any> = Tool$1<INPUT, OUTPUT> & {
113
111
  /** SDK-consistent alias for the AI SDK's `needsApproval` option. */approval?: Tool$1<INPUT, OUTPUT>["needsApproval"];
114
112
  authorize?: (ctx?: Context) => boolean;
115
- onUnauthorized?: UnauthorizedToolPolicy<Context>;
113
+ onUnauthorized?: UnauthorizedPolicy<Context>;
116
114
  };
117
115
  declare function tool<Context extends Record<string, unknown> = Record<string, unknown>, INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any>(definition: Tool<Context, INPUT, OUTPUT>): Tool$1<INPUT, OUTPUT>;
118
116
  //#endregion
117
+ //#region src/server/features/analytics/types.d.ts
118
+ type AnalyticsAttribute = string | number | boolean;
119
+ type AnalyticsAttributes = Readonly<Record<string, AnalyticsAttribute>>;
120
+ interface AnalyticsUsage {
121
+ inputTokens: number;
122
+ outputTokens: number;
123
+ totalTokens: number;
124
+ cachedInputTokens?: number;
125
+ cacheWriteTokens?: number;
126
+ reasoningTokens?: number;
127
+ }
128
+ type AnalyticsEventPayload = {
129
+ type: "prompt.received"; /** Raw model messages. Handlers must treat this field as sensitive data. */
130
+ messages: readonly ModelMessage[];
131
+ continuation: boolean;
132
+ } | {
133
+ type: "turn.completed";
134
+ requestId: string;
135
+ status: string;
136
+ continuation: boolean;
137
+ responseSize: number;
138
+ } | {
139
+ type: "llm.completed";
140
+ model: string;
141
+ provider: string;
142
+ finishReason: string;
143
+ usage: AnalyticsUsage;
144
+ durationMs: number;
145
+ inputSize: number;
146
+ responseSize: number;
147
+ } | {
148
+ type: "tool.completed";
149
+ toolCallId?: string;
150
+ toolName: string;
151
+ skillNames: readonly string[];
152
+ success: boolean;
153
+ durationMs: number;
154
+ inputSize: number;
155
+ outputSize: number;
156
+ } | {
157
+ type: "feedback.submitted";
158
+ messageId: string;
159
+ rating: 1 | -1 | 0;
160
+ };
161
+ type AnalyticsEvent = AnalyticsEventPayload & {
162
+ schemaVersion: 1;
163
+ eventId: string;
164
+ timestamp: number;
165
+ agentName: string;
166
+ durableObjectName: string;
167
+ actorId: string;
168
+ attributes: AnalyticsAttributes;
169
+ };
170
+ /** Receives typed product-analytics events emitted by the SDK. */
171
+ interface AnalyticsHandler {
172
+ readonly name?: string;
173
+ handle(event: AnalyticsEvent): void | Promise<void>;
174
+ }
175
+ interface AnalyticsEventContext {
176
+ agentName: string;
177
+ durableObjectName: string;
178
+ actorId: string;
179
+ attributes?: AnalyticsAttributes;
180
+ }
181
+ //#endregion
182
+ //#region src/server/features/analytics/analytics-engine.d.ts
183
+ /**
184
+ * Creates a Cloudflare Analytics Engine destination for SDK analytics events.
185
+ * It preserves the SDK v2 positional schema and never writes prompt content.
186
+ */
187
+ declare function createAnalyticsEngineHandler(dataset: AnalyticsEngineDataset): AnalyticsHandler;
188
+ //#endregion
189
+ //#region src/server/features/analytics/dispatcher.d.ts
190
+ declare function createAnalyticsEvent(context: AnalyticsEventContext, payload: AnalyticsEventPayload): AnalyticsEvent;
191
+ declare function dispatchAnalyticsEvent(handlers: readonly AnalyticsHandler[], event: AnalyticsEvent): Promise<void>;
192
+ //#endregion
193
+ //#region src/server/features/analytics/emitter.d.ts
194
+ interface AnalyticsOptions {
195
+ getContext(): AnalyticsEventContext;
196
+ getHandlers(): readonly AnalyticsHandler[];
197
+ keepAlive<T>(callback: () => Promise<T>): Promise<T>;
198
+ }
199
+ declare class Analytics {
200
+ private readonly options;
201
+ private handlers?;
202
+ constructor(options: AnalyticsOptions);
203
+ private getHandlers;
204
+ private emit;
205
+ get enabled(): boolean;
206
+ get context(): AnalyticsEventContext;
207
+ promptReceived(messages: readonly ModelMessage[], continuation: boolean): void;
208
+ turnCompleted(requestId: string, status: string, continuation: boolean, response: unknown): void;
209
+ feedbackSubmitted(messageId: string, rating: 1 | -1 | 0): void;
210
+ event(payload: AnalyticsEventPayload | (() => AnalyticsEventPayload)): void;
211
+ }
212
+ //#endregion
119
213
  //#region src/server/agents/Agent.d.ts
120
214
  /** What the model would see on its next step — returned by {@link Agent.inspectTurn}. */
121
215
  interface TurnSnapshot {
@@ -193,14 +287,14 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
193
287
  }): Promise<TurnSnapshot>;
194
288
  workspaceBash: boolean;
195
289
  getSkillScriptRunner(): skills.SkillScriptRunner | null;
196
- /**
197
- * Returns the remote skills to be loaded from SKILLS_BUCKET.
198
- * @returns The remote skills to be loaded from SKILLS_BUCKET.
199
- */
200
- protected getRemoteSkills(): string[];
201
290
  protected pruneTurnMessages(messages: ModelMessage[]): ModelMessage[];
202
- private _getTurnSystemPrompt;
203
291
  private _prepareTools;
292
+ private _renderSkillsSystemBlock;
293
+ private _filterSkillHelperTools;
294
+ private _filterActivateSkillTool;
295
+ private _skillSources?;
296
+ private _getUnauthorizedReason;
297
+ private _getSkillSources;
204
298
  /**
205
299
  * Wrap each tool's `execute` so it falls back to the current turn's tool
206
300
  * context (request body + `_userContext`)
@@ -307,6 +401,14 @@ declare abstract class Agent<RequestContext extends Record<string, unknown> = Re
307
401
  * Best-effort and non-blocking — never allowed to interfere with a turn.
308
402
  */
309
403
  protected registerInstanceActivity(): Promise<void>;
404
+ protected readonly analytics: Analytics;
405
+ /**
406
+ * Additional product-analytics destinations for this agent. Analytics Engine
407
+ * remains enabled whenever `AGENTS_ANALYTICS` is bound.
408
+ */
409
+ getAnalyticsHandlers(): readonly AnalyticsHandler[];
410
+ /** Business dimensions added to every analytics event. */
411
+ getAnalyticsAttributes(): AnalyticsAttributes;
310
412
  observability?: Observability;
311
413
  /**
312
414
  * Resolves the analytics/telemetry agent name to the entry-point agent: the
@@ -423,12 +525,12 @@ type Action<Context extends Record<string, unknown> = Record<string, unknown>, I
423
525
  idempotencyKey?: ActionIdempotencyKey<Input>;
424
526
  permissions?: ActionPermissionSpec<Input>;
425
527
  authorize?: (ctx?: Context) => boolean;
426
- onUnauthorized?: UnauthorizedToolPolicy<Context>;
528
+ onUnauthorized?: UnauthorizedPolicy<Context>;
427
529
  execute(input: Input, ctx: ActionContext<Context>): Promise<Output> | Output;
428
530
  };
429
531
  type RegisteredAction<Context extends Record<string, unknown> = Record<string, unknown>, InputSchema extends FlexibleSchema = FlexibleSchema, Output = unknown> = Action$1<InputSchema, Output> & {
430
532
  authorize?: (ctx?: Context) => boolean;
431
- onUnauthorized?: UnauthorizedToolPolicy<Context>;
533
+ onUnauthorized?: UnauthorizedPolicy<Context>;
432
534
  };
433
535
  /** A native Think action with the SDK's standard authorization policy. */
434
536
  declare function action<Context extends Record<string, unknown> = Record<string, unknown>, Input = any, Output = any>(definition: Action<Context, Input, Output>): RegisteredAction<Context, FlexibleSchema<Input>, Output>;
@@ -441,11 +543,13 @@ interface Skill<Context extends Record<string, unknown> = Record<string, unknown
441
543
  tools?: Record<string, Tool<Context>>;
442
544
  actions?: Record<string, RegisteredAction<Context, any, any>>;
443
545
  authorize?: (ctx?: Context) => boolean;
546
+ onUnauthorized?: UnauthorizedPolicy<Context>;
444
547
  }
445
548
  interface SkillSource<Context extends Record<string, unknown> = Record<string, unknown>> extends SkillSource$1 {
446
549
  tools?: Record<string, Tool<Context>>;
447
550
  actions?: Record<string, RegisteredAction<Context, any, any>>;
448
551
  authorize?: (ctx?: Context | undefined) => boolean;
552
+ onUnauthorized?: UnauthorizedPolicy<Context>;
449
553
  }
450
554
  declare function skill<Context extends Record<string, unknown> = Record<string, unknown>>(definition: Skill<Context>): SkillSource<Context>;
451
555
  //#endregion
@@ -455,4 +559,4 @@ declare function routeAgentRequest<Env>(request: Request, env: Env, options?: Ag
455
559
  //#region src/server/index.d.ts
456
560
  declare function getCurrentToolContext(): any;
457
561
  //#endregion
458
- export { type Action, type ActionContext, Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, Assistant, ChatAgent, type ExchangedToken, type JwtAuthConfig, type RegisteredAction, type Skill, type SkillSource, type TokenExchangeConfig, type TokenExchangeResult, type Tool, type ToolContext, type ToolSet, type TurnSnapshot, type UnauthorizedToolPolicy, action, createJwtAuthConfig, exchangeToken, getCurrentToolContext, routeAgentRequest, skill, tool };
562
+ export { type Action, type ActionContext, Agent, type AgentConnectionStatus, type AgentConnectionType, type AgentEnv, type AnalyticsAttribute, type AnalyticsAttributes, type AnalyticsEvent, type AnalyticsEventPayload, type AnalyticsHandler, type AnalyticsUsage, Assistant, ChatAgent, type ExchangedToken, type JwtAuthConfig, type RegisteredAction, type Skill, type SkillSource, type TokenExchangeConfig, type TokenExchangeResult, type Tool, type ToolContext, type ToolSet, type TurnSnapshot, type UnauthorizedPolicy, type UnauthorizedToolPolicy, action, createAnalyticsEngineHandler, createAnalyticsEvent, createJwtAuthConfig, dispatchAnalyticsEvent, exchangeToken, getCurrentToolContext, routeAgentRequest, skill, tool };