@kindgi/sdk 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kindgi/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "@kindgi/sdk — the authoring SDK for Kindgi™. Facade over the individual @kindgi/* packages + @kindgi/client. Unifies pack authoring (defineTool / defineCheck / defineAgent / defineFlow) and client callsites (createClient) behind three sub-paths: /define, /client, /types. Re-export facade; zero behavior.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -18,27 +18,33 @@
18
18
  "exports": {
19
19
  "./define": {
20
20
  "types": "./dist/define.d.ts",
21
- "import": "./dist/define.js"
21
+ "import": "./dist/define.js",
22
+ "default": "./dist/define.js"
22
23
  },
23
24
  "./client": {
24
25
  "types": "./dist/client.d.ts",
25
- "import": "./dist/client.js"
26
+ "import": "./dist/client.js",
27
+ "default": "./dist/client.js"
26
28
  },
27
29
  "./types": {
28
30
  "types": "./dist/types.d.ts",
29
- "import": "./dist/types.js"
31
+ "import": "./dist/types.js",
32
+ "default": "./dist/types.js"
30
33
  },
31
34
  "./webhooks": {
32
35
  "types": "./dist/webhooks.d.ts",
33
- "import": "./dist/webhooks.js"
36
+ "import": "./dist/webhooks.js",
37
+ "default": "./dist/webhooks.js"
34
38
  },
35
39
  "./build": {
36
40
  "types": "./dist/build.d.ts",
37
- "import": "./dist/build.js"
41
+ "import": "./dist/build.js",
42
+ "default": "./dist/build.js"
38
43
  },
39
44
  ".": {
40
45
  "types": "./dist/index.d.ts",
41
- "import": "./dist/index.js"
46
+ "import": "./dist/index.js",
47
+ "default": "./dist/index.js"
42
48
  },
43
49
  "./package.json": "./package.json"
44
50
  },
@@ -49,15 +55,15 @@
49
55
  "README.md"
50
56
  ],
51
57
  "dependencies": {
52
- "@kindgi/agents": "0.1.1",
53
- "@kindgi/client": "0.1.1",
54
- "@kindgi/crypto": "0.1.1",
55
- "@kindgi/flow": "0.1.1",
56
- "@kindgi/guardrails": "0.1.1",
57
- "@kindgi/handler-runtime": "0.1.1",
58
- "@kindgi/schema": "0.1.1",
59
- "@kindgi/tools": "0.1.1",
60
- "@kindgi/types": "0.1.1"
58
+ "@kindgi/agents": "0.1.3",
59
+ "@kindgi/client": "0.1.3",
60
+ "@kindgi/crypto": "0.1.3",
61
+ "@kindgi/flow": "0.1.3",
62
+ "@kindgi/guardrails": "0.1.3",
63
+ "@kindgi/handler-runtime": "0.1.3",
64
+ "@kindgi/schema": "0.1.3",
65
+ "@kindgi/tools": "0.1.3",
66
+ "@kindgi/types": "0.1.3"
61
67
  },
62
68
  "peerDependencies": {
63
69
  "zod": "^4.0.0"
@@ -75,7 +81,7 @@
75
81
  "vitest": "^2.1.8"
76
82
  },
77
83
  "engines": {
78
- "node": ">=22.0.0"
84
+ "node": ">=22.12.0"
79
85
  },
80
86
  "publishConfig": {
81
87
  "access": "public",
@@ -107,11 +107,17 @@ How the pack tooling reads this file:
107
107
  `configZod`, `configSchema` or `configJsonSchema`, or a top-level
108
108
  `configZod` / `configSchema`), and the declaration's `config` — what
109
109
  the check runs with. It does not record `description`, `budget` or
110
- `judgeCapabilities`.
110
+ `judgeCapabilities`. It checks `config` (none counts as `{}`) against
111
+ the config schema: a config that doesn't fit, or a required field with
112
+ no default left out, is a file error naming where, and `kindgi build`
113
+ refuses the pack.
111
114
  - The **pack service** loads the same module to run the check. It uses
112
115
  the module's `evaluate` export, or the `default` / `check` export when
113
116
  that is a function or has an `evaluate` method — here, the named
114
- `check` export.
117
+ `check` export. A `defineCheck` check's `evaluate` gets the config its
118
+ schema resolves: the schema's defaults applied (a guardrail that
119
+ declares no config gets them all), and a config that doesn't fit
120
+ refused, naming where.
115
121
 
116
122
  ## Validating a declaration in-process
117
123
 
@@ -22,7 +22,7 @@ description: >
22
22
  kindgi-getting-started.
