jat-feedback 2.0.1 → 3.0.0

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/README.md CHANGED
@@ -6,7 +6,7 @@ Reports are stored in your Supabase database. The JAT ingest daemon polls for ne
6
6
 
7
7
  ```
8
8
  User clicks "Report Bug" → Widget captures context → POST /api/feedback/report
9
- → Supabase feedback_reports table → JAT ingest daemon → JAT task created
9
+ → Supabase project_tasks table → JAT ingest daemon → JAT task created
10
10
  ```
11
11
 
12
12
  ## Install
@@ -128,6 +128,138 @@ ANTHROPIC_API_KEY=sk-ant-...
128
128
 
129
129
  The Agent tab appears automatically when `agent-proxy` is set. Without it, only the feedback form and history tabs are shown.
130
130
 
131
+ ### Page-Level Tool Registration
132
+
133
+ Register custom tools that the agent can call during its execution loop. Tools run client-side with full access to your app's state, auth context, and data — the LLM decides when to call them and reasons over the results.
134
+
135
+ #### `registerTools()` API Reference
136
+
137
+ ```typescript
138
+ interface ToolDefinition {
139
+ name: string;
140
+ description: string;
141
+ parameters: Record<string, unknown>; // JSON Schema object
142
+ handler: (args: Record<string, unknown>) => Promise<unknown>;
143
+ }
144
+
145
+ const widget = document.querySelector('jat-feedback');
146
+ widget.registerTools(tools: ToolDefinition[]): void
147
+ ```
148
+
149
+ | Field | Type | Description |
150
+ |-------|------|-------------|
151
+ | `name` | `string` | Unique tool name (snake_case). The LLM uses this to call the tool. |
152
+ | `description` | `string` | Tells the LLM what the tool does and when to use it. |
153
+ | `parameters` | `object` | JSON Schema describing the tool's arguments. Use `{ type: 'object', properties: {} }` for no-arg tools. |
154
+ | `handler` | `async (args) => any` | Runs client-side when the LLM calls the tool. Receives parsed args, returns any JSON-serializable value. |
155
+
156
+ **Behavior:**
157
+ - Multiple `registerTools()` calls **accumulate** — tools are added, not replaced
158
+ - Register tools before the user opens the Agent tab (typically in `onMount`)
159
+ - If a handler throws, the error message is returned to the LLM so it can recover gracefully
160
+ - Handlers have full access to the page's DOM, stores, and JS context
161
+
162
+ #### Example: Global Tools in SvelteKit
163
+
164
+ Register tools in your root `+layout.svelte` so they're available on every page. For page-specific tools, call `registerTools()` again in that page's layout or component — tools accumulate across calls.
165
+
166
+ ```svelte
167
+ <script lang="ts">
168
+ import { page } from "$app/stores"
169
+ import { onMount } from "svelte"
170
+
171
+ onMount(() => {
172
+ const widget = document.querySelector("jat-feedback")
173
+ if (!widget?.registerTools) return
174
+
175
+ widget.registerTools([
176
+ {
177
+ name: "get_current_user",
178
+ description: "Get the currently authenticated user profile",
179
+ parameters: { type: "object", properties: {} },
180
+ handler: async () => {
181
+ const session = $page.data.session
182
+ if (!session?.user) return { authenticated: false }
183
+ const u = session.user
184
+ return {
185
+ authenticated: true,
186
+ id: u.id,
187
+ email: u.email,
188
+ name: u.user_metadata?.full_name ?? null,
189
+ }
190
+ },
191
+ },
192
+ {
193
+ name: "get_current_route",
194
+ description: "Get the current page URL, pathname, and route parameters",
195
+ parameters: { type: "object", properties: {} },
196
+ handler: async () => ({
197
+ pathname: $page.url.pathname,
198
+ params: $page.params,
199
+ search: Object.fromEntries($page.url.searchParams),
200
+ }),
201
+ },
202
+ {
203
+ name: "get_page_data",
204
+ description: "Get data exposed by the current page's load function",
205
+ parameters: { type: "object", properties: {} },
206
+ handler: async () => {
207
+ const { supabase, session, ...rest } = $page.data
208
+ return rest
209
+ },
210
+ },
211
+ ])
212
+ })
213
+ </script>
214
+ ```
215
+
216
+ #### Example: Page-Specific Tools
217
+
218
+ Add tools that only make sense on a specific page:
219
+
220
+ ```svelte
221
+ <!-- src/routes/admin/reports/+page.svelte -->
222
+ <script lang="ts">
223
+ import { onMount } from "svelte"
224
+
225
+ onMount(() => {
226
+ const widget = document.querySelector("jat-feedback")
227
+ if (!widget?.registerTools) return
228
+
229
+ widget.registerTools([
230
+ {
231
+ name: "update_report_status",
232
+ description: "Update a feedback report status",
233
+ parameters: {
234
+ type: "object",
235
+ properties: {
236
+ report_id: { type: "string" },
237
+ status: { type: "string", enum: ["open", "in_progress", "resolved"] },
238
+ },
239
+ required: ["report_id", "status"],
240
+ },
241
+ handler: async (args) => {
242
+ const { error } = await supabase
243
+ .from("project_tasks")
244
+ .update({ status: args.status })
245
+ .eq("id", args.report_id)
246
+ if (error) throw new Error(error.message)
247
+ return { success: true }
248
+ },
249
+ },
250
+ ])
251
+ })
252
+ </script>
253
+ ```
254
+
255
+ #### How Tools Work
256
+
257
+ Tools are integrated into the page-agent's action loop:
258
+ - The LLM sees registered tools alongside built-in browser actions (click, type, scroll, etc.)
259
+ - Each agent step picks one action — either a browser action or a registered tool
260
+ - Tool results feed back to the LLM on the next step automatically
261
+ - If a handler throws, the error message is returned to the LLM so it can recover gracefully
262
+
131
263
  ### Error Handling
