@clawpify/skills 1.0.3 → 1.0.5

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/agent.d.ts CHANGED
@@ -1,18 +1,148 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
  import { ShopifyClient } from "./shopify";
3
+ import type { MemoryStore } from "./memory";
4
+ /** Accumulated token usage and estimated cost for a single chat() call. */
5
+ export interface TokenUsage {
6
+ inputTokens: number;
7
+ outputTokens: number;
8
+ cacheCreationInputTokens: number;
9
+ cacheReadInputTokens: number;
10
+ /** Estimated USD cost based on the configured pricing. */
11
+ totalCost: number;
12
+ }
13
+ /** Per-model pricing in USD per million tokens. */
14
+ export interface ModelPricing {
15
+ inputPerMillion: number;
16
+ outputPerMillion: number;
17
+ cacheWritePerMillion: number;
18
+ cacheReadPerMillion: number;
19
+ }
20
+ /** A user-provided tool + handler that extends the agent's capabilities. */
21
+ export interface AgentPlugin {
22
+ tool: Anthropic.Tool;
23
+ handler: (input: Record<string, any>) => Promise<string>;
24
+ }
25
+ /** Lifecycle hooks for observability and custom behavior. */
26
+ export interface AgentHooks {
27
+ /** Fires before a chat request is processed. */
28
+ onRequest?: (message: string, history: Anthropic.MessageParam[]) => void | Promise<void>;
29
+ /** Fires before each Anthropic API call (including retries in the loop). */
30
+ onApiCall?: (params: {
31
+ model: string;
32
+ messages: Anthropic.MessageParam[];
33
+ tools: Anthropic.Tool[];
34
+ }) => void | Promise<void>;
35
+ /** Fires before a tool handler is executed. */
36
+ onToolCall?: (toolName: string, input: Record<string, any>) => void | Promise<void>;
37
+ /** Fires after a tool handler returns. */
38
+ onToolResult?: (toolName: string, result: string, isError: boolean) => void | Promise<void>;
39
+ /** Fires after the final text response is assembled. */
40
+ onResponse?: (response: string, usage: TokenUsage) => void | Promise<void>;
41
+ /** Fires when an error is caught during the chat loop. */
42
+ onError?: (error: Error) => void | Promise<void>;
43
+ }
44
+ /** Extended thinking configuration. */
45
+ export interface ThinkingConfig {
46
+ /** Token budget for thinking. Must be >= 1024. */
47
+ budgetTokens: number;
48
+ }
49
+ /** Full configuration accepted by the ShopifyAgent constructor. */
50
+ export interface AgentConfig {
51
+ shopify: ShopifyClient;
52
+ skillContent: string;
53
+ model?: string;
54
+ /** Override the default system instruction sent to the model. */
55
+ systemInstruction?: string;
56
+ /** Override default Claude Sonnet pricing. */
57
+ pricing?: ModelPricing;
58
+ /** Register plugins at construction time. */
59
+ plugins?: AgentPlugin[];
60
+ /** Lifecycle hooks for observability. */
61
+ hooks?: AgentHooks;
62
+ /** Enable extended thinking so the model plans before executing. */
63
+ thinking?: ThinkingConfig;
64
+ /** Maximum tool-use loop iterations before the agent stops. Defaults to 20. */
65
+ maxIterations?: number;
66
+ /** Persistent memory store for conversation history across sessions. */
67
+ memory?: MemoryStore;
68
+ }
69
+ /** Return value of a single chat() invocation. */
70
+ export interface ChatResult {
71
+ response: string;
72
+ history: Anthropic.MessageParam[];
73
+ usage: TokenUsage;
74
+ /** Concatenated thinking text when extended thinking is enabled. */
75
+ thinking?: string;
76
+ /** Number of tool-use loop iterations used in this call. */
77
+ iterationsUsed: number;
78
+ }
79
+ /** Events yielded by chatStream(). */
80
+ export type StreamEvent = {
81
+ type: "thinking";
82
+ text: string;
83
+ } | {
84
+ type: "text";
85
+ text: string;
86
+ } | {
87
+ type: "tool_call";
88
+ name: string;
89
+ input: Record<string, any>;
90
+ } | {
91
+ type: "tool_result";
92
+ name: string;
93
+ result: string;
94
+ isError: boolean;
95
+ } | {
96
+ type: "done";
97
+ response: string;
98
+ thinking?: string;
99
+ usage: TokenUsage;
100
+ iterationsUsed: number;
101
+ history: Anthropic.MessageParam[];
102
+ };
103
+ export declare const DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
3
104
  export declare class ShopifyAgent {
4
105
  private anthropic;
5
106
  private shopify;
6
107
  private skillContent;
108
+ private systemInstruction;
7
109
  private model;
8
- constructor(config: {
9
- shopify: ShopifyClient;
10
- skillContent: string;
11
- model?: string;
12
- });
13
- chat(userMessage: string, conversationHistory?: Anthropic.MessageParam[]): Promise<{
14
- response: string;
15
- history: Anthropic.MessageParam[];
16
- }>;
110
+ private pricing;
111
+ private plugins;
112
+ private hooks;
113
+ private thinkingConfig;
114
+ private maxIterations;
115
+ private memory;
116
+ constructor(config: AgentConfig);
117
+ /** Register a plugin at runtime. Throws if a tool with the same name already exists. */
118
+ registerPlugin(plugin: AgentPlugin): void;
119
+ /** Build the system prompt array with prompt caching. */
120
+ private buildSystemPrompt;
121
+ /** Build the tools list with cache_control on the last tool. */
122
+ private buildTools;
123
+ /** Compute max_tokens accounting for thinking budget. */
124
+ private getMaxTokens;
125
+ /** Build optional thinking param for the API call. */
126
+ private getThinkingParam;
127
+ /** Execute a single tool call by name. Returns content and error flag. */
128
+ private executeTool;
129
+ /** Process all tool_use blocks from a response, returning tool results. */
130
+ private processToolCalls;
131
+ /**
132
+ * Send a message and get a complete response (non-streaming).
133
+ * Runs the agentic tool-use loop until the model produces a final text response.
134
+ */
135
+ chat(userMessage: string, conversationHistory?: Anthropic.MessageParam[]): Promise<ChatResult>;
136
+ /**
137
+ * Send a message and stream the response as typed events.
138
+ * Same agentic loop as chat() but yields incremental text/thinking deltas.
139
+ */
140
+ chatStream(userMessage: string, conversationHistory?: Anthropic.MessageParam[]): AsyncGenerator<StreamEvent>;
141
+ /**
142
+ * Chat with automatic session memory.
143
+ * Loads conversation history from the memory store, runs chat(), and saves
144
+ * the updated history back. Requires a MemoryStore to be configured.
145
+ */
146
+ chatWithMemory(sessionId: string, userMessage: string): Promise<ChatResult>;
17
147
  }
