@pikku/kysely 0.13.15 → 0.13.18
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/CHANGELOG.md +229 -0
- package/bin/pikku-kysely-pure.ts +0 -0
- package/dist/src/coercion-plugin.d.ts +41 -0
- package/dist/src/coercion-plugin.js +150 -0
- package/dist/src/create-audited-kysely.d.ts +1 -1
- package/dist/src/index.d.ts +6 -5
- package/dist/src/index.js +5 -4
- package/dist/src/{kysely-ai-run-scores.d.ts → kysely-agent-run-scores.d.ts} +3 -3
- package/dist/src/{kysely-ai-run-scores.js → kysely-agent-run-scores.js} +3 -3
- package/dist/src/{kysely-ai-agent-run-service.d.ts → kysely-agent-run-service.d.ts} +4 -4
- package/dist/src/{kysely-ai-agent-run-service.js → kysely-agent-run-service.js} +8 -8
- package/dist/src/{kysely-ai-run-state-service.d.ts → kysely-agent-run-state-service.d.ts} +6 -5
- package/dist/src/{kysely-ai-run-state-service.js → kysely-agent-run-state-service.js} +11 -11
- package/dist/src/{kysely-ai-storage-service.d.ts → kysely-agent-storage-service.d.ts} +10 -10
- package/dist/src/{kysely-ai-storage-service.js → kysely-agent-storage-service.js} +31 -28
- package/dist/src/kysely-audit-service.d.ts +3 -1
- package/dist/src/kysely-channel-store.d.ts +1 -1
- package/dist/src/kysely-credential-service.js +1 -1
- package/dist/src/kysely-deployment-service.d.ts +2 -1
- package/dist/src/kysely-scope-service.d.ts +2 -1
- package/dist/src/kysely-secret-service.d.ts +1 -1
- package/dist/src/kysely-secret-service.js +2 -2
- package/dist/src/kysely-session-store.d.ts +1 -1
- package/dist/src/kysely-tables.d.ts +12 -12
- package/dist/src/kysely-webhook-service.d.ts +2 -1
- package/dist/src/kysely-webhook-service.js +2 -1
- package/dist/src/kysely-workflow-mirror.d.ts +1 -1
- package/dist/src/kysely-workflow-service.d.ts +3 -2
- package/dist/src/kysely-workflow-service.js +1 -1
- package/dist/src/schema/{ai.schema.d.ts → agent.schema.d.ts} +4 -4
- package/dist/src/schema/{ai.schema.js → agent.schema.js} +29 -29
- package/dist/src/schema/index.js +4 -4
- package/dist/src/serialize-plugin.d.ts +0 -4
- package/dist/src/serialize-plugin.js +0 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/coercion-plugin.test.ts +160 -0
- package/src/coercion-plugin.ts +187 -0
- package/src/create-audited-kysely.test.ts +1 -1
- package/src/create-audited-kysely.ts +1 -1
- package/src/index.ts +10 -5
- package/src/{kysely-ai-run-scores.ts → kysely-agent-run-scores.ts} +5 -5
- package/src/{kysely-ai-agent-run-service.ts → kysely-agent-run-service.ts} +18 -18
- package/src/{kysely-ai-run-state-service.ts → kysely-agent-run-state-service.ts} +16 -15
- package/src/{kysely-ai-storage-service.ts → kysely-agent-storage-service.ts} +53 -43
- package/src/kysely-audit-service.test.ts +1 -1
- package/src/kysely-audit-service.ts +4 -6
- package/src/kysely-channel-store.ts +1 -1
- package/src/kysely-credential-service.ts +5 -5
- package/src/kysely-deployment-service.ts +2 -1
- package/src/kysely-scope-service.ts +5 -2
- package/src/kysely-secret-service.ts +7 -6
- package/src/kysely-services.test.ts +10 -10
- package/src/kysely-session-store.ts +1 -1
- package/src/kysely-tables.ts +12 -12
- package/src/kysely-virtual-user-run-store.ts +1 -1
- package/src/kysely-webhook-service.test.ts +1 -1
- package/src/kysely-webhook-service.ts +2 -2
- package/src/kysely-workflow-mirror.ts +1 -1
- package/src/kysely-workflow-service.test.ts +0 -1
- package/src/kysely-workflow-service.ts +11 -11
- package/src/schema/{ai.schema.ts → agent.schema.ts} +29 -29
- package/src/schema/index.ts +4 -4
- package/src/schema/schema.test.ts +6 -6
- package/src/serialize-plugin.ts +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,232 @@
|
|
|
1
|
+
## 0.13.18
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 746ed6a: fix: one coercion plugin, not three
|
|
6
|
+
|
|
7
|
+
The Kysely coercion plugin existed in three copies — the CLI's local database,
|
|
8
|
+
`@pikku/kysely-node-sqlite` and `@pikku/kysely-bun-sqlite` — and all three had
|
|
9
|
+
drifted apart. Only the CLI's resolved a column against the tables the query
|
|
10
|
+
actually named, so two tables that disagree on the kind of a same-named column
|
|
11
|
+
coerced correctly in local development and silently did not at runtime; only
|
|
12
|
+
bun's dropped a genuinely ambiguous column instead of letting the last table
|
|
13
|
+
processed win.
|
|
14
|
+
|
|
15
|
+
The single implementation now lives in `@pikku/kysely`, which all three already
|
|
16
|
+
depended on, and keeps both behaviours: table-qualified resolution first, an
|
|
17
|
+
ambiguity-safe bare-name fallback second.
|
|
18
|
+
|
|
19
|
+
`ColumnKind` — the value type of the generated `coercion.gen.ts` — is
|
|
20
|
+
`'date' | 'bool' | 'json'`. The CLI's fourth member, `uuid`, was never a
|
|
21
|
+
coercion kind: the codegen excludes it from the map by construction, because a
|
|
22
|
+
UUID is a string in both Postgres and SQLite. It is now `AnnotationKind` in the
|
|
23
|
+
CLI, the union a column may declare in `db/annotations.ts`, of which
|
|
24
|
+
`ColumnKind` is the coercible subset.
|
|
25
|
+
|
|
26
|
+
`@pikku/cli` also drops its unused dependency on the Node-only
|
|
27
|
+
`@pikku/kysely-node-sqlite`.
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [5a1a962]
|
|
30
|
+
- @pikku/core@0.12.86
|
|
31
|
+
|
|
32
|
+
## 0.13.17
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- 266e3bc: One door per name: `@pikku/core/ecosystem/*` and the package root are gone
|
|
37
|
+
|
|
38
|
+
`@pikku/core` published every module twice. `ecosystem/http` re-exported
|
|
39
|
+
`./http`, `ecosystem/services` re-exported `./services`, and a name was
|
|
40
|
+
reachable through either — so every addition had to be made in two places, and a
|
|
41
|
+
consumer's import said nothing about what it actually used. The package root was
|
|
42
|
+
the same problem at a larger scale: a single barrel of 206 names that no bundler
|
|
43
|
+
could take apart, and the one specifier that revealed nothing at all.
|
|
44
|
+
|
|
45
|
+
Both are deleted. Every name now lives on the subpath that owns it, and every
|
|
46
|
+
import carries that subpath — `@pikku/core/http`, `@pikku/core/services`,
|
|
47
|
+
`@pikku/core/errors`, `@pikku/core/types`.
|
|
48
|
+
|
|
49
|
+
Deleting the facades meant the raw subpaths had to become a superset of them,
|
|
50
|
+
which they were not: the facade tree had accumulated 25 names with no raw home
|
|
51
|
+
and about 26 more filed under a different area than the module they came from.
|
|
52
|
+
Those names moved to the area that owns them, and three areas were published as
|
|
53
|
+
new entry points rather than left on a root that is going away — `./types` (the
|
|
54
|
+
shared type surface, the largest single destination), `./state` and
|
|
55
|
+
`./classification`.
|
|
56
|
+
|
|
57
|
+
`./classification` is one door onto one subject: what a value is and how it must
|
|
58
|
+
be handled. Its three halves would each have been an entry point — the brands
|
|
59
|
+
and manifest types, the stored-form helpers (`hashToken`, `unsafeAsSealed` and
|
|
60
|
+
friends), and `SecretValue` — split by whether a name happens to be a type or a
|
|
61
|
+
value, which is the same defect as the facades. The duration and versioned-id
|
|
62
|
+
helpers went to `./utils`, which already published, and `PikkuRequest` went to
|
|
63
|
+
`./function`: it is the transport-agnostic request base, not an HTTP one — HTTP
|
|
64
|
+
has `PikkuHTTPAbstractRequest`, and the only thing outside core that extends
|
|
65
|
+
`PikkuRequest` is Azure's timer request.
|
|
66
|
+
|
|
67
|
+
`./types` inherited the root barrel's habit before it inherited its contents, so
|
|
68
|
+
the names with an owner elsewhere were moved off it. The middleware types and the
|
|
69
|
+
five middleware factories — `pikkuMiddleware`, `pikkuMiddlewareFactory`,
|
|
70
|
+
`pikkuChannelMiddleware`, `pikkuChannelMiddlewareFactory` and
|
|
71
|
+
`pikkuAgentMiddleware`, runtime values on a types entry point — are now
|
|
72
|
+
`@pikku/core/middleware`; the function meta types are `@pikku/core/function`;
|
|
73
|
+
`SerializedError` is `@pikku/core/errors`; and the generic TypeScript helpers
|
|
74
|
+
(`MakeRequired`, `PickRequired`, `PickOptional`, `RequireAtLeastOne`,
|
|
75
|
+
`JSONPrimitive`, `JSONValue`) are `@pikku/core/utils`. What is left on `./types`
|
|
76
|
+
is the vocabulary the wirings share, which no single module owns.
|
|
77
|
+
|
|
78
|
+
`pikku` was itself a root barrel — `export * from '@pikku/core'` — and
|
|
79
|
+
now exports only the services it bundles.
|
|
80
|
+
|
|
81
|
+
One module survives at the old specifier, and only for the bootstrap:
|
|
82
|
+
`packages/cli` is generated by the _published_ CLI pinned in its `build.sh`, and
|
|
83
|
+
that CLI still writes a bare `@pikku/core` into the files it generates for the
|
|
84
|
+
CLI itself. `bootstrap-compat/root.ts` carries the eight types it names, a test
|
|
85
|
+
in core fails if that list grows, and it goes when the pin moves to a CLI
|
|
86
|
+
released from this branch. The adapter names the pinned CLI reaches for —
|
|
87
|
+
`pikkuState` and `CreateWireServices` — are rewritten to `@pikku/core/state` and
|
|
88
|
+
`@pikku/core/types` by the same `build.sh` patch pass, so no second shim is
|
|
89
|
+
needed for them.
|
|
90
|
+
|
|
91
|
+
A guard test keeps the root shut: it parses imports and rejects a bare
|
|
92
|
+
`@pikku/core` rather than grepping for it, because several tests hold a user's
|
|
93
|
+
file as a template literal, where `import … from '@pikku/core'` is fixture text
|
|
94
|
+
rather than an import this repo makes.
|
|
95
|
+
|
|
96
|
+
An agent scaffold a project generated under an older CLI is refreshed rather
|
|
97
|
+
than left to fail: `pikku all` already deleted one importing an entry point
|
|
98
|
+
`@pikku/core` no longer publishes, and the `#pikku` hub joins that list.
|
|
99
|
+
Without it a project that scaffolds the agent endpoint but
|
|
100
|
+
declares no agents keeps the old file forever — the generator that would rewrite
|
|
101
|
+
it only runs when agents exist, and the file being present is what stops it
|
|
102
|
+
being regenerated as missing.
|
|
103
|
+
|
|
104
|
+
`pikku new addon` also wrote a tsconfig `paths` map naming only the deleted hub.
|
|
105
|
+
An addon's `imports` map points into `dist`, so `paths` is what resolves
|
|
106
|
+
`#pikku/<leaf>` for the addon's own source build — it now names the two leaf
|
|
107
|
+
patterns, in both the addon and its test harness.
|
|
108
|
+
|
|
109
|
+
- 786dae5: Bump every dependency whose latest release is a major across the monorepo, and
|
|
110
|
+
port the code the majors broke: `cookie` 2's `parseCookie`/`stringifySetCookie`
|
|
111
|
+
API in `@pikku/core` and the three runtime HTTP adapters, and assistant-ui 0.15's
|
|
112
|
+
store client in `@pikku/assistant-ui`.
|
|
113
|
+
- 6eef0a0: Bump every dependency to its latest compatible minor/patch across the monorepo.
|
|
114
|
+
- Updated dependencies [7722ceb]
|
|
115
|
+
- Updated dependencies [375c1ff]
|
|
116
|
+
- Updated dependencies [02a70cd]
|
|
117
|
+
- Updated dependencies [aeef159]
|
|
118
|
+
- Updated dependencies [a281de6]
|
|
119
|
+
- Updated dependencies [266e3bc]
|
|
120
|
+
- Updated dependencies [02a70cd]
|
|
121
|
+
- Updated dependencies [786dae5]
|
|
122
|
+
- Updated dependencies [6eef0a0]
|
|
123
|
+
- Updated dependencies [3561d67]
|
|
124
|
+
- Updated dependencies [a91c433]
|
|
125
|
+
- Updated dependencies [02a70cd]
|
|
126
|
+
- Updated dependencies [9537f74]
|
|
127
|
+
- Updated dependencies [2b57ca8]
|
|
128
|
+
- Updated dependencies [266e3bc]
|
|
129
|
+
- Updated dependencies [9fce0f1]
|
|
130
|
+
- Updated dependencies [83683a0]
|
|
131
|
+
- Updated dependencies [456c88b]
|
|
132
|
+
- Updated dependencies [456c88b]
|
|
133
|
+
- Updated dependencies [c127273]
|
|
134
|
+
- @pikku/core@0.12.85
|
|
135
|
+
|
|
136
|
+
## 0.13.16
|
|
137
|
+
|
|
138
|
+
### Patch Changes
|
|
139
|
+
|
|
140
|
+
- 7406bfe: Rename the agent runtime from `AI*` to `Agent*` (#596)
|
|
141
|
+
|
|
142
|
+
`AI` described the model provider, not the thing being named. Every symbol that
|
|
143
|
+
belongs to the agent runtime now says `Agent`; the symbols that genuinely wrap a
|
|
144
|
+
model provider — `AIEmbeddingService`, `AIProviderOptions`, `AIEmbedParams`,
|
|
145
|
+
`AITranscriptionParams`, `AIGenerateImageParams` and their siblings, and the
|
|
146
|
+
`@pikku/ai-vercel` / `@pikku/ai-deepinfra` / `@pikku/ai-voice` packages — keep
|
|
147
|
+
their names.
|
|
148
|
+
|
|
149
|
+
**Wiring**
|
|
150
|
+
- `pikkuAIAgent` → `pikkuAgent`, `pikkuAIScorer` → `pikkuAgentScorer`,
|
|
151
|
+
`pikkuAIJudge` → `pikkuAgentJudge`
|
|
152
|
+
- `CoreAIAgent` → `CoreAgent`, `AIAgentInput` → `AgentInput`, `AIAgentStep` →
|
|
153
|
+
`AgentStep`, `AIMessage` → `AgentMessage`, and the rest of the agent types
|
|
154
|
+
- `AIAgentRunnerService` → `AgentRunnerService`, `AIStorageService` →
|
|
155
|
+
`AgentStorageService`, `AIRunStateService` → `AgentRunStateService`
|
|
156
|
+
|
|
157
|
+
**Entry points**
|
|
158
|
+
|
|
159
|
+
`@pikku/core/agent` → `@pikku/core/agent`, `@pikku/core/agent-scorer` →
|
|
160
|
+
`@pikku/core/agent-scorer`.
|
|
161
|
+
|
|
162
|
+
**Queues**
|
|
163
|
+
|
|
164
|
+
The scorer queues are now `agent-score-fast` and `agent-score-slow`. Drain the
|
|
165
|
+
old `ai-score-fast` / `ai-score-slow` queues before deploying — jobs still
|
|
166
|
+
sitting on them when the new workers start will never be picked up.
|
|
167
|
+
|
|
168
|
+
**Scaffolds**
|
|
169
|
+
|
|
170
|
+
The agent scaffold pikku wrote for your project — `<scaffold>/agent/agent.gen.ts`
|
|
171
|
+
and its schemas file — imports `@pikku/core/ai-agent`, which no longer exists. A
|
|
172
|
+
scaffold is normally written once and then left alone, so `pikku all` would find
|
|
173
|
+
it present and leave the broken import in place. It now deletes an agent scaffold
|
|
174
|
+
importing either removed entry point and regenerates it in the same run. Anything
|
|
175
|
+
you added to that file goes with it, so move local edits out first.
|
|
176
|
+
|
|
177
|
+
**Database**
|
|
178
|
+
|
|
179
|
+
The agent tables are renamed: `ai_threads`, `ai_message`, `ai_tool_call`,
|
|
180
|
+
`ai_working_memory`, `ai_run` and `ai_run_score` become `agent_threads`,
|
|
181
|
+
`agent_message`, `agent_tool_call`, `agent_working_memory`, `agent_run` and
|
|
182
|
+
`agent_run_score`, along with their indexes and the `ai_working_memory_pk`
|
|
183
|
+
constraint. The same rename applies to the MongoDB collections.
|
|
184
|
+
|
|
185
|
+
`ensurePikkuSchema` creates tables it cannot find, so an existing database will
|
|
186
|
+
get empty `agent_*` tables and leave the old data stranded in `ai_*`. Rename
|
|
187
|
+
them before the first boot on the new version:
|
|
188
|
+
|
|
189
|
+
```sql
|
|
190
|
+
ALTER TABLE ai_threads RENAME TO agent_threads;
|
|
191
|
+
ALTER TABLE ai_message RENAME TO agent_message;
|
|
192
|
+
ALTER TABLE ai_tool_call RENAME TO agent_tool_call;
|
|
193
|
+
ALTER TABLE ai_working_memory RENAME TO agent_working_memory;
|
|
194
|
+
ALTER TABLE ai_run RENAME TO agent_run;
|
|
195
|
+
ALTER TABLE ai_run_score RENAME TO agent_run_score;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
- 6794681: Publish the ecosystem surface as per-area sub-barrels under `@pikku/core/ecosystem/*`, and point generated code, the CLI, the inspector and the runtime adapters at them.
|
|
199
|
+
|
|
200
|
+
348 names that only generated code, the toolchain or a runtime adapter ever imports now have a second home on `@pikku/core/ecosystem/<area>` — one sub-barrel per area, matching how core already publishes its entrypoints, so no single barrel grows without bound and a consumer only pulls in the area it uses.
|
|
201
|
+
|
|
202
|
+
This step is additive: every name is still exported from the entrypoint it was published from before, so nothing downstream breaks. Removing them from the app-facing barrels is a later change, and needs a release carrying `./ecosystem/*` first.
|
|
203
|
+
|
|
204
|
+
- a7fcd2e: Declare dependencies that were imported but missing from `package.json`
|
|
205
|
+
|
|
206
|
+
`@pikku/openapi-parser` and `@pikku/better-auth` imported `zod`, `@pikku/next`
|
|
207
|
+
imported `path-to-regexp`, `@pikku/cli` imported `kysely`, and
|
|
208
|
+
`@pikku/assistant-ui` imported `rxjs`, none of which were declared. Each
|
|
209
|
+
resolved through Yarn hoisting inside the monorepo and would fail for anyone
|
|
210
|
+
installing the package on its own.
|
|
211
|
+
|
|
212
|
+
`rxjs`, `kysely` and `path-to-regexp` reach consumers through public
|
|
213
|
+
signatures — `Observable<BaseEvent>` is the return type of a published method,
|
|
214
|
+
and `createCoercionPlugin` returns a `KyselyPlugin` — so they are runtime
|
|
215
|
+
dependencies rather than build-only ones.
|
|
216
|
+
|
|
217
|
+
`@pikku/assistant-ui` pins `rxjs` to the exact `7.8.1` that `@ag-ui/client`
|
|
218
|
+
pins, rather than a caret range. The two packages exchange `Observable`s, so a
|
|
219
|
+
range that floats to a second copy gives them two incompatible `Observable`
|
|
220
|
+
types.
|
|
221
|
+
|
|
222
|
+
`@pikku/kysely` also drops `SqliteSerializePlugin`, an alias of
|
|
223
|
+
`SerializePlugin` that has been marked `@deprecated` in favour of it. Use
|
|
224
|
+
`SerializePlugin`.
|
|
225
|
+
|
|
226
|
+
- Updated dependencies [7406bfe]
|
|
227
|
+
- Updated dependencies [6794681]
|
|
228
|
+
- @pikku/core@0.12.84
|
|
229
|
+
|
|
1
230
|
## 0.13.15
|
|
2
231
|
|
|
3
232
|
### Patch Changes
|
package/bin/pikku-kysely-pure.ts
CHANGED
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { KyselyPlugin } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* The kinds a column can be coerced *to* at runtime. This is the value type of
|
|
4
|
+
* the generated `CoercionMap`, so it is a public artifact contract — a kind may
|
|
5
|
+
* only appear here if `fromDb` below actually does something with it.
|
|
6
|
+
*
|
|
7
|
+
* `uuid` is deliberately absent: it is an annotation kind (it selects the `Uuid`
|
|
8
|
+
* TypeScript type in the generated schema) but not a coercion kind, and the
|
|
9
|
+
* codegen filters it out of `coercion.gen.ts` for exactly that reason — a UUID
|
|
10
|
+
* is a string in both Postgres and SQLite.
|
|
11
|
+
*/
|
|
12
|
+
export type ColumnKind = 'date' | 'bool' | 'json';
|
|
13
|
+
/**
|
|
14
|
+
* Per-table column kind map. Keys are the table names queries are written
|
|
15
|
+
* against; inner keys are snake_case column names.
|
|
16
|
+
* Generated into `outDir/db/coercion.gen.ts` by `pikku db migrate` from the
|
|
17
|
+
* explicit `kind` entries in `db/annotations.ts`.
|
|
18
|
+
*/
|
|
19
|
+
export type CoercionMap = Record<string, Record<string, ColumnKind>>;
|
|
20
|
+
export interface CreateCoercionPluginOptions {
|
|
21
|
+
map: CoercionMap;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert values stored in a dialect's on-disk representation back into the
|
|
25
|
+
* logical types app code expects (Date / boolean / parsed JSON).
|
|
26
|
+
*
|
|
27
|
+
* SQLite is what makes this necessary — it stores dates as TEXT, booleans as
|
|
28
|
+
* INTEGER and JSON as TEXT — but the plugin is dialect-neutral: on Postgres the
|
|
29
|
+
* driver already returns Date/boolean/object, and every branch of `fromDb`
|
|
30
|
+
* passes a non-string, non-number value straight through. That is why it lives
|
|
31
|
+
* in `@pikku/kysely` next to `SerializePlugin` rather than in a SQLite package:
|
|
32
|
+
* the CLI installs it on its local Postgres database too.
|
|
33
|
+
*
|
|
34
|
+
* Write-side coercion (Date → ISO string, boolean → 0/1, object → JSON) is
|
|
35
|
+
* handled in the SQLite database adapters (always-on), so this plugin is
|
|
36
|
+
* read-only.
|
|
37
|
+
*
|
|
38
|
+
* Place AFTER CamelCasePlugin in the plugin array (or it handles both
|
|
39
|
+
* orderings via the dual-keyed maps).
|
|
40
|
+
*/
|
|
41
|
+
export declare function createCoercionPlugin(options: CreateCoercionPluginOptions): KyselyPlugin;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
function fromDb(value, kind) {
|
|
2
|
+
if (value == null)
|
|
3
|
+
return value;
|
|
4
|
+
switch (kind) {
|
|
5
|
+
case 'date':
|
|
6
|
+
if (typeof value === 'string') {
|
|
7
|
+
const d = new Date(value);
|
|
8
|
+
return Number.isNaN(d.getTime()) ? value : d;
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
case 'bool':
|
|
12
|
+
if (typeof value === 'number')
|
|
13
|
+
return value !== 0;
|
|
14
|
+
if (typeof value === 'bigint')
|
|
15
|
+
return value !== 0n;
|
|
16
|
+
return value;
|
|
17
|
+
case 'json':
|
|
18
|
+
if (typeof value !== 'string')
|
|
19
|
+
return value;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(value);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function snakeToCamel(name) {
|
|
29
|
+
return name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Flatten the per-table map into a table-qualified lookup plus a bare
|
|
33
|
+
* column-name fallback. Both are indexed by BOTH snake_case and camelCase so
|
|
34
|
+
* they work regardless of CamelCasePlugin ordering in the plugin array.
|
|
35
|
+
*
|
|
36
|
+
* When two tables disagree on the kind for the same column name, the bare name
|
|
37
|
+
* is ambiguous (a joined/aliased query could carry either) and is dropped from
|
|
38
|
+
* the flat map rather than letting whichever table was processed last win. The
|
|
39
|
+
* qualified map still resolves it whenever the query names its tables.
|
|
40
|
+
*/
|
|
41
|
+
function buildMaps(map) {
|
|
42
|
+
const qualified = {};
|
|
43
|
+
const flat = {};
|
|
44
|
+
const ambiguous = new Set();
|
|
45
|
+
const assignFlat = (key, kind) => {
|
|
46
|
+
const existing = flat[key];
|
|
47
|
+
if (existing !== undefined && existing !== kind) {
|
|
48
|
+
ambiguous.add(key);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
flat[key] = kind;
|
|
52
|
+
};
|
|
53
|
+
for (const [table, cols] of Object.entries(map)) {
|
|
54
|
+
for (const [col, kind] of Object.entries(cols)) {
|
|
55
|
+
const camel = snakeToCamel(col);
|
|
56
|
+
qualified[`${table}.${col}`] = kind;
|
|
57
|
+
qualified[`${table}.${camel}`] = kind;
|
|
58
|
+
assignFlat(col, kind);
|
|
59
|
+
assignFlat(camel, kind);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
for (const key of ambiguous)
|
|
63
|
+
delete flat[key];
|
|
64
|
+
return { qualified, flat };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Collect every table named anywhere in the query's operation node, so a result
|
|
68
|
+
* column can be resolved against the tables the query actually touched instead
|
|
69
|
+
* of against every table in the schema.
|
|
70
|
+
*/
|
|
71
|
+
function collectQueryTables(node, out) {
|
|
72
|
+
if (!node || typeof node !== 'object')
|
|
73
|
+
return;
|
|
74
|
+
const op = node;
|
|
75
|
+
if (op.kind === 'TableNode') {
|
|
76
|
+
const tableName = op.table?.identifier?.name;
|
|
77
|
+
if (typeof tableName === 'string' && tableName.length > 0)
|
|
78
|
+
out.add(tableName);
|
|
79
|
+
}
|
|
80
|
+
for (const value of Object.values(node)) {
|
|
81
|
+
if (Array.isArray(value)) {
|
|
82
|
+
for (const item of value)
|
|
83
|
+
collectQueryTables(item, out);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
collectQueryTables(value, out);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve a result column's kind against the query's tables, falling back to
|
|
92
|
+
* the bare column name. Tables that disagree with each other are as ambiguous
|
|
93
|
+
* as two schema tables are, so they fall back too.
|
|
94
|
+
*/
|
|
95
|
+
function lookupKind(maps, tables, col) {
|
|
96
|
+
let matchedKind;
|
|
97
|
+
for (const table of tables) {
|
|
98
|
+
const kind = maps.qualified[`${table}.${col}`];
|
|
99
|
+
if (!kind)
|
|
100
|
+
continue;
|
|
101
|
+
if (matchedKind && matchedKind !== kind)
|
|
102
|
+
return maps.flat[col];
|
|
103
|
+
matchedKind = kind;
|
|
104
|
+
}
|
|
105
|
+
return matchedKind ?? maps.flat[col];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Convert values stored in a dialect's on-disk representation back into the
|
|
109
|
+
* logical types app code expects (Date / boolean / parsed JSON).
|
|
110
|
+
*
|
|
111
|
+
* SQLite is what makes this necessary — it stores dates as TEXT, booleans as
|
|
112
|
+
* INTEGER and JSON as TEXT — but the plugin is dialect-neutral: on Postgres the
|
|
113
|
+
* driver already returns Date/boolean/object, and every branch of `fromDb`
|
|
114
|
+
* passes a non-string, non-number value straight through. That is why it lives
|
|
115
|
+
* in `@pikku/kysely` next to `SerializePlugin` rather than in a SQLite package:
|
|
116
|
+
* the CLI installs it on its local Postgres database too.
|
|
117
|
+
*
|
|
118
|
+
* Write-side coercion (Date → ISO string, boolean → 0/1, object → JSON) is
|
|
119
|
+
* handled in the SQLite database adapters (always-on), so this plugin is
|
|
120
|
+
* read-only.
|
|
121
|
+
*
|
|
122
|
+
* Place AFTER CamelCasePlugin in the plugin array (or it handles both
|
|
123
|
+
* orderings via the dual-keyed maps).
|
|
124
|
+
*/
|
|
125
|
+
export function createCoercionPlugin(options) {
|
|
126
|
+
const maps = buildMaps(options.map);
|
|
127
|
+
const queryTables = new WeakMap();
|
|
128
|
+
return {
|
|
129
|
+
transformQuery(args) {
|
|
130
|
+
const tables = new Set();
|
|
131
|
+
collectQueryTables(args.node, tables);
|
|
132
|
+
queryTables.set(args.queryId, [...tables]);
|
|
133
|
+
return args.node;
|
|
134
|
+
},
|
|
135
|
+
async transformResult(args) {
|
|
136
|
+
const tables = queryTables.get(args.queryId) ?? [];
|
|
137
|
+
const out = [];
|
|
138
|
+
for (const row of args.result.rows) {
|
|
139
|
+
const next = { ...row };
|
|
140
|
+
for (const [col, val] of Object.entries(row)) {
|
|
141
|
+
const kind = lookupKind(maps, tables, col);
|
|
142
|
+
if (kind)
|
|
143
|
+
next[col] = fromDb(val, kind);
|
|
144
|
+
}
|
|
145
|
+
out.push(next);
|
|
146
|
+
}
|
|
147
|
+
return { ...args.result, rows: out };
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ export { KyselyWorkflowService } from './kysely-workflow-service.js';
|
|
|
4
4
|
export { KyselyWorkflowRunService } from './kysely-workflow-run-service.js';
|
|
5
5
|
export { KyselyWorkflowMirror } from './kysely-workflow-mirror.js';
|
|
6
6
|
export { KyselyDeploymentService } from './kysely-deployment-service.js';
|
|
7
|
-
export {
|
|
8
|
-
export { KyselyAgentRunService } from './kysely-
|
|
9
|
-
export {
|
|
7
|
+
export { KyselyAgentStorageService } from './kysely-agent-storage-service.js';
|
|
8
|
+
export { KyselyAgentRunService } from './kysely-agent-run-service.js';
|
|
9
|
+
export { KyselyAgentRunStateService } from './kysely-agent-run-state-service.js';
|
|
10
10
|
export { KyselySecretService } from './kysely-secret-service.js';
|
|
11
11
|
export { KyselyCredentialService } from './kysely-credential-service.js';
|
|
12
12
|
export { KyselySessionStore } from './kysely-session-store.js';
|
|
@@ -15,9 +15,10 @@ export { KyselyWebhookService } from './kysely-webhook-service.js';
|
|
|
15
15
|
export { createAuditedKysely, type CreateAuditedKyselyOptions, } from './create-audited-kysely.js';
|
|
16
16
|
export { KyselyAuditService } from './kysely-audit-service.js';
|
|
17
17
|
export { KyselyVirtualUserRunStore } from './kysely-virtual-user-run-store.js';
|
|
18
|
-
export { SerializePlugin,
|
|
18
|
+
export { SerializePlugin, BaseSerializePlugin, type Serializer, type Deserializer, } from './serialize-plugin.js';
|
|
19
|
+
export { createCoercionPlugin, type ColumnKind, type CoercionMap, type CreateCoercionPluginOptions, } from './coercion-plugin.js';
|
|
19
20
|
export { auditSchema, pikkuSchemas, applyPikkuSchemas, compilePikkuSchemas, ensurePikkuSchema, type EnsureOutcome, resolveRequirements, type PikkuSchema, type RequiredTypes, type UnmetRequirement, type SchemaStatementFactory, } from './schema/index.js';
|
|
20
21
|
export type { KyselyPikkuDB } from './kysely-tables.js';
|
|
21
22
|
export type { WorkflowRunService } from '@pikku/core/workflow';
|
|
22
|
-
export type { AgentRunService, AgentRunRow } from '@pikku/core/
|
|
23
|
+
export type { AgentRunService, AgentRunRow } from '@pikku/core/agent';
|
|
23
24
|
export type { VirtualUserRunStore, VirtualUserRunRecord, } from '@pikku/core/virtual-user';
|
package/dist/src/index.js
CHANGED
|
@@ -4,9 +4,9 @@ export { KyselyWorkflowService } from './kysely-workflow-service.js';
|
|
|
4
4
|
export { KyselyWorkflowRunService } from './kysely-workflow-run-service.js';
|
|
5
5
|
export { KyselyWorkflowMirror } from './kysely-workflow-mirror.js';
|
|
6
6
|
export { KyselyDeploymentService } from './kysely-deployment-service.js';
|
|
7
|
-
export {
|
|
8
|
-
export { KyselyAgentRunService } from './kysely-
|
|
9
|
-
export {
|
|
7
|
+
export { KyselyAgentStorageService } from './kysely-agent-storage-service.js';
|
|
8
|
+
export { KyselyAgentRunService } from './kysely-agent-run-service.js';
|
|
9
|
+
export { KyselyAgentRunStateService } from './kysely-agent-run-state-service.js';
|
|
10
10
|
export { KyselySecretService } from './kysely-secret-service.js';
|
|
11
11
|
export { KyselyCredentialService } from './kysely-credential-service.js';
|
|
12
12
|
export { KyselySessionStore } from './kysely-session-store.js';
|
|
@@ -15,5 +15,6 @@ export { KyselyWebhookService } from './kysely-webhook-service.js';
|
|
|
15
15
|
export { createAuditedKysely, } from './create-audited-kysely.js';
|
|
16
16
|
export { KyselyAuditService } from './kysely-audit-service.js';
|
|
17
17
|
export { KyselyVirtualUserRunStore } from './kysely-virtual-user-run-store.js';
|
|
18
|
-
export { SerializePlugin,
|
|
18
|
+
export { SerializePlugin, BaseSerializePlugin, } from './serialize-plugin.js';
|
|
19
|
+
export { createCoercionPlugin, } from './coercion-plugin.js';
|
|
19
20
|
export { auditSchema, pikkuSchemas, applyPikkuSchemas, compilePikkuSchemas, ensurePikkuSchema, resolveRequirements, } from './schema/index.js';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Kysely } from 'kysely';
|
|
2
2
|
import type { KyselyPikkuDB } from './kysely-tables.js';
|
|
3
|
+
import type { AgentRunScore } from '@pikku/core/agent-scorer';
|
|
3
4
|
import type { SaveScoreInput } from '@pikku/core/services';
|
|
4
|
-
import type { AIRunScore } from '@pikku/core/ai-scorer';
|
|
5
5
|
/**
|
|
6
|
-
* Shared by the two Kysely services that implement `
|
|
6
|
+
* Shared by the two Kysely services that implement `AgentRunStateService` — they
|
|
7
7
|
* differ in how they store approvals, not in how they store grades.
|
|
8
8
|
*/
|
|
9
9
|
export declare const saveRunScore: (db: Kysely<KyselyPikkuDB>, score: SaveScoreInput) => Promise<void>;
|
|
10
|
-
export declare const getRunScores: (db: Kysely<KyselyPikkuDB>, runId: string) => Promise<
|
|
10
|
+
export declare const getRunScores: (db: Kysely<KyselyPikkuDB>, runId: string) => Promise<AgentRunScore[]>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { parseJson } from './kysely-json.js';
|
|
2
2
|
/**
|
|
3
|
-
* Shared by the two Kysely services that implement `
|
|
3
|
+
* Shared by the two Kysely services that implement `AgentRunStateService` — they
|
|
4
4
|
* differ in how they store approvals, not in how they store grades.
|
|
5
5
|
*/
|
|
6
6
|
export const saveRunScore = async (db, score) => {
|
|
7
7
|
await db
|
|
8
|
-
.insertInto('
|
|
8
|
+
.insertInto('agentRunScore')
|
|
9
9
|
.values({
|
|
10
10
|
id: crypto.randomUUID(),
|
|
11
11
|
runId: score.runId,
|
|
@@ -18,7 +18,7 @@ export const saveRunScore = async (db, score) => {
|
|
|
18
18
|
};
|
|
19
19
|
export const getRunScores = async (db, runId) => {
|
|
20
20
|
const rows = await db
|
|
21
|
-
.selectFrom('
|
|
21
|
+
.selectFrom('agentRunScore')
|
|
22
22
|
.selectAll()
|
|
23
23
|
.where('runId', '=', runId)
|
|
24
24
|
.orderBy('createdAt', 'asc')
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentThread, AgentMessage, AgentRunRow, AgentRunService } from '@pikku/core/agent';
|
|
2
2
|
import type { Kysely } from 'kysely';
|
|
3
3
|
import type { KyselyPikkuDB } from './kysely-tables.js';
|
|
4
4
|
export declare class KyselyAgentRunService implements AgentRunService {
|
|
@@ -10,9 +10,9 @@ export declare class KyselyAgentRunService implements AgentRunService {
|
|
|
10
10
|
owners?: string[];
|
|
11
11
|
limit?: number;
|
|
12
12
|
offset?: number;
|
|
13
|
-
}): Promise<
|
|
14
|
-
getThread(threadId: string): Promise<
|
|
15
|
-
getThreadMessages(threadId: string): Promise<
|
|
13
|
+
}): Promise<AgentThread[]>;
|
|
14
|
+
getThread(threadId: string): Promise<AgentThread | null>;
|
|
15
|
+
getThreadMessages(threadId: string): Promise<AgentMessage[]>;
|
|
16
16
|
getThreadRuns(threadId: string): Promise<AgentRunRow[]>;
|
|
17
17
|
deleteThread(threadId: string): Promise<boolean>;
|
|
18
18
|
getDistinctAgentNames(): Promise<string[]>;
|
|
@@ -15,7 +15,7 @@ export class KyselyAgentRunService {
|
|
|
15
15
|
if (owners && owners.length === 0)
|
|
16
16
|
return [];
|
|
17
17
|
let query = this.db
|
|
18
|
-
.selectFrom('
|
|
18
|
+
.selectFrom('agentThreads as t')
|
|
19
19
|
.select([
|
|
20
20
|
't.id',
|
|
21
21
|
't.resourceId',
|
|
@@ -26,7 +26,7 @@ export class KyselyAgentRunService {
|
|
|
26
26
|
]);
|
|
27
27
|
if (agentName) {
|
|
28
28
|
query = query.where('t.id', 'in', this.db
|
|
29
|
-
.selectFrom('
|
|
29
|
+
.selectFrom('agentRun')
|
|
30
30
|
.select('threadId')
|
|
31
31
|
.where('agentName', '=', agentName)
|
|
32
32
|
.distinct());
|
|
@@ -49,7 +49,7 @@ export class KyselyAgentRunService {
|
|
|
49
49
|
}
|
|
50
50
|
async getThread(threadId) {
|
|
51
51
|
const row = await this.db
|
|
52
|
-
.selectFrom('
|
|
52
|
+
.selectFrom('agentThreads')
|
|
53
53
|
.select([
|
|
54
54
|
'id',
|
|
55
55
|
'resourceId',
|
|
@@ -67,13 +67,13 @@ export class KyselyAgentRunService {
|
|
|
67
67
|
async getThreadMessages(threadId) {
|
|
68
68
|
const [msgResult, tcResult] = await Promise.all([
|
|
69
69
|
this.db
|
|
70
|
-
.selectFrom('
|
|
70
|
+
.selectFrom('agentMessage')
|
|
71
71
|
.select(['id', 'role', 'content', 'createdAt'])
|
|
72
72
|
.where('threadId', '=', threadId)
|
|
73
73
|
.orderBy('createdAt', 'asc')
|
|
74
74
|
.execute(),
|
|
75
75
|
this.db
|
|
76
|
-
.selectFrom('
|
|
76
|
+
.selectFrom('agentToolCall')
|
|
77
77
|
.select(['id', 'messageId', 'toolName', 'args', 'result'])
|
|
78
78
|
.where('threadId', '=', threadId)
|
|
79
79
|
.orderBy('createdAt', 'asc')
|
|
@@ -123,7 +123,7 @@ export class KyselyAgentRunService {
|
|
|
123
123
|
}
|
|
124
124
|
async getThreadRuns(threadId) {
|
|
125
125
|
const result = await this.db
|
|
126
|
-
.selectFrom('
|
|
126
|
+
.selectFrom('agentRun')
|
|
127
127
|
.select([
|
|
128
128
|
'runId',
|
|
129
129
|
'agentName',
|
|
@@ -146,14 +146,14 @@ export class KyselyAgentRunService {
|
|
|
146
146
|
}
|
|
147
147
|
async deleteThread(threadId) {
|
|
148
148
|
const result = await this.db
|
|
149
|
-
.deleteFrom('
|
|
149
|
+
.deleteFrom('agentThreads')
|
|
150
150
|
.where('id', '=', threadId)
|
|
151
151
|
.executeTakeFirst();
|
|
152
152
|
return BigInt(result.numDeletedRows) > 0n;
|
|
153
153
|
}
|
|
154
154
|
async getDistinctAgentNames() {
|
|
155
155
|
const result = await this.db
|
|
156
|
-
.selectFrom('
|
|
156
|
+
.selectFrom('agentRun')
|
|
157
157
|
.select('agentName')
|
|
158
158
|
.distinct()
|
|
159
159
|
.orderBy('agentName')
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Kysely } from 'kysely';
|
|
2
2
|
import type { KyselyPikkuDB } from './kysely-tables.js';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
6
|
-
|
|
3
|
+
import type { AgentRunState } from '@pikku/core/agent';
|
|
4
|
+
import type { AgentRunScore } from '@pikku/core/agent-scorer';
|
|
5
|
+
import type { AgentRunStateService, CreateRunInput, SaveScoreInput } from '@pikku/core/services';
|
|
6
|
+
import type { PendingApproval } from '@pikku/core/agent';
|
|
7
|
+
export declare class KyselyAgentRunStateService implements AgentRunStateService {
|
|
7
8
|
private db;
|
|
8
9
|
private initialized;
|
|
9
10
|
constructor(db: Kysely<KyselyPikkuDB>);
|
|
@@ -18,6 +19,6 @@ export declare class KyselyAIRunStateService implements AIRunStateService {
|
|
|
18
19
|
approval: PendingApproval;
|
|
19
20
|
} | null>;
|
|
20
21
|
saveScore(score: SaveScoreInput): Promise<void>;
|
|
21
|
-
getScores(runId: string): Promise<
|
|
22
|
+
getScores(runId: string): Promise<AgentRunScore[]>;
|
|
22
23
|
private toRunState;
|
|
23
24
|
}
|