pgkiln 0.68.0 → 0.70.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.
Files changed (65) hide show
  1. package/db/migrations/135_fulltext_search.sql +60 -0
  2. package/db/migrations/136_vector_search.sql +252 -0
  3. package/docs/apex-feature-parity.md +5 -4
  4. package/docs/guide/03-builder.md +76 -0
  5. package/docs/guide/04-pages-and-regions.md +86 -1
  6. package/docs/guide/09-reference.md +19 -0
  7. package/docs/guide/12-development.md +41 -2
  8. package/docs/guide/15-extensions.md +1 -1
  9. package/examples/hr/README.md +2 -0
  10. package/examples/hr/hr_71_fulltext_search.sql +43 -0
  11. package/examples/hr/hr_72_vector_search.sql +158 -0
  12. package/package.json +1 -1
  13. package/public/builder.css +3 -0
  14. package/src/ai/embeddings.ts +197 -0
  15. package/src/ai/service.ts +13 -9
  16. package/src/app.ts +3 -0
  17. package/src/builder/advisor.ts +79 -3
  18. package/src/builder/ai-agents.ts +13 -5
  19. package/src/builder/components.ts +32 -1
  20. package/src/builder/fulltext.ts +160 -0
  21. package/src/builder/home.ts +1 -0
  22. package/src/builder/i18n/de.ts +54 -0
  23. package/src/builder/i18n/en.ts +55 -0
  24. package/src/builder/i18n/es.ts +54 -0
  25. package/src/builder/i18n/fr.ts +54 -0
  26. package/src/builder/i18n/it.ts +54 -0
  27. package/src/builder/i18n/ja.ts +54 -0
  28. package/src/builder/i18n/ko.ts +54 -0
  29. package/src/builder/i18n/nl.ts +54 -0
  30. package/src/builder/i18n/pt.ts +54 -0
  31. package/src/builder/i18n/zh-cn.ts +54 -0
  32. package/src/builder/i18n/zh-tw.ts +54 -0
  33. package/src/builder/object-actions.ts +2 -0
  34. package/src/builder/shared.ts +1 -1
  35. package/src/builder/sql.ts +6 -0
  36. package/src/builder/table-editor.ts +2 -0
  37. package/src/builder/vector-column.ts +229 -0
  38. package/src/builder/vector-providers.ts +286 -0
  39. package/src/cli/replace.ts +3 -1
  40. package/src/i18n/ar.ts +1 -0
  41. package/src/i18n/cs.ts +1 -0
  42. package/src/i18n/da.ts +1 -0
  43. package/src/i18n/de.ts +1 -0
  44. package/src/i18n/el.ts +1 -0
  45. package/src/i18n/es.ts +1 -0
  46. package/src/i18n/fi.ts +1 -0
  47. package/src/i18n/fr.ts +1 -0
  48. package/src/i18n/he.ts +1 -0
  49. package/src/i18n/it.ts +1 -0
  50. package/src/i18n/ja.ts +1 -0
  51. package/src/i18n/ko.ts +1 -0
  52. package/src/i18n/nb.ts +1 -0
  53. package/src/i18n/pl.ts +1 -0
  54. package/src/i18n/pt.ts +1 -0
  55. package/src/i18n/ru.ts +1 -0
  56. package/src/i18n/sv.ts +1 -0
  57. package/src/i18n/tr.ts +1 -0
  58. package/src/i18n/uk.ts +1 -0
  59. package/src/i18n/zh.ts +1 -0
  60. package/src/i18n.ts +2 -0
  61. package/src/runtime/ai-agents.ts +53 -2
  62. package/src/runtime/report.ts +26 -2
  63. package/src/runtime/search.ts +290 -23
  64. package/src/server.ts +3 -0
  65. package/src/vector.ts +288 -0
