pgkiln 0.51.0 → 0.53.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 +1 -1
- package/SECURITY.md +10 -1
- package/db/migrations/121_ai_agents.sql +94 -0
- package/db/migrations/122_team_development.sql +186 -0
- package/db/migrations/123_workflow_outcomes.sql +407 -0
- package/db/migrations/124_component_details.sql +51 -0
- package/db/migrations/125_app_change.sql +23 -0
- package/db/migrations/126_mail_queue_network_access.sql +119 -0
- package/docs/apex-feature-parity.md +50 -19
- package/docs/guide/01-installation.md +8 -4
- package/docs/guide/03-builder.md +197 -10
- package/docs/guide/04-pages-and-regions.md +71 -21
- package/docs/guide/05-items.md +7 -1
- package/docs/guide/06-processing.md +129 -9
- package/docs/guide/07-dynamic-actions.md +34 -0
- package/docs/guide/08-security.md +55 -0
- package/docs/guide/09-reference.md +5 -2
- package/docs/guide/11-from-apex.md +3 -1
- package/docs/guide/12-development.md +87 -16
- package/docs/guide/14-globalization.md +49 -1
- package/docs/guide/18-cli.md +21 -1
- package/docs/guide/19-rest-data-sources.md +12 -0
- package/docs/guide/20-ai-agents.md +12 -4
- package/examples/hr/README.md +2 -0
- package/examples/hr/hr_64_ai_agent.sql +97 -0
- package/examples/hr/hr_65_ask_reports.sql +21 -0
- package/examples/hr/hr_66_team_development.sql +58 -0
- package/examples/hr/hr_67_workflow_outcomes.sql +113 -0
- package/examples/hr/hr_68_component_details.sql +96 -0
- package/examples/hr/hr_70_data_security.sql +79 -0
- package/package.json +1 -1
- package/public/app.css +135 -21
- package/public/app.js +134 -20
- package/public/builder.css +133 -1
- package/public/builder.js +51 -0
- package/src/ai/chat.ts +18 -18
- package/src/ai/service.ts +35 -11
- package/src/ai/types.ts +7 -2
- package/src/app.ts +15 -0
- package/src/builder/advisor.ts +6 -3
- package/src/builder/ai-agents.ts +372 -0
- package/src/builder/ai-builder.ts +3 -3
- package/src/builder/ai.ts +13 -9
- package/src/builder/app-updates.ts +55 -0
- package/src/builder/assistant.ts +22 -7
- package/src/builder/components.ts +38 -9
- package/src/builder/data-security.ts +182 -0
- package/src/builder/designer.ts +8 -3
- package/src/builder/feedback.ts +6 -1
- package/src/builder/home.ts +16 -5
- package/src/builder/locks.ts +7 -1
- package/src/builder/mail-queue.ts +212 -0
- package/src/builder/mail.ts +72 -45
- package/src/builder/network-access.ts +140 -0
- package/src/builder/object-actions.ts +1 -0
- package/src/builder/object-browser.ts +1 -1
- package/src/builder/region-help.ts +2 -2
- package/src/builder/rest-catalogs.ts +19 -4
- package/src/builder/routes.ts +4 -1
- package/src/builder/shared.ts +1 -1
- package/src/builder/sql.ts +2 -0
- package/src/builder/team.ts +991 -0
- package/src/builder/themeroller.ts +47 -6
- package/src/builder/ui.ts +7 -1
- package/src/builder/websources.ts +1 -1
- package/src/builder/workflow-migrate.ts +210 -0
- package/src/builder/workflows.ts +29 -6
- package/src/builder/workspace-home.ts +2 -0
- package/src/builder/workspace-mail.ts +121 -0
- package/src/builder/workspace-transfer.ts +1 -1
- package/src/builder/workspaces.ts +1 -0
- package/src/cli/main.ts +25 -3
- package/src/cli/mcp.ts +40 -4
- package/src/cli/only.ts +52 -0
- package/src/cli/replace.ts +11 -1
- package/src/datasec.ts +343 -0
- package/src/i18n/ar.ts +17 -0
- package/src/i18n/cs.ts +17 -0
- package/src/i18n/da.ts +17 -0
- package/src/i18n/de.ts +17 -0
- package/src/i18n/el.ts +17 -0
- package/src/i18n/es.ts +17 -0
- package/src/i18n/fi.ts +17 -0
- package/src/i18n/fr.ts +17 -0
- package/src/i18n/he.ts +17 -0
- package/src/i18n/it.ts +17 -0
- package/src/i18n/ja.ts +17 -0
- package/src/i18n/ko.ts +17 -0
- package/src/i18n/nb.ts +17 -0
- package/src/i18n/pl.ts +17 -0
- package/src/i18n/pt.ts +17 -0
- package/src/i18n/ru.ts +17 -0
- package/src/i18n/sv.ts +17 -0
- package/src/i18n/tr.ts +17 -0
- package/src/i18n/uk.ts +17 -0
- package/src/i18n/zh.ts +17 -0
- package/src/i18n.ts +34 -0
- package/src/instance.ts +2 -0
- package/src/mail/mail.ts +50 -11
- package/src/mail/providers.ts +6 -3
- package/src/metadata.ts +11 -3
- package/src/network-acl.ts +126 -0
- package/src/objectstore.ts +3 -0
- package/src/runtime/ai-agents.ts +365 -0
- package/src/runtime/ai-filter.ts +385 -107
- package/src/runtime/assistant.ts +64 -11
- package/src/runtime/context.ts +2 -0
- package/src/runtime/engine.ts +3 -1
- package/src/runtime/ir-phrases.ts +812 -0
- package/src/runtime/ir-plan.ts +449 -0
- package/src/runtime/items.ts +1 -1
- package/src/runtime/regions.ts +6 -2
- package/src/runtime/render.ts +5 -3
- package/src/runtime/report.ts +1 -1
- package/src/runtime/styles.ts +54 -12
- package/src/runtime/tasks.ts +63 -12
- package/src/task-events.ts +232 -0
- package/src/team-samples.ts +74 -0
- package/src/team.ts +342 -0
- package/src/webclient.ts +45 -4
- package/src/webrequests.ts +5 -0
- package/src/websources.ts +30 -12
- package/src/workflow.ts +135 -18
- package/src/workspace-export.ts +16 -1
package/docs/guide/03-builder.md
CHANGED
|
@@ -158,9 +158,11 @@ applications' files. Choose what goes in:
|
|
|
158
158
|
| REST source catalogs | Every [catalog](19-rest-data-sources.md#rest-source-catalogs) with its services |
|
|
159
159
|
| SQL scripts, blueprints, data generators | The SQL Workshop's saved work |
|
|
160
160
|
| Data Reporter datasets | Every [dataset](#data-reporter-datasets-and-reporting-applications) (sprint 110) |
|
|
161
|
+
| Team Development | [Label groups, labels, milestones, templates and issues](#team-development) with their comments and history; an issue's application by alias (sprint 113) |
|
|
161
162
|
|
|
162
|
-
Never in the file: the workspace's name, its [isolation](#isolated-workspaces) and database roles,
|
|
163
|
-
|
|
163
|
+
Never in the file: the workspace's name, its [isolation](#isolated-workspaces) and database roles, its
|
|
164
|
+
[mail service](#a-workspaces-own-mail-service) and [network access list](#network-access) (installation-specific, like
|
|
165
|
+
isolation), passwords and secrets, script runs and other history. **Applications are exported on their own** (an application's *Export*).
|
|
164
166
|
|
|
165
167
|
**Import** reads such a file into the current workspace, for the components you choose. Components with a name the
|
|
166
168
|
workspace already has are kept, or replaced with *Replace components with the same name*; nothing is deleted. A
|
|
@@ -275,7 +277,8 @@ JavaScript. The [default-password banner](#signing-in-and-developer-accounts) st
|
|
|
275
277
|
- **System message**: the pgkiln version the server runs and, when the [release check](#the-release-check) is on and
|
|
276
278
|
a newer release is out, **pgkiln X is available** with a link to its release notes and how to upgrade (back up,
|
|
277
279
|
install the new version, `pgkiln migrate`, restart).
|
|
278
|
-
- **A side column**: About, **
|
|
280
|
+
- **A side column**: About, **Team Development** ([open issues](#team-development), those assigned to you, unseen
|
|
281
|
+
mentions of you, or *Set up Team Development* before it is set up), **Learn more** (this guide, the [tutorial](10-tutorial.md),
|
|
279
282
|
[Coming from APEX](11-from-apex.md), the changelog and the discussions on GitHub) and Resources.
|
|
280
283
|
|
|
281
284
|
### The release check
|
|
@@ -300,9 +303,16 @@ The App Builder's home page, `/builder/apps` (`/builder` shows it too, unless th
|
|
|
300
303
|
developers, the SQL Workshop, and for administrators [workspaces](#workspaces), AI services and the
|
|
301
304
|
[installation log](#installation)). The list, the dashboard and Recent show the current workspace.
|
|
302
305
|
- **The applications**, as a report (application id, name, alias, pages, page views of the last 24
|
|
303
|
-
hours, sign-in, last updated, and Edit / Run) or as cards. **Search** filters the list as you type
|
|
306
|
+
hours, sign-in, last updated, **updated by**, **working copies**, and Edit / Run) or as cards. **Search** filters the list as you type
|
|
304
307
|
(by name, alias or id; without JavaScript, press Enter). Click a column heading, or use
|
|
305
308
|
**Actions**, to sort. The view and the sort are remembered until you sign out.
|
|
309
|
+
- (sprint 116) **Updated by** is the developer who changed the application last in the builder (any change to its
|
|
310
|
+
pages, shared components or settings; locks and comments don't count) or who created, imported or copied it;
|
|
311
|
+
*Updated* is the later of that change and the application's own settings. An import with `pgkiln import` or the
|
|
312
|
+
MCP server changes *Updated* only. **Working copies** counts the application's [working copies](#working-copies)
|
|
313
|
+
and links to them. A **lock icon** after the name shows that the application is [locked](#page-locks-and-comments),
|
|
314
|
+
with its owner in the tooltip (and for screen readers). The cards show the same as small badges. On phones the
|
|
315
|
+
report keeps the id, the name with the lock and the actions.
|
|
306
316
|
- **A side column** (on the right on wide screens, below the list otherwise): About, **Recent** (the
|
|
307
317
|
applications you opened last) and Tasks.
|
|
308
318
|
- **The workspace message**, when the workspace has one, above the tiles.
|
|
@@ -753,6 +763,10 @@ author or an administrator deletes it. The page list counts each page's comments
|
|
|
753
763
|
another number keeps its lock and comments. Locks and comments belong to this installation and
|
|
754
764
|
are not exported.
|
|
755
765
|
|
|
766
|
+
**Make an issue** under a comment turns it into a [Team Development](#team-development) issue about the same page;
|
|
767
|
+
the comment then links to its issue. A page with open issues shows them above the designer's tabs (*1 open issue:
|
|
768
|
+
…*, with *New issue* for that page), and the application's page list tags such pages (*2 issues*).
|
|
769
|
+
|
|
756
770
|
### Arranging the layout
|
|
757
771
|
|
|
758
772
|
Regions are placed in sequence order; a region's *column span* (1–12) sets its width, and a
|
|
@@ -840,7 +854,7 @@ out, other keys are kept, columns the query no longer returns stay listed so you
|
|
|
840
854
|
| `smart_filters` | The same per-column facets, the suggestions per facet and the search field's placeholder |
|
|
841
855
|
| `display_selector` | Tabs or a select list, "Show all", remember the choice; per other region of the page: in a tab and the tab name (saved in that region's settings) |
|
|
842
856
|
| `ai_assistant` | The AI service (those the application may use), system prompt, welcome text, placeholder, error message, tool rounds per question, questions per conversation, public or not, and the context queries and tools as JSON (checked when saving: query shapes, parameter types, REST data sources and authorization schemes that exist) ([AI assistant](04-pages-and-regions.md#ai_assistant-ai-assistant)) |
|
|
843
|
-
| `report` (also) | *Ask in your own words (AI)*: the AI service and placeholder of
|
|
857
|
+
| `report` (also) | *Ask in your own words (AI)*: off, the built-in phrases or an AI service, and the placeholder of [Ask in your own words](04-pages-and-regions.md#ask-in-your-own-words-ai-interactive-reports) |
|
|
844
858
|
| `data_reporter` | Data sources (a table or view each: static id, label, description, offered columns with labels and format masks; or (sprint 110) a dataset of the workspace), who may share, build and moderate reports, publishing, rows per page ([Data Reporter](04-pages-and-regions.md#data_reporter-data-reporter)) |
|
|
845
859
|
| `form_designer` | Who may design forms (an authorization scheme), data sources (a table or view each: static id, label, description, key column, may add / change / delete rows, offered columns with labels and lists of values), rows per page ([Form Designer](04-pages-and-regions.md#form_designer-form-designer)) |
|
|
846
860
|
|
|
@@ -958,6 +972,48 @@ user, page, rating and browser), set its status (*Open*, *In progress*, *Done*,
|
|
|
958
972
|
an answer the user sees. Answering is allowed while the application is locked or Run only. The
|
|
959
973
|
setting travels with the export; the feedback itself belongs to the installation.
|
|
960
974
|
|
|
975
|
+
**Make an issue** turns an entry into a [Team Development](#team-development) issue of the application's workspace
|
|
976
|
+
(title from its first line, the feedback quoted, linked to its page, labelled *Bug* for a problem and *Feature* for
|
|
977
|
+
an idea when the workspace has those labels); open feedback becomes *In progress*, and the entry links to its issue.
|
|
978
|
+
|
|
979
|
+
## Team Development
|
|
980
|
+
|
|
981
|
+
(sprint 113, migration 122; APEX: Team Development) An issue tracker for the developers of a
|
|
982
|
+
[workspace](#workspaces): **Team Development** on the icon rail (`/builder/team`) and a block in the
|
|
983
|
+
[Workspace home](#workspace-home)'s side column with the number of open issues. Everything is of the current
|
|
984
|
+
workspace and works without JavaScript.
|
|
985
|
+
|
|
986
|
+
- **Set up** installs sample data, like APEX's set-up wizard: the label groups *Type* (Bug, Feature, Task) and
|
|
987
|
+
*Priority* (High, Medium, Low), issue templates (*Bug report*, *Feature request*, *Task*), canned responses and the
|
|
988
|
+
milestones *1.0*, *1.1* and *Backlog*. What the workspace has already (by name) is kept, so it can run again.
|
|
989
|
+
The samples are in English; other languages are added in `src/team-samples.ts`.
|
|
990
|
+
- **Issues** have a title, a description in Markdown (rendered safely: raw HTML is shown as text, links are http,
|
|
991
|
+
https, mailto or relative), *Open* or *Closed*, labels, a milestone, assignees (the workspace's developers and the
|
|
992
|
+
installation's administrators), and optionally an application of the workspace and one of its pages. Comments are
|
|
993
|
+
Markdown too; *Comment and close* does both. **@name** mentions a developer of the workspace: they see it under
|
|
994
|
+
*Mentions of you* (and on the Workspace home) until they open the issue or mark them seen; no mail is sent. Every
|
|
995
|
+
change is in the issue's history (who changed the title, labels, milestone, assignees, link or status, and when).
|
|
996
|
+
An issue is deleted by its author or a workspace administrator.
|
|
997
|
+
- **The list** filters by status, label, milestone, assignee (*Me*, *Nobody*), application and a search of the title
|
|
998
|
+
and text (or `#12` for issue 12). **Save view** keeps the filters under a name, for you only.
|
|
999
|
+
- **The board** shows the issues as columns of cards, by the labels of one label group (a card moved to *High*
|
|
1000
|
+
loses *Medium*; *None of these* removes the group's labels) or by milestone. Each card has a *Move* form, so it
|
|
1001
|
+
works without dragging.
|
|
1002
|
+
- **Labels** belong to label groups and have a colour from a fixed palette (red, orange, yellow, green, teal, blue,
|
|
1003
|
+
purple, gray). **Milestones** have a due date and are open or closed, with the share of their issues closed.
|
|
1004
|
+
**Templates** are issue templates (title, labels, text: *Start from a template* on *New issue*) and canned
|
|
1005
|
+
responses (*Canned response* → *Insert* above an issue's comment field). Any developer of the workspace adds and
|
|
1006
|
+
changes them; only its administrators delete labels, label groups and milestones.
|
|
1007
|
+
- Issues come from [feedback](#feedback) and [developer comments](#page-locks-and-comments) with **Make an issue**,
|
|
1008
|
+
linked both ways. The page designer shows a page's open issues and App Home counts them per page (*Open issues* in
|
|
1009
|
+
its Tasks).
|
|
1010
|
+
|
|
1011
|
+
Issues and the rest are workspace data: they are not part of an application's export (an in-place import keeps them)
|
|
1012
|
+
but travel in the workspace's [Export and import](#export-and-import) (*Team Development*): labels, milestones and
|
|
1013
|
+
templates match by name, an issue by its title and creation time; assignees are kept when they are developers of the
|
|
1014
|
+
importing workspace and the application link when it has an application with that alias. GitHub synchronisation is
|
|
1015
|
+
not part of it.
|
|
1016
|
+
|
|
961
1017
|
## Working copies
|
|
962
1018
|
|
|
963
1019
|
APEX's working copies: a second application to change in isolation, then merge back. On an
|
|
@@ -1024,8 +1080,8 @@ is the earlier page: every component in one rail, with **Access control** next t
|
|
|
1024
1080
|
| **Shortcuts** | Named texts: `"NAME"` in static content, help texts and confirm messages ([chapter 2](02-concepts.md#shortcuts-name)) |
|
|
1025
1081
|
| **Application computations** | Computations of (application) items for every page: at sign-in, before every page, after every submit ([chapter 6](06-processing.md#application-computations)) |
|
|
1026
1082
|
| **REST modules** | REST endpoints (method, path, SQL) served by pgkiln, with an OpenAPI description ([chapter 13](13-rest-api.md#rest-modules-in-the-builder)) |
|
|
1027
|
-
| **Workflows** | Multi-step processes of tasks, SQL, web service calls (invoke API), decisions, waits and parallel branches, with versions and a diagram ([chapter 6](06-processing.md#workflows)) |
|
|
1028
|
-
| **Task definitions** | Approvals and action tasks: subject, owners, administrators, due date, the SQL that runs on completion ([chapter 6](06-processing.md#approvals-and-the-task-list)) |
|
|
1083
|
+
| **Workflows** | Multi-step processes of tasks, SQL, web service calls (invoke API), e-mail, decisions, waits and parallel branches, with versions, draft steps, migration of running instances and a diagram (SVG / PNG download) ([chapter 6](06-processing.md#workflows)) |
|
|
1084
|
+
| **Task definitions** | Approvals and action tasks: subject, owners, administrators, due date, custom outcomes, the SQL that runs on completion, events and e-mail notifications ([chapter 6](06-processing.md#approvals-and-the-task-list)) |
|
|
1029
1085
|
| **Document templates** | Letters, invoices and other PDFs filled from a query ([chapter 16](16-files.md#document-templates)), with a preview |
|
|
1030
1086
|
| **Build options** | Include / exclude switches for features; pages and their components name one in their *Build option* property, and *Used in* lists them ([chapter 6](06-processing.md#build-options)) |
|
|
1031
1087
|
| **Web credentials** | How the application signs in to web services (basic, API key header, bearer token, OAuth2 client credentials); the secret is write-only and encrypted ([chapter 19](19-rest-data-sources.md#web-credentials)) |
|
|
@@ -1287,13 +1343,79 @@ provider grant it the application permission *Mail.Send*; for SMTP with OAuth2 t
|
|
|
1287
1343
|
*SMTP.SendAsApp* and register its service principal in Exchange Online. In both cases limit it to the
|
|
1288
1344
|
sending mailboxes (an application access policy or RBAC for Applications).
|
|
1289
1345
|
|
|
1346
|
+
|
|
1347
|
+
### Mail queue
|
|
1348
|
+
|
|
1349
|
+
Administration menu → **Mail queue** (`/builder/mail-queue`; APEX 26.2: Administration → Mail queue): the delivery
|
|
1350
|
+
health of the mail queue, for administrators (every workspace, or one) and a workspace's administrators (the current
|
|
1351
|
+
workspace's applications only; other developers get 403). Filter by period (24 hours, 48 hours, 7 days), workspace and
|
|
1352
|
+
application:
|
|
1353
|
+
|
|
1354
|
+
- **figures**: queued now, retrying now (failed with an error that may pass, waiting for the next of its 5 attempts),
|
|
1355
|
+
being sent, sent and failed in the period, the share delivered and the average provider call;
|
|
1356
|
+
- **Per hour**: queued, sent, failed and retrying mail per hour (UTC);
|
|
1357
|
+
- **Slowest provider calls**: the 10 longest hand-overs of the period (how long the provider took to accept or refuse
|
|
1358
|
+
the mail), with application, service and outcome;
|
|
1359
|
+
- **Per workspace and application**: sent, failed, retrying and queued mail, the average and slowest call;
|
|
1360
|
+
- **Failures**: every failed mail (kept 30 days) with the provider's answer, e.g. the SMTP server's
|
|
1361
|
+
`550 5.1.1 no such user`. **Retry** queues one again with fresh attempts, **Purge** deletes it; *Retry all failed*
|
|
1362
|
+
and *Purge all failed* act on the failures of the filter (never outside the developer's scope).
|
|
1363
|
+
|
|
1364
|
+
Bodies and attachments are never shown here. Every action checks again on the server that the mail's application is in
|
|
1365
|
+
the developer's scope, and is written to the activity log.
|
|
1366
|
+
|
|
1367
|
+
### A workspace's own mail service
|
|
1368
|
+
|
|
1369
|
+
A workspace's page → *Mail and network access* → **mail service** (`/builder/workspaces/<id>/mail`; APEX 26.1:
|
|
1370
|
+
workspace-level SMTP credentials), for the workspace's administrators: a mail service of the workspace's own, with the
|
|
1371
|
+
same providers and checks as [above](#mail-services). The applications of the workspace that an administrator gave no
|
|
1372
|
+
service send through it (an application an administrator gave one keeps it; a service of another workspace is never
|
|
1373
|
+
used). Its secret is stored encrypted with `PGKILN_SECRET_KEY` like a web credential's: write-only, never shown, never
|
|
1374
|
+
exported. It differs from an installation service in two ways that keep it from reaching what the installation
|
|
1375
|
+
doesn't allow:
|
|
1376
|
+
|
|
1377
|
+
- it uses the provider's own API: no API base URL and no token URL (OAuth2 goes to Microsoft Entra of the tenant);
|
|
1378
|
+
- an SMTP server must be on the installation's allow-list (`PGKILN_REST_ALLOWED_HOSTS`, e.g. `smtp.example.com:587`)
|
|
1379
|
+
and the workspace's [network access](#network-access) list, and resolve to a public address (unless
|
|
1380
|
+
`PGKILN_REST_PRIVATE_HOSTS` lists it). The server resolves the host once and connects to the address it checked,
|
|
1381
|
+
with the host name kept for TLS, on every send and test.
|
|
1382
|
+
|
|
1383
|
+
### Network access
|
|
1384
|
+
|
|
1385
|
+
Administration menu → **Network access** (`/builder/network`; APEX 26.2: workspace network ACLs), for administrators
|
|
1386
|
+
(any workspace, `?ws=`) and a workspace's administrators (their workspaces): which web services a workspace's
|
|
1387
|
+
applications may call. The installation's list (`PGKILN_REST_ALLOWED_HOSTS`, set in the server's environment, shown
|
|
1388
|
+
read-only; the private hosts to administrators only) applies to every workspace. A workspace can choose **Only the
|
|
1389
|
+
hosts below**: then every outgoing call made for one of its applications must match one of its entries *and* the
|
|
1390
|
+
installation's list. A workspace's list only narrows; it can never widen the installation's, and private, loopback and
|
|
1391
|
+
link-local addresses stay refused unless the installation allows them. Entries are `api.example.com`, `*.example.com`
|
|
1392
|
+
(its subdomains) or `api.example.com:8443` (that port only); restricted with no entries means no outgoing calls.
|
|
1393
|
+
|
|
1394
|
+
It is enforced on the server for every outgoing web call of the workspace: `meta.web_request` and
|
|
1395
|
+
`meta.web_request_source`, REST data sources (regions, write-back, synchronisation, the assistant), the Invoke API
|
|
1396
|
+
process and workflow step, web credential token endpoints, object storage of file items, the builder's *Test* of a
|
|
1397
|
+
source, REST source catalogs read from a URL, and the SMTP server of the workspace's own mail service. Every redirect
|
|
1398
|
+
hop is checked again, and a REST source's cached response is not served once its host is off the list. A refused call
|
|
1399
|
+
fails with *The host … is not on the network access list of workspace …*, is written to the application's debug log
|
|
1400
|
+
(level 2, warning, for `meta.web_request` in a page process; level 1 for regions and processes) and appears under
|
|
1401
|
+
**Refused calls** (kept 7 days). **Check a URL** says whether a URL may be called, without calling it.
|
|
1402
|
+
|
|
1403
|
+
Not covered by a workspace's list: the installation's own services, which only administrators configure (installation
|
|
1404
|
+
mail services, AI services, the geocoder, sign-in providers) and push notification services (their own list,
|
|
1405
|
+
`PGKILN_PUSH_HOSTS`).
|
|
1406
|
+
|
|
1290
1407
|
## AI services
|
|
1291
1408
|
|
|
1292
1409
|
Workspace utilities → **AI services** (administrators only; APEX: *Generative AI services*) lists the
|
|
1293
1410
|
large language model services of this installation. A service has:
|
|
1294
1411
|
|
|
1295
1412
|
- a **name** (upper case, e.g. `CLAUDE`) by which processes, dynamic actions and SQL refer to it;
|
|
1296
|
-
- a **provider**: *Claude (Anthropic)* or *OpenAI*, called through their official SDKs;
|
|
1413
|
+
- a **provider**: *Claude (Anthropic)* or *OpenAI*, called through their official SDKs; *Gemini*
|
|
1414
|
+
(Google, through its OpenAI-compatible endpoint `https://generativelanguage.googleapis.com/v1beta/openai/`,
|
|
1415
|
+
with the `openai` SDK); or *OpenAI-compatible*: any endpoint that speaks OpenAI's Chat Completions,
|
|
1416
|
+
such as Ollama (`http://localhost:11434/v1`), vLLM, Azure OpenAI (`https://<resource>.openai.azure.com/openai/v1/`)
|
|
1417
|
+
or a gateway. An OpenAI-compatible service needs a base URL; its key may stay empty for endpoints
|
|
1418
|
+
without keys (a local Ollama);
|
|
1297
1419
|
- a **model**, exactly as the provider names it (new Claude services start with `claude-opus-5-5`);
|
|
1298
1420
|
pgkiln never changes or downgrades it;
|
|
1299
1421
|
- for Claude, the **effort** (how deeply the model thinks; current Claude models always think, lower
|
|
@@ -1305,8 +1427,9 @@ large language model services of this installation. A service has:
|
|
|
1305
1427
|
- an optional **base URL** for a gateway or proxy that speaks the provider's API (calls to the AI
|
|
1306
1428
|
service don't go through `PGKILN_REST_ALLOWED_HOSTS`: only administrators set this URL);
|
|
1307
1429
|
- the **API key**: stored encrypted with `PGKILN_SECRET_KEY`, write-only (never shown again, never
|
|
1308
|
-
exported or logged, not readable by applications). Without one the
|
|
1309
|
-
`OPENAI_API_KEY`
|
|
1430
|
+
exported or logged, not readable by applications, never sent to the browser). Without one the
|
|
1431
|
+
server's `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY` or `OPENAI_COMPATIBLE_API_KEY`
|
|
1432
|
+
(by provider) is used.
|
|
1310
1433
|
|
|
1311
1434
|
On a service's page, **Applications** sets which applications may use it, each with optional daily
|
|
1312
1435
|
limits (requests and input + output tokens per UTC day; a request over a limit fails with a message
|
|
@@ -1314,11 +1437,71 @@ and is logged as *limited*), and **Test** sends a prompt (logged as a builder te
|
|
|
1314
1437
|
on the list page for all services, the usage log: the last requests and the totals per application
|
|
1315
1438
|
and service of the last 30 days.
|
|
1316
1439
|
|
|
1440
|
+
An interactive report's *Ask in your own words* doesn't need a service: without one (or when the
|
|
1441
|
+
service is disabled or not allowed for the application) pgkiln reads the request with its built-in
|
|
1442
|
+
phrases ([chapter 4](04-pages-and-regions.md#ask-in-your-own-words-ai-interactive-reports)).
|
|
1443
|
+
|
|
1317
1444
|
**Prompts go to the provider.** Whatever a prompt contains, including the item values substituted
|
|
1318
1445
|
into it, is sent to the chosen provider (or the gateway of the base URL). Choose providers and
|
|
1319
1446
|
models that your organisation allows for that data. See
|
|
1320
1447
|
[Generate text with AI](06-processing.md#generate-text-with-ai).
|
|
1321
1448
|
|
|
1449
|
+
## AI agents
|
|
1450
|
+
|
|
1451
|
+
Shared Components → Generative AI → **AI Agents** (APEX 26.1 / 26.2: AI Agents and AI Tools) holds an
|
|
1452
|
+
application's agents and the tools they may use. An agent reasons over a user's request in an
|
|
1453
|
+
[AI assistant region](04-pages-and-regions.md#ai_assistant-ai-assistant) and acts **only through the
|
|
1454
|
+
tools you approve**; pgkiln prepares the context, runs each tool call itself under the checks below,
|
|
1455
|
+
and composes the conversation.
|
|
1456
|
+
|
|
1457
|
+
An **agent** has:
|
|
1458
|
+
|
|
1459
|
+
- a **name** (upper case, e.g. `SALES_AGENT`) that regions refer to, and a description;
|
|
1460
|
+
- an **AI service** the application may use, and a **system prompt** (`&ITEM.` is replaced by the item's
|
|
1461
|
+
value as delimited data, as in assistant regions);
|
|
1462
|
+
- a **reasoning effort**: *low*, *medium* or *high*, or empty for the service's own. For Claude it is
|
|
1463
|
+
the output effort (thinking depth, `output_config.effort`); for OpenAI, Gemini and OpenAI-compatible
|
|
1464
|
+
services it is sent as `reasoning_effort` (leave it empty for models without reasoning: they refuse it);
|
|
1465
|
+
- the **tools** it may use (ticked from the application's tools);
|
|
1466
|
+
- **maximum steps** (rounds of tool calls per question, 1–20, default 5) and **maximum output tokens**
|
|
1467
|
+
per call (never above the service's maximum);
|
|
1468
|
+
- an **authorization scheme**: other users see *You may not use this assistant* instead of the message
|
|
1469
|
+
box, and their questions are refused before anything is sent to the AI service.
|
|
1470
|
+
|
|
1471
|
+
A **tool** has a name the model calls it by, a description that tells the model what it does and when
|
|
1472
|
+
to use it, optional **parameters** (JSON: `{"DNAME": {"type": "string", "description": "…", "optional": true}}`;
|
|
1473
|
+
types string, integer, number, boolean, date, `enum` for a list of texts), an optional authorization
|
|
1474
|
+
scheme (only users who pass it are offered the tool) and one of these types:
|
|
1475
|
+
|
|
1476
|
+
| Type | What runs | Checks |
|
|
1477
|
+
|---|---|---|
|
|
1478
|
+
| **SQL query** | one `SELECT` (or `WITH`, `VALUES`, `TABLE`) with the parameters as `:NAME` bind values, plus `:APP_USER` and items | as the application's database role (grants and row level security apply), in a **read-only transaction** (functions it calls can't write either), with a time limit (1–60 s, default 15) and at most *maximum rows* rows (default 50) back to the model |
|
|
1479
|
+
| **PL/pgSQL function** | `schema.function` called with named arguments: each parameter name in lower case is an argument name (`P_EMPNO` → `p_empno => …`) | as the application's role; it **may change data** (committed); same time limit and rows |
|
|
1480
|
+
| **REST data source** | a REST data source of the application; the parameters become its parameters | as in [assistant regions](04-pages-and-regions.md#ai_assistant-ai-assistant) |
|
|
1481
|
+
| **JavaScript** | nothing on the server: after the answer the browser calls the function registered with `pgkiln.actions.register(action)` (with `{value: arguments}`) and the dynamic actions of the **custom event** of that name (the arguments as JSON) | once, right after the answer; the arguments are escaped data in the page |
|
|
1482
|
+
| **Navigate** | the model picks one of the tool's **pages**, a link text and item values of that page; pgkiln builds the URL with the item values' **checksum** (bound to application, page and user) and shows the link under the answer | only pages the user may open are offered (the page's authorization scheme and sign-in); only items of that page; the model's values are never substituted (`&ITEM.`); nothing opens the link by itself |
|
|
1483
|
+
|
|
1484
|
+
The model's arguments are checked against the parameters before a tool runs; they are bind values
|
|
1485
|
+
(escaped literals), never SQL text, and can't replace the server's own names (`:APP_USER`, `:APP_ID`, …).
|
|
1486
|
+
Tool results go back to the model as data, with the instruction never to follow instructions inside them.
|
|
1487
|
+
|
|
1488
|
+
**Every tool call is logged** with the arguments the model gave, its status (*ok*, *error*, or *refused*
|
|
1489
|
+
for a page the user may not open) and duration: in the page's debug messages (level 4) and under
|
|
1490
|
+
Activity → **AI usage** → *Tool calls* (`meta.ai_tool_call`, kept 30 days; arguments may hold user data,
|
|
1491
|
+
only developers see them). The token usage of each call to the model is logged as before.
|
|
1492
|
+
|
|
1493
|
+
Agents and tools are kept in the application (`meta.app.ai_agents`, `meta.app.ai_tools`) and **exported
|
|
1494
|
+
with it**; an export made before they existed imports with none. The forms check each one before
|
|
1495
|
+
saving (a SQL tool must be a query, a function `schema.name`, a navigate tool's pages must exist); the
|
|
1496
|
+
runtime checks them again and shows *This assistant is not set up yet* for a broken one. Renaming a
|
|
1497
|
+
tool keeps it in its agents; a tool an agent uses can't be deleted; renaming an agent renames it in
|
|
1498
|
+
the regions that use it.
|
|
1499
|
+
|
|
1500
|
+
The HR example (`examples/hr/hr_64_ai_agent.sql`) has an agent `HR_AGENT` on page 46: ask *Who in Sales
|
|
1501
|
+
earns most?* and it calls the SQL tool `top_earners` as the signed-in user's role, then offers
|
|
1502
|
+
*Open BLAKE's record*, a link to the employee form (page 3) with a valid checksum, only to users who
|
|
1503
|
+
may open that page.
|
|
1504
|
+
|
|
1322
1505
|
## App Builder AI
|
|
1323
1506
|
|
|
1324
1507
|
The App Builder uses one AI service (APEX: AI Assistant in App Builder and SQL Workshop). An
|
|
@@ -1429,6 +1612,10 @@ the SQL Workshop's connection may use. Without JavaScript the header's field ope
|
|
|
1429
1612
|
transaction (nothing changes when one fails, and the error shows under *Output*); **Open in the worksheet** puts
|
|
1430
1613
|
them there instead. *Use as template* starts a new table with the same columns and keys (names with `_copy`).
|
|
1431
1614
|
Defaults, checks and index expressions are single expressions (no `;` or comments).
|
|
1615
|
+
- (sprint 119) **Security** (the Object Browser's *Security* button on a table, *Security…* in its ⋯ menu): the
|
|
1616
|
+
table's row level security policies, a matrix of database roles × columns with *read* and *update*, and masked
|
|
1617
|
+
columns per application role in a masking view; Preview SQL, Apply (one transaction, recorded in the Change Log)
|
|
1618
|
+
or Open in the worksheet ([chapter 8](08-security.md#data-security-per-table-rows-columns-and-values)).
|
|
1432
1619
|
- **Run Statement** (**Ctrl/Cmd + Enter**) runs the statement at the cursor: the one the cursor is in, else the
|
|
1433
1620
|
nearest one before it. A selection runs as it is, even when it holds several statements. The rows of the last
|
|
1434
1621
|
query show in **Query Result**, up to 500, with row numbers, numbers right-aligned and NULL as *(null)*. The
|
|
@@ -256,7 +256,7 @@ Features for end users:
|
|
|
256
256
|
computed columns and views under a name, and switch between saved reports (below);
|
|
257
257
|
- **rows per page**, **download CSV / Excel / PDF**, **print**, **reset**.
|
|
258
258
|
- Active search, filters, break, aggregates, highlights, computed columns and views appear as
|
|
259
|
-
removable chips. Once a group by, pivot or chart is set, **Report / Group by / Pivot / Chart**
|
|
259
|
+
removable chips (with *Ask in your own words*, as chips with Edit and Remove under the question box). Once a group by, pivot or chart is set, **Report / Group by / Pivot / Chart**
|
|
260
260
|
links switch between the views; all views use the same search, filters and facets.
|
|
261
261
|
- **Paging** with Previous/Next.
|
|
262
262
|
- On phones every row **reflows** into a card with labelled values.
|
|
@@ -267,26 +267,71 @@ and highlight values become literals, columns must exist in the result, operator
|
|
|
267
267
|
functions, chart types and colors come from fixed lists, sort positions are integers, and computed
|
|
268
268
|
column expressions are parsed (below), never pasted into SQL.
|
|
269
269
|
|
|
270
|
-
###
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
The
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
270
|
+
### Ask in your own words (AI interactive reports)
|
|
271
|
+
|
|
272
|
+
An interactive report can take a request in the user's own words (APEX 26.1/26.2: AI interactive
|
|
273
|
+
reports): *"sum of salary by department where job is clerk"*, *"managers hired before 1982, highest
|
|
274
|
+
salary first"*, *"bonus is 10% of salary"*. Set `"ai_filter": {}` in the report's attributes (or
|
|
275
|
+
*Ask in your own words* under the report's settings in the page designer); a question box appears
|
|
276
|
+
above the report.
|
|
277
|
+
|
|
278
|
+
The answer is never SQL: it becomes the report's **own settings**, the same ones the Actions menu
|
|
279
|
+
sets: filters, highlights, a search, a sort, a control break, totals (aggregates), a group by, a
|
|
280
|
+
pivot, a chart and computed columns. They are listed under the box as **chips**; each chip has
|
|
281
|
+
**Edit** (a small form with its column, operator, value, function, color or expression) and
|
|
282
|
+
**Remove**, and **Undo** returns to the settings before the last change (the last five steps, kept
|
|
283
|
+
in the session). A new request refines the current settings: a filter on a column replaces that
|
|
284
|
+
column's filters, a sort, break, group by, pivot or chart replaces the old one, highlights, totals
|
|
285
|
+
and computed columns are added; *"start over"* clears them. The chips are buttons of one form, so
|
|
286
|
+
they work without JavaScript.
|
|
287
|
+
|
|
288
|
+
**Without an AI service** pgkiln reads the request itself with a rule-based parser for common
|
|
289
|
+
phrases (APEX 26.2: works with zero AI). Columns are recognised by name or heading (also without
|
|
290
|
+
spaces, and verbs such as *hired* for `hiredate`); values such as *"only clerks"* or *"in sales"*
|
|
291
|
+
are looked up among the report's own rows (as a query parameter); what isn't understood is said
|
|
292
|
+
in the message, not guessed. Phrases it understands, in English (always), Dutch and German (when
|
|
293
|
+
that is the user's language):
|
|
294
|
+
|
|
295
|
+
| Request | Becomes |
|
|
296
|
+
|---|---|
|
|
297
|
+
| *salary over 3000*, *salary between 1,000 and 3k*, *hired before june 1981*, *hired in 1981*, *name contains "mi"*, *no commission* | filters (`gt`, `ge` + `le`, `lt`, a date range, `contains`, `null`) |
|
|
298
|
+
| *only clerks*, *not clerks*, *in sales*, *active* | a filter on the column that holds the value |
|
|
299
|
+
| *sort by hire date, newest first*, *highest salary first* | the sort |
|
|
300
|
+
| *sum of salary by department*, *count by department and job* | a group by with its function |
|
|
301
|
+
| *total salary*, *average salary* | a totals row |
|
|
302
|
+
| *break by department* | a control break |
|
|
303
|
+
| *pivot sum of salary by department and job* | a pivot |
|
|
304
|
+
| *pie chart of count by department*, *chart of salary by job* | a chart |
|
|
305
|
+
| *highlight salary over 4000 in red* | a highlight |
|
|
306
|
+
| *bonus is 10% of salary*, *yearly = sal * 12* | a computed column |
|
|
307
|
+
| *search for smith* | the search |
|
|
308
|
+
| *start over*, *clear all* | no settings |
|
|
309
|
+
|
|
310
|
+
Dutch (*salaris boven 3000*, *sorteer op datum aflopend*, *som van salaris per afdeling*, *alleen
|
|
311
|
+
klerken*, *bonus is 10% van salaris*) and German (*Gehalt über 3000*, *sortiere nach Datum
|
|
312
|
+
absteigend*, *Summe von Gehalt pro Abteilung*, *nur Angestellte*) work the same way; another
|
|
313
|
+
language adds a phrase table to `src/runtime/ir-phrases.ts`.
|
|
314
|
+
|
|
315
|
+
**With an AI service** (`"ai_filter": {"service": "NAME"}`, an [AI
|
|
316
|
+
service](06-processing.md#generate-text-with-ai) the application may use), the request goes to the
|
|
317
|
+
service with the report's shown columns (names, headings and kinds: text, number, date, boolean),
|
|
318
|
+
its operators and functions and the current settings; the answer is a structured output. When the
|
|
319
|
+
service is disabled or not allowed for the application, the built-in phrases answer instead. The
|
|
320
|
+
request and the column names go to the service's provider; logged in the AI usage log with the
|
|
321
|
+
source `nl2ir`.
|
|
322
|
+
|
|
323
|
+
Either way the answer is checked again before it is applied: only the report's shown columns
|
|
324
|
+
(`hidden` columns are neither offered nor accepted), operators, functions, chart types and colors
|
|
325
|
+
from the report's fixed lists, at most five filters, highlights and totals, short values (which
|
|
326
|
+
become escaped literals or query parameters), and computed expressions that pass the same
|
|
327
|
+
validator as Actions → Compute (below). A chip edit is checked the same way; a form that names a
|
|
328
|
+
hidden column, an unknown operator or a chip that isn't there is refused. The report builds the
|
|
329
|
+
SQL and runs it as the application's role. Signed-in users only, unless `"public": true`.
|
|
286
330
|
|
|
287
331
|
| Key | Meaning |
|
|
288
332
|
|---|---|
|
|
289
|
-
| `ai_filter
|
|
333
|
+
| `ai_filter` | `{}` for the built-in phrases |
|
|
334
|
+
| `ai_filter.service` | An AI service's name (the built-in phrases when it isn't available) |
|
|
290
335
|
| `ai_filter.placeholder` | The question box's placeholder |
|
|
291
336
|
| `ai_filter.public` | Also for users who are not signed in |
|
|
292
337
|
|
|
@@ -1297,8 +1342,12 @@ forms *Departments* and *Book a meeting*.
|
|
|
1297
1342
|
### `ai_assistant` (AI assistant)
|
|
1298
1343
|
|
|
1299
1344
|
An **AI assistant** region (APEX: AI Assistant, AI agents and tools) is a chat with an
|
|
1300
|
-
[AI service](06-processing.md#generate-text-with-ai) (Claude
|
|
1301
|
-
configured and allowed for the application.
|
|
1345
|
+
[AI service](06-processing.md#generate-text-with-ai) (Claude, OpenAI, Gemini or an OpenAI-compatible
|
|
1346
|
+
endpoint) that an administrator configured and allowed for the application. Either the region names an
|
|
1347
|
+
**[AI agent](03-builder.md#ai-agents)** of the application (`"agent": "SALES_AGENT"`: the agent sets the
|
|
1348
|
+
service, system prompt, reasoning effort, tools, steps and output limit, and its authorization scheme
|
|
1349
|
+
decides who may use the region; tools may also be PL/pgSQL functions, JavaScript actions and links to
|
|
1350
|
+
pages), or the developer gives the region a system prompt and, optionally,
|
|
1302
1351
|
**context queries** and **tools**; the model then answers questions about the application's data,
|
|
1303
1352
|
calling the tools when it needs to, like an agent. It works without JavaScript (the message is
|
|
1304
1353
|
posted and the page comes back with the answer); with JavaScript the Send button shows that the
|
|
@@ -1344,6 +1393,7 @@ Attributes (written by the region's **Settings**; they travel with the applicati
|
|
|
1344
1393
|
|
|
1345
1394
|
| Key | Default | Meaning |
|
|
1346
1395
|
|---|---|---|
|
|
1396
|
+
| `agent` | | (121) An [AI agent](03-builder.md#ai-agents) of the application; then leave out `service`, `system`, `tools` and `max_rounds` |
|
|
1347
1397
|
| `service` | | The AI service's name |
|
|
1348
1398
|
| `system` | | The system prompt (`&ITEM.` substitutions as delimited data) |
|
|
1349
1399
|
| `welcome` | | The first message shown (translatable) |
|
|
@@ -1357,7 +1407,7 @@ Attributes (written by the region's **Settings**; they travel with the applicati
|
|
|
1357
1407
|
|
|
1358
1408
|
The HR example's page 38 (*HR assistant*) has an assistant with a context query over `hr.policy`
|
|
1359
1409
|
and four tools (the user's own leave, colleagues, departments, and *request_leave*, which files a
|
|
1360
|
-
leave request), next to a staff list with [*Ask in your own words*](#
|
|
1410
|
+
leave request), next to a staff list with [*Ask in your own words*](#ask-in-your-own-words-ai-interactive-reports).
|
|
1361
1411
|
|
|
1362
1412
|
### Template components
|
|
1363
1413
|
|
package/docs/guide/05-items.md
CHANGED
|
@@ -217,6 +217,11 @@ item's config. A combobox is free text and isn't checked.
|
|
|
217
217
|
A `popup_lov` item shows the chosen value's display text and a **Search** button. The button
|
|
218
218
|
opens a dialog with a search field: the server searches the item's own list of values (case
|
|
219
219
|
insensitive, on the display column and any extra columns) and answers one page at a time.
|
|
220
|
+
**The next page loads as the list scrolls** (APEX: infinite scrolling): when the end of the list
|
|
221
|
+
comes into view the dialog fetches the next `page_size` rows and adds them, until the list of
|
|
222
|
+
values has no more, so a list of thousands of rows scrolls to its end without a *More* button. A
|
|
223
|
+
new search starts over at the first page. A browser without `IntersectionObserver` pages with
|
|
224
|
+
‹ and *More* instead.
|
|
220
225
|
|
|
221
226
|
- **Several columns**: the first column is the display value, the second the return value, and
|
|
222
227
|
any further columns are shown in the dialog (and searched), for example:
|
|
@@ -233,7 +238,8 @@ insensitive, on the display column and any extra columns) and answers one page a
|
|
|
233
238
|
parameter (never SQL text), only for an item the user may see and change on a page they may
|
|
234
239
|
open. A submitted value must be one the list of values returns, or the page shows an error.
|
|
235
240
|
|
|
236
|
-
The HR example's page 26 (*Pick an employee*) has one with name, job and department columns
|
|
241
|
+
The HR example's page 26 (*Pick an employee*) has one with name, job and department columns;
|
|
242
|
+
page 47 (*Component details*) one over 6,000 rows, 100 a page.
|
|
237
243
|
|
|
238
244
|
## Cascading lists of values
|
|
239
245
|
|