@foldspace_npm/harness 0.1.13 → 0.1.15
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.md
CHANGED
|
@@ -64,6 +64,12 @@ current CLI contract — risk, prerequisites, effects, next step.
|
|
|
64
64
|
so and offer the next one. On an empty account the useful first action is
|
|
65
65
|
one that creates data - say so instead.
|
|
66
66
|
|
|
67
|
+
**Say when the test window is yours, and when it is theirs.** You and the
|
|
68
|
+
human share one Chrome window. Before you start looking at the app or testing
|
|
69
|
+
in it: *"I'm going to work in that Chrome window for a few minutes - please
|
|
70
|
+
leave it alone until I tell you it's ready."* When it is their turn: *"It's
|
|
71
|
+
ready. Try asking: <the question this experience answers>."*
|
|
72
|
+
|
|
67
73
|
Navigation, uploads, extraction and anything that writes are a later session.
|
|
68
74
|
|
|
69
75
|
### Ask as a choice, and ask almost nothing
|
|
@@ -76,7 +82,7 @@ question. Everything else — attach mode, folder, name, level — you **state a
|
|
|
76
82
|
move on**.
|
|
77
83
|
|
|
78
84
|
Then agree the experience in the customer's words, before creating anything:
|
|
79
|
-
*"Show my plan and credits needs one
|
|
85
|
+
*"Show my plan and credits needs one new action on your agent and one card to
|
|
80
86
|
show it in. Sound right?"*
|
|
81
87
|
|
|
82
88
|
## Find the call yourself
|
|
@@ -111,8 +117,13 @@ an assumption by quoting that file later.
|
|
|
111
117
|
|
|
112
118
|
## Build: objects first, code second
|
|
113
119
|
|
|
114
|
-
Four kinds of thing.
|
|
115
|
-
|
|
120
|
+
Four kinds of thing. With the customer, use **Foldspace's own words** for what
|
|
121
|
+
they will see in Agent Studio - **action**, **task agent**, **navigation**,
|
|
122
|
+
**publish** - and say what each does the first time you use it. Never invent a
|
|
123
|
+
substitute: no "skill", "ability", "capability" or "tool", and no "switch on"
|
|
124
|
+
for publish. "Skill" already means something else in Claude, and the customer
|
|
125
|
+
has seen "Actions" at sign-up and in Agent Studio - a new word breaks the link
|
|
126
|
+
to what they know. The action handler is yours: call it "the code behind it".
|
|
116
127
|
|
|
117
128
|
| Thing | Answers | Lives in | You write |
|
|
118
129
|
|---|---|---|---|
|
|
@@ -233,6 +244,15 @@ Do not report success without all six:
|
|
|
233
244
|
paragraph telling the copilot what to say — those live in Agent Studio.
|
|
234
245
|
Never return `ApiResult.detail` from `execute`; it is for the console.
|
|
235
246
|
Validate parameters and return sanitised errors.
|
|
247
|
+
**What goes back to the agent states what happened - it never says what to
|
|
248
|
+
do next.** A status is state: it succeeded, it failed and why (`reason`),
|
|
249
|
+
or it found nothing. "Refine your query", "try again" and "ask the user for
|
|
250
|
+
the full name" are instructions, and an instruction inside a tool response
|
|
251
|
+
can make the model fire another tool call on its own. What the agent does
|
|
252
|
+
next is decided by the action's instructions in Agent Studio.
|
|
253
|
+
**A search that finds nothing is a valid result, not a failure**:
|
|
254
|
+
`success: true`, the query, zero matches - *"No <records> match
|
|
255
|
+
'<query>'."* - and it stops there.
|
|
236
256
|
2. **`render` receives `execute`'s return value**, not the input params. A
|
|
237
257
|
widget that lacks the ids the card needs passes in isolation and fails in the
|
|
238
258
|
real chat. <https://docs.foldspace.ai/guides/in-chat-ui/>
|
|
@@ -269,6 +289,70 @@ Lint catches some of these in handler code; Agent Studio copy is on you.
|
|
|
269
289
|
- **Never send the user out of the host app.** No "open in <product>" button,
|
|
270
290
|
no pasted URLs — navigate with a route, same tab.
|
|
271
291
|
|
|
292
|
+
## How the agent looks and opens is configuration
|
|
293
|
+
|
|
294
|
+
Three layers: built-in defaults, then Agent Studio, then code - **and code
|
|
295
|
+
wins**. <https://docs.foldspace.ai/customize/configuration/>
|
|
296
|
+
|
|
297
|
+
- **Agent-wide conversation starters you can set yourself**, through the
|
|
298
|
+
Foldspace tools, and they carry over to the customer's real site. Once the
|
|
299
|
+
first action works, offer one starter that asks its question, so they can
|
|
300
|
+
click instead of type. `set_conversation_starters` **replaces the whole set
|
|
301
|
+
and clears whatever you leave out**: call `list_conversation_starters` first
|
|
302
|
+
and send back the full list with your one addition. It changes their
|
|
303
|
+
Foldspace account, so it needs their yes.
|
|
304
|
+
- **Page-specific starters and the bottom bar are only possible from code
|
|
305
|
+
today** - `setConversationStarters` (`null` restores Agent Studio's), and
|
|
306
|
+
`setConfiguration({ bottomBarSettings })` then `openBottomBar()`. Send one
|
|
307
|
+
whole settings group per call, as the docs do.
|
|
308
|
+
- **That code belongs where the product mounts the agent - in the customer's
|
|
309
|
+
own source.** In this project you do not have their source: you see their
|
|
310
|
+
product only through the test window. So this is their engineers' change, not
|
|
311
|
+
yours. Shipping it from this project's start-up code instead is a fallback for
|
|
312
|
+
a customer who cannot make the change, decided with Foldspace - not something
|
|
313
|
+
to reach for, and never in a first session.
|
|
314
|
+
- **An action's `execute` never calls `setConfiguration`**: a partial call from
|
|
315
|
+
one once collapsed the agent's panel to nothing.
|
|
316
|
+
|
|
317
|
+
If they ask for page-specific starters or the bottom bar, say what it takes in
|
|
318
|
+
one sentence and note it in `docs/app-profile.md` as a next step.
|
|
319
|
+
|
|
320
|
+
## Agentic UI components: what bites
|
|
321
|
+
|
|
322
|
+
An Agentic UI component is the card an action draws in the chat (`render`).
|
|
323
|
+
Each of these cost a real build.
|
|
324
|
+
|
|
325
|
+
- **A component that asks sets `awaitUserInput: true` - and then calling
|
|
326
|
+
`callback` is mandatory, on every path.** The agent is paused until it is
|
|
327
|
+
called: submitting, choosing "none of these" and closing the component all
|
|
328
|
+
end in `callback` (or `cancel()` when they abort), or the conversation hangs.
|
|
329
|
+
A component that only shows never sets the flag - it would hold the
|
|
330
|
+
conversation until the user clicked an acknowledgement nobody needed.
|
|
331
|
+
- **What a component sends back is the tool response: the data and the user's
|
|
332
|
+
choice, as fields**, with the state - chosen, declined, failed - and nothing
|
|
333
|
+
about what to do next (**Rules**, 1).
|
|
334
|
+
- **A view-only component's data does not reach the model.** For an action
|
|
335
|
+
that only shows something, the model is told just that *the information was
|
|
336
|
+
displayed to the end-user* - nothing `execute` returned, nothing the component
|
|
337
|
+
drew. So the component carries every fact, including the bad ones.
|
|
338
|
+
- **A failed or signed-out call is never drawn as zeros.** A signed-out response
|
|
339
|
+
often looks like a valid empty one: a 200 with zeros, nulls or an empty list.
|
|
340
|
+
Before you draw numbers, check that the response belongs to a signed-in user -
|
|
341
|
+
an id or a name that has to be there. If it does not, that is `signed_out`:
|
|
342
|
+
return it as a failure (`success: false`, `reason`) and draw that state with
|
|
343
|
+
`renderFailure`. A balance of 0 shown to someone who is signed out is a wrong
|
|
344
|
+
answer reported as a success.
|
|
345
|
+
- **Every path through `render` draws something.** An action that returns
|
|
346
|
+
without drawing leaves the slot spinning forever: nothing throws, the console
|
|
347
|
+
stays clean, and the action is recorded as succeeded. Only looking at it shows
|
|
348
|
+
the problem. Draw the empty or the failed state (`renderEmpty`,
|
|
349
|
+
`renderFailure`) - never nothing.
|
|
350
|
+
- **Totals and money are never computed by the model.** Compute them in the
|
|
351
|
+
action's code or in the component, from the API's own numbers, and show them
|
|
352
|
+
in the component. The action's instructions tell the model not to restate or
|
|
353
|
+
recompute them: a model that adds up line items will eventually add them up
|
|
354
|
+
wrong.
|
|
355
|
+
|
|
272
356
|
## Layout
|
|
273
357
|
|
|
274
358
|
- `agent/actions/` — one handler per action (`execute`, optional `render`),
|
|
@@ -337,6 +421,14 @@ export { apiFetch } from "./api";
|
|
|
337
421
|
|
|
338
422
|
## Safety
|
|
339
423
|
|
|
424
|
+
- **A refusal is an answer.** When a command or tool call is declined - by the
|
|
425
|
+
human or by the session's own safety checks - stop. Say in one plain sentence
|
|
426
|
+
what you wanted it for, or take a narrower read-only route. Never retry it,
|
|
427
|
+
and never try a different command hoping it gets through.
|
|
428
|
+
- **Never create an account or a key** - not in Foldspace, not in the
|
|
429
|
+
customer's product, not anywhere. If one is missing, say which and where it
|
|
430
|
+
goes. **Never widen your own access**: if something is refused for a site or
|
|
431
|
+
a permission, say so and ask; do not try others.
|
|
340
432
|
- Do not commit secrets, cookies, HAR files, browser storage, or
|
|
341
433
|
`.foldspace-dev/`. Nothing transient goes in `docs/`.
|
|
342
434
|
- Local handler changes are not cloud publication.
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@ parameter `name` — *the name, or part of the name, the user said*.
|
|
|
18
18
|
| no name ("how many projects do I have?") | the account's **count**, plus a small sample — never the whole account |
|
|
19
19
|
| one clear match | that project, its match strength, and up to three alternatives |
|
|
20
20
|
| several equally good matches | **all of them**, marked `ambiguous` — never a silent pick |
|
|
21
|
-
| nothing matches | `success:
|
|
21
|
+
| nothing matches | `success: true` with zero `matches` - an empty search is a valid result, not a failure - plus near-misses for a typo, as data. Never "refine your query" |
|
|
22
22
|
| the account is empty | a count of zero — not an error |
|
|
23
23
|
| signed out, no access, throttled, unreachable | `success: false` with the `reason` |
|
|
24
24
|
|
|
@@ -48,15 +48,17 @@ export const find_project_id = {
|
|
|
48
48
|
|
|
49
49
|
if (summaries.length === 0) {
|
|
50
50
|
// Server search is a substring of the name, so a typo finds nothing.
|
|
51
|
-
//
|
|
51
|
+
// An empty search is a VALID result, not a failure: say that nothing
|
|
52
|
+
// matched and stop. Never "refine your query" or "try again" - an
|
|
53
|
+
// instruction in a tool response can make the model call a tool again on
|
|
54
|
+
// its own. Near-misses are facts, so they go back as data - but they are
|
|
52
55
|
// near-misses, not a resolution.
|
|
53
56
|
const wide = await listProjects({ pageSize: SHORTLIST });
|
|
54
57
|
const near = wide.ok ? nearMatches(wide.data.projects.map(toSummary), query, 5) : [];
|
|
55
58
|
return {
|
|
56
|
-
success:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
data: { query, total: res.data.total, nearMatches: near },
|
|
59
|
+
success: true,
|
|
60
|
+
message: `No projects match "${query}".`,
|
|
61
|
+
data: { query, total: res.data.total, matches: [], nearMatches: near },
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
64
|
|