struere 0.3.6 → 0.3.7

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.
@@ -17480,6 +17480,332 @@ function getEnvLocal(deploymentUrl) {
17480
17480
  return `STRUERE_DEPLOYMENT_URL=${deploymentUrl}
17481
17481
  `;
17482
17482
  }
17483
+ function getClaudeMd(name) {
17484
+ const displayName = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
17485
+ return `# ${displayName} Agent
17486
+
17487
+ This is a Struere AI agent project. Struere is a framework for building production AI agents with built-in data management, event tracking, and job scheduling.
17488
+
17489
+ ## Project Structure
17490
+
17491
+ \`\`\`
17492
+ src/
17493
+ \u251C\u2500\u2500 agent.ts # Agent definition (system prompt, model, tools)
17494
+ \u251C\u2500\u2500 context.ts # Dynamic context injection per request
17495
+ \u251C\u2500\u2500 tools.ts # Custom tool definitions
17496
+ \u2514\u2500\u2500 workflows/ # Multi-step workflow definitions
17497
+ tests/
17498
+ \u2514\u2500\u2500 *.test.yaml # YAML-based conversation tests
17499
+ struere.json # Project configuration (agentId, team, slug)
17500
+ struere.config.ts # Framework settings (port, CORS, logging)
17501
+ \`\`\`
17502
+
17503
+ ## Agent Definition
17504
+
17505
+ Define your agent in \`src/agent.ts\`:
17506
+
17507
+ \`\`\`typescript
17508
+ import { defineAgent } from 'struere'
17509
+ import { tools } from './tools'
17510
+ import { context } from './context'
17511
+
17512
+ export default defineAgent({
17513
+ name: 'my-agent',
17514
+ version: '0.1.0',
17515
+ description: 'My AI Agent',
17516
+ model: {
17517
+ provider: 'anthropic',
17518
+ name: 'claude-sonnet-4-20250514',
17519
+ temperature: 0.7,
17520
+ maxTokens: 4096,
17521
+ },
17522
+ systemPrompt: \\\`You are a helpful assistant.
17523
+
17524
+ Current time: {{datetime}}
17525
+ Customer: {{entity.get({"id": "{{thread.metadata.customerId}}"})}}\\\`,
17526
+ tools,
17527
+ context,
17528
+ state: {
17529
+ storage: 'memory',
17530
+ ttl: 3600,
17531
+ },
17532
+ })
17533
+ \`\`\`
17534
+
17535
+ ## System Prompt Templates
17536
+
17537
+ System prompts support dynamic \`{{...}}\` templates that are resolved at runtime before the LLM call.
17538
+
17539
+ ### Available Variables
17540
+
17541
+ | Variable | Description |
17542
+ |----------|-------------|
17543
+ | \`{{organizationId}}\` | Current organization ID |
17544
+ | \`{{userId}}\` | Current user ID |
17545
+ | \`{{threadId}}\` | Conversation thread ID |
17546
+ | \`{{agentId}}\` | Agent ID |
17547
+ | \`{{agent.name}}\` | Agent name |
17548
+ | \`{{agent.slug}}\` | Agent slug |
17549
+ | \`{{thread.metadata.X}}\` | Thread metadata field X |
17550
+ | \`{{message}}\` | Current user message |
17551
+ | \`{{timestamp}}\` | Unix timestamp (ms) |
17552
+ | \`{{datetime}}\` | ISO 8601 datetime |
17553
+
17554
+ ### Function Calls
17555
+
17556
+ Call any agent tool directly in the system prompt:
17557
+
17558
+ \`\`\`
17559
+ {{entity.get({"id": "ent_123"})}}
17560
+ {{entity.query({"type": "customer", "limit": 5})}}
17561
+ {{event.query({"entityId": "ent_123", "limit": 10})}}
17562
+ \`\`\`
17563
+
17564
+ ### Nested Templates
17565
+
17566
+ Variables can be used inside function arguments:
17567
+
17568
+ \`\`\`
17569
+ {{entity.get({"id": "{{thread.metadata.customerId}}"})}}
17570
+ \`\`\`
17571
+
17572
+ ### Error Handling
17573
+
17574
+ Failed templates are replaced with inline errors:
17575
+ \`\`\`
17576
+ [TEMPLATE_ERROR: variableName not found]
17577
+ [TEMPLATE_ERROR: toolName - error message]
17578
+ \`\`\`
17579
+
17580
+ ## Custom Tools
17581
+
17582
+ Define tools in \`src/tools.ts\`:
17583
+
17584
+ \`\`\`typescript
17585
+ import { defineTools } from 'struere'
17586
+
17587
+ export const tools = defineTools([
17588
+ {
17589
+ name: 'search_products',
17590
+ description: 'Search the product catalog',
17591
+ parameters: {
17592
+ type: 'object',
17593
+ properties: {
17594
+ query: { type: 'string', description: 'Search query' },
17595
+ limit: { type: 'number', description: 'Max results' },
17596
+ },
17597
+ required: ['query'],
17598
+ },
17599
+ handler: async (params) => {
17600
+ const results = await searchProducts(params.query, params.limit ?? 10)
17601
+ return { products: results }
17602
+ },
17603
+ },
17604
+ ])
17605
+ \`\`\`
17606
+
17607
+ Custom tool handlers are executed in a sandboxed Cloudflare Worker environment. They can make HTTP requests to allowlisted domains:
17608
+ - api.openai.com, api.anthropic.com, api.stripe.com
17609
+ - api.sendgrid.com, api.twilio.com, hooks.slack.com
17610
+ - discord.com, api.github.com
17611
+
17612
+ ## Built-in Tools
17613
+
17614
+ Agents have access to these built-in tools for data management:
17615
+
17616
+ ### Entity Tools
17617
+
17618
+ | Tool | Description |
17619
+ |------|-------------|
17620
+ | \`entity.create\` | Create a new entity |
17621
+ | \`entity.get\` | Get entity by ID |
17622
+ | \`entity.query\` | Query entities by type/filters |
17623
+ | \`entity.update\` | Update entity data |
17624
+ | \`entity.delete\` | Soft-delete entity |
17625
+ | \`entity.link\` | Create entity relation |
17626
+ | \`entity.unlink\` | Remove entity relation |
17627
+
17628
+ Example entity operations:
17629
+ \`\`\`json
17630
+ // entity.create
17631
+ { "type": "customer", "data": { "name": "John", "email": "john@example.com" } }
17632
+
17633
+ // entity.query
17634
+ { "type": "customer", "filters": { "status": "active" }, "limit": 10 }
17635
+
17636
+ // entity.update
17637
+ { "id": "ent_123", "data": { "status": "vip" } }
17638
+ \`\`\`
17639
+
17640
+ ### Event Tools
17641
+
17642
+ | Tool | Description |
17643
+ |------|-------------|
17644
+ | \`event.emit\` | Emit a custom event |
17645
+ | \`event.query\` | Query event history |
17646
+
17647
+ Example event operations:
17648
+ \`\`\`json
17649
+ // event.emit
17650
+ { "entityId": "ent_123", "eventType": "order.placed", "payload": { "amount": 99.99 } }
17651
+
17652
+ // event.query
17653
+ { "entityId": "ent_123", "eventType": "order.*", "limit": 20 }
17654
+ \`\`\`
17655
+
17656
+ ### Job Tools
17657
+
17658
+ | Tool | Description |
17659
+ |------|-------------|
17660
+ | \`job.enqueue\` | Schedule a background job |
17661
+ | \`job.status\` | Get job status |
17662
+
17663
+ Example job operations:
17664
+ \`\`\`json
17665
+ // job.enqueue
17666
+ { "jobType": "send_email", "payload": { "to": "user@example.com" }, "scheduledFor": 1706745600000 }
17667
+
17668
+ // job.status
17669
+ { "id": "job_abc123" }
17670
+ \`\`\`
17671
+
17672
+ ## Context Function
17673
+
17674
+ Inject dynamic context per request in \`src/context.ts\`:
17675
+
17676
+ \`\`\`typescript
17677
+ import { defineContext } from 'struere'
17678
+
17679
+ export const context = defineContext(async (request) => {
17680
+ const { conversationId, userId, channel, state } = request
17681
+
17682
+ const userProfile = await fetchUserProfile(userId)
17683
+
17684
+ return {
17685
+ additionalContext: \\\`
17686
+ User: \${userProfile.name} (\${userProfile.tier} tier)
17687
+ Conversation: \${conversationId}
17688
+ Channel: \${channel}
17689
+ \\\`,
17690
+ variables: {
17691
+ userId,
17692
+ userTier: userProfile.tier,
17693
+ timestamp: new Date().toISOString(),
17694
+ },
17695
+ }
17696
+ })
17697
+ \`\`\`
17698
+
17699
+ ## Testing
17700
+
17701
+ Write YAML-based conversation tests in \`tests/\`:
17702
+
17703
+ \`\`\`yaml
17704
+ name: Order flow test
17705
+ description: Test the complete order flow
17706
+
17707
+ conversation:
17708
+ - role: user
17709
+ content: I want to order a pizza
17710
+ - role: assistant
17711
+ assertions:
17712
+ - type: contains
17713
+ value: size
17714
+ - type: toolCalled
17715
+ value: get_menu
17716
+
17717
+ - role: user
17718
+ content: Large pepperoni please
17719
+ - role: assistant
17720
+ assertions:
17721
+ - type: toolCalled
17722
+ value: entity.create
17723
+ \`\`\`
17724
+
17725
+ ### Assertion Types
17726
+
17727
+ | Type | Description |
17728
+ |------|-------------|
17729
+ | \`contains\` | Response contains substring |
17730
+ | \`matches\` | Response matches regex |
17731
+ | \`toolCalled\` | Specific tool was called |
17732
+ | \`noToolCalled\` | No tools were called |
17733
+
17734
+ Run tests with:
17735
+ \`\`\`bash
17736
+ bun run test
17737
+ \`\`\`
17738
+
17739
+ ## CLI Commands
17740
+
17741
+ | Command | Description |
17742
+ |---------|-------------|
17743
+ | \`struere dev\` | Start development mode (live sync to Convex) |
17744
+ | \`struere build\` | Validate agent configuration |
17745
+ | \`struere deploy\` | Deploy agent to production |
17746
+ | \`struere test\` | Run YAML conversation tests |
17747
+ | \`struere logs\` | View recent execution logs |
17748
+ | \`struere state\` | Inspect conversation thread state |
17749
+
17750
+ ## Thread Metadata
17751
+
17752
+ Set thread metadata when creating conversations to provide context:
17753
+
17754
+ \`\`\`typescript
17755
+ // Via API
17756
+ POST /v1/chat
17757
+ {
17758
+ "agentId": "agent_123",
17759
+ "message": "Hello",
17760
+ "metadata": {
17761
+ "customerId": "ent_customer_456",
17762
+ "channel": "web",
17763
+ "language": "en"
17764
+ }
17765
+ }
17766
+ \`\`\`
17767
+
17768
+ Access in system prompt:
17769
+ \`\`\`
17770
+ Customer: {{entity.get({"id": "{{thread.metadata.customerId}}"})}}
17771
+ Channel: {{thread.metadata.channel}}
17772
+ \`\`\`
17773
+
17774
+ ## Development Workflow
17775
+
17776
+ 1. **Edit agent configuration** in \`src/agent.ts\`
17777
+ 2. **Run \`bun run dev\`** to sync changes to Convex
17778
+ 3. **Test via API** or dashboard chat interface
17779
+ 4. **Write tests** in \`tests/*.test.yaml\`
17780
+ 5. **Deploy** with \`bun run deploy\`
17781
+
17782
+ ## API Endpoints
17783
+
17784
+ | Endpoint | Method | Description |
17785
+ |----------|--------|-------------|
17786
+ | \`/v1/chat\` | POST | Chat by agent ID |
17787
+ | \`/v1/agents/:slug/chat\` | POST | Chat by agent slug |
17788
+
17789
+ Authentication: Bearer token (API key from dashboard)
17790
+
17791
+ \`\`\`bash
17792
+ curl -X POST https://your-deployment.convex.cloud/v1/chat \\
17793
+ -H "Authorization: Bearer sk_live_..." \\
17794
+ -H "Content-Type: application/json" \\
17795
+ -d '{"agentId": "...", "message": "Hello"}'
17796
+ \`\`\`
17797
+
17798
+ ## Best Practices
17799
+
17800
+ 1. **System Prompts**: Use templates for dynamic data instead of hardcoding
17801
+ 2. **Tools**: Keep tool handlers focused and stateless
17802
+ 3. **Entities**: Model your domain data as entity types
17803
+ 4. **Events**: Emit events for audit trails and analytics
17804
+ 5. **Jobs**: Use jobs for async operations (emails, notifications)
17805
+ 6. **Testing**: Write tests for critical conversation flows
17806
+ 7. **Context**: Use context for user-specific personalization
17807
+ `;
17808
+ }
17483
17809
 