132
264
 
133
265
  The widget handles proxy errors gracefully:
@@ -438,7 +570,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
438
570
  const reporter = body.metadata?.reporter || {};
439
571
 
440
572
  const { data: row, error: insertError } = await supabase
441
- .from('feedback_reports')
573
+ .from('project_tasks')
442
574
  .insert({
443
575
  title: body.title.trim(),
444
576
  description: body.description?.trim() || '',
@@ -479,18 +611,21 @@ export const POST: RequestHandler = async ({ request, locals }) => {
479
611
 
480
612
  ### Step 3: Run the Supabase Migration
481
613
 
482
- The `feedback_reports` table schema is included in this package. Copy it into your migrations folder and push:
614
+ The `project_tasks` table schema is included in this package. Copy it into your migrations folder and push:
483
615
 
484
616
  ```bash
485
- # Copy the migration (rename to match your timestamp convention)
486
- cp node_modules/jat-feedback/supabase/migrations/1.0.0_feedback_reports.sql \
487
- supabase/migrations/$(date +%Y%m%d%H%M%S)_feedback_reports.sql
617
+ # Copy ALL migrations (rename to match your timestamp convention)
618
+ for f in node_modules/jat-feedback/supabase/migrations/*.sql; do
619
+ base=$(basename "$f" .sql)
620
+ cp "$f" "supabase/migrations/$(date +%Y%m%d%H%M%S)_feedback_${base}.sql"
621
+ sleep 1 # ensure unique timestamps
622
+ done
488
623
 
489
624
  # Push to Supabase
490
625
  supabase db push
491
626
  ```
492
627
 
493
- **When upgrading jat-feedback:** check `node_modules/jat-feedback/supabase/migrations/` for new versioned files (e.g. `1.1.0_*.sql`) and copy+apply any you haven't run yet.
628
+ **When upgrading jat-feedback:** check `node_modules/jat-feedback/supabase/migrations/` for new versioned files and copy+apply any you haven't run yet. The `3.0.0_rename_to_project_tasks.sql` migration renames `feedback_reports` to `project_tasks`.
494
629
 
495
630
  ### Step 4: Wire User Context
496
631
 
@@ -555,7 +690,7 @@ Add this entry to the `sources` array.
555
690
  "priority": 2,
556
691
  "labels": ["widget", "feedback"]
557
692
  },
558
- "table": "feedback_reports",
693
+ "table": "project_tasks",
559
694
  "statusColumn": "status",
560
695
  "statusNew": "submitted",
561
696
  "taskIdColumn": "jat_task_id",
@@ -586,7 +721,7 @@ Add this entry to the `sources` array.
586
721
  },
587
722
  "projectUrl": "https://YOUR_SUPABASE_PROJECT_ID.supabase.co",
588
723
  "secretName": "YOUR_PROJECT-supabase-service-role",
589
- "table": "feedback_reports",
724
+ "table": "project_tasks",
590
725
  "statusColumn": "status",
591
726
  "statusNew": "submitted",
592
727
  "taskIdColumn": "jat_task_id",
@@ -617,7 +752,7 @@ Add this entry to the `sources` array.
617
752
  "in_progress": "in_progress",
618
753
  "closed": "completed"
619
754
  },
620
- "referenceTable": "feedback_reports",
755
+ "referenceTable": "project_tasks",
621
756
  "referenceIdFrom": "item_id"
622
757
  },
623
758
  "actions": [
@@ -634,7 +769,7 @@ Add this entry to the `sources` array.
634
769
  "label": "View in Supabase",
635
770
  "description": "Open the original feedback report in Supabase dashboard",
636
771
  "type": "link",
637
- "urlTemplate": "{projectUrl}/project/default/editor/feedback_reports?filter=id%3Deq.{referenceId}",
772
+ "urlTemplate": "{projectUrl}/project/default/editor/project_tasks?filter=id%3Deq.{referenceId}",
638
773
  "icon": "external-link"
639
774
  }
640
775
  ]
@@ -649,7 +784,7 @@ The ingest daemon picks up config changes automatically (no restart needed).
649
784
 
