@lunnoa/client 2.0.0 → 2.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunnoa/client",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "TypeScript SDK for building applications on top of Lunnoa Automate — typed client for the Public API (agents, workflows, executions, entities, knowledge, queues), SSE agent chat streaming, and deployment-specific codegen",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -2,10 +2,10 @@
2
2
  name: lunnoa-client
3
3
  description: >-
4
4
  Builds custom frontends and backends on top of a Lunnoa Automate deployment
5
- using the @lunnoa/client TypeScript SDK. Covers the two auth patterns
6
- (server-side lna_ API keys via createServerClient, browser user JWTs via
7
- createBrowserClient + lunnoa.auth.login / refresh / SSO — never lna_ keys in a
8
- browser), discovery of the deployment's agents, workflows, and entity
5
+ using the @lunnoa/client TypeScript SDK. App login is always a Lunnoa user
6
+ (createBrowserClient + lunnoa.auth.login / refresh / SSO). lna_ API keys are
7
+ for the CLI only (discovery, codegen, deploy), never for the app session and
8
+ never in a browser. Covers discovery of the deployment's agents, workflows, and entity
9
9
  types, running the deployment codegen first for typed accessors, querying
10
10
  and creating entities, triggering workflows and polling executions,
11
11
  resuming NEEDS_INPUT executions from custom forms, streaming agent chat
@@ -49,19 +49,24 @@ Human docs (detail): Lunnoa Docs → Develop → TypeScript client SDK.
49
49
 
50
50
  Run these before inventing resources or shipping UI code:
51
51
 
52
- 1. **Auth** — Pattern A (`createServerClient` + `lna_` on the server) or
53
- Pattern B (`createBrowserClient` + JWT). **Never** put `lna_` in the
54
- browser (SDK throws when `window` exists).
52
+ 1. **Auth** — Lunnoa user JWT via `createBrowserClient` + `lunnoa.auth.login`
53
+ (or SSO). **Never** call Lunnoa as the app's users with an `lna_` key, and
54
+ **never** put `lna_` in the browser (SDK throws when `window` exists).
55
+ `lna_` keys are for CLI discovery, codegen, and deploy only.
55
56
  2. **Codegen** — When building typed UIs, run
56
57
  `npx @lunnoa/client codegen` against the deployment first.
57
58
  3. **Discover before inventing** — prefer the CLI (JSON for agents), then
58
59
  the SDK: `npx @lunnoa/client tools list --json --for-agent`,
59
60
  `tools get <actionId> --json`, `apps list`, `connections list`,
61
+ `ai-connections list --json`,
60
62
  `agents|workflows|entity-types|tables list`, `tables get <slugOrId>`,
61
63
  `features`.
62
64
  SDK equivalents: `workflowApps.list()`, `agents.list`, `workflows.list`,
63
- `entityTypes.list`, `tables.list`, `discovery.enabledFeatures()`.
64
- Do not invent catalogue action ids.
65
+ `entityTypes.list`, `tables.list`, `aiConnections.list()`,
66
+ `discovery.enabledFeatures()`.
67
+ Do not invent catalogue action ids or model ids. `connections list` is
68
+ app connections (Gmail, HTTP). `ai-connections list` is the model
69
+ provider connection and the `models[].id` values `defineAgent` accepts.
65
70
  4. **Run vs deploy** — Ad-hoc: `actions.run` / `runs.start` /
66
71
  `workflows.execute`. Durable shared automation: CLI
67
72
  `npx @lunnoa/client workflows|agents deploy`. Upsert is by slug
@@ -70,36 +75,33 @@ Run these before inventing resources or shipping UI code:
70
75
 
71
76
  ---
72
77
 
73
- ## 1. Auth: decide the pattern first
78
+ ## 1. Auth: Lunnoa users only
74
79
 