23
23
  type: core
24
24
  library: "@kindgi/sdk"
25
- version: "0.9.2"
25
+ version: "0.9.3"
26
26
  sdk_version: "0.0.0"
27
27
  pack_languages: [node, python]
28
28
  sources:
@@ -126,12 +126,46 @@ credential on argv.
126
126
  kindgi providers register --preset=anthropic # Opus 5.5, Sonnet 5.5, Haiku 4.5
127
127
  kindgi providers register --preset=anthropic --models=claude-haiku-4-5 # just one
128
128
  ```
129
- The preset carries the models, context windows and current prices
130
- (`kindgi providers presets` lists the presets and when their prices were
131
- checked). In a pack it refuses until the key is in the pack's env files —
129
+ The preset carries the models, context windows, output limits and current
130
+ prices (`kindgi providers presets` lists the presets and when their prices
131
+ were checked); `--max-output-tokens=<n>` sets another output limit. In a pack it refuses until the key is in the pack's env files —
132
132
  step 1. That's all for Anthropic; go to step 4. The rest of this path is
133
133
  the same registration by hand, for a spec of your own.
134
134
 
135
+ **Or declare it in the pack's config**, and `kindgi dev` registers it on
136
+ every boot: in every git worktree (each has its own dev database), after
137
+ `--reset`, and on a teammate's machine. Prefer this for any provider the pack
138
+ needs under `kindgi dev`:
139
+ ```ts
140
+ // in kindgi.config.ts
141
+ providers: [
142
+ { preset: 'anthropic', models: ['claude-haiku-4-5'] }, // key ANTHROPIC_API_KEY, from the env files
143
+ { preset: 'gemini', project: 'acme-gcp', models: ['gemini-2.5-flash'] },
144
+ { spec: { /* the provider.json body below */ } },
145
+ ],
146
+ ```
147
+ ```toml
148
+ # in pyproject.toml: one table per provider, same keys
149
+ [[tool.kindgi.providers]]
150
+ preset = "anthropic"
151
+ models = ["claude-haiku-4-5"]
152
+ ```
153
+ - A preset entry takes `models`, `project`, `secret` (the key's name, in place
154
+ of the preset's) and `maxOutputTokens`, spelled the same in `pyproject.toml`;
155
+ a `spec` entry is a `--spec` body. A
156
+ key is always a secret's name (`secret_ref`); a credential in
157
+ `adapter_config` is refused.
158
+ - Each boot prints `Providers from kindgi.config.ts:` with one line each:
159
+ `registered`, `unchanged`, `registered again (changed in kindgi.config.ts)`,
160
+ `unregistered (no longer in kindgi.config.ts)`, or ⚠ `not registered: <KEY>
161
+ is not in .env, .env.local` (set the key, then restart: the config isn't
162
+ watched).
163
+ - A provider with that id that `kindgi dev` didn't register is left as it is;
164
+ if its region or models differ, a ⚠ line names the
165
+ `kindgi providers unregister` that lets the config's version apply.
166
+ - A runtime `kindgi dev` doesn't run (staging, production) still gets its
167
+ providers with `kindgi providers register`.
168
+
135
169
  **Step 2 (by hand) — write `provider.json`** at the pack root. One connection,
136
170
  three models — matches how the Anthropic SDK actually works (the API
137
171
  key is per-vendor; the model is per-call):
@@ -438,7 +472,7 @@ outside Google Cloud: put a service-account key (its JSON) in a secret
438
472
  "name": "gemini-2.5-pro",
439
473
  "contextWindow": 1048576,
440
474
  "features": ["tool-use"],
441
- "maxOutputTokens": 8192,
475
+ "maxOutputTokens": 65536,
442
476
  "cost": {
443
477
  "promptUsdPer1kTokens": 0.00125,
444
478
  "completionUsdPer1kTokens": 0.01,
@@ -453,6 +487,7 @@ outside Google Cloud: put a service-account key (its JSON) in a secret
453
487
  "name": "gemini-2.5-flash",
454
488
  "contextWindow": 1048576,
455
489
  "features": ["tool-use"],
490
+ "maxOutputTokens": 65536,
456
491
  "cost": { "promptUsdPer1kTokens": 0.0003, "completionUsdPer1kTokens": 0.0025 }
457
492
  }
458
493
  ]
@@ -12,7 +12,7 @@ description: >
12
12
  authoring agents is covered by kindgi-authoring-agents.
13
13
  type: core
14
14
  library: "@kindgi/sdk"
15
- version: "0.4.3"
15
+ version: "0.4.4"
16
16
  sdk_version: "0.0.0"
17
17
  pack_languages: [node]
18
18
  sources:
@@ -88,7 +88,8 @@ const defined = defineTool({
88
88
  effects: [],
89
89
  mutating: false,
90
90
  handler: async (input, ctx) => {
91
- // ctx.tenantId, ctx.abortSignal, ctx.secrets (what needsSpec declares) available
91
+ // ctx.tenantId, ctx.abortSignal, ctx.secrets (what needsSpec declares) available;
92
+ // in a run, ctx.projectId and ctx.orgId (set from the run, never from the input)
92
93
  // Return type MUST match Output schema (validated at invoke time)
93
94
  return { found: true, canonicalCite: '...' };
94
95
  },
@@ -278,6 +279,17 @@ run start via `semver.maxSatisfying`. No implicit `:latest`.
278
279
  ("⚠ The pack imports @prisma/client (in kindgi/tools/…), which
279
280
  package.json lists only in devDependencies: …"), and `kindgi build`
280
281
  refuses the pack until it moves.
282
+ 10. **A tool that needs the app's install scripts in the image.** The
283
+ image installs with scripts off, so the app's `postinstall` /
284
+ `prepare` (`prisma generate`, husky) don't run there; `kindgi build`
285
+ lists them ("✓ The app's own install scripts don't run in the image:
286
+ …"). A tool that uses Prisma's client then fails the build ("@prisma/client
287
+ did not initialize yet"). Add `prisma({ schema: 'prisma/schema.prisma' })`
288
+ (from `@kindgi/sdk/build`; add `config: 'prisma.config.ts'` when the app
289
+ has one) to `image.extensions` in `kindgi.config.ts`. Other generate
290
+ steps: `defineBuildExtension({ name, contextFiles, postInstall: [{ bin, args }] })`.
291
+ Debian packages: `image.systemPackages`. Placeholder env for those steps:
292
+ `image.buildEnv` (never secrets).
281
293
 
282
294
  ## References
283
295
 
@@ -14,7 +14,7 @@ description: >
14
14
  primitive.
15
15
  type: core
16
16
  library: "@kindgi/sdk"
17
- version: "0.3.4"
17
+ version: "0.3.7"
18
18
  sdk_version: "0.0.0"
19
19
  pack_languages: [node]
20
20
  ---
@@ -158,8 +158,82 @@ Most of the setup is automatable, but two require your knowledge:
158
158
  - **Real LLM provider credentials** — the built-in dev-echo provider
159
159
  returns canned responses (great for the loop test, useless for real
160
160
  agents). It is a fallback, so it steps aside once a real provider is
161
- registered — `kindgi providers register --preset=anthropic` with the
162
- key in `.env`; see `kindgi-authoring-providers`.
161
+ registered. Declare it in `kindgi.config.ts`
162
+ (`providers: [{ preset: 'anthropic' }]`, the key in `.env`) and `kindgi dev`
163
+ registers it on every boot, in every worktree and after `--reset`; or once,
164
+ by hand: `kindgi providers register --preset=anthropic`. See
165
+ `kindgi-authoring-providers`.
166
+
167
+ ## Your app and Kindgi's data
168
+
169
+ When the app keeps something a run did (a ticket a flow triaged, an answer
170
+ an agent gave), its own row stores the run's id, in a column such as
171
+ `kindgi_run_id`. The app starts the run and reads the rest through the API,
172
+ server side, with `createClient()` from `@kindgi/sdk/client`:
173
+
174
+ ```ts
175
+ import { createClient } from '@kindgi/sdk/client';
176
+
177
+ const kindgi = createClient(); // KINDGI_API_URL + KINDGI_API_TOKEN
178
+ const run = await kindgi.runs.start({
179
+ flow: 'my-pack.triage-ticket',
180
+ input: { ticketId },
181
+ options: { wait: false }, // the run id now; run.finished tells you when it ends
182
+ });
183
+ // save run.id as the ticket's kindgi_run_id
184
+ ```
185
+
186
+
187
+ - **Status, output, timing:** `kindgi.runs.get(runId)`
188
+ (`GET /v1/runs/{runId}`); status and timing only: `kindgi.runs.progress(runId)`.
189
+ - **The audit, step by step:** `kindgi.runs.journal(runId)`
190
+ (`GET /v1/runs/{runId}/journal`).
191
+ - **Where an agent's answer came from:** `kindgi.provenance.get(runId)`
192
+ (`GET /v1/provenance/{runId}`). A flow run has none of its own: each agent
193
+ step's `step.completed` entry in the flow's journal names its turn's run
194
+ (`payload.output.runId`).
195
+ - **What it cost:** `kindgi.cost.usage.query({ rootRunId: runId })`
196
+ (`GET /v1/cost/records?rootRunId={runId}`): `.items`, one record per model
197
+ call, with its `model`, `usage` (`promptTokens`, `completionTokens`) and
198
+ `costUsd` (a number, US dollars), a flow's agent steps included. For one
199
+ customer's spend, see below.
200
+ - **When a run finished:** the `run.finished` webhook (the run's id, its
201
+ outcome and its cost in `data.run.usage`; no output, so then `runs.get`),
202
+ not polling.
203
+
204
+ **One customer's spend:** give each customer an org, and start their runs in a
205
+ project of that org. Then one call sums their month:
206
+
207
+ ```ts
208
+ import type { Timestamp } from '@kindgi/sdk/types';
209
+
210
+ // Once per customer. Project slugs are unique across the tenant: put the customer in them.
211
+ const org = await kindgi.orgs.create({ slug: 'acme-customer-one', name: 'Customer one' });
212
+ const project = await kindgi.projects.create({ orgId: org.id, slug: 'acme-customer-one-app', name: 'App' });
213
+ // save org.id and project.id on the customer's row; start their runs with projectId: project.id
214
+
215
+ const now = new Date();
216
+ const month = await kindgi.cost.usage.summary({
217
+ scope: { kind: 'org', orgId: org.id },
218
+ from: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)).toISOString() as Timestamp,
219
+ to: now.toISOString() as Timestamp, // exclusive
220
+ groupBy: ['month'],
221
+ });
222
+ // month.totalUsd; month.groups[i].key ({ month: '2026-10' }), .totalUsd, .tokens
223
+ ```
224
+
225
+ Docs: https://docs.kindgi.com/v0.1/guides/observability/cost-per-run/
226
+
227
+ Show it in the app's own UI. **Never:**
228
+
229
+ - **query Kindgi's database**, even on the app's own Postgres server, and
230
+ never map its tables into the app's ORM. Its schema is private and changes
231
+ with every release (migrations only go forward), row-level security guards
232
+ every tenant query, and a runtime Kindgi hosts gives no database access.
233
+ - **link users to Kindgi's console** or any Kindgi UI for this data.
234
+
235
+ To keep a copy (reporting, search), pull it through the API into the app's
236
+ own tables. Docs: https://docs.kindgi.com/v0.1/guides/runs/show-runs-in-your-app/
163
237
 
164
238
  ## References
165
239
 
@@ -103,6 +103,10 @@ def verify_citation(citation: Citation, ctx: ToolContext) -> Verdict:
103
103
  - `ctx.run_id` — the run (an agent turn or a flow step) the call belongs to.
104
104
  - `ctx.request_id` — this call, e.g. the model's tool-call id; useful
105
105
  for logs and idempotency keys.
106
+ - `ctx.project_id`, `ctx.org_id` — the run's project, and that project's
107
+ org (`None` when it has none). The runtime sets them from the run, never
108
+ from the input: to check an org or project id the input names, compare
109
+ it with these instead of trusting it.
106
110
  - `ctx.cancellation` — fires when the call's deadline passes or the
107
111
  caller disconnects. An `async def` handler is also cancelled at its
108
112
  next `await`. A `def` handler keeps running in its thread: check
@@ -14,7 +14,7 @@ description: >
14
14
  kindgi-python-authoring-agents; models by kindgi-authoring-providers.
15
15
  type: core
16
16
  library: "kindgi (Python)"
17
- version: "0.1.1"
17
+ version: "0.1.5"
18
18
  sdk_version: "0.0.0"
19
19
  pack_languages: [python]
20
20
  sources:
@@ -26,7 +26,7 @@ sources:
26
26
  # Getting started with Kindgi in Python
27
27
 
28
28
  > **Running `kindgi`:** a Python pack has no Node project, so the
29
- > `kindgi` CLI (a Node 22+ program) is the one on `PATH`. Python
29
+ > `kindgi` CLI (a Node 22.12+ program) is the one on `PATH`. Python
30
30
  > commands run in the pack's environment: `uv run …`.
31
31
 
32
32
  ## What a pack is
@@ -129,8 +129,16 @@ kindgi secrets set ANTHROPIC_API_KEY --env=local --scope=tenant # no-echo prom
129
129
  kindgi providers register --preset=anthropic
130
130
  ```
