struere 0.5.15 → 0.5.17
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/bin/struere.js +430 -10
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/index.js +430 -10
- package/dist/cli/templates/index.d.ts +2 -1
- package/dist/cli/templates/index.d.ts.map +1 -1
- package/dist/cli/utils/convex.d.ts +6 -0
- package/dist/cli/utils/convex.d.ts.map +1 -1
- package/dist/cli/utils/extractor.d.ts +15 -0
- package/dist/cli/utils/extractor.d.ts.map +1 -1
- package/dist/cli/utils/loader.d.ts +4 -1
- package/dist/cli/utils/loader.d.ts.map +1 -1
- package/dist/cli/utils/scaffold.d.ts +1 -0
- package/dist/cli/utils/scaffold.d.ts.map +1 -1
- package/dist/define/entityType.d.ts.map +1 -1
- package/dist/define/trigger.d.ts +3 -0
- package/dist/define/trigger.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -1
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bin/struere.js
CHANGED
|
@@ -20096,6 +20096,7 @@ Struere is a framework for building production AI agents with Convex as the real
|
|
|
20096
20096
|
\u2502 \u251C\u2500\u2500 agents/*.ts \u2192 Agent configs synced to Convex \u2502
|
|
20097
20097
|
\u2502 \u251C\u2500\u2500 entity-types/*.ts \u2192 Schema definitions synced to Convex \u2502
|
|
20098
20098
|
\u2502 \u251C\u2500\u2500 roles/*.ts \u2192 RBAC policies synced to Convex \u2502
|
|
20099
|
+
\u2502 \u251C\u2500\u2500 triggers/*.ts \u2192 Automation rules synced to Convex \u2502
|
|
20099
20100
|
\u2502 \u251C\u2500\u2500 tools/index.ts \u2192 Custom tools (run on CF Worker) \u2502
|
|
20100
20101
|
\u2502 \u2514\u2500\u2500 evals/*.eval.yaml \u2192 Test suites (synced + executed) \u2502
|
|
20101
20102
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
@@ -20134,6 +20135,10 @@ roles/ # RBAC: who can do what
|
|
|
20134
20135
|
\u251C\u2500\u2500 support.ts # Limited access
|
|
20135
20136
|
\u2514\u2500\u2500 index.ts
|
|
20136
20137
|
|
|
20138
|
+
triggers/ # Automation rules (react to entity changes)
|
|
20139
|
+
\u251C\u2500\u2500 notify-on-create.ts
|
|
20140
|
+
\u2514\u2500\u2500 index.ts
|
|
20141
|
+
|
|
20137
20142
|
tools/ # Custom tools shared by all agents
|
|
20138
20143
|
\u2514\u2500\u2500 index.ts # defineTools([...])
|
|
20139
20144
|
|
|
@@ -20174,6 +20179,7 @@ export default defineConfig({
|
|
|
20174
20179
|
| \`struere add agent <name>\` | Create agents/name.ts with template |
|
|
20175
20180
|
| \`struere add entity-type <name>\` | Create entity-types/name.ts |
|
|
20176
20181
|
| \`struere add role <name>\` | Create roles/name.ts |
|
|
20182
|
+
| \`struere add trigger <name>\` | Create triggers/name.ts with template |
|
|
20177
20183
|
| \`struere add eval <name>\` | Create evals/name.eval.yaml with template |
|
|
20178
20184
|
| \`struere eval\` | Run all eval suites |
|
|
20179
20185
|
| \`struere eval --suite <name>\` | Run a specific eval suite |
|
|
@@ -20273,6 +20279,39 @@ export default defineEntityType({
|
|
|
20273
20279
|
})
|
|
20274
20280
|
\`\`\`
|
|
20275
20281
|
|
|
20282
|
+
### Binding Entity Types to Roles (\`boundToRole\`)
|
|
20283
|
+
|
|
20284
|
+
When an entity type represents users of a specific role (e.g. a "teacher" entity type for users with the "teacher" role), declare the binding explicitly:
|
|
20285
|
+
|
|
20286
|
+
\`\`\`typescript
|
|
20287
|
+
import { defineEntityType } from 'struere'
|
|
20288
|
+
|
|
20289
|
+
export default defineEntityType({
|
|
20290
|
+
name: "Teacher",
|
|
20291
|
+
slug: "teacher",
|
|
20292
|
+
schema: {
|
|
20293
|
+
type: "object",
|
|
20294
|
+
properties: {
|
|
20295
|
+
name: { type: "string" },
|
|
20296
|
+
email: { type: "string", format: "email" },
|
|
20297
|
+
userId: { type: "string" }, // Links to the Convex user _id
|
|
20298
|
+
},
|
|
20299
|
+
required: ["name", "email", "userId"],
|
|
20300
|
+
},
|
|
20301
|
+
searchFields: ["name", "email"],
|
|
20302
|
+
boundToRole: "teacher", // Role name this entity type represents
|
|
20303
|
+
userIdField: "userId", // Field in data that holds the user's Convex _id (defaults to "userId")
|
|
20304
|
+
})
|
|
20305
|
+
\`\`\`
|
|
20306
|
+
|
|
20307
|
+
This enables \`actor.entityId\` in scope rules to automatically resolve which entity record belongs to the current user. Without \`boundToRole\`, scope rules using \`actor.entityId\` will match nothing.
|
|
20308
|
+
|
|
20309
|
+
**Rules:**
|
|
20310
|
+
- Each role can only be bound to one entity type (enforced at sync time)
|
|
20311
|
+
- \`userIdField\` defaults to \`"userId"\` if not specified
|
|
20312
|
+
- \`userIdField\` requires \`boundToRole\` to be set
|
|
20313
|
+
- The entity's \`data[userIdField]\` must contain the Convex user \`_id\`
|
|
20314
|
+
|
|
20276
20315
|
Entities are stored as:
|
|
20277
20316
|
\`\`\`json
|
|
20278
20317
|
{
|
|
@@ -20307,7 +20346,7 @@ export default defineRole({
|
|
|
20307
20346
|
entityType: "customer",
|
|
20308
20347
|
field: "data.assignedTo", // Field in entity data
|
|
20309
20348
|
operator: "eq",
|
|
20310
|
-
value: "actor.userId" // Current user's
|
|
20349
|
+
value: "actor.userId" // Current user's Convex _id
|
|
20311
20350
|
},
|
|
20312
20351
|
],
|
|
20313
20352
|
|
|
@@ -20328,6 +20367,45 @@ Every tool call goes through permission checks:
|
|
|
20328
20367
|
|
|
20329
20368
|
Deny policies always override allow.
|
|
20330
20369
|
|
|
20370
|
+
### Scope Rule Values
|
|
20371
|
+
|
|
20372
|
+
| Value | Resolves To |
|
|
20373
|
+
|-------|-------------|
|
|
20374
|
+
| \`"actor.userId"\` | Current user's Convex \`_id\` |
|
|
20375
|
+
| \`"actor.organizationId"\` | Current organization ID |
|
|
20376
|
+
| \`"actor.entityId"\` | Entity record bound to this user via \`boundToRole\` (requires entity type with \`boundToRole\` set) |
|
|
20377
|
+
| \`"actor.relatedIds:TYPE"\` | IDs of entities related to the actor's entity via relation type TYPE |
|
|
20378
|
+
| \`"literal:VALUE"\` | Literal string value |
|
|
20379
|
+
|
|
20380
|
+
**Example using \`actor.entityId\`:**
|
|
20381
|
+
|
|
20382
|
+
\`\`\`typescript
|
|
20383
|
+
// roles/teacher.ts \u2014 Teacher sees only their own sessions
|
|
20384
|
+
export default defineRole({
|
|
20385
|
+
name: "teacher",
|
|
20386
|
+
policies: [
|
|
20387
|
+
{ resource: "session", actions: ["list", "read", "update"], effect: "allow" },
|
|
20388
|
+
],
|
|
20389
|
+
scopeRules: [
|
|
20390
|
+
{
|
|
20391
|
+
entityType: "session",
|
|
20392
|
+
field: "data.teacherId",
|
|
20393
|
+
operator: "eq",
|
|
20394
|
+
value: "actor.entityId" // Resolves to the teacher entity _id for this user
|
|
20395
|
+
},
|
|
20396
|
+
],
|
|
20397
|
+
})
|
|
20398
|
+
|
|
20399
|
+
// entity-types/teacher.ts \u2014 Must declare boundToRole for actor.entityId to work
|
|
20400
|
+
export default defineEntityType({
|
|
20401
|
+
name: "Teacher",
|
|
20402
|
+
slug: "teacher",
|
|
20403
|
+
boundToRole: "teacher",
|
|
20404
|
+
userIdField: "userId",
|
|
20405
|
+
// ...schema
|
|
20406
|
+
})
|
|
20407
|
+
\`\`\`
|
|
20408
|
+
|
|
20331
20409
|
## Defining Custom Tools
|
|
20332
20410
|
|
|
20333
20411
|
Edit \`tools/index.ts\`:
|
|
@@ -20396,6 +20474,103 @@ Custom tool handlers can only fetch from:
|
|
|
20396
20474
|
- api.stripe.com, api.sendgrid.com, api.twilio.com
|
|
20397
20475
|
- hooks.slack.com, discord.com, api.github.com
|
|
20398
20476
|
|
|
20477
|
+
## Defining Triggers
|
|
20478
|
+
|
|
20479
|
+
Triggers are automated actions that fire when entities are created, updated, or deleted. They run asynchronously after the mutation completes.
|
|
20480
|
+
|
|
20481
|
+
Create \\\`triggers/notify-on-session.ts\\\`:
|
|
20482
|
+
\\\`\\\`\\\`typescript
|
|
20483
|
+
import { defineTrigger } from 'struere'
|
|
20484
|
+
|
|
20485
|
+
export default defineTrigger({
|
|
20486
|
+
name: "Notify Teacher on New Session",
|
|
20487
|
+
slug: "notify-teacher-on-session",
|
|
20488
|
+
on: {
|
|
20489
|
+
entityType: "session",
|
|
20490
|
+
action: "created",
|
|
20491
|
+
condition: { "data.status": "scheduled" } // optional
|
|
20492
|
+
},
|
|
20493
|
+
actions: [
|
|
20494
|
+
{
|
|
20495
|
+
tool: "entity.get",
|
|
20496
|
+
args: { id: "{{trigger.data.teacherId}}" },
|
|
20497
|
+
as: "teacher" // store result for later steps
|
|
20498
|
+
},
|
|
20499
|
+
{
|
|
20500
|
+
tool: "event.emit",
|
|
20501
|
+
args: {
|
|
20502
|
+
eventType: "notification.sent",
|
|
20503
|
+
entityId: "{{trigger.entityId}}",
|
|
20504
|
+
payload: {
|
|
20505
|
+
teacherName: "{{steps.teacher.data.name}}",
|
|
20506
|
+
sessionTime: "{{trigger.data.startTime}}"
|
|
20507
|
+
}
|
|
20508
|
+
}
|
|
20509
|
+
}
|
|
20510
|
+
]
|
|
20511
|
+
})
|
|
20512
|
+
\\\`\\\`\\\`
|
|
20513
|
+
|
|
20514
|
+
### Trigger Config
|
|
20515
|
+
|
|
20516
|
+
| Field | Required | Description |
|
|
20517
|
+
|-------|----------|-------------|
|
|
20518
|
+
| \\\`name\\\` | Yes | Display name |
|
|
20519
|
+
| \\\`slug\\\` | Yes | Unique identifier (used for sync) |
|
|
20520
|
+
| \\\`on.entityType\\\` | Yes | Entity type slug to watch |
|
|
20521
|
+
| \\\`on.action\\\` | Yes | \\\`"created"\\\`, \\\`"updated"\\\`, or \\\`"deleted"\\\` |
|
|
20522
|
+
| \\\`on.condition\\\` | No | Dot-notation equality conditions on entity data |
|
|
20523
|
+
| \\\`actions\\\` | Yes | Ordered list of tool calls to execute |
|
|
20524
|
+
|
|
20525
|
+
### Action Pipeline
|
|
20526
|
+
|
|
20527
|
+
Each action in the \\\`actions\\\` array runs sequentially:
|
|
20528
|
+
|
|
20529
|
+
| Field | Required | Description |
|
|
20530
|
+
|-------|----------|-------------|
|
|
20531
|
+
| \\\`tool\\\` | Yes | Built-in or custom tool name |
|
|
20532
|
+
| \\\`args\\\` | Yes | Arguments (supports \\\`{{template}}\\\` variables) |
|
|
20533
|
+
| \\\`as\\\` | No | Store result under this name for later steps |
|
|
20534
|
+
|
|
20535
|
+
### Template Variables
|
|
20536
|
+
|
|
20537
|
+
Use \\\`{{...}}\\\` in action args to reference trigger context and previous step results:
|
|
20538
|
+
|
|
20539
|
+
| Variable | Description |
|
|
20540
|
+
|----------|-------------|
|
|
20541
|
+
| \\\`{{trigger.entityId}}\\\` | ID of the entity that changed |
|
|
20542
|
+
| \\\`{{trigger.entityType}}\\\` | Entity type slug |
|
|
20543
|
+
| \\\`{{trigger.action}}\\\` | \\\`"created"\\\`, \\\`"updated"\\\`, or \\\`"deleted"\\\` |
|
|
20544
|
+
| \\\`{{trigger.data.X}}\\\` | Entity data field (e.g. \\\`{{trigger.data.email}}\\\`) |
|
|
20545
|
+
| \\\`{{trigger.previousData.X}}\\\` | Previous value (updates/deletes only) |
|
|
20546
|
+
| \\\`{{steps.NAME.X}}\\\` | Result from a prior action with \\\`as: "NAME"\\\` |
|
|
20547
|
+
|
|
20548
|
+
### Conditions
|
|
20549
|
+
|
|
20550
|
+
Conditions use dot-notation path equality matching:
|
|
20551
|
+
\\\`\\\`\\\`typescript
|
|
20552
|
+
condition: {
|
|
20553
|
+
"data.status": "scheduled", // field must equal value
|
|
20554
|
+
"data.priority": "high" // all conditions must match (AND)
|
|
20555
|
+
}
|
|
20556
|
+
\\\`\\\`\\\`
|
|
20557
|
+
|
|
20558
|
+
### Execution Model
|
|
20559
|
+
|
|
20560
|
+
- **Async**: Triggers are scheduled after the mutation, keeping writes fast
|
|
20561
|
+
- **System actor**: Actions execute with full admin access (not the user's role)
|
|
20562
|
+
- **Fail-fast**: If any action fails, remaining actions are skipped
|
|
20563
|
+
- **Events**: Emits \\\`trigger.executed\\\` on success, \\\`trigger.failed\\\` on error
|
|
20564
|
+
- **Both paths**: Triggers fire from dashboard CRUD, agent tool calls, and API mutations
|
|
20565
|
+
|
|
20566
|
+
### Scaffold a new trigger
|
|
20567
|
+
|
|
20568
|
+
\\\`\\\`\\\`bash
|
|
20569
|
+
struere add trigger my-trigger
|
|
20570
|
+
\\\`\\\`\\\`
|
|
20571
|
+
|
|
20572
|
+
Creates \\\`triggers/my-trigger.ts\\\` with a starter template.
|
|
20573
|
+
|
|
20399
20574
|
## Built-in Tools Reference
|
|
20400
20575
|
|
|
20401
20576
|
### Entity Tools
|
|
@@ -20452,6 +20627,93 @@ Events are immutable audit logs. Use for analytics, debugging, compliance.
|
|
|
20452
20627
|
|
|
20453
20628
|
Jobs run asynchronously with retry logic. Use for: emails, notifications, data sync.
|
|
20454
20629
|
|
|
20630
|
+
### Calendar Tools
|
|
20631
|
+
|
|
20632
|
+
Requires a connected Google Calendar (via Settings > Integrations). The \`userId\` must be a user with a linked Google account.
|
|
20633
|
+
|
|
20634
|
+
\`\`\`typescript
|
|
20635
|
+
// calendar.list - List events in a time range
|
|
20636
|
+
{ userId: "user_abc", timeMin: "2024-01-01T00:00:00Z", timeMax: "2024-01-31T23:59:59Z", maxResults: 50 }
|
|
20637
|
+
|
|
20638
|
+
// calendar.create - Create a calendar event
|
|
20639
|
+
{
|
|
20640
|
+
userId: "user_abc",
|
|
20641
|
+
summary: "Session with Student",
|
|
20642
|
+
startTime: "2024-01-15T10:00:00Z",
|
|
20643
|
+
endTime: "2024-01-15T11:00:00Z",
|
|
20644
|
+
description: "Weekly tutoring session", // optional
|
|
20645
|
+
attendees: ["student@example.com"], // optional
|
|
20646
|
+
timeZone: "America/New_York" // optional
|
|
20647
|
+
}
|
|
20648
|
+
|
|
20649
|
+
// calendar.update - Update an existing event
|
|
20650
|
+
{ userId: "user_abc", eventId: "evt_123", summary: "Updated title", startTime: "2024-01-15T11:00:00Z" }
|
|
20651
|
+
|
|
20652
|
+
// calendar.delete - Delete a calendar event
|
|
20653
|
+
{ userId: "user_abc", eventId: "evt_123" }
|
|
20654
|
+
|
|
20655
|
+
// calendar.freeBusy - Check availability
|
|
20656
|
+
{ userId: "user_abc", timeMin: "2024-01-15T00:00:00Z", timeMax: "2024-01-15T23:59:59Z" }
|
|
20657
|
+
// Returns: { busy: [{ start: "...", end: "..." }, ...] }
|
|
20658
|
+
\`\`\`
|
|
20659
|
+
|
|
20660
|
+
Calendar tools work in both agent tool calls and trigger actions. Example trigger:
|
|
20661
|
+
\`\`\`typescript
|
|
20662
|
+
defineTrigger({
|
|
20663
|
+
name: "Add Session to Calendar",
|
|
20664
|
+
slug: "add-session-to-calendar",
|
|
20665
|
+
on: { entityType: "session", action: "created" },
|
|
20666
|
+
actions: [
|
|
20667
|
+
{
|
|
20668
|
+
tool: "calendar.create",
|
|
20669
|
+
args: {
|
|
20670
|
+
userId: "{{trigger.data.teacherId}}",
|
|
20671
|
+
summary: "Session: {{trigger.data.studentName}}",
|
|
20672
|
+
startTime: "{{trigger.data.startTime}}",
|
|
20673
|
+
endTime: "{{trigger.data.endTime}}"
|
|
20674
|
+
},
|
|
20675
|
+
as: "calendarEvent"
|
|
20676
|
+
}
|
|
20677
|
+
]
|
|
20678
|
+
})
|
|
20679
|
+
\`\`\`
|
|
20680
|
+
|
|
20681
|
+
### Agent Communication Tools
|
|
20682
|
+
|
|
20683
|
+
The \\\`agent.chat\\\` tool lets agents delegate work to other agents within the same organization and environment. The calling agent sends a message to a target agent (by slug), waits for its response, and uses the result to continue its own execution.
|
|
20684
|
+
|
|
20685
|
+
\`\`\`typescript
|
|
20686
|
+
// agent.chat - Send a message to another agent
|
|
20687
|
+
{ agent: "billing-agent", message: "How many credits does guardian ent_abc have?", context: { guardianId: "ent_abc" } }
|
|
20688
|
+
// Returns: { response: "Guardian has 5 remaining credits...", threadId: "thread_xyz", agentSlug: "billing-agent", usage: {...} }
|
|
20689
|
+
\`\`\`
|
|
20690
|
+
|
|
20691
|
+
**Safety limits:**
|
|
20692
|
+
- **Depth limit**: Max 3 levels of agent-to-agent delegation (A\u2192B\u2192C allowed, A\u2192B\u2192C\u2192D rejected)
|
|
20693
|
+
- **Cycle detection**: An agent cannot call itself
|
|
20694
|
+
- **Per-agent iteration cap**: Each agent's LLM loop is independently limited to 10 steps
|
|
20695
|
+
|
|
20696
|
+
**How it works:**
|
|
20697
|
+
1. Caller agent invokes \\\`agent.chat\\\` with a target slug and message
|
|
20698
|
+
2. Target agent is resolved by slug within the same organization
|
|
20699
|
+
3. A new thread is created for the target agent (linked via shared \\\`conversationId\\\`)
|
|
20700
|
+
4. Target agent runs its own LLM loop with its own system prompt, tools, and permissions
|
|
20701
|
+
5. Response is returned as a tool result to the calling agent
|
|
20702
|
+
|
|
20703
|
+
**Example: Coordinator delegates to specialist**
|
|
20704
|
+
\`\`\`typescript
|
|
20705
|
+
// agents/coordinator.ts
|
|
20706
|
+
export default defineAgent({
|
|
20707
|
+
name: "Coordinator",
|
|
20708
|
+
slug: "coordinator",
|
|
20709
|
+
version: "0.1.0",
|
|
20710
|
+
systemPrompt: \\\\\\\`You coordinate between specialist agents.
|
|
20711
|
+
When asked about billing, delegate to the billing agent using agent.chat.
|
|
20712
|
+
When asked about scheduling, delegate to the scheduler agent.\\\\\\\`,
|
|
20713
|
+
tools: ["agent.chat", "entity.query", "event.emit"],
|
|
20714
|
+
})
|
|
20715
|
+
\`\`\`
|
|
20716
|
+
|
|
20455
20717
|
## Invoking Agents (API)
|
|
20456
20718
|
|
|
20457
20719
|
### Chat Endpoint
|
|
@@ -20654,6 +20916,29 @@ Always confirm what was created/updated.\\\`,
|
|
|
20654
20916
|
\`\`\`
|
|
20655
20917
|
`;
|
|
20656
20918
|
}
|
|
20919
|
+
function getTriggerTs(name, slug) {
|
|
20920
|
+
return `import { defineTrigger } from 'struere'
|
|
20921
|
+
|
|
20922
|
+
export default defineTrigger({
|
|
20923
|
+
name: "${name}",
|
|
20924
|
+
slug: "${slug}",
|
|
20925
|
+
on: {
|
|
20926
|
+
entityType: "ENTITY_TYPE_HERE",
|
|
20927
|
+
action: "created",
|
|
20928
|
+
},
|
|
20929
|
+
actions: [
|
|
20930
|
+
{
|
|
20931
|
+
tool: "event.emit",
|
|
20932
|
+
args: {
|
|
20933
|
+
eventType: "trigger.${slug}.fired",
|
|
20934
|
+
entityId: "{{trigger.entityId}}",
|
|
20935
|
+
payload: { triggeredBy: "${slug}" },
|
|
20936
|
+
},
|
|
20937
|
+
},
|
|
20938
|
+
],
|
|
20939
|
+
})
|
|
20940
|
+
`;
|
|
20941
|
+
}
|
|
20657
20942
|
|
|
20658
20943
|
// src/cli/utils/scaffold.ts
|
|
20659
20944
|
function ensureDir(filePath) {
|
|
@@ -20677,7 +20962,8 @@ function scaffoldProjectV2(cwd, options) {
|
|
|
20677
20962
|
"entity-types",
|
|
20678
20963
|
"roles",
|
|
20679
20964
|
"tools",
|
|
20680
|
-
"evals"
|
|
20965
|
+
"evals",
|
|
20966
|
+
"triggers"
|
|
20681
20967
|
];
|
|
20682
20968
|
for (const dir of directories) {
|
|
20683
20969
|
const dirPath = join3(cwd, dir);
|
|
@@ -20697,6 +20983,7 @@ function scaffoldProjectV2(cwd, options) {
|
|
|
20697
20983
|
"entity-types/index.ts": getIndexTs("entity-types"),
|
|
20698
20984
|
"roles/index.ts": getIndexTs("roles"),
|
|
20699
20985
|
"tools/index.ts": getToolsIndexTs(),
|
|
20986
|
+
"triggers/index.ts": getIndexTs("triggers"),
|
|
20700
20987
|
"evals/basic-agent-tests.eval.yaml": getExampleEvalYaml("my-agent")
|
|
20701
20988
|
};
|
|
20702
20989
|
for (const [relativePath, content] of Object.entries(files)) {
|
|
@@ -20782,6 +21069,24 @@ function scaffoldEval(cwd, name, slug, agentSlug = "my-agent") {
|
|
|
20782
21069
|
result.createdFiles.push(`evals/${fileName}`);
|
|
20783
21070
|
return result;
|
|
20784
21071
|
}
|
|
21072
|
+
function scaffoldTrigger(cwd, name, slug) {
|
|
21073
|
+
const result = {
|
|
21074
|
+
createdFiles: [],
|
|
21075
|
+
updatedFiles: []
|
|
21076
|
+
};
|
|
21077
|
+
const triggersDir = join3(cwd, "triggers");
|
|
21078
|
+
if (!existsSync3(triggersDir)) {
|
|
21079
|
+
mkdirSync2(triggersDir, { recursive: true });
|
|
21080
|
+
}
|
|
21081
|
+
const fileName = `${slug}.ts`;
|
|
21082
|
+
const filePath = join3(triggersDir, fileName);
|
|
21083
|
+
if (existsSync3(filePath)) {
|
|
21084
|
+
return result;
|
|
21085
|
+
}
|
|
21086
|
+
writeFileSync3(filePath, getTriggerTs(name, slug));
|
|
21087
|
+
result.createdFiles.push(`triggers/${fileName}`);
|
|
21088
|
+
return result;
|
|
21089
|
+
}
|
|
20785
21090
|
|
|
20786
21091
|
// src/cli/commands/init.ts
|
|
20787
21092
|
async function runInit(cwd, selectedOrg) {
|
|
@@ -20985,7 +21290,8 @@ async function loadAllResources(cwd) {
|
|
|
20985
21290
|
}
|
|
20986
21291
|
const { suites: evalSuites, errors: evalErrors } = loadAllEvalSuites(join4(cwd, "evals"));
|
|
20987
21292
|
errors2.push(...evalErrors);
|
|
20988
|
-
|
|
21293
|
+
const triggers = await loadAllTriggers(join4(cwd, "triggers"));
|
|
21294
|
+
return { agents, entityTypes, roles, customTools, evalSuites, triggers, errors: errors2 };
|
|
20989
21295
|
}
|
|
20990
21296
|
async function loadAllAgents(dir) {
|
|
20991
21297
|
if (!existsSync4(dir)) {
|
|
@@ -21093,13 +21399,24 @@ function loadAllEvalSuites(dir) {
|
|
|
21093
21399
|
}
|
|
21094
21400
|
return { suites, errors: errors2 };
|
|
21095
21401
|
}
|
|
21402
|
+
async function loadAllTriggers(dir) {
|
|
21403
|
+
if (!existsSync4(dir)) {
|
|
21404
|
+
return [];
|
|
21405
|
+
}
|
|
21406
|
+
const indexPath = join4(dir, "index.ts");
|
|
21407
|
+
if (existsSync4(indexPath)) {
|
|
21408
|
+
return loadFromIndex(indexPath);
|
|
21409
|
+
}
|
|
21410
|
+
return loadFromDirectory(dir);
|
|
21411
|
+
}
|
|
21096
21412
|
function getResourceDirectories(cwd) {
|
|
21097
21413
|
return {
|
|
21098
21414
|
agents: join4(cwd, "agents"),
|
|
21099
21415
|
entityTypes: join4(cwd, "entity-types"),
|
|
21100
21416
|
roles: join4(cwd, "roles"),
|
|
21101
21417
|
tools: join4(cwd, "tools"),
|
|
21102
|
-
evals: join4(cwd, "evals")
|
|
21418
|
+
evals: join4(cwd, "evals"),
|
|
21419
|
+
triggers: join4(cwd, "triggers")
|
|
21103
21420
|
};
|
|
21104
21421
|
}
|
|
21105
21422
|
|
|
@@ -21122,7 +21439,13 @@ var BUILTIN_TOOLS = [
|
|
|
21122
21439
|
"event.emit",
|
|
21123
21440
|
"event.query",
|
|
21124
21441
|
"job.enqueue",
|
|
21125
|
-
"job.status"
|
|
21442
|
+
"job.status",
|
|
21443
|
+
"calendar.list",
|
|
21444
|
+
"calendar.create",
|
|
21445
|
+
"calendar.update",
|
|
21446
|
+
"calendar.delete",
|
|
21447
|
+
"calendar.freeBusy",
|
|
21448
|
+
"agent.chat"
|
|
21126
21449
|
];
|
|
21127
21450
|
function extractSyncPayload(resources) {
|
|
21128
21451
|
const customToolsMap = new Map;
|
|
@@ -21135,7 +21458,9 @@ function extractSyncPayload(resources) {
|
|
|
21135
21458
|
slug: et.slug,
|
|
21136
21459
|
schema: et.schema,
|
|
21137
21460
|
searchFields: et.searchFields,
|
|
21138
|
-
displayConfig: et.displayConfig
|
|
21461
|
+
displayConfig: et.displayConfig,
|
|
21462
|
+
boundToRole: et.boundToRole,
|
|
21463
|
+
userIdField: et.userIdField
|
|
21139
21464
|
}));
|
|
21140
21465
|
const roles = resources.roles.map((role) => ({
|
|
21141
21466
|
name: role.name,
|
|
@@ -21178,7 +21503,20 @@ function extractSyncPayload(resources) {
|
|
|
21178
21503
|
finalAssertions: c.finalAssertions
|
|
21179
21504
|
}))
|
|
21180
21505
|
})) : undefined;
|
|
21181
|
-
|
|
21506
|
+
const triggers = resources.triggers.length > 0 ? resources.triggers.map((t) => ({
|
|
21507
|
+
name: t.name,
|
|
21508
|
+
slug: t.slug,
|
|
21509
|
+
description: t.description,
|
|
21510
|
+
entityType: t.on.entityType,
|
|
21511
|
+
action: t.on.action,
|
|
21512
|
+
condition: t.on.condition,
|
|
21513
|
+
actions: t.actions.map((a) => ({
|
|
21514
|
+
tool: a.tool,
|
|
21515
|
+
args: a.args,
|
|
21516
|
+
as: a.as
|
|
21517
|
+
}))
|
|
21518
|
+
})) : undefined;
|
|
21519
|
+
return { agents, entityTypes, roles, evalSuites, triggers };
|
|
21182
21520
|
}
|
|
21183
21521
|
function extractAgentPayload(agent, customToolsMap) {
|
|
21184
21522
|
let systemPrompt;
|
|
@@ -21241,7 +21579,13 @@ function getBuiltinToolDescription(name) {
|
|
|
21241
21579
|
"event.emit": "Emit a custom event for audit logging",
|
|
21242
21580
|
"event.query": "Query historical events with optional filters",
|
|
21243
21581
|
"job.enqueue": "Schedule a background job to run later",
|
|
21244
|
-
"job.status": "Get the status of a scheduled job"
|
|
21582
|
+
"job.status": "Get the status of a scheduled job",
|
|
21583
|
+
"calendar.list": "List Google Calendar events for a user within a time range",
|
|
21584
|
+
"calendar.create": "Create a Google Calendar event on a user's calendar",
|
|
21585
|
+
"calendar.update": "Update an existing Google Calendar event",
|
|
21586
|
+
"calendar.delete": "Delete a Google Calendar event",
|
|
21587
|
+
"calendar.freeBusy": "Check free/busy availability on a user's Google Calendar",
|
|
21588
|
+
"agent.chat": "Send a message to another agent and get its response"
|
|
21245
21589
|
};
|
|
21246
21590
|
return descriptions[name] || name;
|
|
21247
21591
|
}
|
|
@@ -21347,6 +21691,69 @@ function getBuiltinToolParameters(name) {
|
|
|
21347
21691
|
id: { type: "string", description: "The job ID to check" }
|
|
21348
21692
|
},
|
|
21349
21693
|
required: ["id"]
|
|
21694
|
+
},
|
|
21695
|
+
"calendar.list": {
|
|
21696
|
+
type: "object",
|
|
21697
|
+
properties: {
|
|
21698
|
+
userId: { type: "string", description: "User ID (Convex or Clerk) whose calendar to query" },
|
|
21699
|
+
timeMin: { type: "string", description: "Start of time range (ISO 8601 datetime)" },
|
|
21700
|
+
timeMax: { type: "string", description: "End of time range (ISO 8601 datetime)" },
|
|
21701
|
+
maxResults: { type: "number", description: "Maximum number of events to return" }
|
|
21702
|
+
},
|
|
21703
|
+
required: ["userId", "timeMin", "timeMax"]
|
|
21704
|
+
},
|
|
21705
|
+
"calendar.create": {
|
|
21706
|
+
type: "object",
|
|
21707
|
+
properties: {
|
|
21708
|
+
userId: { type: "string", description: "User ID (Convex or Clerk) whose calendar to create the event on" },
|
|
21709
|
+
summary: { type: "string", description: "Event title" },
|
|
21710
|
+
startTime: { type: "string", description: "Event start time (ISO 8601 datetime)" },
|
|
21711
|
+
endTime: { type: "string", description: "Event end time (ISO 8601 datetime)" },
|
|
21712
|
+
description: { type: "string", description: "Event description" },
|
|
21713
|
+
attendees: { type: "array", items: { type: "string" }, description: "List of attendee email addresses" },
|
|
21714
|
+
timeZone: { type: "string", description: 'Time zone (e.g., "America/Santiago")' }
|
|
21715
|
+
},
|
|
21716
|
+
required: ["userId", "summary", "startTime", "endTime"]
|
|
21717
|
+
},
|
|
21718
|
+
"calendar.update": {
|
|
21719
|
+
type: "object",
|
|
21720
|
+
properties: {
|
|
21721
|
+
userId: { type: "string", description: "User ID (Convex or Clerk) whose calendar contains the event" },
|
|
21722
|
+
eventId: { type: "string", description: "Google Calendar event ID to update" },
|
|
21723
|
+
summary: { type: "string", description: "New event title" },
|
|
21724
|
+
startTime: { type: "string", description: "New start time (ISO 8601 datetime)" },
|
|
21725
|
+
endTime: { type: "string", description: "New end time (ISO 8601 datetime)" },
|
|
21726
|
+
description: { type: "string", description: "New event description" },
|
|
21727
|
+
attendees: { type: "array", items: { type: "string" }, description: "Updated list of attendee emails" },
|
|
21728
|
+
status: { type: "string", description: "Event status (confirmed, tentative, cancelled)" }
|
|
21729
|
+
},
|
|
21730
|
+
required: ["userId", "eventId"]
|
|
21731
|
+
},
|
|
21732
|
+
"calendar.delete": {
|
|
21733
|
+
type: "object",
|
|
21734
|
+
properties: {
|
|
21735
|
+
userId: { type: "string", description: "User ID (Convex or Clerk) whose calendar contains the event" },
|
|
21736
|
+
eventId: { type: "string", description: "Google Calendar event ID to delete" }
|
|
21737
|
+
},
|
|
21738
|
+
required: ["userId", "eventId"]
|
|
21739
|
+
},
|
|
21740
|
+
"calendar.freeBusy": {
|
|
21741
|
+
type: "object",
|
|
21742
|
+
properties: {
|
|
21743
|
+
userId: { type: "string", description: "User ID (Convex or Clerk) whose availability to check" },
|
|
21744
|
+
timeMin: { type: "string", description: "Start of time range (ISO 8601 datetime)" },
|
|
21745
|
+
timeMax: { type: "string", description: "End of time range (ISO 8601 datetime)" }
|
|
21746
|
+
},
|
|
21747
|
+
required: ["userId", "timeMin", "timeMax"]
|
|
21748
|
+
},
|
|
21749
|
+
"agent.chat": {
|
|
21750
|
+
type: "object",
|
|
21751
|
+
properties: {
|
|
21752
|
+
agent: { type: "string", description: "Target agent slug to communicate with" },
|
|
21753
|
+
message: { type: "string", description: "The message to send to the agent" },
|
|
21754
|
+
context: { type: "object", description: "Optional context data to pass to the target agent" }
|
|
21755
|
+
},
|
|
21756
|
+
required: ["agent", "message"]
|
|
21350
21757
|
}
|
|
21351
21758
|
};
|
|
21352
21759
|
return schemas[name] || { type: "object", properties: {} };
|
|
@@ -21485,7 +21892,7 @@ var devCommand = new Command("dev").description("Sync all resources to developme
|
|
|
21485
21892
|
spinner.start("Loading resources");
|
|
21486
21893
|
try {
|
|
21487
21894
|
const resources = await loadAllResources(cwd);
|
|
21488
|
-
spinner.succeed(`Loaded ${resources.agents.length} agents, ${resources.entityTypes.length} entity types, ${resources.roles.length} roles, ${resources.customTools.length} custom tools, ${resources.evalSuites.length} eval suites`);
|
|
21895
|
+
spinner.succeed(`Loaded ${resources.agents.length} agents, ${resources.entityTypes.length} entity types, ${resources.roles.length} roles, ${resources.customTools.length} custom tools, ${resources.evalSuites.length} eval suites, ${resources.triggers.length} triggers`);
|
|
21489
21896
|
for (const err of resources.errors) {
|
|
21490
21897
|
console.log(source_default.red(" \u2716"), err);
|
|
21491
21898
|
}
|
|
@@ -21544,6 +21951,7 @@ var devCommand = new Command("dev").description("Sync all resources to developme
|
|
|
21544
21951
|
dirs.roles,
|
|
21545
21952
|
dirs.tools,
|
|
21546
21953
|
dirs.evals,
|
|
21954
|
+
dirs.triggers,
|
|
21547
21955
|
join5(cwd, "struere.config.ts")
|
|
21548
21956
|
].filter((p) => existsSync5(p));
|
|
21549
21957
|
const watcher = import_chokidar.default.watch(watchPaths, {
|
|
@@ -22513,6 +22921,17 @@ var addCommand = new Command("add").description("Scaffold a new resource").argum
|
|
|
22513
22921
|
console.log(source_default.yellow("Eval suite already exists:"), `evals/${slug}.eval.yaml`);
|
|
22514
22922
|
}
|
|
22515
22923
|
break;
|
|
22924
|
+
case "trigger":
|
|
22925
|
+
result = scaffoldTrigger(cwd, displayName, slug);
|
|
22926
|
+
if (result.createdFiles.length > 0) {
|
|
22927
|
+
console.log(source_default.green("\u2713"), `Created trigger "${displayName}"`);
|
|
22928
|
+
for (const file of result.createdFiles) {
|
|
22929
|
+
console.log(source_default.gray(" \u2192"), file);
|
|
22930
|
+
}
|
|
22931
|
+
} else {
|
|
22932
|
+
console.log(source_default.yellow("Trigger already exists:"), `triggers/${slug}.ts`);
|
|
22933
|
+
}
|
|
22934
|
+
break;
|
|
22516
22935
|
default:
|
|
22517
22936
|
console.log(source_default.red("Unknown resource type:"), type);
|
|
22518
22937
|
console.log();
|
|
@@ -22521,6 +22940,7 @@ var addCommand = new Command("add").description("Scaffold a new resource").argum
|
|
|
22521
22940
|
console.log(source_default.gray(" -"), source_default.cyan("entity-type"), "- Create an entity type schema");
|
|
22522
22941
|
console.log(source_default.gray(" -"), source_default.cyan("role"), "- Create a role with permissions");
|
|
22523
22942
|
console.log(source_default.gray(" -"), source_default.cyan("eval"), "- Create an eval suite (YAML)");
|
|
22943
|
+
console.log(source_default.gray(" -"), source_default.cyan("trigger"), "- Create an entity trigger");
|
|
22524
22944
|
console.log();
|
|
22525
22945
|
process.exit(1);
|
|
22526
22946
|
}
|
|
@@ -23076,7 +23496,7 @@ var pullCommand = new Command("pull").description("Pull remote resources to loca
|
|
|
23076
23496
|
// package.json
|
|
23077
23497
|
var package_default = {
|
|
23078
23498
|
name: "struere",
|
|
23079
|
-
version: "0.5.
|
|
23499
|
+
version: "0.5.17",
|
|
23080
23500
|
description: "Build, test, and deploy AI agents",
|
|
23081
23501
|
keywords: [
|
|
23082
23502
|
"ai",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,UAAU,SAqHnB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,eAAO,MAAM,UAAU,SAgSnB,CAAA"}
|