75
- | Pattern | Credential | Use when |
76
- |---|---|---|
77
- | **A. Backend holds the key** | `createServerClient({ apiKey: 'lna_...' })` | The app has its own users/login; Lunnoa never needs to know them. All Lunnoa calls go through the app's backend. |
78
- | **B. End users are Lunnoa users** | `createBrowserClient({ baseUrl })` + `lunnoa.auth.login` | Per-user permissions, agent shares, and task history must apply. The browser talks to Lunnoa directly. |
80
+ Every person who uses the app is a Lunnoa user. If they are not in the
81
+ workspace yet, they are provisioned there first (invite, SSO, or SCIM). The
82
+ app does not keep its own user directory and does not call Lunnoa with an
83
+ `lna_` key on their behalf.
84
+
85
+ | Caller | Credential |
86
+ |---|---|
87
+ | **Person using the app** | `createBrowserClient({ baseUrl })` + `lunnoa.auth.login` (password, 2FA, or SSO). Permissions, agent shares, and task history are that user's. |
88
+ | **CLI (codegen, discovery, deploy)** | `lna_` API key in `.env` / `--api-key`. Not the app session. |
79
89
 
80
90
  Hard rules:
81
91
 
82
92
  - **NEVER put an `lna_` key in browser code, env vars bundled into the client,
83
93
  or anything shipped to the browser.** The SDK throws if an `lna_` key is
84
94
  used while `window` exists. A leaked key exposes the whole workspace.