18
148
  //# sourceMappingURL=agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAsB1C,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE;QAClB,OAAO,EAAE,aAAa,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB;IAOK,IAAI,CACR,WAAW,EAAE,MAAM,EACnB,mBAAmB,GAAE,SAAS,CAAC,YAAY,EAAO,GACjD,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,SAAS,CAAC,YAAY,EAAE,CAAA;KAAE,CAAC;CAyFpE"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/agent.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/agent.ts
2
2
  import Anthropic from "@anthropic-ai/sdk";
3
+ var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
3
4
  var SHOPIFY_GRAPHQL_TOOL = {
4
5
  name: "shopify_graphql",
5
6
  description: "Execute a GraphQL query against the Shopify Admin API. Use this to interact with products, orders, customers, inventory, and other Shopify resources.",
@@ -18,82 +19,372 @@ var SHOPIFY_GRAPHQL_TOOL = {
18
19
  required: ["query"]
19
20
  }
20
21
  };
22
+ var DEFAULT_PRICING = {
23
+ inputPerMillion: 3,
24
+ outputPerMillion: 15,
25
+ cacheWritePerMillion: 3.75,
26
+ cacheReadPerMillion: 0.3
27
+ };
28
+ var DEFAULT_MAX_ITERATIONS = 20;
29
+ async function safeHook(hook, ...args) {
30
+ if (!hook)
31
+ return;
32
+ try {
33
+ await hook(...args);
34
+ } catch {}
35
+ }
36
+ function computeCost(usage, pricing) {
37
+ return usage.inputTokens * pricing.inputPerMillion / 1e6 + usage.outputTokens * pricing.outputPerMillion / 1e6 + usage.cacheCreationInputTokens * pricing.cacheWritePerMillion / 1e6 + usage.cacheReadInputTokens * pricing.cacheReadPerMillion / 1e6;
38
+ }
39
+ function emptyUsage() {
40
+ return {
41
+ inputTokens: 0,
42
+ outputTokens: 0,
43
+ cacheCreationInputTokens: 0,
44
+ cacheReadInputTokens: 0,
45
+ totalCost: 0
46
+ };
47
+ }
48
+ function accumulateUsage(total, raw, pricing) {
49
+ total.inputTokens += raw.input_tokens;
50
+ total.outputTokens += raw.output_tokens;
51
+ total.cacheCreationInputTokens += raw.cache_creation_input_tokens ?? 0;
52
+ total.cacheReadInputTokens += raw.cache_read_input_tokens ?? 0;
53
+ total.totalCost = computeCost(total, pricing);
54
+ }
55
+ function extractContent(response) {
56
+ let text = "";
57
+ let thinking = "";
58
+ for (const block of response.content) {
59
+ if (block.type === "text") {
60
+ text += (text ? `
61
+ ` : "") + block.text;
62
+ } else if (block.type === "thinking") {
63
+ thinking += (thinking ? `
64
+ ` : "") + block.thinking;
65
+ }
66
+ }
67
+ return { text, thinking };
68
+ }
21
69
 
