@clawpify/skills 1.0.7 → 1.0.9

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
@@ -46,13 +46,25 @@ export interface ThinkingConfig {
46
46
  /** Token budget for thinking. Must be >= 1024. */
47
47
  budgetTokens: number;
48
48
  }
49
+ /** Structured context for prompt assembly. Used when systemInstruction is not provided. */
50
+ export interface AgentContextConfig {
51
+ /** Heartbeat content (only for new sessions). Injected at prompt start. */
52
+ heartbeatContent?: string;
53
+ /** Long-term memory content. Always included. */
54
+ memoryContent?: string;
55
+ /** Base system instruction override. Falls back to DEFAULT_SYSTEM_INSTRUCTION. */
56
+ baseInstruction?: string;
57
+ }
49
58
  /** Full configuration accepted by the ShopifyAgent constructor. */
50
59
  export interface AgentConfig {
51
60
  shopify: ShopifyClient;
52
61
  skillContent: string;
53
62
  model?: string;
54
- /** Override the default system instruction sent to the model. */
63
+ /** Override the default system instruction sent to the model (raw string). */
55
64
  systemInstruction?: string;
65
+ /** Structured context assembled into a system instruction internally.
66
+ * Ignored when systemInstruction is provided. */
67
+ context?: AgentContextConfig;
56
68
  /** Override default Claude Sonnet pricing. */
57
69
  pricing?: ModelPricing;
58
70
  /** Register plugins at construction time. */
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/agent.js CHANGED
@@ -48,6 +48,19 @@ async function collectMarkdown(dir, parts) {
48
48
 
49
49
  // src/agent.ts
50
50
  import Anthropic from "@anthropic-ai/sdk";
51
+
52
+ // src/prompt-utils.ts
53
+ var MAX_HEARTBEAT_CHARS = 2000;
54
+ var MAX_MEMORY_CHARS = 4000;
55
+ function clampContent(content, maxChars) {
56
+ const trimmed = content.trim();
57
+ if (trimmed.length <= maxChars)
58
+ return trimmed;
59
+ return trimmed.slice(0, maxChars).trimEnd() + `
60
+ ...[truncated]`;
61
+ }
62
+
63
+ // src/agent.ts
51
64
  var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
52
65
  var SHOPIFY_GRAPHQL_TOOL = {
53
66
  name: "shopify_graphql",
@@ -128,6 +141,29 @@ function extractContent(response) {
128
141
  }
129
142
  return { text, thinking };
130
143
  }
144
+ function buildSystemInstruction(ctx) {
145
+ const base = ctx.baseInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
146
+ let heartbeatBlock = "";
147
+ if (ctx.heartbeatContent?.trim()) {
148
+ heartbeatBlock = `
149
+
150
+ This is a NEW conversation (no recent chat history). ` + "Follow these instructions first, then respond to the merchant's message. " + `Keep the summary brief (1-2 sentences), then address what they asked.
151
+
152
+ ---
153
+ ` + clampContent(ctx.heartbeatContent, MAX_HEARTBEAT_CHARS) + `
154
+ ---`;
155
+ }
156
+ let memoryBlock = "";
157
+ if (ctx.memoryContent?.trim()) {
158
+ memoryBlock = `
159
+
160
+ Things to remember about this merchant/store ` + `(use this context in your responses):
161
+ ---
162
+ ` + clampContent(ctx.memoryContent, MAX_MEMORY_CHARS) + `
163
+ ---`;
164
+ }
165
+ return base + heartbeatBlock + memoryBlock;
166
+ }
131
167
 
132
168
  class ShopifyAgent {
133
169
  anthropic;
@@ -145,7 +181,13 @@ class ShopifyAgent {
145
181
  this.anthropic = new Anthropic;
146
182
  this.shopify = config.shopify;
147
183
  this.skillContent = config.skillContent;
148
- this.systemInstruction = config.systemInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
184
+ if (config.systemInstruction != null) {
185
+ this.systemInstruction = config.systemInstruction;
186
+ } else if (config.context) {
187
+ this.systemInstruction = buildSystemInstruction(config.context);
188
+ } else {
189
+ this.systemInstruction = DEFAULT_SYSTEM_INSTRUCTION;
190
+ }
149
191
  this.model = config.model ?? "claude-sonnet-4-5";
150
192
  this.pricing = config.pricing ?? DEFAULT_PRICING;
151
193
  this.hooks = config.hooks ?? {};
package/dist/index.d.ts CHANGED
@@ -36,9 +36,10 @@
36
36
  export { ShopifyClient, createShopifyClient } from "./shopify";
37
37
  export { createAuthenticatedConfig, getAccessToken, type AccessTokenResponse, type ClientCredentialsConfig, } from "./auth";
38
38
  export { ShopifyAgent, DEFAULT_SYSTEM_INSTRUCTION } from "./agent";
39
- export type { AgentConfig, AgentHooks, AgentPlugin, ChatResult, ModelPricing, StreamEvent, ThinkingConfig, TokenUsage, } from "./agent";
39
+ export type { AgentConfig, AgentContextConfig, AgentHooks, AgentPlugin, ChatResult, ModelPricing, StreamEvent, ThinkingConfig, TokenUsage, } from "./agent";
40
40
  export { InMemoryStore } from "./memory";
41
- export type { MemoryStore } from "./memory";
41
+ export type { MemoryStore, LoadResult } from "./memory";
42
+ export { clampContent, MAX_HEARTBEAT_CHARS, MAX_MEMORY_CHARS } from "./prompt-utils";
42
43
  export { loadSkills, loadSkillMetadata, loadSkillReference, listSkillReferences, } from "./skills";
43
44
  export type { ShopifyClientConfig, GraphQLResponse } from "./shopify";
44
45
  //# 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,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,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAGlB,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,kBAAkB,EAClB,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,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAGlB,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -137,6 +137,19 @@ async function collectMarkdown(dir, parts) {
137
137
 
138
138
  // src/agent.ts
139
139
  import Anthropic from "@anthropic-ai/sdk";
140
+
141
+ // src/prompt-utils.ts
142
+ var MAX_HEARTBEAT_CHARS = 2000;
143
+ var MAX_MEMORY_CHARS = 4000;
144
+ function clampContent(content, maxChars) {
145
+ const trimmed = content.trim();
146
+ if (trimmed.length <= maxChars)
147
+ return trimmed;
148
+ return trimmed.slice(0, maxChars).trimEnd() + `
149
+ ...[truncated]`;
150
+ }
151
+
152
+ // src/agent.ts
140
153
  var DEFAULT_SYSTEM_INSTRUCTION = "You're Clawpify. You help run a Shopify store. The merchant texts you to get stuff done";
141
154
  var SHOPIFY_GRAPHQL_TOOL = {
142
155
  name: "shopify_graphql",
@@ -217,6 +230,29 @@ function extractContent(response) {
217
230
  }
218
231
  return { text, thinking };
219
232
  }
233
+ function buildSystemInstruction(ctx) {
234
+ const base = ctx.baseInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
235
+ let heartbeatBlock = "";
236
+ if (ctx.heartbeatContent?.trim()) {
237
+ heartbeatBlock = `
238
+
239
+ This is a NEW conversation (no recent chat history). ` + "Follow these instructions first, then respond to the merchant's message. " + `Keep the summary brief (1-2 sentences), then address what they asked.
240
+
241
+ ---
242
+ ` + clampContent(ctx.heartbeatContent, MAX_HEARTBEAT_CHARS) + `
243
+ ---`;
244
+ }
245
+ let memoryBlock = "";
246
+ if (ctx.memoryContent?.trim()) {
247
+ memoryBlock = `
248
+
249
+ Things to remember about this merchant/store ` + `(use this context in your responses):
250
+ ---
251
+ ` + clampContent(ctx.memoryContent, MAX_MEMORY_CHARS) + `
252
+ ---`;
253
+ }
254
+ return base + heartbeatBlock + memoryBlock;
255
+ }
220
256
 
221
257
  class ShopifyAgent {
222
258
  anthropic;
@@ -234,7 +270,13 @@ class ShopifyAgent {
234
270
  this.anthropic = new Anthropic;
235
271
  this.shopify = config.shopify;
236
272
  this.skillContent = config.skillContent;
237
- this.systemInstruction = config.systemInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
273
+ if (config.systemInstruction != null) {
274
+ this.systemInstruction = config.systemInstruction;
275
+ } else if (config.context) {
276
+ this.systemInstruction = buildSystemInstruction(config.context);
277
+ } else {
278
+ this.systemInstruction = DEFAULT_SYSTEM_INSTRUCTION;
279
+ }
238
280
  this.model = config.model ?? "claude-sonnet-4-5";
239
281
  this.pricing = config.pricing ?? DEFAULT_PRICING;
240
282
  this.hooks = config.hooks ?? {};
@@ -561,6 +603,9 @@ class InMemoryStore {
561
603
  async clear(sessionId) {
562
604
  this.store.delete(sessionId);
563
605
  }
606
+ async loadWithStatus(sessionId) {
607
+ return { history: await this.load(sessionId), error: false };
608
+ }
564
609
  }
565
610
  export {
566
611
  loadSkills,
@@ -570,8 +615,11 @@ export {
570
615
  getAccessToken,
571
616
  createShopifyClient,
572
617
  createAuthenticatedConfig,
618
+ clampContent,
573
619
  ShopifyClient,
574
620
  ShopifyAgent,
621
+ MAX_MEMORY_CHARS,
622
+ MAX_HEARTBEAT_CHARS,
575
623
  InMemoryStore,
576
624
  DEFAULT_SYSTEM_INSTRUCTION
577
625
  };
package/dist/memory.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /** Result of loadWithStatus() — distinguishes empty history from a storage error. */
2
+ export interface LoadResult {
3
+ history: any[];
4
+ error: boolean;
5
+ }
1
6
  /**
2
7
  * Interface for persisting conversation history across sessions.
3
8
  * Implement this interface to plug in any storage backend (Redis, SQLite, etc.).
@@ -12,6 +17,8 @@ export interface MemoryStore {
12
17
  load(sessionId: string): Promise<any[]>;
13
18
  /** Clear conversation history for a session. */
14
19
  clear(sessionId: string): Promise<void>;
20
+ /** Optional: load with error status for callers that need to distinguish empty from failed. */
21
+ loadWithStatus?(sessionId: string): Promise<LoadResult>;
15
22
  }
16
23
  /**
17
24
  * Simple in-memory implementation of MemoryStore.
@@ -22,5 +29,6 @@ export declare class InMemoryStore implements MemoryStore {
22
29
  save(sessionId: string, history: any[]): Promise<void>;
23
30
  load(sessionId: string): Promise<any[]>;
24
31
  clear(sessionId: string): Promise<void>;
32
+ loadWithStatus(sessionId: string): Promise<LoadResult>;
25
33
  }
26
34
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,GAAG,EAAE,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;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;IAExC,+FAA+F;IAC/F,cAAc,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACzD;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;IAIvC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CAG7D"}
package/dist/memory.js CHANGED
@@ -11,6 +11,9 @@ class InMemoryStore {
11
11
  async clear(sessionId) {
12
12
  this.store.delete(sessionId);
13
13
  }
14
+ async loadWithStatus(sessionId) {
15
+ return { history: await this.load(sessionId), error: false };
16
+ }
14
17
  }
15
18
  export {
16
19
  InMemoryStore
@@ -0,0 +1,7 @@
1
+ /** Max characters allowed for heartbeat content to prevent context bloat. */
2
+ export declare const MAX_HEARTBEAT_CHARS = 2000;
3
+ /** Max characters allowed for memory content to prevent context bloat. */
4
+ export declare const MAX_MEMORY_CHARS = 4000;
5
+ /** Clamp content to a max character count, appending a truncation marker. */
6
+ export declare function clampContent(content: string, maxChars: number): string;
7
+ //# sourceMappingURL=prompt-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-utils.d.ts","sourceRoot":"","sources":["../src/prompt-utils.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAItE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawpify/skills",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
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",
@@ -68,9 +68,6 @@
68
68
  "model-context-protocol"
69
69
  ],
70
70
  "license": "MIT",
71
- "publishConfig": {
72
- "access": "public"
73
- },
74
71
  "repository": {
75
72
  "type": "git",
76
73
  "url": "git+https://github.com/clawpify/skills.git"
package/src/agent.test.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { describe, test, expect, mock } from "bun:test";
2
2
  import { ShopifyAgent, DEFAULT_SYSTEM_INSTRUCTION } from "./agent";
3
- import type { AgentPlugin, AgentHooks, ModelPricing } from "./agent";
3
+ import type { AgentPlugin, AgentHooks, AgentContextConfig, ModelPricing } from "./agent";
4
4
  import { ShopifyClient } from "./shopify";
5
5
  import { InMemoryStore } from "./memory";
6
6
  import type { MemoryStore } from "./memory";
7
+ import { clampContent, MAX_HEARTBEAT_CHARS, MAX_MEMORY_CHARS } from "./prompt-utils";
7
8
 
8
9
  // ---------------------------------------------------------------------------
9
10
  // Helpers — build realistic Anthropic response shapes
@@ -107,6 +108,7 @@ function createAgent(
107
108
  hooks?: AgentHooks;
108
109
  pricing?: ModelPricing;
109
110
  systemInstruction?: string;
111
+ context?: AgentContextConfig;
110
112
  thinking?: { budgetTokens: number };
111
113
  maxIterations?: number;
112
114
  memory?: MemoryStore;
@@ -924,4 +926,133 @@ describe("InMemoryStore", () => {
924
926
  const loaded = await store.load("test");
925
927
  expect(loaded[0].content).toBe("Original");
926
928
  });
929
+
930
+ test("loadWithStatus returns history and error: false", async () => {
931
+ const store = new InMemoryStore();
932
+ const history = [
933
+ { role: "user", content: "Hello" },
934
+ { role: "assistant", content: "Hi!" },
935
+ ];
936
+
937
+ await store.save("test", history);
938
+ const result = await store.loadWithStatus("test");
939
+
940
+ expect(result.error).toBe(false);
941
+ expect(result.history).toEqual(history);
942
+ });
943
+
944
+ test("loadWithStatus returns empty history for unknown session", async () => {
945
+ const store = new InMemoryStore();
946
+ const result = await store.loadWithStatus("nonexistent");
947
+
948
+ expect(result).toEqual({ history: [], error: false });
949
+ });
950
+ });
951
+
952
+ // ==========================================================================
953
+ // 11. clampContent & prompt constants
954
+ // ==========================================================================
955
+
956
+ describe("clampContent", () => {
957
+ test("returns trimmed content when under limit", () => {
958
+ expect(clampContent(" hello world ", 100)).toBe("hello world");
959
+ });
960
+
961
+ test("truncates content that exceeds maxChars", () => {
962
+ const long = "a".repeat(3000);
963
+ const result = clampContent(long, 2000);
964
+ expect(result).toContain("...[truncated]");
965
+ // The content portion should be at most maxChars
966
+ expect(result.replace("\n...[truncated]", "").length).toBeLessThanOrEqual(
967
+ 2000
968
+ );
969
+ });
970
+
971
+ test("returns exact content at the boundary", () => {
972
+ const exact = "b".repeat(2000);
973
+ expect(clampContent(exact, 2000)).toBe(exact);
974
+ });
975
+
976
+ test("constants have expected values", () => {
977
+ expect(MAX_HEARTBEAT_CHARS).toBe(2000);
978
+ expect(MAX_MEMORY_CHARS).toBe(4000);
979
+ });
980
+ });
981
+
982
+ // ==========================================================================
983
+ // 12. AgentContextConfig
984
+ // ==========================================================================
985
+
986
+ describe("AgentContextConfig", () => {
987
+ test("systemInstruction as string still works (backward compat)", () => {
988
+ const agent = createAgent({
989
+ systemInstruction: "Custom instruction",
990
+ });
991
+
992
+ const instruction = (agent as any).systemInstruction;
993
+ expect(instruction).toBe("Custom instruction");
994
+ });
995
+
996
+ test("uses DEFAULT_SYSTEM_INSTRUCTION when neither systemInstruction nor context provided", () => {
997
+ const agent = createAgent();
998
+
999
+ const instruction = (agent as any).systemInstruction;
1000
+ expect(instruction).toBe(DEFAULT_SYSTEM_INSTRUCTION);
1001
+ });
1002
+
1003
+ test("assembles prompt from context when systemInstruction is not provided", () => {
1004
+ const agent = createAgent({
1005
+ context: {
1006
+ heartbeatContent: "Check sales report",
1007
+ memoryContent: "This store sells sneakers",
1008
+ },
1009
+ });
1010
+
1011
+ const instruction: string = (agent as any).systemInstruction;
1012
+
1013
+ // Should start with the default base
1014
+ expect(instruction).toContain(DEFAULT_SYSTEM_INSTRUCTION);
1015
+ // Should include heartbeat block
1016
+ expect(instruction).toContain("NEW conversation");
1017
+ expect(instruction).toContain("Check sales report");
1018
+ // Should include memory block
1019
+ expect(instruction).toContain("Things to remember");
1020
+ expect(instruction).toContain("This store sells sneakers");
1021
+ });
1022
+
1023
+ test("systemInstruction takes precedence over context", () => {
1024
+ const agent = createAgent({
1025
+ systemInstruction: "Override wins",
1026
+ context: {
1027
+ heartbeatContent: "Should not appear",
1028
+ memoryContent: "Should not appear either",
1029
+ },
1030
+ });
1031
+
1032
+ const instruction: string = (agent as any).systemInstruction;
1033
+ expect(instruction).toBe("Override wins");
1034
+ });
1035
+
1036
+ test("context with baseInstruction overrides the default", () => {
1037
+ const agent = createAgent({
1038
+ context: {
1039
+ baseInstruction: "You are a custom assistant.",
1040
+ memoryContent: "Sells hats",
1041
+ },
1042
+ });
1043
+
1044
+ const instruction: string = (agent as any).systemInstruction;
1045
+ expect(instruction).toContain("You are a custom assistant.");
1046
+ expect(instruction).toContain("Sells hats");
1047
+ expect(instruction).not.toContain(DEFAULT_SYSTEM_INSTRUCTION);
1048
+ });
1049
+
1050
+ test("context with no dynamic content uses base instruction only", () => {
1051
+ const agent = createAgent({
1052
+ context: {},
1053
+ });
1054
+
1055
+ const instruction: string = (agent as any).systemInstruction;
1056
+ expect(instruction).toBe(DEFAULT_SYSTEM_INSTRUCTION);
1057
+ });
927
1058
  });
package/src/agent.ts CHANGED
@@ -2,6 +2,11 @@ import Anthropic from "@anthropic-ai/sdk";
2
2
  import { ShopifyClient } from "./shopify";
3
3
  import type { MemoryStore } from "./memory";
4
4
  import { loadSkillReference } from "./skills";
5
+ import {
6
+ clampContent,
7
+ MAX_HEARTBEAT_CHARS,
8
+ MAX_MEMORY_CHARS,
9
+ } from "./prompt-utils";
5
10
 
6
11
  // ---------------------------------------------------------------------------
7
12
  // Types
@@ -75,13 +80,26 @@ export interface ThinkingConfig {
75
80
  budgetTokens: number;
76
81
  }
77
82
 
83
+ /** Structured context for prompt assembly. Used when systemInstruction is not provided. */
84
+ export interface AgentContextConfig {
85
+ /** Heartbeat content (only for new sessions). Injected at prompt start. */
86
+ heartbeatContent?: string;
87
+ /** Long-term memory content. Always included. */
88
+ memoryContent?: string;
89
+ /** Base system instruction override. Falls back to DEFAULT_SYSTEM_INSTRUCTION. */
90
+ baseInstruction?: string;
91
+ }
92
+
78
93
  /** Full configuration accepted by the ShopifyAgent constructor. */
79
94
  export interface AgentConfig {
80
95
  shopify: ShopifyClient;
81
96
  skillContent: string;
82
97
  model?: string;
83
- /** Override the default system instruction sent to the model. */
98
+ /** Override the default system instruction sent to the model (raw string). */
84
99
  systemInstruction?: string;
100
+ /** Structured context assembled into a system instruction internally.
101
+ * Ignored when systemInstruction is provided. */
102
+ context?: AgentContextConfig;
85
103
  /** Override default Claude Sonnet pricing. */
86
104
  pricing?: ModelPricing;
87
105
  /** Register plugins at construction time. */
@@ -243,6 +261,32 @@ function extractContent(response: Anthropic.Message): {
243
261
  return { text, thinking };
244
262
  }
245
263
 
264
+ /** Assemble a system instruction from structured AgentContextConfig. */
265
+ function buildSystemInstruction(ctx: AgentContextConfig): string {
266
+ const base = ctx.baseInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
267
+
268
+ let heartbeatBlock = "";
269
+ if (ctx.heartbeatContent?.trim()) {
270
+ heartbeatBlock =
271
+ "\n\nThis is a NEW conversation (no recent chat history). " +
272
+ "Follow these instructions first, then respond to the merchant's message. " +
273
+ "Keep the summary brief (1-2 sentences), then address what they asked.\n\n---\n" +
274
+ clampContent(ctx.heartbeatContent, MAX_HEARTBEAT_CHARS) +
275
+ "\n---";
276
+ }
277
+
278
+ let memoryBlock = "";
279
+ if (ctx.memoryContent?.trim()) {
280
+ memoryBlock =
281
+ "\n\nThings to remember about this merchant/store " +
282
+ "(use this context in your responses):\n---\n" +
283
+ clampContent(ctx.memoryContent, MAX_MEMORY_CHARS) +
284
+ "\n---";
285
+ }
286
+
287
+ return base + heartbeatBlock + memoryBlock;
288
+ }
289
+
246
290
  // ---------------------------------------------------------------------------
247
291
  // Agent
248
292
  // ---------------------------------------------------------------------------
@@ -264,8 +308,15 @@ export class ShopifyAgent {
264
308
  this.anthropic = new Anthropic();
265
309
  this.shopify = config.shopify;
266
310
  this.skillContent = config.skillContent;
267
- this.systemInstruction =
268
- config.systemInstruction ?? DEFAULT_SYSTEM_INSTRUCTION;
311
+
312
+ if (config.systemInstruction != null) {
313
+ this.systemInstruction = config.systemInstruction;
314
+ } else if (config.context) {
315
+ this.systemInstruction = buildSystemInstruction(config.context);
316
+ } else {
317
+ this.systemInstruction = DEFAULT_SYSTEM_INSTRUCTION;
318
+ }
319
+
269
320
  this.model = config.model ?? "claude-sonnet-4-5";
270
321
  this.pricing = config.pricing ?? DEFAULT_PRICING;
271
322
  this.hooks = config.hooks ?? {};
package/src/index.ts CHANGED
@@ -49,6 +49,7 @@ export {
49
49
  export { ShopifyAgent, DEFAULT_SYSTEM_INSTRUCTION } from "./agent";
50
50
  export type {
51
51
  AgentConfig,
52
+ AgentContextConfig,
52
53
  AgentHooks,
53
54
  AgentPlugin,
54
55
  ChatResult,
@@ -60,7 +61,10 @@ export type {
60
61
 
61
62
  // Memory
62
63
  export { InMemoryStore } from "./memory";
63
- export type { MemoryStore } from "./memory";
64
+ export type { MemoryStore, LoadResult } from "./memory";
65
+
66
+ // Prompt utilities
67
+ export { clampContent, MAX_HEARTBEAT_CHARS, MAX_MEMORY_CHARS } from "./prompt-utils";
64
68
 
65
69
  // Skills loader
66
70
  export {
package/src/memory.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /** Result of loadWithStatus() — distinguishes empty history from a storage error. */
2
+ export interface LoadResult {
3
+ history: any[];
4
+ error: boolean;
5
+ }
6
+
1
7
  /**
2
8
  * Interface for persisting conversation history across sessions.
3
9
  * Implement this interface to plug in any storage backend (Redis, SQLite, etc.).
@@ -14,6 +20,9 @@ export interface MemoryStore {
14
20
 
15
21
  /** Clear conversation history for a session. */
16
22
  clear(sessionId: string): Promise<void>;
23
+
24
+ /** Optional: load with error status for callers that need to distinguish empty from failed. */
25
+ loadWithStatus?(sessionId: string): Promise<LoadResult>;
17
26
  }
18
27
 
19
28
  /**
@@ -35,4 +44,8 @@ export class InMemoryStore implements MemoryStore {
35
44
  async clear(sessionId: string): Promise<void> {
36
45
  this.store.delete(sessionId);
37
46
  }
47
+
48
+ async loadWithStatus(sessionId: string): Promise<LoadResult> {
49
+ return { history: await this.load(sessionId), error: false };
50
+ }
38
51
  }
@@ -0,0 +1,12 @@
1
+ /** Max characters allowed for heartbeat content to prevent context bloat. */
2
+ export const MAX_HEARTBEAT_CHARS = 2000;
3
+
4
+ /** Max characters allowed for memory content to prevent context bloat. */
5
+ export const MAX_MEMORY_CHARS = 4000;
6
+
7
+ /** Clamp content to a max character count, appending a truncation marker. */
8
+ export function clampContent(content: string, maxChars: number): string {
9
+ const trimmed = content.trim();
10
+ if (trimmed.length <= maxChars) return trimmed;
11
+ return trimmed.slice(0, maxChars).trimEnd() + "\n...[truncated]";
12
+ }