131
131
 
132
- It takes over at the next turn. Details and other providers:
133
- `kindgi-authoring-providers`.
132
+ It takes over at the next turn. That registration is in this project's dev
133
+ database only. To have `kindgi dev` register it on every boot, in every
134
+ worktree and after `--reset`, declare it in `pyproject.toml` instead:
135
+
136
+ ```toml
137
+ [[tool.kindgi.providers]]
138
+ preset = "anthropic" # its key, ANTHROPIC_API_KEY, from the env files
139
+ ```
140
+
141
+ Details and other providers: `kindgi-authoring-providers`.
134
142
 
135
143
  `uv run python -m kindgi.pack index --pack-dir .` prints what Kindgi
136
144
  sees (the index); `kindgi dev` reports a broken file with its path and
@@ -182,6 +190,67 @@ for event in client.runs.stream(str(run.id)):
182
190
  `AsyncKindgi` is the asyncio twin. `kindgi dev` prints the URL and the
183
191
  token; `.kindgirc.json` in the pack holds them for the CLI.
184
192
 
193
+ ## Your app and Kindgi's data
194
+
195
+ When the app keeps something a run did (a ticket a flow triaged, an answer
196
+ an agent gave), its own row stores the run's id, in a column such as
197
+ `kindgi_run_id` (`run = client.runs.start(flow=…, input=…, options={"wait": False})`,
198
+ then `run.id`). The app reads the rest through the API, server side, with
199
+ `Kindgi()` from `kindgi.client`:
200
+
201
+ - **Status, output, timing:** `client.runs.get(run_id)`
202
+ (`GET /v1/runs/{runId}`); status and timing only: `client.runs.progress(run_id)`.
203
+ - **The audit, step by step:** `client.runs.journal(run_id).data`
204
+ (`GET /v1/runs/{runId}/journal`).
205
+ - **Where an agent's answer came from:** `client.provenance.get(run_id)`
206
+ (`GET /v1/provenance/{runId}`). A flow run has none of its own: each agent
207
+ step's `step.completed` entry in the flow's journal names its turn's run
208
+ (`entry.payload["output"]["runId"]`).
209
+ - **What it cost:** `client.cost.records.list(root_run_id=run_id).data`
210
+ (`GET /v1/cost/records?rootRunId={runId}`): one record per model call,
211
+ with its `model`, `usage` (`prompt_tokens`, `completion_tokens`) and
212
+ `cost_usd` (a float, US dollars), a flow's agent steps included. For one
213
+ customer's spend, see below.
214
+ - **When a run finished:** the `run.finished` webhook (the run's id, its
215
+ outcome and its cost in `data.run.usage`; no output, so then `runs.get`),
216
+ not polling.
217
+
218
+ **One customer's spend:** give each customer an org, and start their runs in a
219
+ project of that org. Then one call sums their month:
220
+
221
+ ```python
222
+ from datetime import datetime, timezone
223
+
224
+ # Once per customer. Project slugs are unique across the tenant: put the customer in them.
225
+ org = client.orgs.create(slug="acme-customer-one", name="Customer one")
226
+ project = client.projects.create(org_id=str(org.id), slug="acme-customer-one-app", name="App")
227
+ # save org.id and project.id on the customer's row; start their runs with project_id=project.id
228
+
229
+ now = datetime.now(timezone.utc)
230
+ month = client.cost.aggregate(
231
+ group_by="month",
232
+ scope_kind="org",
233
+ scope_id=str(org.id),
234
+ from_=now.replace(day=1, hour=0, minute=0, second=0, microsecond=0).isoformat(),
235
+ to=now.isoformat(), # exclusive
236
+ )
237
+ # month.total_usd; month.groups[i].key ({"month": "2026-10"}), .total_usd, .tokens
238
+ ```
239
+
240
+ Docs: https://docs.kindgi.com/v0.1/guides/observability/cost-per-run/
241
+
242
+ Show it in the app's own UI. **Never:**
243
+
244
+ - **query Kindgi's database**, even on the app's own Postgres server, and
245
+ never map its tables into the app's ORM (SQLAlchemy, Django models). Its
246
+ schema is private and changes with every release (migrations only go
247
+ forward), row-level security guards every tenant query, and a runtime
248
+ Kindgi hosts gives no database access.
249
+ - **link users to Kindgi's console** or any Kindgi UI for this data.
250
+
251
+ To keep a copy (reporting, search), pull it through the API into the app's
252
+ own tables. Docs: https://docs.kindgi.com/v0.1/guides/runs/show-runs-in-your-app/
253
+
185
254
  ## Build an image
186
255
 
187
256
  `kindgi build --env=<name>` (an `[tool.kindgi.environments.<name>]`