@@ -0,0 +1,60 @@
1
+ -- =====================================================================
2
+ -- 135: full-text search configurations (sprint 135, AP-2; APEX: a search
3
+ -- configuration's Search Type "Oracle Text" next to "Standard")
4
+ --
5
+ -- A search configuration gets a search type:
6
+ --
7
+ -- standard every word of the search text in one of the searchable
8
+ -- columns (ILIKE), as before (080);
9
+ -- fulltext PostgreSQL full-text search: the source's tsvector (a column,
10
+ -- an expression, or built from the searchable columns) matched
11
+ -- with websearch_to_tsquery(<text search configuration>, <text>),
12
+ -- the best match first (ts_rank_cd), the matched words
13
+ -- highlighted with ts_headline (src/runtime/search.ts).
14
+ --
15
+ -- The type is open for later ones: `vector` (embeddings) and `hybrid`
16
+ -- (full-text and vector results merged by reciprocal rank fusion) will be
17
+ -- added to the same check with their own columns.
18
+ --
19
+ -- fts_vector a tsvector column of the source, or an expression giving a
20
+ -- tsvector; empty: to_tsvector over the searchable columns
21
+ -- fts_config the text search configuration (pg_ts_config: english,
22
+ -- dutch, german, simple…); empty: the one of the
23
+ -- application's primary language, else simple
24
+ -- did_you_mean with pg_trgm installed: when nothing is found, suggest
25
+ -- the closest words of the source (any search type)
26
+ --
27
+ -- export_app / import_app need no change: the configuration is exported as
28
+ -- to_jsonb of its row, and the before-insert trigger below fills the new
29
+ -- columns for exports made before 135.
30
+ -- =====================================================================
31
+
32
+ alter table meta.search_config
33
+ add column search_type text not null default 'standard',
34
+ add column fts_vector text,
35
+ add column fts_config text,
36
+ add column did_you_mean boolean not null default false;
37
+
38
+ alter table meta.search_config
39
+ add constraint search_config_search_type_check check (search_type in ('standard', 'fulltext')),
40
+ -- a name only (it is checked against pg_ts_config and passed as a query parameter, never as SQL)
41
+ add constraint search_config_fts_config_check check (fts_config is null or fts_config ~ '^[a-z_][a-z0-9_]{0,62}$'),
42
+ add constraint search_config_fts_list_check check (search_type = 'standard' or source_type <> 'list');
43
+
44
+ comment on column meta.search_config.search_type is 'standard (ILIKE per word) or fulltext (websearch_to_tsquery, ts_rank_cd, ts_headline); later vector, hybrid';
45
+ comment on column meta.search_config.fts_vector is 'fulltext: a tsvector column or expression; empty: to_tsvector over the searchable columns';
46
+ comment on column meta.search_config.fts_config is 'fulltext: the text search configuration (pg_ts_config); empty: the application language''s, else simple';
47
+ comment on column meta.search_config.did_you_mean is 'with pg_trgm: suggest the closest words when nothing is found';
48
+
49
+ -- an export made before 135 has none of the new columns
50
+ create or replace function meta.search_config_defaults() returns trigger
51
+ language plpgsql set search_path = pg_catalog as $$
52
+ begin
53
+ new.seq := coalesce(new.seq, 10);
54
+ new.source_type := coalesce(new.source_type, 'table');
55
+ new.searchable_columns := coalesce(new.searchable_columns, '{}');
56
+ new.max_results := coalesce(new.max_results, 10);
57
+ new.search_type := coalesce(new.search_type, 'standard');
58
+ new.did_you_mean := coalesce(new.did_you_mean, false);
59
+ return new;
60
+ end $$;
@@ -0,0 +1,252 @@
1
+ -- =====================================================================
2
+ -- 136: vector providers, vector and hybrid search configurations,
3
+ -- vector columns kept current, Retrieve tools (sprint 136, AP-1;
4
+ -- APEX: Vector Providers, APEX_AI.GET_VECTOR_EMBEDDINGS, a search
5
+ -- configuration of type "Oracle Vector Search")
6
+ --
7
+ -- Everything here installs without pgvector: no meta table or function
8
+ -- uses the `vector` type. Vectors cross meta.* as real[] (pgvector casts
9
+ -- real[] to vector and back); the DDL that adds a vector column to an
10
+ -- application's table is written by the builder (SQL Workshop › Table
11
+ -- Properties › Add vector column) only when the extension is installed.
12
+ --
13
+ -- meta.app.vector_providers: the application's vector providers, a JSON
14
+ -- list (exported with the application in app.json, like ai_agents, 121):
15
+ -- {"name": "POLICY_EMBEDDINGS", "description": "…",
16
+ -- "type": "ai_service", "service": "EMBEDDINGS",
17
+ -- "model": "text-embedding-3-small", "dimensions": 1536,
18
+ -- "batch_size": 64, "per_minute": 60}
19
+ -- {"name": "TOY", "type": "function", "function": "sales.embed", "dimensions": 8}
20
+ -- ai_service: an AI service of the installation (OpenAI, Gemini or an
21
+ -- OpenAI-compatible endpoint such as Ollama) and an embedding model; its
22
+ -- key stays in meta.ai_service (encrypted, never exported). function: a
23
+ -- SQL / PL/pgSQL function (text) returning vector, real[] or float8[].
24
+ -- The server checks the list (src/ai/embeddings.ts).
25
+ --
26
+ -- meta.vector_provider(name, app) returns one definition (none are secret).
27
+ -- meta.embed(text, provider, app) returns the embedding as real[] for a
28
+ -- function provider, called as the caller's role (security invoker). An
29
+ -- AI service is called by the pgkiln server, not from SQL: meta.embed
30
+ -- says so for such a provider (vector search, Retrieve tools and the
31
+ -- vector column queue use it).
32
+ --
33
+ -- meta.search_config: search types `vector` (nearest rows by a vector
34
+ -- column, the user's text embedded by vector_provider; distance cosine,
35
+ -- l2 or inner_product; at least min_similarity) and `hybrid` (full-text
36
+ -- and vector rankings merged by reciprocal rank fusion, rows matched by
37
+ -- key_column). The new columns travel with the configuration
38
+ -- (to_jsonb of the row); the defaults trigger fills them for older exports.
39
+ --
40
+ -- Keeping a vector column current (triggers the builder creates on the
41
+ -- application's table; their arguments: app id, provider, vector column,
42
+ -- key column, source columns…):
43
+ -- meta.embedding_set() BEFORE INSERT OR UPDATE OF the source columns:
44
+ -- a function provider's embedding, at once;
45
+ -- meta.embedding_enqueue() AFTER INSERT OR UPDATE OF the source columns:
46
+ -- the row's key into meta.embedding_queue; the
47
+ -- server embeds queued rows in batches, within
48
+ -- the provider's requests per minute and the
49
+ -- application's daily AI limits (src/embeddings.ts).
50
+ -- meta.embedding_queue: installation data, not exported (like
51
+ -- meta.process_job); only the owner reads it.
52
+ -- =====================================================================
53
+
54
+ alter table meta.app add column vector_providers jsonb not null default '[]'
55
+ check (jsonb_typeof(vector_providers) = 'array');
56
+ comment on column meta.app.vector_providers is 'Vector providers (136): an AI service with an embedding model, or a function returning vector; exported with the application';
57
+
58
+ -- an export made before 136 has no vector_providers (nor one before 121 ai_tools / ai_agents)
59
+ create or replace function meta.app_ai_default() returns trigger
60
+ language plpgsql set search_path = pg_catalog as $$
61
+ begin
62
+ new.ai_tools := coalesce(new.ai_tools, '[]');
63
+ new.ai_agents := coalesce(new.ai_agents, '[]');
64
+ new.vector_providers := coalesce(new.vector_providers, '[]');
65
+ return new;
66
+ end $$;
67
+
68
+ -- ---------------------------------------------------------------- providers and meta.embed
69
+
70
+ -- One vector provider of an application (the current one, or one the login may see).
71
+ create function meta.vector_provider(p_name text, p_app int default null) returns jsonb
72
+ language plpgsql stable security definer set search_path = meta, pg_catalog as $$
73
+ declare
74
+ v_app int := coalesce(p_app, meta.app_id());
75
+ begin
76
+ if v_app is null then
77
+ raise exception 'meta.vector_provider: no current application (pass the application''s id)';
78
+ end if;
79
+ if not meta.app_visible(v_app) then
80
+ raise exception 'Application % is not in this workspace.', v_app using errcode = '42501';
81
+ end if;
82
+ return (select e from meta.app a, jsonb_array_elements(a.vector_providers) e
83
+ where a.id = v_app and e->>'name' = upper(p_name) limit 1);
84
+ end
85
+ $$;
86
+
87
+ -- The embedding of a text by a function provider, as real[] (cast it: meta.embed(…)::vector).
88
+ -- Runs the provider's function as the caller (security invoker): its grants apply. Stable, so
89
+ -- "order by embedding <=> meta.embed(…)::vector" embeds the text once (an index scan's argument).
90
+ create function meta.embed(p_text text, p_provider text, p_app int default null) returns real[]
91
+ language plpgsql stable set search_path = meta, pg_catalog as $$
92
+ declare
93
+ v jsonb := meta.vector_provider(p_provider, p_app);
94
+ fn text;
95
+ r real[];
96
+ begin
97
+ if v is null then
98
+ raise exception 'meta.embed: there is no vector provider %', upper(p_provider);
99
+ end if;
100
+ if p_text is null then
101
+ return null;
102
+ end if;
103
+ if v->>'type' is distinct from 'function' then
104
+ raise exception 'meta.embed: vector provider % uses AI service %, which the pgkiln server calls: use it in a vector search configuration, a Retrieve tool or a vector column (Table Properties › Add vector column); in SQL only function providers embed',
105
+ v->>'name', v->>'service';
106
+ end if;
107
+ fn := v->>'function';
108
+ if fn !~ '^[A-Za-z_][A-Za-z0-9_]{0,62}\.[A-Za-z_][A-Za-z0-9_]{0,62}$' then
109
+ raise exception 'meta.embed: the function of vector provider % is schema.name', v->>'name';
110
+ end if;
111
+ execute format('select (%I.%I($1))::real[]', split_part(fn, '.', 1), split_part(fn, '.', 2)) into r using p_text;
112
+ if r is not null and cardinality(r) is distinct from (v->>'dimensions')::int then
113
+ raise exception 'meta.embed: % returned % dimensions, vector provider % has %', fn, cardinality(r), v->>'name', v->>'dimensions';
114
+ end if;
115
+ return r;
116
+ end
117
+ $$;
118
+
119
+ -- ---------------------------------------------------------------- keeping vector columns current
120
+
121
+ create table meta.embedding_queue (
122
+ id bigserial primary key,
123
+ app_id int not null references meta.app on delete cascade,
124
+ provider text not null,
125
+ -- the table whose trigger queued the row (pg_class oid)
126
+ tbl oid not null,
127
+ vector_column text not null,
128
+ key_column text not null,
129
+ source_columns text[] not null,
130
+ key_value text not null,
131
+ queued_at timestamptz not null default now(),
132
+ next_at timestamptz not null default now(),
133
+ attempts int not null default 0,
134
+ last_error text,
135
+ unique (tbl, vector_column, key_value)
136
+ );
137
+ create index on meta.embedding_queue (next_at);
138
+ create index on meta.embedding_queue (app_id, provider);
139
+ revoke all on meta.embedding_queue from public;
140
+ comment on table meta.embedding_queue is 'Rows whose vector column the pgkiln server re-embeds (136): queued by meta.embedding_enqueue() triggers and Backfill';
141
+
142
+ -- the trigger arguments: app id, provider, vector column, key column, source columns
143
+ create function meta.embedding_args_ok(p_args text[]) returns boolean
144
+ language sql immutable set search_path = pg_catalog as $$
145
+ select cardinality(p_args) between 5 and 24
146
+ and p_args[1] ~ '^[0-9]{1,10}$'
147
+ and p_args[2] ~ '^[A-Za-z][A-Za-z0-9_]{0,59}$'
148
+ and not exists (select from unnest(p_args[3:]) c where c !~ '^[a-z_][a-z0-9_$]{0,62}$')
149
+ $$;
150
+
151
+ -- the text a row is embedded from: its source columns, one per line
152
+ create function meta.embedding_text(p_row jsonb, p_columns text[]) returns text
153
+ language sql immutable set search_path = pg_catalog as $$
154
+ select nullif(concat_ws(E'\n', variadic array(select p_row->>c from unnest(p_columns) with ordinality u(c, n) order by n)), '')
155
+ $$;
156
+
157
+ -- BEFORE INSERT OR UPDATE OF …: a function provider's embedding, set at once (as the role that writes the row)
158
+ create function meta.embedding_set() returns trigger
159
+ language plpgsql volatile set search_path = meta, pg_catalog as $$
160
+ declare
161
+ v_args text[] := array(select unnest(tg_argv));
162
+ v_cols text[];
163
+ v_vec real[];
164
+ begin
165
+ if not meta.embedding_args_ok(v_args) then
166
+ raise exception 'meta.embedding_set: the arguments are app id, provider, vector column, key column, source columns';
167
+ end if;
168
+ v_cols := v_args[5:];
169
+ if tg_op = 'UPDATE' and meta.embedding_text(to_jsonb(old), v_cols) is not distinct from meta.embedding_text(to_jsonb(new), v_cols)
170
+ and to_jsonb(new)->>v_args[3] is not null then
171
+ return new;
172
+ end if;
173
+ v_vec := meta.embed(meta.embedding_text(to_jsonb(new), v_cols), v_args[2], v_args[1]::int);
174
+ new := jsonb_populate_record(new, jsonb_build_object(v_args[3], translate(v_vec::text, '{}', '[]')));
175
+ return new;
176
+ end
177
+ $$;
178
+
179
+ -- AFTER INSERT OR UPDATE OF …: the row's key into the queue (the server embeds it)
180
+ create function meta.embedding_enqueue() returns trigger
181
+ language plpgsql volatile security definer set search_path = meta, pg_catalog as $$
182
+ declare
183
+ v_args text[] := array(select unnest(tg_argv));
184
+ v_app int;
185
+ v_key text;
186
+ begin
187
+ if not meta.embedding_args_ok(v_args) then
188
+ raise exception 'meta.embedding_enqueue: the arguments are app id, provider, vector column, key column, source columns';
189
+ end if;
190
+ v_app := v_args[1]::int;
191
+ if not meta.app_visible(v_app) then
192
+ raise exception 'Application % is not in this workspace.', v_app using errcode = '42501';
193
+ end if;
194
+ if tg_op = 'UPDATE' and meta.embedding_text(to_jsonb(old), v_args[5:]) is not distinct from meta.embedding_text(to_jsonb(new), v_args[5:]) then
195
+ return null;
196
+ end if;
197
+ v_key := to_jsonb(new)->>v_args[4];
198
+ if v_key is null then
199
+ return null;
200
+ end if;
201
+ insert into meta.embedding_queue (app_id, provider, tbl, vector_column, key_column, source_columns, key_value)
202
+ values (v_app, upper(v_args[2]), tg_relid, v_args[3], v_args[4], v_args[5:], v_key)
203
+ on conflict (tbl, vector_column, key_value) do update
204
+ set app_id = excluded.app_id, provider = excluded.provider, key_column = excluded.key_column,
205
+ source_columns = excluded.source_columns, queued_at = now(), next_at = now(), attempts = 0, last_error = null;
206
+ return null;
207
+ end
208
+ $$;
209
+
210
+ grant execute on function meta.vector_provider(text, int), meta.embed(text, text, int), meta.embedding_args_ok(text[]),
211
+ meta.embedding_text(jsonb, text[]), meta.embedding_set(), meta.embedding_enqueue() to public;
212
+
213
+ -- ---------------------------------------------------------------- vector and hybrid search configurations
214
+
215
+ alter table meta.search_config
216
+ add column vector_provider text,
217
+ add column vector_column text,
218
+ add column key_column text,
219
+ add column distance text not null default 'cosine',
220
+ add column min_similarity real;
221
+
222
+ alter table meta.search_config drop constraint search_config_search_type_check;
223
+ alter table meta.search_config
224
+ add constraint search_config_search_type_check check (search_type in ('standard', 'fulltext', 'vector', 'hybrid')),
225
+ add constraint search_config_vector_provider_check check (vector_provider is null or vector_provider ~ '^[A-Z][A-Z0-9_]{0,59}$'),
226
+ -- column names only (quoted as identifiers by the server)
227
+ add constraint search_config_vector_column_check check (vector_column is null or vector_column ~ '^[A-Za-z_][A-Za-z0-9_$]{0,62}$'),
228
+ add constraint search_config_key_column_check check (key_column is null or key_column ~ '^[A-Za-z_][A-Za-z0-9_$]{0,62}$'),
229
+ add constraint search_config_distance_check check (distance in ('cosine', 'l2', 'inner_product')),
230
+ add constraint search_config_min_similarity_check check (min_similarity is null or min_similarity between -1 and 1),
231
+ add constraint search_config_vector_check check (search_type not in ('vector', 'hybrid') or (vector_provider is not null and vector_column is not null)),
232
+ add constraint search_config_hybrid_key_check check (search_type <> 'hybrid' or key_column is not null);
233
+
234
+ comment on column meta.search_config.search_type is 'standard (ILIKE per word), fulltext (websearch_to_tsquery, ts_rank_cd, ts_headline), vector (nearest by an embedding, 136) or hybrid (fulltext and vector by reciprocal rank fusion, 136)';
235
+ comment on column meta.search_config.vector_provider is 'vector, hybrid: the vector provider (static ID) that embeds the search text';
236
+ comment on column meta.search_config.vector_column is 'vector, hybrid: the source''s vector column';
237
+ comment on column meta.search_config.key_column is 'hybrid: the key that matches full-text and vector results';
238
+ comment on column meta.search_config.distance is 'vector, hybrid: cosine (<=>), l2 (<->) or inner_product (<#>)';
239
+ comment on column meta.search_config.min_similarity is 'vector, hybrid: at least this similarity (cosine: 1 - distance; inner product: the product; l2: 1 / (1 + distance))';
240
+
241
+ create or replace function meta.search_config_defaults() returns trigger
242
+ language plpgsql set search_path = pg_catalog as $$
243
+ begin
244
+ new.seq := coalesce(new.seq, 10);
245
+ new.source_type := coalesce(new.source_type, 'table');
246
+ new.searchable_columns := coalesce(new.searchable_columns, '{}');
247
+ new.max_results := coalesce(new.max_results, 10);
248
+ new.search_type := coalesce(new.search_type, 'standard');
249
+ new.did_you_mean := coalesce(new.did_you_mean, false);
250
+ new.distance := coalesce(new.distance, 'cosine');
251
+ return new;
252
+ end $$;
@@ -7,7 +7,7 @@ open item and open an issue or pull request; see [CONTRIBUTING.md](../CONTRIBUTI
7
7
  Legend: ✅ available · 🟡 partial (see notes) · ❌ not yet · ➖ not planned (a deliberate choice,
8
8
  or better served by the PostgreSQL ecosystem; see the notes and [extensions](guide/15-extensions.md))
9
9
 
10
- Last reviewed: 2026-10-27 against **APEX 26.2** (sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
10
+ Last reviewed: 2026-11-03 against **APEX 26.2** (sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
11
11
 
12
12
  ## At a glance
13
13
 
@@ -85,7 +85,7 @@ the 26.2 comparison.)
85
85
  | Pagination of large tables (row ranges, maximum row count) | ✅ | Reports and grids page in the database; `"pagination": "range"` shows APEX's "row ranges X to Y" without a total (it reads one row more for *Next*); `max_rows` is a maximum row count (the total is counted over at most max+1 rows: "of more than N"; downloads are capped too); page numbers and sizes are clamped on the server. Cards (500), charts (1000), dynamic content (1000) and lists of values (5000) have configurable row limits. Keyset ("seek") paging on an indexed sort (`"keyset"`), with signed positions |
86
86
  | Lazy loading of regions | ✅ | `"lazy": true` on report, chart, cards, dynamic, tree and template component regions: a placeholder, fetched after the page shows (page, condition and authorization re-checked); without JavaScript a link shows the region ([chapter 4](guide/04-pages-and-regions.md#large-tables)) |
87
87
  | Region caching (per user, per session, for a duration) | ✅ | `"cache": {"scope": "user" \| "session" \| "all", "seconds": N}` keeps rendered regions in server memory, keyed by app, region, roles, language, the query string and the item values the region uses; a page submit empties it. CSRF tokens and per-user links are never shared. Per server process |
88
- | Search configurations and the search region (22.2) | ✅ | (sprint 50) Shared Components → **Search configurations**: a table, a query (binds allowed) or a list, the searchable columns, and each result's title, subtitle, description, badge, icon and link. A **search** region searches the ones it names with one field (or a page item): every word in one of the columns, as the app's role with the text as a parameter; results grouped per configuration with the words marked; searches as you type, works without JavaScript; exported; checked by the Advisor ([chapter 4](guide/04-pages-and-regions.md#search-search-region)). No Oracle Text, no REST data sources or APEX-application search as sources, no custom result templates |
88
+ | Search configurations and the search region (22.2) | ✅ | (sprint 50) Shared Components → **Search configurations**: a table, a query (binds allowed) or a list, the searchable columns, and each result's title, subtitle, description, badge, icon and link. A **search** region searches the ones it names with one field (or a page item): every word in one of the columns, as the app's role with the text as a parameter; results grouped per configuration with the words marked; searches as you type, works without JavaScript; exported; checked by the Advisor ([chapter 4](guide/04-pages-and-regions.md#search-search-region)). (sprint 135) Search type **fulltext** for APEX's *Oracle Text*: a tsvector column or expression (or built from the searchable columns), a text search configuration per application language (`simple` as fallback), `websearch_to_tsquery` for the user's text (phrases, or, -word), the best match first (`ts_rank_cd`) and matched words highlighted (`ts_headline`, escaped); *Did you mean* with `pg_trgm`; SQL Workshop › Table Properties › *Add full-text search* (generated tsvector column and GIN index, previewed, recorded in the Change Log); report search boxes use a tsvector column too; the Advisor warns about a missing GIN index ([full-text search](guide/04-pages-and-regions.md#full-text-search)). (sprint 136) Search type **vector** for APEX's *Oracle Vector Search*: a vector provider embeds the search text, the nearest rows by a `vector(n)` column (cosine, L2 or inner product, a minimum similarity), and **hybrid**: full-text and vector rankings merged by reciprocal rank fusion; as the app's role, so RLS decides what is found; needs pgvector and says so without it; the Advisor checks the provider, the dimensions and the HNSW index ([vector search](guide/04-pages-and-regions.md#vector-search)). No REST data sources or APEX-application search as sources, no custom result templates |
89
89
  | URL region | ✅ | (sprint 50) A **url** region frames another site's page (or one of this server) in a sandboxed iframe: the origin is written out (an item can never choose the host), `&ITEM.` values after it are URL-encoded, and the page's CSP gets `frame-src` for exactly the origins of its visible URL regions; height, sandbox flags and full screen in the attributes; an *Open in a new tab* link ([chapter 4](guide/04-pages-and-regions.md#url-url-region)) |
90
90
  | Template components and template directives | ✅ | Shared Components → Template components: `#PLACEHOLDERS#` (always escaped), `{if}`, `{case}` and `{loop}` directives, custom attributes, a wrapper; as a region type and as report column templates, with a preview. Templates are checked against an allow-list (no scripts, styles, event handlers or `javascript:` links) ([chapter 4](guide/04-pages-and-regions.md#template-components)) |
91
91
 
@@ -213,7 +213,8 @@ the 26.2 comparison.)
213
213
  | Approvals and task list | ✅ | Task definitions (approval / action, owner roles and users, business administrators, priority, due date, details page), `meta.create_task` from application SQL, a task list region (claim, approve/reject/complete with comment, release, delegate, cancel, history), completion SQL in the same transaction. (sprint 64) **Vacation rules** (a stand-in acts on a user's tasks while the rule is active, checked on every request) and **expiration policies** (expire, renew up to N times, escalate to a role once; a waiting workflow goes on with the outcome `expired`). (sprint 114) **custom outcomes** with labels and colours (Yes / No / Undecided), **task events** on complete, expire and a failed completion SQL (SQL, e-mail or start a workflow; reopen or keep the task) and **notifications** from e-mail templates on create, complete and expire ([chapter 6](guide/06-processing.md#custom-outcomes)) |
214
214
  | Workflow (26.1: parallel flows, multi-tenancy) | ✅ | Workflow definitions of task, SQL, switch, wait, **invoke API** (a REST data source or URL through the invoke-API code, response values and the HTTP status into variables, retryable faults, no transaction open during the call) and end steps with variables, started from application SQL, run by the server (NOTIFY + polling) as the app's role; console region (terminate, retry a faulted step); diagram in the builder. **Parallel branches** (split, then a join that waits for all or for the first branch) and **versions** (development, active, inactive; running instances keep theirs) ([chapter 6](guide/06-processing.md#workflows)). (0.31) **Tenants**: `meta.set_tenant()` (APEX: `APEX_SESSION.SET_TENANT_ID`); workflows, their tasks, background chains, the task list, the console and every action follow the session's tenant ([chapter 6](guide/06-processing.md#tenants)). (sprint 114, 26.1 / 26.2) **Send E-Mail** steps (a template or subject and body), **draft** steps allowed only in development versions, branching on custom task outcomes, **migrating running instances** to a newer version (step mapping, preview, one transaction, a log; not yet for instances inside open parallel branches: [chapter 6](guide/06-processing.md#migrating-instances)) and the diagram as **SVG / PNG** |
215
215
  | Automations (scheduled) | ✅ | Shared Components → Automations: cron schedules with time zones, once or per row of a query, **several ordered actions** with their own conditions, **error handling** (stop, skip the row and continue, or disable; row errors in the run history), roles, run history and Run now, **on-demand runs from SQL** with `meta.run_automation()` (like `APEX_AUTOMATION.EXECUTE`, synchronous in the caller's transaction), safe with several servers ([chapter 6](guide/06-processing.md#automations)) |
216
- | AI assistant, natural-language reports (NL2IR), AI agents and tools (26.1) | ✅ | Region type **AI assistant**: a conversation per session, context queries (RAG over developer queries, run as the app's role, read-only), and **tools** the model may call: SQL with bound arguments checked against declared parameters (read-only unless marked as writing, row limit, timeout) and REST data sources, each optionally behind an authorization scheme. **AI Interactive Reports** (sprint 112; 26.1 / 26.2): an "Ask in your own words" box turns a question into the report's own settings (filters, highlights, search, sort, control break, totals, group by, pivot, chart and computed columns such as "bonus is 10% of salary"), never SQL, limited to its shown columns; each setting is a chip with Edit and Remove, plus Undo. Without an AI service a built-in phrase parser (English, Dutch, German) answers ([chapter 4](guide/04-pages-and-regions.md#ask-in-your-own-words-ai-interactive-reports)). (sprint 122) Conditions a facet can hold set the page's **faceted search and smart filters** facets (values, excluded values, custom ranges, stars), shown as chips; smart filters with `"ask": true` read a typed phrase and offer it as one suggestion. (sprint 111) **AI Agents** as a shared component (26.1 / 26.2): an AI service, system prompt, reasoning effort (low / medium / high, mapped per provider), approved tools, max steps and tokens and an authorization scheme; an assistant region names one. **AI Tools**: SQL (read-only transaction, the app role through RLS, timeout), PL/pgSQL function, REST data source, JavaScript action (a registered action or custom-event dynamic action), and **Navigate**: pgkiln builds the checksummed URL, only to pages the user may open. Every tool call is logged with its arguments (debug and Activity → AI usage). Providers add Gemini and OpenAI-compatible endpoints (Ollama, vLLM, Azure OpenAI). Answers are not streamed; no OCI provider. `pgvector` covers semantic search on the data side |
216
+ | AI assistant, natural-language reports (NL2IR), AI agents and tools (26.1) | ✅ | Region type **AI assistant**: a conversation per session, context queries (RAG over developer queries, run as the app's role, read-only), and **tools** the model may call: SQL with bound arguments checked against declared parameters (read-only unless marked as writing, row limit, timeout) and REST data sources, each optionally behind an authorization scheme. **AI Interactive Reports** (sprint 112; 26.1 / 26.2): an "Ask in your own words" box turns a question into the report's own settings (filters, highlights, search, sort, control break, totals, group by, pivot, chart and computed columns such as "bonus is 10% of salary"), never SQL, limited to its shown columns; each setting is a chip with Edit and Remove, plus Undo. Without an AI service a built-in phrase parser (English, Dutch, German) answers ([chapter 4](guide/04-pages-and-regions.md#ask-in-your-own-words-ai-interactive-reports)). (sprint 122) Conditions a facet can hold set the page's **faceted search and smart filters** facets (values, excluded values, custom ranges, stars), shown as chips; smart filters with `"ask": true` read a typed phrase and offer it as one suggestion. (sprint 111) **AI Agents** as a shared component (26.1 / 26.2): an AI service, system prompt, reasoning effort (low / medium / high, mapped per provider), approved tools, max steps and tokens and an authorization scheme; an assistant region names one. **AI Tools**: SQL (read-only transaction, the app role through RLS, timeout), PL/pgSQL function, REST data source, JavaScript action (a registered action or custom-event dynamic action), and **Navigate**: pgkiln builds the checksummed URL, only to pages the user may open. Every tool call is logged with its arguments (debug and Activity → AI usage). Providers add Gemini and OpenAI-compatible endpoints (Ollama, vLLM, Azure OpenAI). Answers are not streamed; no OCI provider. `pgvector` covers semantic search on the data side (sprint 136) A **Retrieve (RAG)** tool type: the model gives a text, the agent gets the best rows of a search configuration (vector or hybrid) as the app's role in a read-only transaction, logged like other tools |
217
+ | Vector providers, `APEX_AI.GET_VECTOR_EMBEDDINGS`, vector search (24.2) | ✅ | (sprint 136, AP-1) Shared Components → **Vector providers** (exported with the application): an AI service with an embedding model (OpenAI `text-embedding-3-*`, Gemini, any OpenAI-compatible endpoint such as Ollama; the key stays with the service) or a SQL / PL/pgSQL function returning `vector`, with its dimensions, checked on every embedding and against vector columns; **Test**. `meta.embed(text, provider)` for function providers in SQL (as the caller; AI services are called by the server only). Workspace utilities → Vector providers: pgvector detected, *Create extension vector* for administrators, the workspace's providers and vector columns. SQL Workshop › Table Properties › **Add vector column**: `vector(n)`, an HNSW index and a trigger that re-embeds changed rows, at once (function) or through a queue the server works in batches within the provider's requests per minute and the app's daily AI limits, logged under AI usage; **Backfill** with progress ([chapter 3](guide/03-builder.md#vector-providers)). No ONNX models in the database (use a function provider, e.g. pgml or pgai) |
217
218
  | *Generate Text with AI* process, structured outputs (26.1) | ✅ | **AI services** (Workspace utilities, administrators): Claude through `@anthropic-ai/sdk` or OpenAI through `openai`, encrypted write-only keys (or `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`), per-app access with daily request and token limits, a usage log. Page process `ai_generate` (text into an item, or structured output into several items with a schema built from the items or your own) and a dynamic action that runs it without a page submit; `meta.ai_generate` / `ai_result` / `ai_available` from SQL ([chapter 6](guide/06-processing.md)). Prompts, item values included, go to the chosen provider |
218
219
  | Blueprints, spec-driven development (26.1) | ✅ | Create → **From a blueprint**: a JSON spec of tables (types, required, unique, allowed values, references), pages, navigation and sample data; optionally drafted by AI from a description; always reviewed (problems, SQL, pages, menu) before the application is created in one transaction; saved blueprints; (sprint 66) **a blueprint from an existing application** (its tables, pages, menu and optionally sample rows, with notes on what didn't carry over) |
219
220
 
@@ -281,7 +282,7 @@ row above where there is one.
281
282
  | Automations / scheduler | built in, or `pg_cron` | [chapter 6](guide/06-processing.md#automations), [chapter 15](guide/15-extensions.md#tier-2-third-party-widely-available) |
282
283
  | Calling REST APIs synchronously from SQL (`APEX_WEB_SERVICE`; the built-in `meta.web_request()` is queued) | `http`, `pg_net` | [chapter 15](guide/15-extensions.md#tier-3-situational) |
283
284
  | Map data | PostGIS | [chapter 15](guide/15-extensions.md#tier-2-third-party-widely-available) |
284
- | Semantic search / RAG | `pgvector` | [chapter 15](guide/15-extensions.md#tier-2-third-party-widely-available) |
285
+ | Semantic search / RAG | `pgvector` (sprint 136: vector providers, vector and hybrid search and Retrieve tools are built in on it) | [chapter 4](guide/04-pages-and-regions.md#vector-search), [chapter 15](guide/15-extensions.md#tier-2-third-party-widely-available) |
285
286
  | Statement auditing | `pgaudit` | [chapter 15](guide/15-extensions.md#tier-2-third-party-widely-available) |
286
287
  | Code checks (Advisor for PL/pgSQL functions) | `plpgsql_check` (used by the Advisor when installed) | [chapter 15](guide/15-extensions.md#tier-2-third-party-widely-available) |
287
288
  | Pivot reports | `tablefunc` | [chapter 15](guide/15-extensions.md#tier-1-included-with-postgresql) |
@@ -1721,6 +1721,7 @@ scheme (only users who pass it are offered the tool) and one of these types:
1721
1721
  | **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) |
1722
1722
  | **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 |
1723
1723
  | **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 |
1724
+ | **Retrieve (RAG)** | (sprint 136) the model gives a text (`QUERY`); pgkiln runs the tool's **search configuration** (best: [vector or hybrid](04-pages-and-regions.md#vector-search)) and returns the best rows' title, text (the description column) and score | as the application's role in a **read-only transaction** with the time limit, so row level security decides which rows the model sees; at most *maximum rows* rows (default 5); no parameters of its own |
1724
1725
 
1725
1726
  The model's arguments are checked against the parameters before a tool runs; they are bind values
1726
1727
  (escaped literals), never SQL text, and can't replace the server's own names (`:APP_USER`, `:APP_ID`, …).
@@ -1743,6 +1744,70 @@ earns most?* and it calls the SQL tool `top_earners` as the signed-in user's rol
1743
1744
  *Open BLAKE's record*, a link to the employee form (page 3) with a valid checksum, only to users who
1744
1745
  may open that page.
1745
1746
 
1747
+ ## Vector providers
1748
+
1749
+ (sprint 136; APEX: Vector Providers) A **vector provider** turns a text into an **embedding**: a list of numbers
1750
+ (the *dimensions*) whose distance says how close two texts are in meaning. Vector columns, search configurations
1751
+ of type [vector or hybrid](04-pages-and-regions.md#vector-search) and the [Retrieve tools](#ai-agents) of AI
1752
+ agents use one. Providers are part of the application: Shared Components → Generative AI → **Vector providers**
1753
+ (kept in `meta.app.vector_providers`, exported with the application). A provider has:
1754
+
1755
+ - a **name** (static ID, upper case, e.g. `DOC_EMBEDDINGS`) and a description;
1756
+ - a **type**:
1757
+ - *AI service with an embedding model*: an [AI service](#ai-services) the application may use (OpenAI,
1758
+ Gemini, or OpenAI-compatible such as Ollama; Claude has no embeddings API) and the model, exactly as the
1759
+ provider names it: `text-embedding-3-small` (1536 dimensions; OpenAI shortens them to the provider's
1760
+ dimensions), `text-embedding-3-large` (3072), `gemini-embedding-001`, `nomic-embed-text` (768),
1761
+ `mxbai-embed-large` (1024) … The key, base URL and daily limits are the service's: **the key stays with the
1762
+ AI service** (encrypted, write-only, never exported); the export carries only the service's name. Texts per
1763
+ request and requests per minute limit the background embedding of queued rows;
1764
+ - *SQL or PL/pgSQL function*: `schema.name` of a function `(text)` returning `vector`, `real[]` or
1765
+ `float8[]`, e.g. a model inside the database (`pgml.embed`, `ai.openai_embed` of pgai) or your own;
1766
+ - the **dimensions**: every embedding is checked against them, and a vector column is `vector(n)` with this *n*
1767
+ (an HNSW index takes up to 2,000).
1768
+
1769
+ **Test** embeds a sample text and shows how many dimensions came back. A provider's page lists the search
1770
+ configurations and vector columns that use it. In SQL, `meta.embed(text, 'DOC_EMBEDDINGS')` returns a function
1771
+ provider's embedding as `real[]` (cast it: `meta.embed(…)::vector`), running the function **as the role of the
1772
+ query** (its grants apply: grant execute on it to the application's role). An AI service is called by the pgkiln
1773
+ server, never from SQL: `meta.embed` says so for such a provider; use it through a search configuration, a
1774
+ Retrieve tool or a vector column's queue.
1775
+
1776
+ **pgvector.** Everything with vectors needs the [pgvector](https://github.com/pgvector/pgvector) extension in
1777
+ the database (pgkiln itself installs without it). Workspace utilities → **Vector providers** says whether it is
1778
+ installed; when the database server has the package, administrators get **Create extension vector** (pgvector is
1779
+ not a trusted extension: the owner connection must be a superuser; otherwise a superuser runs
1780
+ `create extension vector;`). Without the package: install it (`apt install postgresql-17-pgvector`, the
1781
+ `pgvector/pgvector:pg17` Docker image, or the managed database's *vector* extension). The same page lists every
1782
+ provider of the workspace's applications and the vector columns they keep current.
1783
+
1784
+ **Add vector column** (SQL Workshop › Table Properties, or a table's ⋯ menu) needs a table with a one-column
1785
+ primary key: pick a provider of the workspace's applications, the **source columns** (their text, one per line,
1786
+ is embedded), the distance (`cosine`, `l2`, `inner_product`) and the column's and index's names. **Preview DDL**
1787
+ shows what Apply runs in one transaction (recorded in the Change Log); **Open in the worksheet** puts it there:
1788
+
1789
+ ```sql
1790
+ alter table sales.doc add column embedding public.vector(1536);
1791
+ create index doc_embedding_idx on sales.doc using hnsw (embedding vector_cosine_ops);
1792
+ create trigger embedding_embed after insert or update of title, body on sales.doc
1793
+ for each row execute function meta.embedding_enqueue('12', 'DOC_EMBEDDINGS', 'embedding', 'id', 'title', 'body');
1794
+ ```
1795
+
1796
+ **Keeping it current.** With an AI service the trigger (`meta.embedding_enqueue`) puts the changed row's key in a
1797
+ queue (`meta.embedding_queue`; a change to other columns, or to the same text, queues nothing). The server embeds
1798
+ queued rows in batches of the provider's *texts per request*, at most its *requests per minute*, within the
1799
+ application's daily AI limits, logged under AI usage (source *embedding*), and writes the vectors with the
1800
+ workspace's developer connection (the one the SQL Workshop uses). A failing batch keeps its message and is tried
1801
+ again after 1, 2, 4 … minutes (six times). A function provider can instead set the embedding **in the trigger**
1802
+ (`meta.embedding_set`, before insert or update, as the role that writes the row). After Apply the rows already
1803
+ there are queued; the page shows each vector column with a progress bar (rows embedded, queued, failing, the last
1804
+ message) and **Backfill**, which queues the rows without an embedding (or, ticked, all rows: after changing the
1805
+ provider's model). The server polls the queue every `EMBEDDING_INTERVAL_S` seconds (default 5);
1806
+ `EMBEDDINGS=off` keeps a server from embedding (another one does it).
1807
+
1808
+ **What goes to the provider**: the source columns' text of every row, and every search text. Choose a provider
1809
+ your organisation allows for that data; a function provider keeps it in the database.
1810
+
1746
1811
  ## App Builder AI
1747
1812
 
1748
1813
  The App Builder uses one AI service (APEX: AI Assistant in App Builder and SQL Workshop). An
@@ -1853,6 +1918,17 @@ the SQL Workshop's connection may use. Without JavaScript the header's field ope
1853
1918
  transaction (nothing changes when one fails, and the error shows under *Output*); **Open in the worksheet** puts
1854
1919
  them there instead. *Use as template* starts a new table with the same columns and keys (names with `_copy`).
1855
1920
  Defaults, checks and index expressions are single expressions (no `;` or comments).
1921
+ (sprint 135) **Add full-text search…** (a table's Table Properties, or its ⋯ menu): pick the text columns, a
1922
+ weight for each (A counts most in the ranking, D least: A for a title, B for a body), the **text search
1923
+ configuration** (the languages PostgreSQL has, `english`, `dutch`, `german`…, or `simple` without stemming) and the
1924
+ names of the column and the index. **Preview DDL** shows a stored generated `tsvector` column and a GIN index on it;
1925
+ **Apply** runs both in one transaction and records them in the **Change Log**; **Open in the worksheet** puts them
1926
+ there. The column keeps itself up to date; adding it rewrites the table. Name the column in a search
1927
+ configuration of search type *fulltext*, or in a report's `fulltext` attribute.
1928
+ (sprint 136) **Add vector column…** (Table Properties, or the ⋯ menu): an embedding column `vector(n)` from a
1929
+ [vector provider](#vector-providers), an HNSW index for the distance and a trigger that re-embeds a row when its
1930
+ source columns change (at once with a function provider, else through the server's queue); the page shows each
1931
+ vector column's progress and **Backfill**. Without pgvector it says what is missing.
1856
1932
  - (sprint 119) **Security** (the Object Browser's *Security* button on a table, *Security…* in its ⋯ menu): the
1857
1933
  table's row level security policies, a matrix of database roles × columns with *read* and *update*, and masked
1858
1934
  columns per application role in a masking view; Preview SQL, Apply (one transaction, recorded in the Change Log)