17484
17810
  // src/cli/utils/scaffold.ts
17485
17811
  function ensureDir(filePath) {
@@ -17519,7 +17845,8 @@ function scaffoldAgentFiles(cwd, projectName) {
17519
17845
  "src/tools.ts": getToolsTs(),
17520
17846
  "src/workflows/.gitkeep": "",
17521
17847
  "tests/basic.test.yaml": getBasicTestYaml(),
17522
- ".env.example": getEnvExample()
17848
+ ".env.example": getEnvExample(),
17849
+ ".claude.md": getClaudeMd(projectName)
17523
17850
  };
17524
17851
  for (const [relativePath, content] of Object.entries(files)) {
17525
17852
  const fullPath = join3(cwd, relativePath);
@@ -18768,9 +19095,17 @@ var whoamiCommand = new Command("whoami").description("Show current logged in us
18768
19095
  // package.json
18769
19096
  var package_default = {
18770
19097
  name: "struere",
18771
- version: "0.3.6",
19098
+ version: "0.3.7",
18772
19099
  description: "Build, test, and deploy AI agents",
18773
- keywords: ["ai", "agents", "llm", "anthropic", "openai", "framework", "cli"],
19100
+ keywords: [
19101
+ "ai",
19102
+ "agents",
19103
+ "llm",
19104
+ "anthropic",
19105
+ "openai",
19106
+ "framework",
19107
+ "cli"
19108
+ ],
18774
19109
  author: "struere",
18775
19110
  license: "MIT",
18776
19111
  publishConfig: {
@@ -18797,7 +19132,9 @@ var package_default = {
18797
19132
  types: "./dist/index.d.ts"
18798
19133
  }
18799
19134
  },
18800
- files: ["dist"],
19135
+ files: [
19136
+ "dist"
19137
+ ],
18801
19138
  scripts: {
18802
19139
  build: "bun build ./src/cli/index.ts --outdir ./dist/cli --target bun --external commander --external chalk --external ora --external chokidar --external yaml && bun build ./src/index.ts --outdir ./dist --target node && bun build ./src/bin/struere.ts --outdir ./dist/bin --target bun && tsc --emitDeclarationOnly && chmod +x ./dist/bin/struere.js",
18803
19140
  dev: "tsc --watch",
package/dist/cli/index.js CHANGED
@@ -819,6 +819,332 @@ function getEnvLocal(deploymentUrl) {
819
819
  return `STRUERE_DEPLOYMENT_URL=${deploymentUrl}
820
820
  `;
821
821
  }
822
+ function getClaudeMd(name) {
823
+ const displayName = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
824
+ return `# ${displayName} Agent
825
+
826
+ This is a Struere AI agent project. Struere is a framework for building production AI agents with built-in data management, event tracking, and job scheduling.
827
+
828
+ ## Project Structure
829
+
830
+ \`\`\`
831
+ src/
832
+ \u251C\u2500\u2500 agent.ts # Agent definition (system prompt, model, tools)
833
+ \u251C\u2500\u2500 context.ts # Dynamic context injection per request
834
+ \u251C\u2500\u2500 tools.ts # Custom tool definitions
835
+ \u2514\u2500\u2500 workflows/ # Multi-step workflow definitions
836
+ tests/
837
+ \u2514\u2500\u2500 *.test.yaml # YAML-based conversation tests
838
+ struere.json # Project configuration (agentId, team, slug)
839
+ struere.config.ts # Framework settings (port, CORS, logging)
840
+ \`\`\`
841
+
842
+ ## Agent Definition
843
+
844
+ Define your agent in \`src/agent.ts\`:
845
+
846
+ \`\`\`typescript
847
+ import { defineAgent } from 'struere'
848
+ import { tools } from './tools'
849
+ import { context } from './context'
850
+
851
+ export default defineAgent({
852
+ name: 'my-agent',
853
+ version: '0.1.0',
854
+ description: 'My AI Agent',
855
+ model: {
856
+ provider: 'anthropic',
857
+ name: 'claude-sonnet-4-20250514',
858
+ temperature: 0.7,
859
+ maxTokens: 4096,
860
+ },
861
+ systemPrompt: \\\`You are a helpful assistant.
862
+
863
+ Current time: {{datetime}}
864
+ Customer: {{entity.get({"id": "{{thread.metadata.customerId}}"})}}\\\`,
865
+ tools,
866
+ context,
867
+ state: {
868
+ storage: 'memory',
869
+ ttl: 3600,
870
+ },
871
+ })
872
+ \`\`\`
873
+
874
+ ## System Prompt Templates
875
+
876
+ System prompts support dynamic \`{{...}}\` templates that are resolved at runtime before the LLM call.
877
+
878
+ ### Available Variables
879
+
880
+ | Variable | Description |
881
+ |----------|-------------|
882
+ | \`{{organizationId}}\` | Current organization ID |
883
+ | \`{{userId}}\` | Current user ID |
884
+ | \`{{threadId}}\` | Conversation thread ID |
885
+ | \`{{agentId}}\` | Agent ID |
886
+ | \`{{agent.name}}\` | Agent name |
887
+ | \`{{agent.slug}}\` | Agent slug |
888
+ | \`{{thread.metadata.X}}\` | Thread metadata field X |
889
+ | \`{{message}}\` | Current user message |
890
+ | \`{{timestamp}}\` | Unix timestamp (ms) |
891
+ | \`{{datetime}}\` | ISO 8601 datetime |
892
+
893
+ ### Function Calls
894
+
895
+ Call any agent tool directly in the system prompt:
896
+
897
+ \`\`\`
898
+ {{entity.get({"id": "ent_123"})}}
899
+ {{entity.query({"type": "customer", "limit": 5})}}
900
+ {{event.query({"entityId": "ent_123", "limit": 10})}}
901
+ \`\`\`
902
+
903
+ ### Nested Templates
904
+
905
+ Variables can be used inside function arguments:
906
+
907
+ \`\`\`
908
+ {{entity.get({"id": "{{thread.metadata.customerId}}"})}}
909
+ \`\`\`
910
+
911
+ ### Error Handling
912
+
913
+ Failed templates are replaced with inline errors:
914
+ \`\`\`
915
+ [TEMPLATE_ERROR: variableName not found]
916
+ [TEMPLATE_ERROR: toolName - error message]
917
+ \`\`\`
918
+
919
+ ## Custom Tools
920
+
921
+ Define tools in \`src/tools.ts\`:
922
+
923
+ \`\`\`typescript
924
+ import { defineTools } from 'struere'
925
+
926
+ export const tools = defineTools([
927
+ {
928
+ name: 'search_products',
929
+ description: 'Search the product catalog',
930
+ parameters: {
931
+ type: 'object',
932
+ properties: {
933
+ query: { type: 'string', description: 'Search query' },
934
+ limit: { type: 'number', description: 'Max results' },
935
+ },
936
+ required: ['query'],
937
+ },
938
+ handler: async (params) => {
939
+ const results = await searchProducts(params.query, params.limit ?? 10)
940
+ return { products: results }
941
+ },
942
+ },
943
+ ])
944
+ \`\`\`
945
+
946
+ Custom tool handlers are executed in a sandboxed Cloudflare Worker environment. They can make HTTP requests to allowlisted domains:
947
+ - api.openai.com, api.anthropic.com, api.stripe.com
948
+ - api.sendgrid.com, api.twilio.com, hooks.slack.com
949
+ - discord.com, api.github.com
950
+
951
+ ## Built-in Tools
952
+
953
+ Agents have access to these built-in tools for data management:
954
+
955
+ ### Entity Tools
956
+
957
+ | Tool | Description |
958
+ |------|-------------|
959
+ | \`entity.create\` | Create a new entity |
960
+ | \`entity.get\` | Get entity by ID |
961
+ | \`entity.query\` | Query entities by type/filters |
962
+ | \`entity.update\` | Update entity data |
963
+ | \`entity.delete\` | Soft-delete entity |
964
+ | \`entity.link\` | Create entity relation |
965
+ | \`entity.unlink\` | Remove entity relation |
966
+
967
+ Example entity operations:
968
+ \`\`\`json
969
+ // entity.create
970
+ { "type": "customer", "data": { "name": "John", "email": "john@example.com" } }
971
+
972
+ // entity.query
973
+ { "type": "customer", "filters": { "status": "active" }, "limit": 10 }
974
+
975
+ // entity.update
976
+ { "id": "ent_123", "data": { "status": "vip" } }
977
+ \`\`\`
978
+
979
+ ### Event Tools
980
+
981
+ | Tool | Description |
982
+ |------|-------------|
983
+ | \`event.emit\` | Emit a custom event |
984
+ | \`event.query\` | Query event history |
985
+
986
+ Example event operations:
987
+ \`\`\`json
988
+ // event.emit
989
+ { "entityId": "ent_123", "eventType": "order.placed", "payload": { "amount": 99.99 } }
990
+
991
+ // event.query
992
+ { "entityId": "ent_123", "eventType": "order.*", "limit": 20 }
993
+ \`\`\`
994
+
995
+ ### Job Tools
996
+
997
+ | Tool | Description |
998
+ |------|-------------|
999
+ | \`job.enqueue\` | Schedule a background job |
1000
+ | \`job.status\` | Get job status |
1001
+
1002
+ Example job operations:
1003
+ \`\`\`json
1004
+ // job.enqueue
1005
+ { "jobType": "send_email", "payload": { "to": "user@example.com" }, "scheduledFor": 1706745600000 }
1006
+
1007
+ // job.status
1008
+ { "id": "job_abc123" }
1009
+ \`\`\`
1010
+
1011
+ ## Context Function
1012
+
1013
+ Inject dynamic context per request in \`src/context.ts\`:
1014
+
1015
+ \`\`\`typescript
1016
+ import { defineContext } from 'struere'
1017
+
1018
+ export const context = defineContext(async (request) => {
1019
+ const { conversationId, userId, channel, state } = request
1020
+
1021
+ const userProfile = await fetchUserProfile(userId)
1022
+
1023
+ return {
1024
+ additionalContext: \\\`
1025
+ User: \${userProfile.name} (\${userProfile.tier} tier)
1026
+ Conversation: \${conversationId}
1027
+ Channel: \${channel}
1028
+ \\\`,
1029
+ variables: {
1030
+ userId,
1031
+ userTier: userProfile.tier,
1032
+ timestamp: new Date().toISOString(),
1033
+ },
1034
+ }
1035
+ })
1036
+ \`\`\`
1037
+
1038
+ ## Testing
1039
+
1040
+ Write YAML-based conversation tests in \`tests/\`:
1041
+
1042
+ \`\`\`yaml
1043
+ name: Order flow test
1044
+ description: Test the complete order flow
1045
+
1046
+ conversation:
1047
+ - role: user
1048
+ content: I want to order a pizza
1049
+ - role: assistant
1050
+ assertions:
1051
+ - type: contains
1052
+ value: size
1053
+ - type: toolCalled
1054
+ value: get_menu
1055
+
1056
+ - role: user
1057
+ content: Large pepperoni please
1058
+ - role: assistant
1059
+ assertions:
1060
+ - type: toolCalled
1061
+ value: entity.create
1062
+ \`\`\`
1063
+
1064
+ ### Assertion Types
1065
+
1066
+ | Type | Description |
1067
+ |------|-------------|
1068
+ | \`contains\` | Response contains substring |
1069
+ | \`matches\` | Response matches regex |
1070
+ | \`toolCalled\` | Specific tool was called |
1071
+ | \`noToolCalled\` | No tools were called |
1072
+
1073
+ Run tests with:
1074
+ \`\`\`bash
1075
+ bun run test
1076
+ \`\`\`
1077
+
1078
+ ## CLI Commands
1079
+
1080
+ | Command | Description |
1081
+ |---------|-------------|
1082
+ | \`struere dev\` | Start development mode (live sync to Convex) |
1083
+ | \`struere build\` | Validate agent configuration |
1084
+ | \`struere deploy\` | Deploy agent to production |
1085
+ | \`struere test\` | Run YAML conversation tests |
1086
+ | \`struere logs\` | View recent execution logs |
1087
+ | \`struere state\` | Inspect conversation thread state |
1088
+
1089
+ ## Thread Metadata
1090
+
1091
+ Set thread metadata when creating conversations to provide context:
1092
+
1093
+ \`\`\`typescript
1094
+ // Via API
1095
+ POST /v1/chat
1096
+ {
1097
+ "agentId": "agent_123",
1098
+ "message": "Hello",
1099
+ "metadata": {
1100
+ "customerId": "ent_customer_456",
1101
+ "channel": "web",
1102
+ "language": "en"
1103
+ }
1104
+ }
1105
+ \`\`\`
1106
+
1107
+ Access in system prompt:
1108
+ \`\`\`
1109
+ Customer: {{entity.get({"id": "{{thread.metadata.customerId}}"})}}
1110
+ Channel: {{thread.metadata.channel}}
1111
+ \`\`\`
1112
+
1113
+ ## Development Workflow
1114
+
1115
+ 1. **Edit agent configuration** in \`src/agent.ts\`
1116
+ 2. **Run \`bun run dev\`** to sync changes to Convex
1117
+ 3. **Test via API** or dashboard chat interface
1118
+ 4. **Write tests** in \`tests/*.test.yaml\`
1119
+ 5. **Deploy** with \`bun run deploy\`
1120
+
1121
+ ## API Endpoints
1122
+
1123
+ | Endpoint | Method | Description |
1124
+ |----------|--------|-------------|
1125
+ | \`/v1/chat\` | POST | Chat by agent ID |
1126
+ | \`/v1/agents/:slug/chat\` | POST | Chat by agent slug |
1127
+
1128
+ Authentication: Bearer token (API key from dashboard)
1129
+
1130
+ \`\`\`bash
1131
+ curl -X POST https://your-deployment.convex.cloud/v1/chat \\
1132
+ -H "Authorization: Bearer sk_live_..." \\
1133
+ -H "Content-Type: application/json" \\
1134
+ -d '{"agentId": "...", "message": "Hello"}'
1135
+ \`\`\`
1136
+
1137
+ ## Best Practices
1138
+
1139
+ 1. **System Prompts**: Use templates for dynamic data instead of hardcoding
1140
+ 2. **Tools**: Keep tool handlers focused and stateless
1141
+ 3. **Entities**: Model your domain data as entity types
1142
+ 4. **Events**: Emit events for audit trails and analytics
1143
+ 5. **Jobs**: Use jobs for async operations (emails, notifications)
1144
+ 6. **Testing**: Write tests for critical conversation flows
1145
+ 7. **Context**: Use context for user-specific personalization
1146
+ `;
1147
+ }
822
1148
 
823
1149
  // src/cli/utils/scaffold.ts
824
1150
  function ensureDir(filePath) {
@@ -858,7 +1184,8 @@ function scaffoldAgentFiles(cwd, projectName) {
858
1184
  "src/tools.ts": getToolsTs(),
859
1185
  "src/workflows/.gitkeep": "",
860
1186
  "tests/basic.test.yaml": getBasicTestYaml(),
861
- ".env.example": getEnvExample()
1187
+ ".env.example": getEnvExample(),
1188
+ ".claude.md": getClaudeMd(projectName)
862
1189
  };
863
1190
  for (const [relativePath, content] of Object.entries(files)) {
864
1191
  const fullPath = join3(cwd, relativePath);
@@ -2133,9 +2460,17 @@ var whoamiCommand = new Command11("whoami").description("Show current logged in
2133
2460
  // package.json
2134
2461
  var package_default = {
2135
2462
  name: "struere",
2136
- version: "0.3.6",
2463
+ version: "0.3.7",
2137
2464
  description: "Build, test, and deploy AI agents",
2138
- keywords: ["ai", "agents", "llm", "anthropic", "openai", "framework", "cli"],
2465
+ keywords: [
2466
+ "ai",
2467
+ "agents",
2468
+ "llm",
2469
+ "anthropic",
2470
+ "openai",
2471
+ "framework",
2472
+ "cli"
2473
+ ],
2139
2474
  author: "struere",
2140
2475
  license: "MIT",
2141
2476
  publishConfig: {
@@ -2162,7 +2497,9 @@ var package_default = {
2162
2497
  types: "./dist/index.d.ts"
2163
2498
  }
2164
2499
  },
2165
- files: ["dist"],
2500
+ files: [
2501
+ "dist"
2502
+ ],
2166
2503
  scripts: {
2167
2504
  build: "bun build ./src/cli/index.ts --outdir ./dist/cli --target bun --external commander --external chalk --external ora --external chokidar --external yaml && bun build ./src/index.ts --outdir ./dist --target node && bun build ./src/bin/struere.ts --outdir ./dist/bin --target bun && tsc --emitDeclarationOnly && chmod +x ./dist/bin/struere.js",
2168
2505
  dev: "tsc --watch",
@@ -9,4 +9,5 @@ export declare function getEnvExample(): string;
9
9
  export declare function getGitignore(): string;
10
10
  export declare function getStruereJson(agentId: string, team: string, slug: string, name: string): string;
11
11
  export declare function getEnvLocal(deploymentUrl: string): string;
12
+ export declare function getClaudeMd(name: string): string;
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBnD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAsBpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAgBzC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoC/C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAkBrC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAoDnC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAmBzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAgBrC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAahG;AAED,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGzD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBnD;AAED,wBAAgB,WAAW,IAAI,MAAM,CAsBpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAgBzC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoC/C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAkBrC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAoDnC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAmBzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAgBrC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAahG;AAED,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyUhD"}
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/scaffold.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAeD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CAexF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CA+BrF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CA8BnF;AAsBD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/scaffold.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAeD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CAexF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CAgCrF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CA+BnF;AAsBD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD"}
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "struere",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Build, test, and deploy AI agents",
5
- "keywords": ["ai", "agents", "llm", "anthropic", "openai", "framework", "cli"],
5
+ "keywords": [
6
+ "ai",
7
+ "agents",
8
+ "llm",
9
+ "anthropic",
10
+ "openai",
11
+ "framework",
12
+ "cli"
13
+ ],
6
14
  "author": "struere",
7
15
  "license": "MIT",
8
16
  "publishConfig": {
@@ -29,7 +37,9 @@
29
37
  "types": "./dist/index.d.ts"
30
38
  }
31
39
  },
32
- "files": ["dist"],
40
+ "files": [
41
+ "dist"
42
+ ],
33
43
  "scripts": {
34
44
  "build": "bun build ./src/cli/index.ts --outdir ./dist/cli --target bun --external commander --external chalk --external ora --external chokidar --external yaml && bun build ./src/index.ts --outdir ./dist --target node && bun build ./src/bin/struere.ts --outdir ./dist/bin --target bun && tsc --emitDeclarationOnly && chmod +x ./dist/bin/struere.js",
35
45
  "dev": "tsc --watch",