650
785
  ### Step 6: Deploy the JAT Webhook Edge Function (for callbacks)
651
786
 
652
- The `jat-webhook` Supabase Edge Function receives status-change callbacks from JAT and updates your `feedback_reports` rows. It's included in this package — copy it into your project and deploy it.
787
+ The `jat-webhook` Supabase Edge Function receives status-change callbacks from JAT and updates your `project_tasks` rows. It's included in this package — copy it into your project and deploy it.
653
788
 
654
789
  ```bash
655
790
  # Copy the function into your project
@@ -657,11 +792,19 @@ mkdir -p supabase/functions/jat-webhook
657
792
  cp node_modules/jat-feedback/supabase/functions/jat-webhook/index.ts \
658
793
  supabase/functions/jat-webhook/index.ts
659
794
 
660
- # Deploy to Supabase
661
- supabase functions deploy jat-webhook
795
+ # Deploy to Supabase (--no-verify-jwt required for service role key auth)
796
+ supabase functions deploy jat-webhook --no-verify-jwt
662
797
  ```
663
798
 
664
- The function uses `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` — both are injected automatically by Supabase, no extra configuration needed.
799
+ The function uses `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` — both are injected automatically by Supabase.
800
+
801
+ **If callbacks fail with "Invalid authorization":** Newer Supabase projects use an `sb_secret_` format for the runtime `SUPABASE_SERVICE_ROLE_KEY`, which doesn't match the JWT service role key that JAT sends. Set a custom secret:
802
+
803
+ ```bash
804
+ supabase secrets set JAT_WEBHOOK_SECRET="eyJhbG..." # paste your JWT service role key from API settings
805
+ ```
806
+
807
+ The function checks `JAT_WEBHOOK_SECRET` first, falling back to `SUPABASE_SERVICE_ROLE_KEY`.
665
808
 
666
809
  **Skip this step** if you don't need bidirectional status sync (i.e., you only want JAT to ingest reports, not push status back to Supabase).
667
810
 
@@ -677,7 +820,7 @@ jat ingest status
677
820
  # → Should list your project's feedback source
678
821
 
679
822
  # Submit a test report via the widget, then check:
680
- # 1. Row appears in feedback_reports table
823
+ # 1. Row appears in project_tasks table
681
824
  # 2. JAT task gets created after next poll cycle (pollInterval seconds)
682
825
  ```
683
826
 
@@ -702,14 +845,22 @@ jat ingest status
702
845
 
703
846
  ## Column Reference
704
847
 
705
- The `feedback_reports` table columns used by the pipeline:
706
-
707
- | Column | Type | Purpose |
708
- |--------|------|---------|
709
- | `status` | TEXT | Lifecycle: `submitted` → `in_progress` → `completed` → `accepted` \| `rejected` |
710
- | `jat_task_id` | TEXT | JAT task ID written back after ingest (e.g., `myapp-abc`) |
711
- | `rejection_reason` | TEXT | User-provided reason when rejecting a completed report |
712
- | `dev_notes` | TEXT | Developer notes pushed back via callback |
848
+ The `project_tasks` table columns used by the pipeline:
849
+
850
+ | Column | Type | Since | Purpose |
851
+ |--------|------|-------|---------|
852
+ | `status` | TEXT | 1.0.0 | Lifecycle: `submitted` → `in_progress` → `completed` → `accepted` \| `rejected` |
853
+ | `jat_task_id` | TEXT | 1.0.0 | JAT task ID written back after ingest (e.g., `myapp-abc`) |
854
+ | `rejection_reason` | TEXT | 1.0.0 | User-provided reason when rejecting a completed report |
855
+ | `dev_notes` | TEXT | 1.0.0 | Developer notes pushed back via callback |
856
+ | `source_type` | TEXT | 3.0.0 | Original `type` column renamed — `bug`, `enhancement`, `other` |
857
+ | `source` | TEXT | 3.0.0 | Where the item came from: `feedback`, `jat`, `manual` |
858
+ | `issue_type` | TEXT | 3.0.0 | Classification: `bug`, `feature`, `task`, `epic` |
859
+ | `assignee` | TEXT | 3.0.0 | Assigned agent or person |
860
+ | `due_date` | TIMESTAMPTZ | 3.0.0 | Due date for the task |
861
+ | `labels` | TEXT[] | 3.0.0 | Flexible categorization labels |
862
+ | `parent_id` | UUID | 3.0.0 | Self-referential parent for hierarchical tasks |
863
+ | `updated_at` | TIMESTAMPTZ | 3.0.0 | Auto-updated timestamp |
713
864
 
714
865
  ## Upgrading
715
866
 
@@ -746,7 +897,7 @@ supabase db push
746
897
  cp node_modules/jat-feedback/supabase/functions/jat-webhook/index.ts \
747
898
  supabase/functions/jat-webhook/index.ts
748
899
 
749
- supabase functions deploy jat-webhook
900
+ supabase functions deploy jat-webhook --no-verify-jwt
750
901
  ```
751
902
 
752
903
  ## Versioning