85
- - For browser apps with their own user base, use the **backend-for-frontend
86
- pattern**: the browser calls your backend; your backend holds the key and
87
- calls Lunnoa. Next.js route handlers / server actions count as backend.
88
- - Pattern B needs the deployment to allow the app's origin via
89
- `CORS_ALLOWED_ORIGINS`.
90
- - Keys are minted by a SuperAdmin in **Adminspace → API keys** (workspace +
95
+ - **NEVER build a backend-for-frontend that holds an `lna_` key so the app
96
+ can have its own users.** Next.js route handlers and server actions count
97
+ as the app: they must forward the signed-in user's JWT, not a service key.
98
+ - The deployment must allow the app's origin via `CORS_ALLOWED_ORIGINS`.
99
+ - CLI keys are minted by a SuperAdmin in **Adminspace → API keys** (workspace +
91
100
  RBAC role + optional expiry; secret shown once). Recommend a minimal custom
92
101
  role (e.g. `entities:read`, `entities:create`, `agents:use`), not Admin.
93
102
 
94
103
  ```typescript
95
- // Pattern A (server only)
96
- import { createServerClient } from '@lunnoa/client';
97
- const lunnoa = createServerClient({
98
- baseUrl: process.env.LUNNOA_URL!,
99
- apiKey: process.env.LUNNOA_API_KEY!,
100
- });
101
-
102
- // Pattern B (browser) — login + localStorage token store + auto-refresh on 401
104
+ // App session — login + localStorage token store + auto-refresh on 401
103
105
  import { createBrowserClient, isLoginRequires2FA } from '@lunnoa/client';
104
106
  const lunnoa = createBrowserClient({ baseUrl });
105
107
  const result = await lunnoa.auth.login({ email, password });
@@ -150,7 +152,7 @@ const { data, setPage } = useEntityList({ objectTypeSlug: 'invoice' });
150
152
 
151
153
  Peer: `react` ≥ 18 for `/react`. `@ai-sdk/react` ships with the SDK (no extra install).
152
154
  Errors are `LunnoaApiError` with `.status`, `.body`, `.isUnauthorized`,
153
- `.isForbidden`, `.isRateLimited`. A 403 means the key's role or the
155
+ `.isForbidden`, `.isRateLimited`. A 403 means the user's role or the
154
156
  deployment's licence edition does not cover the endpoint.
155
157
 
156
158
  ---
@@ -169,8 +171,9 @@ npx @lunnoa/client codegen --url <deployment-url> --api-key <lna_key> --out ./sr
169
171
  This emits `src/lunnoa/lunnoa.generated.ts` with `createDeploymentClient`:
170
172
 
171
173
  ```typescript
174
+ import { createBrowserClient } from '@lunnoa/client';
172
175
  import { createDeploymentClient } from './lunnoa/lunnoa.generated';
173
- const lunnoa = createDeploymentClient(new LunnoaClient({ baseUrl, apiKey }));
176
+ const lunnoa = createDeploymentClient(createBrowserClient({ baseUrl }));
174
177
 
175
178
  await lunnoa.entities.invoice.list({ state: 'pending' }); // typed attributes + states
176
179
  await lunnoa.workflows.processInvoice.execute({ invoiceId }); // typed trigger inputs
@@ -365,7 +368,8 @@ export const ping = defineWorkflow({
365
368
 
366
369
  export const triage = defineAgent({
367
370
  slug: 'support-triage',
368
- model: 'gpt-4o',
371
+ // models[].id from `npx @lunnoa/client ai-connections list --json`
372
+ model: 'deepseek-ai/DeepSeek-V4-Pro',
369
373
  instructions: 'Triage mail. Be concise.',
370
374
  tools: [defineAction({ id: 'http_action_send-request' })],
371
375
  });
@@ -385,11 +389,20 @@ npx @lunnoa/client tools list --json --for-agent
385
389
  npx @lunnoa/client tools search email --json --for-agent
386
390
  npx @lunnoa/client tools get http_action_send-request --json
387
391
  npx @lunnoa/client connections list --app gmail --json
392
+ npx @lunnoa/client ai-connections list --json
388
393
  ```
389
394
 
390
395
  `tools get` returns `inputConfig` / `inputFields` and a `defineAction` sketch.
391
396
  `tools list` is compact; use `get` for the schema. `--json` is for coding agents.
392
397
 
398
+ `ai-connections list` returns the AI connections this key can assign to an
399
+ agent. Set `defineAgent({ model })` to a `models[].id` from that JSON
400
+ (on Lunnoa LLMs that is a catalogue id such as
401
+ `deepseek-ai/DeepSeek-V4-Pro`). Omit `aiConnection` to
402
+ use the connection with `isDefault: true`. Pass
403
+ `defineAiConnection({ id })` only for a different connection. SDK:
404
+ `lunnoa.aiConnections.list()`.
405
+
393
406
  Deploy to Automate UI (upsert by slug inside the workspace on the API key; prefer CLI):
394
407
 
395
408
  ```bash
@@ -443,6 +456,8 @@ for await (const chunk of stream) {
443
456
  }
444
457
  ```
445
458
 
459
+ A turn from an app runs in **preview**: 10 model rounds, so the agent can call tools a few times and still send a final reply. The SDK sends `chatMode: 'preview'` for you. Do not pass `chatMode: 'builder'` from an app. That is the agent-editor interview: 4 rounds, and it stops a tool-using agent halfway. The workflow then fails with "Agent did not generate a response" even when a tool already saved the data. A workflow Message Agent step uses the same preview budget. For a job that chains many tool calls (read every record, then write a result), turn on **Long-horizon mode** on that agent in Lunnoa. That raises the budget to 50 rounds. `defineAgent` cannot set the switch, and a later deploy leaves it as you set it.
460
+
446
461
  - **React apps:** prefer `useAgentChat` from `@lunnoa/client/react`, which wraps AI SDK `useChat` + `DefaultChatTransport`
447
462
  pointed at
448
463
  `${baseUrl}/api/agents/${agentId}/tasks/${taskId}/stream-message` with an
@@ -500,7 +515,7 @@ const { items: work } = await lunnoa.queueItems.listByObject(ticket.id);
500
515
  `lunnoa.approvals` mirrors Automate **Approvals** (`/approvals`). It uses the
501
516
  workspace API (`/api/approvals/...`), not Public API v1. The inbox is filtered
502
517
  to requests where the **current user** is eligible and has not decided yet.
503
- Prefer pattern B (user JWT). Role needs `approvals:read` / `approvals:decide`.
518
+ The caller is the signed-in Lunnoa user. Role needs `approvals:read` / `approvals:decide`.
504
519
 
505
520
  ```typescript
506
521
  const { items } = await lunnoa.approvals.inbox(); // pending + partially_approved
@@ -531,14 +546,15 @@ with emails (capped; not Azure object IDs).
531
546
 
532
547
  ## 10. Ship checklist (after the mandatory checklist)
533
548
 
534
- 1. Confirm base URL + credential pattern (A or B); wire the key server-side only.
535
- For Pattern B prefer `createBrowserClient` and `lunnoa.auth.login` (not raw
536
- localStorage getters unless you already hold a JWT).
549
+ 1. Confirm the base URL. Sign people in with `createBrowserClient` and
550
+ `lunnoa.auth.login` (not an `lna_` key, and not raw localStorage getters
551
+ unless you already hold that user's JWT). Allow the origin in
552
+ `CORS_ALLOWED_ORIGINS`.
537
553
  2. Run `npx @lunnoa/client codegen` against the deployment; commit the output.
538
554
  3. Call `discovery.enabledFeatures()` and hide unsupported areas.
539
555
  4. Build forms/tables from `attributeSchema` / `customInputConfig` (or the generated types).
540
556
  5. Render workflow progress from `executionPath`; handle `NEEDS_INPUT` with `submitInput`.
541
- 6. For single-action calls, use `actions.run`; for linear multi-step, use `runs.start` / `defineWorkflow`. Deploy with `npx @lunnoa/client workflows|agents deploy`. Discover catalogue via `npx @lunnoa/client tools list|get|search` (or `workflowApps.list()`).
557
+ 6. For single-action calls, use `actions.run`; for linear multi-step, use `runs.start` / `defineWorkflow`. Deploy with `npx @lunnoa/client workflows|agents deploy`. Discover catalogue via `npx @lunnoa/client tools list|get|search` (or `workflowApps.list()`). Discover agent models via `npx @lunnoa/client ai-connections list --json` (or `aiConnections.list()`).
542
558
  7. For Request Approval nodes, use `approvals.inbox` / `approvals.decide` (or `executions.submitApproval`).
543
559
  8. Chat: stream via SSE, handle resume (reconnects) and stop, load history from the task.
544
560
  9. Handle `LunnoaApiError`: 401 → re-auth; 403 → hide the capability; 429 → back off.
@@ -42,10 +42,11 @@ interrogation.
42
42
 
43
43
  ### Actors
44
44
 
45
- - Who uses the custom UI: Lunnoa employees (workspace users), external
46
- customers (not Lunnoa users), or a backend system only?
47
- - That choice drives auth: JWT (Pattern B) vs API key BFF (Pattern A). Never
48
- put `lna_` keys in a browser.
45
+ - Who uses the custom UI? They sign in as Lunnoa users. If they are not in
46
+ the workspace yet, they are provisioned there first (invite, SSO, or SCIM).
47
+ - The app does not keep its own login and does not call Lunnoa with an `lna_`
48
+ key on their behalf. `lna_` keys are for the CLI only. Never put one in a
49
+ browser.
49
50
 
50
51
  ### Data and knowledge
51
52
 
@@ -70,10 +71,10 @@ interrogation.
70
71
 
71
72
  ### Auth for any custom UI
72
73
 
73
- | End users | Prefer |
74
+ | End users | Auth |
74
75
  |---|---|
75
- | App has its own login; Lunnoa is a backend | Pattern A: server holds `lna_` |
76
- | End users are Lunnoa users; per-user history/permissions | Pattern B: browser JWT |
76
+ | People using the app | Lunnoa user JWT: `createBrowserClient` + `lunnoa.auth.login` (or SSO). Provision missing people with invite, SSO, or SCIM first. |
77
+ | Coding agent / CLI | `LUNNOA_API_KEY` for discovery, codegen, and deploy. Not the app session. |
77
78
  | Anonymous embed chat (no full login) | Out of scope for v1 client path; scoped embed tokens are a later platform bet |
78
79
 
79
80
  ---
@@ -105,18 +106,28 @@ interrogation.
105
106
  1. **Agents have no schedules or event triggers.** If something must run on a
106
107
  cron or webhook, use a **Workflow** that messages the agent (or runs
107
108
  actions). Do not invent an agent trigger.
108
- 2. **Connections stay on Lunnoa.** Definitions only reference connection ids
109
+ 2. **A tool-using agent gets 10 model rounds per turn** from an app or a
110
+ Message Agent step. That covers a handful of tool calls plus a final reply.
111
+ If the job chains many calls (read every record, then write), the brief must
112
+ say to turn on **Long-horizon mode** for that agent in Lunnoa (50 rounds).
113
+ Do not plan around `chatMode: 'builder'`; that is the editor interview and
114
+ stops after 4 rounds.
115
+ 3. **Connections stay on Lunnoa.** Definitions only reference connection ids
109
116
  (or omit for sole/default resolution). Never ask the partner to put OAuth
110
117
  secrets in their app.
111
- 3. **Do not invent catalogue actions.** Discover with
118
+ 4. **Do not invent catalogue actions or model ids.** Discover actions with
112
119
  `npx @lunnoa/client tools list|get|search --json` (or `workflowApps.list()`
113
- / codegen). Client `defineAction` binds existing catalogue actions; toolkit
114
- `createAction` is a different product (in-platform apps).
115
- 4. **Durable vs ephemeral:** experiments → `runs.start`; shared production
120
+ / codegen). Discover models with
121
+ `npx @lunnoa/client ai-connections list --json` and use a returned
122
+ `models[].id` (Lunnoa LLMs uses catalogue ids such as
123
+ `deepseek-ai/DeepSeek-V4-Pro`). Client `defineAction` binds existing
124
+ catalogue actions; toolkit `createAction` is a different product
125
+ (in-platform apps).
126
+ 5. **Durable vs ephemeral:** experiments → `runs.start`; shared production
116
127
  automation → CLI `workflows deploy` / `agents deploy` by slug.
117
- 5. **UI is headless.** `@lunnoa/client` has no design system. Optional React
128
+ 6. **UI is headless.** `@lunnoa/client` has no design system. Optional React
118
129
  hooks in `@lunnoa/client/react`. Partners bring their own UI.
119
- 6. **Reuse before create.** Before proposing any new entity type, table,
130
+ 7. **Reuse before create.** Before proposing any new entity type, table,
120
131
  workflow, or agent, run `npx @lunnoa/client entity-types list --json`,
121
132
  `tables list --json`, `workflows list --json`, and `agents list --json`.
122
133
  The build brief must state explicitly what is **reused** vs **created**.
@@ -124,11 +135,13 @@ interrogation.
124
135
  ### Common anti-patterns to reject
125
136
 
126
137
  - Putting an agent on a schedule without a workflow wrapper
138
+ - Expecting an agent to loop tools indefinitely, or sending `chatMode: 'builder'` from an app (4 rounds, editor only)
127
139
  - Building a fake multi-step “batch” as many unrelated `actions.run` calls
128
140
  when the user wanted one Execution (use `runs.start` / workflow)
129
141
  - Shipping `lna_` to the browser “just for the demo”
130
142
  - Using `@lunnoa/toolkit` to build a customer portal
131
143
  - Designing a local LangChain loop instead of Lunnoa-hosted agents
144
+ - Hardcoding `model: 'gpt-4o'` without reading `ai-connections list`
132
145
 
133
146
  ---
134
147
 
@@ -149,6 +162,7 @@ can execute. Use this shape:
149
162
 
150
163
  ### Discovery (run first)
151
164
  - [ ] `npx @lunnoa/client tools list --json --for-agent` then `tools get <id>`
165
+ - [ ] `npx @lunnoa/client ai-connections list --json` before choosing an agent model
152
166
  - [ ] agents / workflows / entity-types / tables list — reuse before create
153
167
  - [ ] codegen — if building typed entity/workflow accessors
154
168
 
@@ -192,7 +206,7 @@ continue in a coding turn with that skill loaded.
192
206
  **You ask:** Who chats (customers or staff)? Data source (entities vs ERP
193
207
  action)? Need approvals? Existing HTTP/CRM connections?
194
208
 
195
- **You conclude (example):** Pattern A BFF; Agent `order-status` with tools
209
+ **You conclude (example):** Customers are Lunnoa users (SCIM or invite) and sign in with a browser JWT; Agent `order-status` with tools
196
210
  `defineAction` for ERP lookup (after `tools list` / `tools get`) + optional
197
211
  workflow for staff notifications; UI = chat only; no agent schedule.
198
212