@clawpify/skills 1.0.4 → 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 +139 -9
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +341 -49
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +358 -50
- package/dist/mcp-server.js +1 -1
- package/dist/memory.d.ts +26 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +17 -0
- package/dist/shopify.d.ts +1 -1
- package/dist/shopify.js +1 -1
- package/package.json +8 -2
- package/src/agent.test.ts +927 -0
- package/src/agent.ts +608 -68
- package/src/index.ts +15 -1
- package/src/memory.ts +38 -0
- package/src/shopify.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ class ShopifyClient {
|
|
|
6
6
|
constructor(config) {
|
|
7
7
|
this.storeUrl = config.storeUrl.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
8
8
|
this.accessToken = config.accessToken;
|
|
9
|
-
this.apiVersion = config.apiVersion ?? "2026-
|
|
9
|
+
this.apiVersion = config.apiVersion ?? "2026-04";
|
|
10
10
|
}
|
|
11
11
|
async graphql(query, variables) {
|
|
12
12
|
const url = `https://${this.storeUrl}/admin/api/${this.apiVersion}/graphql.json`;
|
|
@@ -89,6 +89,7 @@ async function createAuthenticatedConfig() {
|
|
|
89
89
|
|
|
90
90
|
// src/agent.ts
|
|
91
91
|
import Anthropic from "@anthropic-ai/sdk";
|
|
92
|
+
var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
|
|
92
93
|
var SHOPIFY_GRAPHQL_TOOL = {
|
|
93
94
|
name: "shopify_graphql",
|
|
94
95
|
description: "Execute a GraphQL query against the Shopify Admin API. Use this to interact with products, orders, customers, inventory, and other Shopify resources.",
|
|
@@ -107,79 +108,384 @@ var SHOPIFY_GRAPHQL_TOOL = {
|
|
|
107
108
|
required: ["query"]
|
|
108
109
|
}
|
|
109
110
|
};
|
|
111
|
+
var DEFAULT_PRICING = {
|
|
112
|
+
inputPerMillion: 3,
|
|
113
|
+
outputPerMillion: 15,
|
|
114
|
+
cacheWritePerMillion: 3.75,
|
|
115
|
+
cacheReadPerMillion: 0.3
|
|
116
|
+
};
|
|
117
|
+
var DEFAULT_MAX_ITERATIONS = 20;
|
|
118
|
+
async function safeHook(hook, ...args) {
|
|
119
|
+
if (!hook)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
await hook(...args);
|
|
123
|
+
} catch {}
|
|
124
|
+
}
|
|
125
|
+
function computeCost(usage, pricing) {
|
|
126
|
+
return usage.inputTokens * pricing.inputPerMillion / 1e6 + usage.outputTokens * pricing.outputPerMillion / 1e6 + usage.cacheCreationInputTokens * pricing.cacheWritePerMillion / 1e6 + usage.cacheReadInputTokens * pricing.cacheReadPerMillion / 1e6;
|
|
127
|
+
}
|
|
128
|
+
function emptyUsage() {
|
|
129
|
+
return {
|
|
130
|
+
inputTokens: 0,
|
|
131
|
+
outputTokens: 0,
|
|
132
|
+
cacheCreationInputTokens: 0,
|
|
133
|
+
cacheReadInputTokens: 0,
|
|
134
|
+
totalCost: 0
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function accumulateUsage(total, raw, pricing) {
|
|
138
|
+
total.inputTokens += raw.input_tokens;
|
|
139
|
+
total.outputTokens += raw.output_tokens;
|
|
140
|
+
total.cacheCreationInputTokens += raw.cache_creation_input_tokens ?? 0;
|
|
141
|
+
total.cacheReadInputTokens += raw.cache_read_input_tokens ?? 0;
|
|
142
|
+
total.totalCost = computeCost(total, pricing);
|
|
143
|
+
}
|
|
144
|
+
function extractContent(response) {
|
|
145
|
+
let text = "";
|
|
146
|
+
let thinking = "";
|
|
147
|
+
for (const block of response.content) {
|
|
148
|
+
if (block.type === "text") {
|
|
149
|
+
text += (text ? `
|
|
150
|
+
` : "") + block.text;
|
|
151
|
+
} else if (block.type === "thinking") {
|
|
152
|
+
thinking += (thinking ? `
|
|
153
|
+
` : "") + block.thinking;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { text, thinking };
|
|
157
|
+
}
|
|
110
158
|
|
|
111
159
|
class ShopifyAgent {
|
|
112
160
|
anthropic;
|
|
113
161
|
shopify;
|
|
114
162
|
skillContent;
|
|
163
|
+
systemInstruction;
|
|
115
164
|
model;
|
|
165
|
+
pricing;
|
|
166
|
+
plugins = new Map;
|
|
167
|
+
hooks;
|
|
168
|
+
thinkingConfig;
|
|
169
|
+
maxIterations;
|
|
170
|
+
memory;
|
|
116
171
|
constructor(config) {
|
|
117
172
|
this.anthropic = new Anthropic;
|
|
118
173
|
this.shopify = config.shopify;
|
|
119
174
|
this.skillContent = config.skillContent;
|
|
175
|
+
this.systemInstruction = config.systemInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
|
|
120
176
|
this.model = config.model ?? "claude-sonnet-4-5";
|
|
177
|
+
this.pricing = config.pricing ?? DEFAULT_PRICING;
|
|
178
|
+
this.hooks = config.hooks ?? {};
|
|
179
|
+
this.thinkingConfig = config.thinking;
|
|
180
|
+
this.maxIterations = config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
181
|
+
this.memory = config.memory;
|
|
182
|
+
if (config.plugins) {
|
|
183
|
+
for (const plugin of config.plugins) {
|
|
184
|
+
this.registerPlugin(plugin);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
registerPlugin(plugin) {
|
|
189
|
+
const name = plugin.tool.name;
|
|
190
|
+
if (name === "shopify_graphql") {
|
|
191
|
+
throw new Error(`Cannot register plugin with reserved tool name "shopify_graphql"`);
|
|
192
|
+
}
|
|
193
|
+
if (this.plugins.has(name)) {
|
|
194
|
+
throw new Error(`Plugin with tool name "${name}" is already registered`);
|
|
195
|
+
}
|
|
196
|
+
this.plugins.set(name, plugin);
|
|
197
|
+
}
|
|
198
|
+
buildSystemPrompt() {
|
|
199
|
+
return [
|
|
200
|
+
{ type: "text", text: this.systemInstruction },
|
|
201
|
+
{
|
|
202
|
+
type: "text",
|
|
203
|
+
text: this.skillContent,
|
|
204
|
+
cache_control: { type: "ephemeral" }
|
|
205
|
+
}
|
|
206
|
+
];
|
|
207
|
+
}
|
|
208
|
+
buildTools() {
|
|
209
|
+
const allTools = [
|
|
210
|
+
SHOPIFY_GRAPHQL_TOOL,
|
|
211
|
+
...[...this.plugins.values()].map((p) => p.tool)
|
|
212
|
+
];
|
|
213
|
+
if (allTools.length > 0) {
|
|
214
|
+
const last = allTools[allTools.length - 1];
|
|
215
|
+
allTools[allTools.length - 1] = Object.assign({}, last, {
|
|
216
|
+
cache_control: { type: "ephemeral" }
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return allTools;
|
|
220
|
+
}
|
|
221
|
+
getMaxTokens() {
|
|
222
|
+
return this.thinkingConfig ? this.thinkingConfig.budgetTokens + 4096 : 4096;
|
|
223
|
+
}
|
|
224
|
+
getThinkingParam() {
|
|
225
|
+
if (!this.thinkingConfig)
|
|
226
|
+
return {};
|
|
227
|
+
return {
|
|
228
|
+
thinking: {
|
|
229
|
+
type: "enabled",
|
|
230
|
+
budget_tokens: this.thinkingConfig.budgetTokens
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
async executeTool(name, input) {
|
|
235
|
+
await safeHook(this.hooks.onToolCall, name, input);
|
|
236
|
+
if (name === "shopify_graphql") {
|
|
237
|
+
try {
|
|
238
|
+
const result = await this.shopify.graphql(input.query, input.variables);
|
|
239
|
+
const content2 = JSON.stringify(result, null, 2);
|
|
240
|
+
await safeHook(this.hooks.onToolResult, name, content2, false);
|
|
241
|
+
return { content: content2, isError: false };
|
|
242
|
+
} catch (error) {
|
|
243
|
+
const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
244
|
+
await safeHook(this.hooks.onToolResult, name, content2, true);
|
|
245
|
+
return { content: content2, isError: true };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (this.plugins.has(name)) {
|
|
249
|
+
const plugin = this.plugins.get(name);
|
|
250
|
+
try {
|
|
251
|
+
const content2 = await plugin.handler(input);
|
|
252
|
+
await safeHook(this.hooks.onToolResult, name, content2, false);
|
|
253
|
+
return { content: content2, isError: false };
|
|
254
|
+
} catch (error) {
|
|
255
|
+
const content2 = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
256
|
+
await safeHook(this.hooks.onToolResult, name, content2, true);
|
|
257
|
+
return { content: content2, isError: true };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const content = `Error: Unknown tool "${name}"`;
|
|
261
|
+
await safeHook(this.hooks.onToolResult, name, content, true);
|
|
262
|
+
return { content, isError: true };
|
|
263
|
+
}
|
|
264
|
+
async processToolCalls(response) {
|
|
265
|
+
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
266
|
+
const toolResults = [];
|
|
267
|
+
for (const toolUse of toolUseBlocks) {
|
|
268
|
+
const input = toolUse.input;
|
|
269
|
+
const { content, isError } = await this.executeTool(toolUse.name, input);
|
|
270
|
+
toolResults.push({
|
|
271
|
+
type: "tool_result",
|
|
272
|
+
tool_use_id: toolUse.id,
|
|
273
|
+
content,
|
|
274
|
+
...isError ? { is_error: true } : {}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return toolResults;
|
|
121
278
|
}
|
|
122
279
|
async chat(userMessage, conversationHistory = []) {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
280
|
+
const usage = emptyUsage();
|
|
281
|
+
let iterationsUsed = 0;
|
|
282
|
+
let allThinking = "";
|
|
283
|
+
const systemPrompt = this.buildSystemPrompt();
|
|
284
|
+
const allTools = this.buildTools();
|
|
285
|
+
const maxTokens = this.getMaxTokens();
|
|
286
|
+
const thinkingParam = this.getThinkingParam();
|
|
128
287
|
const messages = [
|
|
129
288
|
...conversationHistory,
|
|
130
289
|
{ role: "user", content: userMessage }
|
|
131
290
|
];
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
291
|
+
await safeHook(this.hooks.onRequest, userMessage, conversationHistory);
|
|
292
|
+
try {
|
|
293
|
+
await safeHook(this.hooks.onApiCall, {
|
|
294
|
+
model: this.model,
|
|
295
|
+
messages,
|
|
296
|
+
tools: allTools
|
|
297
|
+
});
|
|
298
|
+
let response = await this.anthropic.messages.create({
|
|
299
|
+
model: this.model,
|
|
300
|
+
max_tokens: maxTokens,
|
|
301
|
+
system: systemPrompt,
|
|
302
|
+
tools: allTools,
|
|
303
|
+
messages,
|
|
304
|
+
...thinkingParam
|
|
305
|
+
});
|
|
306
|
+
accumulateUsage(usage, response.usage, this.pricing);
|
|
307
|
+
const firstContent = extractContent(response);
|
|
308
|
+
if (firstContent.thinking)
|
|
309
|
+
allThinking += firstContent.thinking;
|
|
310
|
+
while (response.stop_reason === "tool_use") {
|
|
311
|
+
iterationsUsed++;
|
|
312
|
+
if (iterationsUsed > this.maxIterations) {
|
|
313
|
+
const err = new Error(`Agent exceeded maximum iterations (${this.maxIterations})`);
|
|
314
|
+
await safeHook(this.hooks.onError, err);
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
messages.push({
|
|
318
|
+
role: "assistant",
|
|
319
|
+
content: response.content
|
|
320
|
+
});
|
|
321
|
+
const toolResults = await this.processToolCalls(response);
|
|
322
|
+
messages.push({ role: "user", content: toolResults });
|
|
323
|
+
await safeHook(this.hooks.onApiCall, {
|
|
324
|
+
model: this.model,
|
|
325
|
+
messages,
|
|
326
|
+
tools: allTools
|
|
327
|
+
});
|
|
328
|
+
response = await this.anthropic.messages.create({
|
|
329
|
+
model: this.model,
|
|
330
|
+
max_tokens: maxTokens,
|
|
331
|
+
system: systemPrompt,
|
|
332
|
+
tools: allTools,
|
|
333
|
+
messages,
|
|
334
|
+
...thinkingParam
|
|
335
|
+
});
|
|
336
|
+
accumulateUsage(usage, response.usage, this.pricing);
|
|
337
|
+
const loopContent = extractContent(response);
|
|
338
|
+
if (loopContent.thinking) {
|
|
339
|
+
allThinking += (allThinking ? `
|
|
340
|
+
` : "") + loopContent.thinking;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const { text: finalResponse } = extractContent(response);
|
|
344
|
+
const updatedHistory = [
|
|
345
|
+
...messages,
|
|
346
|
+
{ role: "assistant", content: response.content }
|
|
347
|
+
];
|
|
348
|
+
await safeHook(this.hooks.onResponse, finalResponse, usage);
|
|
349
|
+
return {
|
|
350
|
+
response: finalResponse,
|
|
351
|
+
history: updatedHistory,
|
|
352
|
+
usage,
|
|
353
|
+
thinking: allThinking || undefined,
|
|
354
|
+
iterationsUsed
|
|
355
|
+
};
|
|
356
|
+
} catch (error) {
|
|
357
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
358
|
+
await safeHook(this.hooks.onError, err);
|
|
359
|
+
throw err;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async* chatStream(userMessage, conversationHistory = []) {
|
|
363
|
+
const usage = emptyUsage();
|
|
364
|
+
let iterationsUsed = 0;
|
|
365
|
+
let allThinking = "";
|
|
366
|
+
let finalResponse = "";
|
|
367
|
+
const systemPrompt = this.buildSystemPrompt();
|
|
368
|
+
const allTools = this.buildTools();
|
|
369
|
+
const maxTokens = this.getMaxTokens();
|
|
370
|
+
const thinkingParam = this.getThinkingParam();
|
|
371
|
+
const messages = [
|
|
372
|
+
...conversationHistory,
|
|
373
|
+
{ role: "user", content: userMessage }
|
|
374
|
+
];
|
|
375
|
+
await safeHook(this.hooks.onRequest, userMessage, conversationHistory);
|
|
376
|
+
try {
|
|
377
|
+
let stopReason = null;
|
|
378
|
+
do {
|
|
379
|
+
await safeHook(this.hooks.onApiCall, {
|
|
380
|
+
model: this.model,
|
|
381
|
+
messages,
|
|
382
|
+
tools: allTools
|
|
383
|
+
});
|
|
384
|
+
const stream = this.anthropic.messages.stream({
|
|
385
|
+
model: this.model,
|
|
386
|
+
max_tokens: maxTokens,
|
|
387
|
+
system: systemPrompt,
|
|
388
|
+
tools: allTools,
|
|
389
|
+
messages,
|
|
390
|
+
...thinkingParam
|
|
391
|
+
});
|
|
392
|
+
for await (const event of stream) {
|
|
393
|
+
if (event.type === "content_block_delta") {
|
|
394
|
+
const delta = event.delta;
|
|
395
|
+
if (delta.type === "text_delta") {
|
|
396
|
+
yield { type: "text", text: delta.text };
|
|
397
|
+
} else if (delta.type === "thinking_delta") {
|
|
398
|
+
yield { type: "thinking", text: delta.thinking };
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const response = await stream.finalMessage();
|
|
403
|
+
accumulateUsage(usage, response.usage, this.pricing);
|
|
404
|
+
stopReason = response.stop_reason;
|
|
405
|
+
const content = extractContent(response);
|
|
406
|
+
if (content.thinking) {
|
|
407
|
+
allThinking += (allThinking ? `
|
|
408
|
+
` : "") + content.thinking;
|
|
409
|
+
}
|
|
410
|
+
if (content.text) {
|
|
411
|
+
finalResponse = content.text;
|
|
412
|
+
}
|
|
413
|
+
if (stopReason === "tool_use") {
|
|
414
|
+
iterationsUsed++;
|
|
415
|
+
if (iterationsUsed > this.maxIterations) {
|
|
416
|
+
const err = new Error(`Agent exceeded maximum iterations (${this.maxIterations})`);
|
|
417
|
+
await safeHook(this.hooks.onError, err);
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
messages.push({
|
|
421
|
+
role: "assistant",
|
|
422
|
+
content: response.content
|
|
423
|
+
});
|
|
424
|
+
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
425
|
+
const toolResults = [];
|
|
426
|
+
for (const toolUse of toolUseBlocks) {
|
|
427
|
+
const input = toolUse.input;
|
|
428
|
+
yield { type: "tool_call", name: toolUse.name, input };
|
|
429
|
+
const result = await this.executeTool(toolUse.name, input);
|
|
430
|
+
yield {
|
|
150
431
|
type: "tool_result",
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
432
|
+
name: toolUse.name,
|
|
433
|
+
result: result.content,
|
|
434
|
+
isError: result.isError
|
|
435
|
+
};
|
|
155
436
|
toolResults.push({
|
|
156
437
|
type: "tool_result",
|
|
157
438
|
tool_use_id: toolUse.id,
|
|
158
|
-
content:
|
|
159
|
-
is_error: true
|
|
439
|
+
content: result.content,
|
|
440
|
+
...result.isError ? { is_error: true } : {}
|
|
160
441
|
});
|
|
161
442
|
}
|
|
443
|
+
messages.push({ role: "user", content: toolResults });
|
|
444
|
+
} else {
|
|
445
|
+
messages.push({
|
|
446
|
+
role: "assistant",
|
|
447
|
+
content: response.content
|
|
448
|
+
});
|
|
162
449
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
450
|
+
} while (stopReason === "tool_use");
|
|
451
|
+
await safeHook(this.hooks.onResponse, finalResponse, usage);
|
|
452
|
+
yield {
|
|
453
|
+
type: "done",
|
|
454
|
+
response: finalResponse,
|
|
455
|
+
thinking: allThinking || undefined,
|
|
456
|
+
usage,
|
|
457
|
+
iterationsUsed,
|
|
458
|
+
history: messages
|
|
459
|
+
};
|
|
460
|
+
} catch (error) {
|
|
461
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
462
|
+
await safeHook(this.hooks.onError, err);
|
|
463
|
+
throw err;
|
|
174
464
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
465
|
+
}
|
|
466
|
+
async chatWithMemory(sessionId, userMessage) {
|
|
467
|
+
if (!this.memory) {
|
|
468
|
+
throw new Error("chatWithMemory requires a MemoryStore. Pass `memory` in AgentConfig.");
|
|
469
|
+
}
|
|
470
|
+
const history = await this.memory.load(sessionId);
|
|
471
|
+
const result = await this.chat(userMessage, history);
|
|
472
|
+
await this.memory.save(sessionId, result.history);
|
|
473
|
+
return result;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/memory.ts
|
|
478
|
+
class InMemoryStore {
|
|
479
|
+
store = new Map;
|
|
480
|
+
async save(sessionId, history) {
|
|
481
|
+
this.store.set(sessionId, structuredClone(history));
|
|
482
|
+
}
|
|
483
|
+
async load(sessionId) {
|
|
484
|
+
const data = this.store.get(sessionId);
|
|
485
|
+
return data ? structuredClone(data) : [];
|
|
486
|
+
}
|
|
487
|
+
async clear(sessionId) {
|
|
488
|
+
this.store.delete(sessionId);
|
|
183
489
|
}
|
|
184
490
|
}
|
|
185
491
|
|
|
@@ -220,5 +526,7 @@ export {
|
|
|
220
526
|
createShopifyClient,
|
|
221
527
|
createAuthenticatedConfig,
|
|
222
528
|
ShopifyClient,
|
|
223
|
-
ShopifyAgent
|
|
529
|
+
ShopifyAgent,
|
|
530
|
+
InMemoryStore,
|
|
531
|
+
DEFAULT_SYSTEM_INSTRUCTION
|
|
224
532
|
};
|
package/dist/mcp-server.js
CHANGED
|
@@ -8,7 +8,7 @@ class ShopifyClient {
|
|
|
8
8
|
constructor(config) {
|
|
9
9
|
this.storeUrl = config.storeUrl.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
10
10
|
this.accessToken = config.accessToken;
|
|
11
|
-
this.apiVersion = config.apiVersion ?? "2026-
|
|
11
|
+
this.apiVersion = config.apiVersion ?? "2026-04";
|
|
12
12
|
}
|
|
13
13
|
async graphql(query, variables) {
|
|
14
14
|
const url = `https://${this.storeUrl}/admin/api/${this.apiVersion}/graphql.json`;
|
package/dist/memory.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for persisting conversation history across sessions.
|
|
3
|
+
* Implement this interface to plug in any storage backend (Redis, SQLite, etc.).
|
|
4
|
+
*
|
|
5
|
+
* History is stored as raw MessageParam arrays — the same type the agent
|
|
6
|
+
* accepts and returns — so round-tripping is lossless.
|
|
7
|
+
*/
|
|
8
|
+
export interface MemoryStore {
|
|
9
|
+
/** Save conversation history for a session. */
|
|
10
|
+
save(sessionId: string, history: any[]): Promise<void>;
|
|
11
|
+
/** Load conversation history for a session. Returns empty array if not found. */
|
|
12
|
+
load(sessionId: string): Promise<any[]>;
|
|
13
|
+
/** Clear conversation history for a session. */
|
|
14
|
+
clear(sessionId: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Simple in-memory implementation of MemoryStore.
|
|
18
|
+
* Data is lost when the process restarts — use for dev/testing only.
|
|
19
|
+
*/
|
|
20
|
+
export declare class InMemoryStore implements MemoryStore {
|
|
21
|
+
private store;
|
|
22
|
+
save(sessionId: string, history: any[]): Promise<void>;
|
|
23
|
+
load(sessionId: string): Promise<any[]>;
|
|
24
|
+
clear(sessionId: string): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD,iFAAiF;IACjF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAExC,gDAAgD;IAChD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED;;;GAGG;AACH,qBAAa,aAAc,YAAW,WAAW;IAC/C,OAAO,CAAC,KAAK,CAA4B;IAEnC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAKvC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
|
package/dist/memory.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/memory.ts
|
|
2
|
+
class InMemoryStore {
|
|
3
|
+
store = new Map;
|
|
4
|
+
async save(sessionId, history) {
|
|
5
|
+
this.store.set(sessionId, structuredClone(history));
|
|
6
|
+
}
|
|
7
|
+
async load(sessionId) {
|
|
8
|
+
const data = this.store.get(sessionId);
|
|
9
|
+
return data ? structuredClone(data) : [];
|
|
10
|
+
}
|
|
11
|
+
async clear(sessionId) {
|
|
12
|
+
this.store.delete(sessionId);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
InMemoryStore
|
|
17
|
+
};
|
package/dist/shopify.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export interface ShopifyClientConfig {
|
|
|
3
3
|
storeUrl: string;
|
|
4
4
|
/** Admin API access token */
|
|
5
5
|
accessToken: string;
|
|
6
|
-
/** API version (defaults to "2026-
|
|
6
|
+
/** API version (defaults to "2026-04") */
|
|
7
7
|
apiVersion?: string;
|
|
8
8
|
}
|
|
9
9
|
export interface GraphQLResponse<T = any> {
|
package/dist/shopify.js
CHANGED
|
@@ -6,7 +6,7 @@ class ShopifyClient {
|
|
|
6
6
|
constructor(config) {
|
|
7
7
|
this.storeUrl = config.storeUrl.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
8
8
|
this.accessToken = config.accessToken;
|
|
9
|
-
this.apiVersion = config.apiVersion ?? "2026-
|
|
9
|
+
this.apiVersion = config.apiVersion ?? "2026-04";
|
|
10
10
|
}
|
|
11
11
|
async graphql(query, variables) {
|
|
12
12
|
const url = `https://${this.storeUrl}/admin/api/${this.apiVersion}/graphql.json`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawpify/skills",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Shopify Agent SDK — query and manage Shopify stores via GraphQL Admin API with AI agents and MCP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,6 +35,12 @@
|
|
|
35
35
|
"bun": "./src/skills.ts",
|
|
36
36
|
"import": "./dist/skills.js",
|
|
37
37
|
"default": "./dist/skills.js"
|
|
38
|
+
},
|
|
39
|
+
"./memory": {
|
|
40
|
+
"types": "./dist/memory.d.ts",
|
|
41
|
+
"bun": "./src/memory.ts",
|
|
42
|
+
"import": "./dist/memory.js",
|
|
43
|
+
"default": "./dist/memory.js"
|
|
38
44
|
}
|
|
39
45
|
},
|
|
40
46
|
"bin": {
|
|
@@ -46,7 +52,7 @@
|
|
|
46
52
|
"clawpify"
|
|
47
53
|
],
|
|
48
54
|
"scripts": {
|
|
49
|
-
"build": "rm -rf dist && bun build ./src/index.ts ./src/agent.ts ./src/shopify.ts ./src/auth.ts ./src/skills.ts ./src/mcp-server.ts --outdir ./dist --target node --format esm --external @anthropic-ai/sdk --external @modelcontextprotocol/sdk && tsc -p tsconfig.build.json",
|
|
55
|
+
"build": "rm -rf dist && bun build ./src/index.ts ./src/agent.ts ./src/shopify.ts ./src/auth.ts ./src/skills.ts ./src/memory.ts ./src/mcp-server.ts --outdir ./dist --target node --format esm --external @anthropic-ai/sdk --external @modelcontextprotocol/sdk && tsc -p tsconfig.build.json",
|
|
50
56
|
"prepublishOnly": "bun run build",
|
|
51
57
|
"start": "bun run examples/server.ts"
|
|
52
58
|
},
|