22
70
  class ShopifyAgent {
23
71
  anthropic;
24
72
  shopify;
25
73
  skillContent;
74
+ systemInstruction;
26
75
  model;
76
+ pricing;
77
+ plugins = new Map;
78
+ hooks;
79
+ thinkingConfig;
80
+ maxIterations;
81
+ memory;
27
82
  constructor(config) {
28
83
  this.anthropic = new Anthropic;
29
84
  this.shopify = config.shopify;
30
85
  this.skillContent = config.skillContent;
86
+ this.systemInstruction = config.systemInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
31
87
  this.model = config.model ?? "claude-sonnet-4-5";
88
+ this.pricing = config.pricing ?? DEFAULT_PRICING;
89
+ this.hooks = config.hooks ?? {};
90
+ this.thinkingConfig = config.thinking;
91
+ this.maxIterations = config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
92
+ this.memory = config.memory;
93
+ if (config.plugins) {
94
+ for (const plugin of config.plugins) {
95
+ this.registerPlugin(plugin);
96
+ }
97
+ }
98
+ }
99
+ registerPlugin(plugin) {
100
+ const name = plugin.tool.name;
101
+ if (name === "shopify_graphql") {
102
+ throw new Error(`Cannot register plugin with reserved tool name "shopify_graphql"`);
103
+ }
104
+ if (this.plugins.has(name)) {
105
+ throw new Error(`Plugin with tool name "${name}" is already registered`);
106
+ }
107
+ this.plugins.set(name, plugin);
108
+ }
109
+ buildSystemPrompt() {
110
+ return [
111
+ { type: "text", text: this.systemInstruction },
112
+ {
113
+ type: "text",
114
+ text: this.skillContent,
115
+ cache_control: { type: "ephemeral" }
116
+ }
117
+ ];
118
+ }
119
+ buildTools() {
120
+ const allTools = [
121
+ SHOPIFY_GRAPHQL_TOOL,
122
+ ...[...this.plugins.values()].map((p) => p.tool)
123
+ ];
124
+ if (allTools.length > 0) {
125
+ const last = allTools[allTools.length - 1];
126
+ allTools[allTools.length - 1] = Object.assign({}, last, {
127
+ cache_control: { type: "ephemeral" }
128
+ });
129
+ }
130
+ return allTools;
131
+ }
132
+ getMaxTokens() {
133
+ return this.thinkingConfig ? this.thinkingConfig.budgetTokens + 4096 : 4096;
134
+ }
135
+ getThinkingParam() {
136
+ if (!this.thinkingConfig)
137
+ return {};
138
+ return {
139
+ thinking: {
140
+ type: "enabled",
141
+ budget_tokens: this.thinkingConfig.budgetTokens
142
+ }
143
+ };
144
+ }
145
+ async executeTool(name, input) {
146
+ await safeHook(this.hooks.onToolCall, name, input);
147
+ if (name === "shopify_graphql") {
148
+ try {
149
+ const result = await this.shopify.graphql(input.query, input.variables);
150
+ const content2 = JSON.stringify(result, null, 2);
151
+ await safeHook(this.hooks.onToolResult, name, content2, false);
152
+ return { content: content2, isError: false };
153
+ } catch (error) {
154
+ const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
155
+ await safeHook(this.hooks.onToolResult, name, content2, true);
156
+ return { content: content2, isError: true };
157
+ }
158
+ }
159
+ if (this.plugins.has(name)) {
160
+ const plugin = this.plugins.get(name);
161
+ try {
162
+ const content2 = await plugin.handler(input);
163
+ await safeHook(this.hooks.onToolResult, name, content2, false);
164
+ return { content: content2, isError: false };
165
+ } catch (error) {
166
+ const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
167
+ await safeHook(this.hooks.onToolResult, name, content2, true);
168
+ return { content: content2, isError: true };
169
+ }
170
+ }
171
+ const content = `Error: Unknown tool "${name}"`;
172
+ await safeHook(this.hooks.onToolResult, name, content, true);
173
+ return { content, isError: true };
174
+ }
175
+ async processToolCalls(response) {
176
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
177
+ const toolResults = [];
178
+ for (const toolUse of toolUseBlocks) {
179
+ const input = toolUse.input;
180
+ const { content, isError } = await this.executeTool(toolUse.name, input);
181
+ toolResults.push({
182
+ type: "tool_result",
183
+ tool_use_id: toolUse.id,
184
+ content,
185
+ ...isError ? { is_error: true } : {}
186
+ });
187
+ }
188
+ return toolResults;
32
189
  }
33
190
  async chat(userMessage, conversationHistory = []) {
34
- const systemPrompt = `You are a helpful Shopify assistant that can query and manage a Shopify store using the GraphQL Admin API.
35
-
36
- ${this.skillContent}
37
-
38
- When the user asks about products, orders, customers, or any Shopify data, use the shopify_graphql tool to fetch or modify the data. Always explain what you're doing and present results clearly.`;
191
+ const usage = emptyUsage();
192
+ let iterationsUsed = 0;
193
+ let allThinking = "";
194
+ const systemPrompt = this.buildSystemPrompt();
195
+ const allTools = this.buildTools();
196
+ const maxTokens = this.getMaxTokens();
197
+ const thinkingParam = this.getThinkingParam();
39
198
  const messages = [
40
199
  ...conversationHistory,
41
200
  { role: "user", content: userMessage }
42
201
  ];
43
- let response = await this.anthropic.messages.create({
44
- model: this.model,
45
- max_tokens: 4096,
46
- system: systemPrompt,
47
- tools: [SHOPIFY_GRAPHQL_TOOL],
48
- messages
49
- });
50
- const assistantMessages = [];
51
- while (response.stop_reason === "tool_use") {
52
- const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
53
- assistantMessages.push(...response.content);
54
- const toolResults = [];
55
- for (const toolUse of toolUseBlocks) {
56
- if (toolUse.name === "shopify_graphql") {
57
- const input = toolUse.input;
58
- try {
59
- const result = await this.shopify.graphql(input.query, input.variables);
60
- toolResults.push({
202
+ await safeHook(this.hooks.onRequest, userMessage, conversationHistory);
203
+ try {
204
+ await safeHook(this.hooks.onApiCall, {
205
+ model: this.model,
206
+ messages,
207
+ tools: allTools
208
+ });
209
+ let response = await this.anthropic.messages.create({
210
+ model: this.model,
211
+ max_tokens: maxTokens,
212
+ system: systemPrompt,
213
+ tools: allTools,
214
+ messages,
215
+ ...thinkingParam
216
+ });
217
+ accumulateUsage(usage, response.usage, this.pricing);
218
+ const firstContent = extractContent(response);
219
+ if (firstContent.thinking)
220
+ allThinking += firstContent.thinking;
221
+ while (response.stop_reason === "tool_use") {
222
+ iterationsUsed++;
223
+ if (iterationsUsed > this.maxIterations) {
224
+ const err = new Error(`Agent exceeded maximum iterations (${this.maxIterations})`);
225
+ await safeHook(this.hooks.onError, err);
226
+ break;
227
+ }
228
+ messages.push({
229
+ role: "assistant",
230
+ content: response.content
231
+ });
232
+ const toolResults = await this.processToolCalls(response);
233
+ messages.push({ role: "user", content: toolResults });
234
+ await safeHook(this.hooks.onApiCall, {
235
+ model: this.model,
236
+ messages,
237
+ tools: allTools
238
+ });
239
+ response = await this.anthropic.messages.create({
240
+ model: this.model,
241
+ max_tokens: maxTokens,
242
+ system: systemPrompt,
243
+ tools: allTools,
244
+ messages,
245
+ ...thinkingParam
246
+ });
247
+ accumulateUsage(usage, response.usage, this.pricing);
248
+ const loopContent = extractContent(response);
249
+ if (loopContent.thinking) {
250
+ allThinking += (allThinking ? `
251
+ ` : "") + loopContent.thinking;
252
+ }
253
+ }
254
+ const { text: finalResponse } = extractContent(response);
255
+ const updatedHistory = [
256
+ ...messages,
257
+ { role: "assistant", content: response.content }
258
+ ];
259
+ await safeHook(this.hooks.onResponse, finalResponse, usage);
260
+ return {
261
+ response: finalResponse,
262
+ history: updatedHistory,
263
+ usage,
264
+ thinking: allThinking || undefined,
265
+ iterationsUsed
266
+ };
267
+ } catch (error) {
268
+ const err = error instanceof Error ? error : new Error(String(error));
269
+ await safeHook(this.hooks.onError, err);
270
+ throw err;
271
+ }
272
+ }
273
+ async* chatStream(userMessage, conversationHistory = []) {
274
+ const usage = emptyUsage();
275
+ let iterationsUsed = 0;
276
+ let allThinking = "";
277
+ let finalResponse = "";
278
+ const systemPrompt = this.buildSystemPrompt();
279
+ const allTools = this.buildTools();
280
+ const maxTokens = this.getMaxTokens();
281
+ const thinkingParam = this.getThinkingParam();
282
+ const messages = [
283
+ ...conversationHistory,
284
+ { role: "user", content: userMessage }
285
+ ];
286
+ await safeHook(this.hooks.onRequest, userMessage, conversationHistory);
287
+ try {
288
+ let stopReason = null;
289
+ do {
290
+ await safeHook(this.hooks.onApiCall, {
291
+ model: this.model,
292
+ messages,
293
+ tools: allTools
294
+ });
295
+ const stream = this.anthropic.messages.stream({
296
+ model: this.model,
297
+ max_tokens: maxTokens,
298
+ system: systemPrompt,
299
+ tools: allTools,
300
+ messages,
301
+ ...thinkingParam
302
+ });
303
+ for await (const event of stream) {
304
+ if (event.type === "content_block_delta") {
305
+ const delta = event.delta;
306
+ if (delta.type === "text_delta") {
307
+ yield { type: "text", text: delta.text };
308
+ } else if (delta.type === "thinking_delta") {
309
+ yield { type: "thinking", text: delta.thinking };
310
+ }
311
+ }
312
+ }
313
+ const response = await stream.finalMessage();
314
+ accumulateUsage(usage, response.usage, this.pricing);
315
+ stopReason = response.stop_reason;
316
+ const content = extractContent(response);
317
+ if (content.thinking) {
318
+ allThinking += (allThinking ? `
319
+ ` : "") + content.thinking;
320
+ }
321
+ if (content.text) {
322
+ finalResponse = content.text;
323
+ }
324
+ if (stopReason === "tool_use") {
325
+ iterationsUsed++;
326
+ if (iterationsUsed > this.maxIterations) {
327
+ const err = new Error(`Agent exceeded maximum iterations (${this.maxIterations})`);
328
+ await safeHook(this.hooks.onError, err);
329
+ break;
330
+ }
331
+ messages.push({
332
+ role: "assistant",
333
+ content: response.content
334
+ });
335
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
336
+ const toolResults = [];
337
+ for (const toolUse of toolUseBlocks) {
338
+ const input = toolUse.input;
339
+ yield { type: "tool_call", name: toolUse.name, input };
340
+ const result = await this.executeTool(toolUse.name, input);
341
+ yield {
61
342
  type: "tool_result",
62
- tool_use_id: toolUse.id,
63
- content: JSON.stringify(result, null, 2)
64
- });
65
- } catch (error) {
343
+ name: toolUse.name,
344
+ result: result.content,
345
+ isError: result.isError
346
+ };
66
347
  toolResults.push({
67
348
  type: "tool_result",
68
349
  tool_use_id: toolUse.id,
69
- content: `Error: ${error instanceof Error ? error.message : String(error)}`,
70
- is_error: true
350
+ content: result.content,
351
+ ...result.isError ? { is_error: true } : {}
71
352
  });
72
353
  }
354
+ messages.push({ role: "user", content: toolResults });
355
+ } else {
356
+ messages.push({
357
+ role: "assistant",
358
+ content: response.content
359
+ });
73
360
  }
74
- }
75
- messages.push({ role: "assistant", content: assistantMessages.slice() });
76
- messages.push({ role: "user", content: toolResults });
77
- assistantMessages.length = 0;
78
- response = await this.anthropic.messages.create({
79
- model: this.model,
80
- max_tokens: 4096,
81
- system: systemPrompt,
82
- tools: [SHOPIFY_GRAPHQL_TOOL],
83
- messages
84
- });
361
+ } while (stopReason === "tool_use");
362
+ await safeHook(this.hooks.onResponse, finalResponse, usage);
363
+ yield {
364
+ type: "done",
365
+ response: finalResponse,
366
+ thinking: allThinking || undefined,
367
+ usage,
368
+ iterationsUsed,
369
+ history: messages
370
+ };
371
+ } catch (error) {
372
+ const err = error instanceof Error ? error : new Error(String(error));
373
+ await safeHook(this.hooks.onError, err);
374
+ throw err;
85
375
  }
86
- const textBlocks = response.content.filter((block) => block.type === "text");
87
- const finalResponse = textBlocks.map((b) => b.text).join(`
88
- `);
89
- const updatedHistory = [
90
- ...messages,
91
- { role: "assistant", content: response.content }
92
- ];
93
- return { response: finalResponse, history: updatedHistory };
376
+ }
377
+ async chatWithMemory(sessionId, userMessage) {
378
+ if (!this.memory) {
379
+ throw new Error("chatWithMemory requires a MemoryStore. Pass `memory` in AgentConfig.");
380
+ }
381
+ const history = await this.memory.load(sessionId);
382
+ const result = await this.chat(userMessage, history);
383
+ await this.memory.save(sessionId, result.history);
384
+ return result;
94
385
  }
95
386
  }
96
387
  export {
97
- ShopifyAgent
388
+ ShopifyAgent,
389
+ DEFAULT_SYSTEM_INSTRUCTION
98
390
  };
99
-
package/dist/auth.js CHANGED
@@ -54,4 +54,3 @@ export {
54
54
  getAccessToken,
55
55
  createAuthenticatedConfig
56
56
  };
57
-
package/dist/index.d.ts CHANGED
@@ -35,7 +35,10 @@
35
35
  */
36
36
  export { ShopifyClient, createShopifyClient } from "./shopify";
37
37
  export { createAuthenticatedConfig, getAccessToken, type AccessTokenResponse, type ClientCredentialsConfig, } from "./auth";
38
- export { ShopifyAgent } from "./agent";
38
+ export { ShopifyAgent, DEFAULT_SYSTEM_INSTRUCTION } from "./agent";
39
+ export type { AgentConfig, AgentHooks, AgentPlugin, ChatResult, ModelPricing, StreamEvent, ThinkingConfig, TokenUsage, } from "./agent";
40
+ export { InMemoryStore } from "./memory";
41
+ export type { MemoryStore } from "./memory";
39
42
  export { loadSkills } from "./skills";
40
43
  export type { ShopifyClientConfig, GraphQLResponse } from "./shopify";
41
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAG/D,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAG/D,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,GAC7B,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AACnE,YAAY,EACV,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,UAAU,GACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}