@hailer/mcp 1.3.14 → 1.3.23
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/.claude/skills/create-and-publish-app/SKILL.md +44 -56
- package/.claude/skills/hailer-app-builder/SKILL.md +414 -970
- package/.claude/skills/hailer-app-primitives/SKILL.md +742 -0
- package/.claude/skills/hailer-apps-pictures/SKILL.md +191 -87
- package/.claude/skills/hailer-design-patterns/SKILL.md +317 -0
- package/.claude/skills/hailer-design-system/SKILL.md +202 -149
- package/.claude/skills/hailer-workflow-archetypes/SKILL.md +301 -0
- package/.claude/skills/insight-join-patterns/SKILL.md +313 -0
- package/.claude/skills/publish-hailer-app/SKILL.md +211 -0
- package/.claude/skills/sdk-activity-patterns/SKILL.md +257 -105
- package/.claude/skills/sdk-function-fields/SKILL.md +253 -492
- package/.claude/skills/sdk-insight-calculations/SKILL.md +364 -0
- package/.claude/skills/sdk-insight-queries/SKILL.md +192 -397
- package/.claude/skills/sdk-ws-config-skill/SKILL.md +265 -720
- package/.claude/skills/tool-response-verification/SKILL.md +143 -0
- package/CLAUDE.md +50 -19
- package/dist/bot/bot.d.ts.map +1 -1
- package/dist/bot/bot.js +26 -34
- package/dist/bot/bot.js.map +1 -1
- package/dist/bot/services/helper-prompt.d.ts +1 -1
- package/dist/bot/services/helper-prompt.d.ts.map +1 -1
- package/dist/bot/services/helper-prompt.js +62 -82
- package/dist/bot/services/helper-prompt.js.map +1 -1
- package/dist/bot/services/system-prompt.js +4 -4
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/mcp/hailer-rpc.d.ts +1 -0
- package/dist/mcp/hailer-rpc.d.ts.map +1 -1
- package/dist/mcp/hailer-rpc.js +4 -0
- package/dist/mcp/hailer-rpc.js.map +1 -1
- package/dist/mcp/tools/activity.d.ts.map +1 -1
- package/dist/mcp/tools/activity.js +8 -2
- package/dist/mcp/tools/activity.js.map +1 -1
- package/dist/mcp/tools/app-core.d.ts.map +1 -1
- package/dist/mcp/tools/app-core.js +6 -3
- package/dist/mcp/tools/app-core.js.map +1 -1
- package/dist/mcp/tools/app-marketplace.d.ts.map +1 -1
- package/dist/mcp/tools/app-marketplace.js +5 -1
- package/dist/mcp/tools/app-marketplace.js.map +1 -1
- package/dist/mcp/webhook-handler.d.ts.map +1 -1
- package/dist/mcp/webhook-handler.js +27 -0
- package/dist/mcp/webhook-handler.js.map +1 -1
- package/dist/public-chat/graduate.d.ts.map +1 -1
- package/dist/public-chat/graduate.js +153 -53
- package/dist/public-chat/graduate.js.map +1 -1
- package/dist/public-chat/rate-limit.js +1 -1
- package/dist/public-chat/rate-limit.js.map +1 -1
- package/dist/public-chat/studio-prewarm.js +2 -2
- package/dist/public-chat/studio-prewarm.js.map +1 -1
- package/dist/public-chat/system-prompt.d.ts.map +1 -1
- package/dist/public-chat/system-prompt.js +41 -25
- package/dist/public-chat/system-prompt.js.map +1 -1
- package/package.json +1 -1
- package/.claude/skills/hailer-project-protocol/SKILL.md +0 -398
- package/.opencode/package-lock.json +0 -117
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tool-response-verification
|
|
3
|
+
description: Verify MCP tool execution results before reporting success. Load when creating activities, updating activities, listing activities, or any MCP tool call where a silent failure could cause incorrect reporting. Covers the two distinct response envelopes (MCP wire result vs agent delegation report), create vs update response shapes, error asymmetry, empty-list shape, and MCP connection error detection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tool Response Verification
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Ensure agents verify actual tool execution results before reporting success. Prevents fabricated responses when MCP servers are disconnected or tools fail silently.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Pattern 1: Always Check Tool Results
|
|
15
|
+
|
|
16
|
+
Every MCP tool call returns a result. Read it before proceeding.
|
|
17
|
+
|
|
18
|
+
## Pattern 2: Never Assume Success
|
|
19
|
+
|
|
20
|
+
If you didn't see confirmation in the result, it didn't happen.
|
|
21
|
+
|
|
22
|
+
## Pattern 3: Report Actual Errors
|
|
23
|
+
|
|
24
|
+
If a tool returned an error, report error status — don't fabricate success.
|
|
25
|
+
|
|
26
|
+
## Pattern 4: No Fabrication
|
|
27
|
+
|
|
28
|
+
Never claim "created 5 activities" if you didn't see 5 activity IDs returned.
|
|
29
|
+
|
|
30
|
+
## Pattern 5: Verification Checklist
|
|
31
|
+
|
|
32
|
+
Before returning success:
|
|
33
|
+
- Did the tool return a result (not an error)?
|
|
34
|
+
- Does the result contain expected data (IDs, counts, etc.)?
|
|
35
|
+
- Am I reporting data FROM the result, not data I expected?
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Pattern 6: Two Distinct Envelopes — Don't Confuse Them
|
|
40
|
+
|
|
41
|
+
**MCP tool wire result** — what the tool actually returns:
|
|
42
|
+
```
|
|
43
|
+
{ content: [{ type: "text", text: "..." }], isError?: boolean }
|
|
44
|
+
```
|
|
45
|
+
Success and error both arrive as `text` content. Errors are signalled by a ❌ prefix in the text (e.g. `"❌ Activity not found"`), not by a structured status field. Activity/discussion tools do not set `isError: true` — read the text to determine outcome.
|
|
46
|
+
|
|
47
|
+
**Agent delegation report** — what the agent returns to the orchestrator after verifying the tool result:
|
|
48
|
+
```json
|
|
49
|
+
{ "status": "success|error", "result": { ... }, "summary": "..." }
|
|
50
|
+
```
|
|
51
|
+
This `{status, result, summary}` shape is the agent's own output. It is NOT the MCP tool return value.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Pattern 7: Runtime-Verified Wire Shapes for Activity Tools
|
|
56
|
+
|
|
57
|
+
The following shapes are runtime-verified against testspace 2026-06-07.
|
|
58
|
+
|
|
59
|
+
### Success — create_activity (single and bulk)
|
|
60
|
+
|
|
61
|
+
Both single and bulk creates emit a fenced JSON block:
|
|
62
|
+
```json
|
|
63
|
+
{"created_ids":["<24-hex-id>", ...]}
|
|
64
|
+
```
|
|
65
|
+
Single create also includes a `discussionId` field alongside `created_ids`. There is NO prose-only success path for create — if you don't see `created_ids`, the create did not succeed.
|
|
66
|
+
|
|
67
|
+
### Success — update_activity (single and bulk)
|
|
68
|
+
|
|
69
|
+
Update success is **prose only** — there is NO `created_ids` on update responses.
|
|
70
|
+
|
|
71
|
+
- Single: `✅ Successfully updated activity <id>!` + `API Response: 1`
|
|
72
|
+
- Bulk: `🎉 Successfully updated N activities!` + `Total Updated: N`
|
|
73
|
+
|
|
74
|
+
### Error Envelope — Asymmetry Between create and update
|
|
75
|
+
|
|
76
|
+
Both create and update errors are prefixed with `❌`. There is no structured `isError`/`status` field on activity tool responses — read the text.
|
|
77
|
+
|
|
78
|
+
**create_activity errors are RICH:**
|
|
79
|
+
- 191 (field-level): full JSON `{"msg":"...","code":191,"details":{...},"debug":...}`
|
|
80
|
+
- Zod validation: structured `**Validation Error for create_activity**` block, e.g. `name: Activity name cannot be empty` / `workflowId: Required, phaseId: Required`
|
|
81
|
+
|
|
82
|
+
**update_activity errors are LOSSY:**
|
|
83
|
+
- Any rejection collapses to `❌ Error updating activity: [object Object]` — the underlying message is swallowed. Verify update outcomes via read-back (`show_activity_by_id`) rather than relying on the error text.
|
|
84
|
+
|
|
85
|
+
### Empty-List Shape
|
|
86
|
+
|
|
87
|
+
`list_activities` with zero results returns:
|
|
88
|
+
```
|
|
89
|
+
✅ Found 0 activities in workflow "X"
|
|
90
|
+
📊 PAGINATION INFO ... Activities on this page: 0
|
|
91
|
+
[]
|
|
92
|
+
```
|
|
93
|
+
A human-readable string + a bare `[]` — NOT a `{activities:[]}` JSON envelope. Do not flag a bare `[]` as a parse error or an offline-server symptom.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Pattern 8: Detect MCP Connection Errors
|
|
98
|
+
|
|
99
|
+
When an MCP server is offline, tools may return unexpected text or transport-level errors.
|
|
100
|
+
|
|
101
|
+
**Red flags in the text content:**
|
|
102
|
+
- "0 Workflows Found" / "Activities on this page: 0" when the workspace is known to have data AND transport-layer error strings are present
|
|
103
|
+
- Error strings containing: "connection", "ECONNREFUSED", "timeout", "unavailable", "ENOTFOUND"
|
|
104
|
+
|
|
105
|
+
**Note:** `describe_workflows` returns a text blob like `"📋 N Workflows Found"` — there is no `workflows: []` JSON array. Read the text for the count and workflow names.
|
|
106
|
+
|
|
107
|
+
**What to do:**
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"status": "error",
|
|
112
|
+
"result": { "tool": "tool_name", "error": "MCP server appears offline" },
|
|
113
|
+
"summary": "Cannot proceed: MCP server not responding"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Examples
|
|
120
|
+
|
|
121
|
+
### Correct — Verify Before Reporting
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
GOOD: Call create_activity → read result → if result.created_ids has entries → return success
|
|
125
|
+
GOOD: "Created customer with ID abc123" (ID from actual result)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Wrong — Fabricating Success
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
BAD: Call create_activity → immediately return {"status": "success", "created": 1}
|
|
132
|
+
BAD: "I created the customer" (without checking result)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Correct — Error Reporting
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"status": "error",
|
|
140
|
+
"result": { "tool": "create_activity", "error": "code 191: 'priority' must be a string" },
|
|
141
|
+
"summary": "Tool failed: field validation error"
|
|
142
|
+
}
|
|
143
|
+
```
|
package/CLAUDE.md
CHANGED
|
@@ -11,6 +11,12 @@ Remote = MCP tools for activities, discussions, calendar, insights, files, permi
|
|
|
11
11
|
|
|
12
12
|
Before any MCP call, ask: "Is this answerable from `workspace/` files or a CLI?" If yes, do that instead. (SDK-profile connections don't even serve the shadowed tools; if you can see them, you're on a general connection — the rule still applies.)
|
|
13
13
|
|
|
14
|
+
## Workflow, not dataset, for stage-based work
|
|
15
|
+
|
|
16
|
+
A "dataset" and a "workflow" are the **same backing entity** — the only difference is the `enableUnlinkedMode` flag in the workflow config. Unset/`false` = a phased workflow (activities live in phases and move between stages). `true` = a dataset (a flat list, activities detached from phase progression).
|
|
17
|
+
|
|
18
|
+
**If the brief involves phases, stages, statuses, a pipeline, or moving items between steps, build a phased workflow — leave `enableUnlinkedMode` unset (false).** Reserve datasets (`enableUnlinkedMode: true`) for flat reference data with no progression (contact lists, product catalogues). Why: when activities are spread across phases, generating an app that correctly displays records from ALL phases at once is error-prone and takes many retries — picking the right structure up front avoids the churn and wasted tokens.
|
|
19
|
+
|
|
14
20
|
## What Goes Where
|
|
15
21
|
|
|
16
22
|
| Need | Do this | Don't |
|
|
@@ -59,7 +65,7 @@ workspace/
|
|
|
59
65
|
├── templates/ # Document templates
|
|
60
66
|
└── <WorkflowName>_<id>/
|
|
61
67
|
├── fields.ts # Field definitions (type, label, key, options, required)
|
|
62
|
-
├── phases.ts # Phases (name, key, isInitial, isEndpoint,
|
|
68
|
+
├── phases.ts # Phases (name, key, isInitial, isEndpoint, possibleNextPhase)
|
|
63
69
|
├── main.ts # Workflow config
|
|
64
70
|
└── functions/ # Function field code (one file per function)
|
|
65
71
|
```
|
|
@@ -89,13 +95,27 @@ Always use `:force` — the non-force variants prompt interactively.
|
|
|
89
95
|
|--------|---------|-------|
|
|
90
96
|
| New entities | Omit `_id` — server assigns it | Don't add `_id` manually |
|
|
91
97
|
| After push | `npm run pull` to get server-assigned IDs | Don't assume local IDs are final |
|
|
92
|
-
| Function fields | `npm run fields-push:force`
|
|
98
|
+
| Function fields | `npm run fields-push:force` — function code + `functionVariables` push from `functions/` regardless of force | non-force only prompts on deletes and hangs agents |
|
|
93
99
|
| Enum imports | Verify after pull — identical hex suffixes can collide | Don't blindly trust auto-generated imports |
|
|
94
100
|
| `linkedfrom` fields | Don't work in isolated-vm; use `<` backlink dependency | Don't use in function fields |
|
|
95
101
|
| Function field code | Plain JavaScript only | Not TypeScript |
|
|
96
|
-
| Phase transitions |
|
|
102
|
+
| Phase transitions | Move with the target `phaseId` (hex or key) from `describe_workflows` / enums | Don't pass the phase name string — it's not resolved |
|
|
97
103
|
| Activity field values (MCP) | Date: Unix ms (`1730937600000`); Dropdown: exact string; ActivityLink: string ID; fields keyed by field ID, never label | Not ISO dates, not arrays, not field names |
|
|
98
104
|
|
|
105
|
+
### New-workflow pull-wipe guard
|
|
106
|
+
|
|
107
|
+
`npm run pull` after `npm run workflows-sync` **wipes** any locally-staged field/phase edits on other workflows. Safe sequence:
|
|
108
|
+
|
|
109
|
+
1. `npm run workflows-sync` → check CLI output for `✨ Created: N` (N ≥ 1). If N = 0, the create was a no-op — do NOT pull.
|
|
110
|
+
2. `npm run pull` — only after confirming the workflow was created.
|
|
111
|
+
3. Complete the new workflow end-to-end (fields-push → phases-push) before pulling for any other reason.
|
|
112
|
+
|
|
113
|
+
Never mix un-pushed field edits on existing workflows into the same batch as a new-workflow create-then-pull.
|
|
114
|
+
|
|
115
|
+
### No multi-select field types
|
|
116
|
+
|
|
117
|
+
Hailer fields hold **one value**. There is no multi-select for activitylink, dropdown (textpredefinedoptions), users, or teams. Writing `["id1", "id2"]` for any of these is a bug — it will silently fail or be rejected. To attach multiple linked activities, use multiple separate ActivityLink fields (or the inverse backlink). To assign multiple users, use multiple user fields.
|
|
118
|
+
|
|
99
119
|
## App Lifecycle
|
|
100
120
|
|
|
101
121
|
| Step | How |
|
|
@@ -126,25 +146,36 @@ Tools not in this list are either SDK-shadowed (see matrix above) or admin/dange
|
|
|
126
146
|
|
|
127
147
|
## Skills
|
|
128
148
|
|
|
129
|
-
|
|
149
|
+
Skills live in `.claude/skills/`. Load the relevant skill before starting that kind of work — it carries the patterns, gotchas, and correct formats for that domain.
|
|
150
|
+
|
|
151
|
+
### Skill routing
|
|
152
|
+
|
|
153
|
+
| Task / symptom | Load this skill |
|
|
154
|
+
|----------------|-----------------|
|
|
155
|
+
| Creating or editing workflows, fields, phases, teams, groups — or debugging push errors, field-not-visible issues, phase ordering | `sdk-ws-config-skill` |
|
|
156
|
+
| Writing or debugging any function (calculated) field; code 191 compile errors; null returns; cross-workflow aggregation | `sdk-function-fields` |
|
|
157
|
+
| Creating or updating activities via MCP; bulk create; field format questions; `createMany`/`updateMany`; silent write failures | `sdk-activity-patterns` |
|
|
158
|
+
| Writing or debugging any insight SQL query; timestamp unit confusion (seconds vs ms); reserved column names; NULL aggregates | `sdk-insight-queries` |
|
|
159
|
+
| Insight calculations beyond plain SUM/COUNT — weighted sums, CASE bucketing, conversion rates, date truncation, top-N, percentage of total | `sdk-insight-calculations` |
|
|
160
|
+
| Cross-workflow insight JOINs; NULL join results; ActivityLink display values; row multiplication from one-to-many | `insight-join-patterns` |
|
|
161
|
+
| Verifying MCP tool results; checking create/update actually succeeded; detecting silent failures | `tool-response-verification` |
|
|
162
|
+
| Building a Hailer app UI — components, hooks, reads/writes, v1↔v2 migration, ActivityLink shapes | `hailer-app-builder` |
|
|
163
|
+
| Scaffolding and publishing an app — `@hailer/create-app`, `prep-app`, publish scripts, auth, marketplace publish | `create-and-publish-app` |
|
|
164
|
+
| Theme, colors, Chakra tokens, icons, layout patterns | `hailer-design-system` |
|
|
165
|
+
| Adding images or media to an app | `hailer-apps-pictures` |
|
|
166
|
+
| Chakra UI primitives — Select, ConfirmDialog, date pickers, state machines, REST calls from app | `hailer-app-primitives` |
|
|
167
|
+
| Publish script flags, `--market`, `--create`, post-publish app registration | `publish-hailer-app` |
|
|
168
|
+
|
|
169
|
+
### Field-by-key resolver (apps)
|
|
130
170
|
|
|
131
|
-
|
|
132
|
-
|-------|------|
|
|
133
|
-
| `sdk-ws-config-skill` | Workflows, fields, phases, teams, groups |
|
|
134
|
-
| `sdk-function-fields` | Calculated fields, nameFunction |
|
|
135
|
-
| `sdk-activity-patterns` | Creating/updating activities via MCP |
|
|
136
|
-
| `sdk-insight-queries` | SQL insight queries |
|
|
137
|
-
| `hailer-app-builder` | Building Hailer apps (React/Chakra) |
|
|
138
|
-
| `hailer-design-system` | Theme, colors, icons, layout |
|
|
139
|
-
| `create-and-publish-app` | Scaffolding + publishing apps (dev/prod/marketplace) |
|
|
140
|
-
| `testing-patterns` | Vitest/playwright tests |
|
|
171
|
+
In app code, reference fields by their **key** via the generated field resolver — never hardcode hex field IDs. A field with `key: "status"` is accessible as `activity.fields.status` (with `returnFlat: true`) or via the resolver. This keeps apps workspace-portable if fields are recreated.
|
|
141
172
|
|
|
142
|
-
|
|
173
|
+
Fields without a `key` fall back to hex ID lookup. Assign meaningful keys when creating fields.
|
|
143
174
|
|
|
144
|
-
|
|
175
|
+
## Design before building
|
|
145
176
|
|
|
146
|
-
|
|
177
|
+
Before building a workspace, load `hailer-workflow-archetypes` to pick the structural shape (Register, Pipeline, Header+LineItems, etc.), then `hailer-design-patterns` for parent/child lifecycle, row progression, and integration patterns. Design the structure first — flat field-piles without archetype thinking cause expensive rework later.
|
|
147
178
|
|
|
148
|
-
|
|
179
|
+
## Build strategy
|
|
149
180
|
|
|
150
|
-
Build apps with a single agent + the `hailer-app-builder` / `create-and-publish-app` skills —
|
|
181
|
+
Build apps with a single agent (`agent-giuseppe-app-builder`) + the `hailer-app-builder` / `create-and-publish-app` skills — a focused agent dispatch is more efficient than multi-agent fan-out for app builds (no shared-contract prep, no cross-agent integration fixups).
|
package/dist/bot/bot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../src/bot/bot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,YAAY,EAAa,MAAM,sBAAsB,CAAC;AAwB/D,OAAO,EAAkC,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAEH,SAAS,EAMZ,MAAM,eAAe,CAAC;AAIvB,iEAAiE;AACjE,UAAU,aAAa;IACrB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7D;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AA2HD;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IACrB,UAAU,EAAE,MAAM;IAAS,WAAW,EAAE,MAAM;gBAA9C,UAAU,EAAE,MAAM,EAAS,WAAW,EAAE,MAAM;CAIpE;AA4KD,qBAAa,GAAG;IACZ,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAA4B;IAG/C,OAAO,CAAC,IAAI,CAAyC;IACrD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAqB;IAGzC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,aAAa,CAA0B;IAG/C,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAiC;IAEpD;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAIhC;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAM1C;IAGH,OAAO,CAAC,aAAa,CAA0D;IAC/E,OAAO,CAAC,qBAAqB,CAA6B;IAC1D,OAAO,CAAC,uBAAuB,CAA6B;IAC5D,OAAO,CAAC,sBAAsB,CAA6B;IAC3D,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,UAAU,CAAuB;gBAE7B,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU;IAqBlD,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,QAAQ,IAAI,MAAM,CAErB;IACD,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IACD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKpD,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI;IAKxD,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI;IAOjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoM5B;;;;;;;;;;KAUC;YACa,4BAA4B;IAoB1C;;;;;;;;;;KAUC;YACa,qBAAqB;
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../src/bot/bot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,YAAY,EAAa,MAAM,sBAAsB,CAAC;AAwB/D,OAAO,EAAkC,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAEH,SAAS,EAMZ,MAAM,eAAe,CAAC;AAIvB,iEAAiE;AACjE,UAAU,aAAa;IACrB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7D;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AA2HD;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IACrB,UAAU,EAAE,MAAM;IAAS,WAAW,EAAE,MAAM;gBAA9C,UAAU,EAAE,MAAM,EAAS,WAAW,EAAE,MAAM;CAIpE;AA4KD,qBAAa,GAAG;IACZ,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAA4B;IAG/C,OAAO,CAAC,IAAI,CAAyC;IACrD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAqB;IAGzC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,aAAa,CAA0B;IAG/C,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAiC;IAEpD;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAIhC;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAM1C;IAGH,OAAO,CAAC,aAAa,CAA0D;IAC/E,OAAO,CAAC,qBAAqB,CAA6B;IAC1D,OAAO,CAAC,uBAAuB,CAA6B;IAC5D,OAAO,CAAC,sBAAsB,CAA6B;IAC3D,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,UAAU,CAAuB;gBAE7B,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU;IAqBlD,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,IAAI,QAAQ,IAAI,MAAM,CAErB;IACD,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,SAAS,IAAI,OAAO,CAEvB;IACD,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IACD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKpD,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI;IAKxD,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI;IAOjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoM5B;;;;;;;;;;KAUC;YACa,4BAA4B;IAoB1C;;;;;;;;;;KAUC;YACa,qBAAqB;IAuNnC;;;;;;KAMC;IACK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B;;;;KAIC;IACD,OAAO,CAAC,mBAAmB;IA0BrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA0Bb,YAAY;YAiIZ,iBAAiB;YAoGjB,cAAc;IA4C5B,8FAA8F;IAC9F,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAA8H;YAEtJ,YAAY;IAqD1B,OAAO,CAAC,gBAAgB;YAsBV,UAAU;YAuJV,YAAY;IAqL1B,OAAO,CAAC,qBAAqB;YAmCf,sBAAsB;YAmJtB,qBAAqB;YAqBrB,cAAc;YA4Cd,oBAAoB;IAiBlC,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,iBAAiB;YAiBX,WAAW;IAazB,OAAO,CAAC,cAAc;IAOtB,oGAAoG;YACtF,uBAAuB;IAerC,OAAO,CAAC,eAAe;CAiB1B"}
|
package/dist/bot/bot.js
CHANGED
|
@@ -62,7 +62,6 @@ const operation_logger_1 = require("./operation-logger");
|
|
|
62
62
|
const services_1 = require("./services");
|
|
63
63
|
const bot_config_1 = require("../bot-config");
|
|
64
64
|
const logger_1 = require("../lib/logger");
|
|
65
|
-
const config_1 = require("../config");
|
|
66
65
|
// ===== CONSTANTS =====
|
|
67
66
|
/**
|
|
68
67
|
* Parse the optional `seedContext` field on the bot config — a JSON array
|
|
@@ -118,7 +117,7 @@ function parseSeedTurns(raw, log) {
|
|
|
118
117
|
if (typeof summary === 'string' && summary.length > 0) {
|
|
119
118
|
// Append explicit template names so the bot sees them clearly
|
|
120
119
|
const namesHint = templateNames.length > 0
|
|
121
|
-
? `\n\n[INSTALL THESE
|
|
120
|
+
? `\n\n[INSTALL THESE PRODUCTS BY NAME: ${templateNames.join(', ')}]`
|
|
122
121
|
: '';
|
|
123
122
|
return {
|
|
124
123
|
turns: [{ role: 'user', content: `[Demo conversation summary]\n${summary}${namesHint}` }],
|
|
@@ -674,7 +673,7 @@ class Bot {
|
|
|
674
673
|
accessLevel: this.config.accessLevel,
|
|
675
674
|
allowBotMessages: this.config.allowBotMessages,
|
|
676
675
|
});
|
|
677
|
-
const { turns: seedTurns, viewedSlides, templateIds } = parseSeedTurns(this.config.seedContext, this.logger);
|
|
676
|
+
const { turns: seedTurns, viewedSlides, templateIds, templateNames } = parseSeedTurns(this.config.seedContext, this.logger);
|
|
678
677
|
const hasSeed = seedTurns.length > 0;
|
|
679
678
|
// Map slide ids → short human labels for the prompt. Anything not in
|
|
680
679
|
// the map is dropped (defence against stale ids leaking through).
|
|
@@ -729,44 +728,35 @@ class Bot {
|
|
|
729
728
|
}
|
|
730
729
|
}
|
|
731
730
|
const templatesInstalledHint = installedTemplateNames.length > 0
|
|
732
|
-
? `\n\nIMPORTANT:
|
|
731
|
+
? `\n\nIMPORTANT: Everything the visitor chose during the demo has ALREADY been installed. Do NOT ask what they want or offer to install anything — it's done. Do NOT name specific products. Just say everything is installed and ready, and offer to show them around.`
|
|
733
732
|
: '';
|
|
734
733
|
// Only promise an automatic build when Studio session creation is
|
|
735
734
|
// configured for this deployment; otherwise nothing builds the
|
|
736
735
|
// workspace and the bot must not promise a build that never runs. The
|
|
737
736
|
// graduation flow gates createStudioSession on the same env var, so
|
|
738
737
|
// "build promised" matches "build attempted".
|
|
739
|
-
const studioBuilding = !!config_1.environment.STUDIO_SESSIONS_CREATE_URL;
|
|
740
738
|
const introInstruction = hasSeed
|
|
741
|
-
? (
|
|
742
|
-
? `You are being posted in your own activity discussion for the first time. The user just graduated from a public demo chat with you — the messages above are the conversation you both had there.
|
|
743
|
-
|
|
744
|
-
What this first message needs to do:
|
|
745
|
-
|
|
746
|
-
1. Greet them warmly and acknowledge you remember the demo. Be specific — name the thing they were exploring (e.g. "the plumbing-company job tracker you were sketching out" rather than "your business").
|
|
747
|
-
|
|
748
|
-
2. Tell them what's happening RIGHT NOW: based on that conversation, their workspace is being set up for them automatically — the workflow(s) to run that process, a few sample records so they can see it in action, and a custom app on top. It takes a couple of minutes. Do NOT offer to build it yourself and do NOT ask "want me to set this up?" — it is already being built. You are not the one building it; just let them know it's underway.
|
|
749
|
-
|
|
750
|
-
3. Tell them what comes next: as soon as the workflows are ready you'll walk them through their new workspace with a quick guided tour, so there's nothing they need to do yet — they can sit tight or keep chatting with you here.
|
|
751
|
-
|
|
752
|
-
4. Mention in passing that they can shape how you behave (tone, persona, language, even your picture) just by asking you here, and that account-level settings live in the AI Hub app.
|
|
753
|
-
|
|
754
|
-
Tone: conversational, friendly, reassuring. No section headers, no bullet lists. Keep it under ~150 words.`
|
|
755
|
-
: `You are being posted in your own activity discussion for the first time. The user just graduated from a public demo chat with you — the messages above are the conversation you both had there.
|
|
739
|
+
? (`You are being posted in your own activity discussion for the first time. The user just graduated from a public demo chat with you — the messages above are the conversation you both had there.
|
|
756
740
|
|
|
757
741
|
CRITICAL: This is a plain text greeting. No tool calls, no bot-action tags, no JSON, no XML, no code blocks. Just normal sentences.
|
|
758
742
|
|
|
759
743
|
Write exactly this structure:
|
|
760
|
-
1. "Welcome to Hailer!" — warm greeting, one sentence.
|
|
761
|
-
2. If a template was mentioned in the demo context: "I see you chose [template name] — shall I install it?" Ask for confirmation, nothing more.
|
|
762
|
-
3. If no template was mentioned: "What would you like to set up first?" — one sentence.
|
|
763
|
-
|
|
764
744
|
${installedTemplateNames.length > 0
|
|
765
|
-
|
|
766
|
-
|
|
745
|
+
? `Products were auto-installed. Say: "Welcome to Hailer! ${installedTemplateNames.join(', ')} ${installedTemplateNames.length === 1 ? 'has' : 'have'} been installed and ${installedTemplateNames.length === 1 ? 'is' : 'are'} ready to use — want me to show you around?"`
|
|
746
|
+
: templateNames.length > 0
|
|
747
|
+
? `Products were selected but not yet installed. Say: "Welcome to Hailer! I see you picked ${templateNames.join(', ')} — shall I install ${templateNames.length === 1 ? 'it' : 'them'} for you?"`
|
|
748
|
+
: `The user signed up without choosing anything. Say: "Welcome to Hailer! I noticed you haven't picked anything yet — no worries. Want me to find something from the marketplace that fits your needs, or would you like me to explain how things work here first?"`}
|
|
749
|
+
|
|
750
|
+
Under 60 words. No headers, no lists. Plain text only — no tool calls, no bot-action tags, no JSON.`)
|
|
751
|
+
: this.config.helperMode
|
|
752
|
+
? `You are being posted in your own activity discussion for the first time. This is a new user who just signed up — their workspace is empty.
|
|
753
|
+
|
|
754
|
+
CRITICAL: This is a plain text greeting. No tool calls, no bot-action tags, no JSON, no code blocks.
|
|
755
|
+
|
|
756
|
+
Say: "Welcome to Hailer! Your workspace is empty for now — I can help you set it up. Want me to find something from the marketplace that fits your needs, or would you like me to explain how things work here first?"
|
|
767
757
|
|
|
768
|
-
Under
|
|
769
|
-
|
|
758
|
+
Under 50 words. No headers, no lists.`
|
|
759
|
+
: `You are being posted in your own activity discussion for the first time. Introduce yourself briefly in your own voice.
|
|
770
760
|
|
|
771
761
|
CRITICAL: do NOT invent a backstory or claim to be a real person, celebrity, or fictional character based on your name alone. Your name was just chosen by the user — they may have meant a specific person/character, or they may have just liked the sound of it. If you don't have explicit persona instructions, acknowledge your name but be honest that you're a fresh assistant without a defined persona yet, and ask what kind of assistant they want you to be (or invite them to configure you).
|
|
772
762
|
|
|
@@ -1439,8 +1429,9 @@ Keep it short and conversational. No bullet lists, no headers.`;
|
|
|
1439
1429
|
results.push({ type: 'tool_result', tool_use_id: block.id, content: 'You are already responding in this discussion. Your text response will be posted automatically — do not use add_discussion_message for the current discussion. Use it only for OTHER discussions.', is_error: true });
|
|
1440
1430
|
continue;
|
|
1441
1431
|
}
|
|
1442
|
-
// Dedup cache: serve cached result for read-only tools (same sender + same args)
|
|
1443
|
-
|
|
1432
|
+
// Dedup cache: serve cached result for read-only tools (same sender + same args).
|
|
1433
|
+
// helperMode only — never alters the tool path for normal bots.
|
|
1434
|
+
if (this.config.helperMode && Bot.DEDUP_TOOLS.has(block.name)) {
|
|
1444
1435
|
const dedupKey = `${block.name}:${message.senderId}:${JSON.stringify(args)}`;
|
|
1445
1436
|
const cached = this.toolDedupCache.get(dedupKey);
|
|
1446
1437
|
if (cached) {
|
|
@@ -1498,12 +1489,13 @@ Keep it short and conversational. No bullet lists, no headers.`;
|
|
|
1498
1489
|
contentStr = `${contentStr.slice(0, MAX_TOOL_RESULT_CHARS)}\n\n[Tool result truncated. Original: ${originalLen} chars (~${Math.round(originalLen / 4)} tokens). Narrow your query: use 'fields' parameter, add filters, lower 'limit', or use run_insight with aggregate SQL.]`;
|
|
1499
1490
|
this.logger.warn('Tool result truncated', { tool: block.name, originalLen, truncatedTo: MAX_TOOL_RESULT_CHARS });
|
|
1500
1491
|
}
|
|
1501
|
-
// Invalidate dedup cache when a write tool executes
|
|
1502
|
-
if (Bot.WRITE_TOOLS_FOR_CACHE.has(block.name)) {
|
|
1492
|
+
// Invalidate dedup cache when a write tool executes (helperMode only)
|
|
1493
|
+
if (this.config.helperMode && Bot.WRITE_TOOLS_FOR_CACHE.has(block.name)) {
|
|
1503
1494
|
this.toolDedupCache.clear();
|
|
1504
1495
|
}
|
|
1505
|
-
// Store read-only results in dedup cache (post-filter, so permissions are baked in)
|
|
1506
|
-
|
|
1496
|
+
// Store read-only results in dedup cache (post-filter, so permissions are baked in).
|
|
1497
|
+
// helperMode only — never alters the tool path for normal bots.
|
|
1498
|
+
if (this.config.helperMode && Bot.DEDUP_TOOLS.has(block.name)) {
|
|
1507
1499
|
const dedupKey = `${block.name}:${message.senderId}:${JSON.stringify(args)}`;
|
|
1508
1500
|
this.toolDedupCache.set(dedupKey, contentStr);
|
|
1509
1501
|
}
|